SpringMVC 拦截器实现原理
1、拦截器和过滤器针对功能来说十分相似,都起到过滤拦截的功能
2、区别:
1)拦截器是框架中的内容,过滤器是servlet的内容
2)拦截器对象可以使用框架容器管理,过滤器对象servlet容器管理
3)拦截器基于的是反射的方式,过滤器基于的是函数回调方式
4)执行的先后:请求—过滤器—拦截器—后端控制器—拦截器----过滤器----响应
springMVC拦截器的实现一般有两种方式
第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口
第二种方式是继承实现了HandlerInterceptor接口的类,比如Spring已经提供的实现了HandlerInterceptor接口的抽象类HandlerInterceptorAdapter
拦截器中重写的几个方法的执行情况
preHandle(): 这个方法在业务处理器处理请求之前被调用,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
postHandle():这个方法在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
afterCompletion():该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
1)自定义拦截器
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
// 实现拦截的,返回值为false不放行 ;true则放行 ---后端控制器是否被执行
System.out.println("pre...handler");
return true;
}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
//在后端控制器的方法执行完毕,还没有返回模型和视图之前执行此方法
//执行单元执行完毕,模型视图返回适配器之前,执行此方法
/*
* 执行单元
* String save(){
* xxxx
* xxxx
* xxxx
*
* return "";
* }
*
* */
//此方法适用于在后端控制器送回给适配器模型和视图之前进行模型和视图的再操作
System.out.println("post....handler");
}
@Override//相当于aop中的最终通知after
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// 当后端控制器中发生异常时,可以执行此方法
// 后端控制器不发生异常,也执行此方法
System.out.println("exception.....com");
}
}
2)配置拦截器
<mvc:interceptors>
<!-- 可以定义多个拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.offcn.interceptor.FirstInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器的使用案例 登录拦截
1)页面–登录页面
<form action="login" method="post">
<p><input type="text" name="username"></p>
<p><input type="password" name="password"></p>
<p><input type="submit" value="登录"></p>
</form>
2)执行单元—处理登录
@RequestMapping(value="/login",method = RequestMethod.POST)
public String login(String username,String password,HttpSession session) {
//通过username和password进行判断---正常,说明登录成功
//信息保存到session
session.setAttribute("username", username);
return "/WEB-INF/main.jsp";
}
3)main页面
<a href="users">这个连接需要登录成功才能操作</a>
4)执行单元—处理main页面中users请求
@RequestMapping("/users")
public String getUser() {
return "/WEB-INF/user.jsp";
}
此时没有添加拦截器,那么main页面中的请求无论是否登录都会实现请求的响应
5)添加拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object obj) throws Exception {
//做登录拦截的操作
//获取当前请求的url
String url = request.getRequestURI();
url = url.substring(url.lastIndexOf("/")+1);
if("login".equals(url)) {
return true;
}
HttpSession session = request.getSession();
String name = (String) session.getAttribute("username");
if(name != null) {
return true;
}
//原生态的响应操作,路径带有/,表示的是端口号位置,没有项目名
response.sendRedirect(session.getServletContext().getContextPath()+"/index.jsp");
return false;
}
6)拦截器配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.offcn.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
此时再测试—绕过登录,先测试没有登录,直接访问main页面中的users请求,此时拦截的,所以又返回index页面;当正常登录之后users请求才会正常响应
1975



被折叠的 条评论
为什么被折叠?



