ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] # 1. 简单获取 HttpServletRequest 提供了下面 4 个方法来获取简单的请求体。 ```java //根据指定的参数名获取对应的值 //1. 如果不存在则返回 null //2. 如果存在但不设置值返回空字符串 "" //3. 如果存在相同的参数名则返回第一个的值。 String getParameter(String name) //返回相同参数名对应的值 String[] getParameterValues(String name) //返回所有的参数名 Enumeration<String> getParameterNames() //返回参数并包装为一个Map,key就是参数名 Map<String, String[]> getParameterMap() ``` 上面的 4 个基本方法有如下限制: ``` 1. 能获取拼接在url后面的参数,如username=zhangsan&password=123456789 2. 能获取请求类型为 multipart/form-data 的请求体,但是不能获取上传的文件 3. 能获取请求类型为 application/x-www-form-urlencoded 的请求体 4. 不能获取请求类型为 application/json 的请求体 ``` # 2. 允许HttpServletRequest流读取多次 HttpServletRequest 的流默认只能读取一次,如果第二次读取就会抛出异常`has already been called for this reques`。 ```java HttpServletRequest request = ... //第一次读取BufferedReader、或ServletInputStream BufferedReader reader = request.getReader(); ServletInputStream in = request.getInputStream(); //如果再读取第二次,就不行了 //BufferedReader reader = request.getReader(); //ServletInputStream in = request.getInputStream(); ``` 如果需要可以重复多次读取,可以如下封装: ```java public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { private final byte[] body; public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException { super(request); try (InputStream inputStream = request.getInputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { byte[] bytes = new byte[1024]; int len; while ((len = inputStream.read(bytes)) != -1) { buffer.write(bytes, 0, len); } body = buffer.toByteArray(); } } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); 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(); } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } } ``` 在拦截器拦截之前、或过滤器过滤之前如下覆盖默认的HttpServletRequest: ```java HttpServletRequest request = new MultiReadHttpServletRequest(request); ``` # 3. 获取application/json请求体 当请求类型为`application/json` ,`getParameterXXX`方法就不能获取请求体了,如果想要获取,可以如下获取。 ```java public class TestFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; boolean isJSON = ("" + request.getContentType()).toLowerCase().contains(MediaType.APPLICATION_JSON_VALUE); if (isJSON) { //使用上面封装的MultiReadHttpServletRequest request = new MultiReadHttpServletRequest(request); //在过滤前获取 testGetJson(request); } filterChain.doFilter(request, servletResponse); //也可以同时在响应后获取 if (isJSON) { testGetJson(request); } } private void testGetJson(HttpServletRequest request) throws IOException { BufferedReader reader = request.getReader(); StringBuilder jsonData = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { jsonData.append(line); } //去除所有的空字符串 String formatStr = jsonData.toString().replaceAll("\\s+", ""); ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> jsonMap = objectMapper.readValue(formatStr, Map.class); log.info(objectMapper.writeValueAsString(jsonMap)); } } ``` # 4. 获取multipart/form-data请求体 当请求类型为 multipart/form-data ,`getParameterXXX`方法不能获取上传的文件信息。 可以采用下面的方案来获取完整的 multipart/form-data 请求体。 ```java HttpServletRequest request = (HttpServletRequest) servletRequest; StandardServletMultipartResolver resolver = new StandardServletMultipartResolver(); if (resolver.isMultipart(request)) { MultipartHttpServletRequest multReq = resolver.resolveMultipart(request); //获取文本类型数据 for (Enumeration<String> names = multReq.getParameterNames(); names.hasMoreElements(); ) { String name = names.nextElement(); log.info("[{}={}", name, request.getParameter(name)); } //获取文件类型数据 List<MultipartFile> files = multReq.getFiles("file"); for (MultipartFile file : files) { log.info(file.getOriginalFilename()); //如果需要在多个地方存储文件,则不能调用transferTo方法,否则文件只能被存储一次就没了 //应该使用file.getInputStream()取出文件 //file.transferTo(...); try (InputStream inputStream = file.getInputStream()) { File destinationFile = new File("F:\\demo\\f_" + file.getOriginalFilename()); Files.copy(inputStream, destinationFile.toPath()); } catch (IOException e) { e.printStackTrace(); } } } ```