SpringMVC学习记录
留神:以下内容是学习 北京能源节点 的SpringMVC视频后所记录的笔记、源码以及集体的了解等,记录下来仅供学习
_
第4章 SpringMVC 核心技术
4.3 拦截器
SpringMVC 中的 Interceptor 拦截器是十分重要和相当有用的,它的次要作用是拦挡指定的用户申请,并进行相应的预处理与后处理。其拦挡的工夫点在“处理器映射器依据用户提交的申请映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前”。当然,在处理器映射器映射出所要执行的处理器类时,曾经将拦截器与处理器组合为了一个处理器执行链,并返回给了地方调度器。
4.3.1 一个拦截器的执行
自定义拦截器
package com.bjpowernode.handler;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Date;//拦截器类:拦挡用户的申请。public class MyInterceptor implements HandlerInterceptor { private long btime = 0; /* * preHandle叫做预处理办法。 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { btime = System.currentTimeMillis(); System.out.println("拦截器的MyInterceptor的preHandle()"); //计算的业务逻辑,依据计算结果,返回true或者false //给浏览器一个返回后果 //request.getRequestDispatcher("/tips.jsp").forward(request,response); return true; } /* postHandle:后处理办法。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception { System.out.println("拦截器的MyInterceptor的postHandle()"); //对原来的doSome执行后果,须要调整。 if( mv != null){ //批改数据 mv.addObject("mydate",new Date()); //批改视图 mv.setViewName("other"); } } /* afterCompletion:最初执行的办法 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("拦截器的MyInterceptor的afterCompletion()"); long etime = System.currentTimeMillis(); System.out.println("计算从preHandle到申请解决实现的工夫:"+(etime - btime )); }}
自定义拦截器,须要实现Handlerinterceptor接口。而该接口中含有三个办法:
1、 preHandle(request,response, Object handler) 预处理办法:
该办法在处理器办法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方 法,且会将afterCompletion()办法放入到一个专门的办法栈中期待执行。
重要:是整个我的项目的入口,门户。 当preHandle返回true 申请能够被解决。 preHandle返回false,申请到此办法就截止。参数: Object handler : 被拦挡的控制器对象 返回值boolean true:申请是通过了拦截器的验证,能够执行处理器办法。 拦截器的MyInterceptor的preHandle() =====执行MyController中的doSome办法===== 拦截器的MyInterceptor的postHandle() 拦截器的MyInterceptor的afterCompletion() false:申请没有通过拦截器的验证,申请达到拦截器就截止了。 申请没有被解决 拦截器的MyInterceptor的preHandle()特点: a.办法在控制器办法(MyController的doSome)之前先执行的。 用户的申请首先达到此办法 b.在这个办法中能够获取申请的信息, 验证申请是否符合要求。能够验证用户是否登录, 验证用户是否有权限拜访某个连贯地址(url)。 如果验证失败,能够截断申请,申请不能被解决。 如果验证胜利,能够放行申请,此时控制器办法能力执行。
2、postHandle(request/response/ Object handlei,modelAndView) 后处理办法:
该办法在处理器办法执行之后执行。处理器办法若最终未被执行,则该办法不会执行。 因为该办法是在处理器办法执行完后执行,且该办法参数中蕴含ModelAndView,所以该办法能够修 改处理器办法的处理结果数据,且能够批改跳转方向。
参数: Object handler:被拦挡的处理器对象MyController ModelAndView mv:处理器办法的返回值特点: a.在处理器办法之后执行的(MyController.doSome()) b.可能获取到处理器办法的返回值ModelAndView,能够批改ModelAndView中的 数据和视图,能够影响到最初的执行后果。 c.次要是对原来的执行后果做二次修改, ModelAndView mv = MyController.doSome(); postHandle(request,response,handler,mv);
3、afterCompletion(request,response, Object handler, Exception ex)最初执行的办法:
当preHandle()办法返回true时,会将该办法放到专门的办法栈中,等到对申请进行响应的所有 工作实现之后才执行该办法。即该办法是在地方调度器渲染(数据填充)了响应页面之后执行的,此 时对ModelAndView再操作也对响应杯水车薪。
afterCompletion**最初执行的办法,革除资源,例如在Controller办法中退出数据
参数 Object handler:被拦截器的处理器对象 Exception ex:程序中产生的异样 特点: a.在申请解决实现后执行的。框架中规定是当你的视图解决实现后,对视图执行了forward。就认为申请解决实现。 b.个别做资源回收工作的, 程序申请过程中创立了一些对象,在这里能够删除,把占用的内存回收。
拦截器中办法与处理器办法的执行程序如下图:
换一种体现形式,也能够这样了解:
(1) 注册拦截器
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--申明组件扫描器--> <context:component-scan base-package="com.bjpowernode.controller" /> <!--申明 springmvc框架中的视图解析器, 帮忙开发人员设置视图文件的门路--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀:视图文件的门路--> <property name="prefix" value="/WEB-INF/view/" /> <!--后缀:视图文件的扩展名--> <property name="suffix" value=".jsp" /> </bean> <!--申明拦截器: 拦截器能够有0或多个--> <mvc:interceptors> <!--申明第一个拦截器--> <mvc:interceptor> <!--指定拦挡的申请uri地址 path:就是uri地址,能够应用通配符 ** ** : 示意任意的字符,文件或者多级目录和目录中的文件 http://localhost:8080/myweb/user/listUser.do http://localhost:8080/myweb/student/addStudent.do --> <mvc:mapping path="/**"/> <!--申明拦截器对象--> <bean class="com.bjpowernode.handler.MyInterceptor" /> </mvc:interceptor> </mvc:interceptors></beans>
<mvc:mapping/>用于指定以后所注册的拦截器能够拦挡的申请门路,而 /**示意拦挡所 有申请。
(2) 批改 index 页面
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><% String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";%><html><head> <title>Title</title> <base href="<%=basePath%>" /></head><body> <p>一个拦截器</p> <form action="some.do" method="post"> 姓名:<input type="text" name="name"> <br/> 年龄:<input type="text" name="age"> <br/> <input type="submit" value="提交申请"> </form></body></html>
(3) 批改处理器
MyController.java
package com.bjpowernode.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;/** * @RequestMapping: * value : 所有申请地址的公共局部,叫做模块名称 * 地位: 放在类的下面 */@Controllerpublic class MyController { @RequestMapping(value = "/some.do") public ModelAndView doSome(String name,Integer age) { System.out.println("=====执行MyController中的doSome办法====="); //解决some.do申请了。 相当于service调用解决实现了。 ModelAndView mv = new ModelAndView(); mv.addObject("myname",name); mv.addObject("myage",age); mv.setViewName("show"); return mv; }}
(4) 批改 show 页面
show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>Title</title></head><body> <h3>/WEB-INF/view/show.jsp从request作用域获取数据</h3><br/> <h3>myname数据:${myname}</h3><br/> <h3>myage数据:${myage}</h3></body></html>
4.3.2 多个拦截器的执行
我的项目在4.3.1的根底上
我的项目构造
(1) 再定义一个拦截器
MyInterceptor2 .java
package com.bjpowernode.handler;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;//拦截器类:拦挡用户的申请。public class MyInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("22222-拦截器的MyInterceptor的preHandle()"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception { System.out.println("22222-拦截器的MyInterceptor的postHandle()"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("22222-拦截器的MyInterceptor的afterCompletion()"); }}
(2) 多个拦截器的注册与执行
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--申明组件扫描器--> <context:component-scan base-package="com.bjpowernode.controller" /> <!--申明 springmvc框架中的视图解析器, 帮忙开发人员设置视图文件的门路--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀:视图文件的门路--> <property name="prefix" value="/WEB-INF/view/" /> <!--后缀:视图文件的扩展名--> <property name="suffix" value=".jsp" /> </bean> <!--申明拦截器: 拦截器能够有0或多个 在框架中保留多个拦截器是ArrayList, 依照申明的先后顺序放入到ArrayList --> <mvc:interceptors> <!--申明第一个拦截器--> <mvc:interceptor> <mvc:mapping path="/**"/> <!--申明拦截器对象--> <bean class="com.bjpowernode.handler.MyInterceptor" /> </mvc:interceptor> <!--申明第二个拦截器--> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.bjpowernode.handler.MyInterceptor2" /> </mvc:interceptor> </mvc:interceptors></beans>
当有多个拦截器时,造成拦截器链。拦截器链的执行程序,与其注册程序统一。须要再次强调一点的是,当某一个拦截器的peHandle()办法返回 true 并被执行到时,会向一个专门的办法栈中放入该拦截器的 afterCompletion()办法。
多个拦截器中办法与处理器办法的执行程序如下图:
从图中能够看出,只有有一个preHandle()办法返回false,则上部的执行链将被断开, 其后续的处理器办法与postHandle()办法将无奈执行。但,无论执行链执行状况怎么,只有 办法栈中有办法,即执行链中只有有preHandle()办法返回true,就会执行办法栈中的 afterCompletion()办法。最终都会给出响应。
换一种体现形式,也能够这样了解:
4.3.3 公共资源
(1) pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.bjpowernode</groupId> <artifactId>ch11-interceptor2</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!--jsp依赖--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> <scope>provided</scope> </dependency> <!--springmvc依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.5.RELEASE</version> </dependency> </dependencies> <build> <plugins> <!-- 编码和编译和JDK版本 --> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build></project>
(2) web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--申明,注册springmvc的外围对象DispatcherServlet 须要在tomcat服务器启动后,创立DispatcherServlet对象的实例。 为什么要创立DispatcherServlet对象的实例呢? 因为DispatcherServlet在他的创立过程中, 会同时创立springmvc容器对象, 读取springmvc的配置文件,把这个配置文件中的对象都创立好, 当用户发动 申请时就能够间接应用对象了。 servlet的初始化会执行init()办法。 DispatcherServlet在init()中{ //创立容器,读取配置文件 WebApplicationContext ctx = new ClassPathXmlApplicationContext("springmvc.xml"); //把容器对象放入到ServletContext中 getServletContext().setAttribute(key, ctx); } 启动tomcat报错,读取这个文件 /WEB-INF/springmvc-servlet.xml(/WEB-INF/myweb-servlet.xml) springmvc创立容器对象时,读取的配置文件默认是/WEB-INF/<servlet-name>-servlet.xml . --> <servlet> <servlet-name>myweb</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--自定义springmvc读取的配置文件的地位--> <init-param> <!--springmvc的配置文件的地位的属性--> <param-name>contextConfigLocation</param-name> <!--指定自定义文件的地位--> <param-value>classpath:springmvc.xml</param-value> </init-param> <!--在tomcat启动后,创立Servlet对象 load-on-startup:示意tomcat启动后创建对象的程序。它的值是整数,数值越小, tomcat创建对象的工夫越早。 大于等于0的整数。 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myweb</servlet-name> <!-- 应用框架的时候, url-pattern能够应用两种值 1. 应用扩展名形式, 语法 *.xxxx , xxxx是自定义的扩展名。 罕用的形式 *.do, *.action, *.mvc等等 不能应用 *.jsp http://localhost:8080/myweb/some.do http://localhost:8080/myweb/other.do 2.应用斜杠 "/" --> <url-pattern>*.do</url-pattern> </servlet-mapping></web-app>