开始时间:2022-02-22
课程链接:动力节点SpringMVC课程
拦截器
拦截器:
1)拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。
2)拦截器和过滤器类似,功能方向侧重点不同。 过滤器是用来过滤器请求参数,设置编码字符集等工作。
拦截器是拦截用户的请求,做请求做判断处理的。
3)拦截器是全局的,可以对多个Controller做拦截。
一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
拦截器常用在:用户登录处理,权限检查, 记录日志。
拦截器的使用步骤:
1.定义类实现HandlerInterceptor接口
2.在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在。
拦截器的执行时间:
1)在请求处理之前, 也就是controller类中的方法执行之前先被拦截。
2)在控制器方法执行之后也会执行拦截器。
3)在请求处理完成后也会执行拦截器。
拦截器:看做是多个Controller中公用的功能,集中到拦截器统一处理。使用的aop的思想
拦截器使用步骤
1.新建maven web项目
2.加入依赖
3.创建Controller类
4.创建一个普通类,作为拦截器使用
1)实现HandlerInterceptor接口
2)实现接口中的三个方法
5.创建show.jsp
6.创建springmvc的配置文件
1)组件扫描器 ,扫描@Controller注解
2)声明拦截器,并指定拦截的请求uri地址
按照这个是顺序来写
MyController类
public 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;
}
}
创建拦截器
package BUPT.handler;
import...;
//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {
//private long btime = 0;
/*
* preHandle叫做预处理方法。
* 重要:是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。
* preHandle返回false,请求到此方法就截止。
* 参数:
* Object handler : 被拦截的控制器对象
* 返回值boolean
* true:请求是通过了拦截器的验证,可以执行处理器方法。
* 拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptor的postHandle()
拦截器的MyInterceptor的afterCompletion()
*
* false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
* 拦截器的MyInterceptor的preHandle()
* 特点:
* 1.方法在控制器方法(MyController的doSome)之前先执行的。
* 用户的请求首先到达此方法
*
* 2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
* 可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
* 如果验证失败,可以截断请求,请求不能被处理。
* 如果验证成功,可以放行请求,此时控制器方法才能执行。
*/
预处理方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//btime = System.currentTimeMillis();
System.out.println("拦截器的MyInterceptor的preHandle()");
//计算的业务逻辑,根据计算结果,返回true或者false
return true;
}
预处理方法返回false
此时就只能转到tip里面而没办法转发到dosome那里去
@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 false;
}
后处理方法:主要是对原来的执行结果做二次修正
转发到的是other视图
/*
postHandle:后处理方法。
参数:
Object handler:被拦截的处理器对象MyController
ModelAndView mv:处理器方法的返回值
特点:
1.在处理器方法之后执行的(MyController.doSome())
2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
数据和视图,可以影响到最后的执行结果。
3.主要是对原来的执行结果做二次修正,
ModelAndView mv = MyController.doSome();
postHandle(request,response,handler,mv);
*/
@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
特点:
1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收
/*
afterCompletion:最后执行的方法
参数
Object handler:被拦截器的处理器对象
Exception ex:程序中发生的异常
。
*/
@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 ));
}
}
我们这里得到结果
计算从preHandle到请求处理完成的时间:199
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>
配置文件
组件扫描器
<?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="BUPT.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
user开头的都拦截下来
-->
<mvc:mapping path="/**"/>
<!--声明拦截器对象-->
<bean class="BUPT.handler.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
可以观察到执行顺序
拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
拦截器的MyInterceptor的postHandle()
拦截器的MyInterceptor的afterCompletion()
多个拦截器
再定义一个拦截器MyInterceptor2
执行顺序按照在SpringMVC里面的配置顺序来的
因为传回去是一个ArrayList,顺序就是配置顺序
package BUPT.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()");
}
}
并给他进行注册
<mvc:interceptors>
<!--声明第一个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--声明拦截器对象-->
<bean class="BUPT.handler.MyInterceptor" />
</mvc:interceptor>
<!--声明第二个拦截器-->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="BUPT.handler.MyInterceptor2" />
</mvc:interceptor>
</mvc:interceptors>
此时preHandle两个拦截器都是true
得到运行结果
111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
=====执行MyController中的doSome方法=====
22222-拦截器的MyInterceptor的postHandle()
111111-拦截器的MyInterceptor的postHandle()
22222-拦截器的MyInterceptor的afterCompletion()
111111-拦截器的MyInterceptor的afterCompletion()
执行顺序如图
考虑情况
拦截器1为真,2 为假
111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
111111-拦截器的MyInterceptor的afterCompletion()
考虑情况
拦截器1为假,2为真/假
111111-拦截器的MyInterceptor的preHandle()
只要有一个 preHandle()方法返回 false,则上部的执行链将被断开,
其后续的处理器方法与 postHandle()方法将无法执行。但,无论执行链执行情况怎样,只要
方法栈中有方法,即执行链中只要有 preHandle()方法返回 true,就会执行方法栈中的
afterCompletion()方法。最终都会给出响应。
拦截器和过滤器的区别
拦截器和过滤器的区别
1.过滤器是servlet中的对象, 拦截器是框架中的对象
2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
拦截器是用来验证请求的,能截断请求。
4.过滤器是在拦截器之前先执行的。
5.过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
6.过滤器是一个执行时间点。
拦截器有三个执行时间点
7.过滤器可以处理jsp,js,html等等
拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
登录验证拦截器
ch12-interceptor-permission: 使用拦截器检查登录的用户是不是能访问系统
实现步骤:
1.新建maven
2.修改web.xml注册中央调度器
3.新建index.jsp发起请求
4.创建MyController处理请求
5.创建结果show.jsp
6.创建一个login.jsp,模拟登录(把用户的信息放入到session);
创建一个jsp, logout.jsp,模拟退出系统(从session中删除数据)
7.创建拦截器,从session中获取用户的登录数据,验证能否访问系统
8.创建一个验证的jsp,如果验证视图,给出提示
9.创建springmvc配置文件
声明组件扫描器
声明拦截器
这个功能我要说明下
就是说
我最开始如果直接在index界面上输入姓名和年龄
无论我输入的姓名是否是zs,我都进不去,因为他这里的判断逻辑是session里面有没有携带zs
而当我直接在浏览器中输入
http://localhost:8080/ch12_interceptor_permission/login.jsp
进入了一次login.jsp,模拟了登录成功(这里的登录成功不是从index里面来的,是直接输入的网址)
此时
我再到index界面后,无论输入是否是zs,都能进去得到信息了
相当于进入了一次login,获取了管理员权限,此时都可以操作
那想取消权限,就在浏览器中输入
http://localhost:8080/ch12_interceptor_permission/logout.jsp
这样来看再从index里面进去,输入什么都不行了
很多代码都是重复的
下面给些不重复的
MyInterceptor
package BUPT.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 {
//验证登录的用户信息, 正确return true,其它return false
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("111111-拦截器的MyInterceptor的preHandle()");
String loginName = "";
//从session中获取name的值
Object attr = request.getSession().getAttribute("name");
if( attr != null){
loginName = (String)attr;
}
//判断登录的账户,是否符合要求
if( !"zs".equals(loginName)){
//不能访问系统
//给用户提示
request.getRequestDispatcher("/tips.jsp").forward(request,response);
return false;
}
//zs登录
return true;
}
}
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
模拟登录,zs登录系统
<%
session.setAttribute("name","zs");
%>
</body>
</html>
logout.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
退出系统,从session中删除数据
<%
session.removeAttribute("name");
%>
</body>
</html>
tips.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
tips.jsp 非zs不能访问系统
</body>
</html>
第一次访问
然后让其登录一次
再退出一次
就不能进去了
总结SpringMVC流程
(1)浏览器提交请求到中央调度器(index.jsp中的some.do)
(2)中央调度器直接将请求转给处理器映射器。
(3)处理器映射器会根据请求,找到处理该请求的处理器,并将其封装为处理器执行链后
返回给中央调度器。(MyController中的doSome)
(4)中央调度器根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器。
(5)处理器适配器调用执行处理器。
(6)处理器将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给
处理器适配器。(doSome返回mv)
(7)处理器适配器直接将结果返回给中央调度器。
(8)中央调度器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
(9)视图解析器将封装了的视图对象返回给中央调度器(springmvc.xml中的视图解析器)
(10)中央调度器调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
(11)中央调度器响应浏览器。(show.jsp)
或者说
SpringMVC内部请求的处理流程:
- 用户发起请求some.do
- DispatcherServlet接收请求some.do,把请求转交给处理器映射器
- 处理器映射器:springmvc框架中的一种对象,框架把实现了HandlerMapping接口的类都叫做映射器(多个)
处理器映射器作用;根据请求,从SpringMVC容器对象中获取处理器对象(MyController controller=ctx.getBean(“some.do”),框架把找到的处理器对象放到一个叫做处理器执行链(HandletExecutionChain)的类保存
HandlerExecutionChain类中保存着:处理器对象(MyController)以及项目中的所有拦截器List<HandlerInterceptors>
- DispatcherServlet把2中的HandlerExecutionChain中的处理器对象交给了处理器适配器对象(多个)
处理器适配器:springMVC框架中的对象,需要实现HandlerAdapter接口
适配器作用:执行处理器方法(调用MyControllerl.doSome()得到返回值ModelAndView) - DispatcherServlet把3中获取的ModelAndView交给了视图解析器对象
视图解析器:springmvc中的对象,需要实现viewResoler接口(可以有多个)
视图解析器作用:组成视图完整路径,使用前缀,后缀。并创建view对象。
View是一个接口,表示视图的,在框架中jsp,html不是string表示,而是使用view和他的实现类表示视图。
InternalResourceView:视图类,表示jsp文件,视图解析器会创建InternalResourceView类对象。
这个对象里面有一个属性url=/WEB-INF/view/show.jsp - DispatcherServlet把4步骤中创建的view对象获取到,调用view类自己的方法,把Modiel数据放入到request作用域。执行对象视图的forward。请求结束。
结束时间:2022-02-23