zoukankan      html  css  js  c++  java
  • 《JavaWeb从入门到改行》过滤器学习笔记


    Filter API 

     

    @过滤器( filter)是JavaWeb三大组件之一 ,作用是拦截请求,在访问指定目标资源(如Servlet、JSP、css、html)之前先执行过滤器中的操作 。  

    @过滤流程 是服务器启动后,自动创建Filter接口的实例对象,并进行初始化,我们编写一个filter类继承该实例对象,并且重写其doFilter方法,在此方法中添加过滤规则 。 当客户端每次要访问目标资源时,Servlet容器都会调用Filter接口的实例对象的doFilter方法,也就是会调用我们自己重写的doFilter方法,在此方法中,如果符合规则,则调用FilterChain对象的doFilter方法,表示这个过滤器对该请求进行放行,可以去执行下一个过滤器的生命周期方法中的doFilter方法。 如果下一个过滤器也放行的话,就再去执行下下个过滤器,知道通过了所有过滤器的考验,最终访问到目标资源

    过滤器的详解

     @过滤器的配置在Servet2.5及以前版本都需要在web.xml中进行配置 ,一个目标资源可以添加多个过滤器,也就是多个过滤规则 ,只有全部通过了,请求才能到达目标资源

     1   <filter>
     2     <filter-name>第一个过滤器类名字</filter-name>
     3     <filter-class>包.类</filter-class>
     4   </filter>
     5   <filter-mapping>
     6     <filter-name>第一个过滤器类名字</filter-name>
     7     <url-pattern>要过滤的目标资源A</url-pattern>
     8   </filter-mapping>
     9   <filter>
    10     <filter-name>第二个过滤器类名字</filter-name>
    11     <filter-class>包.类</filter-class>
    12   </filter>
    13   <filter-mapping>
    14     <filter-name>第二个过滤器类名字</filter-name>
    15     <url-pattern>要过滤的目标资源A</url-pattern>
    16   </filter-mapping>

    @多个过滤器的执行顺序 是按照配置的先后顺序执行的

    @四种拦截方式 ,假如: 我们编写一个过滤器用来过滤资源A,当我们直接访问该资源A时就会被过滤,但是当我们间接访问资源A(比如: 在其他页面用转发的形式间接访问资源A)时,过滤器不会执行。 所以有时候我们要定义我拦截方式。

    拦截方式 说明
    REQUEST 直接访问目标资源时执行过滤器 ,默认
    FORWARD 转发访问执行过滤器
    INCLUDE 包含访问执行过滤器
    ERROR

    当目标资源在web.xml中配置为<error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器。

    在<filter-mapping>中添加0~n个<dispatcher>子元素,来说明当前访问的拦截方式。

    <filter-mapping>
            <filter-name>过滤器名字</filter-name>
            <url-pattern>目标资源路径</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>              
    </filter-mapping>

    经典案例_分IP统计网站的访问次数

     @说明 网站的访问次数绝不可能随着浏览器的关闭而重置为0,因为和服务器的寿命是一样的,所以必须用Application域 。而访问次数与IP有关系,最好放在map中,即map<ip地址,访问次数>,而这个map又必须是在服务器启动时就需要创建并且要保存到Application域中以供使用,所以需要监听器

     @注意 类名包名等路径随自己的项目更改

     1 package cn.kmust.web.demo1.filter;
     2 
     3 import java.io.IOException;
     4 import java.util.LinkedHashMap;
     5 import java.util.Map;
     6 
     7 import javax.servlet.Filter;
     8 import javax.servlet.FilterChain;
     9 import javax.servlet.FilterConfig;
    10 import javax.servlet.ServletContext;
    11 import javax.servlet.ServletException;
    12 import javax.servlet.ServletRequest;
    13 import javax.servlet.ServletResponse;
    14 
    15 /**
    16  * 过滤器  [分IP统计访问次数案例]
    17  * @功能 在访问a.jsp和b.jsp资源之前,进行分ip统计访问次数
    18  *    统计功能不需要拦截,所以放行,web.xml中为了不与其他demo项目冲突,
    19  *         所以拦截对象只是本例的demo1_show.jsp
    20  * @author ZHAOYUQIANG
    21  *
    22  */
    23 public class CountFilter implements Filter {
    24     private FilterConfig config ;
    25     
    26     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    27         /*
    28          * 1. 得到application对象
    29          * 2. 获取application域中的Map
    30          * 3. 从request中获取当前客户端的IP地址
    31          * 4. 查看Map中是否存在这个IP对应的访问次数,
    32          *     如果存在,获取访问次数,+1
    33          * 5. 如果不存在ip,说明第一次访问,设置访问次数为1
    34          * 6. 操作完成后,再把map放回到application中
    35          * 7. 这个过滤器不需要拦截,所以放行
    36          */
    37         ServletContext app = config.getServletContext();
    38         Map<String,Integer> map = (Map<String , Integer>)app.getAttribute("map");
    39         String ip  = request.getRemoteAddr();
    40         if(map.containsKey(ip)){
    41             int cnt = map.get(ip);
    42             map.put(ip, cnt+1);
    43         }else{
    44             map.put(ip, 1);
    45         }
    46         app.setAttribute("map", map);
    47         chain.doFilter(request, response);
    48     }
    49 
    50     /**
    51      * 在服务器启动时执行
    52      *   保存config对象
    53      */
    54     public void init(FilterConfig fConfig) throws ServletException {
    55         this.config = fConfig ;
    56         
    57     }
    58     public void destroy() {
    59         // TODO Auto-generated method stub
    60     }
    61 
    62 }
    CountFilter
     1 package cn.kmust.web.demo1.listerner;
     2 
     3 import java.util.LinkedHashMap;
     4 import java.util.Map;
     5 
     6 import javax.servlet.ServletContext;
     7 import javax.servlet.ServletContextEvent;
     8 import javax.servlet.ServletContextListener;
     9 
    10 /**
    11  * 监听器   [项目统计按IP分类为统计访问人数的辅助类] 
    12  * @功能 创建Map,保存到application域中
    13  *     分IP查询,Map的类型为Map<IP地址,访问次数> ; 因为访问次数是项目整体范围,所以保存到application域中
    14  * @author ZHAOYUQIANG
    15  *
    16  */
    17 public class CountListerner implements ServletContextListener {
    18     /**
    19      * 在服务器启动时创建Map,保存到ServletContext中
    20      */
    21     public void contextInitialized(ServletContextEvent sce) {
    22         /*
    23          * 1. 创建Map<IP地址,访问次数>
    24          * 2. 通过ServletContextEvent对象获取ServletContext
    25          * 3. 把Map保存到application中
    26          */
    27         Map<String,Integer> map = new LinkedHashMap<String, Integer>();
    28         ServletContext application = sce.getServletContext();
    29         application.setAttribute("map", map);
    30     }
    31 
    32     public void contextDestroyed(ServletContextEvent arg0) {
    33         // TODO Auto-generated method stub
    34     }
    35     
    36 }
    CountListerner
    <body>
        <h1><center>显示结果</center></h1>
        <table align="center" width="60%" border="1">
            <tr>
               <th>IP</th>
               <th>次数</th>
            </tr>
    <c:forEach items="${applicationScope.map }" var="entry">
            <tr>
               <td>${entry.key }</td>
               <td>${entry.value }</td>
            </tr>
    </c:forEach>
             
        </table>
      </body>
    测试页面
    <filter>
        <display-name>CountFilter</display-name>
        <filter-name>CountFilter</filter-name>
        <filter-class>cn.kmust.web.demo1.filter.CountFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>CountFilter</filter-name>
        <url-pattern>/demo1_show.jsp</url-pattern>
      </filter-mapping>
      <listener>
        <listener-class>cn.kmust.web.demo1.listerner.CountListerner</listener-class>
      </listener>
    配置

    经典案例_粗粒度权限控制

     @说明 防止为登陆的用户访问主页, /user/userindex.jsp是目标资源 ,如果为登陆的用户直接访问该资源,则打回到登陆页面

     @注意 类名包名等路径随自己的项目更改

     1 package cn.kmust.webfilter.web.filter;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.Filter;
     6 import javax.servlet.FilterChain;
     7 import javax.servlet.FilterConfig;
     8 import javax.servlet.ServletException;
     9 import javax.servlet.ServletRequest;
    10 import javax.servlet.ServletResponse;
    11 import javax.servlet.http.HttpServletRequest;
    12 /**
    13  * 过滤器 用来 ,对/user/userindex.jsp进行过滤
    14  * @功能 当有请求访问userindex.jsp时,先检查session域中有没有用户名,如果有则放行,如果没有,则拦截,并且打回
    15  * @author ZHAOYUQIANG
    16  *
    17  */
    18 public class LoginFilter implements Filter {
    19     public void destroy() {        
    20     }
    21     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    22         //因为用的是Http协议的请求,所以需要把过滤器中的ServletRequest转换成Http协议的
    23         HttpServletRequest req = (HttpServletRequest) request;
    24         //从session域中获取用户名
    25         String name  = (String) req.getSession().getAttribute("session_user");
    26         if(name != null ){
    27             chain.doFilter(request, response);
    28         }else{
    29             req.getRequestDispatcher("/user/userlogin.jsp").forward(request, response);
    30         }
    31         chain.doFilter(request, response);
    32     }
    33     public void init(FilterConfig fConfig) throws ServletException {
    34     
    35     }
    36 }
    filter
     1 package cn.kmust.webfilter.web.filter;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.Filter;
     6 import javax.servlet.FilterChain;
     7 import javax.servlet.FilterConfig;
     8 import javax.servlet.ServletException;
     9 import javax.servlet.ServletRequest;
    10 import javax.servlet.ServletResponse;
    11 import javax.servlet.http.HttpServletRequest;
    12 /**
    13  * 过滤器 用来 ,对/user/userindex.jsp进行过滤
    14  * @功能 当有请求访问userindex.jsp时,先检查session域中有没有用户名,如果有则放行,如果没有,则拦截,并且打回
    15  * @author ZHAOYUQIANG
    16  *
    17  */
    18 public class LoginFilter implements Filter {
    19     public void destroy() {        
    20     }
    21     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    22         //因为用的是Http协议的请求,所以需要把过滤器中的ServletRequest转换成Http协议的
    23         HttpServletRequest req = (HttpServletRequest) request;
    24         //从session域中获取用户名
    25         String name  = (String) req.getSession().getAttribute("session_user");
    26         if(name != null ){
    27             chain.doFilter(request, response);
    28         }else{
    29             req.getRequestDispatcher("/user/userlogin.jsp").forward(request, response);
    30         }
    31         chain.doFilter(request, response);
    32     }
    33     public void init(FilterConfig fConfig) throws ServletException {
    34     
    35     }
    36 }
    servlet
    1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2 <body>
    3   <h2>用户名字是user,密码是123</h2>
    4     <form action ="<c:url value="/LoginServlet"/>" method="post">
    5       <input type="text" name="username"/><br>
    6       <input type="password" name="password"/><br>
    7       <input type="submit" name="登陆"/>
    8     </form>
    9   </body>
    login
    <body>
       <h1><center>这是用户主页,没有登陆的用户是不能直接访问该页的</center></h1>
      </body>
    userindex
    <filter>
        <display-name>LoginFilter</display-name>
        <filter-name>LoginFilter</filter-name>
        <filter-class>cn.kmust.webfilter.web.filter.LoginFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/LoginFilter</url-pattern>
      </filter-mapping>
      <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/user/userindex.jsp</url-pattern>
      </filter-mapping>
    配置

    经典案例_解决全站字符乱码

    @说明 servlet处理post和get请求编码可以写在过滤器中,但是post和get编码的处理方式不是一样的,所以需要对request进行装饰,所以编写了EncodingRequest类来对request进行装饰,来帮助过滤器完成对get请求的编码 。  

    <%--get请求,传递过去method参数,指明调用TestServlet的fun2方法,并且传递一个参数param--%>
    <a href="<c:url value='/GetServlet?param=哈哈'/>"> 这是get请求</a>
    <%--post请求--%>
    <form action="<c:url value='/PostServlet'/>" method="post">
       <input type="text" name="param" value="我是表单参数" />
       <input type="submit" name="提交"/>
    </form>
    提交页面
     1 package cn.kmust.webfilter.web.servlet;
     2 import java.io.IOException;
     3 
     4 import javax.servlet.ServletException;
     5 import javax.servlet.http.HttpServlet;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 /**
     9  *  post请求访问的Servlet,在过滤器中会进行编码的处理 
    10  *  获取参数,转发到显示页面
    11  * @author ZHAOYUQIANG
    12  *
    13  */
    14 public class PostServlet extends HttpServlet {
    15 
    16     public void doPost(HttpServletRequest request, HttpServletResponse response)
    17             throws ServletException, IOException {
    18          request.setAttribute("param", request.getParameter("param"));
    19          request.getRequestDispatcher("/show.jsp").forward(request, response);
    20     }
    21 }
    PostServlet
    package cn.kmust.webfilter.web.servlet;
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     *  get请求访问的Servlet,在过滤器中会进行编码的处理 
     *  获取参数,转发到显示页面
     * @author ZHAOYUQIANG
     *
     */
    public class GetServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            String  param = request.getParameter("param");
            request.setAttribute("param", param);
            request.getRequestDispatcher("/show.jsp").forward(request, response);
        }
    }
    GetServlet
    package cn.kmust.webfilter.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.http.HttpServletRequest;
    
    import cn.kmust.webfilter.utils.EncodingRequest;
    
    /**
     * 解决乱码的过滤器,servlet处理post和get乱码的操作,全都在这儿处理
     * @author ZHAOYUQIANG
     *
     */
    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");
            /*
             * 处理GET请求编码问题
             *   String name1 =  request.getParameter("name");
             *   name2 = new String(name.getBytes("ISO-8859-1"),"utf-8");
             *    GET不一样,设置编码后,servlet中获取name,获取应该是name2,都是如果如上写的话,
             *     getParameter("name")获取的是name1 .
             * 掉包request
             *    1. 写一个request的装饰类
             *    2. 放行时,使用我们自己的request
             *    3. 但是POST方式依然使用request
             */
            HttpServletRequest req = (HttpServletRequest) request ;
            if(req.getMethod().equals("GET")){
                EncodingRequest er = new EncodingRequest(req);     
                chain.doFilter(er, response);
            }else if(req.getMethod().equals("POST")){
                chain.doFilter(request, response);
            }
    //        response.setContentType("text/html;charset=UTF-8");
        }
    
        public void init(FilterConfig fConfig) throws ServletException {
            // TODO Auto-generated method stub
        }
    }
    EncodingFilter
    package cn.kmust.webfilter.utils;
    
    import java.io.UnsupportedEncodingException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    /**
     * 辅助过滤器来处理GET编码问题
     * @author ZHAOYUQIANG
     *
     */
    public class EncodingRequest extends HttpServletRequestWrapper{
    private HttpServletRequest request ;
        
        public EncodingRequest(HttpServletRequest request) {
            super(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) {
                // TODO Auto-generated catch block
                throw new RuntimeException(e);
            }        
            return value;
        }
    
    }
    EncodingRequest
     ${requestScope.param }
    显示页面
    <filter>
        <display-name>EncodingFilter</display-name>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>cn.kmust.webfilter.web.filter.EncodingFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/EncodingFilter</url-pattern>
      </filter-mapping>
      <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/GetServlet</url-pattern>
      </filter-mapping>
      <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/PostServlet</url-pattern>
      </filter-mapping>
    过滤器配置

    经典案例_页面静态化

     @说明 (页面静态化是什么请自行百度,这儿不做累述),我们做一个过滤器,让其访问servlet时判断是否符合静态化页面的要求 。如果是,则让其直接访问静态化的页面,如果不是,则继续访问资源。 

    CREATE TABLE `t_book` (
      `bid` char(32) NOT NULL,
      `bname` varchar(100) DEFAULT NULL,
      `price` decimal(10,2) DEFAULT NULL,
      `category` int(11) DEFAULT NULL,
      PRIMARY KEY (`bid`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    
    
    insert  into `t_book`(`bid`,`bname`,`price`,`category`) values ('b1','JavaSE_1','10.00',1),('b2','JavaSE_2','15.00',1),('b3','JavaSE_3','20.00',1),('b4','JavaSE_4','25.00',1),('b5','JavaEE_1','30.00',2),('b6','JavaEE_2','35.00',2),('b7','JavaEE_3','40.00',2),('b8','Java_framework_1','45.00',3),('b9','Java_framework_2','50.00',3);
    数据库
    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
        <default-config><!-- 这是默认的配置信息 -->
            <!-- 连接四大参数配置 -->
            <property name="jdbcUrl">jdbc:mysql://localhost:3306/filtertest</property>
            <property name="driverClass">com.mysql.jdbc.Driver</property>
            <property name="user">root</property>
            <property name="password">123456</property>
            <!-- 池本身的参数配置 -->
            <property name="acquireIncrement">3</property>
            <property name="initialPoolSize">10</property>
            <property name="minPoolSize">2</property>
            <property name="maxPoolSize">10</property>
        </default-config>
        
        <!-- 专门为oracle准备的配置信息 -->
        <!-- 这也是命名配置信息,在JDBC中创建连接池对象的时候要加 oracle-config这个参数-->
        <named-config name="oracle-config">
            <property name="jdbcUrl">  oracle的url   </property>
            <property name="driverClass">  oracle的驱动   </property>
            <property name="user">    oracle的用户 </property>
            <property name="password">    密码</property>
            <property name="acquireIncrement">3</property>
            <property name="initialPoolSize">10</property>
            <property name="minPoolSize">2</property>
            <property name="maxPoolSize">10</property>
        </named-config>
        
    </c3p0-config>
    c3p0配置
    1 <h1>链接页面</h1> 
    2 <%--Get方式,向页面传递method参数和方法中的参数 --%>  
    3 <a href="<c:url value='/BookServlet?method=findAll'/>">查询所有</a><br/>
    4 <a href="<c:url value='/BookServlet?method=findByCategory&category=1'/>">查询SE</a><br/>
    5 <a href="<c:url value='/BookServlet?method=findByCategory&category=2'/>">查询EE</a><br/>
    6 <a href="<c:url value='/BookServlet?method=findByCategory&category=3'/>">查询Framework</a><br/>
    提交页面
     1  <h1 align="center">图书列表</h1>
     2   <table border="1" align="center" width="50%">
     3     <tr>
     4         <th>书名</th>
     5         <th>单价</th>
     6         <th>分类</th>
     7     </tr>
     8 <c:forEach items="${bookList }" var="book">    
     9     <tr>
    10         <td>${book.bname }</td>
    11         <td>${book.price }</td>
    12         <%--每个分类都是不同的颜色 --%>
    13         <c:choose>
    14           <c:when test="${book.category eq 1 }"><td style="color:red">JavaSE</td></c:when>
    15           <c:when test="${book.category eq 2 }"><td style="color:blue">JavaEE</td></c:when>
    16           <c:when test="${book.category eq 3 }"><td style="color:green">JaveFrameWork</td></c:when>
    17         </c:choose>
    18         <td>${book.category }</td>
    19     </tr>
    20 </c:forEach>    
    21   </table>
    显示页面
     1 package cn.kmust.book.web.servlet;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import cn.itcast.servlet.BaseServlet;
    10 import cn.kmust.book.dao.BookDao;
    11 /**
    12  * servlet层 
    13  * @功能 把查询到的图书放到request域中,转发到list.jsp中显示
    14  * @author ZHAOYUQIANG
    15  *
    16  */
    17 public class BookServlet extends BaseServlet {
    18     private BookDao bookDao = new BookDao();
    19     /**
    20      * 查询所有图书
    21      * @param request
    22      * @param response
    23      * @return
    24      * @throws ServletException
    25      * @throws IOException
    26      */
    27     public String findAll(HttpServletRequest request,HttpServletResponse response)
    28              throws ServletException,IOException{
    29         request.setAttribute("bookList", bookDao.findAll());
    30         return "/list.jsp" ;
    31     }
    32     /**
    33      * 按分类条件查询图书
    34      * @param request
    35      * @param response
    36      * @return
    37      * @throws ServletException
    38      * @throws IOException
    39      */
    40     public String findByCategory(HttpServletRequest request,HttpServletResponse response)
    41              throws ServletException,IOException{
    42         String value = request.getParameter("category");
    43         int category = Integer.parseInt(value);
    44         request.setAttribute("bookList", bookDao.findByCategorys(category));
    45         return "/list.jsp" ;
    46     }
    47 
    48 }
    servlet
     1 package cn.kmust.book.web.filter;
     2 
     3 import java.io.File;
     4 import java.io.IOException;
     5 import javax.servlet.Filter;
     6 import javax.servlet.FilterChain;
     7 import javax.servlet.FilterConfig;
     8 import javax.servlet.ServletContext;
     9 import javax.servlet.ServletException;
    10 import javax.servlet.ServletRequest;
    11 import javax.servlet.ServletResponse;
    12 import javax.servlet.http.HttpServletRequest;
    13 import javax.servlet.http.HttpServletResponse;
    14 
    15 import cn.kmust.book.utils.StaticResponse;
    16 /**
    17  * 过滤器
    18  * @功能 /BookServlet, 访问Servlet之前,进行判断,如果静态化页面存在,过滤器直接拦截下来,直接让它访问该静态化页面,避免继续往下访问serlvet去查询数据库。
    19  *      如果静态化页面不存在(第一次访问),此时,生成新的静态化页面 ,过滤器放行, 放行之后,servlet会通过访问dao层查询数据库得到查询的数据,这个时候servlet会向list.jsp页面输出数据,但是
    20  *        我们不能让list.jsp输出,而是想办法让新的静态化页面做输出。
    21  * @解决问题 如何不能让list.jsp输出,而是让新的静态化页面做输出 ? 
    22  *           jsp的输出实际上是out.write("<html>"),而这个out流底层就是response的getWriter()(注意,区分开Out内置对象)。
    23  *             就是因为这个out流,jsp中的out.write()才会输出在jsp页面中 。假如我们改变了out流,让这个流与我们指定静态页面绑定,那么
    24  *                jsp中的out流就会向定的静态页面中输出,这个过程就做调包response 。
    25  *                   毕竟response在一个请求中是不变的,用的同一个,所以我们用调包后的response来操作就完成了解决了这个问题 
    26  * @解决问题  新的html页面会产生乱码问题 。 所以需要jsp页面中添加<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">                
    27  *                  
    28  * @author ZHAOYUQIANG
    29  *
    30  */
    31 public class StaticFilter implements Filter {
    32     private FilterConfig config ;
    33     public void destroy() {}    
    34     public void init(FilterConfig fConfig) throws ServletException {
    35         this.config = fConfig ;
    36     }    
    37     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    38         /*
    39          * 把request和response转换成HttpServlet类型的
    40          */
    41         HttpServletRequest req = (HttpServletRequest) request ;
    42         HttpServletResponse res = (HttpServletResponse) response;
    43         /*
    44          * 1. 获取category参数,变成对应的文件名称
    45          *     category有四种值,分别对应四个静态化的页面
    46          *       null--> null.html
    47          *       1--> 1.html
    48          *       2--> 2.html
    49          *       3--> 3.html
    50          * 2. 获取文件所在目录路径
    51          *       FilterConfig对象的getServletContext()能够获取ServletContext对象
    52          * 3. 用路径和文件名称 创建一个新的文件
    53          * 4. 判断该新文件是否存在,如果文件存在,重定向到这个文件
    54          *
    55          */
    56         String category = request.getParameter("category");
    57         String htmlPage = category+".html" ;
    58         String htmlPath = config.getServletContext().getRealPath("/htmls");
    59         File destFile = new File(htmlPath,htmlPage);
    60         if(destFile.exists()){
    61             res.sendRedirect(req.getContextPath()+"/htmls/"+htmlPage);
    62             return ;
    63         }
    64         /*
    65          * 5. 如果该新文件不存在,调包response
    66          *      把新文件的路径传递过去,让out流与其路径绑定
    67          * 6. 放行
    68          *     在放行后,程序访问servlet,查询到数据,因为sr是调包后的response(response的getWriter()方法产生的out流与指定html绑定的),
    69          *        那么,数据都输出到指定的静态页面中了。这个时候浏览器是不显示这个页面的,用户也是看不到的
    70          * 7. 来一个重定向,让浏览器去显示这个静态页面
    71          */
    72         StaticResponse sr = new StaticResponse(res, destFile.getAbsolutePath());
    73         chain.doFilter(request, sr);
    74         res.sendRedirect(req.getContextPath()+"/htmls/"+htmlPage);
    75         
    76     }
    77 
    78 }
    filter
    package cn.kmust.book.utils;
    
    import java.io.FileNotFoundException;
    import java.io.PrintWriter;
    import java.io.UnsupportedEncodingException;
    
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    /**
     * 调包response 
     *    让getWriter()与传递过来的路径绑定
     * @author ZHAOYUQIANG
     *
     */
    public class StaticResponse extends HttpServletResponseWrapper {
        private PrintWriter pw ;
        /**
         * 创建一个与html文件路径在一起的流对象
         * String path表示的是html文件路径
         * 
         * @param response
         * @param path
         * @throws UnsupportedEncodingException 
         * @throws FileNotFoundException 
         */
        public StaticResponse(HttpServletResponse response,String path) 
                throws FileNotFoundException, UnsupportedEncodingException {
            super(response);
            
            pw = new PrintWriter(path,"utf-8");
        }
    
        /**
         * 返回一个与html绑定在一起的printWriter对象
         *  jsp会使用它进行输出,这样数据都输出到了静态html页面中了
         */
        public PrintWriter getWriter(){
            
            return pw;
        }
    
    }
    调包response,辅助过滤器

    关于dao层和servic层页面不再给出源码,大家可以直接下载完整项目源码:

    @本项目源码使用说明 本代码第一次访问,查看各种分类 时,会访问数据库,获取资源,并且在htmls文件下建立静态化页面,可以去tomcat目录下的htmls下查看。 当再次访问该页面时候,直接重定向到该静态页面,不需要再去访问数据库了 。 

    @全部项目源码下载地址  https://files.cnblogs.com/files/zyuqiang/%E9%A1%B9%E7%9B%AE.zip

    Servlet3.0新特性 之 使用@WebFilter注解取代web.xml进行对filter的配置

     点击这里   请去Servlet3.0新特性中学习 

  • 相关阅读:
    中心极限定理
    BCEloss和交叉熵损失的区别
    postgresql的python接口
    DataGrip 2020.1 安装与激活方法
    区块链技术
    TensorRT推理加速推断并提高吞吐量
    纯视觉取代slam做路径规划及避障的思路
    DL重新回顾总结
    OpenCV 轮廓方向
    OpenCV 低通滤波(可设置频率)
  • 原文地址:https://www.cnblogs.com/zyuqiang/p/7411526.html
Copyright © 2011-2022 走看看