一、过滤器 Filter (servlet的规范 在servlet之前对请求响应进行过滤)
1 filter快速入门
web包下创建filter
在App中贴注解@ServletComponentScan 通过这个注解使springboot支持filter
实现Filter接口(javax.Servlet),实现方法(init 初始化 执行一次,doFilter 每次过滤请求的时候都执行,destory 销毁 执行一次),贴注解@WebFilter
doFilter 中 过滤器是基于函数回调放行,在其之前可以写放行前的逻辑,后面可以写放行后的逻辑
@WebFilter("/*")
public class HelloFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("helloFilter初始化了!");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("helloFilter正在执行前!");
chain.doFilter(request,response);
System.out.println("helloFilter正在执行后!");
}
@Override
public void destroy() {
System.out.println("helloFilter销毁了!");
}
}
2 filter详解:
I 执行流程:
II filter链:
springboot 中谁名字在字典中谁靠前谁先执行。
3 完成登录校验:
拦截所有请求
在dofilter进行操作
拿到相关HTTP相关的 request 和response
获取请求url(uri -- 统一资源定位符即服务器资源路径(最后的请求路径)和 url -- 全路径)
判断是否为登录请求 (判断的是所有需要放行的请求)
是为登录请求,在获取令牌,放行
否为其他请求。都需要拦截(过滤)获取token 前端传过来的,必须叫token
判断令牌是否存在 -- StirngUtils.hasText()
若不存在,封装一个统一返回对象
将Java对象转换为 JSON 字符串 1 Spring --> SpringMVC 内置了 jackson --> ObjectMapper 2 FastJson --> 阿里出品。号称史上最快的转换 -- 先导入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
我们需要告诉浏览器按照JSON格式解析响应
相应转换后的JSON字符串
若存在 token 解析 token(try catch 一下)
没有异常则解析成功,可以放行其他操作
有异常在走一遍不存在
放行
二、拦截器 Interceptor(Spring 规范,经过servlet到达处理方法之前执行,对处理器方法进行拦截)
1 执行流程:
2 快速入门:
在web包下创建interceptor拦截器包
实现 handlerInterceptor
目标业务方法执行之前(preHandle)这个用的多 其中Handler是目标方法,return true放行 false拦截
true 放行 ,false 拦截
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("perHandle...");
return true;
}
}
创建config包
实现WebMvcConfigurer接口,贴Configuration注解
自动装配拦截器
重写 addInterceptors
在这里写可以注册多个拦截器 优先级是谁先写先执行谁 可以添加拦截路径和排除路径 (全部拦截是 /**)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**");
}
}
3过滤器拦截器区别:
I 使用范围:
过滤器:
-
可以过滤所有的Servlet请求,不仅限于Spring MVC的请求。
拦截器:
-
仅限于Spring MVC请求,是Spring AOP的一种实现方式
II 执行顺序:
过滤器:
-
在请求进入Servlet容器之后,进入Spring MVC的DispatcherServlet之前执行。
-
可以在请求到达Servlet之前或之后执行。
拦截器:
-
在请求进入Spring MVC的DispatcherServlet之后,但在调用具体的Controller之前执行。
-
拦截器可以在Controller方法执行之前、之后或者Controller方法抛出异常时执行。
III 配置方式:
过滤器:
-
不能在bean中
拦截器:
-
可以在bean中
次数
4 拦截器完成登录 (与过滤器差不多)
自动装配ObjectMapper
直接对目标方法进行拦截。所以直接可以获取请求头的 token
判断token是否存在
不存在,返回信息,返回false
存在,解析token
判断信息是否正确,try catch 一下
@Autowired
private ObjectMapper om;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
if (!StringUtils.hasText(token)){
ResultData resultData = ResultData.error("NOT_LOGIN");
String json = om.writeValueAsString(resultData);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return false;
}
try {
Claims claims = JWTUtils.parseJwt(token);
} catch (Exception e) {
e.printStackTrace();
ResultData resultData = ResultData.error("NOT_LOGIN");
String json = om.writeValueAsString(resultData);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return false;
}
return true;
}
四、异常处理
1 解决问题:
统一异常处理 要把所有 try catch 删掉 try catch 会覆盖 -- 解决不好维护
2 实现
web包下创建excpertion
贴注解@RestControllerAdvice = @ControllerAdvice + @ResponseBody
处理异常 -- 捕获运行是异常 贴@ExceptionHandler(RuntimeExpertion.class)
打印异常消息
返回错误信息
注:多个异常处理会由精确度更高的处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler()
public ResultData exceptionHandler(RuntimeException e){
e.printStackTrace();
return ResultData.error("服务器崩溃...请联系管理员kk...电话xxx");
}
@ExceptionHandler(ArithmeticException.class)
public ResultData exceptionHandler(ArithmeticException e){
e.printStackTrace(); // 打印异常消息
return ResultData.error("除数不能为0");
}
@ExceptionHandler(SignatureException.class)
public ResultData exceptionHandler(SignatureException e){
e.printStackTrace(); // 打印异常消息
return ResultData.error("NOT_LOGIN");
}
}