拦截器
官方文档介绍
所有实现都支持处理程序拦截器,当您要将特定功能应用于某些请求(例如,检查主体)时,这些拦截器非常有用。拦截器必须使用三种方法从包中实现,这些方法应提供足够的灵活性来执行各种预处理和后处理:HandlerMapping
HandlerInterceptor
org.springframework.web.servlet
preHandle(..)
:在运行实际处理程序之前,postHandle(..)
:运行处理程序后afterCompletion(..)
:完成请求后
拦截器如何实现
实现一个自己的拦截器,需要实现HandlerInterceptor接口。接口内的三个核心方法如下:
1.preHandle():该方法在业务处理器处理请求之前调用。主要用来进行一些前置初始化操作或者是对当前请求的预处理,也可以进行一些判断来决定请求是否要继续下去,该方法的返回值类型位boolean值,如果返回位false,就表示当前请求结束,如果返回为true,那么就会继续调用下一个Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候就会调用当前请求的 Controller 方法。
2.postHandle():这个方法在当前请求进行处理之后,也就是Controller方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView 对象进行操作。
3.afterCompletion():在postHandle执行之后执行,发生异常也会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
拦截器的代码实现
登陆拦截器
publicclassLogInterceptorextendsHandlerInterceptorAdapter {
//在执行Controller方法之前来执行的
//用于用户认证校验、用户权限校验
@Override
publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)
throwsException {
longstartTime=System.currentTimeMillis();
System.out.println("\n-------- LogInterception.preHandle --- ");
System.out.println("Request URL: "+request.getRequestURL());
System.out.println("Start Time: "+System.currentTimeMillis());
request.setAttribute("startTime", startTime);
returntrue;
}
//在执行Controller方法之后返回modelAndView之前来执行
//如果需要向页面提供一些公用的数据或配置一些视图信息,使用此方法实现从modelAndView入手
@Override
publicvoidpostHandle(HttpServletRequestrequest, HttpServletResponseresponse, //
Objecthandler, ModelAndViewmodelAndView) throwsException {
System.out.println("\n-------- LogInterception.postHandle --- ");
System.out.println("Request URL: "+request.getRequestURL());
// You can add attributes in the modelAndView
// and use that in the view page
}
//完成对页面的渲染之后执行此方法
//作系统统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间 点的差就是执行时长
//实现系统统一日志记录
@Override
publicvoidafterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, //
Objecthandler, Exceptionex) throwsException {
System.out.println("\n-------- LogInterception.afterCompletion --- ");
longstartTime= (Long) request.getAttribute("startTime");
longendTime=System.currentTimeMillis();
System.out.println("Request URL: "+request.getRequestURL());
System.out.println("End Time: "+endTime);
System.out.println("Time Taken: "+ (endTime-startTime));
}
}
鉴权拦截器
publicclassAdminInterceptorextendsHandlerInterceptorAdapter {
@Override
publicbooleanpreHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)
throwsException {
System.out.println("\n-------- AdminInterceptor.preHandle --- ");
returntrue;
}
@Override
publicvoidpostHandle(HttpServletRequestrequest, HttpServletResponseresponse, //
Objecthandler, ModelAndViewmodelAndView) throwsException {
System.out.println("\n-------- AdminInterceptor.postHandle --- ");
}
@Override
publicvoidafterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, //
Objecthandler, Exceptionex) throwsException {
System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");
}
}
拦截器添加到拦截列表
@Configuration
publicclassWebConfigimplementsWebMvcConfigurer {
@Override
publicvoidaddInterceptors(InterceptorRegistryregistry) {
// LogInterceptor apply to all URLs.
// LogInterceptor应用于所有url。
registry.addInterceptor(newLogInterceptor());
// 这个拦截器应用于/admin/*这样的URL
// Exclude /admin/oldLogin
registry.addInterceptor(newAdminInterceptor())//
.addPathPatterns("/admin/*");
}
}
业务逻辑处理Controller
@Controller
publicclassInterceptorTestController {
@RequestMapping(value= { "/", "/test" })
publicStringtest(Modelmodel) {
System.out.println("\n-------- MainController --- ");
System.out.println(" ** You are in Controller ** ");
return"test";
}
@RequestMapping(value= { "/admin/login" })
publicStringlogin(Modelmodel) {
System.out.println("\n-------- MainController.login --- ");
System.out.println(" ** You are in Controller ** ");
return"login";
}
}
流程顺序
模拟登陆拦截
配置登陆拦截器
publicclassLoginInterceptor2implements HandlerInterceptor{
@Override
publicbooleanpreHandle(HttpServletRequestrequest,
HttpServletResponseresponse, Objecthandler) throwsException {
System.out.println("preHandle方法在控制器的处理请求方法调用之前执行");
Stringuri=request.getRequestURI();
//判断当前请求地址是否登录地址
if(uri.contains("login") ||uri.contains("toLoginPage"))
{
//直接放行
returntrue;
}
else
{
//判断用户是否登录
if(request.getSession().getAttribute("userName")!=null)
//说明已经登录,放行
returntrue;
else
//没有登录,重定向到登录界面
response.sendRedirect(request.getContextPath() +"/toLoginPage");
}
//默认拦截
returnfalse;
}
@Override
publicvoidpostHandle(HttpServletRequestrequest,
HttpServletResponseresponse, Objecthandler,
ModelAndViewmodelAndView) throwsException {
System.out.println("postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行");
}
@Override
publicvoidafterCompletion(HttpServletRequestrequest,
HttpServletResponseresponse, Objecthandler, Exceptionex)
throwsException {
System.out.println("afterCompletion方法在控制器的处理请求方法执行完成后执行,即视图渲染结束之后执行");
}
}
添加登陆拦截器
@Configuration
publicclassWebConfigimplementsWebMvcConfigurer {
@Override
publicvoidaddViewControllers(ViewControllerRegistryregistry)
{
registry.addViewController("/toIndexPage").setViewName("/index");
registry.addViewController("/").setViewName("/index");
}
@Override
publicvoidaddInterceptors(InterceptorRegistryregistry) {
registry.addInterceptor(newLoginInterceptor2())
.addPathPatterns("/**") //所有路径都被拦截
.excludePathPatterns( //添加不拦截路径
"/toLoginPage", //登录页面
"/login", //登录请求
"/**/*.html", //html静态资源
"/**/*.js", //js静态资源
"/**/*.css" //css静态资源
);
}
}
controller层
@Controller
publicclassUserController {
/**
* 登录页面
*/
@RequestMapping("/toLoginPage")
publicStringtoLoginPage()
{
//跳转至登录页面
return"login.html";
}
/**
* 登录
*/
@RequestMapping(value="/login", method=RequestMethod.POST)
publicStringlogin(Modelmodel, HttpServletRequestrequest, StringuserName, Stringpassword)
{
//验证登录信息
if (userName.equals("xiaoqi") &&password.equals("123456"))
{
//验证成功,记录Session信息
request.getSession().setAttribute("userName", userName);
//重定向到首页
return"redirect:toIndexPage";
}
else
{
model.addAttribute("errorMsg", "账号或密码错误!");
}
//跳转至登录页面
returntoLoginPage();
}
/**
* 登出
*/
@RequestMapping(value="/logout")
publicStringlogout(HttpServletRequestrequest)
{
//销毁session对象
request.getSession().invalidate();
//重定向到登录页面
return"redirect:toLoginPage";
}
}
HTML页面
<!DOCTYPE html>
<htmllang="en"xmlns:th="http://www.thymeleaf.org">
<head>
<metacharset="UTF-8">
<title>用户登录</title>
</head>
<body>
<divalign="center">请输入登录信息
<formname="Mfrom"method="post"action="/login"onsubmit="SubmitLogin()">
<table>
<tr>
<td>用户姓名:</td>
<td><inputtype="text"name="userName"value="xiaoqi"class="txtBox"/></td>
</tr>
<tr>
<td>登录密码:</td>
<td><inputtype="password"name="password"value="123456"class="txtBox"/></td>
</tr>
<!-- 以下是提交、取消按钮 -->
<tr>
<td>
<inputtype="submit"value="登录"/>
</td>
<td>
<inputtype="reset"value="取消"/>
</td>
</tr>
</table>
<pstyle="color:red"th:text="${errorMsg}"></p>
</form>
</div>
</body>
<script>
//提交登录
functionSubmitLogin() {
//判断用户名是否为空
if (!Mfrom.userName.value) {
alert("请输入用户姓名!");
Mfrom.userName.focus();
returnfalse;
}
//判断密码是否为空
if (!Mfrom.password.value) {
alert("请输入登录密码!");
Mfrom.password.focus();
returnfalse;
}
returntrue;
}
</script>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
<meta name="author" content="pan_junbiao的博客">
</head>
<body>
<h1>首页</h1>
<p>当前Session中保存的登录人名称:<span th:text="${session.userName}"/></p>
<a href="logout" onclick="return confirm('确定注销吗?');">注销</a>
</body>
</html>