SpringMVC拦截器详解:原理、使用与配置
目录
1. 什么是拦截器?
2. 拦截器与过滤器的区别
3. 拦截器方法详解
4. 单个拦截器执行流程
5. 使用拦截器实现用户登录权限验证
6. 多个拦截器的执行流程
1. 什么是拦截器?
在SpringMVC框架中,拦截器(Interceptor)是一种用于拦截用户请求并进行处理的机制,类似于Servlet中的过滤器(Filter)。拦截器主要用于:
- 用户权限验证
- 用户是否登录验证
- 日志记录
- 请求的预处理和后处理等
SpringMVC的拦截器机制是可插拔的,可以在配置文件中进行灵活配置,启用或禁用某个功能的拦截器。例如,如果需要权限验证,只需在配置文件中添加拦截器;如果不需要,只需将其移除。
2. 拦截器与过滤器的区别
拦截器与过滤器在功能上相似,都是用于拦截请求并作相应处理,但它们的实现和执行流程有所不同。以下是它们的主要区别:
区别 | 过滤器 (Filter) | 拦截器 (Interceptor) |
---|---|---|
依赖关系 | 依赖于Servlet,工作在Servlet容器层 | 属于SpringMVC,工作在SpringMVC层 |
作用范围 | 对所有请求都有效 | 仅对Controller层的请求有效 |
执行顺序 | 过滤器先执行,拦截器后执行 | 拦截器在Controller方法执行前和后都可执行 |
执行顺序:
- 过滤器在请求进入Tomcat容器后、Servlet前执行。
- 拦截器则是在请求到达Controller方法前执行,在请求返回视图前以及请求处理完后执行。
3. 拦截器方法详解
自定义拦截器需要实现SpringMVC的HandlerInterceptor
接口,该接口定义了以下三个方法:
-
preHandle:在Controller方法执行之前执行。如果该方法返回
false
,请求会被拦截,不再执行后续的操作;如果返回true
,则继续执行后续操作,包括Controller方法。 -
postHandle:在Controller方法执行之后、视图渲染之前执行。可以在此方法中修改返回的Model和View,例如添加一些数据或修改视图。
-
afterCompletion:在整个请求处理完毕之后执行,用于清理资源、记录日志等。
示例代码:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle: 在Controller方法执行前");
return true; // 继续执行后续操作
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle: 在Controller方法执行后,视图返回前");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion: 请求处理完成,视图渲染后");
}
}
4. 单个拦截器执行流程
当请求到达SpringMVC时,拦截器的执行顺序如下:
- preHandle():首先执行
preHandle()
方法。如果返回false
,请求会被拦截,后续操作不会执行;如果返回true
,继续执行Controller方法。 - Controller方法:处理请求,进行相应的业务逻辑处理。
- postHandle():Controller方法执行后,执行
postHandle()
方法,此时可以操作Model和View。 - 视图渲染:DispatcherServlet将视图返回给客户端。
- afterCompletion():请求处理完毕后,执行
afterCompletion()
方法,进行资源清理、日志记录等操作。
5. 使用拦截器实现用户登录权限验证
以下是一个实现用户登录验证的例子。在SpringMVC应用中,我们可以通过自定义拦截器来检查用户是否已登录,若未登录,则拦截请求并重定向到登录页面。
1. Controller层设计
@Controller
public class LoginController {
/**
* 跳转登录页
* @return
*/
@RequestMapping(value = "/login",method = RequestMethod.GET)
public String loginPage(){
System.out.println("跳转到login.html页面当中");
return "login";
}
/**
* 用户登录,成功到主页,失败回到登录页
* @param user
* @param model
* @param session
* @return
*/
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(User user, Model model, HttpSession session){
if(user.getUsername() !=null && user.getUsername().equals("admin")
&& user.getPassword() !=null && user.getPassword().equals("123456")){
System.out.println("用户登录功能实现");
//将用户添加到session保存
session.setAttribute("user",user);
return "/suc";
}
model.addAttribute("msg","账户或密码错误,请重新登录");
return "login";
}
/**
* 跳转到主页
* @return
*/
@RequestMapping("/index")
public String indexPage(){
System.out.println("跳转到主页");
return "suc";
}
/**
* 用户退出登录
* @param session
* @return
*/
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();//清除session
System.out.println("用户退出登录");
return "login";
}
}
2. 登录拦截器设计
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = request.getRequestURI();
// 如果是非登录请求,且用户未登录,跳转到登录页面
if (!url.contains("login")) {
if (request.getSession().getAttribute("user") != null) {
return true; // 已登录,放行
} else {
request.setAttribute("msg", "您还未登录,请先登录");
request.getRequestDispatcher("/login").forward(request, response); // 跳转到登录页面
return false; // 拦截请求
}
}
return true; // 登录请求,放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 可用于对返回的视图做修改
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 可用于清理资源、记录日志等
}
}
3. 拦截器配置
在springmvc.xml
配置文件中配置拦截器:
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/> <!--/**表示所有url-->
<bean class="com.qcby.Interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
4. 登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h1> <font color="red"> <b th:text="${msg}"></b></font></h1>
<form action="/SSMDemo/login" method="post">
账户:<input type="text" name="username"/>
密码:<input type="password" name="password"/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
5.主页
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello <b th:text="${msg}"></b></h1>
<a href="/SSMDemo/logout" >入门程序</a>
</body>
</html>
6. 多个拦截器的执行流程
当有多个拦截器同时工作时,它们的执行流程如下:
- preHandle()方法按照配置的顺序执行。
- postHandle()方法和afterCompletion()方法则是按照配置的逆序执行;
即后配置的拦截器的postHandle()
和afterCompletion()
方法先执行。
示例:
假设有两个拦截器Interceptor1
和Interceptor2
,并且Interceptor1
先配置在springmvc.xml
中。它们的执行顺序如下:
Interceptor1
的preHandle()
执行Interceptor2
的preHandle()
执行- Controller方法执行
Interceptor2
的postHandle()
执行Interceptor1
的postHandle()
执行Interceptor2
的afterCompletion()
执行Interceptor1
的afterCompletion()
执行
总结
SpringMVC的拦截器为我们提供了灵活的请求处理机制,能够在请求的生命周期中进行多方面的控制,如权限验证、日志记录、性能监控等。通过实现HandlerInterceptor
接口并配置拦截器,可以轻松地在请求的不同阶段插入自定义逻辑,从而增强应用的功能和可维护性。