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