美文网首页
Servlet学习6--过滤器

Servlet学习6--过滤器

作者: 张氏小毛驴 | 来源:发表于2022-04-13 17:26 被阅读0次

    一.过滤器Filter

    1. Filter介绍

      Servlet有三大组件:Servlet,Filter,Listener.

      Filter中文意思为过滤,在Web中,过滤器可以在请求到达目标资源之前先对请求进行拦截,也就是可以先对请求进行一些处理,之后再放行去访问目标资源;也可以在响应返回到客户端之前对响应进行拦截,也就是可以对响应做一些处理,再返回给客户端。

    1. 过滤器作用

      通过Filter,能够对web服务器管理的所有web资源,比如jsp,servlet,静态图片,静态html等文件进行拦截过滤,从而实现一些特殊的功能。比如登录验证,统一编码处理,敏感词汇过滤等。

    2. Filter接口

      在Servlet中,提供了一个接口javax.servlet.Filter,只要实现该接口的类,就可以称为过滤器。

      Filter接口有三个方法需要重写:

      • init():初始化方法,在服务器启动后会创建Filter对象,然后调用init方法,只会执行一次,用于加载资源。
      • doFilter():核心方法,对于请求和响应的过滤,都是在该方法中完成,每一次请求被拦截的资源时会执行。
      • destroy():销毁方法,在服务器关闭后,Filter对象被销毁,会执行该方法,只执行一次,一般用于释放资源。
    3. 创建Filter过滤器

      • 创建一个类实现javax.servlet.Filter接口
      • 重写接口中的方法
      • 配置Filter(web.xml或者注解)
      import javax.servlet.*;
      import java.io.IOException;
      
      public class FilterDemo1 implements Filter {
      
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              System.out.println("Filter 初始化");
          }
      
          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              System.out.println("Filter 调用");
              filterChain.doFilter(servletRequest, servletResponse);
          }
      
          @Override
          public void destroy() {
              System.out.println("Filter 销毁");
          }
      }
      
      

      注意:在Filter的doFilter方法内部如果没有调用doFilter(request,response)方法,那么服务器中的资源是不会被访问到的。doFilter(request,response)就是一个放行

    4. Filter细节

      1. web.xml配置

        • 注册Filter

          <filter>
              <filter-name>Demo1</filter-name>
              <filter-class>com.zzy.www.filter.FilterDemo1</filter-class>
              <init-param>
                  <param-name>path</param-name>
                  <param-value>/WEB_INF/a.txt</param-value>
              </init-param>
          </filter>
          

          <filter-name>:设置过滤器的名字,内容不能为空

          <filter-class>:指定过滤器的完整的类名

          <init-param>:用于为过滤器指定初始化参数,<param-name>指定参数的名称,<param-value>指定参数的值。(在过滤器中可以使用FilterConfig接口对象来访问初始化参数)(多个参数就有多个<init-param>)

        • 映射Filter

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

          <filter-name>:用于设置Filter的注册名称,这个值必须是在注册Filter时<filter>中声明过的过滤器名字。

          <url-pattern>:设置Filter要拦截的请求路径。Filter的全路径匹配只支持/*,不支持/

          <filter-mapping>还有两个标签<servlet-name><dispatcher>

          <servlet-name>:指定过滤器要拦截的Servlet名称

          <dispatcher>:指定过滤器拦截的资源被Servlet调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认是REQUEST。

          • REQUEST:默认值,只要不是由RequestDispatch的forward()或include()方法转发的,都会被该Filter拦截。
          • FORWARD:当前Filter只会拦截由RequestDispatcher的forward()方法所转发的请求,其他的请求不会拦截。
          • INCLUDE:只要是通过<jsp:include page="xxx.jsp"/>嵌入进来的页面,每一个嵌入的页面,都会走一次值为INCLUDE的过滤器。
          • ERROR:当前Filter只会拦截转向错误页面的请求,其他请求不会拦截。
          • ASYNC:会拦截AsyncContext对象发出的请求。

          如果是注解的方式配置,则是设置dispatcherTypes属性

      2. 过滤器执行流程

        • 执行过滤器
        • 执行放行后的资源
        • 返回执行过滤器放行代码下边的代码
      3. 过滤器生命周期

        • 当服务器启动时,会创建Filter对象,并调用init()方法,只会调用一次。
        • 当访问资源时,路径与Filter的拦截路径匹配时,会执行Filter中的doFilter()方法,该方法是真正实现拦截操作的方法。
        • 当服务器关闭时,会调用Filter的destroy()方法进行销毁,只会调用一次。
      4. 过滤器链(多个过滤器)

        如果在web中设置了多个过滤器,那么这些过滤器执行过程是以一种链的形式执行的。

        也就是每一个Filter串一起形成一条链,按照链的顺序依次执行,一个Filter执行完filterChain的doFilter()方法后,转而执行另一个Filter,直到最后一个Filter,最后一个Filter的filterChain.doFilter()会自动跳转到最终的请求资源。

        在请求到达Filter之后,Filter可以拦截请求对象,并能对请求进行修改,修改过后再转向下一个Filter或资源。

        当最终的资源执行完毕,形成了响应对象后,会按照Filter链的顺序逆序再次访问Filter,此时的Filter能够拦截到响应对象,并能对响应进行修改,最后客户端接收到的是被FIlter修改过的响应。

        Filter3.png
    5. Filter的特点

      • Filter是单例多线程的
      • FIlter是在web应用被加载时创建并初始化的,这点与Servlet不同(Servlet是在servlet第一次被访问时创建)
      • 客户端每提交一次该Filter可以过滤的请求,服务器就会执行一次doFilter()方法,doFilter()方法是可以被多次执行的
      • 由于Filter是单例多线程的,所以一般为了保证线程安全,是不会在FIlter类定义可以修改的成员变量的,因为会出现线程安全问题。

    二.Filter例子

    1. Filter解决乱码问题

      之前编写servlet时候,在处理POST请求乱码时,需要在获取请求参数前设置request的编码request.setCharacterEncoding("utf-8");

      在响应时候,也需要处理乱码问题,之前是使用response.setContentType("text/html;charset=utf-8");

      这种处理方式很繁琐,需要在每一个servlet中都声明这些编码,可以通过使用过滤器,提取这些公有代码到过滤器中。

      @WebServlet("/LoginServlet")
      public class LoginServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              String username = request.getParameter("username");
              System.out.println("username: " + username);
      
              response.getWriter().println("用户名为:" + username);
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>登录</title>
      </head>
      <body>
      <form action="/BookTest/LoginServlet" method="post">
          <label for="username">姓名:</label><input type="text" id="username" placeholder="请输入姓名" name="username"> <br>
          <input type="submit" value="登录">
      </form>
      </body>
      </html>
      
      @WebFilter(filterName = "FilterTest1", urlPatterns = "/*")
      public class FilterTest1 implements Filter {
          public void destroy() {
          }
      
          public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
              HttpServletRequest request = (HttpServletRequest)req;
              HttpServletResponse response = (HttpServletResponse)resp;
      
              request.setCharacterEncoding("utf-8");
              response.setContentType("text/html;charset=utf-8");
      
              chain.doFilter(req, resp);
          }
      
          public void init(FilterConfig config) throws ServletException {
      
          }
      
      }
      
      
    2. 登陆验证

      针对用户访问网站,当用户未登录时只能访问首页,登陆页面,其他页面是没有权限访问的,必须登陆才能访问,此时过滤器可以做一个权限管控,如果用户已登录,就放行;否则则跳转到登录页面。

      比如用户访问news.jsp页面.未登录前先访问news.jsp是会自动跳转到登录页面的,只有登录后访问才能直接访问news.jsp

      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>news</title>
      </head>
      <body>
          <h1>Welcome!</h1>
      </body>
      </html>
      
      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>登录</title>
      </head>
      <body>
      <form action="/BookTest/LoginServlet" method="post">
          <label for="username">姓名:</label><input type="text" id="username" placeholder="请输入姓名" name="username"> <br>
          <label for="password">密码:</label><input type="password" id="password" placeholder="请输入密码" name="password"><br>
          <input type="submit" value="登录">
      </form>
      </body>
      </html>
      
      @WebServlet("/LoginServlet")
      public class LoginServlet extends HttpServlet {
          protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              String username = request.getParameter("username");
              System.out.println("username: " + username);
      
              if (username != null) {
                  HttpSession s = request.getSession();
      
                  if (s.getAttribute("username") == null) {
                      s.setAttribute("username", username);
                  }
              }
      
              response.sendRedirect("/BookTest/news.jsp");
          }
      
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doPost(request, response);
          }
      }
      
      @WebFilter(filterName = "FilterTest2",urlPatterns = "/*")
      public class FilterTest2 implements Filter {
          public void destroy() {
          }
      
          public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
              HttpServletRequest request = (HttpServletRequest)req;
              HttpServletResponse response = (HttpServletResponse)resp;
      
              // 获取访问地址
              String path = request.getServletPath();
              System.out.println(path);
              if (path.startsWith("/news.jsp")) {
                  HttpSession s = request.getSession();
                  System.out.println(s);
                  // 说明还没登录
                  if (s == null) {
                      // 跳转到登录界面
                      response.sendRedirect("/BookTest/login.html");
                  } else {
                      String name = (String)s.getAttribute("username");
                      System.out.println("name = " + name);
                      if (name == null) {
                          response.sendRedirect("/BookTest/login.html");
                      }
                  }
              }
              chain.doFilter(req, resp);
          }
      
          public void init(FilterConfig config) throws ServletException {
      
          }
      
      }
      

    相关文章

      网友评论

          本文标题:Servlet学习6--过滤器

          本文链接:https://www.haomeiwen.com/subject/mnqsjrtx.html