过滤器(Filter)
过滤器主要用于对用户请求进行预处理,也可以对响应进行后处理。例如:敏感词处理,在过滤器中定义了一些敏感词,请求内容包含这些敏感词的直接禁止访问。
过滤器应用场景
- 过滤黑名单
- 过滤敏感词汇
- 设置字符编码,对非标准编码的请求解码
- 压缩响应信息
拦截器(Interceptor)
拦截器是一种面向方面/切面编程(AOP Aspect-Oriented Programming),而面向切面就是将多个模块的通用服务进行分离,如权限管理、日志服务,这些通用服务的具体实现是通过拦截器来完成。就是在不侵入业务代码的情况下,你可以对业务代码做点你想做的事,干预业务代码的执行,甚至终止它进行!
拦截器应用场景
- 登录验证
- 权限验证
- 日志记录
过滤器与拦截器的区别
- 过滤器是基于函数回调的(职责链),而拦截器则是基于 Java 反射的;
- 过滤器依赖于 Servlet 容器,而拦截器不依赖于 Servlet 容器;
- 过滤器对几乎所有的请求起作用,而拦截器只能对 Action 请求起作用;
- 拦截器可以访问 Action 的上下文,值栈里的对象,而过滤器不能;
- 在 Action 的生命周期里,拦截器可以被多次调用,而过滤器只能在容器初始化时调用一次。
执行顺序
过滤前 -> 拦截前 -> 业务 -> 拦截后 -> 请求与响应完成 -> 过滤后
INFO 4744 --- [nio-8080-exec-1] c.c.m.f.filter.MingYueIpWordFilter : 过滤前
INFO 4744 --- [nio-8080-exec-1] c.c.m.f.interceptor.LogInterceptor : 拦截前
INFO 4744 --- [nio-8080-exec-1] c.c.m.f.interceptor.LogInterceptor : 拦截后
INFO 4744 --- [nio-8080-exec-1] c.c.m.f.interceptor.LogInterceptor : 请求与响应完成
INFO 4744 --- [nio-8080-exec-1] c.c.m.f.filter.MingYueIpWordFilter : 过滤后
SpringBoot 过滤器使用
Demo 地址:mingyue-springboot-filter-interceptor
需求:过滤
localhost/127.0.0.1
ip 的请求。
1.编写过滤器
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* Ip过滤器
*
* @author Strive
*/
@Slf4j
@Component
public class MingYueIpWordFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
/*
* 0:0:0:0:0:0:0:1 是 ipv6 的表现形式,对应 ipv4 来说相当于 127.0.0.1,也就是本机
* 禁止使用 127.0.0.1 / localhost 访问
* 这里 ip 可以换成动态黑名单 ip
*/
if ("0:0:0:0:0:0:0:1".equals(request.getRemoteHost())
|| "127.0.0.1".equals(request.getRemoteHost())) {
response.getWriter().append("Not Allowed Ip!");
log.info("Not Allowed Ip:{}!", request.getRemoteHost());
} else {
filterChain.doFilter(request, response);
}
}
}
2.编写接口
@ApiOperation("根据用户ID查询用户信息")
@GetMapping("/{userId}")
public ResponseEntity<MingYueUser> queryUserById(@PathVariable Long userId) {
return ResponseEntity.ok(mingYueUserService.queryUserById(userId));
}
3.请求接口
访问:http://127.0.0.1:8080/user/1
# 日志打印如下
c.c.m.f.filter.MingYueIpWordFilter : Not Allowed Ip:127.0.0.1!
SpringBoot 拦截器使用
Demo 地址:mingyue-springboot-filter-interceptor
1.编写拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 日志拦截器
*
* @author csp73
*/
@Slf4j
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("拦截前");
log.info("request " + request.getServletPath() + " api into");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView)
throws Exception {
log.info("拦截后");
log.info("request " + request.getServletPath() + " api start");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("请求与响应完成");
log.info("request " + request.getServletPath() + " api end");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2.注册拦截器
import com.csp.mingyue.filterAndInterceptor.interceptor.LogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Web配置
*
* @author Strive
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 将日志拦截器注册到拦截器注册表
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
3.请求接口
访问:http://127.0.0.1:8080/user/1
# 日志打印如下
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.filter.MingYueIpWordFilter : 过滤前
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : 拦截前
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : preHandle request /user/1 api into
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : 拦截后
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : postHandle request /user/1 api start
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : 请求与响应完成
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.interceptor.LogInterceptor : afterCompletion request /user/1 api end
INFO 19136 --- [nio-8080-exec-2] c.c.m.f.filter.MingYueIpWordFilter : 过滤后