一 簡介
如題所示,有時候我們需要在一個請求到達Controller之前能夠截獲其請求,並且根據其具體情況對 HttpServletRequest 中的參數進行過濾或者修改。這時,有的同學可能會想:我們是否可以在一個Filter中將 HttpServletRequest 裡的所有參數都取出來分別進行過濾然後再放回到該HttpServletRequest 中呢。
很顯然,在 HttpServletRequest 貌似只有 setAttribute(String name, Object o) 這個方法可以設定參數,但是我們經過嘗試之後可以發現:使用 setAttribute(String name, Object o) 方法來重新設定參數顯然是不行的,因為在Controller中擷取參數本質上還是調用的ServletRequest的public String getParameter(String name) 或者 public String[] getParameterValues(String name) 方法,因此想要達到“在Filter中修改HttpServletRequest的參數”的目的,顯然是需要使用裝飾模式來複寫這些方法才行的
在正式代碼之前,我還是先簡單介紹下ServletRequest、HttpServletRequest、ServletRequestWrapper以及HttpServletRequestWrapper這幾個介面或者類之間的層次關係,並說明“繼承HttpServletRequestWrapper類以實現在Filter中修改HttpServletRequest的參數”這種方式的原理是什麼
如果我們從網上下載tomcat的原始碼並查看的話,就可以很清楚地看到這幾個類之間的層次關係了,在eclipse中看,它們之間的層次關係是這樣的:
如果這個圖表還不夠清楚地話,我還畫了一個簡單的UML結構圖:
註:因為我現在沒有下載專門的UML建模工具,因此就使用“畫圖”工具簡單地畫了一下類圖,同時這裡的ModifyParametersWrapper 是我後面舉例用到的的一個自訂的類
如果學過“裝飾模式”的童鞋可能已經發現了,上面這個關係毫無疑問是一個很標準的裝飾模式: ServletRequest 抽象組件 HttpServletRequest 抽象組件的一個子類,它的執行個體被稱作“被裝飾者” ServletRequestWrapper 一個基本的裝飾類,這裡是非抽象的 HttpServletRequestWrapper 一個具體的裝飾者,當然這裡也繼承了HttpServletRequest這個介面,是為了擷取一些在ServletRequest中沒有的方法 ModifyParametersWrapper 同樣是 一個具體的裝飾者(PS:我自訂的一個類)
註:一個標準的裝飾模式的UML類圖是這樣的:
那麼問題來了,如何在Filter中修改後台Controller中擷取到的HttpServletRequest中的參數。
答:很簡單,只需要在Filter中自訂一個類繼承於HttpServletRequestWrapper,並複寫getParameterNames、getParameter、getParameterValues等方法即可 二 代碼實現
(1)自訂的過濾器ModifyParametersFilter.java: package cn.zifangsky.filter; import java.io.IOException; import java.util.Enumeration; import java.util.Map; import java.util.Vector; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.OncePerRequestFilter; public class ModifyParametersFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ModifyParametersWrapper mParametersWrapper = new ModifyParametersWrapper(request); filterChain.doFilter(mParametersWrapper, response); } /** * 繼承HttpServletRequestWrapper,建立裝飾類,以達到修改HttpServletRequest參數的目的 */ private class ModifyParametersWrapper extends HttpServletRequestWrapper { private Map<String, String[]> parameterMap; // 所有參數的Map集合 public ModifyParametersWrapper(HttpServletRequest request) { super(request); parameterMap = request.getParameterMap(); } // 重寫幾個HttpServletRequestWrapper中的方法 /** * 擷取所有參數名 * * @return 返回所有參數名 */ @Override public Enumeration<String> getParameterNames() { Vector<String> vector = new Vector<String>(parameterMap.keySet()); return vector.elements(); } /** * 擷取指定參數名的值,如果有重複的參數名,則返回第一個的值 接收一般變數 ,如text類型 * * @param name * 指定參數名 * @return 指定參數名的值 */ @Override public String getParameter(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0) return null; else { System.out.println("修改之前: " + results[0]); return modify(results[0]); } } /** * 擷取指定參數名的所有值的數組,如:checkbox的所有資料 * 接收陣列變數 ,如checkobx類型 */ @Override public String[] getParameterValues(String name) { String[] results = parameterMap.get(name); if (results == null || results.length <= 0) return null; else { int length = results.length; for (int i = 0; i < length; i++) { System.out.println("修改之前2: " + results[i]); results[i] = modify(results[i]); } return results; } } /** * 自訂的一個簡單修改原參數的方法,即:給原來的參數值前面添加了一個修改標誌的字串 * * @param string * 原參數值 * @return 修改之後的值 */ private String modify(String string) { return "Modified: " + string; } } }
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
package cn . zifangsky . filter ; import java . io . IOException ; import java . util . Enumeration ; import java . util . Map ; import java . util . Vector ; import javax . servlet . FilterChain ; import javax . servlet . ServletException ; import javax . servlet . http . HttpServletRequest ; import javax . servlet . http . HttpServletRequestWrapper ; import javax . servlet . http . HttpServletResponse ; import org . springframework . web . filter . OncePerRequestFilter ; public class ModifyParametersFilter extends OncePerRequestFilter { @Override protected void doFilterInternal ( HttpServletRequest request , HttpServletResponse response , FilterChain filterChain ) throws ServletException , IOException { ModifyParametersWrapper mParametersWrapper = new ModifyParametersWrapper ( request ) ; filterChain . doFilter ( mParametersWrapper , response ) ; } /** * 繼承HttpServletRequestWrapper,建立裝飾類,以達到修改HttpServletRequest參數的目的 */ private class ModifyParametersWrapper extends HttpServletRequestWrapper { private Map < String , String [ ] > parameterMap ; // 所有參數的Map集合 public ModifyParametersWrapper ( HttpServletRequest request ) { super ( request ) ; parameterMap = request . getParameterMap ( ) ; } // 重寫幾個HttpServletRequestWrapper中的方法 /** * 擷取所有參數名 * * @return 返回所有參數名 */ @Override public Enumeration <String> getParameterNames ( ) { Vector <String> vector = new Vector <String> ( parameterMap . keySet ( ) ) ; return vector . elements ( |