以前就聽說javaweb中的過濾器可以修改請求過來和響應回去的數據,請求過來的數據修改比較簡單,在此主要討論的是響應回去的數據,咱們如何修改?
tomcat源碼中提供了一個類HttpServletResponseWrapper,該類實際上實現了HttpServletResponse接口,也就是過濾器中直接封裝該類的子類就可以調用,以下是該類部分源碼。
public class HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse { public HttpServletResponseWrapper(HttpServletResponse response) { super(response); } private HttpServletResponse _getHttpServletResponse() { return (HttpServletResponse)super.getResponse(); }
還記得輸出時是通過response.getOutputStream()或者resp.getWriter()獲取的輸出流,然后將需要返回的數據寫入數據流中;我們可以拿到這兩個輸出流,但是這兩個流都是包裝流,數據沒辦法直接從這兩個輸出流中讀取出來,這該如何解決?那我們能不能自己封裝這樣的一個接口呢,看下面的代碼:
package com.asiainfo.wrapper; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; /** * 返回值輸出代理類 * @author Administrator * */ public class ResponseWrapper extends HttpServletResponseWrapper { // 真正緩存數據的流 private ByteArrayOutputStream buffer = null; private ServletOutputStream out = null; private PrintWriter writer = null; public ResponseWrapper(HttpServletResponse response) { super(response); // TODO Auto-generated constructor stub buffer = new ByteArrayOutputStream(); out = new WrapperOutputStream(buffer); writer = new PrintWriter(buffer); } /** * 當獲取字節輸出流時,實際獲取的是我們自己包裝的字節輸出流 */ public ServletOutputStream getOutputStream() { return out; } /** * 當獲取字符輸出流時,實際獲取的是我們自己包裝的字符輸出流 */ public PrintWriter getWriter() { return writer; } public void flushBuffer() throws IOException { if (out != null) { out.flush(); } if (writer != null) { writer.flush(); } } public byte[] getResponseData() throws IOException { flushBuffer(); return buffer.toByteArray(); } public String getContent() throws IOException { flushBuffer(); return buffer.toString(); } } class WrapperOutputStream extends ServletOutputStream { private OutputStream out; public WrapperOutputStream(OutputStream out) { super(); this.out = out; } @Override public void write(int b) throws IOException { // TODO Auto-generated method stub out.write(b); } }
寫一個servlet處理調用請求
package com.asiainfo.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/demo") public class FrontServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub ServletOutputStream outputStream = resp.getOutputStream(); resp.setContentType("application/json;charset=UTF-8"); String content = "{\"a\":\"前置servlet\"}"; outputStream.write("{\"a\":\"前置servlet\"}".getBytes("utf-8")); System.out.println("servlet中寫入的內容:"+content); outputStream.flush(); outputStream.close(); } }
下面是寫兩個過濾器,DemoFilter2先對servlet中相應數據做修改,然后可以在DemoFilter1中查看修改后的內容,代碼如下:
package com.asiainfo; 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.annotation.WebFilter; import javax.servlet.http.HttpServletResponse; import com.asiainfo.wrapper.ResponseWrapper; @WebFilter("/*") public class DemoFilter2 implements Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletResponse); chain.doFilter(servletRequest, responseWrapper); byte[] content = responseWrapper.getResponseData(); String str = ""; if (content != null && !"".equals(content)) { // 這里可以對相應數據做修改,修改后的內容 str = "{\"a\":\"前置servlet\",\"b\":\"新增內容\"}"; System.out.println("第二個過濾器修改后的內容:" + str); HttpServletResponse response = (HttpServletResponse) servletResponse; // 注意:這里的response還要傳原來的,不然內容無法輸出頁面 writeResponse(response, 200, str); } } public static void writeResponse(HttpServletResponse response, int status, String json) { try { response.setContentType("application/json;charset=UTF-8"); response.setStatus(status); response.getWriter().write(json); } catch (IOException e) { e.printStackTrace(); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } } package com.asiainfo; 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.annotation.WebFilter; import javax.servlet.http.HttpServletResponse; import com.asiainfo.wrapper.ResponseWrapper; @WebFilter("/*") public class DemoFilter1 implements Filter { @Override public void init(FilterConfig filterconfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws IOException, ServletException { // TODO Auto-generated method stub ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) servletresponse); filterchain.doFilter(servletrequest, responseWrapper); String content = responseWrapper.getContent(); if (content != null) { System.out.println("第一個過濾器讀取到的內容:"+content); } HttpServletResponse response = (HttpServletResponse) servletresponse; writeResponse(response, 200, content); } public static void writeResponse(HttpServletResponse response, int status, String json) { try { response.setContentType("application/json;charset=UTF-8"); response.setStatus(status); response.getWriter().write(json); } catch (IOException e) { e.printStackTrace(); } } @Override public void destroy() { // TODO Auto-generated method stub } }
將上面的web工程部署到tomcat中啟動,瀏覽器中調用地址:http://localhost:8080/DemoFilter/demo
結果顯示如下:
控制台結果: