過(guò)濾器(Filter)
Servlet/Filter/Listener統(tǒng)稱為JavaWeb的三大組件.其中Filter也叫做過(guò)濾器,通過(guò)過(guò)濾器技術(shù)拌滋,開(kāi)發(fā)人員可以實(shí)現(xiàn)用戶在訪問(wèn)某個(gè)資源之前或之后赞辩,對(duì)訪問(wèn)的請(qǐng)求和響應(yīng)進(jìn)行攔截雌芽,從而做一些相關(guān)的處理。
總結(jié):
1.所謂的過(guò)濾器诗宣,就是攔截用戶對(duì)資源的訪問(wèn)
2.一個(gè)過(guò)濾器可以攔截多個(gè)資源膘怕,一個(gè)資源也可以配置多個(gè)過(guò)濾器進(jìn)行攔截
3.其實(shí)所謂的攔截,就是將代表請(qǐng)求的request對(duì)象和代表響應(yīng)的response對(duì)象攔截下來(lái),攔截下來(lái)后:
(1)控制是否允許訪問(wèn) – 比如:用戶登陸之后才能訪問(wèn)自己的訂單或購(gòu)物車
(2)在訪問(wèn)資源之前或之后做一些處理 比如: 全站亂碼解決
[toc]
開(kāi)發(fā)過(guò)濾器
1.步驟
Servlet API中提供了一個(gè)Filter接口召庞,開(kāi)發(fā)web應(yīng)用時(shí),如果編寫一個(gè)類實(shí)現(xiàn)了這個(gè)接口来破,則這個(gè)類就是一個(gè)過(guò)濾器類篮灼。
(1)寫一個(gè)類實(shí)現(xiàn)Filter接口,并實(shí)現(xiàn)其中的方法
(2)在web應(yīng)用的web.xml中配置過(guò)濾器所攔截的路徑
2.過(guò)濾器方法
(1)init方法
當(dāng)Filter實(shí)例創(chuàng)建之后徘禁,服務(wù)器立即調(diào)用init方法進(jìn)行初始化的操作.
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FilterDemo1實(shí)例已經(jīng)被創(chuàng)建...");
}
(2)doFilter方法
當(dāng)過(guò)濾器攔截到對(duì)資源的訪問(wèn)時(shí)诅诱,服務(wù)器會(huì)調(diào)用doFilter方法進(jìn)行處理
//
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("FilterDemo1.doFilter()");
}
FilterChain:代表多個(gè)過(guò)濾器組成的過(guò)濾器鏈對(duì)象
(1)一個(gè)資源可以配置多個(gè)過(guò)濾器進(jìn)行攔截,多個(gè)過(guò)濾器執(zhí)行的順序是按照Filter在web.xml中對(duì)應(yīng)的filter-mapping標(biāo)簽的先后配置順序執(zhí)行的.多個(gè)過(guò)濾器就組成了一條過(guò)濾器鏈.
(2)當(dāng)過(guò)濾器攔截到對(duì)資源的訪問(wèn)時(shí)送朱,如果處理之后放行過(guò)濾器娘荡,即調(diào)用FilterChain中的doFilter方法來(lái)放行過(guò)濾器. 接著才可以執(zhí)行后面的資源
(3)如果后面仍然是過(guò)濾器,則也需要在過(guò)濾器的doFilter方法中調(diào)用FilterChain.doFilter方法才可以放行過(guò)濾器驶沼,執(zhí)行后面的資源.
(4)如果后面沒(méi)有過(guò)濾器炮沐,則訪問(wèn)對(duì)應(yīng)的資源.
也就是說(shuō)當(dāng)所有的過(guò)濾器都調(diào)用了FilterChain的doFilter方法時(shí),才可以放行所有的過(guò)濾器回怜,才可以訪問(wèn)到對(duì)應(yīng)的資源
chain.doFilter(request, response);
(3)destroy方法
在Filter實(shí)例銷毀之前大年,執(zhí)行destroy方法進(jìn)行善后的處理
public void destroy() {
System.out.println("FilterDemo1實(shí)例將要被銷毀啦...");
}
3.全站亂碼處理過(guò)濾器
//pakeage:com.znonline.jt.filter
/**
* 處理全站亂碼的過(guò)濾器
* 1.處理請(qǐng)求參數(shù)亂碼(GET和POST)
* 2.處理響應(yīng)正文亂碼
*/
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
/* 處理所攔截到的請(qǐng)求的核心方法
* (相當(dāng)于Servlet中的service方法) */
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("EncodingFilter.doFilter()....");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
/* POST:
* 在過(guò)濾器中處理請(qǐng)求參數(shù)亂碼(只需要寫一次, 所有被攔截到的資源的亂碼問(wèn)題都可以解決)
*/
request.setCharacterEncoding("utf-8");//針對(duì)POST提交
/*
* 在過(guò)濾器中處理響應(yīng)正文亂碼(只需要寫一次,
* 所有被攔截到的資源的亂碼問(wèn)題都可以解決)
*/
response.setContentType("text/html;charset=utf-8");
HttpServletRequest myRequest = new MyHttpServletRequest(req);
//處理完后一定要放行過(guò)濾器, 才可以接著訪問(wèn)下面的資源
chain.doFilter(myRequest, response);
}
/* 在Filter實(shí)例銷毀之前立即執(zhí)行
* 進(jìn)行善后的處理
*/
public void destroy() {}
}
class MyHttpServletRequest extends HttpServletRequestWrapper{
private boolean isEncode = true;
/* isEncode 是否進(jìn)行手動(dòng)編解碼的標(biāo)識(shí),
默認(rèn)值是true, 表示還沒(méi)有手動(dòng)編解碼 */
private HttpServletRequest request;
public MyHttpServletRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
return this.getParameterValues(name) == null? null : this.getParameterValues(name)[0];
}
@Override
public String[] getParameterValues(String name) {
return this.getParameterMap().get(name);
}
@Override
public Map<String, String[]> getParameterMap() {
/*
該方法可以返回所有請(qǐng)求參數(shù)組成的map集合, 此時(shí)map中
保存的數(shù)據(jù)是亂碼(get提交), 我們可以遍歷map中的每一個(gè)
參數(shù)值, 手動(dòng)編解碼處理完后將正確的數(shù)據(jù)再次存回map中,
最后返回一個(gè)沒(méi)有亂碼的map集合
*/
if("POST".equalsIgnoreCase(request.getMethod())){//是POST提交
return request.getParameterMap();
}else if("GET".equalsIgnoreCase(request.getMethod())){
//遍歷map, 挨個(gè)取出亂碼, 手動(dòng)編解碼再次存回map并返回map
Map<String, String[]> map = request.getParameterMap();
if(isEncode){
for (Map.Entry<String, String[]> entry : map.entrySet()) {
//取出每一個(gè)鍵值對(duì), 由于值是數(shù)組, 還需要遍歷
String[] vs = entry.getValue();
for (int i = 0; i < vs.length; i++) {
try {
vs[i] = new String(vs[i].getBytes("iso8859-1"), "utf-8");
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
isEncode = false;
}
return map;
}else{//其他5種提交方式
return request.getParameterMap();
}
}
}
/*
* 被裝飾者: request對(duì)象 --> 所屬的類: A
* 被裝飾者所屬的類實(shí)現(xiàn)的接口: HttpServletRequest
*
* 裝飾類: MyHttpServletRequest 要實(shí)現(xiàn)HttpServletRequest接口
* 在這里讓MyHttpServletRequest繼承一個(gè)裝飾類, 我們這個(gè)類也是一個(gè)
* 裝飾類, 只需要覆蓋需要改造的父類中方法即可!!
*/
/*
* 1.寫一個(gè)裝飾類, 裝飾類要和被裝飾者所屬的類實(shí)現(xiàn)相同的接口
* 或者繼承相同的父類
* 2.裝飾類要提供構(gòu)造方法接受被裝飾者并保存在類的內(nèi)部
* 3.對(duì)于想要改造的方法直接進(jìn)行改造, 對(duì)于不想改造的方法, 調(diào)用
* 原有對(duì)象上的方法
*/
web.xml配置
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.znonline.jt.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Java設(shè)計(jì)模式:裝飾器模式
裝飾者模式(Decorator Pattern,有的也用 Wrapper Pattern)就是動(dòng)態(tài)地把職責(zé)附加到已有對(duì)象上去玉雾,實(shí)現(xiàn)功能擴(kuò)展翔试。這種特性,使得裝飾者模式提供了比繼承更具有彈性的解決方案复旬。