一、Filter簡介css
(1)Filter也稱之爲過濾器,它是Servlet技術中最實用的技術,WEB開發人員經過Filter技術,對web服務器管理的全部web資源:例如Jsp, Servlet, 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現URL級別的權限訪問控制、過濾敏感詞彙、壓縮響應信息等一些高級功能。html
(2)Servlet API中提供了一個Filter接口,開發web應用時,若是編寫的Java類實現了這個接口,則把這個java類稱之爲過濾器Filter。經過Filter技術,開發人員能夠實現用戶在訪問某個目標資源以前,對訪問的請求和響應進行攔截,以下所示:java
2、Filter是如何實現攔截的?mysql
Filter接口中有一個doFilter方法,當開發人員編寫好Filter,並配置對哪一個web資源(攔截url)進行攔截後,WEB服務器每次在調用web資源以前,都會先調用一下filter的doFilter方法,所以,在該方法內編寫代碼可達到以下目的:web
調用目標資源以前,讓一段代碼執行算法
是否調用目標資源(便是否讓用戶訪問web資源)。sql
web服務器在調用doFilter方法時,會傳遞一個filterChain對象進來,filterChain對象是filter接口中最重要的一個對象,它也提供了一個doFilter方法,開發人員能夠根據需求決定是否調用此方法,調用該方法,則web服務器就會調用web資源的service方法,即web資源就會被訪問,不然web資源不會被訪問。數據庫
調用目標資源以後,讓一段代碼執行apache
三、Filter開發入門編程
(1)Filter開發分爲二個步驟:
編寫java類實現Filter接口,並實現(三個方法)其doFilter方法。
在 web.xml 文件中使用<filter>和<filter-mapping>元素對編寫的filter類進行註冊,並設置它所能攔截的資源。
(2)Filter鏈 ---
在一個web應用中,能夠開發編寫多個Filter,這些Filter組合起來稱之爲一個Filter鏈。
web服務器根據Filter在web.xml文件中的註冊順序<mapping>,決定先調用哪一個Filter,當第一個Filter的doFilter方法被調用時,web服務器會建立一個表明Filter鏈的FilterChain對象傳遞給該方法。在doFilter方法中,開發人員若是調用了FilterChain對象的doFilter方法,則web服務器會檢查FilterChain對象中是否還有filter,若是有,則調用第2個filter,若是沒有,則調用目標資源。
Filter鏈實驗(查看filterChain API文檔)
四、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時,可使用<init-param>爲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) 配置全局參數,<context-param> 進行配置,經過ServletContext 得到
(4)實驗:獲得filter配置信息
六、註冊Filter
<filter>
<filter-name>testFitler</filter-name>
<filter-class>org.test.TestFiter</filter-class>
<init-param>
<param-name>word_file</param-name>
<param-value>/WEB-INF/word.txt</param-value>
</init-param>
</filter>
<filter-name>用於爲過濾器指定一個名字,該元素的內容不能爲空。
<filter-class>元素用於指定過濾器的完整的限定類名。
<init-param>元素用於爲過濾器指定初始化參數,它的子元素<param-name>指定參數的名字,<param-value>指定參數的值。在過濾器中,可使用FilterConfig接口對象來訪問初始化參數。
七、映射Filter
<filter-mapping>元素用於設置一個 Filter 所負責攔截的資源。一個Filter攔截的資源可經過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑
(1)<filter-name>子元素用於設置filter的註冊名稱。該值必須是在<filter>元素中聲明過的過濾器的名字
(2)<url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
(3)<servlet-name>指定過濾器所攔截的Servlet名稱。
(4)<dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式,能夠是REQUEST,INCLUDE,FORWARD和ERROR之一,默認REQUEST。用戶能夠設置多個<dispatcher> 子元素用來指定 Filter 對資源的多種調用方式進行攔截。
(5)<filter-mapping> 過濾器攔截配置
若是鏈接目標資源是一個Servlet,能夠選擇url和servlet名稱兩種配置方式
<!-- 攔截/hello是Servlet 路徑 -->
<url-pattern>/hello</url-pattern>
<!-- 攔截Servlet 還能夠經過Servlet 名稱進行攔截 -->
<servlet-name>HelloServlet</servlet-name>
(6)url-pattern 和 Servlet中路徑寫法同樣,有三種 : 徹底匹配、目錄匹配、擴展名匹配
(7)<dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式
容器調用服務器端資源 有四種方式
REQUEST、FORWARD、INCLUDE、ERROR
八、映射Filter的多種方式
<dispatcher> 子元素能夠設置的值及其意義:
REQUEST:當用戶直接訪問頁面時,Web容器將會調用過濾器。若是目標資源是經過RequestDispatcher的include()或forward()方法訪問時,那麼該過濾器就不會被調用。
INCLUDE:若是目標資源是經過RequestDispatcher的include()方法訪問時,那麼該過濾器將被調用。除此以外,該過濾器不會被調用。
FORWARD:若是目標資源是經過RequestDispatcher的forward()方法訪問時,那麼該過濾器將被調用,除此以外,該過濾器不會被調用。
ERROR:若是目標資源是經過聲明式異常處理機制調用時,那麼該過濾器將被調用。除此以外,過濾器不會被調用
九、映射Filter示例
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
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<String, String[]> 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>encode</filter-name>
<filter-class>com.itheima.filter.EncodingFilter</filter-class>
<init-param>
<param-name>encode</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-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
}
}
<filter>
<filter-name>nocach</filter-name>
<filter-class>com.itheima.filter.NoChachFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>nocach</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
(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
}
}
<filter>
<filter-name>cache</filter-name>
<filter-class>com.itheima.filter.CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cache</filter-name>
<url-pattern>*.jpg</url-pattern>
<url-pattern>*.gif</url-pattern>
<url-pattern>*.png</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
(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>(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>(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
}
}
<filter>
<filter-name>autologinFilter</filter-name>
<filter-class>com.itheima.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autologinFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(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<String, String> map = new HashMap<String, String>();
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);
}
}
}
<filter>
<filter-name>PrivilegeFilter</filter-name>
<filter-class>com.itheima.filter.PrivilegeFilter</filter-class>
<init-param>
<param-name>/admin</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>/user</param-name>
<param-value>user</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>PrivilegeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
十一、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 < 32 - md5code.length(); 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接口中的全部方法。
1五、response加強案例—壓縮響應
應用HttpServletResponseWrapper對象,壓縮響應正文內容。思路:
經過filter向目標頁面傳遞一個自定義的response對象。
在自定義的response對象中,重寫getOutputStream方法和getWriter方法,使目標資源調用此方法輸出頁面內容時,得到的是咱們自定義的ServletOutputStream對象。
在咱們自定義的ServletOuputStream對象中,重寫write方法,使寫出的數據寫出到一個buffer中。
當頁面完成輸出後,在filter中就可獲得頁面寫出的數據,從而咱們能夠調用GzipOuputStream對數據進行壓縮後再寫出給瀏覽器,以此完成響應正文件壓縮功能。
複習:Tomcat服務器內,提供對響應壓縮 配置實現
在conf/server.xml 中
<Connector port="80" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/> 添加 compressableMimeType 和 compression
沒有壓縮 : 00:00:00.0000.0637553GET200text/htmlhttp://localhost/
<Connector port="80" protocol="HTTP/1.1"
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