SpringBoot之在拦截器获取http请求的json数据公共参数的验证

Posted zengnansheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot之在拦截器获取http请求的json数据公共参数的验证相关的知识,希望对你有一定的参考价值。

HTTP请求中的是字符串数据

//字符串读取
void charReader(HttpServletRequest request) {
    BufferedReader br = request.getReader();
    String str, wholeStr = "";
    while((str = br.readLine()) != null){
       wholeStr += str;
    }
    System.out.println(wholeStr);
}
//二进制读取
void binaryReader(HttpServletRequest request) {
     int len = request.getContentLength();
     ServletInputStream iii = request.getInputStream();
     byte[] buffer = new byte[len];
     iii.read(buffer, 0, len);
}

注意:
request.getInputStream(); request.getReader(); 和request.getParameter("key");
这三个函数中任何一个函数执行一次后(可正常读取body数据),之后再执行就无效了,比如在Controller里面就不能再调用了。

解决方法: 包装HttpServletRequest对象,缓存body数据,再次读取的时候将缓存的值写出

 

新建RequestWrapper

import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;

/**
 * @description 包装HttpServletRequest,目的是让其输入流可重复读
 **/
@Slf4j
public class RequestWrapper extends HttpServletRequestWrapper {
    /**
     * 存储body数据的容器
     */
    private final byte[] body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);

        // 将body数据存储起来
        String bodyStr = getBodyString(request);
        body = bodyStr.getBytes(Charset.defaultCharset());
    }

    /**
     * 获取请求Body
     *
     * @param request request
     * @return String
     */
    public String getBodyString(final ServletRequest request) {
        try {
            return inputStream2String(request.getInputStream());
        } catch (IOException e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取请求Body
     *
     * @return String
     */
    public String getBodyString() {
        final InputStream inputStream = new ByteArrayInputStream(body);

        return inputStream2String(inputStream);
    }

    /**
     * 将inputStream里的数据读取出来并转换成字符串
     *
     * @param inputStream inputStream
     * @return String
     */
    private String inputStream2String(InputStream inputStream) {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("", e);
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    log.error("", e);
                }
            }
        }

        return sb.toString();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream inputStream = new ByteArrayInputStream(body);

        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return inputStream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }
}

 

新建RequestWrapperFilter

import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * @description RequestWrapperFilter
 **/
@Slf4j
@WebFilter(filterName = "requestWrapperFilter", urlPatterns = "/*")
public class RequestWrapperFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("RequestWrapperFilter初始化...");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = new RequestWrapper((HttpServletRequest) request);
        chain.doFilter(requestWrapper, response);
    }

    @Override
    public void destroy() {
        log.info("RequestWrapperFilter 销毁...");
    }
}

springboot启动类增加@ServletComponentScan注解

在拦截器就可以获取请求参数了

新建一个拦截器ApiInterceptor

@Slf4j
public class ApiInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        Gson gson = new GsonBuilder().serializeNulls().enableComplexMapKeySerialization().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
        String requestUrl = request.getServletPath();
        String requestJson = new RequestWrapper(request).getBodyString();
        Map parameterMap = gson.fromJson(requestJson, Map.class);
        log.info(" 请求地址为: " + requestUrl + " 请求参数为: " + requestJson);

        try {
            if (parameterMap.get("appId") == null || parameterMap.get("appId").toString() == "") {
                responseJson(response, gson.toJson(WrapMapper.wrap(Wrapper.ERROR_CODE, "appId 参数错误或不存在")));
                return false;
            }
            return true;
        } catch (Exception e) {
            log.error(e.toString());
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }

    private void responseJson(HttpServletResponse response, String json) throws Exception {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/json; charset=utf-8");
        try {
            log.info(json);
            writer = response.getWriter();
            writer.print(json);
        } catch (IOException e) {
            log.error(e.toString());
        } finally {
            if (writer != null)
                writer.close();
        }
    }
}

 

WebMvcConfig增加拦截器配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Bean
    public ApiInterceptor getApiInterceptor() {
        System.out.println("注入了 ApiInterceptor");
        return new ApiInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 排除拦截
        String[] excludePaths = {
                "/login"
        };
        registry.addInterceptor(getApiInterceptor()).addPathPatterns("/**").excludePathPatterns(Arrays.asList(excludePaths));
    }
}

 

 

  

以上是关于SpringBoot之在拦截器获取http请求的json数据公共参数的验证的主要内容,如果未能解决你的问题,请参考以下文章

springboot通过HttpServletRequestWrapper获取所有请求参数

SpringBoot 三种拦截http请求方式Filter,interceptor和aop

获取请求未通过授权标头[关闭]

SpringBoot拦截器和 Servlet3.0自定义FilterListener

springboot请求体中的流只能读取一次的问题

Dio(Dart 的 Http 客户端)获取请求不适用于拦截器