Filter&Listener11_Filter1

Filter:过滤器

1. 概念

  * 生活中的过滤器:净水器,空气净化器,土匪

  * web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。

  * 过滤器的作用:一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...

2. 快速入门

  a. 步骤:

    1. 定义一个类,实现接口Filter

    2. 复写方法

    3. 配置拦截路径

      1. web.xml

      2. 注解

  更改Filter模板:File-Settings-Editor-File and Code Templates-Other-Web-Java code templates-Filer Annotated Class.java,在这儿更改一下Filter类的脚本,新建的时候就能一键填充部分内容。

  b. 代码:

    注解配置拦截路径

  @WebFilter("/*") //访问所有资源之前都会执行该过滤器

  @WebFilter("/demo.jsp") //访问demo.jsp之前会执行该过滤器

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 过滤器快速入门程序
 */
@WebFilter("/*")//访问所有资源之前都会执行该过滤器
public class FilterDemo1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo1被执行了...");

        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

  index.jsp

<%--
  Created by IntelliJ IDEA.
  User: ajing
  Date: 2022/2/28
  Time: 21:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    index.jsp...
  </body>
</html>

  如果不写filterChain.doFilter(servletRequest,servletResponse);那么浏览器访问http://localhost/day11/index.jsp,idea控制台输出:filterDemo1被执行了...,但是浏览器未输出index.jsp...,因为被拦截了;

  写了filterChain.doFilter(servletRequest,servletResponse);那么浏览器访问http://localhost/day11/index.jsp时,idea控制台会输出:filterDemo1被执行了...,同时浏览器会输出index.jsp...

3. web.xml配置拦截路径

 web包中新建路径WEB-INF,WEB-INF下新建web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    
    <filter>
        <filter-name>demo2</filter-name>
        <filter-class>cn.itcast.web.filter.FilterDemo2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>demo2</filter-name>
        <url-pattern>/*</url-pattern> <!-- 拦截路径 -->
    </filter-mapping>
    
</web-app>
package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 过滤器快速入门程序
 */
public class FilterDemo2 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("filterDemo2被执行了...");

        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

  浏览器访问http://localhost/day11/index.jsp,检查idea控制台输出:filterDemo2被执行了...,同时浏览器展示:index.jsp。

4. 过滤器执行流程

  a. 执行过滤器

  b. 执行放行后的资源

  c. 回来执行过滤器放行代码下边的代码

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo3 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

        //对request对象请求消息增强
        System.out.println("filterDemo3执行了...");
        //放行
        chain.doFilter(req, resp);
        //对response对象的响应消息增强
        System.out.println("filterDemo3回来了...");
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  index.jsp

<%--
  Created by IntelliJ IDEA.
  User: ajing
  Date: 2022/2/28
  Time: 21:16
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
    index.jsp...
  <%
    System.out.println("index.jsp......");
  %>
  </body>
</html>

   浏览器访问http://localhost/day11/index.jsp,检查浏览器输出:index.jsp...,同时idea控制台输出结果:

   

    可以看出来执行顺序,先执行打印filterDemo3执行了...,然后执行放行,去执行index.jsp,输出到浏览器及idea控制台,执行完后执行放行下方的代码,打印:filterDemo3回来了...

5. 过滤器生命周期方法

 a. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源

 b. doFilter:每一次请求被拦截资源时,会执行。执行多次

 c. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

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

    /**
     * 每一次请求被拦截资源时,会执行。执行多次
     * @param req
     * @param resp
     * @param chain
     * @throws ServletException
     * @throws IOException
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("doFilter...");
        chain.doFilter(req, resp);
    }

    /**
     * 在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
     * @param config
     * @throws ServletException
     */
    public void init(FilterConfig config) throws ServletException {
        System.out.println("init...");
    }

    /**
     * 在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
     */
    public void destroy() {
        System.out.println("destroy...");
    }

}

  tomcat启动成功后,检查idea控制台输出:init...。

  浏览器访问http://localhost/day11/index.jsp,检查输出doFilter...,再请求一次http://localhost/day11/index.jsp,继续输出doFilter...。

  tomcat关闭服务后,检查idea控制台输出:destroy...

6. 过滤器配置详解

  a. 拦截路径配置:

    1. 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行。访问其他资源不会执行过滤器

    2. 拦截目录: /user/* 访问/user下的所有资源时,过滤器都会被执行

    3. 后缀名拦截: *.jsp 访问所有后缀名为jsp资源时,过滤器都会被执行

    4. 拦截所有资源:/* 访问所有资源时,过滤器都会被执行

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/index.jsp")
public class FilterDemo5 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo5...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器访问http://localhost/day11/index.jsp,idea控制台会输出:filterDemo5...,访问http://localhost/day11/hello.jsp,过滤器不会被执行,idea控制台不会输出内容。

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/user/*")
public class FilterDemo5 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo5...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
package cn.itcast.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/user/findAllServlet")
public class ServletDemo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("findAllServlet...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}
package cn.itcast.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/user/updateServlet")
public class ServletDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("updateServlet...");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

  浏览器访问http://localhost/day11/user/findAllServlet,检查idea控制台输出:filterDemo5...及findAllServlet...。浏览器访问http://localhost/day11/user/updateServlet,检查idea控制台输出filterDemo5...及updateServlet...。访问http://localhost/day11/index.jsp,检查idea控制台不会输出:filterDemo5...

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("*.jsp")
public class FilterDemo5 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo5...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器访问http://localhost/day11/index.jsp,idea控制台会输出:filterDemo5...。访问http://localhost/day11/user/findAllServlet,过滤器不会被执行,idea控制台不会输出内容。

  b. 拦截方式配置:资源被访问的方式

    注解配置:

      * 设置dispatcherTypes属性(数组)

        1. REQUEST:默认值。浏览器直接请求资源
        2. FORWARD:转发访问资源
        3. INCLUDE:包含访问资源
        4. ERROR:错误跳转资源
        5. ASYNC:异步访问资源

    web.xml配置

      设置<dispatcher></dispatcher>标签即可

      取值同上面5个,如:<dispatcher>REQUEST</dispatcher>

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

//浏览器直接请求资源时,该过滤器会被执行
@WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.REQUEST)
public class FilterDemo6 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo6...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}
package cn.itcast.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/user/updateServlet")
public class ServletDemo2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("updateServlet...");

        //转发到index.jsp
        request.getRequestDispatcher("/index.jsp").forward(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

  浏览器直接访问http://localhost/day11/index.jsp,idea控制台会输出:filterDemo6...。

  浏览器访问http://localhost/day11/user/updateServlet,idea控制台不会输出内容。

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


//只有转发访问index.jsp时,该过滤器才会被执行
@WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.FORWARD)
public class FilterDemo6 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo6...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器访问http://localhost/day11/user/updateServlet,idea控制台会输出:filterDemo6...。

  浏览器访问http://localhost/day11/index.jsp,idea控制台不会输出内容。

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


//浏览器直接请求index.jsp或者转发访问index.jsp时,该过滤器都会被执行
@WebFilter(value = "/index.jsp",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})

public class FilterDemo6 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo6...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器直接访问http://localhost/day11/index.jsp,idea控制台会输出:filterDemo6...。

  浏览器访问http://localhost/day11/user/updateServlet,idea控制台会输出:filterDemo6...。

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


@WebFilter(value = "/*",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
public class FilterDemo6 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo6...");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器直接访问http://localhost/day11/index.jsp,idea控制台会输出:filterDemo6...。

   浏览器访问http://localhost/day11/user/updateServlet,idea控制台输出结果:

   

6. 过滤器链(配置多个过滤器)

  a. 执行顺序:如果有两个过滤器:过滤器1和过滤器2

    1. 过滤器1

    2. 过滤器2

    3. 资源执行

    4. 过滤器2

    5. 过滤器1

  b. 过滤器先后顺序问题:

    1. 注解配置:按照类名的字符串比较规则比较,值小的先执行

      * 如: AFilter 和 BFilter,AFilter就先执行了。

    2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行

package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo7 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo7执行了。。。");
        chain.doFilter(req, resp);
        System.out.println("filterDemo7回来了。。。");

    }

    public void init(FilterConfig config) throws ServletException {

    }

}
package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class FilterDemo8 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("filterDemo8执行了。。。");

        chain.doFilter(req, resp);

        System.out.println("filterDemo8回来了。。。");

    }

    public void init(FilterConfig config) throws ServletException {

    }

}

  浏览器访问http://localhost/day11/index.jsp,检查idea控制台输出结果(7比8小所以FilterDemo7先执行):

  

7. 案例:登录验证

  需求:

    1. 访问day10_case案例的资源。验证其是否登录

    2. 如果登录了,则直接放行。

    3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。

   分析:

    

   代码:

    login.jsp

<%--
  Created by IntelliJ IDEA.
  User: ajing
  Date: 2022/2/26
  Time: 20:42
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>login</title>
    <script>
        window.onload = function(){
            document.getElementById("img").onclick = function () {
                this.src="/day10/checkCodeServlet?time="+ new Date().getTime();
            }
        }
    </script>

    <style>
        div{
            color: red;
        }
    </style>
</head>
<body>

    <form action="/day10/loginServlet" method="post">
        <table>
            <tr>
                <td>用户名</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="text" name="password"></td>
            </tr>
            <tr>
                <td>验证码</td>
                <td><input type="text" name="checkCode"></td>
            </tr>
            <tr>
                <td colspan="2"><img id="img" src="/day10/checkCodeServlet"></td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="登录"></td>
            </tr>
        </table>
    </form>

    <div><%=request.getAttribute("cc_error") == null ? "":request.getAttribute("cc_error")%></div>
    <div><%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%></div>

</body>
</html>
package cn.itcast.servlet;

import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 设置request编码
        request.setCharacterEncoding("utf-8");
        //2. 获取参数Map
        Map<String, String[]> map = request.getParameterMap();

        //3. 创建User对象
        User loginUser = new User();
        UserDao dao = new UserDao();
        try {
            BeanUtils.populate(loginUser,map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //3. 先获取生产的验证码
        HttpSession session = request.getSession();
        String checkCode_session = (String) session.getAttribute("checkCode_session");

        //删除session中存储的验证码
        session.removeAttribute("checkCode_session");

        //3.先判断验证码是否正确
        if(checkCode_session != null && checkCode_session.equalsIgnoreCase(map.get("checkCode")[0])){
            //忽略大小写比较
            //验证码正确
            //判断用户名和密码是否一致

            //4. 调用UserDao的login方法
            User user = dao.login(loginUser);

            if(user != null){
                //登录成功
                //存储信息:用户信息
                session.setAttribute("user",user.getUsername());

                //重定向到success.jsp
                response.sendRedirect(request.getContextPath()+"/success.jsp");
            }else {
                //登录失败
                //存储提示信息到request
                request.setAttribute("login_error","用户名或密码错误");
                //转发到登录页面
                request.getRequestDispatcher("/login.jsp").forward(request,response);
            }
        }else{
            //验证码不一致
            //存储提示信息到request
            request.setAttribute("cc_error","验证码错误");
            //转发到登录页面
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

    success.jsp

<%--
  Created by IntelliJ IDEA.
  User: ajing
  Date: 2022/2/26
  Time: 21:15
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <h1><%=request.getSession().getAttribute("user")%>,欢迎您</h1>

</body>
</html>
package cn.itcast.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 登录验证的过滤器
 */
@WebFilter("/*")
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
       
        //0. 强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        
        //1. 获取资源请求路径
        String uri = request.getRequestURI();

        //2.判断是否包含登录相关的资源路径,要注意排除掉css/js/图片/验证码等资源
        if(uri.contains("/login.jsp")|| uri.contains("/loginServlet")|| uri.contains("/css")|| uri.contains("/js")|| uri.contains("/fonts")|| uri.contains("/checkCodeServlet")){
            //包含,用户想登陆。放行
            chain.doFilter(req, resp);
        }else{
            //不包含,需要验证用户是否登录
            //3.从获取session中获取user
            Object user = request.getSession().getAttribute("user");
            if(user!=null){
                //登录了,放行
                chain.doFilter(req, resp);
            }else{
                //没有登录,跳转登录页面
                request.setAttribute("login_error","您尚未登录,请先登录");
                request.getRequestDispatcher("/login.jsp").forward(request,resp);
            }
        }              
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

 

posted on 2022-02-26 01:35  花溪月影  阅读(32)  评论(0编辑  收藏  举报