1. 程式人生 > >關於在Spring過濾器中修改request的引數值遇到的問題(三)

關於在Spring過濾器中修改request的引數值遇到的問題(三)

  1. 繼上一遍為背景

  2. 問題描述:
    成功解密了reqeust中的引數後,在控制層Controller中獲取到的引數,是沒有解密的引數。例如:在過濾器中修改 引數名為username 的引數值432895328195783915781(一串加密的密文) 為 xiaomin(解密後的明文),在Cotroller中獲取到的依然是加密後的密文432895328195783915781。

  3. 問題定位
    百度,沒有,心酸,跑不掉,一步一步debugger,終於發現
    在SpringMVC框架中,request到controller層的資料bind(繫結)中,用到該類的方法org.springframework.web.method.annotation.RequestParamMethodArgumentResolver

    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        MultipartHttpServletRequest multipartRequest =
                WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
        Object arg; // 將被繫結的值
    . . . if (multipartRequest != null) { List<MultipartFile> files = multipartRequest.getFiles(name); if (!files.isEmpty()) { arg = (files.size() == 1 ? files.get(0) : files); } } if (arg == null) { // 方法走了該判斷體 String[] paramValues = webRequest.getParameterValues(name); if
    (paramValues != null) { arg = (paramValues.length == 1 ? paramValues[0] : paramValues); } } }

    如上註釋,方法在一定條件下走了String[] paramValues = webRequest.getParameterValues(name);這一段程式碼,debugger發現,
    這段程式碼走的的真正實現竟然是web容器Tomcat提供的request包裝類org.apache.catalina.connector.RequestFacade中的方法。(因為這裡的WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class)最後返回了一個Tomcat提供的request包裝類)

     @Override
    public String[] getParameterValues(String name) {
    
        if (request == null) {
            throw new IllegalStateException(
                            sm.getString("requestFacade.nullRequest"));
        }
    
        String[] ret = null;
        if (SecurityUtil.isPackageProtectionEnabled()){
            ret = AccessController.doPrivileged(
                new GetParameterValuePrivilegedAction(name));
            if (ret != null) {
                ret = ret.clone();
            }
        } else {
            ret = request.getParameterValues(name);
        }
    
        return ret;
    }

    而該Tomcat的request包裝類中的引數,確實是沒有解密之前的值。由此猜測(個人猜測,不對的請指點迷津,感激) 1.伺服器在接受請求時,Spring和Tomcat各自都建立了一個request的包裝類(可以發現都實現了HttpServletRequest介面),在沒有修改rquest引數時,這兩個包裝類幾乎一樣(指引數值都是一致的),當我在過濾器中修改了Spring的rquest包裝類引數值,tomcat的request包裝類是沒有修改的。2.在SpringMVC的資料繫結中,應為某些原因,需要從tomcat的request包裝類中獲取引數值。這就導致了上述問題的發生。

    4.解決方案
    在之前的自定義包裝類中(繼承了ServletRequestWrapper)重寫 getParameterValues(String name)方法

    import org.apache.catalina.util.ParameterMap;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.util.Map;
    
    public class ParameterRequestWrapper extends HttpServletRequestWrapper {
    
        private ParameterMap<String, String[]> params;
    
        @SuppressWarnings("all")
        public ParameterRequestWrapper(HttpServletRequest request) {
            super(request);
            params = (ParameterMap) request.getParameterMap();
            // TODO Auto-generated constructor stub
        }
    
        @Override
        public String getParameter(String name) {
            // TODO Auto-generated method stub
            String[] values = params.get(name);
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }
    
        @Override
        public Map<String, String[]> getParameterMap() {
            // TODO Auto-generated method stub
            return params;
        }
    
        // 就是該方法
        @Override
        public String[] getParameterValues(String name) {
            return params.get(name);
        }
    
        public void addParameter(String name, Object value) {
            if (value != null) {
                params.setLocked(false);
                if (value instanceof String[]) {
                    params.put(name, (String[]) value);
                } else if (value instanceof String) {
                    params.put(name, new String[] { (String) value });
                } else {
                    params.put(name, new String[] { String.valueOf(value) });
                }
                params.setLocked(true);
            }
        }
    }
    

    解決問題,如有不對的地方,還請高人路過指點。