监听器和过滤器,在线人数统计、登录过滤拦截、字符中文格式编码控制

文章目录

  • Listener监听器
    • 案例:实现网页在线人数统计
      • 1-页面显示
      • 2-请求设计
      • 3-监听器设计
      • 4-xml监听器配置
      • 5-问题
  • Filter过滤器
    • 多个Filter的执行顺序
    • 案例:实现网页字符中文格式显示
    • 案例:实现登录过滤拦截
      • 1-login.jsp页面设计
      • 2-LoginServlet请求设计
        • Constant类设计
      • 3-登录成功、失败的页面设计
      • 4-LogoutServlet请求设计
      • 5-问题:过滤器拦截

监听器和过滤器,在线人数统计、登录过滤拦截、字符中文格式编码控制_第1张图片

Listener监听器

同过滤器

过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.

当Filter被移除或服务器正常关闭时,会执行destroy方法。

案例:实现网页在线人数统计

1-页面显示

<%--
  Created by IntelliJ IDEA.
  User: PitYk
  Date: 2020/7/11
  Time: 11:21
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

  
    $Title$
  
  
  

当前有 <%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%> 人在线

$END$

2-请求设计

因为监听器获取当前Session的id情况,每个浏览器是一种Session,所以不用设计请求。

3-监听器设计

public class OnlineCountListener implements HttpSessionListener {
    //创建session监听: 看你的一举一动
    //一旦创建Session就会触发一次这个事件!
    public void sessionCreated(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        System.out.println(se.getSession().getId());
        Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
        if (onlineCount==null){
            onlineCount = new Integer(1);
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count+1);
        }
        ctx.setAttribute("OnlineCount",onlineCount);
    }

    //销毁session监听
    //一旦销毁Session就会触发一次这个事件!
    public void sessionDestroyed(HttpSessionEvent se) {
        ServletContext ctx = se.getSession().getServletContext();
        Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
        if (onlineCount==null){
            onlineCount = new Integer(0);
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count-1);
        }
        ctx.setAttribute("OnlineCount",onlineCount);
    }
    /*
    Session销毁:
    1. 手动销毁  getSession().invalidate();
    2. 自动销毁
     */
}

4-xml监听器配置


<listener>
    <listener-class>com.pit.listener.OnlineCountListenerlistener-class>
listener>


<session-config>
    <session-timeout>1session-timeout>
session-config>

5-问题

如果出现第一次打开浏览器,在线人数过多的情况,你只需要重启服务器。

重启的过程,会销毁所有的Session,再次打开服务器时会重新统计在线人数的!
监听器和过滤器,在线人数统计、登录过滤拦截、字符中文格式编码控制_第2张图片

因为我的电脑打开了3个浏览器,所以会有3个Session的id存在
在这里插入图片描述

Filter过滤器

参考博客:Java Web之过滤器(Filter)https://blog.csdn.net/yuzhiqiang_1993/article/details/81288912

过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.

当Filter被移除或服务器正常关闭时,会执行destroy方法。

多个Filter的执行顺序

在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下

  1. 在web.xml中,filter执行顺序跟**的顺序**有关,先声明的先执行
  2. 使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
  3. 如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

案例:实现网页字符中文格式显示

过滤器设计

public class CharacterEncodingFilter implements Filter {
    //初始化:web服务器启动,就以及初始化了,随时等待过滤对象出现!
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CharacterEncodingFilter初始化");
    }

    //Chain : 链
    /*
    1. 过滤中的所有代码,在过滤特定请求的时候都会执行
    2. 必须要让过滤器继续同行
        chain.doFilter(request,response);
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=UTF-8");

        System.out.println("CharacterEncodingFilter执行前....");
        chain.doFilter(request,response); //让我们的请求继续走,如果不写,程序到这里就被拦截停止!
        System.out.println("CharacterEncodingFilter执行后....");
    }

    //销毁:web服务器关闭的时候,过滤会销毁
    public void destroy() {
        System.out.println("CharacterEncodingFilter销毁");
    }
}

web.xml过滤器配置

<filter>
    <filter-name>CharacterEncodingFilterfilter-name>
    <filter-class>com.kuang.filter.CharacterEncodingFilterfilter-class>
filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilterfilter-name>
    
    <url-pattern>/servlet/*url-pattern>
    
filter-mapping>

案例:实现登录过滤拦截

1-login.jsp页面设计

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



登录

<%--此处action路径==web.xml内urlpattern设计!!!请求响应到LoginServlet--%>

2-LoginServlet请求设计

注意!登录页面Login.jsp登录采用的是post方式提交,所以LoginServlet中后端设计也在doPost方法内。


public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取前端请求的参数
        String username = req.getParameter("username");
        if (username.equals("admin")){ //登录成功
           req.getSession().setAttribute(Constant.USER_SESSION,req.getSession().getId());
           resp.sendRedirect("/sys/success.jsp");
        }else { //登录失败
            resp.sendRedirect("/error.jsp");
        }
        
    }

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

/*
* 上述引入了Constant类,目的在于设计“常量”思想,避免程序文件复杂时的频繁修改参数问题!
* 此外,还可设计多VIP区分!
*/

Constant类设计

util包下,新增该类!

package com.kuang.util;

public class Constant {
    public final static String USER_SESSION = "USER_SESSION";
}

/*
User
    id
    name
    level    等级
VIP1
VIP2
VIP3
VIP4
 */

右键新增LoginServlet后,自动跳转到web.xml进行Servlet映射

<servlet>
    <servlet-name>LoginServletservlet-name>
    <servlet-class>com.pit.servlet.LoginServletservlet-class>
servlet>
<servlet-mapping>
    <servlet-name>LoginServletservlet-name>
    <url-pattern>/servlet/loginurl-pattern>
servlet-mapping>

3-登录成功、失败的页面设计

web包下新增sys文件夹,登陆成功页面:success.jsp

目的在于方便后面过滤器的设计,将过滤sys文件下所有的Servlet请求!!!

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title



主页

注销

登陆失败页面设计:error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


错误

没有权限,用户名错误

返回登录页面

登录成功,进入主页;点击注销,返回登录界面;登陆失败,返回登录界面!

4-LogoutServlet请求设计

public class LogoutServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object user_session = req.getSession().getAttribute(Constant.USER_SESSION);
        if (user_session!=null){
            req.getSession().removeAttribute(Constant.USER_SESSION);
            resp.sendRedirect("/Login.jsp");
        }else {
            resp.sendRedirect("/Login.jsp");
        }
    }
}

Logout请求获取SessionConstant.USER_SESSION属性,

根据该属性值进行跳转!==null,已经注销过了,直接跳转到login;!=null,移除Session的USER_SESSION属性。

5-问题:过滤器拦截

注意编辑tomcat的布置路径为"/"即可!

登录、注销页面均运行良好,但是会出现一个问题:在首次登录成功后,注销,然后再网页的url内直接输入succes.jsp也可以直接跳转到首页显示。

分析:因为虽说在logout的servlet请求内,注销操作remove了Session属性,但是网页url页面跳转 success.jsp 是直接显示,并没有获取判断该属性是否还存在。

解决方法:

引入过滤器对 success.jsp 页面跳转条件 进行 判断拦截!

在filter包新增 SysFilter.jsp过滤器:

public class SysFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // ServletRequest    HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (request.getSession().getAttribute(Constant.USER_SESSION)==null){
            response.sendRedirect("/error.jsp");
        }

        filterChain.doFilter(request,response);
    }

    public void destroy() {

    }
}

web.xml内注册该过滤器

<filter>
    <filter-name>SysFilterfilter-name>
    <filter-class>com.pit.filter.SysFilterfilter-class>
filter>

<filter-mapping>
    <filter-name>SysFilterfilter-name>
    <url-pattern>/sys/*url-pattern>
filter-mapping>

ss.jsp 页面跳转条件 进行 判断拦截!

在filter包新增 SysFilter.jsp过滤器:

public class SysFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // ServletRequest    HttpServletRequest
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        if (request.getSession().getAttribute(Constant.USER_SESSION)==null){
            response.sendRedirect("/error.jsp");
        }

        filterChain.doFilter(request,response);
    }

    public void destroy() {

    }
}

web.xml内注册该过滤器

<filter>
    <filter-name>SysFilterfilter-name>
    <filter-class>com.pit.filter.SysFilterfilter-class>
filter>

<filter-mapping>
    <filter-name>SysFilterfilter-name>
    <url-pattern>/sys/*url-pattern>
filter-mapping>

你可能感兴趣的:(JavaWeb)