SpringMVC拦截器
拦截器介绍
- 拦截器同过滤器一样,都是面向切面编程—AOP的具体实现,符合横切关注点的功能都可以考虑使用AOP实现;
- 可以使用Interceptor来执行某些任务,例如在Controller处理请求之前编写日志,添加或配置更新配置;
- 在Spring中,当请求发送到Controller处理之前,他必须经过Interceptor(0个或多个);
拦截器作用
- 日志记录:记录请求信息的日志,以便进行信息监控,信息统计等等;
- 权限检查:如登录检测,进入处理器检测是否登录;
- 性能监控:通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间;
- 通用行为:读取Cookie得到用户信息并将用户对象放入请求,只要是多个处理器都需要的即可使用拦截器实现;
package com.kuangstudy.config.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("1-----preHandle----->");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("3-----postHandle----->");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("4-----afterCompletion----->");
}
}
package com.kuangstudy.config.mvc;
import com.kuangstudy.config.handler.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
// 初始化拦截器放入到ioc容器中
public LoginInterceptor getLoginInterceptor(){
return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry
// 1: 拦截器注册
.addInterceptor(getLoginInterceptor())
// 2: 给拦截器配置并且定义规则
.addPathPatterns("/api/**");
}
}
拦截器链の执行顺序
根据配置的先后顺序执行preHandler, postHandle和afterCompletion则相反
自定义拦截器
这是SpringMVC的拦截器
-
自定义拦截器必须实现
HandlerInterceptor
接口或者继承HandlerInterceptorAdapter
类,并且重写三个方法:preHandler
在目标Handler方法执行前执行; 返回true执行目标方法, 返回false阻止目标方法postHandler
在目标Handler方法执行后,视图生成前执行;afterCompletion
在目标Handler方法执行后,视图生成后执行;
preHandler -(判断逻辑写在
preHandler
)-> Handler –> postHandler –> 视图 –> afterCompletion -
创建一个SpringMVC的拦截器的配置类实现WebMvcConfigurer的接口,并且重写addInterceptors()方法,注册拦截器类,并且为当前拦截器类定义规则;
-
可以在xml配置配置拦截方式;
具体实现举例
LogInterceptor
类:
public class LogInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
long startTime = 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);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- LogInterception.postHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("\n-------- LogInterception.afterCompletion --- ");
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("End Time: " + endTime);
System.out.println("Time Taken: " + (endTime - startTime));
}
}
OldLoginInterceptor
类:
public class OldLoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("\n-------- OldLoginInterceptor.preHandle --- ");
System.out.println("Request URL: " + request.getRequestURL());
System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login");
// 在控制层之前,所有请求都进入这里,被重定向到/admin/login
response.sendRedirect(request.getContextPath()+ "/admin/login");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("\n-------- OldLoginInterceptor.afterCompletion --- ");
}
}
配置拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor());
registry.addInterceptor(new OldLoginInterceptor()).addPathPatterns("/admin/oldLogin");
registry.addInterceptor(new AdminInterceptor()).addPathPatterns("/admin/*").excludePathPatterns("/admin/oldLogin");
}
}
解析:
LogInterceptor 拦截器用于拦截所有请求;
OldLoginInterceptor 用来拦截链接 “ / admin / oldLogin”,它将重定向到新的 “ / admin / login”。;
AdminInterceptor用来拦截链接 “/admin/*”,除了链接 “ / admin / oldLogin”。
自定义Controller验证拦截器
@Controller
public class LoginController {
@RequestMapping("/index")
public String index(Model model){
return "index";
}
@RequestMapping(value = "/admin/login")
public String login(Model model){
return "login";
}
}
登录检测
流程:
- 访问需要登录的资源时,由拦截器重定向到登录页面;
- 如果访问的是登录页面,拦截器不应该拦截;
- 用户登录成功后,往Cookie/session中添加登录成功的标识(如用户编号);
- 下次请求时,拦截器通过判断Cookie/session中是否有该标识来决定继续流程还是到登录页面;
- 在此拦截器还应该允许游客访问的资源(看具体业务需要);
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean flag = true;
String ip = request.getRemoteAddr();
long startTime = System.currentTimeMillis();
request.setAttribute("requestStartTime", startTime);
if (handler instanceof ResourceHttpRequestHandler) {
System.out.println("preHandle这是一个静态资源方法!");
} else if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
System.out.println("用户:" + ip + ",访问目标:" + method.getDeclaringClass().getName() + "." + method.getName());
}
//如果用户未登录
User user = (User) request.getSession().getAttribute("user");
if (null == user) {
//重定向到登录页面
response.sendRedirect("toLogin");
flag = false;
}
return flag;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (handler instanceof ResourceHttpRequestHandler) {
System.out.println("postHandle这是一个静态资源方法!");
} else if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
long startTime = (long) request.getAttribute("requestStartTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
int time = 1000;
//打印方法执行时间
if (executeTime > time) {
System.out.println("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
} else {
System.out.println("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : "
+ executeTime + "ms");
}
}
}
}
标签:拦截器,SpringMVC,request,System,println,public,out
From: https://www.cnblogs.com/code-jia/p/18070601