浅析springboot中拦截器的使用方法
一、拦截器简介
产生背景:在面向对象开发的过程,我们可以通过继承、多态来解决纵向功能扩展问题。但是,对于横向功能扩展方面,比如给所有的服务开启事务,或者统一日志功能等,是没有办法实现的。所以就有了面向切面编程思想(AOP),它只是一种思想,是对面向对象思想的一种补充;于是就产生了拦截器,拦截器可以获取IOC容器中的任何bean;
二、拦截器功能用法
1.用法
- 定义个class类,实现HandlerInterceptor接口
- 选择拦截器中的拦截方式,并实现具体拦截内容
2.拦截方式
源码:
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
说明:
- preHandle:在业务处理前调用。属于预处理,可以进场权限校验,安全控制等处理;
- postHandle:在业务处理请求执行完成后,生成视图之前执行。属于后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView
- afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面)
三、使用实战
1.定义一个拦截器类,实现HandleInterceptor
package com.test0510.study.interceptor;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.*;
public class LoginInterceptor implements HandlerInterceptor {
/**
* 预处理拦截器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Enumeration<String> headerNames = request.getHeaderNames();
// String header = request.getHeader("ib-web");
// HttpSession session = request.getSession();
// String contextPath = request.getContextPath();
// Cookie[] cookies = request.getCookies();
// HttpServletMapping httpServletMapping = request.getHttpServletMapping();
// String queryString = request.getQueryString();
// String s = request.changeSessionId();
String requestURI = request.getRequestURI();
// 拦截,并返回拦截原因
if(requestURI.startsWith("/role/test")){
log.debug("鉴权失败,无权限的请求路径!");
this.err(response,request);
return false;
}
// 不拦截,可通过的接口
if(StringUtils.startsWithIgnoreCase(requestURI,"/learn/user")){
return true;
}
return true;
}
}
/**
* 自定义拦截器报错提示信息
* @param response
*/
private void err(HttpServletResponse response,HttpServletRequest request){
response.setContentType("application/json;charset=UTF-8");
Map<String,String> map = new HashMap<>();
map.put("code","400");
map.put("errMessage","未开通访问权限的url");
try(PrintWriter writer = response.getWriter()) {
writer.write(JSONObject.toJSONString(map));
}catch (IOException e){
log.error(request.getRequestURI()+"无权限,已被拦截");
}
}
2.向容器中注入定义的拦截器
package com.test0510.study.config;
import com.test0510.study.interceptor.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 MvcConfig implements WebMvcConfigurer {
/**
* 在springmvc容器中添加拦截器
* @return
*/
@Bean
public LoginInterceptor loginInterceptor(){
return new LoginInterceptor();
}
// 此处样例为拦截"/learn"开头的模块的url,不添加具体模块,会将swagger等测试工具也拦截掉
@Override
public void addInterceptors( InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor()).addPathPatterns("/learn/**") // 拦截learn开头的url
.order(1) // 值越小,优先级越高
.excludePathPatterns(
"/learn/hello"
,"/learn/user"
); // 排除拦截"/learn/hello","/learn/user"的url
}
}
3.结果:
- url是"/role/test"会被拦截,因为其被配置在了拦截器中;
- url是learn开头的会被拦截,但是"/learn/hello"和"/learn/user"两个url除外,注入容器的拦截方式配置了此种拦截方式;