zoukankan      html  css  js  c++  java
  • 过滤器

    一、过滤器简介
    a)Filter是SUN公司提供的一个资源过滤器接口,不同的Web容器有着不同的实现
    b)Filter位于Web服务器和Web资源(Servlet/Jsp/Html)之间
    c)过滤器过滤请求和响应二者
    d)Filter可以进行简单判段,是否将请求放行给Web资源
    e)Filter的开发过程:
    1>>类 implements javax.servlet.Filter接口
    2>>在web.xml文件配置Filter过滤器,告之Web服务器有过滤器的存在
    web.xml中的配置信息如下:

    <filter>
    <filter-name>FilterDemo1</filter-name>(过滤器,可以随意,但要和filter-mapping中的name一致)
    <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>(过滤器全路径)
    </filter>
    <filter-mapping>
    <filter-name>FilterDemo1</filter-name>(过滤器名,同上)
    <url-pattern>/*</url-pattern>(过滤器能够过滤的资源路径,不是用户在URL中访问的路径) \*/
    </filter-mapping>
    

      



    注意:
    1)当访问一个web资源时,没有得到对应的结果,有可能是Filter没有放行资源
    2)总结:写Filter一定要知道该Filter过滤哪个或哪些资源,不是所有的Filter都过滤/*的资源。 \*/

    3 过滤器链
    a)一个Web应用可以有0个或多个Filter,多个Filter的组合就是过滤器链
    b)**多个Filter的执行先后顺序,与web.xml文件中配置的顺序有关
    c)chain.doFilter(request,response)具有二义性:
    >>如果有下一个Filter时,将请求转发给下一个Filter
    >>如果无下一个Filter时,将请求转发给Web资源(serlvet/jsp/html)
    d)可以将web资源中的一些公共代码,提取出来,放入Filter中

    4 过滤器生命周期(Filter是一个单例)
    空参构造() 1次
    ||
    init() 1次
    ||
    doFilter(请求,响应,过滤器链) N次,与请求次数有关
    ||
    destory() 1次

    *5 Filter的案例
    a)简单的登录页面:设置请求和响应的编码方式
    init()可以获取到初始化的配置信息,因此将POST请求方式的中文的编码进行设置,
    防止提交中文和响应中文时的乱码问题。

     1 web.xml:
     2 <filter>
     3 <filter-name>FilterDemo1</filter-name>
     4 <filter-class>com.suse.servlet.FilterDemo1</filter-class>
     5 <init-param>
     6 <param-name>charset</param-name>
     7 <param-value>utf-8</param-value>
     8 </init-param>
     9 </filter>
    10 <filter-mapping>
    11 <filter-name>FilterDemo1</filter-name>
    12 <url-pattern>/*</url-pattern> //////*/
    13 </filter-mapping>
    14 
    15 fileterCode:
    16 private FilterConfig filterConfig;
    17 @Override
    18 public void init(FilterConfig filterConfig) throws ServletException {
    19 this.filterConfig = filterConfig;//设置filterConfig值
    20 }
    21 
    22 @Override
    23 public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    24 String charSet = this.filterConfig.getInitParameter("charset");//得到配置文件的编码方式
    25 request.setCharacterEncoding(charSet);//设置请求时编码
    26 response.setContentType("text/html;charset="+charSet);//设置响应时编码
    27 filterChain.doFilter(request, response);//放行
    28 }

    b)静态资源和动态资源进行不同的缓存处理,代码如下:

     1 if(uri!=null && uri.endsWith("jsp")){
     2 //NO3如果是动态资源,设置三个响应头通知浏览器不缓存
     3 response.setDateHeader("Expires", -1);//IE
     4 response.setHeader("Cache-Control", "no-cache");
     5 response.setHeader("Pragma", "no-cache");
     6 }else if(uri!=null && uri.endsWith("html")){
     7 //NO4如果是静态资源,缓存一定的时间
     8 String strHtml = filterConfig.getInitParameter("html");
     9 long time = System.currentTimeMillis()+Integer.parseInt(strHtml)*1000;
    10 //time为毫秒值
    11 response.setDateHeader("expires",time); //第二个参数为保存到的时间,单位为毫秒
    12 response.setHeader("cache-control",time/1000+"");//第二个参数为保存到的时间,单位为秒
    13 response.setHeader("pragma",time/1000+"");//第二个参数为保存到的时间,单位为秒
    14 }

    c)通过Filter实现URL级别的权限认证 ———— 对敏感目录进行认证
    //访问admin目录下的admin.html文件需要带上用户名和密码进行验证

    d)通过Filter和cookie实现自动登录功能

     1 xml配置:
     2 <filter>
     3 <filter-name>AutoLoginFilter</filter-name>
     4 <filter-class>com.suse.filter.AutoLoginFilter</filter-class>
     5 </filter>
     6 <filter-mapping>
     7 <filter-name>AutoLoginFilter</filter-name>
     8 <url-pattern>/welcome.jsp</url-pattern>
     9 </filter-mapping>
    10 第一次登录,设置cookie:
    11 String username = request.getParameter("username");
    12 String password = request.getParameter("password");
    13 if (username != null && password != null && username.equals("jack") && password.equals("123")) {
    14 Cookie cookie = new Cookie("usernameApassword", username + "_" + password);
    15 cookie.setMaxAge(10 * 60);
    16 response.addCookie(cookie);
    17 request.setAttribute("username", username);
    18 request.getRequestDispatcher("/welcome.jsp").forward(request, response);
    19 } else {
    20 response.getWriter().write("登录失败!");
    21 }
    22 第二次登录,解析cookie:
    23 @Override
    24 public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
    25 HttpServletRequest request = (HttpServletRequest) req;
    26 HttpServletResponse response = (HttpServletResponse) res;
    27 String username = null;
    28 String password = null;
    29 Cookie[] cookies = request.getCookies();
    30 for (Cookie cookie : cookies) {
    31 if (cookie.getName().equalsIgnoreCase("usernameApassword")) {
    32 String str = cookie.getValue();
    33 String[] usernameApassword = str.split("_");
    34 username = usernameApassword[0];
    35 password = usernameApassword[1];
    36 }
    37 }
    38 if (username != null && password != null && username.equals("jack") && password.equals("123")) {
    39 request.setAttribute("username", username);
    40 filterChain.doFilter(request, response);
    41 } else {
    42 request.getRequestDispatcher("/login.jsp").forward(request, response);
    43 }
    44 }

    二、映射Filter的细节

    a)在默认情况下,Filter只过滤Request的请求,即:web资源之间的转包和包含不过滤.
      MappingFilter::doFilter():A
      FromServlet::doGet()
      ToServlet::doGet()
      MappingFilter::doFilter():B

    b)当需要过滤forward请求的资源时,可以设置dispatcher为FORWARD过滤方式
    (注意:默认的REQUEST方式便不存在了)

      FromServlet::doGet()
      MappingFilter::doFilter():A
      ToServlet::doGet()
      MappingFilter::doFilter():B

    在web.xml文件中配置代码如下:

    <filter-nameapping>
    <filter-name>MappingFilter</filter-name>
    <url-pattern>/ToServlet</url-pattern> 
    <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

    c)即过滤REQUEST又过滤FORWARD时:

    <filter-nameapping>
    <filter-name>MappingFilter</filter-name>
    <url-pattern>/ToServlet</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

    d)当需要过滤include请求的资源时,可以设置dispatcher为INCLUDE过滤方式
    e)当需要过滤error请求的资源时,可以设置dispatcher为ERROR过滤方式
    注意:此时,一定在要web.xml文件声明错误代码或类型

    <error-page>
    <error-code>500</error-code>
    <location>/sys_500.jsp</location>
    </error-page>    
    
    <filter-mapping>
    <filter-name>MappingFilter</filter-name>
    <url-pattern>/*</url-pattern> */
    <dispatcher>ERROR</dispatcher>
    </filter-mapping>


    f)对于过滤Servlet资源时,即可使用url-pattern,又可以使用servlet-name
    g)一个Filter可以过滤1个或N个资源,
    即:一个<filter>,多个<filter-mapping>


    *2 装饰设计模式
    a)当某个类的某个方法不适应当前业务的需要
    思路:
    1》扩展父类的可供扩展的方法,可以使有,但不优
    2》装饰设计模式(推荐)

    开发步骤:
      1)写一个普通类(非web应用)或写一个普通类扩展[extends]一个父类(web应用)
      2)写一个需要被包装的实例变量
      3)通过构造方式为被包装的实例变量赋值
      4)对于不满足需求的方法,重写父类的相关方法
    [可选]5)对于满足需求的方法,直接调用被包装的对象

    code:

    1,带有行号的BufferedReader的ReadLine方法的类:MyBufferedReader

     1 public class MyBufferedReader {
     2 
     3 private BufferedReader bufferedReader;
     4 
     5 private Integer lineNum;
     6 
     7 public MyBufferedReader(BufferedReader bufferedReader) {
     8 this.lineNum = 1;
     9 this.bufferedReader = bufferedReader;
    10 }
    11 
    12 
    13 //包装readLine()方法
    14 public String readLine() throws IOException {
    15 String read = null;
    16 String line = null;
    17 if ((line = bufferedReader.readLine()) != null) {
    18 read = this.lineNum + ":" + line;
    19 lineNum++;
    20 }
    21 return read;
    22 }
    23 
    24 //关闭文件流,使用父类的方法来关闭流
    25 public void close() throws IOException {
    26 bufferedReader.close();
    27 } 
    28 }

    2,增强Date类的toLocalString()方法,显示类似信息 "XXXX年XX月XX日 星期X XX:XX:XX"

     1 public class MyDate {
     2 
     3 private Date date;
     4 
     5 public MyDate(Date date) {
     6 this.date = date;
     7 }
     8 
     9 public String toLocalString() {
    10 /*SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 EEEE HH:mm:ss ");
    11 return dateFormat.format(date);*/
    12 DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM, Locale.CHINA);
    13 return dateFormat.format(date); 
    14 }
    15 }


    *3 Filter案例

    a)对request进行装饰,完全解决get、post请求方式下的乱码问题

     1 //MyRequest.java
     2 public class MyRequest extends HttpServletRequestWrapper {
     3 
     4 private HttpServletRequest request;
     5 
     6 public MyRequest(HttpServletRequest request) {
     7 super(request);
     8 this.request = request;
     9 }
    10 
    11 @Override
    12 public String getParameter(String name) {
    13 String value = null;
    14 //获取请求方式[GET/POST]
    15 String method = request.getMethod();
    16 if("GET".equals(method)) {
    17 try {
    18 value = request.getParameter(name);
    19 byte[] buf = value.getBytes("ISO8859-1");
    20 value = new String(buf, "utf-8");
    21 } catch (UnsupportedEncodingException e) {
    22 e.printStackTrace();
    23 }
    24 } else {
    25 try {
    26 request.setCharacterEncoding("utf-8");
    27 value = request.getParameter(name);
    28 } catch (UnsupportedEncodingException e) {
    29 e.printStackTrace();
    30 }
    31 }
    32 return value;
    33 }
    34 
    35 //EncodingFilter
    36 public class EncodingFilter implements Filter {
    37 @Override
    38 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    39 HttpServletRequest request = (HttpServletRequest) req;
    40 HttpServletResponse response = (HttpServletResponse) res;
    41 chain.doFilter(new MyRequest(request), response);
    42 }
    43 }

    b)对request进行装饰,实现html标签的转义功能
    //转义html符号

     1 private String filter(String message) {
     2 if (message == null)
     3 return (null);
     4 char content[] = new char[message.length()];
     5 message.getChars(0, message.length(), content, 0);
     6 StringBuffer result = new StringBuffer(content.length + 50);
     7 for (int i = 0; i < content.length; i++) {
     8 switch (content[i]) {
     9 case '<':
    10 result.append("&lt;");
    11 break;
    12 case '>':
    13 result.append("&gt;");
    14 break;
    15 case '&':
    16 result.append("&amp;");
    17 break;
    18 case '"':
    19 result.append("&quot;");
    20 break;
    21 default:
    22 result.append(content[i]);
    23 }
    24 }
    25 return (result.toString());
    26 }


    c)对response进行装饰[有一定难度]————压缩响应
    思路: 缓存 --> 压缩 --> 输出

     1 //MyResponse
     2 public class MyResponse extends HttpServletResponseWrapper {
     3 
     4 private HttpServletResponse response;
     5 private ByteArrayOutputStream bout = new ByteArrayOutputStream();
     6 
     7 public MyResponse(HttpServletResponse response) {
     8 super(response);
     9 this.response = response;
    10 }
    11 
    12 public ServletOutputStream getOutputStream() throws IOException {
    13 return new MyServletOutputStream(bout);
    14 }
    15 
    16 public byte[] getBuffer() {
    17 return bout.toByteArray();
    18 }
    19 
    20 }
    21 
    22 class MyServletOutputStream extends ServletOutputStream {
    23 
    24 private ByteArrayOutputStream bout;
    25 
    26 public MyServletOutputStream(ByteArrayOutputStream bout) {
    27 this.bout = bout;
    28 }
    29 
    30 @Override
    31 public void write(int arg0) throws IOException {
    32 }
    33 
    34 public void write(byte[] bytes) throws IOException {
    35 bout.write(bytes);
    36 bout.flush();
    37 }
    38 
    39 }
    40 
    41 
    42 //Filter
    43 public class GzipFilter implements Filter {
    44 @Override
    45 public void destroy() {
    46 
    47 }
    48 @Override
    49 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    50 HttpServletRequest request = (HttpServletRequest) req;
    51 HttpServletResponse response = (HttpServletResponse) res;
    52 MyResponse myResponse = new MyResponse(response);
    53 
    54 chain.doFilter(request, myResponse);
    55 
    56 byte[] data = myResponse.getBuffer();
    57 System.out.println("压缩前:" + data.length);
    58 
    59 ByteArrayOutputStream bout = new ByteArrayOutputStream();
    60 GZIPOutputStream gout = new GZIPOutputStream(bout);
    61 gout.write(data);
    62 gout.flush();
    63 gout.close();
    64 
    65 data = bout.toByteArray();
    66 System.out.println("压缩后" + data.length);
    67 
    68 response.setHeader("content-encoding", "gzip");
    69 response.setHeader("content-length", data.length + "");
    70 
    71 response.getOutputStream().write(data);
    72 
    73 }
    74 
    75 @Override
    76 public void init(FilterConfig arg0) throws ServletException {
    77 // TODO Auto-generated method stub
    78 }
    79 }

    c)简单Filter缓存

    //单例,一个服务器只有一个ChcheFilter
    public class CacheFilter implements Filter {
    
    //示例变量【每个线程都共享】
    private Map<String, byte[]> cache = new HashMap<String, byte[]>();
    
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    
    //获取到访问路径,判断是否已经缓存
    String uri = request.getRequestURI();
    byte[] data = cache.get(uri);
    //若没有缓存,从数据库拉取数据
    if (null == data) {
    System.out.println("没有缓存,从数据库拉取数据!");
    MyResponse myResponse = new MyResponse(response);
    //放行到servlet,从数据库拉取数据
    chain.doFilter(request, myResponse);
    //获取数据,并缓存到Map中
    data = myResponse.getBuffer();
    cache.put(uri, data);
    }
    
    //将数据回写给浏览器
    response.getOutputStream().write(data);
    }


    4 总结Filter和Servlet

    a)Filter通常完成一些非核心的业务流程控制
    Servlet通常完成一些核心的业务流程控制

    b)Filter通常完成一些对Servlet的请求和响应的预先处理控制。
    Servlet却不行

    c)Filter和Servlet是一个互补的技术,而不是替代技术

     


  • 相关阅读:
    Easy-Transfer学习
    录音+语音转文字
    pyQt点击事件和数据传输
    第一个python-ui界面
    python写第一个网页
    pyhthon第一个小脚本——文件备份
    Stones HDU 1896
    Cow Sorting POJ 3270 & HDU 2838
    Stones
    大数相加
  • 原文地址:https://www.cnblogs.com/SkyGood/p/4215873.html
Copyright © 2011-2022 走看看