今日内容
第一章:相应数据和结果视图
第二章:SpringMVC实现文件上传
第三章:SpringMVC中的异常处理
第四章:SpringMVC中的拦截器
第一章:相应数据和结果视图
1.1 Controller中方法返回值分类
1.1.1 返回字符串
controller方法返回字符串可以指定逻辑视图名,通过解析器解析为物理视图地址。
return "success"; ---- 通过视图解析器跳转到相应的页面
```
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString方法执行了...");
//模拟从数据库中查询出user对象
User user = new User();
user.setUsername("美美");
user.setPassword("123");
user.setAge(30);
//model:将数据存入Request域中
model.addAttribute("user", user);
return "success";
}
```
1.1.2 返回值 -- void
1.默认情况
* jsp
```
<a href="user/testVoid">testVoid</a>
```
* UserController
```
@RequestMapping("/testVoid")
public void testVoid(){
System.out.println("testVoid方法执行了...");
}
```
* 效果: 404错误
点击jsp链接后访问到了localhost:8080/day0615/user/testVoid资源。
成功打印了输出语句:testVoid方法执行了...
但是由于执行的Controller类中的方法没有返回值(void),默认会跳转到
@RequestMapping(value="testVoid") testVoid.jsp页面。
但是由于没有该页面,所以报404的错误。
2.解决:可以使用请求转发或者重定向跳转到指定的页面
2.1 转发解决 -- 转发到localhost:8080/day0615/WEB-INF/pages/success.jsp
* jsp
```
<a href="user/testVoidRequest">testVoidRequest</a>
```
* UserController
```
@RequestMapping("/testVoidRequest")
public void testVoidRequest(HttpServletRequest request, HttpServletResponse response)
throws Exception{
System.out.println("testVoid方法执行了...");
//编写请求转发程序
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request, response);
System.out.println(request.getContextPath());
//转发程序写完后,还会执行后续的代码,如果不想可以加一个return;
return;
}
```
注意:编写请求转发是不写request.getRequestDispatcher("success"):
因为是转发请求,不会默认去调用视图解析器。
2.2 重定向 -- 重定向到localhost:8080/day0615/index.jsp
* jsp
```
<a href="user/testVoidResponse">testVoidResponse</a>
```
* UserController
```
@RequestMapping("/testVoidResponse")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws Exception{
System.out.println("testVoid方法执行了...");
//编写重定向程序
response.sendRedirect("/day0615_springmvc01_response/index.jsp");
System.out.println(request.getContextPath());
//转发程序写完后,还会执行后续的代码,如果不想可以加一个return;
return;
}
```
这里参数写的是绝对路径,所以最终的重定向URL:
localhost:8080//day0615_springmvc01_response/index.jsp
也可以这样写:
response.sendRedirect(request.getContextPath()+"/index.jsp");
request.getContextPath() : /day0615_springmvc01_response
3. 直接通过输出流把数据响应到页面上
* jsp
```
<a href="user/testResponse">直接响应</a>
```
* Controller
```
@RequestMapping("/testResponse")
public void testResponse(HttpServletRequest request, HttpServletResponse response)
throws Exception{
System.out.println("testVResponse方法执行了...");
//解决中文乱码
response.setCharacterEncoding("UTF-8");
//浏览器解析编码
response.setContentType("text/html;charset=UTF-8");
//拿到输出流
response.getWriter().print("你好");
return;
}
```
* 结果
4. 用关键字做转发和重定向
Controller方法提供了String类型的返回值之后,默认就是请求转发,是通过视图解析器实现的。
我们可以用关键字forward:实现这一结果。
注意:用了关键字后,就不用在用视图解析器了,所以要补全path。
1. 请求转发
```
@RequestMapping("/testForwardAndRedirect")
public String testForwardAndRedirect(){
System.out.println("testForwardAndRedirect方法执行了...");
//关键字转发
return "forward:/WEB-INF/pages/success.jsp";
}
```
2. 重定向
```
@RequestMapping("/testForwardAndRedirect")
public String testForwardAndRedirect(HttpServletRequest request){
System.out.println("testForwardAndRedirect方法执行了...");
//关键字重定向:
return "redirect:"+request.getContextPath()+"/index.jsp";
}
```
注意:
重定向的绝对路径要写项目名。
但是在用redirect关键字时,springmvc其实会帮我们加上,所以这里也可以写:
return "redirect:/index.jsp";
1.1.3 ResponseBody响应json数据
1 使用说明
作用:
该注解用于将Controller的方法返回的对象,通过HttpMessageConverter接口转换为指定
格式的数据入:json,xml等,通过Response响应给客户端。
2. 案例演示
1. 引入JQuery文件到jsp中
2. 写一个ajax代码:response.jsp
```
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
//页面加载,绑定单击事件
$(function () {
$("#btn").click(function () {
alert("hello btn")
});
});
</script>
</head>
<body>
<button id="btn">发送ajax请求</button>
</body>
</html>
```
3.我们发现ajax请求发送失败
4.原因:
我们在response.jsp中的引入了静态资源;
```
<script src="js/jquery.min.js"></script>
```
这个静态资源也会被我们在web.xml配置的前端控制器拦截下来:
我们配置的前端控制器将项目路径下的所有路径都拦截了。
5. 我们要告诉前端控制器不要拦截静态资源。
在spring.xml文件中配置:告诉前端控制器,哪些静态资源不拦截-
```
<mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 -->
<mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 -->
<mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
```
注意:配置好后,要重新启动IDEA才能生效(引入的JQuery就不会被拦截了)
6. 前置知识点
Spring默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson包
作用:将对象转成json字符串,或者将json字符串转成JavaBean对象
引入依赖坐标:
```
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
```
7. 继续写前端页面
```
<script src="js/jquery-1.11.0.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
//alert("hello btn");
//$ : JQuery全局对象
$.ajax({
//编写json格式,设置属性和值
url:"user/testAjax",
/指定给服务其传json类型数据
contentType:"application/json;charset=UTF-8",
//发送到服务器的数据:json格式
data:'{"username":"大宝","password":"123","age":"30"}',
//设置服务返回的数据格式
dataType:"json",
//请求方式
type:"post",
//请求成功后的处理函数
success:function (data) {
//data服务端响应的json数据,进行解析
alert(data);
alert(data.username);
alert(data.age);
alert(data.password);
}
});
});
});
</script>
```
8. 写后端代码:将接收的json数据转成对象后,再转成json格式响应给客户端
```
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
//前台响应过来的json数据在请求体内:我们用@RequestBody注解来接收
System.out.println("testAjax法执行了...");
System.out.println(user);
//json数据中的key如果能和JAVABean中的属性对应上的话,springmvc就正好可以帮我们封装
//前提是导入几个jar包
//做响应:模拟查询数据库
user.setUsername("haha");
user.setAge(40);
//做响应:注意前端设定的返回类型是json
//在返回值声明处:public @ResponseBody User
return user;
}
```
9. 分析:
前端页面将数据以放到request中以json格式发送过来,我们首先要接受。
通过方法中的参数接收request中的数据。
如果json数据中的key能和JAVABean中的属性对应上的话,springmvc就正好可以帮我们封装。
所以我们直接将对象返回:return user;
但是前台页面要接收的是json格式:所以用@ResponseBody User将方法返回的对象转成json。
1.1.4 返回值 -- ModelAndView
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图。
我们可以在方法的返回值上返回这个对象,它也可以通过视图解析器帮你跳转到某页面。
Model可以存储JavaBean对象,View可以存储你想跳转的页面。
Controller:
```
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了...");
//模拟从数据库中查询出user对象
User user = new User();
user.setUsername("小凤");
user.setPassword("145");
user.setAge(30);
//把user对象存储到mv对象中,同时底层也会将user存到request对象中
mv.addObject("user", user);
//跳转的页面: 会调用视图解析器解析这个视图
mv.setViewName("success");
return mv;
}
```
注意:
视图解析器会根据配置:
```
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
```
自动去补全前缀和后缀,找到页面。
第二章:SpringMVC实现文件上传
2.1 文件上传的回顾
A form表单的enctype取值必须是:multipart/form-data
enctype:是表单请求正文的类型
默认值是:application/x-www-form-urlencoded
B method属性取值必须是Post
C 提供一个文件选择域<input type=”file” />
2.2 文件上传的原理分析
当form表单的enctype取值不是默认值后,request.getParameter()将失效。
enctype="application/x-www-form-urlencoded"时,form表单在request中的的正文内容是:
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--
2.4 借助第三方组件实现文件上传
使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:
Commons-fileupload和commons-io。
。commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1
版本开始,它工作时需要commons-io包的支持。
需要注入的坐标依赖:
```
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
```
2.5 传统方式上传文件
1. 前端JSP
```
<body>
<h3>文件上传</h3>
<form action="user/fileupload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/>
<input type="submit" value="上传"/>
</form>
</body>
```
2. 后端Controller
```
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 文件上传
* @return
*/
@RequestMapping("/fileupload1")
public String fileupload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传...");
//上传的位置
String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
//判断该路径是否存在
File file = new File(realPath);
if(!file.exists()){
//创建文件夹
file.mkdirs();
}
//解析request对象,获取上传文件项。new 磁盘文件项工厂
//文件项:表单上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request:返回一个文件项list
List<FileItem> items = upload.parseRequest(request);
//遍历
for (FileItem item : items) {
//判断当前的item对象是否是上传文件项
if(item.isFormField()){
//普通表单项
}else {
//上传文件项
//获取上传文件的名称
String itemName = item.getName();
//当传的是同名文件时:不覆盖,添加
//把文件名称设一个唯一值:uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
itemName = uuid+"-"+itemName;
//完成文件上传
item.write(new File(realPath, itemName));
//删除临时文件:上传文件大于10kb,就会生成临时文件。小于10kb在内存中生成缓存(不用处理)。
item.delete();
}
}
return "success";
}
}
```
分析一下代码:
1.
首先要明确:选择要上传的文件并且提交表单后,数据是先封装到Request域中
2.
String realPath = request.getSession().getServletContext().getRealPath("/uploads/");
String realPath1 = request.getSession().getServletContext().getRealPath("");
当部署的项目名是:
day0615_springmvc02_fileupload:war expload,
项目部署在工程源码目录下的target下
E:\Idea_Projects\day0615_springmvc02_fileupload\target\day0615_springmvc02_fileupload
那么当前当前项目的绝对根目录:
E:\Idea_Projects\day0615_springmvc02_fileupload\target\day0615_springmvc02_fileupload\
所以realPath:
E:\Idea_Projects\day0615_springmvc02_fileupload\target\day0615_springmvc02_fileupload\uploads\
所以realPath1:
E:\Idea_Projects\day0615_springmvc02_fileupload\target\day0615_springmvc02_fileupload\
当部署的项目名是:
day0615_springmvc02_fileupload:war
项目部署在tomcat目录下:
D:\Developer_Tools\apache-tomcat-8.5.31\webapps\day0615_springmvc02_fileupload_war
那么当前当前项目的绝对根目录:
D:\Developer_Tools\apache-tomcat-8.5.31\webapps\day0615_springmvc02_fileupload_war\
所以realPath:
D:\Developer_Tools\apache-tomcat-8.5.31\webapps\day0615_springmvc02_fileupload_war\uploads\
所以realPath1:
D:\Developer_Tools\apache-tomcat-8.5.31\webapps\day0615_springmvc02_fileupload_war\
3. new 磁盘文件项工厂和核心操作类
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
4. 核心操作类对象upload解析request对象,获取上传文件项
List<FileItem> items = upload.parseRequest(request);
5.当传的是同名文件时:不覆盖,添加。
给文件名称设一个唯一值:uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
itemName = uuid+"-"+itemName;
6. 删除临时文件:上传文件大于10kb,就会生成临时文件。小于10kb在内存中生成缓存(不用处理)。
item.delete();
2.6 springmvc上传文件
2.6.1 原理分析
1. 在springmvc.xml中先配置一个文件解析器
```
<!--配置文件解析器对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件最大值.单位字节Byte: 1024Byte=1KB 104857600=1024*1024*100-->
<property name="maxUploadSize" value="104857600"></property>
</bean>
```
2. 前端页面发送请求后,会先经过前端控制器。
它会调文件解析器,然后文件解析器解析request中的文件上传项拿到上传文件对象。
传给fileupload2方法中的参数MultipartFile upload。
注意参数MultipartFile upload 必须和表单提交的name名一致
2.6.2 代码实现
3. 前端JSP
```
<h3>SpringMVC文件上传</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传"/>
</form>
```
4. 后端Controller
```
@RequestMapping("/fileupload2")
//注意参数二MultipartFile upload 必须和表单提交的name名一致
public String fileupload2(HttpServletRequest request, MultipartFile upload) throws Exception {
System.out.println("springMVC方式上传路径...");
//上传的位置
String path = request.getSession().getServletContext().getRealPath("/MVCUploads/");
//判断该路径是否存在
File file = new File(path);
if(!file.exists()){
file.mkdirs();
}
//不用我们自己写代码解析request,mvc帮我们解析
//获取上传文件名称
String filename = upload.getOriginalFilename();
//给名称值设置一个唯一值
String uuid = UUID.randomUUID().toString().replace("_", "");
filename = uuid+"_"+filename;
//完成文件上传
upload.transferTo(new File(path, filename));
return "success";
}
```
2.7 springmvc跨服务器方式的上传文件
2.7.1 跨服务器方式的上传文件
在实际开发中,我们会有很多处理不同功能的服务器。例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理大并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
2.7.2 步骤
1. 我们先部署图片服务器:FileUploadServer
不用配置文件,设置一下端口,建一个上传文件夹。
2.相关jar包:帮我们实现跨服务器上传文件
在应用服务器day0615_springmvc02_fileupload 导入必要的jar包:
```
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
```
3. 接收服务器:设置读写权限
web.xml
```
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<!--suppress ALL -->
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
```
4. 在项目部署路径下创建一个接受目录
5. 前端jsp --- 应用服务器
```
<h3>跨服务器方式的文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br/>
<input type="submit" value="上传"/>
</form>
```
6. 后端Controller --- 应用服务器
```
@RequestMapping("/fileupload3")
//注意参数二MultipartFile upload 必须和表单提交的name名一致
public String fileupload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器方式文件上传...");
//1.定义上传文件服务器的路径
String path = "http://192.168.3.126:8080/springmvc02/uploads";
//获取上传文件名称
String filename = upload.getOriginalFilename();
//给名称值设置一个唯一值
String uuid = UUID.randomUUID().toString().replace("_", "");
filename = uuid+"_"+filename;
//创建客户端对象
Client client = Client.create();
//和图片服务器进行连接:拿到一个web资源
WebResource webResource = client.resource(path + "/" + filename);
//跨服务器上传文件
webResource.put(upload.getBytes());
return "success";
}
```
第三章:SpringMVC中的异常处理
3.1 SpringMVC处理异常的流程
系统中异常包括两类:预期异常和运行时异常RuntimeException,
前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,
最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
在前端控制器捕获到有下面抛上来的异常后,交由异常处理器组件来处理
这个异常。目的是给客户端展示一个良好的错误提示页面。
3.2 演示自定义异常处理器
配置我们自定义的异常处理器类。
1. 编写自定义异常类(做提示信息)
```
public class SysException extends Exception{
//存储提示信息
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public SysException(String msg) {
this.msg = msg;
}
}
```
2. 编写异常处理器
```
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 当Controller类将异常抛给DispatcherServlet后,DispatcherServlet
* 会调用异常处理器组件来处理这个异常
*
* 我们自定义了一个异常处理器,在里面写我们的逻辑。
* @param ex 接受我们在Controller抛出的异常
*/
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
//1.获取到异常对象
SysException e = null;
if(ex instanceof SysException){
e = (SysException)ex;
}else{
e = new SysException("系统正在维护");
}
//注意返回值:ModelAndView。其中的View可以设置我们跳转的页面
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg", e.getMsg());
//视图解析器会根据配置:自动去补全前缀和后缀,找到页面
mv.setViewName("error");
return mv;
}
}
```
3. 配置异常处理器(跳转到提示页面)
spingmvc.xml
```
<!--配置我自定义的异常处理器-->
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"></bean>
```
第四章:SpringMVC中的拦截器
4.1 拦截器概述
Spring MVC 的处理器拦截器类似于Servlet开发中的过滤器Filter,用
对处理器(Controller类)进行预处理和后处理。
用户可以自己定义一些拦截器来实现特定的功能。放行之前会编写一写逻
辑代码(预处理),放行之后也会编写一写代码(后处理)。Controller执行
完之后,想往前跳就执行放行后的代码。
拦截器链(Interceptor Chain):多个拦截器
拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方
法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
(这里是它也是AOP思想的具体应用:将Controller类中的公共代码都抽
取出来,按照一定的顺序配置多个拦截器)
拦截器和过滤器是有几分相似,但是也有区别,接下来我们就来说说他
们的区别:
1.过滤器是servlet规范中的一部分,任何java web工程都可以使用。
是sun公司提供的web规范,SrpingMVC Web项目也可以使用过滤器技术。
2.拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能用。
3.过滤器在url-pattern中配置了/*之后,可以对所有要访问的资源拦截。
4.拦截器它是只会拦截访问的控制器(Controller类中的方法)方法,
如果访问的是jsp,html,css,image或者js是不会进行拦截的。
拦截器只拦Controller。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor接口。
4.2 自定义拦截器的步骤
1. 第一步:编写一个拦截器类。
编写一个普通类实现HandlerInterceptor接口
```
public class MyInterceptor1 implements HandlerInterceptor {
//发现实现这个接口,却不用重写方法。里面没有方法吗?
//JDK1.8 接口增强。 接口的方法已经实现了
/**
* 预处理:controller中的方法执行前先走该方法。
* return true放行,执行下一个拦截器,如果没有,执行Controller中的方法。
* return false不放行:我们可以用参数中的req,resp跳转到某个页面。
* 即Controller中的方法没执行,直接跳到某个页面。可给一些提示信息。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...");
return true;
}
}
```
2. 第二步:配置拦截器 在springmvc.xml中配置
``
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--要拦截的具体方法,没配置的剩下的方法就不拦-->
<mvc:mapping path="/user/*"/>
<!--不要拦截的方法,没配置的剩下的方法就拦
<mvc:exclude-mapping path=""/>-->
<!--配置我定义的拦截器对象-->
<bean class="cn.itcast.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>`
``
分析一下执行顺序:
1.JSP发送请求user/testInterceptor,请求:
Controller中的testInterceptor方法
2. 被拦截器拦截到,执行了预处理后放行,执行下一个拦截器。
3. 没有拦截器了,执行Controller中的testInterceptor方法
4. testInterceptor的方法执行完,想跳转到success.jsp页面。
发现拦截器中没有重写后处理方法,放行。
5. 顺利走到success.jsp页面。
4.3 分析一下HandlerInterceptor接口中的三个方法
Controller类中的方法:跳转到success.jsp页面
```
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/testInterceptor")
public String testException() {
System.out.println("testInterceptor执行了...");
return "success";
}
}
```
1. 预处理:不放行,转发到其他页面
```
public class MyInterceptor1 implements HandlerInterceptor {
//发现实现这个接口,却不用重写方法。里面没有方法吗?
//JDK1.8 接口增强。 接口的方法已经实现了
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...");
//如果有问题,不放行,跳转到其他页面
request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return false;
}
}
```
2.后处理
没有返回值,所以一定会向前面放行。
在前置处理放行后,Controller中的方法执行完,想要跳转到某个页面,
会被后置处理拦截到。
```
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了后置处理...");
}
```
并且如果你给他加一个跳转页面的操作,那么他就不会跳转到原来的页面了。
```
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了后置处理...");
//跳转到一个新的页面,原来的页面就不跳转了
request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
```
注意:虽然拦截器中的后处理会设置一个新的跳转页面,但是因为是从
Controller中的方法执行过来的,所以Controller中的跳转页面的操作会最
后执行,只是不跳转页面。(会执行页面中的java脚本,或者一些输出语句)
3. afterCompletion 最终处理
```
/**
* success.jsp页面执行后,该方法会执行
* 执行最终处理时,不能再跳页面了。
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了最终处理....");
}
```
注意:Controller中方法要跳转的页面执行完后,才会执行该方法
4.4 两个拦截器
1. 写两个拦截器:
1.1 拦截器1
```
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了前置处理...1111");
//如果有问题,不放行,跳转到其他页面
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了后置处理...1111");
//跳转到一个新的页面,原来的页面就不跳转了
request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行了最终处理....11111");
}
}
```
1.2 拦截器2
```
public class MyInterceptor2 implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor2执行了前置处理...2222");
//如果有问题,不放行,跳转到其他页面
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor2执行了后置处理...2222");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor2执行了最终处理....2222");
}
}
```
2. 配置两个拦截器
拦截器1,Interceptor1会先拦截,
打印:MyInterceptor1执行了前置处理...1111 然后放行。
拦截器2,Interceptor2拦截到,
打印:MyInterceptor2执行了前置处理...2222 然后放行。
执行Controller中的testException方法:
打印:testInterceptor执行了... 然后跳转success.jsp
被拦截器2又拦截到,执行后置处理:
打印:MyInterceptor2执行了后置处理...2222 继续向前走
被拦截器1又拦截到,执行后置处理:
打印:MyInterceptor1执行了后置处理...1111 跳转到响应页面
执行跳转页面上的打印输出操作
打印:error.jsp执行了
执行Controller中的testException方法要跳转的页面中的操作
打印:success.jsp执行了
执行拦截器2的最终处理:
打印:MyInterceptor2执行了最终处理....2222
执行拦截器1的最终处理:
打印:MyInterceptor1执行了最终处理....1111
```
public String testException() {
System.out.println("testInterceptor执行了...");
return "success";
}
```