Filter:過濾器
- 概念
- 當訪問服務器的資源時,過濾器可以將請求攔截下來,完成一些特殊的功能。
- 一般用於完成通用的操作。(如:登錄驗證、統一編碼處理、敏感字符過濾…)
- 步驟
- 定義一個類,實現接口Filter
- 複寫方法
- 配置攔截路徑
- web.xml
- 註解
@WebFilter("/*") //訪問所有資源之前都會執行該過濾器
public class FilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//對request對象請求消息增強
System.out.println("FilterDemo被執行了。。。。");
filterChain.doFilter(servletRequest,servletResponse);//放行
//對response對象的響應消息增強
System.out.println("FilterDemo回來了。。。。");
}
@Override
public void destroy() {}
}
過濾器細節
web.xml配置
<filter>
<filter-name>demo1</filter-name>
<filter-class>cn.comany.web.filter.FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>demo</filter-name>
<!-- 攔截路徑 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
過濾器執行流程
- 執行過濾器
- (放行)執行放行後的資源
- 回來執行過濾器放行代碼下邊的代碼
過濾器生命週期方法
- init:在服務器啓動後,會創建Filter對象,然後調用init方法。(只執行一次,用於加載資源)
- doFilter:每一次請求被攔截資源時,會執行。(執行多次)
- destroy:在服務器關閉後,Filter對象被銷燬。如果服務器是正常關閉,則會執行destroy方法。(只執行一次,用於釋放資源)
過濾器配置詳解
攔截路徑配置
- 具體資源路徑:
/index.jsp
只有訪問index.jsp
資源時,過濾器纔會被執行 - 攔截目錄:
/user/*
訪問/user
下的資源時,過濾器會被執行 - 後綴名攔截:
*.jsp
訪問後綴名爲jsp
資源時,過濾器會被執行 - 攔截所有資源:
/*
訪問任何資源,過濾器都會被執行
攔截方式配置:資源被訪問的方式
註解配置
- 設置
dispatcherTypes
屬性- REQUEST:默認值。瀏覽器直接請求資源
- FORWARD:轉發訪問資源
- INCLUDE:包含訪問資源
- ERROR:錯誤跳轉資源
- ASYNC:異步訪問資源
//瀏覽器直接請求index.jsp資源時會被執行
@WebFilter(value="/index.jsp",dispatcherTypes=DispatcherType.REQUEST)
//只有轉發訪問index.jsp時,該過濾器纔會被執行
@WebFilter(value="/index.jsp",dispatcherTypes=DispatcherType.FORWARD)
//瀏覽器直接請求index.jsp 或 轉發訪問index.jsp時,該過濾器纔會被執行
@WebFilter(value="/index.jsp",dispatcherTypes={DispatcherType.REQUEST,DispatcherType.FORWARD})
public class FilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo被執行了。。。。");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}
web.xml配置
- 設置
<dispatcher></dispatcher>
標籤即可
過濾器鏈(配置多個過濾器)
- 執行順序:如果有兩個過濾器(過濾器1和過濾器2)
- 過濾器1
- 過濾器2
- 資源執行
- 過濾器2
- 過濾器1
- 過濾器先後順序問題:
- 註解配置:按照類名的字符串比較規則比較,值小的先執行
- 如: AFilter 和 BFilter,AFilter就先執行了。
- web.xml配置:
<filter-mapping>
誰定義在上邊,誰先執行
- 註解配置:按照類名的字符串比較規則比較,值小的先執行
增強對象的功能
- 設計模式:一些通用的解決固定問題的方式
裝飾模式
代理模式
- 概念
- 真實對象:被代理的對象
- 代理對象:代理真實對象
- 代理模式:代理對象代理真實對象,達到增強真實對象功能的目的
實現方式
- 靜態代理:有一個類文件描述代理模式
- 動態代理:在內存中形成代理類
- 實現步驟:
- 代理對象和真實對象實現相同的接口
代理對象 = Proxy.newProxyInstance();
- 使用代理對象調用方法
- 增強方法
- 增強方式
- 增強參數列表
- 增強返回值類型
- 增強方法體執行邏輯
- 實現步驟:
//真實類
public class Phone implements SalePhone {
@Override
public String sale(double money){
System.out.println("花"+money+"買了一部手機");
return "XX手機";
}
@Override
public void show(){
System.out.println("很開心");
}
}
public class ProxyTest {
public static void main(String[] args) {
//1.創建真實對象
Phone phone = new Phone();
//2.動態代理增強Phone對象
/*
* 三個參數:
* 1.類加載器:真實對象.getClass().getClassLoader()
* 2.接口數組:真實對象.getClass().getInterfaces()
* 3.處理器:new InvocationHandler()
* */
SalePhone proxyPhone = (SalePhone) Proxy.newProxyInstance(phone.getClass().getClassLoader(), phone.getClass().getInterfaces(), new InvocationHandler() {
/*
* 代理邏輯編寫的方法:代理對象調用的所有方法都會觸發該方法執行
* 參數:
* 1.proxy:代理對象
* 2.method:代理對象調用的方法,被封裝爲的對象
* 3.args:代理對象調用方法時,傳遞的實際參數
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
System.out.println(method.getName()); //proxyPhone.show();代理對象調用該方法輸出show
System.out.println(args[0]); //proxyPhone.sale(8000);代理對象調用該方法輸出8888
*/
//判斷是否是sale方法
if (method.getName().equals("sale")) {
//1.增強參數
double money = (double) args[0];
money *= 0.85;
//使用真實對象調用該方法
String obj = (String) method.invoke(phone, money);
//2.增強返回值
return obj + "_耳機";
} else {
Object obj = method.invoke(phone, args);
return obj;
}
}
});
//2.調用方法
String newPhone = proxyPhone.sale(8888);
System.out.println(newPhone);
proxyPhone.show(); //調用代理的對象
}
}
Listener:監聽器
- 概念:web的三大組件之一。
- 事件監聽機制
- 事件:一件事情
- 事件源:事件發生的地方
- 監聽器:一個對象
- 註冊監聽:將事件、事件源、監聽器綁定在一起。 當事件源上發生某個事件後,執行監聽器代碼。
- 事件監聽機制
ServletContextListener
-
監聽ServletContext對象的創建和銷燬
-
方法
void contextDestroyed(ServletContextEvent sce)
:ServletContext對象被銷燬之前會調用該方法void contextInitialized(ServletContextEvent sce)
:ServletContext對象創建後會調用該方法
-
步驟
-
定義一個類,實現ServletContextListener接口
-
複寫方法
-
配置
1.web.xml
<listener> <listener-class>cn.company.web.listener.ContextLoaderListener</listener-class> </listener> <!-- 指定初始化參數 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext.xml</param-value> </context-param>
2.註解:
@WebListener
-
@WebListener
public class ContextLoaderListener implements ServletContextListener {
/*
* 監聽ServletContext對象創建的。ServletContext對象服務器啓動後自動創建
* 在服務器啓動後自動調用
* */
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
//加載資源文件
//1.獲取ServletContext對象
ServletContext servletContext = servletContextEvent.getServletContext();
//2.加載資源文件
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
//3.獲取真實路徑
String realPath = servletContext.getRealPath(contextConfigLocation);
//4.加載進內存
try {
FileInputStream fis = new FileInputStream(realPath);
System.out.println(fis);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("ServletContext對象被創建了。。。");
}
/*
* 在服務器關閉後,ServletContext對象被銷燬。當服務器正常關閉後該方法被調用
* */
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("ServletContext對象被銷燬了。。。");}
}