过滤器Filter和监听器Listener

过滤器

在多个页面需要统一执行的代码,可以通过过滤器的web组件来完成;

  1. 定义过滤器

//识别过滤器
@WebFilter(urlPattern="要过滤哪些路径")
class 过滤器类 implements Filter{
    
    //初始化操作
    public void init(){}
    
    //销毁操作
    public void destroy(){}
    
    //过滤方法
    //FilterChain过滤器链
    public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain){
        //要统一执行的代码
        
        //是否让请求继续前进
        chain.doFilter(req,resp);
        
    }
}
  1. 过滤的路径格式
  • 精准匹配 /servlet1:只会进入servlet1之前进入过滤器;
  • 后缀匹配 *.jsp:访问任意一个以.jsp结尾的路径都会经过过滤器;
  • 前缀匹配 /user/*:当请求的路径是以user开头的就会经过过滤器;

如果有多个过滤器都和目标路径匹配,那么会依次经过多个过滤器,经过先后顺序跟过滤器的名字有关;

  1. request和response的类型转换

Filter中的request和response声明的是父类型,有些方法没有,需要转换为子类型对象;


  1. 过滤器的应用
  • post请求的中文乱码,可以采用字符编码过滤器来解决
req.setCharacterEncoding("解码字符集");
req.getParameter()

四种拦截方式

  • 请求 dispatcher
  • 转发 forward
  • 包含 include
  • 错误 error

在这里插入图片描述
过滤器的应用场景

  • 执行目标资源之前的预处理工作,例如设置编码;
  • 通过条件是都放行;
  • 在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理。

案例

登录检查过滤器

@WebFilter(urlPatterns = "/*")
public class Filter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        //检查路径是否为登录界面路径,如果是则直接放行,否则判断用户是否已经登录
        String uri = req.getRequestURI();
        if (uri.equals("/users.jsp") || uri.equals("/servlet01")){
            filterChain.doFilter(req,resp);
            return;
        }
        
        //检查会话中是否存在username用户,如果存在这说明已经登录,否则跳转到登录页面让用户继续登录
        HttpSession session = req.getSession();
        Object user = session.getAttribute("username");
        if(user ==null){
            session.setAttribute("error","您尚未登录");
            resp.sendRedirect("/users.jsp");

        }else {
            filterChain.doFilter(req,resp);
        }
    }
    @Override
    public void destroy() {

    }
}

如果跳转页面有多层目录,在跳转时在路径前加上"/",以相对主机名和端口号进行跳转;
否则会以从后往前第一个"/"之前的路径为相对路径进行跳转。

自动登录过滤器

  1. 浏览器第一次登陆,发送登录请求,登陆成功后,服务器将包含用户名、密码的登录标志信息放入session中;
  2. 服务器返回给浏览器一个cookie响应,包含用户名和密码,并且浏览器设置maxAge等属性;
  3. 浏览器关闭,session中的信息失效,但是浏览器中存在cookie的信息,在发送请求的时候,
    同时将cookie中的信息发送给服务器;
  4. 过滤器先检查session内容,如果有旧直接放行,否则检查cookie中的信息,看cookie是否存在并且用户名和密码是否正确,
    如果正确直接放行,否则需要重新登录;

在servlet中判断是否要自动登录

 //如果自动登录栏被勾选则执行
        if (req.getParameter("autoLogin").equals("true")){
            req.setAttribute("success","登陆成功");
            //创建cookie对象,将用户信息存入
            Cookie cookie = new Cookie("up",user.getUsername()+":"+user.getPassword());
            //设置cookie的存活时间
            cookie.setMaxAge(24*3600);
            //将cookie添加到响应,返回给浏览器
            resp.addCookie(cookie);
        }

在过滤器中,先判断session中是否存在用户信息,如果存在则自动登录;如果不存在则判断浏览器发过来的
cookie中是否存在用户信息,如果存在则自动登录,并且把cookie中的信息放入session中方便以后使用,否则跳转到登录页面;

//检查会话中是否存在username用户
        HttpSession session = req.getSession();
        Object user = session.getAttribute("username");
        if(user !=null){
            filterChain.doFilter(req,resp);
        }else {
            //如果session中没有用户信息,则检查cookie中是否存在

            //获取浏览器请求时发过来的cookie
            Cookie[] cookies = req.getCookies();
            Cookie up=null;
            for (Cookie cookie : cookies) {
                if(cookie.getName().equals("up")){
                    up=cookie;
                    break;
                }
            }

            if(up!=null){
                //获取用户名和密码
                String[] split = up.getValue().split(":");
                //验证用户名和密码
                UserDao ud = new UserDao();
                String username = split[0];
                String password=split[1];

                User user1 = ud.authUser(username);
                if (user1!=null && user1.getPassword().equals(password)){
                    //将用户名放入session
                    session.setAttribute("username",username);
                 filterChain.doFilter(req,resp);
                 return;
                }
            }

        }

统计网站IP访问次数

需要一个全局的集合来放数据,而且这个集合在服务启动时创建;在监听器的初始化方法中创建一个map并放入application作用域中。

@WebListener()
public class Listener implements ServletContextListener{

//    定义存储集合
    private LinkedHashMap<String,Integer> linkedHashMap;

    public Listener() {
    }


    public void contextInitialized(ServletContextEvent sce) {
//        服务器启动时创建map
        linkedHashMap=new LinkedHashMap<>();
        ServletContext application = sce.getServletContext();
//        将map放入application作用域
        application.setAttribute("map",linkedHashMap);
    }

    public void contextDestroyed(ServletContextEvent sce) {
    }
}

@WebFilter(urlPatterns = "*.jsp")
public class Filter implements javax.servlet.Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//        拦截统计次数,放行
        ServletContext application = req.getServletContext();
        LinkedHashMap map =(LinkedHashMap) application.getAttribute("map");
        String ip = req.getLocalAddr();
        Integer count =(Integer) map.get(ip);
        if(count==null){
            map.put(ip,1);
        }else {
            map.put(ip,count+1);
        }
        application.setAttribute("map",map);
        System.out.println("被拦截");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri ="http://java.sun.com/jsp/jstl/core" %>>
<html>
<head>
    <title>统计Ip访问次数</title>
</head>
<body>
<table align="center" width="60%" border="1">
        <tr>
            <td>IP</td>
            <td>访问次数</td>
        </tr>
        <c:forEach items="${applicationScope.map}" var="entry">
            <tr>
                <td>${entry.key}</td>
                <td>${entry.value}</td>
            </tr>
        </c:forEach>
</table>


</body>
</html>

监听器

事件源:三大域

  • servletContext;与天地同寿

    • 生死监听:ServletContextListener;有两个方法,一个在出生时调用,一个在死亡时调用。
    • 属性监听:ServletContextAttributeListener;由三个方法,一个是在添加属性时调用,一个在替换属性时调用,最后一个在移除属性时调用。
  • HttpSession;有session时才创建

    • 生死监听:HttpSessionListener;有两个方法,一个在出生时调用,一个在死亡时调用。
    • 属性监听:HttpSessionAttributeListener;由三个方法,一个是在添加属性时调用,一个在替换属性时调用,最后一个在移除属性时调用。
  • ServletRequest;发出请求就创建

    • 生死监听: ServletRequestListener;有两个方法,一个在出生时调用,一个在死亡时调用。
    • 属性监听: ServletRequestAttributeListener;由三个方法,一个是在添加属性时调用,一个在替换属性时调用,最后一个在移除属性时调用。

Listener没有路径,特定事件发生时,会执行监听器代码;

  • ServletRequestListener:在请求对象初始化和销毁时,会被调用;
  • HttpSessionListener:在session初始化和销毁的时候会被调用;

事件对象

  • ServletContextEvent:ServletContext.getServletContext();
  • HTTPSessionEvent:HTTPSession.getSession();
  • ServletRequest:
    • ServletContext.getServletContext();
    • ServletRequest.getServletRequest();

感知监听器

  • 它用来添加JavaBean上,而不是添加到三大域上;
  • 这两个监听器都不用需要在web.xml中注册;

意义:让对象知道自己是否被添加到session中。

应用场景:

  • ServletContextListener:在application对象创建和销毁的时候被调用;

  • ServletRequestAttributeListener:在往request作用域中变量发生变化时被调用

  • HTTPSessionAttributeListener:在往session作用域中变量发生变化时被调用

  • ServletContextAttributeListener:在往application作用域中变量发生变化时被调用

  • HttpSessionActivationListener:在session钝化(从内存到磁盘)和活化(从磁盘到内存)session中存储对象,
    对象要实现序列化和反序列化;

  • HTTPSessionBindingListener:

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值