SpringBoot 自定义过滤的使用:
- (1)@WebFilter注解标记一个类为filter,并被spring进行扫描
- (2)主启动类上面加一个@ServletComponentScan注解,进行扫描
- (3) 非前后端分离项目适用,前后端分离项目,可以使用拦截器
- (4) 拦截器和过滤器区别:最明显的区别:过滤器可以过滤所有资源,拦截器只能拦截请求!
1. 自定义过滤器
package com.example.lchtest.springbootdemo1.customfilter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义过滤器
*/
//@WebFilter(urlPatterns = "/*",filterName = "loginFilter") // urlPatterns如果是配置成/*则是拦截所有请求
@WebFilter(urlPatterns = "/api/*",filterName = "loginFilter")
public class LoginFilter implements Filter {
/**
*
* @param filterConfig 过滤器配置
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
System.out.println("自定义过滤器执行doFilter逻辑.");
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;
String username = req.getParameter("username");
if(username.equals("test")){
filterChain.doFilter(req, resp);
} else {
// 使用response.sendRedirect,login.html放在resources/static下面才可以,放到templates目录下不行,使用modelAnaView返回逻辑视图名可以跳到templates目录下,why??
resp.sendRedirect("/login.html");
}
}
@Override
public void destroy() {
System.out.println("LoginFilter destroy");
}
}
在上面的自定义过滤器中,检测url中的username,如果为test则校验通过,如果为其他的值,则校验不通过,重定向到login.html :
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>error</title>
</head>
<body>
<h2>过滤器测试,过滤器中校验不通过,重定向到该页面!</h2>
</body>
</html>
2. 自定义拦截器
(1)自定义的拦截器,实现HandlerInterceptor 接口,重写preHandle/ postHandle / afterCompletion方法,定制业务逻辑
(2) 编写一个配置类,实现WebMvcConfigurer 接口,
package com.example.lchtest.springbootdemo1.custominterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* 自定义拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
/**
* 进入controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("自定义拦截器 preHandle");
// 拦截器业务处理逻辑
String username = request.getParameter("username");
if("test2".equals(username)){
return true;
} else {
PrintWriter writer = response.getWriter();
String result = "{\"errMsg\":\"user unAuthorized\", \"retCode\":\"401\"}";
writer.print(result);
writer.flush();
writer.close();
return false;
}
}
/**
* 调用完controller执行,视图渲染之前,如果controller中出现异常,postHandle不会被执行 afterCompletion
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("自定义拦截器 postHandle");
}
/**
* 整个controller完成之后;不管有没有异常,afterCompletion都会被调用,通常用于资源清理
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("自定义拦截器 afterCompletion");
}
}
package com.example.lchtest.springbootdemo1.custominterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置自定义拦截器的url并注册到springMVC中,加上@Configuration注解
*/
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// /*是拦截目录,/**才是拦截url路径
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/api2/*/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
测试controller:自定义过滤器对/api/xx 的请求进行处理,自定义拦截器对api2/xx 的请求进行拦截处理
package com.example.lchtest.springbootdemo1.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 登录控制器:用于测试自定过滤器和自定义拦截器
* 自定义过滤器对/api/*的请求进行处理
* 自定义拦截器对api2/*的请求进行拦截处理
*/
@RestController
public class CustomFilterController {
/**
* 自定义过滤器测试
* http://localhost:8080/api/testFilter?username=test 直接返回,改变username的值,则返回login.html
* @param username
* @return
*/
@GetMapping("/api/testFilter")
public String testFilter(@RequestParam("username") String username){
System.out.println("username=" + username);
return "testFilter Success";
}
/**
* 自定义拦截器测试
* http://localhost:8080/api2/testInterceptor?username=test2 username改为其他值,返回{errMsg=user unAuthorized, retCode=401}
* @param username
* @return
*/
@GetMapping("/api2/testInterceptor")
public String testInterceptor(@RequestParam("username") String username){
System.out.println("username=" + username);
return "testInterceptor Success";
}
/**
* 自定义拦截器,不管controlelr中有无异常,拦截器中的afterCompletion方法都会执行
* http://localhost:8080/api2/testException?username=test2
* @param username
* @return
*/
@GetMapping("/api2/testException")
public String testInterceptor2(@RequestParam("username") String username){
System.out.println("username=" + username);
int i = 1/0;
return "testInterceptor Success";
}
/**
* *********requestInitialized *********
* 2020-01-01 14:15:57.217 INFO 12208 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
* 2020-01-01 14:15:57.217 INFO 12208 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
* 2020-01-01 14:15:57.219 INFO 12208 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
* 自定义拦截器 preHandle
* username=test2
* 2020-01-01 14:15:57.278 WARN 12208 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [java.lang.ArithmeticException: / by zero]
* 自定义拦截器 afterCompletion
* *********requestDestroyed *********
*/
}
自定义过滤器测试结果:username为test时,校验通过,返回字符串,为其他值时,校验失败,重定向到指定页面
自定义拦截器测试:username为test2时,校验通过,执行后续的逻辑,为其他值时,返回校验不通过的json串
需要注意的是,自定义的拦截器,不管controlelr中有无异常,拦截器中的afterCompletion方法都会执行!