26、過濾器
過濾器
專案開發中,經常會涉及到重複程式碼的實現!
註冊 ---- 提交Servlet 【1. 設定編碼格式】 ----轉到JSP
修改 ---- 提交Servlet 【1. 設定編碼格式】 --- 轉到JSP
其他:
如判斷使用者是否登陸,只有登陸才能有操作許可權!
涉及到重複判斷: 獲取session,取出session資料,判斷是否為空,為空說明沒有登陸,不能操作
只有登陸後,才能操作!
如何解決:
- 抽取重複程式碼,封裝
- 每個用到重複程式碼的地方,手動的呼叫!
過濾器,設計執行流程:
- 使用者訪問伺服器
- 過濾器: 對Servlet請求進行攔截
- 先進入過濾器, 過濾器處理
- 過濾器處理完後, 在放行, 此時,請求到達Servlet/JSP
- Servlet處理
- Servlet處理完後,再回到過濾器, 最後在由tomcat伺服器相應使用者;
(過濾器就像回家的門!)
基本知識
過濾器:
* 概述:
* Filter的作用:起到過濾的作用.
* Filter執行的時機:
* 在執行對應的Servlet之前.(過濾Request物件中的內容)
* 在執行對應的Servlet之後.(過濾Respons物件中的內容)
* 發展:
* Filter最早在Servlet 2.3版本提供.
* Filter在Servlet 2.5版本完善.
* 如何使用Filter:
* Filter是JavaEE提供的一個介面.(自定義Filter需要實現該介面,並重寫所有方法)
* Filter提供的方法:
* init()
* doFilter()
* destroy()
* 實現步驟:
* 建立Java類,實現Filter介面,並且重寫所有方法.
* 在web.xml檔案中進行配置.
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>app.java.filter.MyFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* Filter的生命週期:
* 出生:Hello World
* init()方法
* 活著:Love World
* doFilter()方法
* 死去:GoodBye World
* destroy()方法
* 過濾器鏈:
* 問題:
* 如何定義過濾器被執行的先後順序?
* Filter的doFilter()方法具有一個引數FilterChain,通過呼叫chain.doFilter()方法可以放行.
* 在過濾器鏈中,執行chain.doFilter()方法,是否還是放行的作用?
* 如果是,應該被放行到哪裡去了?(單個Filter時,直接被放行到對應的Web資源[Servlet、JSP])
* 解決以上問題:
* chain.doFilter()方法依舊是放行方法.
* 如果執行的不是過濾器鏈中最後一個過濾器的話,執行chain.doFilter()方法,會被放行到下一個過濾器裡.
* 如果執行的是過濾器鏈中最後一個過濾器的話,chain.doFilter()方法,才會被放行到對應Web資源中.
* 過濾器鏈中的過濾器執行的先後順序由web.xml檔案中的<filter-mapping>標籤定義的先後順序決定.
* 實際開發的意義:
* 單個Filter完成單個任務.
* FilterConfig
* 讀取web.xml檔案中的初始化引數.
* 在web.xml檔案中是如何配置的:
<filter>
<filter-name>MyFilter2</filter-name>
<filter-class>app.java.filter.MyFilter2</filter-class>
<init-param>
<param-name>mingjiao</param-name>
<param-value>zhangwuji</param-value>
</init-param>
</filter>
* FilterConfig的用法與ServletConfig一致.
* 在web.xml檔案中配置全域性初始化引數<context-param>,通過ServletContext物件讀取.
* Filter的對映配置:<url-pattern>
* 完全匹配:/xxxx
* 目錄匹配:/aaaa/
* 副檔名匹配:*.do
* 優先順序別:完全匹配 -> 目錄匹配 -> 副檔名匹配
* 如果當前Filter攔截對應Servlet的話:
* 還可以使用<servlet-name>標籤
* Filter攔截Servlet預設情況是攔截直接請求.
* 在web.xml檔案中配置<filter-mapping>標籤中具有<dispatcher>
* <dispatcher>標籤在同一個Filter的配置中,可以配置多個.
* <dispatcher>標籤的值:
* REQUEST:是預設值,表示一次請求.
* FORWARD:表示請求轉發到.
* INCLUDE:表示包含(例如JSP包含另一個JSP等)
* ERROR:表示JSP的<%@ page errorPage=""%>
* Filter的案例:
* 全站亂碼案例:
* 利用Servlet的doGet()和doPost()方法中,可以解決中文亂碼:
* doGet()
String value = request.getParameter("");
value = new String(value.getBytes("ISO8859-1"),"utf-8");
response.setContentType("text/html;charset=utf-8");
* doPost()
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
* 以上問題:
* 實際開發時,Web應用程式的邏輯比較複雜(多個Servlet).
* 上述的解決方案,僅能解決當前Servlet的中文亂碼問題.
* 如果使用上述方案,解決中文亂碼問題:程式碼重複性太多.
過濾器案例:
介面:
|-- interface Filter 過濾器核心介面
Void init(filterConfig); 初始化方法,在伺服器啟動時候執行
Void doFilter(request,response,filterChain); 過濾器攔截的業務處理方法
Void destroy(); 銷燬過濾器例項時候呼叫
|-- interface FilterConfig 獲取初始化引數資訊
String getInitParameter(java.lang.String name)
Enumeration getInitParameterNames()
|-- interface FilterChain 過濾器鏈引數;一個個過濾器形成一個執行鏈;
void doFilter(ServletRequest request, ServletResponse response);
//執行下一個過濾器或放行
public class HelloFilter implements Filter{
// 建立例項
public HelloFilter(){
System.out.println("1. 建立過濾器例項");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2. 執行過濾器初始化方法");
// 獲取過濾器在web.xml中配置的初始化引數
String encoding = filterConfig.getInitParameter("encoding");
System.out.println(encoding);
// 獲取過濾器在web.xml中配置的初始化引數 的名稱
Enumeration<String> enums = filterConfig.getInitParameterNames();
while (enums.hasMoreElements()){
// 獲取所有引數名稱:encoding、path
String name = enums.nextElement();
// 獲取名稱對應的值
String value = filterConfig.getInitParameter(name);
System.out.println(name + "\t" + value);
}
}
// 過濾器業務處理方法: 在請求到達servlet之前先進入此方法處理公用的業務邏輯操作
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("3. 執行過濾器業務處理方法");
// 放行 (去到Servlet)
// 如果有下一個過濾器,進入下一個過濾器,否則就執行訪問servlet
chain.doFilter(request, response);
System.out.println("5. Servlet處理完成,又回到過濾器");
}
@Override
public void destroy() {
System.out.println("6. 銷燬過濾器例項");
}
}
public class HelloFilter2 implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("第二個過濾器");
// 放心
chain.doFilter(request, response);
System.out.println("第二個過濾器執行結束");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
xml配置:
<!-- 過濾器配置
<filter>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>path</param-name>
<param-value>c:/...</param-value>
</init-param>
<filter-name>hello_filter</filter-name>
<filter-class>cn.itcast.a_filter_hello.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hello_filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<!-- 配置第二個過濾器 -->
<!-- 演示: 攔截指定的請求 -->
<filter>
<filter-name>hello_filter2</filter-name>
<filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>hello_filter2</filter-name>
<!-- 1. 攔截所有
<url-pattern>/*</url-pattern>
-->
<!-- 2. 攔截指定的jsp
<url-pattern>/index.jsp</url-pattern>
<url-pattern>/list.jsp</url-pattern>
-->
<!-- 攔截所有的jsp
<url-pattern>*.jsp</url-pattern>
-->
<!-- 3. 根據servlet的內部名稱攔截
<servlet-name>IndexServlet</servlet-name>
-->
<!-- 攔截指定的servlet
<url-pattern>/index</url-pattern>
-->
<!-- 4. 指定攔截指定的型別 -->
<url-pattern>/*</url-pattern>
<!-- 攔截直接訪問的請求或者重定向的資源 -->
<dispatcher>REQUEST</dispatcher>
<!--<dispatcher>FORWARD</dispatcher>-->
</filter-mapping>
編碼處理過濾器
public class EncodingFilter implements Filter {
// 過濾器業務處理方法:處理的公用的業務邏輯操作
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 轉型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 一、處理公用業務
request.setCharacterEncoding("UTF-8"); // POST提交有效
response.setContentType("text/html;charset=UTF-8");
/*
* 出現GET中文亂碼,是因為在request.getParameter方法內部沒有進行提交方式判斷並處理。
* String name = request.getParameter("userName");
*
* 解決:對指定介面的某一個方法進行功能擴充套件,可以使用代理!
* 對request物件(目標物件),建立代理物件!
*/
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(), // 指定當前使用的累載入器
new Class[]{HttpServletRequest.class}, // 對目標物件實現的介面型別
new InvocationHandler() { // 事件處理器
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 定義方法返回值
Object returnValue = null;
// 獲取方法名
String methodName = method.getName();
// 判斷:對getParameter方法進行GET提交中文處理
if ("getParameter".equals(methodName)) {
// 獲取請求資料值【 <input type="text" name="userName">】
String value = request.getParameter(args[0].toString()); // 呼叫目標物件的方法
// 獲取提交方式
String methodSubmit = request.getMethod(); // 直接呼叫目標物件的方法
// 判斷如果是GET提交,需要對資料進行處理 (POST提交已經處理過了)
if ("GET".equals(methodSubmit)) {
if (value != null && !"".equals(value.trim())){
// 處理GET中文
value = new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}
return value;
}
else {
// 執行request物件的其他方法
returnValue = method.invoke(request, args);
}
return returnValue;
}
});
// 二、放行 (執行下一個過濾器或者servlet)
chain.doFilter(proxy, response); // 傳入代理物件
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
資料過濾器
/**
* 無效資料過濾
* @author Jie.Yuan
*
*/
public class DateFilter implements Filter {
// 初始化無效資料
private List<String> dirtyData;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 模擬幾個資料
dirtyData = new ArrayList<String>();
dirtyData.add("NND");
dirtyData.add("炸使館");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// 轉型
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 一、處理公用業務
request.setCharacterEncoding("UTF-8"); // POST提交有效
response.setContentType("text/html;charset=UTF-8");
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(), // 指定當前使用的累載入器
new Class[]{HttpServletRequest.class}, // 對目標物件實現的介面型別
new InvocationHandler() { // 事件處理器
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 定義方法返回值
Object returnValue = null;
// 獲取方法名
String methodName = method.getName();
// 判斷:對getParameter方法進行GET提交中文處理
if ("getParameter".equals(methodName)) {
// 獲取請求資料值【 <input type="text" name="userName">】
String value = request.getParameter(args[0].toString()); // 呼叫目標物件的方法
// 獲取提交方式
String methodSubmit = request.getMethod(); // 直接呼叫目標物件的方法
// 判斷如果是GET提交,需要對資料進行處理 (POST提交已經處理過了)
if ("GET".equals(methodSubmit)) {
if (value != null && !"".equals(value.trim())){
// 處理GET中文
value = new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}
// 中文資料已經處理完: 下面進行無效資料過濾
//【如何value中出現dirtyData中資料,用****替換】
for (String data : dirtyData) {
// 判斷當前輸入資料(value), 是否包含無效資料
if (value.contains(data)){
value = value.replace(data, "*****");
}
}
// 處理完編碼、無效資料後的正確資料
return value;
}
else {
// 執行request物件的其他方法
returnValue = method.invoke(request, args);
}
return returnValue;
}
});
// 二、放行 (執行下一個過濾器或者servlet)
chain.doFilter(proxy, response); // 傳入代理物件
}
@Override
public void destroy() {
}
}
攔截過濾器
/**
* 登陸驗證過濾器
*
* http://localhost:8080/emp_sys/login.jsp 可以直接訪問
http://localhost:8080/emp_sys/login 可以直接訪問
http://localhost:8080/emp_sys/index 不能直接訪問
http://localhost:8080/emp_sys/list.jsp 不能直接訪問
* @author Jie.Yuan
*
*/
public class LoginFilter implements Filter {
private String uri;
/**
* 分析:
*
1. 先指定放行的資源,哪些資源不需要攔截:
login.jsp + /login (request物件可以獲取)
2. 獲取session,從session中獲取登陸使用者
3. 判斷是否為空:
為空, 說明沒有登陸, 跳轉到登陸
不為空, 已經登陸,放行!
*/
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
//0. 轉換
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//1. 獲取請求資源,擷取
String uri = request.getRequestURI(); // /emp_sys/login.jsp
// 擷取 【login.jsp或login】
String requestPath = uri.substring(uri.lastIndexOf("/") + 1, uri.length());
//2. 判斷: 先放行一些資源:/login.jsp、/login
if ("login".equals(requestPath) || "login.jsp".equals(requestPath)) {
// 放行
chain.doFilter(request, response);
}
else {
//3. 對其他資源進行攔截
//3.1 先獲取Session、獲取session中的登陸使用者(loginInfo)
HttpSession session = request.getSession(false);
// 判斷
if (session != null) {
Object obj = session.getAttribute("loginInfo");
//3.2如果獲取的內容不為空,說明已經登陸,放行
if (obj != null) {
// 放行
chain.doFilter(request, response);
} else {
//3.3如果獲取的內容為空,說明沒有登陸; 跳轉到登陸
uri = "/login.jsp";
}
} else {
// 肯定沒有登陸
uri = "/login.jsp";
}
request.getRequestDispatcher(uri).forward(request, response);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
相關文章
- 過濾Servlet--過濾器Servlet過濾器
- 過濾器過濾器
- 4、過濾器的使用及自定義過濾器過濾器
- 點雲濾波器與過濾器過濾器
- 代理過濾器過濾器
- vue 過濾器Vue過濾器
- Filter過濾器Filter過濾器
- hbase過濾器過濾器
- CAN過濾器過濾器
- Servlet過濾器Servlet過濾器
- jms過濾器過濾器
- DataV過濾器過濾器
- Vue過濾器Vue過濾器
- Xor過濾器:比布隆Bloom過濾器更快,更小過濾器OOM
- asp.net core MVC 過濾器之ActionFilter過濾器(二)ASP.NETMVC過濾器Filter
- 誠翔濾器光刻膠過濾器濾芯:保障光刻過程的高效與安全過濾器
- Vue中過濾器Vue過濾器
- 布隆過濾器過濾器
- vue---過濾器Vue過濾器
- PHP 過濾器(Filter)PHP過濾器Filter
- vue filters過濾器VueFilter過濾器
- Java Filter過濾器JavaFilter過濾器
- lucene Filter過濾器Filter過濾器
- 四種過濾器過濾器
- Spring Cloud Gateway ---GatewayFilter過濾器、過濾器工廠(入門)SpringCloudGatewayFilter過濾器
- 監聽器和過濾器過濾器
- 過濾器應用【編碼、敏感詞、壓縮、轉義過濾器】過濾器
- Spring Cloud Gateway中的過濾器工廠:重試過濾器SpringCloudGateway過濾器
- 5.scrapy過濾器過濾器
- NetCore過濾器NetCore過濾器
- 攔截過濾器模式過濾器模式
- Filter過濾器的使用Filter過濾器
- JavaWeb 中 Filter過濾器JavaWebFilter過濾器
- SpringSecurity過濾器原理SpringGse過濾器
- 4、angularJS過濾器AngularJS過濾器
- 服務閘道器過濾器過濾器
- struts struts攔截器(過濾器)過濾器
- 13.gateway中的過濾器的介紹以及自定義過濾器Gateway過濾器