JavaWeb過濾器

1.JavaWeb三大組件都須要在web.xml中進行配置css

2.過濾器html

  它會在一組資源(jsp、servlet、.css、.html等等)的前面執行!java

它可讓請求獲得目標資源,也能夠不讓請求達到!web

  *過濾器有攔截請求的能力!數據庫

過濾器如何編寫服務器

1.寫一個類實現Filter接口session

2.在web.xml中進行配置app

 Filter接口jsp

void init(FilterConfig)ide

  *建立以後立刻執行;Filter會在服務器啓動時就建立!

void destory()

  *銷燬以前執行!在服務器關閉的時候銷燬

void doFilter(ServletRequest ,  ServletResponse,  FilterChain)

  *每次過濾時都會執行

Filter是單例的!

 

web.xml中配置:

<filter>
  <filter-name>xxx</filter-name>
  <filter-class>com.xjs.web.filter.AFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>xxx</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

使用:

寫一個過濾器AFilter:

package com.xjs.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;

public class AFilter implements Filter{

    /**
     * 建立以後立刻執行,用來作初始化!
     */
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        System.out.println("過濾器出生");
    }
    
    /**
     * 每次過濾時都會執行
     */
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        System.out.println("開始攔截");
    }
    
    /**
     * 銷燬以前執行,用來作對非內存資源進行釋放
     */
    @Override
    public void destroy() {
        System.out.println("過濾器銷燬");
    }
}

而後在web.xml中配置Filter,指定過濾哪些路徑(這裏是AServlet)

  <filter>
      <filter-name>xx</filter-name>
      <filter-class>com.xjs.filter.AFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>xx</filter-name>
      <url-pattern>/AServlet</url-pattern>
  </filter-mapping>

AServlet:

package com.xjs;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("AServlet....");
    }
}

當請求AServlet時被過濾器攔截。


 

FilterConfig--->與ServletConfig類似

  * 獲取初始化參數:getInitParameter()

  * 獲取過濾器名稱:getFilterName()

  * 獲取application:getServletContext()

FilterChain

  * doFilter(ServletRequest,  ServletResponse):放行!

  放行,就至關於調用了目標Servlet的service()方法。


 

多過濾器

FilterChain#doFilter()方法:

  執行目標資源,或者執行下一個過濾器!

過濾器的四種攔截方式

      <dispatcher>REQUEST</dispatcher>  默認的!
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>INCLUDE</dispatcher>
      <dispatcher>ERROR</dispatcher>
  <error-page>
      <error-code>500</error-code>
      <location>500.jsp</location>
  </error-page>

 

在<filter-mapping>中進行配置!

多個過濾器的執行順序

<filter-mapping>的配置順序決定了過濾器的執行順序!

建立的FIlter

過濾器的應用場景

  過濾器的應用場景:

    *執行目標資源以前作預處理工做,例如設置編碼,這種一般會放行,只是在目標資源執行以前作的一些準備工做;

      幾乎全部的Servlet中都須要寫request.setCharacterEndoing()能夠把它放到一個Filter中

  

    *經過條件判斷是否放行,例如校驗當前用戶是否已經登陸,或者用戶IP是否已經被禁用;

    *在目標資源執行以後,作一些後續的特殊處理工做,例如把目標資源輸出的數據進行處理;

      回程攔截!


 

 案例1:分ip統計網站次數

ip count
192.168.1.111 5
192.168.1.112 62

 

  統計工做須要在全部資源以前都執行,那麼就能夠放到Filter中了。

  咱們這個過濾器不打算作攔截操做!由於咱們只是用來作統計的。

  用什麼東西來裝載統計的數據。Map<String, Integer>

  整個網站只須要一個Map便可!

  Map何時建立(使用ServletContextListener,在服務器啓動時完成建立,並保存到ServletContext中),Map保存到哪裏!(Map保存到ServletContext中!!!)

    > Map須要在Filter中用來保存數據

    > Map須要在頁面使用,打印Map中的數據

 1).網站統計每一個IP地址訪問本網站的次數。

使用的是註解(代替了在web.xml中的配置)

AListener監聽器:

package com.xjs.web.listener;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class AListener implements ServletContextListener {

    /**
     * 在服務器啓動時建立Map,保存到ServletContext
     */
    public void contextInitialized(ServletContextEvent sce) {
        //建立Map
        Map<String,Integer> map=new LinkedHashMap<String,Integer>();
        //獲得ServletContext
        ServletContext application = sce.getServletContext();
        application.setAttribute("map", map);
    }
    
    public void contextDestroyed(ServletContextEvent arg0) {
        
    }
}

AFilter攔截器----負責統計訪問次數

package com.xjs.web.filter;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
 * 從application中獲取Map
 * 從request中獲取當前客戶端的IP
 * 進行統計工做,結果保存到Map中
 * @author hp
 *
 */
@WebFilter("/*")
public class AFliter implements Filter {
    private FilterConfig config;

    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        /*
         * 1.獲得application中的 map
         * 2.從request中獲取當前客戶端的ip地址
         * 3.查看map中是否存在這個IP對應的訪問次數,若是存在,把次數+1再保存回去
         * 4.若是不存在這個Ip ,那麼說明第一次訪問本站,設置訪問次數爲1
         */
        ServletContext application = config.getServletContext();
        Map<String,Integer> map = (Map<String,Integer>)application.getAttribute("map");
        
        //獲取客戶端IP地址
        String ip = request.getRemoteAddr();
        //進行判斷
        if(map.containsKey(ip)){//這個IP在map中存在
            Integer count = map.get(ip);
            map.put(ip, count+1);
        }else{//不存在
            map.put(ip, 1);
        }
        application.setAttribute("map", map);//把map在放回到application中
        chain.doFilter(request, response);
    }
    
    /**
     * 在服務器啓動時調用,並且只執行一次
     */
    public void init(FilterConfig fConfig) throws ServletException {
        this.config=fConfig;
    }
}

show.jsp---顯示本項目的訪問次數

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<body>
    <h1 align="center">顯示結果</h1>
    <table align="center" width="60%" border="1">
        <tr>
            <th>IP</th>
            <th>COUNT</th>
        </tr>
        <c:forEach items="${applicationScope.map }" var="entry">
            <tr>
                <td>${entry.key }</td>
                <td>${entry.value }</td>
            </tr>
        </c:forEach>
    </table>
</body>

 結果:

 

案例2:粗粒度權限控制(攔截是否登陸、攔截用戶名admin權限)

1)什麼是粗粒度和細粒度權限

  粗粒度權限管理,對資源類型的權限管理。資源類型好比:菜單、url連接、用戶添加頁面、用戶信息、類方法、頁面中按鈕,等等。。。

  粗粒度權限管理好比:超級管理員能夠訪問用戶添加頁面、用戶信息等所有頁面。

  細粒度權限管理,對資源實例的權限管理。資源實例就資源類型的具體化,好比:用戶id爲001的修改連接,1110班的用戶信息。

  細粒度權限管理就是數據級別的權限管理。好比:部門經理能夠訪問本部門的員工信息,用戶只能夠看到本身的菜單,大區經理只能查看本轄區的銷售訂單。。


 

粗粒度和細粒度例子:
 系統有一個用戶列表查詢頁面,對用戶列表查詢分權限,若是粗顆粒管理,張三和李四都有用戶列表查詢的權限,張三和李四均可以訪問用戶列表查詢。
進一步進行細顆粒管理,張三(行政部)和李四(開發部)只能夠查詢本身本部門的用戶信息。張三隻能查看行政部 的用戶信息,李四隻能查看開發部門的用戶信息。細粒度權限管理就是數據級別的權限管理。


 

分爲管理員,普通用戶,遊客。

管理員能訪問的資源(jsp) 放到admin文件夾下。

普通用戶能訪問的資源(jsp)放到users文件夾下。

寫兩個Filter過濾器對資源的訪問進行過濾。

UserFilter.java:----用戶和管理員都能訪問

package com.xjs.web.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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@WebFilter("/admin/*")
public class AdminFilter implements Filter {

    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        /*
         * 1.獲得session 2.判斷session域中是否存在 admin,若是存在,放行
         * 3.判讀session域中是否存在username,若是存在,放行,不然打回login.jsp
         */
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();
        String name = (String) session.getAttribute("admin");
        if (name != null) {//管理員
            chain.doFilter(request, response);
        } else {
            req.setAttribute("msg", "您多是個啥,但確定不是管理員!");
            req.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
    public void init(FilterConfig fConfig) throws ServletException {
        
    }

}

 

AdminFilter.java:---只有管理員才能訪問

package com.xjs.web.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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@WebFilter("/admin/*")
public class AdminFilter implements Filter {

    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        
        /*
         * 1.獲得session 2.判斷session域中是否存在 admin,若是存在,放行
         * 3.判讀session域中是否存在username,若是存在,放行,不然打回login.jsp
         */
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession();
        String name = (String) session.getAttribute("admin");
        if (name != null) {//管理員
            chain.doFilter(request, response);
        } else {
            req.setAttribute("msg", "您多是個啥,但確定不是管理員!");
            req.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }
    public void init(FilterConfig fConfig) throws ServletException {
        
    }

}

 

LoginServlet:----用登陸來區分身份

package com.xjs;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public final class LoginServlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        
        /*
         * 1.獲取用戶名
         * 2.判斷用戶名中是否包含itcast
         *     3.包含,就是管理員
         *     4.不包含,就是普通會員
         * 5.要把登陸的信息保存到session中
         * 6.轉發到index.jsp
         */
        String username = request.getParameter("username");
        if(username.contains("itcast")){
            request.getSession().setAttribute("admin", username);;
        }else{
            request.getSession().setAttribute("username", username);
        }
        request.getRequestDispatcher("/index.jsp").forward(request, response);    
    }
}

案例3:解決全站字符亂碼(POST和GET中文編碼問題)

總在Servlet中寫:Post----request.setCharacterEncoding("utf-8");

          Get-----String username=request.getParameter("username");
                username=new String(username.getBytes("ISO-8859-1"), "utf-8");

 在Tomcat8以前,使用get方式獲得參數會有亂碼,在Tomcat8中默認編碼爲UTF-8。因此在Tomcat8中Get獲取參數,不用考慮編碼問題。

1) 編寫一個過濾器EncodingFilter.java:---完成對POST請求和GET請求編碼問題

package com.xjs.web.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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter("/*")
public class EncodingFilter implements Filter {

    public void destroy() {
    }
    
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //處理post請求編碼問題
        request.setCharacterEncoding("utf-8");
        
        HttpServletRequest req=(HttpServletRequest) request;
        /*
         * 處理Get請求的編碼問題
         */
        /*
         * 掉包request
         * 1.寫一個request的裝飾類
         * 2.在放行時,使用咱們本身的request
         */
        if(req.getMethod().equals("GET")){
            //向這個類傳遞一個HttpServletRequest,完成getParameter()方法的重寫,而後回返回一個重寫後的Request對象(具備獲得參數爲utf-8的能力)
            EncodingRequest er=new EncodingRequest(req);
            chain.doFilter(er, response);//--這個er(request)是裝飾以後的request,它的getParameter();獲得的參數是utf-8編碼
        }else if(req.getMethod().equals("POST")){
            chain.doFilter(request, response);
        }
        
    }

    public void init(FilterConfig fConfig) throws ServletException {
    }

}

 

 這裏面在處理GET請求時,涉及到Filter中的參數爲ServletRequest須要強制類型轉換成HttpServletRequest,而後就是經過一個EncodingRequest類完成對request對象的getParameter()方法的重寫。而後把對getParameter()裝飾過的request對象放行------->傳遞到相應的Servlet的doGet方法中。

2)EncodingRequest.java: 

  (1)本來EncodingRequest實現HttpServletRequest接口,重寫String  getParameter(String name)方法

EncodingRequest implements HttpServletRequest 重寫getParameter()方法
private
HttpServletRequest request; public EncodingRequest(HttpServletRequest request) { this.request = request; } public String getParameter(String name) { String value = request.getParameter(name); // 處理編碼問題 try { value = new String(value.getBytes("iso-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(); } return value; }

 

   (2)Java提供了HttpServletRequestWrapper類,只需EncodingRequest繼承HttpServletRequestWrapper該類,重寫getParameter()方法便可。

Wrapper:包裝器的意思

package com.xjs.web.filter;

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * 裝飾request
 * 
 * @author hp
 *
 */
public class EncodingRequest extends HttpServletRequestWrapper {
    private HttpServletRequest req;

    // java提供了這個類,只需實現這個構造器
    public EncodingRequest(HttpServletRequest request) {
        super(request);
        this.req = request;
    }

    public String getParameter(String name) {
        String value = req.getParameter(name);
        // 處理編碼問題
        try {
            value = new String(value.getBytes("iso-8859-1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException();
        }
        return value;
    }
}

 


案例4:頁面靜態化之準備工做()

 什麼是頁面靜態化!

首次訪問去數據庫獲取數據,而後把數據保存到一個html頁面中

二次訪問,就再也不去數據庫獲取了,而是直接顯示html

 1.給出一個過濾器,把servlet請求的資源所作輸出保存到html中,重定向到html頁面。

二次訪問時,這個html頁面已經存在,那麼直接重定向,不用再去訪問servlet!

//////////////////////////////////////////////////////////////////

原來在jsp上顯示,HttpServletResponse的getWriter()方法獲得的PrintWriter對象是與jsp綁定在一塊兒,把響應的內容輸出到了jsp頁面上了。PrintWriter(String  fileName, String  can)構造方法能夠建立指定文件的名稱(路徑),和字符集。

因此咱們調包response的getWriter()方法:----返回一個jsp頁面使用它向html頁面輸出內容的PrintWriter對象

package com.xjs.web.filter;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
 * 是你還有你,一切拜託你
 * @author hp
 *
 */
public class StaticResponse extends HttpServletResponseWrapper {
    private HttpServletResponse response;
    private PrintWriter pw;

    /**
     * String path:html文件路徑!
     * @param response
     * @param path
     * @throws UnsupportedEncodingException 
     * @throws FileNotFoundException 
     */
    public StaticResponse(HttpServletResponse response,String path) throws FileNotFoundException, UnsupportedEncodingException {
        super(response);//一切拜託你
        this.response=response;
        
        //建立一個與html文件路徑綁定在一塊兒的流對象
        pw=new PrintWriter(path,"utf-8");
    }
    
    //本身須要加強的部分
    public PrintWriter getWriter(){
        //返回一個與html綁定在一塊兒的printWriter對象
        //jsp會使用它進行輸出,這樣數據都輸出到了html文件中!
        return pw;
    }
}

 

 這個過濾器判斷是不是第一次訪問(也就是有無html頁面)

 在這個裏面生成html文件也就是在執行chain.doFilter(req,sr)放行時,傳遞的是裝飾過的Response對象,會執行BookServlet,而後轉發到show.jsp(並無顯示),使用裝飾後的Response對象中的getWriter()方法獲得PrintWriter對象,向html上輸出內容,生成了html頁面。

而後再重定向到html頁面便可!

package com.xjs.web.filter;

import java.io.File;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebFilter(servletNames = { "BookServlet" })
public class StaticFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest) request;
        HttpServletResponse res=(HttpServletResponse) response;
        /*
         * 1.第一次訪問時,查找請求對應的html頁面是否存在,若是存在重定向到html
         * 2.若是不存在,放行!把servlet訪問數據庫後,輸出給客戶端的數據保存到一個html文件中
         *     再重定向到html
         */
        /*
         * 1、獲取category參數!
         * null--->null.html
         * 1--->1.html
         * 2--->2.html
         * 3---->3.html
         * htmls目錄下
         */
        String category = req.getParameter("category");
        String htmlPage=category+".html";//獲得對應文件的名稱
        String htmlPath=req.getServletContext().getRealPath("/htmls");//獲得文件存放目錄
        File destFile=new File(htmlPath,htmlPage);
        
        if(destFile.exists()){//若是文件存在
            //重定向到這個文件
            res.sendRedirect(req.getContextPath()+"/htmls/"+htmlPage);
            return;
        }
        
        /*
         * 2、若是html文件不存在,咱們要生成html文件
         * 1.放行,show.jsp會作出不少的輸出,咱們要讓它再也不輸出客戶端,而是輸出到咱們指定的一個html文件中
         * 完成:
         *     調包response,讓它的getWriter()與一個html文件綁定,那麼show.jsp的輸出就到了html文件中
         * 
         */
        StaticResponse sr=new StaticResponse(res, destFile.getAbsolutePath());//文件的絕對路徑。
        chain.doFilter(req, sr);//放行,即生成了html文件
        //這時頁面已經存在,重定向到html文件
        res.sendRedirect(req.getContextPath()+"/htmls/"+htmlPage);
    }

    public void init(FilterConfig fConfig) throws ServletException {
    }
}

 

BookServlet.java:

package com.xjs.web.servlet;


import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xjs.web.dao.BookDao;

import cn.itcast.servlet.BaseServlet;

public class BookServlet extends BaseServlet {

    private BookDao bookDao=new BookDao();
    
    public String findAll(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setAttribute("bookList", bookDao.findAll());
        return "/show.jsp";
    }
    
    public String findByCategory(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String value = request.getParameter("category");
        int category = Integer.parseInt(value);
        request.setAttribute("bookList", bookDao.findByCategory(category));
        return "/show.jsp";
    }
}

 

 link.jsp:顯示連接

  <body>
    <h1>連接頁面</h1>
    <a href='<c:url value="/BookServlet?method=findAll"></c:url>'>查看全部</a><br>
    <a href='<c:url value="/BookServlet?method=findByCategory&category=1"></c:url>'>查看SE</a><br>
    <a href='<c:url value="/BookServlet?method=findByCategory&category=2"></c:url>'>查看EE</a><br>
    <a href='<c:url value="/BookServlet?method=findByCategory&category=3"></c:url>'>查看Framework</a><br>
  </body>

 

 show.jsp:負責向html頁面響應內容

<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<!-- 模擬html的響應頭,告訴服務器html使用的編碼 -->
至關於向html頁面加的響應頭



<body>
    <h1 align="center">圖書列表</h1>
    <table border="1" align="center">
        <tr>
            <th>書名</th>
            <th>單價</th>
            <th>分類</th>
        </tr>
        <c:forEach items="${bookList }" var="book">
            <tr>
                <td>${book.bname }</td>
                <td>${book.price }</td>
                <td>${book.category }</td>
            </tr>
        </c:forEach>
    </table>
</body>

 

 

 

相關文章
相關標籤/搜索