過濾器Filter
filter是對客戶端訪問資源的過濾,符合條件放行,不符合條件不放行,並且可以對目標資源訪問前后進行邏輯處理。
步驟:
- 編寫一個過濾器的類實現Filter接口
- 實現接口中尚未實現的方法(着重實現doFilter方法)
- 在web.xml中進行配置(主要是配置要對哪些資源進行過濾)
例子,過濾器實現類:
package com.yyb.filter; import java.io.IOException; import javax.servlet.*; /** * Created by Administrator on 2017/7/28. */ public class FilterDemo implements Filter { @Override //Filter創建的時候執行init方法 public void init(FilterConfig filterConfig) throws ServletException { //1、獲得web.xml中filter 的名稱<filter-name>FilterDemo</filter-name> System.out.println(filterConfig.getFilterName()); //2、獲得當前filter的初始化參數 System.out.println(filterConfig.getInitParameter("aaa")); //3、獲得servletContext filterConfig.getServletContext(); System.out.println("init ...."); } @Override //doFilter是Filter的核心過濾的方法 /* * request: 內部封裝是客戶端http請求的內容 * response: 代表是響應 * FilterChain: 過濾器鏈對象 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("quick1 running...."); //放行請求 chain.doFilter(request, response); } @Override //Filter對象銷毀的時候執行destory方法 public void destroy() { System.out.println("destroy..."); } }
web.xml
<filter> <filter-name>FilterDemo</filter-name> <filter-class>com.yyb.filter.FilterDemo</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Filter的API詳解
filter生命周期及其與生命周期相關的方法,Filter接口有三個方法,並且這個三個都是與Filter的生命相關的方法:
- init(Filterconfig):代表filter對象初始化方法,filter對象創建時執行。
- doFilter(ServletRequest,ServletResponse,FilterCha):代表filter執行過濾的核心方法,如果某資源在已經被配置到這個filter進行過濾的話,那么每次訪問這個資源都會執行doFilter方法。
- destory():代表是filter銷毀方法,當filter對象銷毀時執行該方法。
Filter對象的生命周期
- Filter何時創建:服務器啟動時就創建該filter對象
- Filter何時銷毀:服務器關閉時filter銷毀
init(FilterConfig):其中參數config代表該Filter對象的配置信息的對象,內部封裝是該filter的配置信息。
destory()方法:filter對象銷毀時執行。
doFilter方法:doFilter(ServletRequest,ServletResponse,FilterChain),其中的參數ServletRequest/ServletResponse是每次在執行doFilter方法時web容器負責創建一個request和一個response對象作為doFilter的參數傳遞進來。該request與response就是在訪問目標資源的service方法時的request和response。FilterChain是過濾器鏈對象,通過該對象的doFilter方法可以放行該請求。chain對象根據配置的filter-mapping順序依次執行filter。

Filter的配置
<filter> <filter-name>FilterDemo</filter-name> <filter-class>com.yyb.filter.FilterDemo</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
url-pattern配置
- 完全匹配
/Servlet1,只有訪問Servlet1時才執行
- 目錄匹配 /aaa/bbb/*
/user/*:訪問前台的資源進入此過濾器
/admin/*:訪問后台的資源時執行此過濾器
- 擴展名匹配 *.abc *.jsp
注意:url-pattern可以使用servlet-name替代,也可以混用。
<filter-mapping> <filter-name>FilterDemo</filter-name> <!--<url-pattern>/*</url-pattern>--> <servlet-name>FilterTest</servlet-name> <servlet-name>FilterTest1</servlet-name> </filter-mapping>
dispatcher:訪問的方式
- REQUEST:默認值,代表直接訪問某個資源時執行filter
- FORWARD:轉發時才執行filter
- INCLUDE: 包含資源時執行filter
- ERROR:發生錯誤時 進行跳轉時執行filter
例子:web.xml
<filter> <filter-name>FilterDemo</filter-name> <filter-class>com.yyb.filter.FilterDemo</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
在FilterTest中,添加轉發代碼 request.getRequestDispatcher("/index.jsp").forward(request, response); ,此時當訪問FilterTest時,過濾器只會執行依次,而不是兩次。轉發時不會執行過濾器。
但是重定向會執行兩次,在FilterTest中,添加轉發代碼 response.sendRedirect(request.getContextPath()+"/index.jsp"); ,可以看到執行結果。
Filter的作用
- 公共代碼的提取
- 可以對request和response中的方法進行增強(裝飾者模式/動態代理)
- 進行權限控制
使用filter解決參數中文亂碼
package com.ithiema.web.filter; import java.io.IOException; import java.io.UnsupportedEncodingException; 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; import javax.servlet.http.HttpServletRequestWrapper; public class EncodingFilter implements Filter{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //request.setCharacterEncoding("UTF-8"); //在傳遞request之前對request的getParameter方法進行增強 /* * 裝飾者模式(包裝) * * 1、增強類與被增強的類要實現統一接口 * 2、在增強類中傳入被增強的類 * 3、需要增強的方法重寫 不需要增強的方法調用被增強對象的 * */ //被增強的對象 HttpServletRequest req = (HttpServletRequest) request; //增強對象 EnhanceRequest enhanceRequest = new EnhanceRequest(req); chain.doFilter(enhanceRequest, response); } @Override public void destroy() { } @Override public void init(FilterConfig filterConfig) throws ServletException { } } class EnhanceRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public EnhanceRequest(HttpServletRequest request) { super(request); this.request = request; } //對getParaameter增強 @Override public String getParameter(String name) { String parameter = request.getParameter(name);//亂碼 try { parameter = new String(parameter.getBytes("iso8859-1"),"UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return parameter; } }
注解
注解就是符合一定格式的語法 @xxxx,是給jvm看的,給機器看的。注解在目前而言最主流的應用是代替配置文件。
關於配置文件與注解開發的優缺點:
- 優點:開發效率高,成本低
- 缺點:耦合性大,並且不利於后期維護
jdk5提供的注解
@Override:告知編譯器此方法是覆蓋父類的
@Deprecated:標注過時
@SuppressWarnings:壓制警告
不同的注解只能在不同的位置使用(方法上、字段上、類上)
自定義注解
怎樣去編寫一個自定義的注解,使用@interface關鍵字。
public @interface MyAnno { //注解的屬性 String name(); int age() default 28; }
怎樣去使用注解
@MyAnno(name="",age=20) public void show(){ } @MyAnno(name="") public void show1(){ }
注意:如果屬性的名字是value,並且注解的屬性值只有一個,那么在使用注解時可以省略value。注解屬性類型只能是以下幾種:基本類型;String;枚舉類型;注解類型;Class類型 ;以上類型的一維數組類型。
public @interface MyAnno2 {
//String value();
String[]value();
}
//@MyAnno2("aa")
//public void show2(){
//}
@MyAnno3({"name","age"})
public void show3(){
}
怎樣去解析注解-----使用反射知識
介入一個概念,元注解。代表修飾注解的注解,作用是限制定義的注解的特性。
@Retention
- SOURCE: 注解在源碼級別可見,在字節碼文件中就沒有了。
- CLASS:注解在字節碼文件級別可見
- RUNTIME:注解在整個運行階段都可見

@Target 代表注解修飾的范圍:類上使用,方法上使用,字段上使用
- FIELD:字段上可用此注解
- METHOD:方法上可以用此注解
- TYPE:類/接口上可以使用此注解
import java.lang.reflect.Method; /** * Created by Administrator on 2017/7/28. */ public class MyAnnoParse { public static void main(String[]args) throws NoSuchMethodException { //解析show方法上面的@MyAnno //直接的目的是 獲得show方法上的@MyAnno中的參數 //獲得show方法的字節碼對象 Class clazz = MyAnnoTest.class; Method method = clazz.getMethod("show", String.class); //獲得show方法上的@MyAnno MyAnno annotation = method.getAnnotation(MyAnno.class); //獲得@MyAnno上的屬性值 System.out.println(annotation.name());//zhangsan System.out.println(annotation.age());//28 //根據業務需求寫邏輯代碼 } }
注意:要想解析使用了注解的類 ,那么該注解的Retention必須設置成Runtime,注解解析的實質是從注解中解析出屬性值
字節碼對象存在於獲得注解相關的方法
isAnnotationPresent(Class<? extends Annotation> annotationClass) : 判斷該字節碼對象身上是否使用該注解了 getAnnotation(Class<A> annotationClass) :獲得該字節碼對象身上的注解對象
