官术网_书友最值得收藏!

第7章 過濾器與監聽器技術

7.1 Servlet過濾器

Servlet過濾器從表面的字意理解為經過一層層的過濾處理才達到使用的要求,而其實Servlet過濾器就是服務器與客戶端請求與響應的中間層組件,在實際項目開發中Servlet過濾器主要用于對瀏覽器的請求進行過濾處理,將過濾后的請求再轉給下一個資源。其實Servlet過濾器與Servlet十分相似,只是多了一個具有攔截瀏覽器請求的功能。過濾器可以改變請求的內容來滿足客戶的需求,對開發人員來說,這點在Web開發中具有十分重要的作用。

實例180 創建過濾器

光盤位置:光盤\MR\07\180

初級

實用指數:

實例說明

本實例將介紹如何創建一個過濾器,并使用過濾器在打開頁面的同時輸出信息,此功能是由過濾器處理完成的,運行結果如圖7.1所示。

圖7.1 創建過濾器

關鍵技術

Servlet過濾器實現了Filter接口,在該接口中定義了以下幾個方法。

? init():程序啟動時調用此方法,用于初始化該Filter。

? doFilter():客戶請求服務器時會經過這里,是具體執行過濾器代碼。

? destroy():程序關閉時調用此方法,用于銷毀一些資源。

以上3個方法反映了Filter的生命周期,其中init()和destroy()方法只會被調用一次,分別在Web程序加載和卸載時調用,而doFilter()方法每次有客戶端請求就會被調用一次。

設計過程

(1)創建過濾器類FirstFilter,主要代碼如下:

        package com.mr;
        public class FirstFilter implements Filter{
        private FilterConfig filterConfig;
        //初始化方法
        public void init(FilterConfig filterConfig) throws ServletException {
              this.filterConfig = filterConfig;
        }
        //具體執行的方法
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException{
              try {
                  System.out.println("客戶端的請求經過這里!! ! ! ");
                  filterChain.doFilter (request, response);
                  System.out.println("賬號和密碼請求處理經過這里");
              } catch (ServletException e) {
                  System.out.println("客戶端請求失敗");
              }catch(IOException io){
                  System.out.println("賬號和密碼請求失敗");
              }
        }
        //銷毀過濾器
        public void destroy() {
            this.filterConfig=null;
        }
        }

(2)在web.xml中配置過濾器,關鍵代碼如下:

        <filter>
              <filter-name>FirstFilter</filter-name><! --過濾器名稱 -->
              <filter-class>com.mr.FirstFilter</filter-class><! --過濾器的實現類 -->
        </filter>
        <filter-mapping>
            <filter-name>firstFilter</filter-name>    <! --映射過濾器名稱 -->
              <url-pattern>/*</url-pattern>          <! --使用通配符*什么請求都經過濾器 -->
        </filter-mapping>

秘笈心法

過濾器在web.xml配置時,<filter>元素用來定義一個過濾器,<filter-mapping>元素用于為過濾器映射特定的URL。注意在配置多個Filter時執行有先有后,規定是<filter-mapping>配置在前面的Filter執行要早于配置在后面的Filter,另外要注意多個Filter可能會互相影響。

實例181 防盜鏈過濾器

光盤位置:光盤\MR\07\181

初級

實用指數:

實例說明

本實例將介紹如何使用過濾器技術,防止通過其他URL地址直接訪問本站資源。運行本實例,當URL地址不是本站地址時,在網頁中將顯示錯誤提示信息,實例運行效果如圖7.2所示。

圖7.2 防盜鏈過濾器

關鍵技術

本實例主要應用request對象的getHeader()方法獲取信息頭來源地址,若是來自其他網站就彈出錯誤圖片。getHeader()方法的語法結構如下:

        public String getHeader(String headerName)

參數說明

headerName:指定字符串類型的響應頭名稱。

設計過程

(1)創建Filter過濾器的實現類ImageFilter,在doFilter()方法中對request進行驗證,實現將圖片顯示在頁面之前,驗證客戶端請求是否來自本網站,主要代碼如下:

        public class ImageFilter implements Filter {
        public void init(FilterConfig config) throws ServletException {
        }
        public void doFilter(ServletRequest req, ServletResponse res,
                  FilterChain chain) throws IOException, ServletException {
              HttpServletRequest request=(HttpServletRequest)req;                    //request對象
              HttpServletResponse response=(HttpServletResponse)res;                 //response對象
              String imurl=request.getHeader("imurl");                               //鏈接的來源地址
              if(imurl==null||! imurl.contains(request.getServerName())){            //判斷訪問來源
                  request.getRequestDispatcher("/errorimage.gif").forward(request,   //顯示錯誤圖片
                            response);
              } else {
                  chain.doFilter(request, response);                                 //正常顯示圖片
              }
        }
        public void destroy() {
        }
        }

(2)在web.xml中配置Filter,該過濾器是從request信息頭中獲取請求來源,主要代碼如下:

        <filter>
        <filter-name>imageFilter</filter-name>
        <filter-class>com.mr.filter.ImageFilter</filter-class>
        </filter>
        <filter-mapping>
        <filter-name>imageFilter</filter-name>
        <url-pattern>/images/*</url-pattern>
        </filter-mapping>

秘笈心法

本實例的Filter是對images下所有的資源有效,如果是“/*”就是對工程包下所有的資源有效。

實例182 日志記錄過濾器

光盤位置:光盤\MR\07\182

初級

實用指數:

實例說明

在實際的項目開發過程中,經常需要在項目運行時記錄并在控制臺中輸出運行時的日志信息,便于查看項目的運行狀況。本實例將介紹如何應用過濾器實現日志記錄。運行本實例,將在控制臺中輸出項目運行時的日志信息,如圖7.3所示。

圖7.3 控制臺輸出日志信息

關鍵技術

本實例主要應用Apache的Log4j組件輸出日志信息。該組件主要用于日志管理。Logger是Log4j的日志記錄器,它是Log4j的核心組件。

在程序中可以使用Logger類的不同方法來輸出各種級別的日志信息,Log4j會根據配置的當前日志級別決定輸出哪些日志。對應各種級別日志的輸出方法如下:

(1)DEBUG日志可以使用Logger類的debug()方法輸出日志消息,語法格式如下:

        logger.debug(Object message)

message:輸出的日志消息,如“logger.debug("調試日志")”。

(2)INFO日志可以使用Logger類的info()方法輸出日志消息,語法格式如下:

        logger.info(Object message)

message:輸出的日志消息,如“logger.info("消息日志")”。

(3)WARN日志可以使用Logger類的warn()方法輸出日志消息,語法格式如下:

        logger.warn(Object message)

message:輸出的日志消息,如“logger.warn("警告日志")”。

(4)ERROR日志可以使用Logger類的error()方法輸出日志消息,語法格式如下:

        logger.error(Object message)

message:輸出的日志消息,如“logger.error("數據庫連接失敗")”。

(5)FATAL日志可以使用Logger類的fatal()方法輸出日志消息,語法格式如下:

        logger.fatal(Object message)

message:輸出的日志消息,如“logger.fatal("內存不足")”。

設計過程

(1)創建日志Filter實現類LogFilter.java,主要是在初次調用時開始記錄,執行時獲取訪問的URI和執行前的時間,關鍵代碼如下:

        public class LogFilter implements Filter {
        private Log log=LogFactory.getLog(this.getClass());
        private String filterName;
        public void init(FilterConfig config) throws ServletException {
              filterName=config.getFilterName();                                   //獲取Filter的name
              log.info("啟動Filter: "+filterName);                                  //啟動Filter
        }
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                  throws IOException, ServletException {
              HttpServletRequest request = (HttpServletRequest) req;
              HttpServletResponse response = (HttpServletResponse) res;
              long startTime=System.currentTimeMillis();                           //運行前的時間
              String requestURI=request.getRequestURI();                           //獲取訪問的URI
              requestURI=request.getQueryString()==null? requestURI                //所有的地址欄參數對比
                      : (requestURI + "? " + request.getQueryString());
              chain.doFilter(request, response);
              long endTime=System.currentTimeMillis();
              //消耗的總時間
              log.info(request.getRemoteAddr()+" 訪問了 "+requestURI+", 總用時 "+(endTime-startTime)+" 毫秒。");
        }
        public void destroy() { //銷毀時記錄日志
        }
        }

(2)使用日志記錄需要commons-logging的Log4j來輸出日志,本實例輸出格式如下:

        log4j.rootLogger=INFO, A1
        log4j.appender.A1=org.apache.log4j.ConsoleAppender
        log4j.appender.A1.layout=org.apache.log4j.PatternLayout
        log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss, SSS} [%l]-[%p] %m%n

秘笈心法

Filter日志最大的優點在于可拆卸性,當不需要記錄日志功能時,只需要將Filter配置注釋掉即可。

實例183 字符替換過濾器

光盤位置:光盤\MR\07\183

初級

實用指數:

實例說明

有時對網站內容進行控制是用來防止輸出非法內容或者敏感內容的,常規的辦法是保存數據庫之前對非法內容進行替換,但這種辦法具有局限性,工作量大并且耦合性比較高。本實例將介紹如何使用過濾器,對非法字符和關鍵字進行過濾處理,實例運行結果如圖7.4所示。

圖7.4 運行結果

關鍵技術

實現本實例,可以在服務器端使用過濾器技術。在Web服務器獲得用戶的請求之前,過濾器可以訪問該請求。在Web服務器將輸出響應發送給用戶之前,過濾器還可以訪問該響應。所以在過濾器中訪問該響應信息,然后將該響應轉換為自定義的響應,最后將過濾后的自定義響應內容返回給客戶端。

在java.servlet.http包中,包含了一個名為HttpServletResponseWrapper的類,該類的對象表示一個自定義的響應對象,它實現了HttpServletResponse接口,其構造方法通過傳入的HttpServletResponse類型的參數,將響應轉換為自定義的響應。構造方法的語法結構如下:

        public HttpServletResponseWrapper(HttpServletResponse response)

設計過程

(1)創建Cr.java類文件,作用是處理對頁面響應的內容,用toString()方法進行重載,然后將頁面中的內容轉換成字符串,關鍵代碼如下:

        public class Cr extends HttpServletResponseWrapper {
            private CharArrayWriter output;
            public String toString() {
              return output.toString();
            }
            public Cr(HttpServletResponse response){
              super(response);
              this.output=new CharArrayWriter();
            }
            public PrintWriter getWriter(){
              return new PrintWriter(output);
            }
        }

(2)創建過濾器實現類CtFilter.java,在doFilter()方法中獲取頁面的響應,然后對這個響應內容進行處理并生成自定義的響應,把敏感字去掉并替換成“***”,再返回給客戶端,關鍵代碼如下:

        public class CtFilter extends HttpServlet implements Filter {
            public void init(FilterConfig filterConfig) throws ServletException {
            }
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
                  throws ServletException, IOException {
              response.setCharacterEncoding("gb2312");
              PrintWriter out = response.getWriter();
              Cr wrapper = new Cr((HttpServletResponse)response);
              filterChain.doFilter(request, wrapper);
              String resStr = wrapper.toString().trim();
              String newStr = "";
              if (resStr.indexOf("混蛋") > 0) {
                  newStr = resStr.replace("混蛋", "***");
              }
              out.println(newStr);
            }
        }

(3)在web.xml文件中配置過濾器,關鍵代碼如下:

        <filter>
              <filter-name>cr</filter-name>
              <filter-class>com.mr.CtFilter</filter-class>
        </filter>
        <filter-mapping>
        <filter-name>cr</filter-name>
        <url-pattern>/*</url-pattern>
        </filter-mapping>

秘笈心法

如果響應response輸出的內容為字符類內容,則調用getWriter()方法;如果為二進制內容或圖像數據等,就需要調用getOutputStream()方法,本實例只覆蓋了getWriter()方法。

實例184 異常捕獲過濾器

光盤位置:光盤\MR\07\184

初級

實用指數:

實例說明

本實例將介紹如何實現異常捕獲過濾器。運行本實例,單擊異常超鏈接,會彈出相應的處理頁面,運行結果如圖7.5所示。

圖7.5 運行結果

關鍵技術

本實例主要是在過濾器Filter的doFilter()方法中對執行過濾器鏈的chain的doFilter()語句處添加try…catch異常捕獲語句,然后在catch語句中循環異常對象,直到找出根異常為止。

設計過程

(1)創建Filter實現類ExceptionFilter.java,利用throwable拋出異常去捕捉異常原因并轉到相應的頁面中,主要代碼如下:

        public class ExceptionFilter implements Filter {
        public void destroy() {
        }
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              try {
                  chain.doFilter(request, response);
              }catch(Exception e){                                                   //如果有異常則捕捉
                  Throwable rootCause = e;
                  while (rootCause.getCause() ! = null) {
                      rootCause = rootCause.getCause();
                  }
                  String errormessage=rootCause.getMessage();                        //返回此異常的詳細消息字符串
                  errormessage = errormessage == null ? "異常:" + rootCause.getClass().getName()
                            :errormessage;                                           //中止傳遞異常的原因
                  request.setAttribute("errormessage", errormessage);
                  request.setAttribute("e", e);
                  if(rootCause instanceof LoginException){                           //轉到登錄頁面
                      request.getRequestDispatcher("/LoginException.jsp").forward(request, response);
                  } else if (rootCause instanceof OperationException) { 
                                                                                     //轉到操作頁面
                      request.getRequestDispatcher("/OperationException.jsp").forward(request, response);
                  } else {
                      request.getRequestDispatcher("/exception.jsp").forward(request, //其他異常
                                response);
                  }
              }
        }
        public void init(FilterConfig arg0) throws ServletException {
        }
        }

(2)創建LoginException.jsp登錄異常頁面,主要代碼如下:

        <div align="center"style="font-size:large; ">后臺操作</div>
        <form action="">
        <table align="center">
              <tr>
                  <td>賬號</td>
                  <td><input type="text"name="account"/></td>
              </tr>
              <tr>
                  <td>密碼</td>
                  <td><input type="password"name="password"/></td>
              </tr>
              <tr>
                  <td align="center"colspan="2"><input type="submit"value=" 登錄"/>
                  <input type="submit"value="退出"/></td>
              </tr>
        </table>
        </form>
        <div class="error"align="center">
        ${ errormessage }
        </div>

(3)創建OperationException操作異常頁面,主要代碼如下:

        <div class="error"align="center">
        ${errormessage}<a href="javascript:history.go(-1);">返回上一級操作</a>
        </div>

(4)創建Exceptionmain.jsp頁面,關鍵代碼如下:

        <%
        String action = request.getParameter("action");
        if("OperationException".equals(action)){
              throw new OperationException("此操作失敗.  ");
        }
        else if("LoginException".equals(action)){
            throw new LoginException("請您登錄后再進行此項操作.  ");
        }
        else if("exception".equals(action)){
            Integer.parseInt("null空傳遞參數");
        }
        %>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>異常捕捉過濾器</title>
        </head>
        <body>
        <table align="left"cellpadding="2"cellspacing="2">
        <Tr><td><a href="${pageContext.request.requestURI}? action=OperationException">過濾操作</a></td></Tr>
        <tr><td><a href="${pageContext.request.requestURI}? action=LoginException">過濾登錄</a></td></tr>
        <Tr><td><a href="${pageContext.request.requestURI}? action=exception">過濾異常</a></td></Tr>
        </table>

秘笈心法

Throwable類是Java語言中所有錯誤或異常的超類,只有當對象是此類的實例時,才能通過Java虛擬機或者Java throw語句拋出,類似的只有此類或其子類之一才可以是catch子句中的參數類型。

實例185 驗證用戶身份Filter過濾器

光盤位置:光盤\MR\07\185

初級

實用指數:

實例說明

在進行用戶的首次身份認證后都會在session中留下相應的用戶對象作為標識,在以后的操作中,只需要在進行身份驗證的頁面或Servlet中查看相應的session即可。最有效的驗證方法就是通過過濾器對一批頁面或Servlet統一進行身份驗證,這樣在設計頁面或Servlet時就不需要考慮身份驗證的問題,避免出現代碼冗余等問題。本實例將介紹如何通過過濾器來進行用戶身份驗證。運行本實例,填寫用戶名和密碼進行正常登錄,則可以登錄成功,當用戶沒有登錄時,直接在URL地址欄輸入loginsuccee.jsp頁面,則會彈出提示信息,如圖7.6所示。

圖7.6 未進行登錄時顯示提示信息

關鍵技術

實現本實例,主要是判斷session域中是否存在用戶名。首先,用戶在登錄時,系統會將用戶名保存在session域中。在Filter過濾器的doFilter()方法中,會判斷session域中是否包含當前這個用戶名,如果存在則允許登錄;否則會彈出提示信息,并將當前的請求地址轉向用戶登錄頁。

設計過程

(1)創建過濾器的實現類FilterLogin.java,先初始化init(FilterConfig filterConfig)方法,再在執行體中判斷session是否有user對象,如果沒有則輸出提示語句,否則繼續執行,主要代碼如下:

        public class FilterLogin extends HttpServlet implements Filter {
            private FilterConfig filterConfig;
            public void init(FilterConfig filterConfig) throws ServletException {
              this.filterConfig = filterConfig;
            }
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
                  throws ServletException, IOException {
              HttpSession session=((HttpServletRequest)request).getSession();
              response.setCharacterEncoding("gb2312");   //響應客戶端類型
              if(session.getAttribute("user")==null){       //判斷session中是否有user這個對象
                  PrintWriter out=response.getWriter();   //創建一個輸出流
                  //如果為空則通過JavaScript腳本輸出提示并跳轉到index.jsp頁面
                  out.print("<script language=javascript>alert(’您還沒有登錄!! ! '); window.location.href='../index.jsp'; </script>");
              }else{
                  filterChain.doFilter(request, response);  //否則繼續執行
              }
            }
            public void destroy() {
            }
        }

(2)創建loginresult.jsp頁面,用于在user對象的session中執行跳轉到下一頁面,代碼如下:

        <%
        request.setCharacterEncoding("gb2312");
        String name=request.getParameter("name");
        String password=request.getParameter("password");
              User user=new User();
              user.setUsername(name);
              user.setPassword(password);
              session.setAttribute("user", user);
        response.sendRedirect("filter/loginsuccee.jsp");
        %>

(3)創建JavaBean類User,存放登錄名稱與密碼,并設置getter與setter方法。

(4)創建用戶登錄頁面,關鍵代碼如下:

        <body><div align="center">使用過濾器身份驗證
        <form name="form" method="post" action="loginresult.jsp" onSubmit="return checkEmpty()">
        <table width="220"  border="0"align="center">
          <tr>
            <td >用戶名:</td>
            <td><input name="name"type="text"></td>
          </tr>
          <tr>
            <td >密&nbsp; &nbsp;碼:</td>
            <td><input name="password"type="password"></td>
          </tr>
        </table><br>
          <input type="submit"name="Submit"value="登錄">
          <input type="submit"value="退出"/>
        </form>

(5)在web.xml文件中配置如下:

        <filter>
            <filter-name>filterUser</filter-name>
            <filter-class>com.mr.filter.FilterLogin</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>filterUser</filter-name>
            <url-pattern>/filter/*</url-pattern>
        </filter-mapping>

秘笈心法

在設置需要進行身份驗證的頁面時,應該把登錄頁面排除在外;否則,如果登錄頁面無法通過身份驗證,用戶將無法進行登錄,所有進行身份驗證的頁面都將無法訪問。

實例186 字符編碼過濾器

光盤位置:光盤\MR\07\186

初級

實用指數:

實例說明

初學者在編寫Web程序時,經常出現頁面編碼混亂的問題,也就是中文字符顯示成亂碼。這類問題經常困擾初學者,本實例使用Servlet過濾器解決編碼導致的頁面亂碼問題。本實例使用GBK編碼格式,如果不進行編碼轉換,將在頁面中輸出亂碼;而通過過濾器自動將所有數據都轉換為GBK編碼就不會出現亂碼,如圖7.7所示。

圖7.7 字符編碼過濾器

關鍵技術

本實例主要在web.xml中配置默認的字符編碼,并在Filter過濾器的初始化init()方法中加載這個參數,然后在執行doFilter()方法中獲取這個編碼的配置參數,將它設置為request和response的默認編碼。

設計過程

(1)創建過濾器的實現類Encoding.java,用于處理頁面的字符編碼格式。在初始化方法init()中,加載web. xml配置的編碼方式,并啟用enabled編碼,然后在doFilter()方法中設置請求以及相應的編碼格式,關鍵代碼如下:

        public class EncodingFilter implements Filter {
        private String Encoding;                                          //配置web.xml編碼
        private boolean enabled;                                          //是否啟用Filter
        public void init(FilterConfig config) throws ServletException {
              Encoding=config.getInitParameter("Encoding");               //編碼方式
              enabled = "true".equalsIgnoreCase(Encoding.trim())|| "1".equalsIgnoreCase(Encoding.trim());
        }
        public void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain chain) throws IOException, ServletException {
              if(enabled||Encoding! =null){                              //如果啟用了此Filter
                  request.setCharacterEncoding(Encoding);                //request的編碼
                  response.setCharacterEncoding(Encoding);               //response的編碼
              }
              chain.doFilter(request, response);                         //繼續執行下一個Filter
        }
        public void destroy() {
              Encoding = null;
        }}

(2)在web.xml中配置初始化編碼格式,主要代碼如下:

        <filter>
              <filter-name>encodingFilter</filter-name>
              <filter-class>com.mr.encoding.EncodingFilter</filter-class>
              <init-param>
                  <param-name>Encoding</param-name>
                  <param-value>UTF-8</param-value>
              </init-param>
              <init-param>
                  <param-name>enabled</param-name>
                  <param-value>true</param-value>
              </init-param>
        </filter>
        <filter-mapping>
              <filter-name>encodingFilter</filter-name>
              <url-pattern>/*</url-pattern>
        </filter-mapping>

(3)創建Encoding.jsp頁面,應用EL表達式輸出編碼后的內容,關鍵代碼如下:

        <form action="${param.request.requestURL}"method="post">
        <table align="left"bgcolor="lightblue"cellpadding="3"
                      cellspacing="7">
              <tr><td>
              <textarea name="text"rows="8"cols="40">${param.text}</textarea>
                  </td>
              <tr><td align="center"colspan="4">
                      <input type="submit"value="提交內容"/>
                  </td></Tr>
          <tr><Td>您輸入的是:<br/>
                  <div><font size="6" >${ param.text }</font></div></Td></tr>
        </table>
        </form>

秘笈心法

如果表單請求方式為GET,還需要在Tomcat的文件夾下的conf/server.xml配置文件中修改URIEncoding參數,因為默認的編碼為ISO-8859-1,否則依然會出現亂碼。

實例187 使用過濾器監控網站流量

光盤位置:光盤\MR\07\187

初級

實用指數:

實例說明

Servlet過濾器可以對用戶提交的數據或服務器返回的數據進行更改。任何到達服務器的請求都會首先經過過濾器的處理。本實例應用過濾器的這個特點編寫一個專門用于流量統計的過濾器,運行結果如圖7.8所示。

圖7.8 運行結果

關鍵技術

首先,需要一個整型變量來記錄當前的流量,它需要在這個服務器中一直存在,可以用一個整型的靜態私有變量來存放這個值,它的初值為0,設置代碼如下:

        private static int flux = 0;

其次,在每次有用戶訪問頁面時,必須對統計變量進行相應的修改。但是對于Web系統中多用戶訪問的系統,修改變量時必須考慮到同步的問題,即同一時間只能有一個用戶修改這個整型變量,否則將會產生共享沖突,引起統計數據的不準確(得到的值比實際值小)。

在Java中可以通過關鍵字synchronized來解決這個問題。被synchronized關鍵字修飾的方法在執行過程中不會中斷,也就是說線程一旦進入synchronized修飾的方法,其他線程就不會被阻塞,直到當前線程執行完這個方法為止。在本實例中就可以使用關鍵字synchronized來解決上述問題。

最后,把統計變量放入request中,以便任何頁面都可以隨時訪問到網站當前的流量值,執行代碼如下:

        request.setAttribute("flux", String.valueOf(flux));

設計過程

(1)創建過濾器的實現類FilterNum.java,通過Servlet中的過濾器技術統計網站的訪問量,關鍵代碼如下:

        public class FilterNum extends HttpServlet implements Filter {
            private static int num=0;  //定義全局變量
            public void init(FilterConfig filterConfig) throws ServletException {
            }
        public synchronized void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
              throwsServletException, IOException {
              this.num++;           //自增長
              request.setAttribute("num", String.valueOf(num));
              filterChain.doFilter(request, response);
            }
            public void destroy() {
            }
        }

(2)創建index.jsp頁面,主要代碼如下:

        <table width="300"height="100"border="0"cellpadding="0"cellspacing="0">
              <tr align="center"bgcolor="lightblue"><Td>目前在線訪問流量是:</Td></tr>
            <tr align="center">
            <td><%=request.getAttribute("num")%>人訪問過</td>
            </tr>
        </table>

(3)在web.xml中配置FilterNum過濾器,關鍵代碼如下:

        <filter>
            <filter-name>filterNum</filter-name>
            <filter-class>com.mr.filter.FilterNum</filter-class>
        </filter>
          <filter-mapping>
            <filter-name>filterNum</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

秘笈心法

為了避免多個用戶并發訪問而導致數據的不準確,可以使用synchronized關鍵字修飾方法。

實例188 防止頁面緩存的過濾器

光盤位置:光盤\MR\07\188

初級

實用指數:

實例說明

IE緩存雖然能夠提高已存儲網站的訪問速度,但是過度的IE緩存會影響瀏覽器的響應速度。同時還可能為網站的運行帶來一些不必要的麻煩。例如,可能會因為瀏覽器緩存的應用,而導致Web服務器不能準確地計算一個頁面或廣告被閱覽的次數;在論壇或者網上商城系統中由于瀏覽器緩存的使用,導致更新的圖片信息不能得到及時的顯示。這些都是瀏覽器緩存帶來的負面影響。本實例主要介紹瀏覽網頁時不自動緩存,這樣下次訪問能及時更新圖片或者相關信息,運行結果如圖7.9所示。

圖7.9 緩存文件夾為空

關鍵技術

本實例主要應用過濾器(Filter)防止頁面緩存。關鍵是應用javax.servlet.Filter接口中提供的doFilter()方法。在doFilter()方法中設置HTML中meta標簽的http-equiv屬性,實現禁止瀏覽器緩存的功能。

(1)設置http-equiv屬性的參數expires,控制網頁的過期時間。

(2)設置http-equiv屬性的參數Pragma,禁止瀏覽器從本地計算機的緩存中訪問頁面內容。

(3)設置HTTP消息頭中的Cache-control參數,控制頁面的緩存。Cache-control的常見值有private、no-cache、max-age和must-revalidate等,默認值為private。

Cache-control的作用根據瀏覽方法的不同可以分為以下幾種情況:

(1)以打開新窗口的方式進行瀏覽

如果指定Cache-control的值為private、no-cache或者must-revalidate,那么打開新窗口訪問時就會重新訪問服務器;如果指定的值為max-age,那么在此值規定的時間中就不會重新訪問服務器,如Cache-control:max-age=10表示當訪問此網頁后的10秒內不會再次訪問服務器。

(2)在地址欄中按Enter鍵進行瀏覽

如果值為private或must-revalidate,則只有第一次訪問時會訪問服務器,以后就不再訪問;如果值為no-cache,那么每次都會訪問;如果值為max-age,則在過期之前不會重復訪問。

(3)按后退鍵進行瀏覽

如果值為private、must-revalidate或max-age,則不會重復訪問;如果值為no-cache,則每次都重復訪問。

(4)按刷新鍵

無論為何值,都會重復訪問。如果指定Cache-control值為no-cache時,訪問此頁面不會在Internet臨時文件夾中留下頁面備份。

設計過程

(1)創建過濾器的實現類NoCacheFilter.java,設置HTTP信息頭禁止瀏覽器從緩存中讀取頁面。在doFilter()方法中通過設置響應頭信息防止頁面緩存,關鍵代碼如下:

        public class NoCacheFilter implements Filter {
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain) throws IOException, ServletException {
              //HTTP消息頭控制網頁的緩存
          ((HttpServletResponse) response).setHeader("Cache-Control", "no-cache");
              //禁止瀏覽器從本機的緩存中讀取頁面
        ((HttpServletResponse)response).setHeader("Pragma", "no-cache");
        ((HttpServletResponse)response).setHeader("Expires", "-1");    //緩存中的有效期
              filterchain.doFilter(request, response);
            }
            public void destroy() {
            }
        }

(2)在web.xml中配置NoCacheFilter.java過濾器,關鍵代碼如下:

        <filter>
              <filter-name>BrowserNoCacheFilter</filter-name>
              <filter-class>com.mr.nocache.NoCacheFilter</filter-class>
              <init-param>
                  <param-name>Cache-control</param-name>
                  <param-value>no-cache</param-value>
              </init-param>
              <init-param>
                  <param-name>Pragma</param-name>
                  <param-value>no-cache</param-value>
              </init-param>
              <init-param>
                  <param-name>Expires</param-name>
                  <param-value>-1</param-value>
              </init-param>
        </filter>
        <filter-mapping>
              <filter-name>NoCacheFilter</filter-name>
              <url-pattern>/*</url-pattern>
              <dispatcher>REQUEST</dispatcher>
              <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
        <session-config>
              <session-timeout>30</session-timeout>
        </session-config>

提示:Session-timeout為緩存有效期30秒。

秘笈心法

緩存文件夾的打開方式是,選擇IE瀏覽器,單擊鼠標右鍵,并在彈出的快捷菜單中選擇“屬性”命令,彈出Internet屬性對話框,選擇“常規”選項卡,在Internet監時文件中單擊“設置”按鈕,在彈出的設置對話框中單擊“查看文件”按鈕,將看到瀏覽器緩存中存儲的文件,而此時該文件夾下沒有任何文件。

實例189 通過過濾器控制頁面輸出內容

光盤位置:光盤\MR\07\189

初級

實用指數:

實例說明

在開發程序的過程中,很多程序員都實現過在打開的頁面中彈出一個對話框的功能,通過該對話框來輸出一些廣告或者公告信息。如果想將這個功能應用到多個頁面中,就需要在多個頁面中添加調用彈出對話框功能的代碼來完成,這樣做雖然能夠實現此功能,但是卻增加了代碼的冗余。

本實例將介紹一種不必在多個頁面中編寫代碼而實現彈出對話框的方法,即通過過濾器來控制頁面輸出的內容,進而實現在每個響應的頁面中都彈出一個對話框的功能。運行本實例,單擊頁面中的任何超鏈接,都會彈出一個新的對話框,如圖7.10所示。

圖7.10 轉換后的效果

關鍵技術

本實例的關鍵在于在完成過濾任務時,將請求的對象返回到自定義的應答對象中,通過自定義應答對象對請求的數據進行編譯,編譯完成后通過自定義的方法返回響應數據,并通過replace()方法向響應的數據中添加調用彈出對話框的代碼。完成通過過濾器控制頁面輸出的操作。

replace()方法的語法結構如下:

        public String replace(char oldChar, char newChar)

將該方法中的newChar替換指定字符串中出現的所有oldChar,返回一個新的字符串。

參數說明

? oldChar:要替換的子字符串或者字符。

? newChar:新的字符串或字符,用于替換原有字符串的內容。

設計過程

(1)創建OutputStream.java文件并且繼承ServletOutputStream類,替換父類的輸出流,關鍵代碼如下:

        public class OutputStream extends ServletOutputStream {
            ByteArrayOutputStream stream;                          //創建字節數組輸出流
            public OutputStream(ByteArrayOutputStream stream) {
              this.stream=stream;                                 //構造方法初始化輸出流
            }
            public void write(int b) throws IOException {
              stream.write(b);                                    //使用此類的輸出流替換父類的輸出方法
            }
        }

(2)創建ResponseWrapper.java文件并且繼承HttpServletResponseWrapper,使響應對象進行重新編譯并返回響應的數據,關鍵代碼如下:

        public class ResponseWrapper extends HttpServletResponseWrapper {
            private OutputStream stream;                             //聲明一個輸出流
            private ByteArrayOutputStream byteStream;                //聲明字節數組輸出流
            private PrintWriter pw;                                  //聲明打印輸出流
            public ResponseWrapper(HttpServletResponse response) {
              super(response);
              byteStream=new ByteArrayOutputStream();               //數據流初始化
              stream = new OutputStream(byteStream);
              pw = new PrintWriter(byteStream);
            }
            public ServletOutputStream getOutputStream() throws IOException {
              return stream;                                        //返回字節輸出流并重寫父類方法
            }
            public PrintWriter getWriter() throws IOException {
              return pw;                                            //返回打印輸出流重寫父類方法
            }
            public String getContent() throws UnsupportedEncodingException {
              return byteStream.toString();                         //返回響應數據
            }
        }

(3)創建過濾器的實現類OutFilter.java,在doFilter()方法中完成對過濾器的操作,并用getContent()獲取到響應的數據,用replace()方法將彈出對話框的代碼層加到response響應的數據中去,關鍵代碼如下:

        public class OutFilter implements Filter {
            private boolean variable=true;               //如果variable為真,每次都生成HTML首頁
            private FilterConfig filterConfig = null;
            public void init(FilterConfig filterConfig) {
              this.filterConfig = filterConfig;
            }
            public void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain chain)
                  throws IOException, ServletException {
              HttpServletResponse httpResp = (HttpServletResponse) response;
              ResponseWrapper responseWrapper = new ResponseWrapper(httpResp);
              chain.doFilter(request, responseWrapper);   //過濾器的操作
              PrintWriter out=response.getWriter();      //創建輸出流
              responseWrapper.getWriter().flush();       //獲取輸出流并強制刷新
              String str=responseWrapper.getContent();
              String
        stres="</head><script>window.open('message.htm', '', 'width='+300+', height='+180+', top='+'+window.screen.width-300+'+', left='+'+window.screen.heigh
        t+180+'); </script>";
              out.println(str.replace("</head>", stres));
            }
            public void destroy() {
            }
            public void log(String msg) {
              filterConfig.getServletContext().log(msg);
            }
        }

(4)在web.xml中配置過濾器,關鍵代碼如下:

        <filter>
          <filter-name>CharacterEncodingFilter</filter-name>
          <filter-class>com.mr.filter.CharacterEncodingFilter</filter-class>
          <init-param>
          <param-name>encoding</param-name>
          <param-value>GBK</param-value>
          </init-param>
         </filter>
        <filter>
          <filter-name>outFilter</filter-name>
          <filter-class>com.mr.filter.OutFilter</filter-class>
         </filter>
         <filter-mapping>
          <filter-name>CharacterEncodingFilter</filter-name>
          <url-pattern>/*</url-pattern>
          <dispatcher>REQUEST</dispatcher>
          <dispatcher>FORWARD</dispatcher>
         </filter-mapping>
         <filter-mapping>
          <filter-name>outFilter</filter-name>
          <url-pattern>/index.jsp</url-pattern>
          <dispatcher>REQUEST</dispatcher>
          <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
            <filter-mapping>
              <filter-name>outFilter</filter-name>
              <url-pattern>/indexsure.jsp</url-pattern>
              <dispatcher>REQUEST</dispatcher>
              <dispatcher>FORWARD</dispatcher>
            </filter-mapping>

秘笈心法

在開發Web工程時,網頁中彈出一個對話框是很常見的,如果想在多個頁面中添加此功能,則每個頁面都添加對話框功能的代碼會帶來大量代碼的冗余,本實例正是解決此辦法之一。

實例190 使用過濾器自動生成靜態頁面

光盤位置:光盤\MR\07\190

初級

實用指數:

實例說明

在開發程序的過程中,創建的幾乎都是動態頁面,因為在每個頁面中都要使用或者傳遞一些數據,所以在瀏覽網頁時速度就不是很理想,總是因為數據的處理而影響網頁打開的速度。然而,如果都是靜態網頁,網頁的打開速度就不會受到影響,同樣還可以更改網頁文件的后綴名,從而隱藏程序開發使用的語言。本實例將介紹一種生成靜態網頁的方法,即通過過濾器將動態頁面生成靜態頁,運行結果如圖7.11所示。

圖7.11 自動生成靜態頁面

關鍵技術

通過過濾器生成靜態頁面主要應用過濾器接受請求,然后通過自定義的響應對象對請求的數據進行處理,生成一個靜態頁面,最后將經過處理的響應數據返回到客戶端。

首先實現Filter接口,然后定義doFilter()方法,在該方法中獲取到請求的數據,應用自定義的響應對象ResponseWrapper對請求數據進行過濾,過濾業務完成后生成靜態頁面。

設計過程

(1)創建OutputStream類,在構造方法中初始化輸出流,定義writer()方法并替換父類的輸出方法,關鍵代碼如下:

        public class OutputStream extends ServletOutputStream {
            ByteArrayOutputStream ostream;                               //創建字節數組輸出流
            public OutputStream(ByteArrayOutputStream ostream) {
              this.ostream=ostream;                                      //在構造方法中初始化輸出流
            }
            public void write(int b) throws IOException {
              ostream.write(b);                                          //使用此類輸出流替換父類的輸出方法
            }
        }

(2)創建ResponseWrapper類文件,該類繼承HttpServletResponseWrapper類,使用它對請求的數據進行處理,關鍵代碼如下:

        public class ResponseWrapper extends HttpServletResponseWrapper {
            private OutputStream ostream;                                              //自定義輸出流
            private ByteArrayOutputStream byteStream;                                  //字節數組輸出流
            private PrintWriter pw;                                                    //打印輸出流
            public ResponseWrapper(HttpServletResponse response) {
                super(response);
                byteStream=new ByteArrayOutputStream();                               //數據流初始化
                ostream = new OutputStream(byteStream);
                pw = new PrintWriter(byteStream);
            }
            public ServletOutputStream getOutputStream() throws IOException {
                return ostream;                                                       //返回字節輸出流并重寫父類方法
            }
            public PrintWriter getWriter() throws IOException {
                return pw;                                                            //返回打印輸出流重寫分類方法
            }
            public String getContent() throws UnsupportedEncodingException {
                return byteStream.toString();                                         //自定義方法返回響應的數據
            }
        }

(3)創建過濾器的實現類StaticHtmlFilter,將定義的對象為響應對象來完成過濾操作,在定義的響應對象中獲取請求的數據,并對其進行修改生成靜態頁面,最后將修改后的響應返回到客戶端,關鍵代碼如下:

        public class StaticHtmlFilter implements Filter {
            private boolean variable=true;                                             //定義一個變量variable時,每次都生成HTML首頁
            String strs = "";
            private FilterConfig filterConfig = null;
            public void init(FilterConfig filterConfig) {
              this.filterConfig = filterConfig;
            }
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                  throws IOException, ServletException {
              HttpServletResponse httpRes = (HttpServletResponse) response;
              String path = ((HttpServletRequest) request).getServletPath();
              strs=path.substring(1);                                                 //獲取文件名
              ResponseWrapper responseWrapper=new ResponseWrapper(httpRes);           //創建定義的應答對象
              chain.doFilter(request, responseWrapper);                               //完成過濾的操作
              responseWrapper.getWriter().flush();
              int len=strs.length();                                                  //獲取文件名長度
              String str=strs.substring(0, len-4)+".html";                            //定義靜態頁文件的名稱
              String jspPath=request.getRealPath(str);                                //獲取文件的真實存儲路徑
              File jspFile=new File(jspPath);                                         //創建頁面文件對象
              String static_path=jspFile.getParent()+"\\";                            //定義靜態頁文件存儲的位置
              File htmlFile=new File(static_path, str);                               //創建靜態頁文件對象
              Date htmlDate = null;
              Date now = new Date();
              if (htmlFile.exists()) {
                  htmlDate = new Date(htmlFile.lastModified());
              } else {
                  htmlFile.createNewFile();
              }
              //如果已生成的HTML文件不是當前的,就重新生成一個
              if (variable || htmlDate == null || htmlDate.getDate() ! = now.getDate()) {
                  FileOutputStream fileStream=new FileOutputStream(htmlFile);           //創建HTML文件的輸出流
                  DataOutputStream fout=new DataOutputStream(fileStream);               //創建數據輸出流
                  DateFormat dateFormat=DateFormat.getDateTimeInstance(FULL,FULL);//創建日期格式器
                  fout.writeChars("");                                                  //輸出一個空字符
                  fout.writeUTF("生成時間:"+dateFormat.format(new Date()));              //使用UTF格式輸出注釋信息,標注HTML文檔生成事件
                  fout.writeUTF(responseWrapper.getContent());                          //使用UTF格式輸出HTML內容,保存到HTML文件中
                  fout.close();
              }
              System.out.println("/"+str+"");                             //如果當天已經生成過HTML文件,直接把請求轉發給HTML文件
              request.getRequestDispatcher("/"+str+"").forward(request, response);
            }
            public void destroy() {
            }
            public void log(String msg) {
              filterConfig.getServletContext().log(msg);
          }
        }

秘笈心法

本實例使用的ResponseWrapper對象是自定義Java類文件,用于對請求的數據流進行處理,其中還應用了自定義的OutputStream.java類對父類的輸出方法進行替換。

實例191 文件上傳過濾器

光盤位置:光盤\MR\07\191

初級

實用指數:

實例說明

本實例主要把上傳的文件保存到系統文件夾中,然后通過自定義的request傳入Filter,再使用getAttribute()方法直接獲取上傳的文件,運行效果如圖7.12所示。

圖7.12 上傳結果

關鍵技術

實現本實例時,在上傳文件時需要把<form>標簽的enctype屬性設置為multipart/form-data,然后創建一個繼承自HttpServletRequestWrapper類的自定義請求,在該自定義請求中,轉換由過濾器的doFilter()方法傳遞過來的原始請求,然后在這個自定義的請求中應用Apache的文件上傳組件對原始請求進行解析,判斷是否為上傳文件的請求,如果是文件則保存到服務器的指定目錄,并將解析出的上傳文件對象保存到Map中。

設計過程

(1)創建實現類UploadFilter.java,自定義一個request處理文件上傳,主要代碼如下:

        public class UploadFilter implements Filter {
        public void destroy() {
        }
        public void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain chain) throws IOException, ServletException {
                                                        //自定義上傳的類型
              UploadRw uploadRequest = new UploadRw(
                      (HttpServletRequest) request);
              chain.doFilter(uploadRequest, response);                                  //繼續執行下一個Filter
                }
          Public void init(FilterConfig filterConfig) throws ServletException {
          }
          }

(2)創建UploadRw.java類文件來處理文件讀取以及通過apache工具來解析文件,然后通過map取值輸出到文件中去,主要代碼如下:

        public class UploadRw extends HttpServletRequestWrapper {
        private static final String MULTIPART_HEADER="Content-type";                //文件類型
        private boolean multipart;                                                 //確認上傳文件
                                                                                   //保存提交的數據
        private Map<String, Object> param = new HashMap<String, Object>();
        @SuppressWarnings("all")
        public UploadRw(HttpServletRequest request) {
              super(request);
                                                                                   //判斷是否為上傳文件
              multipart=request.getHeader(MULTIPART_HEADER)! =null
                      &&request.getHeader(MULTIPART_HEADER).startsWith(
                                "multipart/form-data");
              if (multipart){
                  try {
                                                                                   //使用apache自帶的工具解析
                      DiskFileUpload upload = new DiskFileUpload();
                      upload.setHeaderEncoding("utf8");
                                                                                   //獲得所有的文本域與文件域
                      List<FileItem> fileItems = upload.parseRequest(request);
                      for (Iterator<FileItem> it = fileItems.iterator(); it.hasNext(); ) {
                                                                                   //使用遍歷
                            FileItem item = it.next();
                            if (item.isFormField()) {
                                                                                   //如果是文本域直接放到Map中
                                param.put(item.getFieldName(), item.getString("utf8"));
                            } else {
                                                                                   //否則為文件先獲取文件名稱
                                String filename = item.getName().replace("\\", "/");
                                                                                   //替換特殊字符或字符串
                                filename = filename.substring(filename.lastIndexOf("/") + 1);
                                                                                   //保存到系統監時文件夾中
                                File file=new File(System.getProperty("java.io.tmpdir"),filename);
                                                                                   //保存文件內容
                                OutputStream ous = new FileOutputStream(file);
                                ous.write(item.get());
                                ous.close();
                                                                                   //放入map中
                                param.put(item.getFieldName(), file);
                            }
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
        }
        public Object getAttribute(String name) {
                                                                                   //如果是上傳文件就到map中取值
              if (multipart && param.containsKey(name)) {
                  return param.get(name);
              }
              return super.getAttribute(name);
        }

(3)創建upload.jsp頁面,主要代碼如下:

        <div align="center">
                  信息頭是 =${header['Content-type']}
        </div>
              <br />
        <form action=""method="post"enctype="multipart/form-data">
            <table align="center"cellpadding="0"cellspacing="0"background="images/upload.jpg"height="400"width="500">
        <tr height="50"align="center">
                <td width="250">
                      <input type="file"name="file1"border="2"value="瀏覽">
                </td>
        <%
        File file1=(File)request.getAttribute("file1");
            if(file1! =null)
                out.println("<br/>文件:"+file1+", <br/>大小字節 : "+file1.length());
        %>
        </tr>
        <Tr align="center"height="50">
                <td width="250">
                      <input type="submit"value=" 上傳文件">
                </td>
        </Tr>
        <Tr height="200">
                <td>&nbsp; </td>
        </Tr>
            </table>
        </form>

注意:本實例中自定義了request方法,需要添加apache的common-fileuploadin.jar的架包(在本實例Web工程包的webRoot\web-INF\lib目錄下可以找到)。

秘笈心法

本實例為簡單起見,自定義的request并沒有覆蓋getParameterNames等方法,也沒有處理多選框提交相同數據的情況。

實例192 權限驗證過濾器

光盤位置:光盤\MR\07\192

初級

實用指數:

實例說明

本實例實現對session的校驗,如果沒有相對應的處理就拋出一個LoginException異常。本實例添加一個URI與權限role角色檢查,這個配置文件存放在properties配置文件中,運行結果如圖7.13所示。

圖7.13 左為允許訪問(右為無權限訪問)

關鍵技術

本實例主要用到properties配置文件來保存所有的權限,然后應用Properties類來操作properties文件。Properties類表示了一個持久的屬性集。配置文件properties可保存在流中或從流中加載。屬性列表中每個鍵及其對應值都是一個字符串,在設置訪問路徑時用到RequestURI方法獲取路徑,再獲取相應的參數,本實例為action,這兩個組合在一起形成一個新的URI。

設計過程

(1)創建過濾器的實現類PriorityFilter.java,在該類中創建一個Properties對象,使它可以保存在流中或從流中加載,作用是保存所有的權限,并在初始化方法中獲取這個權限文件的位置與配置,在doFilter()中設置訪問的路徑與后綴的參數,并組成一個新的URI,主要代碼如下:

        public class PriorityFilter implements Filter {
        private Properties pts = new Properties();
        public void init(FilterConfig config) throws ServletException {
              //從初始化參數中獲取權限配置文件的位置
              String file = config.getInitParameter("file");
              String realPath = config.getServletContext().getRealPath(file);
              try {
                  pts.load(new FileInputStream(realPath));
              } catch (Exception e) {
                  config.getServletContext().log("讀取權限文件錯誤", e);
              }
        }
        public void doFilter(ServletRequest req, ServletResponse res,
                  FilterChain chain) throws IOException, ServletException {
              HttpServletRequest request = (HttpServletRequest) req;
              //獲取訪問的路徑
              String requestURI = request.getRequestURI().replace(request.getContextPath() + "/", "");
              //獲取action的參數
              String action = req.getParameter("action");
              action = action == null ? "" : action;
              //組合成新的URI
              String uri = requestURI + "? action=" + action;
              //在session中獲取用戶權限
              String role = (String) request.getSession(true).getAttribute("role");
              role = role == null ? "guest" : role;
              boolean authentificated = false;
              //審核用戶是否有權限登錄訪問
              for (Object obj : pts.keySet()) {
                  String key = ((String) obj);
                  //使用正則表達式驗證,需要將 ? 替換,并通過通配符 * 處理
                  if (uri.matches(key.replace("? ", "\\? ").replace(".", "\\.").replace("*", ".*"))) {
                      //如果role角色匹配
                      if (role.equals(pts.get(key))) {
                            authentificated = true;
                            break;
                      }
                  }
              }
              if (! authentificated) {
                  throw new RuntimeException(new LoginException("您無權訪問該頁面。請以合適的身份登錄后查看。"));
              }
              //下一個過濾器或者Servlet
              chain.doFilter(req, res);
        }
        public void destroy() {
              pts = null;
        }
        }

(2)創建priority.properties配置文件,如果只有key-value屬性值,其中key鍵為訪問的地址,value為控制訪問的權限名稱,主要代碼如下:

        # Privilege Settings
        admin.do? action\=*=administrators
        login.do? action\=*=administrators
        method.do? action\=add=system
        method.do? action\=delete= system
        method.do? action\=save = system
        method.do? action\=view = guest
        method.do? action\=list = guest

(3)配置web.xml文件,其中捕捉異常要用到上個異常過濾器的范例,這樣拿過來直接調用即可,主要代碼如下:

        <display-name>filter</display-name>
        <servlet>
            <servlet-name>dispatcherServlet</servlet-name>
            <jsp-file>/output.jsp</jsp-file>
        </servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServlet</servlet-name>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
            <filter>
            <filter-name>exceptionFilter</filter-name>
            <filter-class>
                  com.mr.filter.ExceptionFilter
            </filter-class>
        </filter>
        <filter>
            <filter-name>priorityFilter</filter-name>
            <filter-class>
                  com.mr.filter.PriorityFilter
            </filter-class>
            <init-param>
                  <param-name>file</param-name>
                  <param-value>/WEB-INF/priority.properties</param-value>
            </init-param>
        </filter>
            <filter-mapping>
            <filter-name>exceptionFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter-mapping>
        <filter-name>priorityFilter</filter-name>
            <url-pattern>*.do</url-pattern>
        </filter-mapping>

秘笈心法

正則表達式是一個描述字符模式的對象,在Web開發中正則表達式應用相當廣泛,使用正則表達式可以檢查一個字符串中是否含有指定的子字符串、替換匹配的子字符串為指定的內容或者從某個字符串中取出符合條件的子字符串等。

主站蜘蛛池模板: 崇义县| 张掖市| 鄯善县| 甘泉县| 阳泉市| 宁武县| 锡林郭勒盟| 铅山县| 平昌县| 阿坝县| 临湘市| 台湾省| 深水埗区| 银川市| 白水县| 马龙县| 始兴县| 揭西县| 闽清县| 始兴县| 江西省| 无锡市| 朔州市| 叶城县| 读书| 淳化县| 浠水县| 泗洪县| 遵义县| 汝南县| 迁西县| 资源县| 桦甸市| 行唐县| 获嘉县| 西乌| 安义县| 铜梁县| 府谷县| 灵山县| 堆龙德庆县|