我的环境
idea 2019.1
jdk 1.8
Spring 5
Lombok插件 这里是使用和安装链接(包括idea和eclipse) @简单粗暴节省JavaBean代码插件 Lombok.jar
上一篇 @SpringMVC知识点整合(上)
基本环境搭建
环境搭建 pom.xml
UTF-8
1.8
1.8
5.0.2.RELEASE
org.springframework
spring-context
${spring.version}
org.springframework
spring-web
${spring.version}
org.springframework
spring-webmvc
${spring.version}
javax.servlet
servlet-api
2.5
provided
javax.servlet.jsp
jsp-api
2.0
provided
org.projectlombok
lombok
1.18.8
provided
配置web.xml 里面解决乱码和前端控制器
Archetype Created Web Application
DispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
1
DispatcherServlet
/
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
CharacterEncodingFilter
/*
新建 java root 和 resources root
编写 springmvc.xml
编写 index.jsp 和 /webapp/ipages/success.jsp
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
helle
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
success
然后部署到Tomcat
测试:
5. 响应数据和结果视图
5.1.返回值分类
响应返回值是 String 类型
准备: response.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
response
返回字符串
方法 UserController.java
package cn.icanci.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: icanci
* @ProjectName: springmvc_day2
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 9:51
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testString")
public String testString() {
System.out.println("UserController.testString");
return "success";
}
}
测试:
下面测试传递对象到jsp页面 其实这里和JavaWeb很像 只是有些地方框架为我们做了封装
执行的方法:UserController.java
package cn.icanci.controller;
import cn.icanci.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: icanci
* @ProjectName: springmvc_day2
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 9:51
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testString")
public String testString(Model model) {
System.out.println("UserController.testString");
//模拟从数据库中查询一个 User 对象
User user = new User();
user.setUsername("haxi");
user.setPassword("445454");
user.setAge(16);
model.addAttribute("user",user);
return "success";
}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
Title
success
${user.username}
${user.password}
测试结果
响应返回值是 void 类型
准备方法:
@RequestMapping("/testVoid")
public void testVoid(Model model) {
System.out.println("UserController.testVoid");
}
准备界面 超链接
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
response
返回字符串
无返回值类型
跳转报错 报错信息说明 没有找到对应的jsp界面
解决方法
1.在对应路径下建立 包和文件
2.使用HttpServletRequest对象 进行请求转发跳转到 WEB-INF 下的某个文件 或者 HtttpServletRequest 对象的重定向 跳转
3.直接输出一个界面
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("UserController.testVoid");
try {
//请求转发
// req.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(req, resp);
//重定向
// resp.sendRedirect("/index.jsp");
//有的时候直接响应
//设置中文乱码
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("hello");
} catch (Exception e) {
e.printStackTrace();
}
}
返回值类型是 ModelAndView
ModelAndView 是 SpringMVC 为我们提供的一个对象,该对象也可以用作控制器方法的返回值。
该对象中有两个方法:
//把User对象存储到mv对象中去 也会把user对象存储到 request对象中去
mv.addObject("user",user);
//跳转到那个界面
mv.setViewName("success");
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
System.out.println("UserController.testModelAndView");
ModelAndView mv = new ModelAndView();
//模拟从数据库中查询一个 User 对象
User user = new User();
user.setUsername("haxi");
user.setPassword("445454");
user.setAge(16);
//把User对象存储到mv对象中去 也会把user对象存储到 request对象中去
mv.addObject("user",user);
//跳转到那个界面
mv.setViewName("success");
return mv;
}
测试
5.2 转发和重定向
实例代码
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect() {
System.out.println("UserController.testForwardOrRedirect");
// return "forward:/WEB-INF/pages/success.jsp";
return "redirect:/index.jsp";
}
5.3 ResponseBody 响应 json 数据
作用:
该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的
数据如:json,xml 等,通过 Response 响应给客户端
准备界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
response
返回字符串
无返回值类型
ModelAndView
testForwardOrRedirect
配置springmvc.xml 因为 前端控制器拦截了资源 导致不能加载
使用响应json数据发送数据
前端界面 此界面用来测试是否可以响应 alert函数
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
response
返回字符串
无返回值类型
ModelAndView
testForwardOrRedirect
后端方法
@RequestMapping("/testAjax")
public void testAjax(@RequestBody String body){
System.out.println("UserController.testAjax");
System.out.println(body);
}
测试
如果需要把json转换为JavaBean,还需要一个jar包
导入依赖
com.fasterxml.jackson.core
jackson-databind
2.9.0
com.fasterxml.jackson.core
jackson-core
2.9.0
com.fasterxml.jackson.core
jackson-annotations
2.9.0
response.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
response
返回字符串
无返回值类型
ModelAndView
testForwardOrRedirect
方法
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("UserController.testAjax");
//客户端传输的是json 后台那数据封装到 JavaBean中
System.out.println(user);
user.setUsername("hashTable");
System.out.println(user);
return user;
}
测试结果
6.SpringMVC实现文件上传
JavaWeb中的表单上传文件的回顾
文件上传的必要前提
A form 表单的 enctype 取值必须是:multipart/form-data
(默认值是:application/x-www-form-urlencoded)
enctype:是表单请求正文的类型
B method 属性取值必须是 Post
C 提供一个文件选择域
文件上传的原理分析
当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。
enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
key=value&key=value&key=value
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file";
filename="C:\Users\zhy\Desktop\fileupload_demofile\b.txt"
Content-Type: text/plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--
借助第三方组件
使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。commons-io 不属于文件上传组件的开发 jar 文件,但Commons-fileupload 组件从 1.1 版本开始,它工作时需要 commons-io 包的支持。
使用之前的基本环境
a.使用传统方式文件上传
准备一个类和方法 UserController .java
package cn.icanci.controller;
import cn.icanci.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: icanci
* @ProjectName: springmvc_day2
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 9:51
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 第一个文件上传的方法
*
* @return
*/
@RequestMapping("/testFileUpload1")
public String testFileUpload1() {
System.out.println("UserController.testFileUpload1");
return "success";
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
hello 文件上传
导入依赖
commons-fileupload
commons-fileupload
1.3.1
commons-io
commons-io
2.4
上传文件的控制类 testFileUpload1.java
package cn.icanci.controller;
import java.util.UUID;
import java.io.File;
import java.util.List;
import cn.icanci.domain.User;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: icanci
* @ProjectName: springmvc_day2
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 9:51
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 第一个文件上传的方法 传统方式
*
* @return
*/
@RequestMapping("/testFileUpload1")
public String testFileUpload1(HttpServletRequest req) {
System.out.println("UserController.testFileUpload1");
//使用 fileupload 组件完成文件上传
//上传的位置
String path = req.getSession().getServletContext().getRealPath("/uploads/");
//判断路径是否存在
System.out.println(path);
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
//解析req对象 获取上传文件的
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析 req
try {
List fileItems = upload.parseRequest(req);
//遍历
for (FileItem item : fileItems) {
//判断上传的文件是不是上传文件项
if (item.isFormField()) {
//说明是普通表单项
System.out.println("item form");
} else {
System.out.println("upload");
//说明是文件表单项
//获取上产文件的名称
String fileName = item.getName();
//完成文件上传
try {
UUID uuid = UUID.randomUUID();
item.write(new File(path, uuid.toString().replace("-", "") + "_" + fileName));
//删除临时文件
item.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
System.out.println("上传成功");
return "success";
}
}
测试
控制台打印一些信息
文件路径
第一种方式测试通过
b.使用SpringMVC传统的方式上传文件
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的name属性名称相同。
配置springmvc.xml中的文件解析器
注意:
-
此处 id的值必须为 multipartResolver 否则报错以下异常
-
如果文件大小超出设置的 就会报以下异常
修改之后 此时测试通过
c.使用SpringMVC跨服务器方式的文件上传
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
首先需要搭建环境
配置一个新的服务器 注意端口需要修改 同时 Tomcat 的 conf 目录下的 server.xml 的宽口也要修改
选中刚刚的项目 右键 new 一个模块 按照初始配置就可以 或者直接复制之前的项目 代码 然后测试
测试结果
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
嘻嘻嘻
到之前的pom.xml里面导入坐标
com.sun.jersey
jersey-core
1.18.1
com.sun.jersey
jersey-client
1.18.1
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Title
hello 文件上传
传统方式
SpringMVC方式
SpringMVC开服务器方式
后台代码
package cn.icanci.controller;
import java.io.IOException;
import java.util.UUID;
import java.io.File;
import java.util.List;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
/**
* @Author: icanci
* @ProjectName: springmvc_day2
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 9:51
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
/**
* @param upload 此处的名字和你表单中的名字 必须一样
* @return
*/
@RequestMapping("/testFileUpload3")
public String testFileUpload3(MultipartFile upload) {
System.out.println("UserController.testFileUpload3");
//定义上传服务器的地址
String path = "http://localhost:8080/f2/uploads/";
//说明是文件表单项
//获取上产文件的名称
String fileName = upload.getOriginalFilename();
//完成文件上传
UUID uuid = UUID.randomUUID();
fileName = uuid.toString().replace("-", "") + "_" + fileName;
System.out.println(fileName);
//跨服务器上传
//创建客户端的对象
Client client = Client.create();
//和图片服务器进行链接
WebResource wr = client.resource(path+fileName);
//上传文件
try {
wr.put(upload.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
/**
* @param req
* @param upload 此处的名字和你表单中的名字 必须一样
* @return
*/
@RequestMapping("/testFileUpload2")
public String testFileUpload2(HttpServletRequest req, MultipartFile upload) {
System.out.println("UserController.testFileUpload2");
//使用 fileupload 组件完成文件上传
//上传的位置
String path = req.getSession().getServletContext().getRealPath("/uploads/");
//判断路径是否存在
System.out.println(path);
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
//说明是文件表单项
//获取上产文件的名称
String fileName = upload.getOriginalFilename();
//完成文件上传
UUID uuid = UUID.randomUUID();
fileName = uuid.toString().replace("-", "") + "_" + fileName;
System.out.println(fileName);
//完成文件上传
try {
upload.transferTo(new File(path,fileName));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
/**
* 第一个文件上传的方法 传统方式
*
* @return
*/
@RequestMapping("/testFileUpload1")
public String testFileUpload1(HttpServletRequest req) {
System.out.println("UserController.testFileUpload1");
//使用 fileupload 组件完成文件上传
//上传的位置
String path = req.getSession().getServletContext().getRealPath("/uploads/");
//判断路径是否存在
System.out.println(path);
File file = new File(path);
if (!file.exists()) {
file.mkdir();
}
//解析req对象 获取上传文件的
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析 req
try {
List fileItems = upload.parseRequest(req);
//遍历
for (FileItem item : fileItems) {
//判断上传的文件是不是上传文件项
if (item.isFormField()) {
//说明是普通表单项
System.out.println("item form");
} else {
System.out.println("upload");
//说明是文件表单项
//获取上产文件的名称
String fileName = item.getName();
//完成文件上传
try {
UUID uuid = UUID.randomUUID();
item.write(new File(path, uuid.toString().replace("-", "") + "_" + fileName));
//删除临时文件
item.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
System.out.println("上传成功");
return "success";
}
}
开启两个服务器 然后测试
执行之后报错
如图 是因为没有这个文件夹
创建此文件夹
7.SpringMVC的异常处理
环境搭建和开始的时候一样
步骤
- 自定义异常类
- 自定义异常处理器
- 配置异常处理器
准备 自定义异常类 SelfException.java
package cn.icanci.exception;
import lombok.Data;
import java.security.spec.ECFieldF2m;
/**
* @Author: icanci
* @ProjectName: springMVCException
* @PackageName: cn.icanci.exception
* @Date: Created in 2020/1/14 22:54
* @ClassAction: 自定义异常类
*/
@Data
public class SelfException extends Exception {
//用来存储异常信息的
private String message;
public SelfException(){}
public SelfException(String message){
this.message = message;
}
public void setMessage(String message){
this.message = message;
}
}
UserController.java
package cn.icanci.controller;
import cn.icanci.exception.SelfException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author: icanci
* @ProjectName: springMVCException
* @PackageName: cn.icanci.controller
* @Date: Created in 2020/1/14 22:46
* @ClassAction:
*/
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testException")
public String testException() throws Exception{
System.out.println("UserController.testException");
try {
int a = 10/0;
} catch (Exception e) {
e.printStackTrace();
throw new SelfException("用户有异常");
}
return "success";
}
}
SelfExceptionResolver.java 处理异常到界面
package cn.icanci.exception;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: icanci
* @ProjectName: springMVCException
* @PackageName: cn.icanci.exception
* @Date: Created in 2020/1/14 23:05
* @ClassAction:
*/
public class SelfExceptionResolver implements HandlerExceptionResolver {
/**
* 处理业务逻辑
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e
* @return
*/
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
//准备获取异常对象
SelfException exception = null;
if(e instanceof SelfException){
exception = (SelfException) e;
}else {
e = new SelfException("系统正在维护.//.///");
}
//创建 ModelAndView 对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
mv.setViewName("error");
return mv;
}
}
准备 error.jsp界面
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
Title
${errorMsg}
在springmvc,xml 配置异常处理器
测试
8.SpringMVC中的拦截器
基本环境和之前的一样
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链
中的拦截器会按着定义的顺序执行。 - 拦截器和过滤器的功能比较类似,有区别
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
- 拦截器也是AOP思想的一种实现方式
- 想要自定义拦截器,需要实现HandlerInterceptor接口。
自定义拦截器
- 创建类,实现HandlerInterceptor接口,重写需要的方法
- 在springmvc.xml中配置拦截器类
HandlerInterceptor接口中的方法
1. preHandle方法是controller方法执行前拦截的方法
1. 可以使用request或者response跳转到指定的页面
2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
3. return false不放行,不会执行controller中的方法。
2. postHandle是controller方法执行后执行的方法,在JSP视图执行前。
1. 可以使用request或者response跳转到指定的页面
2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。
3. postHandle方法是在JSP执行后执行
1. request或者response不能再跳转页面了
后台代码
/**
* 自定义拦截器
*/
public class MyInterceptor2 implements HandlerInterceptor{
/**
* 预处理,controller方法执行前
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* return false不放行
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...前2222");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法,controller方法执行后,success.jsp执行之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后2222");
// request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
/**
* success.jsp页面执行后,该方法会执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了...最后2222");
}
}
SpringMVC的知识点总结告一段落 之后有补充的会添加进来
此处 @我自己 这是QQ聊天的链接 欢迎一起吹