一個請求:http://localhost:8080/FilterTest/ServletTest?name=%E4%B8%AD%E6%96%87 傳送到Web服務器是不帶編碼的,可是web容器解碼是有默認處理的編碼,Tomcat就是用"ISO-8859-1"解碼的,而後將請求交給相應的Servlet類處理。html
因此咱們能夠寫一個過濾器,在請求傳給相應的Servlet類處理以前改變其編碼。java
下面是一個簡單的Demo。web
代碼:數組
package cn.xiaol.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @date 建立時間:2016年10月15日 下午11:15:10 * @Description TODO */ public class ServletTest extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name = req.getParameter("name"); System.out.println("GET後臺打印:" + name); resp.getWriter().println("GET前臺打印" + name); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name = req.getParameter("name"); System.out.println("POST後臺打印:" + name); resp.getWriter().println("POST前臺打印" + name); } }
web.xml:服務器
<servlet> <servlet-name>ServletTest</servlet-name> <servlet-class>cn.xiaol.servlet.ServletTest</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletTest</servlet-name> <url-pattern>/ServletTest</url-pattern> </servlet-mapping>
請求後的結果:app
GET????涓枃
接下來,咱們寫一個過濾器:ide
package cn.xiaol.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; /** * @date 建立時間:2016年10月16日 上午12:51:10 * @Description 編碼過濾器 */ public class CharSetFilter implements Filter { // 默認編碼爲UTF-8 private String charset = "UTF-8"; @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 處理響應編碼,不設置的話,後臺打印顯示中文,可是返回到前臺的是亂碼 response.setContentType("text/html;charset=UTF-8"); HttpServletRequest req = (HttpServletRequest) request; if (req.getMethod().equalsIgnoreCase("GET")) { if (!(req instanceof RequestWrapper)) { // 處理Get請求編碼 // 用裝飾者request替換了本來的request,執行過濾鏈 req = new RequestWrapper(req, charset); } } else { // 處理Post請求編碼 req.setCharacterEncoding(charset); } // 用裝飾者request替換了本來的request,執行過濾鏈 chain.doFilter(req, response); } @Override public void init(FilterConfig config) throws ServletException { // 從web.xml中讀取編碼信息 String charset = config.getInitParameter("charset"); // 若是不爲空就替換咱們默認的UTF-8 if (charset != null && !charset.isEmpty()) { this.charset = charset; } } }
全部的request進來後,先判斷是否是GET請求,若是不是就直接設置編碼,放行。不然就替換成裝飾模式的RequestWrapper。之因此要替換成RequestWrapper,是由於RequestWrapper做爲裝飾者,它的大部分方法咱們都不重寫,只重寫其中咱們想要改變的方法。post
下面是RequestWrapper的代碼:this
package cn.xiaol.filter; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** * @date 建立時間:2016年10月16日 上午12:09:12 * @Description 這是使用裝飾模式後的request類 */ public class RequestWrapper extends HttpServletRequestWrapper { // 存放傳進來的HttpServletRequest對象 private HttpServletRequest request; // 編碼格式 private String charset; /** * 爲了方便設置編碼格式,增長一個編碼格式入參 * * @param request * @param charset */ public RequestWrapper(HttpServletRequest request, String charset) { // 把引用傳一份給父類,由於父類也是一個裝飾者,實現了咱們不想重寫的方法 super(request); this.request = request; this.charset = charset; } @Override public String getParameter(String key) { String value = request.getParameter(key); if (value == null)// 若是value爲null就返回null return null; try { // Get請求的時候實際上是沒有帶編碼格式的,是Web服務器,也就是Tomcat默認採用了ISO-8859-1 // 因此先用ISO-8859-1取數據,再轉爲UTF-8 return new String(value.getBytes("ISO-8859-1"), charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Map getParameterMap() { Map<String, String[]> map = request.getParameterMap(); if (map == null) { return map; } for (String key : map.keySet()) {// 遍歷全部的key String[] values = map.get(key);// 獲得key的value字符串數組 for (int i = 0; i < values.length; i++) {// 遍歷value字符串數組,設置編碼 try { values[i] = new String(values[i].getBytes("ISO-8859-1"), charset); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } } return map; } }
這裏重寫了getParameter和getParameterMap方法,由於咱們須要用這些方法得到前臺傳入的參數。編碼
web.xml:
<filter> <filter-name>CharsetFilter</filter-name> <filter-class>cn.xiaol.filter.CharSetFilter</filter-class> <!-- init-param初始化參數能夠不給,由於在Filter中設置了默認編碼爲UTF-8 --> <init-param> <param-name>charset</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharsetFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
請求後的結果:
GET前臺打印中文
最後在這裏提一下,get請求是將數據放入rul中,而後對中文進行UTF-8編碼,再進行ISO-8859-1編碼(爲了縮短字符),然傳給Web服務器。因此RequestWrapper中將傳入參數先用ISO-8859-1編碼getBytes獲得byte數組,再用UTF-8轉爲String。
而post請求,是把數據進行UTF-8編碼而後放在http請求體中傳給服務器,因此CharSetFilter中,直接req.setCharacterEncoding("UTF-8")就能夠正確顯示中文了。
下面給出完整的Demo: