1 SpringBoot过滤器
- 什么是过滤器
filter简单理解:⼈--->检票员(filter)---> 景点 - SpringBoot2.X⾥⾯的过滤器
ApplicationContextHeaderFilter
OrderedCharacterEncodingFilter
OrderedFormContentFilter
OrderedRequestContextFilter
- 过滤器优先级
Ordered.HIGHEST_PRECEDENCE Ordered.LOWEST_PRECEDENCE
低位值意味着更⾼的优先级 Higher values are interpreted as lower priority
⾃定义Filter,避免和默认的Filter优先级⼀样,不然会冲突 - 注册Filter配置两种⽅式
bean FilterRegistrationBean
Servlet3.0 webFileter
2 使用Servlet3.0注解开发⾃定义的过滤器
- 使⽤Servlet3.0的注解进⾏配置步骤
启动类⾥⾯增加 @ServletComponentScan,进⾏扫描
新建⼀个Filter类,implements Filter,并实现对应的接⼝
@WebFilter 标记⼀个类为filter,被spring进⾏扫描
urlPatterns:拦截规则,⽀持正则
控制chain.doFilter的⽅法的调⽤,来实现是否通过放⾏
不放⾏,web应⽤resp.sendRedirect("/index.html") 或者 返回json字符串 - 使用场景
权限控制、⽤户登录状态控制,也可以交给拦截器处理等 - 示例:用户登录过滤器
2.1 新建controller同级包filter
2.2 创建登录过滤器类LoginFilter
@WebFilter(urlPatterns = "/app/v1/pri/*", filterName = "loginFilter")
public class LoginFilter implements Filter {
private static final ObjectMapper objectMapper = new ObjectMapper(); // 处理对象与json的转换
/**
* 容器加载的时候
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init LoginFilter======");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter LoginFilter======");
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String token = req.getHeader("token");
if(StringUtils.isEmpty(token)){
token = req.getParameter("token");
}
if(!StringUtils.isEmpty(token)){
//判断token是否合法
User user = UserServiceImpl.sessionMap.get(token);
if(user!=null){
filterChain.doFilter(servletRequest,servletResponse);
} else {
// 有token,但token无效
RetData retData = RetData.RetError(-2,"登录失败,token无效");
String jsonStr = objectMapper.writeValueAsString(retData);
renderJson(resp,jsonStr);
}
}else {
// 没有登录
RetData retData = RetData.RetError(-3,"未登录");
String jsonStr = objectMapper.writeValueAsString(retData);
renderJson(resp,jsonStr);
}
}
/**
* 容器销毁的时候
*/
@Override
public void destroy() {
System.out.println("destroy LoginFilter======");
}
/**
* @param response
* @param json
*/
private void renderJson(HttpServletResponse response,String json){
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
try(PrintWriter writer = response.getWriter()){
writer.print(json);
}catch (Exception e){
e.printStackTrace();
}
}
}
2.3 测试
没有登录访问
{
"code": -3,
"data": null,
"message": "未登录"
}
错误的token访问
{
"code": -2,
"data": null,
"message": "登录失败,token无效"
}
登录之后使用正确的token访问
{
"code": 0,
"data": "下单成功!",
"message": "success"
}
3 使⽤ Servlet3.0的注解⾃定义原⽣Servlet
编写Servlet类继承HttpServlet
/**
* 使用servlet3.0开发原生接口
*/
@WebServlet(name = "userServlet", urlPatterns = "/api/v1/test/customs" )
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.write("this is my custom servlet api");
writer.flush();
writer.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
测试接口访问:结果正确输出
this is my custom servlet api
4 Servlet3.0的注解⾃定义原⽣Listener监听器
- 应用上下文监听器ServletContextListener
@WebListener
public class CustomContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("===========contextInitialized==============");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("===========contextDestroyed==============");
}
}
- 会话监听器HttpSessionLisener
@WebListener
public class CustomSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("===========sessionCreated==============");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("===========sessionDestroyed==============");
}
}
- 请求监听器ServletRequestListener
@WebListener
public class CustomRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("===========requestDestroyed==============");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("===========requestInitialized==============");
}
}
5 SpringBoot2.X拦截器配置
拦截器的作用和用法和过滤器⽤途基本类似
SpringBoot2.x使⽤步骤:
- ⾃定义拦截器 HandlerInterceptor
preHandle:调⽤Controller某个⽅法之前
postHandle:Controller之后调⽤,视图渲染之前,如果控制器Controller出现了异常,则不会执⾏此⽅法
afterCompletion:不管有没有异常,这个afterCompletion都会被调⽤,⽤于资源清理 - 配置拦截器 implements WebMvcConfigurer
有多个拦截器的情况下,按照注册顺序进⾏拦截,先注册,先被拦截
5.1 示例演示:配置登录拦截器
- 创建controller同级包intercepter
- 创建自定义拦截器类LoginIntercepter
public class LoginIntercepter implements HandlerInterceptor {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("========LoginIntercepter preHandle======");
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)){
token = request.getParameter("token");
}
if(!StringUtils.isEmpty(token)){
//判断token是否合法
User user = UserServiceImpl.sessionMap.get(token);
if(user!=null){
return true;
} else {
RetData retData = RetData.RetError(-2,"登录失败,token无效");
String jsonStr = objectMapper.writeValueAsString(retData);
renderJson(response,jsonStr);
}
}else {
RetData retData = RetData.RetError(-3,"未登录");
String jsonStr = objectMapper.writeValueAsString(retData);
renderJson(response,jsonStr);
}
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("=============postHandle=============");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=============postHandle=============");
}
/**
* 返回json数据
* @param response
* @param json
*/
private void renderJson(HttpServletResponse response,String json){
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
try(PrintWriter writer = response.getWriter()){
writer.print(json);
}catch (Exception e){
e.printStackTrace();
}
}
}
- 配置拦截器
/**
* 拦截器配置类
*/
@Configuration
public class CustomMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("==========addInterceptors=============");
registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/app/v1/pri/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
/**
* 通过bean的方式引入拦截器
* @return
*/
@Bean
public LoginIntercepter getLoginInterceptor(){
return new LoginIntercepter();
}
}
5.2 拦截器不⽣效常⻅问题:
- 是否有加@Configuration
- 拦截路径是否有问题 ** 和 *
- 拦截器最后路径⼀定要 /** 如果是⽬录的话则是 /*/
5.3 拦截器和Filter过滤器的区别
- Filter和Interceptor⼆者都是AOP编程思想的体现,功能基本都可以实现
- 拦截器功能更强⼤些,Filter能做的事情它都能做
- Filter在只在Servlet前后起作⽤,⽽Interceptor够深⼊到⽅法前后、异常抛出前后等
- filter依赖于Servlet容器即web应⽤中,⽽Interceptor不依赖于Servlet容器所以可以运⾏在
多种环境。 - 在接⼝调⽤的⽣命周期⾥,Interceptor可以被多次调⽤,⽽Filter只能在容器初始化时调⽤⼀
次。
5.4 Filter和Interceptor的执⾏顺序
- 过滤前->拦截前->action执⾏->拦截后->过滤后
5.5 如何配置不拦截某些路径?
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/v1/pri/**")
//配置不拦截某些路径,⽐如静态资源
.excludePathPatterns("/**/*.html","/**/*.js");