多次讀取請求request里數據


如果請求是GET方法,可以直接通過getParameter(String param)方法讀取指定參數,可讀取多次;

而POST方法的參數是存儲在輸入流中,只能讀一次,不能多次讀取。

有時需要在filter里打印請求參數,因而在filter里讀取post請求里的輸入流后,會導致具體的controller里拿不到請求參數。

解決方法:

  • 采用ThreadLocal,在filter里把讀取到的post參數存入ThreadLocal里,而controller就可以再從ThreadLocal里把請求參數讀取出來
  • 使用servlet提供的HttpServletRequestWrapper類,重寫相關ServletRequest方法,實現多次讀取的能力

 

1.ThreadLocal方法

ThreadLocal實現:

public class ThreadCache {
  // ThreadLocal里只存儲了簡單的String對象,也可以自己定義對象,存儲更加復雜的參數
private static ThreadLocal<String> threadLocal = new ThreadLocal<String>(); public static String getPostRequestParams{ return threadLocal.get(); } public static void setPostRequestParams(String postRequestParams){ threadLocal.set(postRequestParams); } public static void removePostRequestParams(){ threadLocal.remove(); } }

一個簡單的filter:

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by EndStart on 16/12/19.
 */
@WebFilter(value = {"/test/threadLocal/*"})
public class SimpleFilter implements Filter {
    private static Logger log = LoggerFactory.getLogger(SimpleFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        try {
            if ("POST".equals(req.getMethod().toUpperCase())) {
          // 獲取請求參數
byte[] bytes = IOUtils.toByteArray(request.getInputStream()); String params = new String(bytes, req.getCharacterEncoding()); ThreadCache.setPostRequestParams(params); log.info("filer-post請求參數:[params={}]", params); } else { log.info("非post請求"); } chain.doFilter(request, response); } catch (Exception e) { log.error(e.getMessage(), e); } } @Override public void destroy() { } }

簡單的測試controller:

import com.sankuai.xm.ems.auth.filter.ThreadCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Created by Endstart on 16/12/19.
 */
@Controller
@RequestMapping("/test")
public class TestController {
    private static Logger log = LoggerFactory.getLogger(TestController.class);

    @RequestMapping(value = "/threadLocal/getPostRequestParams",method = RequestMethod.POST)
    @ResponseBody
    public void getPostRequestParams() {
        String params = ThreadCache.getPostRequestParams();

        log.info("controller-post請求參數:[params={}]", params);
    }

}

 

這里我們只保存了post參數,從ThreadLocal中反復讀取,而get方法的還需要從request里獲取;

 

2.HttpServletRequestWrapper方法

  實現一個HttpServletRequestWrapper子類:

import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

/**
 * Created by Endstart on 16/11/30.
 */
public class WrappedHttpServletRequest extends HttpServletRequestWrapper {

    private byte[] bytes;
    private WrappedServletInputStream wrappedServletInputStream;

    public WrappedHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        // 讀取輸入流里的請求參數,並保存到bytes里
        bytes = IOUtils.toByteArray(request.getInputStream());
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);

     // 很重要,把post參數重新寫入請求流      
reWriteInputStream(); } /** * 把參數重新寫進請求里 */ public void reWriteInputStream() { wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0])); } @Override public ServletInputStream getInputStream() throws IOException { return wrappedServletInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(wrappedServletInputStream)); } /** * 獲取post參數,可以自己再轉為相應格式 */ public String getRequestParams() throws IOException { return new String(bytes, this.getCharacterEncoding()); } private class WrappedServletInputStream extends ServletInputStream { public void setStream(InputStream stream) { this.stream = stream; } private InputStream stream; public WrappedServletInputStream(InputStream stream) { this.stream = stream; } @Override public int read() throws IOException { return stream.read(); } @Override public boolean isFinished() { return true; } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { } } }

 實現另一個filter:

import com.sankuai.xm.ems.utils.wrap.WrappedHttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Created by EndStart on 16/12/19.
 */
@WebFilter(value = {"/test/wrapped/*"})
public class SimpleWrappedFilter implements Filter {
    private static Logger log = LoggerFactory.getLogger(SimpleWrappedFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        try {
            WrappedHttpServletRequest requestWrapper = new WrappedHttpServletRequest((HttpServletRequest) request);

            if ("POST".equals(requestWrapper.getMethod().toUpperCase())) {
          // 獲取請求參數 String params
= requestWrapper.getRequestParams(); log.info("filer-post請求參數:[params={}]", params); } else { log.info("非post請求"); } // 這里doFilter傳入我們實現的子類 chain.doFilter(requestWrapper, response); } catch (Exception e) { log.error(e.getMessage(), e); } } @Override public void destroy() { } }

我們在上面的TestController里加入一個新的處理方法:

    @RequestMapping(value = "/wrapped/getPostRequestParams",method = RequestMethod.POST)
    @ResponseBody
//    public void getPostRequestParams(@RequestBody String params) {
    public void getPostRequestParams(HttpServletRequest request) throws Exception{
        byte[] bytes = IOUtils.toByteArray(request.getInputStream());
        String params = new String(bytes, request.getCharacterEncoding());
        
        log.info("controller-post請求參數:[params={}]", params);
    }

這種方法里,我們在SimpleWrappedFilter里一個實現了WrappedHttpServletRequest類,其構造器自動讀取了servletRequest里的輸入流,並把數據保存了下來,最后又把數據重新寫入servletRequest里,使得cotroller可以再次從request里讀取到輸入參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM