1. 拦截器
1.1 什么是拦截器
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),用于对处理器进行预处理和后处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
1.2 拦截器/过滤器
拦截器与过滤器的区别如下:
- 拦截器是基于Java的反射机制,是AOP思想的具体应用,而过滤器是基于函数回调;
- 拦截器不依赖于servlet容器,过滤器依赖于servlet容器;
- 拦截器只能对action请求起作用,而过滤器几乎作用于所有的i请求;
- 拦截器可以访问action上下文、栈里的对象,而过滤器不行;
- 在action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次;
- 拦截器可以获取IOC容器的各个bean,而过滤器不行。
1.3 拦截器定义
在 Spring MVC 框架中定义一个拦截器需要对拦截器进行定义和配置,主要有以下 2 种方式。
- 通过实现
HandlerInterceptor
接口或继承HandlerInterceptor
接口的实现类(例如HandlerInterceptorAdapter
)来定义; - 通过实现
WebRequestInterceptor
接口或继承WebRequestInterceptor
接口的实现类来定义。
1.4 HandlerInterceptor接口
HandlerInterceptor接口主要包含三个抽象方法:
preHandle: 在控制器的处理请求方法调用之前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
**postHandle: **在控制器的处理请求方法调用之后,解析视图之前执行。
afterCompletion: 在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行,做清理工作。
该接口的实现类如下:
2. 拦截器使用
2.1 前期准备
1️⃣ Step1:给项目添加Web;
2️⃣ Step2:修改web.xml
文件,配置DispatcherServlet映射;
3️⃣ Step3:修改web.xml
文件,通过init-param
初始化参数,并指定SpringMV-Servlet配置文件
4️⃣ Step4:修改web.xml
文件,配置启动级别;
5️⃣ Step5:修改web.xml
文件,配置CharacterEncodingFilter映射;
6️⃣ Step6:修改SpringMV-Servlet配置文件,配置context自动扫描、mvc注解支持、禁止加载静态资源;
7️⃣ Step7:修改SpringMV-Servlet配置文件,配置视图解析器InternalResourceViewResolver;
2.2 实现抽象方法
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle执行了!");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle执行了!");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion执行了!");
}
}
2.3 配置XML文件
在springmvc-servlet的配置文件中需要配置定义好的拦截器。
- 所有的拦截器需要定义在
<mvc:interceptors>
标签中; <mvc:mapping path="/**"/>
:需要拦截的路径;- path:值为
/**
时表示拦截所有路径,例如/admin/**
表示拦截/admin/
下的所有路径; - path:值为
/*
时表示只拦截某包下的内容,例如/admin/*
表示拦截/admin/
下的路径, 而/admin/add/user
则不会被拦截; <bean class="xxx"/>
:需要配置的拦截器实现类。
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="Config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
2.4 编写Controller
@Controller
public class InterceptorTest {
@RequestMapping("/Test")
public String Test() {
System.out.println("控制器中的方法执行了");
return "test";
}
}
2.5 测试输出
3. 拦截器实例
下面我们来完成一个用户登录验证的例子!
JSP页面包括:login.jsp
、success.jsp
、usertest.jsp
。
Controller、Interceptor各一个:UserController
、UserInterceptor
。
3.1 前端页面
login.jsp
:用于用户登录,action中为请求路径。
${pageContext.request.contextPath}
:获取当前页面的绝对路径。
<h1>===这是登录页面===</h1>
<form action="${pageContext.request.contextPath}/user/Login">
Username:<input type="text" name="username"> <br>
Password:<input type="password" name="password"> <br>
<input type="submit" value="Submit">
</form>
success.jsp
:用户登录成功后进入该页面。
<h1>===这是成功页面===</h1>
<p>当前登录的用户为:${username}</p><br/>
<a href="${pageContext.request.contextPath}/user/Logout">退出登录</a>
usertest.jsp
:该页面用于测试拦截器是否有效。
- 若拦截器无效,可直接进入成功页面
- 若拦截器有效,则会重定向到登录页面(在拦截器中实现)
<a href="${pageContext.request.contextPath}/user/GoLogin">前往登录</a>
<a href="${pageContext.request.contextPath}/user/GoSuccess">直接进入成功页面</a>
3.2 编写Controller
Controller中包含四个方法。
login
方法说明:
- 获取前端页面提交的username、password;
- 当参数都不为空时进入成功页面,否则进入登录页面。
//登陆提交
@RequestMapping("/Login")
public String login(HttpSession session, String username, String password) throws Exception {
// 向session记录用户身份信息
System.out.println("当前登录用户:" + username);
if (!username.trim().equals("") && !password.trim().equals("")) {
session.setAttribute("username", username);
return "success";
}
return "login";
}
//跳转到登陆页面
@RequestMapping("/GoLogin")
public String userLogin() {
return "login";
}
//跳转到成功页面
@RequestMapping("/GoSuccess")
public String userSuccess() {
return "success";
}
//退出登陆
@RequestMapping("/Logout")
public String logout(HttpSession session) {
session.invalidate(); // 使session无效
return "login";
}
3.3 编写Interceptor
拦截器应用于登录验证,所以只需实现preHandle方法即可。
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果是登陆页面进来,则返回true
System.out.println("URL:" + request.getRequestURI());
if (request.getRequestURI().contains("Login")) {
return true;
}
// 如果用户登录进来,则返回true
if (request.getSession().getAttribute("username") != null){
return true;
}
// 重定向到登录页面
request.getRequestDispatcher("/jsp/login.jsp").forward(request,response);
return false;
}
}
3.4 配置Interceptor
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="Config.UserInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
3.5 测试输出
3.5.1 配置Interceptor前
3.5.2 配置Interceptor后
4. 写在最后
实现HandlerInterceptor时,其中的方法非必须实现,因此需要根据需求实现即可。