http://www.cnblogs.com/javawebsoa/p/3228858.html
1、Filter簡介
(1)Filter也稱之為過濾器,它是Servlet技術中最實用的技術,WEB開發人員通過Filter技術,對web服務器管理的所有web資源:例如Jsp,?Servlet,?靜態圖片文件或靜態?html?文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的權限訪問控制、過濾敏感詞匯、壓縮響應信息等一些高級功能。
(2)Servlet?API中提供了一個Filter接口,開發web應用時,如果編寫的Java類實現了這個接口,則把這個java類稱之為過濾器Filter。通過Filter技術,開發人員可以實現用戶在訪問某個目標資源之前,對訪問的請求和響應進行攔截,如下所示:
2、Filter是如何實現攔截的?
Filter接口中有一個doFilter方法,當開發人員編寫好Filter,并配置對哪個web資源(攔截url)進行攔截后,WEB服務器每次在調用web資源之前,都會先調用一下filter的doFilter方法,因此,在該方法內編寫代碼可達到如下目的:
調用目標資源之前,讓一段代碼執行
是否調用目標資源(即是否讓用戶訪問web資源)。
web服務器在調用doFilter方法時,會傳遞一個filterChain對象進來,filterChain對象是filter接口中最重要的一個對象,它也提供了一個doFilter方法,開發人員可以根據需求決定是否調用此方法,調用該方法,則web服務器就會調用web資源的service方法,即web資源就會被訪問,否則web資源不會被訪問。
調用目標資源之后,讓一段代碼執行
3、Filter開發入門
(1)Filter開發分為二個步驟:
編寫java類實現Filter接口,并實現(三個方法)其doFilter方法。
在?web.xml?文件中使用和元素對編寫的filter類進行注冊,并設置它所能攔截的資源。
(2)Filter鏈?---?
在一個web應用中,可以開發編寫多個Filter,這些Filter組合起來稱之為一個Filter鏈。
web服務器根據Filter在web.xml文件中的注冊順序,決定先調用哪個Filter,當第一個Filter的doFilter方法被調用時,web服務器會創建一個代表Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中,開發人員如果調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,如果有,則調用第2個filter,如果沒有,則調用目標資源。
Filter鏈實驗(查看filterChain?API文檔)
4、Filter的生命周期
(1)init(FilterConfig?filterConfig)throws?ServletException:
和我們編寫的Servlet程序一樣,Filter的創建和銷毀由WEB服務器負責。?web?應用程序啟動時,web?服務器將創建Filter?的實例對象,并調用其init方法進行初始化(注:filter對象只會創建一次,init方法也只會執行一次。示例?)
開發人員通過init方法的參數,可獲得代表當前filter配置信息的FilterConfig對象。
(2)doFilter(ServletRequest,ServletResponse,FilterChain)
每次filter進行攔截都會執行
在實際開發中方法中參數request和response通常轉換為HttpServletRequest和HttpServletResponse類型進行操作
(3)destroy():
在Web容器卸載?Filter?對象之前被調用。
package?com.itheima.filter;
import?java.io.IOException;
import?java.util.Enumeration;
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?com.sun.net.httpserver.Filter.Chain;
public?class?Filter1?implements?Filter?{
public?Filter1()?{
System.out.println("Filter被創建出來了。。。");
}
public?void?destroy()?{
System.out.println("destory......");
}
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
System.out.println("dofilter....");
chain.doFilter(request,?response);
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
System.out.println("init.....");
String?value1?=?filterConfig.getInitParameter("param1");
System.out.println(value1);
Enumeration?enumeration?=filterConfig.getInitParameterNames();
while(enumeration.hasMoreElements()){
String?name?=?(String)?enumeration.nextElement();
String?value?=?filterConfig.getInitParameter(name);
System.out.println(name+":"+value);
}
filterConfig.getServletContext();
}
}
?5、FilterConfig接口
(1)用戶在配置filter時,可以使用為filter配置一些初始化參數,當web容器實例化Filter對象,調用其init方法時,會把封裝了filter初始化參數的filterConfig對象傳遞進來。因此開發人員在編寫filter時,通過filterConfig對象的方法,就可獲得:
String?getFilterName():得到filter的名稱。
String?getInitParameter(String?name):?返回在部署描述中指定名稱的初始化參數的值。如果不存在返回null.
Enumeration?getInitParameterNames():返回過濾器的所有初始化參數的名字的枚舉集合。
public?ServletContext?getServletContext():返回Servlet上下文對象的引用。
(2)FilterConfig?提供參數,是Filter類私有參數,Filter2的初始化參數,不能在Filter1?中進行獲取?
(3)?配置全局參數,?進行配置,通過ServletContext?獲得?
(4)實驗:得到filter配置信息
6、注冊Filter
??????testFitler
?????org.test.TestFiter
?????
?word_file
?/WEB-INF/word.txt
?????
用于為過濾器指定一個名字,該元素的內容不能為空。
元素用于指定過濾器的完整的限定類名。
元素用于為過濾器指定初始化參數,它的子元素指定參數的名字,指定參數的值。在過濾器中,可以使用FilterConfig接口對象來訪問初始化參數。
7、映射Filter
元素用于設置一個?Filter?所負責攔截的資源。一個Filter攔截的資源可通過兩種方式來指定:Servlet?名稱和資源訪問的請求路徑
(1)子元素用于設置filter的注冊名稱。該值必須是在元素中聲明過的過濾器的名字
(2)設置?filter?所攔截的請求路徑(過濾器關聯的URL樣式)
(3)指定過濾器所攔截的Servlet名稱。
(4)指定過濾器所攔截的資源被?Servlet?容器調用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默認REQUEST。用戶可以設置多個?子元素用來指定?Filter?對資源的多種調用方式進行攔截。
(5)?過濾器攔截配置
如果連接目標資源是一個Servlet,可以選擇url和servlet名稱兩種配置方式?
攔截/hello是Servlet?路徑?-->
/hello
攔截Servlet?還可以通過Servlet?名稱進行攔截?-->
HelloServlet
(6)url-pattern?和?Servlet中路徑寫法一樣,有三種?:?完全匹配、目錄匹配、擴展名匹配
(7)指定過濾器所攔截的資源被?Servlet?容器調用的方式
容器調用服務器端資源?有四種方式?
REQUEST、FORWARD、INCLUDE、ERROR
8、映射Filter的多種方式
?子元素可以設置的值及其意義:
REQUEST:當用戶直接訪問頁面時,Web容器將會調用過濾器。如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那么該過濾器就不會被調用。
INCLUDE:如果目標資源是通過RequestDispatcher的include()方法訪問時,那么該過濾器將被調用。除此之外,該過濾器不會被調用。
FORWARD:如果目標資源是通過RequestDispatcher的forward()方法訪問時,那么該過濾器將被調用,除此之外,該過濾器不會被調用。
ERROR:如果目標資源是通過聲明式異常處理機制調用時,那么該過濾器將被調用。除此之外,過濾器不會被調用
9、映射Filter示例
?????testFilter
????/test.jsp
????testFilter
???/index.jsp
???REQUEST
???FORWARD
10、Filter常見應用
(1)統一全站字符編碼的過濾器
通過配置參數encoding指明使用何種字符編碼,以處理Html?Form請求參數的中文問題
案例:編寫jsp?輸入用戶名,在Servlet中獲取用戶名,將用戶名輸出到瀏覽器上?
處理請求post亂碼代碼
request.setCharacterEncoding("utf-8");
設置響應編碼集代碼
response.setContentType("text/html;charset=utf-8");
經常會使用,而過濾器可以在目標資源之前執行,將很多程序中處理亂碼公共代碼,提取到過濾器中?,以后程序中不需要處理編碼問題了?
package?com.itheima.filter;
import?java.io.IOException;
import?java.io.UnsupportedEncodingException;
import?java.util.Map;
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?{
private?FilterConfig?config?=?null;
public?void?destroy()?{
}
/**
?*?全站亂碼解決
?*/
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
HttpServletRequest?req?=?(HttpServletRequest)?request;
chain.doFilter(new?MyRequest(req),?response);
}
class?MyRequest?extends?HttpServletRequestWrapper?{
private?HttpServletRequest?request?=?null;
private?boolean?isEncode?=?false;
public?MyRequest(HttpServletRequest?request)?{
super(request);
this.request?=?request;
}
@Override
public?Map?getParameterMap()?{
if?(request.getMethod().equalsIgnoreCase("post"))?{
try?{
request.setCharacterEncoding(config.getInitParameter("encode"));
return?request.getParameterMap();
}?catch?(UnsupportedEncodingException?e)?{
e.printStackTrace();
}
}?else?if?(request.getMethod().equalsIgnoreCase("get"))?{
try?{
Map?map?=?request.getParameterMap();
if(!isEncode){
for?(String?key?:?map.keySet())?{
String?[]?vs?=?map.get(key);
for(int?i=0;i<vs.length;i++){
String?v?=?vs[i];
v?=?new?String(v.getBytes("iso8859-1"),?config.getInitParameter("encode"));
vs[i]?=?v;
}
}
isEncode?=?true;
}
return?map;
}?catch?(Exception?e)?{
e.printStackTrace();
}
}
return?super.getParameterMap();
}
@Override
public?String[]?getParameterValues(String?name)?{
if(getParameterMap().get(name)==null)return?null;
return?(String[])getParameterMap().get(name);
}
@Override
public?String?getParameter(String?name)?{
if(getParameterMap().get(name)==null)return?null;
return?((String[])getParameterMap().get(name))[0];
}
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
this.config?=?filterConfig;
}
}
package?com.itheima.web;
import?java.io.IOException;
import?java.util.Map;
import?javax.servlet.ServletException;
import?javax.servlet.http.HttpServlet;
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
public?class?EncodeTestServlet?extends?HttpServlet?{
public?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)
throws?ServletException,?IOException?{
String?vs?=?request.getParameterValues("username")[0];
System.out.println(vs);
String?value?=?request.getParameter("username");
System.out.println(value);
}
public?void?doPost(HttpServletRequest?request,?HttpServletResponse?response)
throws?ServletException,?IOException?{
doGet(request,?response);
}
}
filter>
filter-name>encodefilter-name>
filter-class>com.itheima.filter.EncodingFilterfilter-class>
init-param>
param-name>encodeparam-name>
param-value>utf-8param-value>
init-param>
filter>
filter-mapping>
filter-name>encodefilter-name>
url-pattern>/*url-pattern>
filter-mapping>
(2)禁止瀏覽器緩存所有動態頁面的過濾器:
有?3?個?HTTP?響應頭字段都可以禁止瀏覽器緩存當前頁面,它們在?Servlet?中的示例代碼如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");?
response.setHeader("Pragma","no-cache");?
并不是所有的瀏覽器都能完全支持上面的三個響應頭,因此最好是同時使用上面的三個響應頭。
Expires數據頭:值為GMT時間值,為-1指瀏覽器不要緩存頁面
Cache-Control響應頭有兩個常用值:?
no-cache指瀏覽器不要緩存當前頁面。
max-age:xxx指瀏覽器緩存頁面xxx秒。
package?com.itheima.filter;
import?java.io.IOException;
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.HttpServletResponse;
public?class?NoChachFilter?implements?Filter?{
public?void?destroy()?{
//?TODO?Auto-generated?method?stub
}
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
HttpServletResponse?resp?=?(HttpServletResponse)?response;
??resp.setDateHeader("Expires",-1);
??resp.setHeader("Cache-Control","no-cache");
??resp.setHeader("Pragma","no-cache");
chain.doFilter(request,?response);
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
//?TODO?Auto-generated?method?stub
}
}
nocach
com.itheima.filter.NoChachFilter
nocach
*.jsp
(3)控制瀏覽器緩存頁面中的靜態資源的過濾器:
場景:有些動態頁面中引用了一些圖片或css文件以修飾頁面效果,這些圖片和css文件經常是不變化的,所以為減輕服務器的壓力,可以使用filter控制瀏覽器緩存這些文件,以提升服務器的性能。
Tomcat緩存策略?
對于服務器端經常不變化文件,設置客戶端緩存時間,在客戶端資源緩存時間到期之前,就不會去訪問服務器獲取該資源?--------?比tomcat內置緩存策略更優手段?
*?減少服務器請求次數,提升性能?
設置靜態資源緩存時間,需要設置?Expires?過期時間?,在客戶端資源沒有過期之前,不會產生對該資源的請求的?
*?設置Expires?通常使用?response.setDateHeader?進行設置?設置毫秒值?
package?com.itheima.filter;
import?java.io.IOException;
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.HttpServletResponse;
public?class?CacheFilter?implements?Filter?{
public?void?destroy()?{
//?TODO?Auto-generated?method?stub
}
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
HttpServletResponse?resp?=?(HttpServletResponse)?response;
resp.setDateHeader("Expires",?System.currentTimeMillis()+3600l*24*30*1000);
chain.doFilter(request,?response);
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
//?TODO?Auto-generated?method?stub
}
}
cache
com.itheima.filter.CacheFilter
cache
*.jpg
*.gif
*.png
REQUEST
(4)實現用戶自動登陸的過濾器
在用戶登陸成功后,以cookis形式發送用戶名、密碼給客戶端
編寫一個過濾器,filter方法中檢查cookie中是否帶有用戶名、密碼信息,如果存在則調用業務層登陸方法,登陸成功后則向session中存入user對象(即用戶登陸標記),以實現程序完成自動登陸。
在訪問一個站點,登陸時勾選自動登陸(三個月內不用登陸),操作系統后,關閉瀏覽器;過幾天再次訪問該站點時,直接進行登陸后狀態?
在數據庫中創建?user表
create?table?user?(
???id?int?primary?key?auto_increment,
???username?varchar(20),
???password?varchar(40),
???role?varchar(10)
);
insert?into?user?values(null,'admin','123','admin');
insert?into?user?values(null,'aaa','123','user');
insert?into?user?values(null,'bbb','123','user');
自動登陸?:未登錄、存在自動登陸信息、自動登陸信息正確?
在用戶完成登陸后,勾選自動登陸復選框,服務器端將用戶名和密碼?以Cookie形式,保存在客戶端?。當用戶下次訪問該站點,AutoLoginFilter?過濾器從Cookie中獲取?自動登陸信息?
1、判斷用戶是否已經登陸,如果已經登陸,沒有自動登陸的必要
2、判斷Cookie中是否含有自動登陸信息?,如果沒有,無法完成自動登陸
3、使用cookie用戶名和密碼?完成自動登陸?
?page?language="java"?import="java.util.*"?pageEncoding="utf-8"%>
DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN">
html>
??head>
??head>
??body>
???form?action="${pageContext.request.contextPath?}/servlet/LoginServlet2"?method="post">
?? 用戶名input?type="text"?name="username"/>
?? 密碼input?type="text"?name="password"/>
???input?type="checkbox"?name="autoLogin"?value="true"?/>一個月內自動登錄
???input?type="submit"?value="登錄"/>
???form>
??body>
html>
package?com.itheima.autologin;
import?java.io.IOException;
import?javax.servlet.ServletException;
import?javax.servlet.http.Cookie;
import?javax.servlet.http.HttpServlet;
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
import?org.apache.commons.dbutils.QueryRunner;
import?org.apache.commons.dbutils.handlers.BeanHandler;
import?com.itheima.domain.User;
import?com.itheima.util.DaoUtil;
import?com.itheima.util.MD5Util;
public?class?LoginServlet2?extends?HttpServlet?{
public?void?doGet(HttpServletRequest?request,?HttpServletResponse?response)
throws?ServletException,?IOException?{
try{
//1.校驗用戶名密碼是否正確
QueryRunner?runner?=?new?QueryRunner(DaoUtil.getSource());
User?user?=?runner.query("select?*?from?user?where?username=??and?password=?",?new?BeanHandler(User.class),request.getParameter("username"),MD5Util.md5(request.getParameter("password")));
if(user?==?null){
request.setAttribute("msg",?"用戶名密碼不正確!!");
request.getRequestDispatcher("/login.jsp").forward(request,?response);
return;
}else{
//用戶名密碼都正確,在session域中保存用戶的登錄狀態
request.getSession().setAttribute("user",?user);
//如果勾選過一個月內自動登錄,發送cookie信息給瀏覽器,使瀏覽器保存用戶名密碼一個月
if(request.getParameter("autoLogin")!=null){
Cookie?cookie?=?new?Cookie("autologin",user.getUsername()+":"+user.getPassword());
cookie.setMaxAge(3600*24*30);
cookie.setPath(request.getContextPath());
response.addCookie(cookie);
}
response.sendRedirect(request.getContextPath()+"/autologin/homepage.jsp");
}
}catch?(Exception?e)?{
e.printStackTrace();
}
}
public?void?doPost(HttpServletRequest?request,?HttpServletResponse?response)
throws?ServletException,?IOException?{
doGet(request,?response);
}
}
?page?language="java"?import="java.util.*"?pageEncoding="utf-8"%>
?taglib?uri="http://java.sun.com/jsp/jstl/core"?prefix="c"?%>
DOCTYPE?HTML?PUBLIC?"-//W3C//DTD?HTML?4.01?Transitional//EN">
html>
??head>
??head>
??body>
???c:if?test="${sessionScope.user?==?null}">
?? 歡迎光臨游客!a?href="${pageContext.request.contextPath?}/autologin/login.jsp">登錄a>
???c:if>
???c:if?test="${sessionScope.user?!=?null}">
?? 歡迎回來
???c:if>
??body>
html>
package?com.itheima.filter;
import?java.io.IOException;
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.Cookie;
import?javax.servlet.http.HttpServletRequest;
import?org.apache.commons.dbutils.QueryRunner;
import?org.apache.commons.dbutils.handlers.BeanHandler;
import?com.itheima.domain.User;
import?com.itheima.util.DaoUtil;
public?class?AutoLoginFilter?implements?Filter?{
public?void?destroy()?{
}
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
HttpServletRequest?req?=?(HttpServletRequest)?request;
//1.檢查用戶是否已經登錄
if(req.getSession(false)?==?null?||?req.getSession().getAttribute("user")==null){
//2.如果用戶沒有登錄過,則檢查是否帶了autologincookie
Cookie?[]?cs?=?req.getCookies();
Cookie?findc?=?null;
if(cs!=null){
for(Cookie?c?:?cs){
if(c.getName().equals("autologin")){
findc?=?c;
break;
}
}
}
if(findc?!=?null){
//3.如果有autologin?cookie,獲取cookie的值,檢查用戶名密碼是否正確
String?username?=?findc.getValue().split(":")[0];
String?password?=?findc.getValue().split(":")[1];
//4.如果用戶名密碼都正確,則自動登錄一把
try{
QueryRunner?runner?=?new?QueryRunner(DaoUtil.getSource());
User?user?=?runner.query("select?*?from?user?where?username=??and?password=?",?new?BeanHandler(User.class),username,password);
if(user!=null){
req.getSession().setAttribute("user",?user);
}
}catch?(Exception?e)?{
e.printStackTrace();
}
}
}
//5.放行資源
chain.doFilter(request,?response);
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
//?TODO?Auto-generated?method?stub
}
}
autologinFilter
com.itheima.filter.AutoLoginFilter
autologinFilter
/*
(5)使用Filter實現URL級別的權限認證
(1)情景:在實際開發中我們經常把一些執行敏感操作的servlet映射到一些特殊目錄中,并用filter把這些特殊目錄保護起來,限制只能擁有相應訪問權限的用戶才能訪問這些目錄下的資源。從而在我們系統中實現一種URL級別的權限功能。
要求:為使Filter具有通用性,Filter保護的資源和相應的訪問權限通過filter參數的形式予以配置。
(2)系統中存在很多資源,將需要進行權限控制的資源,放入特殊路徑中,編寫過濾器管理訪問特殊路徑的請求,如果沒有相應身份和權限,控制無法訪問?
認證:who?are?you???用戶身份的識別?------------?登陸功能
權限:以認證為基礎?what?can?you?do???您能做什么??必須先登陸,才有身份,有了身份,才能確定可以執行哪些操作?
package?com.itheima.filter;
import?java.io.IOException;
import?java.util.Enumeration;
import?java.util.HashMap;
import?java.util.Map;
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.HttpSession;
import?com.itheima.domain.User;
public?class?PrivilegeFilter?implements?Filter?{
private?FilterConfig?config?=?null;
private?Map?map?=?new?HashMap();
public?void?destroy()?{
//?TODO?Auto-generated?method?stub
}
public?void?doFilter(ServletRequest?request,?ServletResponse?response,
FilterChain?chain)?throws?IOException,?ServletException?{
//1.當前訪問的資源是否需要權限(當前訪問資源路徑是否是map中具有的需要權限控制的路徑的子路徑)
HttpServletRequest?req?=?(HttpServletRequest)?request;
String?uri?=?req.getRequestURI();
uri?=?uri.substring(config.getServletContext().getContextPath().length());
String?privilege?=?null;
for(String?name?:?map.keySet()){
if(uri.startsWith(name)){
privilege?=?map.get(name);
}
}
if(privilege?==?null){
//2.如果不需要權限,直接放行
chain.doFilter(request,?response);
return;
}else{//3.如果需要權限,判斷當前用戶具有的權限和訪問該資源需要的權限是否相匹配,如果匹配就放行,如果不匹配則提示
HttpSession??session?=?req.getSession(false);
if(session?==?null?||?session.getAttribute("user")==null){
throw?new?RuntimeException("請先登錄");
}
User?user?=?(User)?session.getAttribute("user");
if(user.getRole().equals(privilege)){
chain.doFilter(request,?response);
return;
}else{
throw?new?RuntimeException("沒有對應的權限!!!!");
}
}
}
public?void?init(FilterConfig?filterConfig)?throws?ServletException?{
this.config?=?filterConfig;
Enumeration?enumeration?=?config.getInitParameterNames();
while(enumeration.hasMoreElements()){
String?name?=?(String)?enumeration.nextElement();
String?value?=?config.getInitParameter(name);
map.put(name,?value);
}
}
}
PrivilegeFilter
com.itheima.filter.PrivilegeFilter
param>
/admin
admin
param>
param>
/user
user
param>
PrivilegeFilter
/*
11、MD5加密
/**
?*?使用md5的算法進行加密
?*/
public?static?String?md5(String?plainText)?{
byte[]?secretBytes?=?null;
try?{
secretBytes?=?MessageDigest.getInstance("md5").digest(
plainText.getBytes());
}?catch?(NoSuchAlgorithmException?e)?{
throw?new?RuntimeException("沒有md5這個算法!");
}
String?md5code?=?new?BigInteger(1,?secretBytes).toString(16);
for?(int?i?=?0;?i?
md5code?=?"0"?+?md5code;
}
return?md5code;
}
如果將用戶密碼保存在cookie文件中,非常不安全的?,通常情況下密碼需要加密后才能保存到客戶端?
*?使用md5算法對密碼進行加密?
*?md5?加密算法是一個單向加密算法?,支持明文---密文?不支持密文解密?
MySQL數據庫中提供md5?函數,可以完成md5?加密
mysql>?select?md5('123');?
+----------------------------------+
|?md5('123')???????????????????????|
+----------------------------------+
|?202cb962ac59075b964b07152d234b70?|
+----------------------------------+
解密后結果是32位數字?16進制表示?
Java中提供類?MessageDigest?完成MD5加密
------------------------------------------------------------------
將數據表中所有密碼?變為密文?update?user?set?password?=?md5(password)?;
在Demo4Servlet?登陸邏輯中,對密碼進行md5?加密?
在AutoLoginFilter?因為從Cookie中獲得就是加密后密碼,所以登陸時無需再次加密?
------------------------------------------------------------------
MD5?在2004?年被王小云破解,md5算法是多對一加密算法,出現兩個加密后相同密文的明文很難發現?,王小云并沒有研究出md5?解密算法,研究出一種提高碰撞概率的算法?
12、Filter高級開發
(1)由于開發人員在filter中可以得到代表用戶請求和響應的request、response對象,因此在編程中可以使用Decorator(裝飾器)模式對request、response對象進行包裝,再把包裝對象傳給目標資源,從而實現一些特殊需求。
(2)Decorator設計模式的實現
1.首先看需要被增強對象繼承了什么接口或父類,編寫一個類也去繼承這些接口或父類。
2.在類中定義一個變量,變量類型即需增強對象的類型。
3.在類中定義一個構造函數,接收需增強的對象。
4.覆蓋需增強的方法,編寫增強的代碼。
(3)Decorator模式?
1、包裝類需要和被包裝對象?實現相同接口,或者繼承相同父類
2、包裝類需要持有?被包裝對象的引用?
在包裝類中定義成員變量,通過包裝類構造方法,傳入被包裝對象?
3、在包裝類中,可以控制原來那些方法需要加強
不需要加強?,調用被包裝對象的方法
需要加強,編寫增強代碼邏輯?
ServletRequestWrapper?和?HttpServletRequestWrapper?提供對request對象進行包裝的方法,但是默認情況下每個方法都是調用原來request對象的方法,也就是說包裝類并沒有對request進行增強?
在這兩個包裝類基礎上,繼承HttpServletRequestWrapper?,覆蓋需要增強的方法即可?
13、request對象的增強
(1)Servlet?API?中提供了一個request對象的Decorator設計模式的默認實現類HttpServletRequestWrapper?,?(HttpServletRequestWrapper?類實現了request?接口中的所有方法,但這些方法的內部實現都是僅僅調用了一下所包裝的的?request?對象的對應方法)以避免用戶在對request對象進行增強時需要實現request接口中的所有方法。
(2)使用Decorator模式包裝request對象,完全解決get、post請求方式下的亂碼問題
14、response對象的增強
Servlet??API?中提供了response對象的Decorator設計模式的默認實現類HttpServletResponseWrapper?,?(HttpServletResponseWrapper類實現了response接口中的所有方法,但這些方法的內部實現都是僅僅調用了一下所包裝的的?response對象的對應方法)以避免用戶在對response對象進行增強時需要實現response接口中的所有方法。
15、response增強案例—壓縮響應
應用HttpServletResponseWrapper對象,壓縮響應正文內容。思路:
通過filter向目標頁面傳遞一個自定義的response對象。
在自定義的response對象中,重寫getOutputStream方法和getWriter方法,使目標資源調用此方法輸出頁面內容時,獲得的是我們自定義的ServletOutputStream對象。
在我們自定義的ServletOuputStream對象中,重寫write方法,使寫出的數據寫出到一個buffer中。
當頁面完成輸出后,在filter中就可得到頁面寫出的數據,從而我們可以調用GzipOuputStream對數據進行壓縮后再寫出給瀏覽器,以此完成響應正文件壓縮功能。
復習:Tomcat服務器內,提供對響應壓縮?配置實現?
在conf/server.xml?中?
???????????????connectionTimeout="20000"?
???????????????redirectPort="8443"/>?添加?compressableMimeType?和?compression
沒有壓縮?:??00:00:00.0000.0637553GET200text/htmlhttp://localhost/
???????????????connectionTimeout="20000"?
???????????????redirectPort="8443"?compressableMimeType="text/html,text/xml,text/plain"?compression="on"/>
壓縮后?:??00:00:00.0000.1712715GET200text/htmlhttp://localhost/?
Content-Encoding:?gzip
Content-Length?:?2715
實際開發中,很多情況下,沒有權限配置server.xml??,無法通過tomcat配置開啟gzip?壓縮
編寫過濾器對響應數據進行gzip壓縮?
flush?方法
只有沒有緩沖區字節流,FileOutputStream?不需要flush?
而字節數組ByteArrayOutputStream、字節包裝流、字符流?需要flush?-----?這些流在調用close方法時都會自動flush?
- 誰能舉個通俗易懂的例子告訴我IAAS,SAAS,PAAS的區別?
- 服務器與容器
- 常見NIO框架
- Nginx/Apache 和Apache Tomcat 的區別
- tomcat結合nginx使用小結
- java nio框架netty 與tomcat的關系
- Nginx、Lighttpd與Apache的區別
- Apache vs Lighttpd vs Nginx對比
- 數據庫
- mybatis
- MyBatis傳入多個參數的問題
- MS
- JMS(Java消息服務)入門教程
- ActiveMQ
- JMS簡介與ActiveMQ實戰
- JMS-使用消息隊列優化網站性能
- 深入淺出JMS(一)--JMS基本概念
- 深入淺出JMS(二)--ActiveMQ簡單介紹以及安裝
- 深入淺出JMS(三)--ActiveMQ簡單的HelloWorld實例
- RabbitMq、ActiveMq、ZeroMq、kafka之間的比較,資料匯總
- kafka
- zookeeper
- 集群與負載
- 單機到分布式集群
- 日志
- 從Log4j遷移到LogBack的理由
- 角色權限
- shiro
- Shiro的認證和權限控制
- Spring 整合 Apache Shiro 實現各等級的權限管理
- 安全
- basic
- Servlet、Filter、Listener深入理解
- filter與servlet的比較
- Servlet Filter