The difference between interceptor and filter in Java and the realization of their respective functions

foreword

This blog post mainly wants to express the following aspects

  • What is a filter?
  • What is an interceptor?
  • What is the difference between filter and interceptor?
  • What are the application scenarios of filters and interceptors?
  • Use filters and interceptors to achieve functional requirements in actual development

What is a filter - Filter

Foreword: Take what you think

  • Depends on the Servlet container, implements callback function-based filtering of all requests
  • Filter is started when the web application is started, initialized only once, and destroyed when the web application is stopped.
    • Load an instance of the filter at startup and call the **init()** method to initialize the instance
    • Each request can only be processed by calling **doFilter()**
    • When the service is stopped, call destroy to destroy the instance

shortcoming

  • Can only be called once when the container is initialized

What is an interceptor - Interceptor

Forerunners: use what you use

  • Relying on the web framework and the reflection mechanism of Java is the reflection of the idea of ​​AOP
  • Based on the web framework, various dependencies in the IOC container can be called, and some business operations can be performed
  • Two ways to implement interceptors (spring)
    • Implement the HandlerInterceptor interface
    • Implement the WebRequestInterceptor interface or a class that implements WebRequestInterceptor
  • The HandlerInterceptor interface defines methods preHandle, postHandle, and afterCompletion
    • preHandle : The request method is pre-intercepted. This method will be called before Controller processing. There can be multiple Interceptors in Spring. These interceptors will be called in the order of the set Order. When an interceptor returns false in preHandle , the request will terminate
    • postHandle : When preHandle returns true, it is called after the Controller method is executed and before the view is rendered
  • afterCompletion : This method is executed after preHandle returns true and the entire request ends.

Difference Between Filter and Interceptor

same

  • All are the embodiment of AOP thought.
  • Both intercept the requested method and enhance the method

different

  • The realization principle is different

    • Filter is based on callback function
    • Interceptor based on Java reflection mechanism (dynamic proxy implementation)
  • Different scope of use

    • Filter is defined in the Servlet specification, depends on containers such as Tomcat, and can only be used in web programs
    • Interceptor is a component of spring, managed by spring and can be used alone
  • Trigger timing is different

    img/image-20211115101325025.png  0 → 100644

Interceptor function implementation

Functional requirements: Implement user login authentication

Interceptor configuration class (InterceptorConfig)

  • Generally, it is mainly used to configure the interception path/release path
  • Inject Bean, which takes effect when interception occurs. Example: LoginInterceptor below
/**
 * 拦截配置
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    
    
    @Bean
    LoginInterceptor loginInterceptor() {
    
    
        return new LoginInterceptor();
    }

    /**
     * 添加拦截路径
     * 放行拦截路径
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    

        // 拦截全部路径,这个跨域需要放在最上面
        registry.addInterceptor(corsInterceptor()).addPathPatterns("/**");

        // 拦截路径
        registry.addInterceptor(loginInterceptor()).addPathPatterns("/api/v1/pri/*/*/**")
                //放行路径
                .excludePathPatterns("/api/v1/pri/user/login", "/api/v1/pri/user/register");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}

implement interceptor

  • Implement the HandlerInterceptor interface and rewrite the method of preHandle inside

  • Here, a process of user permission verification is implemented. When the front-end sends a request to the back-end, it intercepts the request, obtains the token inside, and puts the "deciphered" token into the request field for return.

  • The sendJsonMessage class, when the verification token is null, respond directly to the front end

/**
 * 登录拦截器
 * 进入到Restcontroller之前的方法
 * @author ouj
 */
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            //从请求中获取token
            String accessToken = request.getHeader("token");
            if (accessToken == null) {
                accessToken = request.getParameter("token");
            }
            // 判断token是否为null
            if (StringUtils.isNotBlank(accessToken)) {
                Claims claims = JWTUtils.checkJWT(accessToken);
                if (claims == null) {
                    sendJsonMessage(response, "登录过期,请重新登录");
                }
                Integer id = (Integer) claims.get("id");
                String name = (String) claims.get("name");

                //在request域中把id的属性放进"User_id"中
                request.setAttribute("user_id", id);
                request.setAttribute("name", name);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 登录失败
        return false;
    }

    /**
     * 响应json数据给前端
     * @param response
     * @param obj
     */
    public static void sendJsonMessage(HttpServletResponse response, Object obj) {

        try {
            /**
             * 将数据转成Json字符串,然后以数据流的形式writer写出去
             * ObjectMapper 是Jackson库中主要用于读取和写入Json数据的类,能够很方便地将Java对象转为Json格式的数据
             * 用于后端Servlet向AJAX传递Json数据,动态地将数据展示在页面上。为了能够使用这个类,需要先下载Jackson库。
             */
            ObjectMapper objectMapper = new ObjectMapper();
            response.setContentType("application/json; charset=utf-8");
            //返回一个输出流
            PrintWriter writer = response.getWriter();
            // writeValue(参数,obj):直接将传入的对象序列化为json,并且返回给客户端
            // writeValueAsString(obj):将传入的对象序列化为json,返回给调用者
            writer.print(objectMapper.writeValueAsString(obj));
            writer.close();
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

Filter function implementation

Implement functional requirements: user verification

/**
 * 过滤器
 */
@WebFilter(urlPatterns = "/api/v1/pri/*",filterName = "loginfilter")
public class LoginFilter implements Filter {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 容器加载的时候
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("开启过滤器");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤开始");
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse rep = (HttpServletResponse) servletResponse;

        //从headers中得到token
        String token =req.getHeader("token");
        // 如果header里面没有token时,从请求的参数里面拿token
        if (StringUtils.isEmpty(token)){
            token = req.getParameter("token");
        }
        //如果还为空,直接返回json字符串或跳转index页面
        if (!StringUtils.isEmpty(token)){
            // 判断token是否合法
            //在登录时在sessionMap里存了token,通过token取出user,若为空则未登录,若不为空则显示正确
            User user = UserServiceImpl.sessionMap.get(token);
            if(user !=null){
                filterChain.doFilter(servletRequest,servletResponse);
            }else{
                JsonData jsonData = JsonData.buildError("登录失败,token无效",-2);
                //json转字符
                String jsonStr = objectMapper.writeValueAsString(jsonData);
                renderJson(rep,jsonStr);
            }
        }else {
            JsonData jsonData = JsonData.buildError("登录失败,token无效",-3);
            String jsonStr = objectMapper.writeValueAsString(jsonData);
            renderJson(rep,jsonStr);
        }
    }

    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();
        }
    }

    /**
     * 容器销毁的时候
     */
    @Override
    public void destroy() {
        System.out.println("destory LoginFilter");
    }
}

Application scenarios

  • filter
    • bytecode encoding conversion
    • Sensitive word filtering (included to prevent sql injection)
    • Permission Validation
    • Compressed response information
  • interceptor
    • Permission Validation
    • logging
    • performance monitoring
    • generic behavior
      • Read the cookie to get the user information and put the user object into the request, so as to facilitate the use of subsequent processes, as well as extracting Locale, Theme information, etc., as long as it is required by multiple processors, you can use the interceptor to achieve 5)

Guess you like

Origin blog.csdn.net/m0_49969111/article/details/121332863