過濾器和監聽器

過濾器和監聽器

1. 過濾器

1.1 過濾器定義

//也可以通過註解配置filter:@WebFilter("/*"),攔截所有請求
public class EncodFilter implements Filter {
    
    //初始化的方法,可以通過FilterConfig獲得xml配置的參數
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
    
	//過濾器處理業務的方法,完成業務處理之後一定要放行。
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        
        //放行
        filterChain.doFilter(req,resp);
    }

    //銷燬filter時執行的方法
    @Override
    public void destroy() {}
}

1.2 過濾器配置

<filter>                                                            
    <filter-name>encode</filter-name>                               
    <filter-class>com.yogie.lesson.filter.EncodFilter</filter-class>
    //配置參數
    <init-param>                                                    
        <param-name>encoding</param-name>                           
        <param-value>utf-8</param-value>                            
    </init-param>                                                   
    <init-param>                                                    
        <param-name>force</param-name>                              
        <param-value>true</param-value>                             
    </init-param>                                                   
</filter>
<filter-mapping>                     
    <filter-name>encode</filter-name>
    //配置過濾路徑:所有請求都要經過encode過濾器
    <url-pattern>/*</url-pattern>    
</filter-mapping>                    

1.3 過濾器的生命週期

​ 啓動tomcat的時候開始,先創建FilterConfig,再調用init方法,filter是單例模式,只有一個對象。關閉tomcat服務器或者停止虛擬機運行的時候,過濾器調用destroy方法。

1.4 過濾器的應用

​ 1、對字符進行編碼。

<filter>                                                               
    <filter-name>encoding</filter-name>                                
    <filter-class>com.yogie.lesson.filter.EncodingFilter</filter-class>
    <init-param>                                                       
        <param-name>charset</param-name>                               
        <param-value>UTF-8</param-value>                               
    </init-param>                                                      
    <init-param>                                                       
        <param-name>force</param-name>                                 
        <param-value>true</param-value>                                
    </init-param>                                                      
</filter>
<filter-mapping>                       
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>      
</filter-mapping>                      
public class EncodingFilter implements Filter {
    private String charset;
    private Boolean force;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //讀取配置文件中filter中的配置
        charset = filterConfig.getInitParameter("charset");
        //如果用戶沒有配置編碼方式
        if(charset==null || "".equals(charset)){
            //設置一個默認的編碼
            charset = "UTF-8";
        }
        //Boolean.parseBoolean(null)的結果也爲false
        force = Boolean.parseBoolean(filterConfig.getInitParameter("force"));

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse)servletResponse;
        //獲取請求對象攜帶過來的編碼方式
        String ce = req.getCharacterEncoding();
        if( ce==null || "".equals(ce) || force){
            //如果request請求中沒有設置編碼方式,
            //如果配置了強制使用配置中的編碼方式
            req.setCharacterEncoding(charset);
        }
        filterChain.doFilter(req,resp);
    }

    @Override
    public void destroy() {

    }
}

​ 2、讓瀏覽器不緩存。
​ 3、屏蔽非法文字(敏感詞過濾處理)。

  • 關鍵字過濾器
@WebFilter("/*")
public class SensitiveFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //將servletRequest轉換成HttpServletRequest對象
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        //HttpServletRequest轉換成MyHttpRequestWapper,
        //在這個轉換的過程中,請求對象所攜帶的文本信息中的敏感信息被過濾掉了
        MyHttpRequestWapper requestWapper = new MyHttpRequestWapper(req);
        //放行後,request對象已經是經過包裝的request對象了
        filterChain.doFilter(requestWapper, servletResponse);
    }

    @Override
    public void destroy() {

    }
}
  • 請求對象的裝飾類
public class MyHttpRequestWapper extends HttpServletRequestWrapper {
    private HttpServletRequest req = null;
    public MyHttpRequestWapper(HttpServletRequest request) {
        //必須顯示調用父類的構造方法,因爲父類沒有默認的無參構造方法
        super(request);
        //將HttpServletRequest對象賦值給字段
        req = request;
    }

    @Override
    public String getParameter(String name) {
        //根據參數名獲取請求對象中的對應的值
        String value = req.getParameter(name);
        return SensitiveUtil.filterWords(value,"*");
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        //獲取請求對象中的鍵值對map
        Map<String, String[]> map = req.getParameterMap();
        //準備一個返回的map
        Map<String, String[]> result = new HashMap<>();
        //取出其中所有的鍵值對集合
        Set<Map.Entry<String, String[]>> entries = map.entrySet();
        //遍歷集合
        for (Map.Entry<String, String[]> entry : entries) {
            //key
            String key = entry.getKey();
            //value:有的字段可能對應多個值,例如select標籤
            String[] value = entry.getValue();
            //設計一個與value一致長度的數組
            String[] arr = new String[value.length];
            //遍歷這個vlaue數組,將數組中每個元素的字符串都進行敏感詞過濾
            for (int i = 0; i < value.length; i++) {
                arr[i] = SensitiveUtil.filterWords(value[i],"*");
            }
            //將過濾後的值保存到map集合中
            result.put(key,arr);
        }
        return result;
    }
}
  • 敏感詞替換的工具類
public class SensitiveUtil {

    private static List<String> keyWords = new ArrayList<>();

    static{
        Scanner sc = new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("sensitive.txt"),"UTF-8");
        while (sc.hasNextLine()){
            String line = sc.nextLine();
            if(line!=null || !"".equals(line)){
                keyWords.add(line);
            }
        }
        sc.close();
    }

    /**
     * 將str中的敏感詞替換爲指定字符拼接成的字符串
     * @param str
     * @param mask
     * @return
     */
    public static String filterWords(String str,String mask){
        for (String keyWord : keyWords) {
            if(str!=null && str.indexOf(keyWord) >= 0){
                str = str.replaceAll(keyWord,buildMask(keyWord,mask));
            }
        }
        return str;
    }

    /**
     * 配置keyword長度的替代字符
     * @param keyWord
     * @param mask
     * @return
     */
    private static String buildMask(String keyWord, String mask) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keyWord.length(); i++) {
            sb.append(mask);
        }
        return sb.toString();
    }
}

​ 4、登錄權限驗證。

  • 登錄權限的過濾器
public class LoginFilter implements Filter {
    String[] strs = null;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //將配置中不用驗證的資源放入strs數組中
        strs = filterConfig.getInitParameter("outs").split(",");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        //從session中獲得key爲username的對象
        Object obj = req.getSession().getAttribute("NAME_IN_SESSION");
        //獲取到請求路徑中的uri描述,並按照反斜槓分割
        String[] split = req.getRequestURI().split("/");
        //將配置中的路徑放到list中
        List<String> list = Arrays.asList(strs);
        //如果配置的路徑中不包含此次請求資源且session爲空,不能放行
        if(!list.contains(split[split.length-1]) && obj==null){
            resp.sendRedirect("/xx/index.html");
            return;
        }
        //放行
        filterChain.doFilter(req,resp);
    }

    @Override
    public void destroy() {

    }
}
  • 配置
<filter>
    <filter-name>login</filter-name>
    <filter-class>com.yogie.lesson.filter.LoginFilter</filter-class>
    <init-param>
        <param-name>outs</param-name>
        <!--除了這兩個資源,其他都要驗證權限-->
        <param-value>index.html,login</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>login</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 登錄的servlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet{

    StudentDao dao = new StudentDaoImpl();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Student stu = BeanUtil.getBean(req, Student.class);
        Student stu1 = dao.queryByUsernameAndPassword(stu.getUsername(),stu.getPassword());
        if(stu1!=null){
            //登錄成功,將用戶名存入session
            req.getSession().setAttribute("NAME_IN_SESSION",stu.getUsername());
            //跳轉到系統列表
            resp.sendRedirect("/xx/controller?cmd=query");
        }else{
            //登錄失敗,返回登錄頁面
            resp.sendRedirect("/xx/index.html");
        }
    }
}

​ 5、請求分發器。
​ 6、頁面僞靜態化處理。

2. 過濾器鏈

​ 多個過濾器鍊形成的一組過濾器,然後我們在訪問最終的資源的時候會經過這一組過濾器,在返回的時候還會經過這一組過濾器。過濾器鏈的執行順序是按照filter-mapping的順序執行的。

3. FilterConfig對象

String getFilterName();  獲取filter的名稱(配置的name)。
ServletContext getServletContext();  獲得web項目的上下文對象。
String getInitParameter(String var1);  根據參數名獲取filter配置中的init-param的value。
Enumeration<String> getInitParameterNames();  獲取所有參數配置的name。

4. 特殊的請求過濾

4.1 請求轉發過濾

<filter-mapping>
    <filter-name>a</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

4.2 重定向過濾

<filter-mapping>
    <filter-name>b</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REDIRECT</dispatcher>
</filter-mapping>

4.3 默認情況

<filter-mapping>
    <filter-name>b</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

5. 監聽器

在web中,監聽器的監聽內容一般有:
1、監聽四大作用的生命週期(主要是創建與銷燬)。
2、監聽作用域屬性的變化(主要是增刪改查)。

5.1 作用域監聽器接口

ServletRequestListener  -> 對request作用域監聽器
HttpSessionListener     -> 對session作用域監聽器
ServletContextListener  -> 對application作用域監聽器
ServletRequestAttributeListener  -> 對request作用域的屬性監聽器
HttpSessionAttibuteListener      -> 對session作用域的屬性監聽器
ServletContextAttributeListener  -> 對application作用域的屬性監聽器

需要創建哪一種監聽器,就去實現對應的接口。

5.2 監聽器的配置

<listener>
	<listener-class>com.yogie.filter.MyFilter</listener-class>
</listener>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章