您好,欢迎来到汇意旅游网。
搜索
您的当前位置:首页在自定义HandlerInterceptor中 方法执行之后获取响应体参数

在自定义HandlerInterceptor中 方法执行之后获取响应体参数

来源:汇意旅游网

需求描述

通过自定义的对部分接口的返回添加缓存,请求接口和参数作为redisKey
假设自定义 MyHandlerInterceptor 对部分接口进行拦截, 我们需要实现HandlerInterceptor 接口并重写 其中的部分方法如下:

@Component
public class MyHandlerInterceptor implements HandlerInterceptor {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
	@Override
	 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		String eid = request.getParameter("eid");
		// 获取对应参数 的缓存
		 String redisKey = getRedisKey(request);
        String s = stringRedisTemplate.opsForValue().get(redisKey);
        if(StringUtils.isNotBlank(s)){
             ResponseData responseData = JSONObject.parseObject(s, ResponseData.class);
             // 直接返回前端
             result(response,responseData);
             return false;
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
		}
		//在afterCompletion 方法中 获取到 方法执行后的响应体,判断如果执行成功则 生成对应key  和 对应结果,存入redis 中
	
	@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String eid = request.getParameter("eid");
        String responseBody = ContentCachingWrapperFilter.getResponseBody(response);
        ResponseData responseData = JSONObject.parseObject(responseBody, ResponseData.class);
        if(responseData.getCode() == 1){
            String redisKey = getRedisKey(request);
            stringRedisTemplate.opsForValue().set(redisKey,JSONObject.toJSONString(responseData), 30, TimeUnit.MINUTES);
        }
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
        public String getRedisKey(HttpServletRequest request){
        Map<String, String[]> parameterMap = request.getParameterMap();
        List<String> resultList = new ArrayList<>();
        parameterMap.forEach((s, strings) -> {
            for (String string : strings) {
                if(StringUtils.isNotBlank(string)){
                    resultList.add(string);
                }
            }
        });
        // 参数排序
        List<String> collect = resultList.stream().sorted().collect(Collectors.toList());
        String join = StringUtils.join(collect, "_");
       return request.getRequestURI()+"_"+ join;
    }
 // 直接返回响应体给前端
    public static void result(HttpServletResponse response, ResponseData result) {
        try {
            response.setContentType("text/json");
            response.setCharacterEncoding("UTF-8");
            PrintWriter write = response.getWriter();
            String s = JSONUtil.toJsonStr(result);
            write.write(s);
            write.flush();
            write.close();
        } catch ( IOException e ) {
            e.printStackTrace();
        }
    }
}

以上代码关键在于如何在 afterCompletion 方法中获取到相应参数

String responseBody = ContentCachingWrapperFilter.getResponseBody(response);

借助以下工具类

package com.boshiyun.application.intercept;


import org.apache.commons.io.IOUtils;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * 缓存请求体和响应体过滤器
 *
 * <p>
 * 由于 requestBody 和 responseBody 分别对应的是 InputStream 和 OutputStream,由于流的特性,读取完之后就无法再被使用了。
 * 所以,需要额外缓存一次流信息。
 * </p>
 *
 * @author Charles7c
 * @since 2022/9/22 16:33
 */
@Component
public class ContentCachingWrapperFilter extends OncePerRequestFilter implements Ordered {

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE - 10;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        // 包装流,可重复读取
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }

        filterChain.doFilter(request, response);
        updateResponse(response);
    }

    /**
     * 更新响应(不操作这一步,会导致接口响应空白)
     *
     * @param response 响应对象
     * @throws IOException /
     */
    private void updateResponse(HttpServletResponse response) throws IOException {
        ContentCachingResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        Objects.requireNonNull(responseWrapper).copyBodyToResponse();
    }

    /**
     * 获取请求体
     *
     * @param request 请求对象
     * @return 请求体
     */
    public static String getRequestBody(HttpServletRequest request) throws IOException {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8.toString());
        }
        return requestBody;
    }

    /**
     * 获取响应体
     *
     * @param response 响应对象
     * @return 响应体
     */
    public static String getResponseBody(HttpServletResponse response) throws IOException {
        String responseBody = "";
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8.toString());
        }
        return responseBody;
    }
}


requestBody 和 responseBody 分别对应的是 InputStream 和 OutputStream,由于流的特性,读取完之后就无法再被使用了。以上的逻辑就是起到 流的重复使用

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- hids.cn 版权所有 赣ICP备2024042780号-1

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务