Filter

本節內容:html

  • filter的簡介
  • 快速入門
  • filter的API詳解
  • filter的配置
  • 案例一:自動登陸
  • 案例二:解決全局代碼

 

1、filter的簡介

filter是對客戶端訪問資源的過濾,符合條件放行,不符合條件不放行,而且能夠對目標資源訪問先後進行邏輯處理。java

 

2、快速入門

【步驟】:web

  1. 編寫一個過濾器的類實現Filter接口
  2. 實現接口中還沒有實現的方法(着重實現doFilter方法)
  3. 在web.xml中進行配置(主要是配置要對哪些資源進行過濾)
public class QuickFilter1 implements Filter{
    
    @Override
    //Filter建立的時候執行init方法
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    @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...");
    }

}
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在前面,根據各個filter在web.xml文件中的位置,注意是看<filter-mapping>的位置,不是看<filter>的位置。cookie

 

3、filter的API詳解

(1)filter生命週期及其與生命週期相關的方法session

Filter接口有三個方法,而且這個三個都是與Filter的生命相關的方法app

  • init(Filterconfig):表明filter對象初始化方法。即filter對象建立時執行。
  • doFilter(ServletRequest,ServletResponse,FilterCha):表明filter執行過濾的核心方法,若是某資源在已經被配置到這個filter進行過濾的話,那麼每次訪問這個資源都會執行doFilter方法。
  • destory():表明是filter銷燬方法,當filter對象銷燬時執行該方法。

Filter對象的生命週期:jsp

  • Filter什麼時候建立:服務器啓動時就建立該filter對象。
  • Filter什麼時候銷燬:服務器關閉時filter銷燬。

 

(2)Filter的AP詳解ide

1)init(FilterConfig)
其中參數config表明 該Filter對象的配置信息的對象,內部封裝是該filter的配置信息。

2)destory()方法
filter對象銷燬時執行

3)doFilter方法
doFilter(ServletRequest,ServletResponse,FilterChain)
其中的參數:

ServletRequest/ServletResponse:每次在執行doFilter方法時 web容器負責建立一個request和一個response對象做爲doFilter的參數傳遞進來。該request個該response就是在訪問目標資源的service方法時的request和response。
FilterChain:過濾器鏈對象,經過該對象的doFilter方法能夠放行該請求。

 

4、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/*:訪問前臺的資源進入此過濾器
    • /admin/*:訪問後臺的資源時執行此過濾器
  • 擴展名匹配 *.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>中的屬性,沒配置的話,它有個默認值。

  • REQUEST:默認值,表明直接訪問某個資源時執行filter。重定向也叫直接訪問,只不過是客戶端自動去訪問的,不是你在瀏覽器本身輸入去訪問的。
  • FORWARD:轉發時才執行filter
  • INCLUDE: 包含資源時執行filter
  • ERROR:發生錯誤時、進行跳轉時執行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> 

 

總結Filter的做用:

  • 公共代碼的提取
  • 能夠對request和response中的方法進行加強(裝飾者模式或動態代理)
  • 進行權限控制

 

5、案例一:自動登陸

自動登陸的filter是功能加強的,並非進行攔截的。帶着用戶名和密碼的cookie,就幫忙自動登上去,沒帶也放行,該訪問誰訪問誰。

public class LoginServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        request.setCharacterEncoding("UTF-8"); //POST提交要寫這個,能夠在filter裏寫上這句話,這樣每一個接收數據的Servlet中就不用寫這句話了
                                             //可是這種方式對GET不生效
        
        HttpSession session = request.getSession();
        
        //獲取數據
        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){
            //登陸成功
            //判斷用戶是否勾選自動登陸,若是登陸,將用戶名和密碼設置進cookie
            String autoLogin = request.getParameter("autoLogin");
            if(autoLogin!=null){
                //對中文張三進行編碼,要存入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);
                //設置cookie的持久化時間
                cookie_username.setMaxAge(60*60);
                cookie_password.setMaxAge(60*60);
                //設置cookie的攜帶路徑
                cookie_username.setPath(request.getContextPath());
                cookie_password.setPath(request.getContextPath());
                //發送cookie
                response.addCookie(cookie_username);
                response.addCookie(cookie_password);
            }
            
            //將登陸的用戶的user對象存到session中
            session.setAttribute("user", user);
            //重定向到首頁
            response.sendRedirect(request.getContextPath());
            
        }else{
            //失敗 轉發到登陸頁面 提出提示信息
            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中用戶名和密碼 進行登陸的操做
        //定義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();
                    //解碼,恢復中文用戶名
                    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" style="padding-top:20px">
        <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

 

6、案例二:解決全局的編碼

當用戶輸入中文提交時,不管是POST方式仍是GET方式提交,在獲取用戶提交的數據時都會遇到編碼問題。在前面的文章中,對編碼的處理都是放在Servlet中,這樣凡是Servlet中須要獲取用戶提交數據的,若是存在中文,都須要處理亂碼。

咱們能夠將編碼處理挪到filter中,這樣後面的Servlet就不須要單獨處理了。

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方法進行加強
        /*
         * 裝飾者模式(包裝)
         * 
         * 一、加強類與被加強的類要實現統一接口
         * 二、在加強類中傳入被加強的類
         * 三、須要加強的方法重寫,不須要加強的方法調用被加強對象的
         * 
         */
        //被加強的對象
        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{ //HttpServletRequest也是實現了HttpServletRequestWrapper
    
    private HttpServletRequest request;

    public EnhanceRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }
    
    //對getParameter加強,注意並無對getParameterMap作加強
    @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
  <!-- 編碼統一處理的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
相關文章
相關標籤/搜索