Filter
本節(jié)內(nèi)容:
filter的簡介
快速入門
filter的API詳解
filter的配置
案例一:自動登錄
案例二:解決全局代碼
一、filter的簡介
filter是對客戶端訪問資源的過濾,符合條件放行,不符合條件不放行,并且可以對目標(biāo)資源訪問前后進(jìn)行邏輯處理。
二、快速入門
【步驟】:
編寫一個過濾器的類實(shí)現(xiàn)Filter接口
實(shí)現(xiàn)接口中尚未實(shí)現(xiàn)的方法(著重實(shí)現(xiàn)doFilter方法)
在web.xml中進(jìn)行配置(主要是配置要對哪些資源進(jìn)行過濾)
public class QuickFilter1 implements Filter{
@Override
//Filter創(chuàng)建的時候執(zhí)行init方法
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
//doFilter是Filter的核心過濾的方法
/*
* request: 內(nèi)部封裝是客戶端http請求的內(nèi)容
* response: 代表是響應(yīng)
* FilterChain: 過濾器鏈對象
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("quick1 running....");
//放行請求。如果不放行,請求將不會到達(dá)你想訪問的資源
chain.doFilter(request, response);
}
@Override
//Filter對象銷毀的時候執(zhí)行destory方法
public void destroy() {
System.out.println("destroy...");
}
}
QuickFilter1.java --過濾器
public class Servlet1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Servlet1 running....");
response.getWriter().write("Servlet1 running....");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Servlet1.java --作為被攔截的資源
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>WEB24</display-name>
<filter>
<filter-name>QuickFilter1</filter-name>
<filter-class>com.ithiema.web.filter.QuickFilter1</filter-class>
</filter>
<filter-mapping>
<filter-name>QuickFilter1</filter-name>
<url-pattern>/*</url-pattern> <!-- 配置對哪些資源攔截 -->
</filter-mapping>
<servlet>
<description></description>
<display-name>Servlet1</display-name>
<servlet-name>Servlet1</servlet-name>
<servlet-class>com.ithiema.web.servlet.Servlet1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/servlet1</url-pattern>
</servlet-mapping>
</web-app>
web.xml
瀏覽器訪問servlet1資源,在控制臺可以看出先走的QuickFilter1,然后在到Servlet1資源。
filter的訪問流程:
至于圖中的哪個filter在前面,根據(jù)各個filter在web.xml文件中的位置,注意是看<filter-mapping>的位置,不是看<filter>的位置。
三、filter的API詳解
(1)filter生命周期及其與生命周期相關(guān)的方法
Filter接口有三個方法,并且這個三個都是與Filter的生命相關(guān)的方法
init(Filterconfig):代表filter對象初始化方法。即filter對象創(chuàng)建時執(zhí)行。
doFilter(ServletRequest,ServletResponse,FilterCha):代表filter執(zhí)行過濾的核心方法,如果某資源在已經(jīng)被配置到這個filter進(jìn)行過濾的話,那么每次訪問這個資源都會執(zhí)行doFilter方法。
destory():代表是filter銷毀方法,當(dāng)filter對象銷毀時執(zhí)行該方法。
Filter對象的生命周期:
Filter何時創(chuàng)建:服務(wù)器啟動時就創(chuàng)建該filter對象。
Filter何時銷毀:服務(wù)器關(guān)閉時filter銷毀。
(2)Filter的AP詳解
1)init(FilterConfig)
其中參數(shù)config代表 該Filter對象的配置信息的對象,內(nèi)部封裝是該filter的配置信息。
2)destory()方法
filter對象銷毀時執(zhí)行
3)doFilter方法
doFilter(ServletRequest,ServletResponse,FilterChain)
其中的參數(shù):
ServletRequest/ServletResponse:每次在執(zhí)行doFilter方法時 web容器負(fù)責(zé)創(chuàng)建一個request和一個response對象作為doFilter的參數(shù)傳遞進(jìn)來。該request個該response就是在訪問目標(biāo)資源的service方法時的request和response。
FilterChain:過濾器鏈對象,通過該對象的doFilter方法可以放行該請求。
四、filter的配置
配置示例:
<filter>
<filter-name>QuickFilter2</filter-name>
<filter-class>com.ithiema.web.filter.QuickFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>QuickFilter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
url-pattern配置:
完全匹配 /sertvle1
目錄匹配 /aaa/bbb/* --最多的
/user/*:訪問前臺的資源進(jìn)入此過濾器
/admin/*:訪問后臺的資源時執(zhí)行此過濾器
擴(kuò)展名匹配 *.abc *.jsp
【注意】:url-pattern可以使用servlet-name替代,也可以混用。比如:
<filter-mapping>
<filter-name>QuickFilter2</filter-name>
<!--<url-pattern>/Servlet1</url-pattern>-->
<servlet-name>Servlet1</servlet-name> <!-- 和上面那行配置是等效的 -->
</filter-mapping>
dispatcher:訪問的方式(了解)。dispatcher是可以配置在<filter-mapping>中的屬性,沒配置的話,它有個默認(rèn)值。
REQUEST:默認(rèn)值,代表直接訪問某個資源時執(zhí)行filter。重定向也叫直接訪問,只不過是客戶端自動去訪問的,不是你在瀏覽器自己輸入去訪問的。
FORWARD:轉(zhuǎn)發(fā)時才執(zhí)行filter
INCLUDE: 包含資源時執(zhí)行filter
ERROR:發(fā)生錯誤時、進(jìn)行跳轉(zhuǎn)時執(zhí)行filter
<filter>
<filter-name>QuickFilter2</filter-name>
<filter-class>com.ithiema.web.filter.QuickFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>QuickFilter2</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
總結(jié)Filter的作用:
公共代碼的提取
可以對request和response中的方法進(jìn)行增強(qiáng)(裝飾者模式或動態(tài)代理)
進(jìn)行權(quán)限控制
五、案例一:自動登錄
自動登錄的filter是功能增強(qiáng)的,并不是進(jìn)行攔截的。帶著用戶名和密碼的cookie,就幫忙自動登上去,沒帶也放行,該訪問誰訪問誰。
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); //POST提交要寫這個,可以在filter里寫上這句話,這樣每個接收數(shù)據(jù)的Servlet中就不用寫這句話了
//但是這種方式對GET不生效
HttpSession session = request.getSession();
//獲取數(shù)據(jù)
String username = request.getParameter("username");//中文 張三
String password = request.getParameter("password");
UserService service = new UserService();
User user = null;
try {
user = service.login(username,password);
} catch (SQLException e) {
e.printStackTrace();
}
if(user!=null){
//登錄成功
//判斷用戶是否勾選自動登錄,如果登錄,將用戶名和密碼設(shè)置進(jìn)cookie
String autoLogin = request.getParameter("autoLogin");
if(autoLogin!=null){
//對中文張三進(jìn)行編碼,要存入cookie中
String username_code = URLEncoder.encode(username, "UTF-8");
Cookie cookie_username = new Cookie("cookie_username",username_code);
Cookie cookie_password = new Cookie("cookie_password",password);
//設(shè)置cookie的持久化時間
cookie_username.setMaxAge(60*60);
cookie_password.setMaxAge(60*60);
//設(shè)置cookie的攜帶路徑
cookie_username.setPath(request.getContextPath());
cookie_password.setPath(request.getContextPath());
//發(fā)送cookie
response.addCookie(cookie_username);
response.addCookie(cookie_password);
}
//將登錄的用戶的user對象存到session中
session.setAttribute("user", user);
//重定向到首頁
response.sendRedirect(request.getContextPath());
}else{
//失敗 轉(zhuǎn)發(fā)到登錄頁面 提出提示信息
request.setAttribute("loginInfo", "用戶名或密碼錯誤");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
LoginServlet.java
public class AutoLoginFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession session = req.getSession();
//獲得cookie中用戶名和密碼 進(jìn)行登錄的操作
//定義cookie_username
String cookie_username = null;
//定義cookie_password
String cookie_password = null;
//獲得cookie
Cookie[] cookies = req.getCookies();
if(cookies!=null){
for(Cookie cookie : cookies){
//獲得名字是cookie_username和cookie_password
if("cookie_username".equals(cookie.getName())){
cookie_username = cookie.getValue();
//解碼,恢復(fù)中文用戶名
cookie_username = URLDecoder.decode(cookie_username, "UTF-8");
}
if("cookie_password".equals(cookie.getName())){
cookie_password = cookie.getValue();
}
}
}
//判斷username和password是否是null
if(cookie_username!=null&&cookie_password!=null){
//登錄的代碼
UserService service = new UserService();
User user = null;
try {
user = service.login(cookie_username,cookie_password);
} catch (SQLException e) {
e.printStackTrace();
}
//將登錄的用戶的user對象存到session中
session.setAttribute("user", user);
}
//放行
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
AutoLoginFilter.java
public class User {
private int id;
private String username;
private String password;
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
User.java
<!-- 自動登錄的filter -->
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>com.ithiema.web.filter.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xml
<!-- 登錄 注冊 購物車... -->
<div class="container-fluid">
<div class="col-md-4">
<img src="img/logo2.png" />
</div>
<div class="col-md-5">
<img src="img/header.png" />
</div>
<div class="col-md-3">
<ol class="list-inline">
<c:if test="${empty user }">
<li><a href="login.jsp">登錄</a></li>
<li><a href="register.jsp">注冊</a></li>
</c:if>
<c:if test="${!empty user }">
<li>歡迎您,${user.username }</li>
<li><a href="#">退出</a></li>
</c:if>
<li><a href="cart.jsp">購物車</a></li>
<li><a href="order_list.jsp">我的訂單</a></li>
</ol>
</div>
</div>
header.jsp
六、案例二:解決全局的編碼
當(dāng)用戶輸入中文提交時,無論是POST方式還是GET方式提交,在獲取用戶提交的數(shù)據(jù)時都會遇到編碼問題。在前面的文章中,對編碼的處理都是放在Servlet中,這樣凡是Servlet中需要獲取用戶提交數(shù)據(jù)的,如果存在中文,都需要處理亂碼。
我們可以將編碼處理挪到filter中,這樣后面的Servlet就不需要單獨(dú)處理了。
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方法進(jìn)行增強(qiáng)
/*
* 裝飾者模式(包裝)
*
* 1、增強(qiáng)類與被增強(qiáng)的類要實(shí)現(xiàn)統(tǒng)一接口
* 2、在增強(qiáng)類中傳入被增強(qiáng)的類
* 3、需要增強(qiáng)的方法重寫,不需要增強(qiáng)的方法調(diào)用被增強(qiáng)對象的
*
*/
//被增強(qiáng)的對象
HttpServletRequest req = (HttpServletRequest) request;
//增強(qiáng)對象
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{ //HttpServletRequest也是實(shí)現(xiàn)了HttpServletRequestWrapper
private HttpServletRequest request;
public EnhanceRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
//對getParameter增強(qiáng),注意并沒有對getParameterMap做增強(qiáng)
@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;
}
}
EncodingFilter.java
public class EncodingServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String parameter = request.getParameter("username");//直接獲得中文
System.out.println(parameter);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
EncodingServlet.java
<!-- 編碼統(tǒng)一處理的filter -->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.ithiema.web.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xml
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/WEB24/encodingServlet" method="get">
<input type="text" name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
encoding.jsp
總結(jié)
- 上一篇: vue 判断数组是否为空
- 下一篇: 斐济旅游攻略(斐济自由行,你必须做的攻略