過濾器
我們寫多了servlet會發現,很多代碼和功能是重復的,比如:解決中文亂碼問題、權限驗證、日志的記錄等,他們的特點是:代碼相同或相似、分散在不同位置、不利于維護。
過濾器就是他們的解決辦法。
過濾器是請求到達目標之前的處理程序,也是響應離開服務器之前的處理程序。
我們可以定義多個過濾器來組成一個過濾器鏈,每個過濾器完成一個任務,請求和響應如圖所示,依次經過過濾器,第一個過濾器最先被經過,離開時最后被經過。
這種設計使用了一個設計模式:責任鏈模式。
一個圖秒懂
如圖,功能類似的代碼只有一份,便于維護。
我們如何使用過濾器呢?
1)開發過濾器類
2)指定過濾器過濾范圍(有些請求不需要經過某些過濾器)
一共也就兩個方法,非常簡單,我們寫一個解決中文亂碼的過濾器吧:
public class EncodingFilter implements Filter{private String encoding;/*** 初始化操作,只執行一次*/@Overridepublic void init(FilterConfig config) throws ServletException {//先讀取配置文件,獲取編碼類型encoding = config.getInitParameter("encoding");if(encoding == null){encoding = "utf-8";}}/*** 相當于Servlet的service(),過濾范圍的每次請求響應都經過*/@Overridepublic void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException, ServletException {//請求到達目標資源之前的預處理操作request.setCharacterEncoding(encoding);//調用下一個過濾器或者目標資源chain.doFilter(request, response);//響應離開服務器端之前的后處理操作(無)}/*** 銷毀操作,只執行一次*/@Overridepublic void destroy() {// TODO Auto-generated method stub}}
相關配置也和servlet類似(通過kv找到utf-8):
<filter><filter-name>EncodingFilter</filter-name><filter-class>com.bjsxt.filter.EncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param></filter><filter-mapping><filter-name>EncodingFilter</filter-name><url-pattern>/servlet/*</url-pattern></filter-mapping>
我們再理解一下過濾器的執行過程:
代碼中:
? ? ? ? ? ? ? ?//請求到達目標資源之前的預處理操作
? ? ? ? ? ??
? ? ? ? ? ? ? ?//調用下一個過濾器或者目標資源
? ? ? ? ? ? ? ?//響應離開服務器端之前的后處理操作(無)
一共有這么三個操作,而過濾器的執行過程就是如此的
化的很丑但是就是這個意思。
再寫一下怎么搞過濾范圍,也超簡單直接上代碼了:
?
public class AuthFilter implements Filter{@Overridepublic void init(FilterConfig filterconfig) throws ServletException {// TODO Auto-generated method stub}/*** 過濾路徑是 /servlet/* *.jsp* 某些jsp應該排除在外 * 某些servlet應該排除在外*/@Overridepublic void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httprequest = (HttpServletRequest)request; String uri = httprequest.getRequestURI();int n1 = uri.indexOf("login.jsp");// >=0 存在int n2 = uri.indexOf("register.jsp");int n3 = uri.indexOf("index.jsp");int n4 = -1;int n5 = -1;if(n1>=0 || n2>=0 ||n3>=0 ||n4>=0 ||n5>=0 ){ //假設是需要排除在外的資源//放行chain.doFilter(request, response);}else{//do something}}@Overridepublic void destroy() {// TODO Auto-generated method stub}
}
監聽器
監聽器是一個實現特定接口的普通Java程序,這個程序專門用于監聽另一個Java對象的方法調用或屬性改變,當被監聽對象發生上述事件后,監聽器某個方法立即被執行
超簡單代碼例子:
package listener;import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
/**
* 記錄每個請求的時間,客戶端IP,URL地址到日志文件中
* @author Administrator
*
*/
public class LogListener implements ServletRequestListener,ServletRequestAttributeListener{/*** 請求結束了*/@Overridepublic void requestDestroyed(ServletRequestEvent servletrequestevent) {// TODO Auto-generated method stub}/*** 請求開始了* 其實對于圖片、視頻、音頻、js、css也會有一個新的請求,所以也會被監聽*/@Overridepublic void requestInitialized(ServletRequestEvent sre) {//獲取要記錄的每個請求的時間,客戶端IP,URL地址Date now = new Date();HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();String addr = request.getRemoteAddr();String url = request.getRequestURL().toString(); //http://127.0.0.1:8081/myservlet/servlet/UserServletString qs = request.getQueryString(); //method=login//記錄到日志文件中PrintWriter pw = null;try {pw = new PrintWriter(new FileWriter("d:/requestlog.log", true)); //if(qs!= null){pw.println("time="+now.toLocaleString()+",addr="+addr+",url="+url+"?"+qs);}else{pw.println("time="+now.toLocaleString()+",addr="+addr+",url="+url);} } catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally{pw.close();}}/*** request.setAttribute("error","用戶名不能為空");**/@Overridepublic void attributeAdded(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}/**** request.removeAttribute("error");*/@Overridepublic void attributeRemoved(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}/*** request.setAttribute("error","用戶名和密碼錯誤");*/@Overridepublic void attributeReplaced(ServletRequestAttributeEvent servletrequestattributeevent) {// TODO Auto-generated method stub}}<listener><listener-class>listener.LogListener</listener-class></listener>
?