过滤器和拦截器的基本知识
前提提要,由于过滤器和拦截器的相关函数是没有返回值的,所以我们像前端返回数据时需要使用到
HttpServletResponse
中的相关函数,且需要配合阿里巴巴的插件fastjson
将返回信息转为json格式,或者使用gson
转为json
- fastjson使用示例
HttpServletResponse response = (HttpServletResponse) servletResponse;
Result result = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(result);
response.getWriter().write(notLogin);
- gson使用实例:
private GSon gson;
@Test
public void testJSON()
{
String json = gson.toJson(Result.success());
System.out.println(json);
}
一、过滤器
过滤器是javaWeb的三大组件之一,所以我们在使用过滤器是需要在启动类添加注解
@ServletComponentScan
, 表明该springboot工程支持Servlet组件扫描
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import javax.servlet.annotation.WebFilter;
// 表明支持Servlet组件扫描
@ServletComponentScan
@SpringBootApplication
public class TiliasWebManagementApplication {
public static void main(String[] args) {
SpringApplication.run(TiliasWebManagementApplication.class, args);
}
}
使用过滤器我们一般需要实现三个函数,分别是
- init —>这个函数提供了默认实现,可以不实现
- doFilter -->核心函数
- destory -->同样提供了默认实现,可以不实现
1、执行流程
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
{
// filterChain.doFilter之前的操作为放行前的操作,像身份验证这些需要判断的一般都是filterChain.doFilter执行前完成的
//放行,即如果前面的过滤条件满足,则将请求发送给对应的执行函数进行后续操作
filterChain.doFilter(servletRequest, servletResponse);
// filterChain.doFilter之后的操作为放行后的操作
}
下面是一个登录验证的操作
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 获取URL
String url = request.getRequestURI().toString();
if (url.contains("login")) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}
// 获取token
String jwt = request.getHeader("token");
log.info("token = {}", jwt);
// 如果token为空,但会未登录信号
if (!StringUtils.hasLength(jwt)) {
Result result = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(result);
response.getWriter().write(notLogin);
return;
}
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("jwt令牌无效");
Result result = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(result);
response.getWriter().write(notLogin);
return;
}
//放行
filterChain.doFilter(servletRequest, servletResponse);
}
二、拦截器
拦截器的使用一般还需要配合一个配置类的使用,所以拦截器实现相较于过滤器略显复杂,但也相差无几
拦截器的使用一般需要添加一个配置类,该配置类需要实现
WebMvcConfigurer
中的addInterceptors
方法
package com.example.config;
import com.example.interceptor.LoginCheckInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置类
*/
// Configuration 设置该类为一个配置类
@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册一个拦截器,拦截除了/login之外的所有请求
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
拦截器同样有三个重要函数,实现效果跟Filter类似
- preHandle -->放行前的操作
- postHandle -->放行后的操作
- afterCompletion–>最后执行的操作
其中,拦截器更精细化的控制前端的请求
- 使用示例
package com.example.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.example.pojo.Result;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 拦截器处理逻辑
*/
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
// 目标资源方法前执行,true为方行,false为拦截
// 与doFilter的fileChain前执行的方法类似
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取token
String token = request.getHeader("token");
// 如果token为空,返回未登录信号
if(!StringUtils.hasLength(token)){
Result error = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(error);
response.getWriter().write(notLogin);
return false;
}
// 放行
return true;
}
@Override
// 目标资源方法后执行后执行
// 与doFilter的fileChain后执行的方法类似
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("afterCompletion");
}
}
需要注意的是,拦截器的放行和拦截是使用true和false来指定的,true表明放行,false表明拦截