情况一:接口使用 @RequestParam 接收参数
情况二:接口使用 @RequestBody 接收参数
针对情况一,代码写起来就非常简单了,我们只需要在拦截器中通过request.getParameterMap() 来获得全部 Parameter 参数就可以了
但是当接口使用 @RequestBody 接收参数时,我们在拦截器中使用同样的方法获取参数,就会出现流已关闭的异常,也就导致参数读取失败了 … 这是因为 Spring 已经对 @RequestBody 提前进行处理,而 HttpServletReqeust 获取输入流时仅允许读取一次,所以会报java.io.IOException: Stream closed。
解决方法就是获取HttpServletReqeust数据将它保存下来
具体代码如下:
import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; /** * HttpServletRequest 过滤器 * 解决: request.getInputStream()只能读取一次的问题 * 目标: 流可重复读 */ @Component @WebFilter(filterName = "HttpServletRequestFilter",urlPatterns = "/") public class HttpServletRequestFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if(request instanceof HttpServletRequest) { requestWrapper = new RequestWrapper((HttpServletRequest) request); } //获取请求中的流,将取出来的字符串,再次转换成流,然后把它放入到新 request对象中 // 在chain.doFiler方法中传递新的request对象 if(null == requestWrapper) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void destroy() { Filter.super.destroy(); } /*** * HttpServletRequest 包装器 * 解决: request.getInputStream()只能读取一次的问题 * 目标: 流可重复读 */ public class RequestWrapper extends HttpServletRequestWrapper { /** * 请求体 */ private String body; public RequestWrapper(HttpServletRequest request) { super(request); body=getBody(request); } /** * 获取请求体 * @param request 请求 * @return 请求体 */ private String getBody(HttpServletRequest request) { return HttpContextUtils.getBodyString(request); } /** * 获取请求体 * @return 请求体 */ public String getBody() { return body; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { // 创建字节数组输入流 final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return bais.read(); } }; } } }
import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; public class HttpContextUtils { /** * 获取query参数 * @param request * @return */ public static MapgetParameterMapAll(HttpServletRequest request) { Enumeration parameters = request.getParameterNames(); Map params = new HashMap<>(); while (parameters.hasMoreElements()) { String parameter = parameters.nextElement(); String value = request.getParameter(parameter); params.put(parameter, value); } return params; } /** * 获取请求Body * * @param request * @return */ public static String getBodyString(ServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = request.getInputStream(); reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } }
过滤器执行之后进入到拦截器。然后拦截器根据request类型不同,解析方式也不同
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.nacos.common.utils.MapUtils; import com.alibaba.nacos.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.Map; import java.util.Set; @Component @Slf4j public class LogPrintInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI=request.getRequestURI(); StringBuffer buffer=new StringBuffer(); if(request instanceof HttpServletRequestFilter.RequestWrapper){ buffer.append(HttpContextUtils.getBodyString(request)); } if(StringUtils.isEmpty(buffer.toString())){ MapparameterMap = request.getParameterMap(); try { if (MapUtils.isNotEmpty(parameterMap)) { Set keySet = parameterMap.keySet(); for (String key : keySet) { Object values = parameterMap.get(key); try { JSONArray jsonarray = JSON.parseArray(JSON.toJSONString(values)); buffer.append(key + "->" + jsonarray + "; "); } catch (Exception e) { buffer.append(key + "->" + values + "; "); } } } } catch (Exception e) { log.error("LogPrintInterceptor print error", e); } } log.info("LogPrintInterceptor preHandle print log,requestURI={},params=[{}]",requestURI, buffer); return true; } }
打印返回参数采用继承ResponseBodyAdvice的方式来实现
import com.alibaba.fastjson.JSON; import com.techwolf.samplebase.common.resp.ApiResp; import lombok.extern.slf4j.Slf4j; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @ControllerAdvice @Slf4j public class InterceptResponse implements ResponseBodyAdvice
在AdminMvcConfig可以配置多个拦截器
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc public class AdminMvcConfig implements WebMvcConfigurer { @Autowired private LogPrintInterceptor logPrintInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(logPrintInterceptor).addPathPatterns("/api/**"); } }