Filter過濾器原理和登入實現,filter過濾器原理

來源:互聯網
上載者:User

Filter過濾器原理和登入實現,filter過濾器原理

Filter過濾器API
     Servlet過濾器API包含了3個介面,它們都在javax.servlet包中,分別是Filter介面、FilterChain介面和FilterConfig介面。
Filter介面(源碼)

public interface Filter {    public void init(FilterConfig filterConfig) throws ServletException;    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;    public void destroy();}

所有的過濾器都必須實現Filter介面。該介面定義了init,doFilter0,destory()三個方法:
  (1)init(FilterConfig filterConfig)
      在web應用程式啟動時,web伺服器將根據 web.xml檔案中的配置資訊來建立每個註冊的Filter執行個體對象,並將其儲存在伺服器的記憶體中。Web容器建立Filter對象執行個體後,將立即調用該Filter對象的init方法。Init方法在Filter生命週期中僅執行一次,web容器在調用init方法時,會傳遞一個包含Filter的配置和運行環境的FilterConfig對象(FilterConfig的用法和ServletConfig類似)。利用FilterConfig對象可以得到ServletContext對象,以及部署描述符中配置的過濾器的初始化參數。
  (2)doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

      doFilter()方法類似於Servlet介面的service()方法。當用戶端請求目標資源的時候,容器就會調用與這個目標資源相關聯的過濾器的 doFilter()方法。其中參數 request, response 為 web 容器或 Filter 鏈的上一個 Filter 傳遞過來的請求和相應對象;參數 chain 為代表當前 Filter 鏈的對象,在特定的操作完成後,可以在當前 Filter 對象的 doFilter 方法內部需要調用 FilterChain 對象的 chain.doFilter(request,response)方法才能把請求交付給 Filter 鏈中的下一個 Filter 或者目標 Servlet 程式去處理,也可以直接向用戶端返迴響應資訊,或者利用RequestDispatcher的forward()和include()方法,以及 HttpServletResponse的sendRedirect()方法將請求轉向到其他資源。這個方法的請求和響應參數的類型是 ServletRequest和ServletResponse,也就是說,過濾器的使用並不依賴於具體的協議。
 (3)public void destroy()
       在Web容器卸載 Filter 對象之前被調用。該方法在Filter的生命週期中僅執行一次。在這個方法中,可以釋放過濾器使用的資源。
FilterChain介面(源碼)

public interface FilterChain {    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;}

(1)doFilter(ServletRequest request,ServletResponse response)
      此方法是由Servlet容器提供給開發人員的,用於對資源請求過濾鏈的依次調用,通過FilterChain調用過濾鏈中的下一個過濾  器,如果是最後一個過濾器,則下一個就調用目標資源。
FilterConfig介面(源碼)  FilterConfig介面檢索過濾器名、初始化參數以及活動的Servlet上下文。

public interface FilterConfig {  //返回web.xml部署檔案中定義的該過濾器的名稱    public String getFilterName();  //返回調用者所處的servlet上下文    public ServletContext getServletContext();  //返回過濾器初始化參數值的字串形式,當參數不存在時,返回nul1.name是初始化參數名    public String getInitParameter(String name);  //以Enumeration形式返回過濾器所有初始化參數值,如果沒有初始化參數,返回為空白    public Enumeration getInitParameterNames();}

 

瞭解了Filter的基本概念和源碼,下面具體使用下Filter過濾器來實現登入過濾。

需求:訪問A頁面(登入後才能訪問的頁面)-->未登入-->跳轉到登入頁面-->登陸成功後,跳轉到A頁面

自訂HttpFilter

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.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * HttpFilter */public abstract class HttpFilter implements Filter{ //儲存filterConfig對象 private FilterConfig filterConfig; /** * 直接返回filterConfig對象 * @return */ public FilterConfig getFilterConfig() { return filterConfig; } /** * 不建議子類直接覆蓋,若直接失敗,將可能導致filterConfig成員變數初始化失敗 */ @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; init(); } /** * 供子類繼承的初始化方法,刻通過getFilterConfig()方法獲得filterConfig對象 */ private void init() {} /** * 原生的doFilter方法,在方法內部把ServletRequest和ServletResponse轉化化為了HttpServletRequest和HttpServletResponse, * 並調用了doFilter(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain)方法 */ @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; doFilter(request, response, filterChain); } /** * 抽象方法,為http請求定製,必須實現的方法 * @param request * @param response * @param filterChain * @throws IOException * @throws ServletException */ public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException; @Override public void destroy() {}}View Code

web.xml配置CommonFilter

    <filter>        <filter-name>commonFilter</filter-name>        <filter-class>com.gcx.emall.Filter.CommonFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>commonFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>

登入過濾器CommonFilter

import java.io.IOException;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class CommonFilter extends HttpFilter {    private final Logger log = LoggerFactory.getLogger(CommonFilter.class);        @Override    public void doFilter(HttpServletRequest request,            HttpServletResponse response, FilterChain filterChain)            throws IOException, ServletException {        log.info("==============攔截get請求================");        if ("GET".equalsIgnoreCase(request.getMethod())) {            RequestUtil.saveRequest(request);        }                String requestUri = request.getRequestURI();        String contextPath = request.getContextPath();        String url = requestUri.substring(contextPath.length());        if ("/login".equals(url)) {            filterChain.doFilter(request, response);            return;        } else {            String username = (String) request.getSession().getAttribute("user");            if (username == null) {                log.info("被攔截:跳轉到login頁面!");                request.getRequestDispatcher("/page/index1.jsp").forward(request, response);            } else                filterChain.doFilter(request, response);        }    }}

RequestUtil 儲存、擷取request並加密請求頁面

public class RequestUtil { private static final Logger logger = LoggerFactory.getLogger(RequestUtil.class); private static final Base64 base64 = new Base64(true); public static final String LAST_PAGE = "lastPage";//未登入時訪問的頁面 public static final String REDIRECT_HOME = "/";//未登入時跳轉到首頁 public static final String LOGIN_HOME = "/index.jsp";//登入成功後進入的頁面 /** * 儲存當前請求 */ public static void saveRequest(HttpServletRequest request) { request.getSession().setAttribute(LAST_PAGE, RequestUtil.hashRequestPage(request)); logger.debug("被攔截的url的sessionID:{}", request.getSession().getId()); logger.debug("save request for {}", request.getRequestURI()); } /** * 加密請求頁面 * @param request * @return */ public static String hashRequestPage(HttpServletRequest request) { String reqUri = request.getRequestURI(); String query = request.getQueryString(); if (query != null) { reqUri += "?" + query; } String targetPage = null; try { targetPage = base64.encodeAsString(reqUri.getBytes("UTF-8")); } catch (UnsupportedEncodingException ex) { //this does not happen } return targetPage; } /** * 取出之前儲存的請求 * @return */ public static String retrieveSavedRequest(HttpServletRequest request) { HttpSession session = request.getSession(); if (session == null) { return REDIRECT_HOME; } String HashedlastPage = (String) session.getAttribute(LAST_PAGE); if (HashedlastPage == null) { return LOGIN_HOME; } else { return retrieve(HashedlastPage); } } /** * 解密請求的頁面 * @param targetPage * @return */ public static String retrieve(String targetPage) { byte[] decode = base64.decode(targetPage); try { String requestUri = new String(decode, "UTF-8"); int i = requestUri.indexOf("/", 1); return requestUri.substring(i); } catch (UnsupportedEncodingException ex) { //this does not happen return null; } }}View Code

LoginCOntroller

        @RequestMapping(value = "/hello",method = RequestMethod.GET)
     public String testHello( String test) {
         log.info("執行了Hello方法!");
         return "loginSuccess";
     }
@RequestMapping(value = "/login",method = RequestMethod.POST) public String login(HttpServletRequest request,String userName,String password){ log.info("執行了login方法!"); password = DigestUtils.md5Hex(password); User user = userService.findUser(userName,password); if(user!=null){ request.getSession().setAttribute("userId", user.getId()); request.getSession().setAttribute("user", userName); return "redirect:" + RequestUtil.retrieveSavedRequest(request);//跳轉至訪問頁面 }else{ log.info("使用者不存在"); request.getSession().setAttribute("message", "使用者名稱不存在,請重新登入"); return "index"; } }

最後需要幾個jsp頁面login.jsp,index.jsp(首頁面,任何人都能訪問的),loginSuccess.jsp,還需要在controller中加上一個測試testHello方法用於滿足之前說的需求。

注意事項:我們過濾的是所有請求,但對於靜態資源css,js,image我們應該不攔截,對其允許存取。我們可以在web.xml中進行指定

    <!-- 不攔截靜態檔案 -->    <servlet-mapping>        <servlet-name>default</servlet-name>        <url-pattern>/js/*</url-pattern>        <url-pattern>/css/*</url-pattern>        <url-pattern>/image/*</url-pattern>        <url-pattern>/fonts/*</url-pattern>    </servlet-mapping>

寫在後面:本來想把Filter和SpringMVC的interceptor攔截器一起寫總結了,但感覺篇幅有些長打算下篇在介紹。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.