There are two ways for springboot to obtain parameters through interceptors: one is through request Getparameter gets the parameters passed by Get. The other is through request Getinputstream or requests GetReader obtains the parameters passed through POST/PUT/DELETE/PATCH;
1. What are the methods for interceptors to obtain parameters
- @PathVariable annotation is a REST style url to obtain parameters. It can only be used in GET request type to obtain parameters through getParameter
- @The requestparameter annotation supports get and POST/PUT/DELETE/PATCH methods. The get method obtains parameters through getParameter and the post method obtains parameters through getInputStream or getReader
- @The RequestBody annotation supports POST/PUT/DELETE/PATCH, and parameters can be obtained through getInputStream and getReader
- The HttpServletRequest parameter can be obtained through getParameter and getInputStream or getReader
Obtaining the above parameters in the interceptor through getInputStream or getReader will cause the parameters obtained by the controller to be empty, because the flag bit of the stream has changed after the stream is read once, and the parameters cannot be read multiple times;
2. Write back the parameters after reading the parameters through the HttpServletRequestWrapper wrapper class each time
package com.sgrain.boot.common.servlet; import com.sgrain.boot.common.utils.io.IOUtils; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; /** * @Description: Rewrite HttpServletRequest, * 1,It is used to receive the data type of application/json parameter, that is, the parameter marked by @ RequestBody annotation, and solve the problem of multiple reading * 2,It is used to solve the problem of annotation @ RequestParam passing parameters through POST/PUT/DELETE/PATCH methods to solve the problem of multiple reading * First, let's take a look at the three annotations of the springboot controller: * 1,@PathVariable Annotation is a way to obtain parameters from REST style url. It can only be used in GET request type, and parameters can be obtained through getParameter * 2,@RequestParam Annotation supports get and POST/PUT/DELETE/PATCH modes. Get mode obtains parameters through getParameter and post mode obtains parameters through getInputStream or getReader * 3,@RequestBody Annotations support POST/PUT/DELETE/PATCH, and parameters can be obtained through getInputStream and getReader * @create: 2020/8/19 */ public class RequestWrapper extends HttpServletRequestWrapper { //Parameter byte array private byte[] requestBody; //Http request object private HttpServletRequest request; public RequestWrapper(HttpServletRequest request) throws IOException { super(request); this.request = request; } /** * @return * @throws IOException */ @Override public ServletInputStream getInputStream() throws IOException { /** * Each time this method is called, the data in the data stream is read out and then backfilled into the InputStream * Solve the problem that the controller cannot get the parameters after reading once through @ RequestBody and @ RequestParam (POST mode) */ if (null == this.requestBody) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); IOUtils.copy(request.getInputStream(), baos); this.requestBody = baos.toByteArray(); } final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() { return bais.read(); } }; } public byte[] getRequestBody() { return requestBody; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } }
3. After the package class of the write back parameter is written, the next step is to add it to the filter chain, as follows:
package com.sgrain.boot.web.filter; import com.sgrain.boot.common.servlet.RequestWrapper; import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; /** * @Description: Intercept all request filters and replace requests with HttpServletRequest with custom {@ link com.sgrain.boot.common.servlet.RequestWrapper} * @create: 2020/8/19 */ @Component @WebFilter(filterName = "channelFilter", urlPatterns = {"/*"}) public class ChannelFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { try { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { requestWrapper = new RequestWrapper((HttpServletRequest) request); } if (requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } catch (IOException e) { e.printStackTrace(); } catch (ServletException e) { e.printStackTrace(); } } @Override public void destroy() { } }
In this way, each request will pass through the above filter, and each HttpServletRequest request will be converted into a wrapper type RequestWrapper. In the future, we can get the parameters we want before the request reaches the controller resources;
4. The tool method for obtaining parameters in AOP interceptor (all request parameters can be obtained) is as follows:
/** * Get request input parameters * * @param request * @return */ public static Map<String, Object> getParameterMap(HttpServletRequest request) { Map<String, Object> paramMap = new LinkedHashMap<>(); if(request instanceof RequestWrapper){ RequestWrapper requestWrapper = (RequestWrapper) request; Map<String, Object> body = getParameterMap(requestWrapper.getRequestBody()); if (!CollectionUtils.isEmpty(body)) { paramMap.putAll(body); } } Enumeration<String> names = request.getParameterNames(); while (names.hasMoreElements()) { String key = names.nextElement(); paramMap.put(key, request.getParameter(key)); } return paramMap; } /** * Get parameter object * * @param params * @return */ public static Map<String, Object> getParameterMap(byte[] params) { try { return JSONUtils.toObject(params, Map.class); } catch (Exception e) { return convertParameterToMap(IOUtils.toString(params, CharsetUtils.UTF_8)); } } /** * Convert parameter type to Map * * @param param * @return */ public static Map<String, Object> convertParameterToMap(String param) { if (StringUtils.isEmpty(param)) { return Collections.emptyMap(); } Map<String, Object> pMap = Maps.newLinkedHashMap(); String[] pArray = StringUtils.split(param, CharacterUtils.AND_AIGN); for (int i = 0; i < pArray.length; i++) { String[] array = StringUtils.split(pArray[i], CharacterUtils.EQUAL_SIGN); if (array.length == 2) { pMap.put(array[0], array[1]); } } return pMap; }
GitHub source code: https://github.com/mingyang66/spring-parent/tree/master/sgrain-spring-boot-common