JavaEE学习day-54:监听器和过滤器

一、监听器的使用

1.监听器的介绍:

Servlet 监听器是 Servlet 规范中定义的一种特殊类,用于监听 ServletContext、HttpSession 和 ServletRequest 等域对象的创建与销毁事件,以及监听这些域对象中属性发生修改的事件。

  • 作用:

监听request、session、application三个域对象的创建,销毁和数据的变更(添加、修改和删除)。

2.监听器的使用:

  • 监听session对象的使用:

实现接口:
javax.servlet.http.HttpSessionAttributeListener;
javax.servlet.http.HttpSessionListener;
接口中的方法:
(1)监听session的创建和销毁:HttpSessionListener:
SessionCreated(HttpSessionEvent se);
sessionDestroyed(HttpSessionEvent se);
(2)监听session的作用域数据的变更:
AttributeAdded(Http SessionBindingEvent event);
attributeRemoved(HttpSessionBindingEvent event);
attributeReplaced(HttpSessionBindingEvent event);

  • 监听Request对象的使用:

实现接口:
javax.servlet.ServletRequestListener;
javax.servlet.ServletRequestAttributeListener;
接口中的方法:
(1)监听Request的创建和销毁:
requestInitialized(ServletRequestEvent sre);
requestDestroyed(ServletRequestEvent sre);
(2)监听Request的作用域数据的变更:
attributeAdded(ServletRequestAttributeEvent srae);
attributeRemoved(ServletRequestAttributeEvent srae);
attributeReplaced(ServletRequestAttributeEvent srae);

  • 监听Application对象的使用:

实现接口:
javax.servlet.http.HttpSessionAttributeListener;
javax.servlet.ServletContextListener;
接口中的方法:
(1)监听application对象的创建和销毁:
contextInitialized(ServletContextEvent sce);
contextDestroyed(ServletContextEvent sce);
(2)监听application对象的数据的变更:
attributeAdded(ServletContextAttributeEvent event);
attributeRemoved(ServletContextAttributeEvent event);
attributeReplaced(ServletContextAttributeEvent event);

3.案例在线人数的统计:

  • 实现思路:

定义一个计数器;每当session创建时计数器就加1;session被销毁时计数器就-1。

  • 在原项目中创建监听器:
package com.zlw.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MyListener implements HttpSessionListener,ServletContextListener{

    //监听Context对象
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        int count = 0;
        //获取Application对象
        ServletContext sc = sce.getServletContext();
        sc.setAttribute("count", count);
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        
    }
    //监听session对象
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        //获取Application对象中的计数器
        ServletContext sc = se.getSession().getServletContext();
        int count = (int)sc.getAttribute("count");
        //计数器自增
        ++count;
        //然后将计数器存储到application中
        sc.setAttribute("count", count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        //获取Application对象中的计数器
        ServletContext sc = se.getSession().getServletContext();
        int count = (int) sc.getAttribute("count");
        //计数器自减
        --count;
        //然后再将计数器存储到Application中
        sc.setAttribute("count",count);
    }
}
  • web.xml文件配置:
!-- 监听器的配置 -->
  <listener>
  <listener-class>com.zlw.listener.MyListener</listener-class>
  </listener>
  • 增加效果:


    效果

二、过滤器的使用

1.问题:

Servlet 的作用是针对浏览器发起的请求,进行请求的处理。通过 Servlet 技术我们可以灵活的进行请求的处理,但是我们不但要对请求记性处理,我们还需对服务器的资源进行统一的管理 ,比如请求编码格式的统一设置,资源的统一分配等等。


原理图

2.过滤器的作用:

过滤器可以拦截所有的请求;可以添加多个过滤,考虑性能一般不会添加过多过滤器;是由服务器创建的。
可以用来限制访问的权限;
过滤敏感的关键字;
解决乱码问题。

3.创建过滤器和实现方法:

  • 接口:

javax.servlet.Filter;

  • 实现方法:

init方法:服务器启动时调用;
doFilter方法;进行业务处理。
destory方法:服务器关闭时调用;

  • doFilter方法的作用:

服务器在接收到浏览器发过来的请求后,先解析请求信息,创建对象request和response然后根据请求URL地址判断如果符合过滤器的过滤范围,则会调用过滤器中的doFilter来进行请求拦截,并将request和response对象作为实参传递给doFilter方法。我们可以在doFilter方法中声明过滤器拦截代码。

  • doFilter中的参数:

ServletRequest:接收此次拦截的请求的request实参
ServletResponse:接收此次拦截的请求的response实参
FilterChain:可以进行请求放行

  • 过滤器拦截的范围:

拦截所有:/*
拦截部分Servlet的请求:*.do
拦截指定Servlet的请求:和要拦截的指定的Servlet的url-pattern配置完全一致即可,例如:/my。
注意:过滤器之间会出现多重拦截,如果是按照拦截拦截范围的大小在web.xml中自大而小进行的配置,则会先执行大范围的拦截器,再执行小范围的拦截器。

  • web.xml文件配置:

<filter>
<filter-name>配置的过滤器名称</filter-name>
<filter-class>要配置的过滤器的全限定路径:包名.类名</filter-class>
</filter>
<filter-mapping>
<filter-name>配置的过滤器名称</filter-name>
<url-pattern>过滤器拦截请求地址的范围</url-pattern>
</filter-mapping>

  • 代码示例:
package com.zlw.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class MyFilter implements Filter{

    @Override
    public void destroy() {
        System.out.println("MyFilter过滤器被销毁!");
        
    }
    //
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("MyFilter.doFilter(我是过滤器MyFilter:佩奇小区门口的保安)");
        //放行
        chain.doFilter(request, response);
        System.out.println("(*^_^*)");
    }

    @Override
    public void init(FilterConfig filterconfig) throws ServletException {
        System.out.println("创建了MyFilter过滤器");
    }
}
package com.zlw.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter2 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("MyFilter2.doFilter(我是佩奇家楼门口的保安!)");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        // TODO Auto-generated method stub  
    }
}
package com.zlw.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter3 implements Filter {
    //创建
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
        
    }
    //操作
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("MyFilter3.doFilter(我是佩奇家门口的保安!)");
        chain.doFilter(request, response);
    }
    //销毁
    @Override
    public void destroy() {
        // TODO Auto-generated method stub  
    }
}
package com.zlw.serlvet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MySerlvet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("MyServlet.service(小猪佩奇家被访问了!)");
    }
}
  <!--过滤器配置  :拦截所有-->
  <filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.zlw.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <!--过滤器配置:拦截部分  -->
  <filter>
    <filter-name>myFilter2</filter-name>
    <filter-class>com.zlw.filter.MyFilter2</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter2</filter-name>
    <url-pattern>*.do</url-pattern>
  </filter-mapping>
  <!--过滤器配置:拦截指定的Servlet的请求  -->
  <filter>
    <filter-name>myFilter3</filter-name>
    <filter-class>com.zlw.filter.MyFilter3</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myFilter3</filter-name>
    <url-pattern>/my.do</url-pattern>
  </filter-mapping>
  • 结果:
    结果

4.解决乱码问题:

  • 分析图:
  • 解决Post方式提交的乱码问题:

request.setCharacterEncoding("utf-8");

  • 解决Get方式提交乱码问题:

String userName = request.getParamenter(" ");
String str = new String (userName.getBytes("ios-8859-1"),utf-8);

  • 代码示例:
package com.zlw.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class EncodingFilter implements Filter{
    private String encoding;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        encoding = filterConfig.getInitParameter("encoding");//获取配置文件中参数的值
        System.out.println(encoding);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse resp = (HttpServletResponse)response;
//      req.setCharacterEncoding("utf-8");
//      resp.setContentType("text/html;charset=utf-8");
        req.setCharacterEncoding(encoding);
        resp.setContentType("text/html;charset="+encoding);
        chain.doFilter(request, response);//将请求继续向下传递
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}
  • Serlvet
package com.zlw.serlvet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取用户输入的用户名和密码
        String userName = request.getParameter("userName");
        String userPass = request.getParameter("userPass");
        //如何处理地址栏传参或get提交的乱码问题
        userName = new String (userName.getBytes("iso-8859-1"));
        System.out.println(userName+"---"+userPass);
        if(("admin".equals(userName)&&"admin".equals(userPass))||("张三".equals(userName)&&"admin".equals(userPass))){
            request.getSession().setAttribute("userName", userName);
            response.sendRedirect("index.jsp");
        }else{
            response.sendRedirect("login.jsp");
        }
    }
}
  • jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
  
  </head>
  <body>
    <h3 style="color: red">登录成功</h3>
  </body>
</html>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>测试乱码解决</title>
    
  </head>
  
  <body>
  <form action="login"method="get">
   用户名:<input type="text" name="userName" />
    密码:<input type="password" name="passName" />
    <input type="submit" value="登录" />
    </form>
  </body>
</html>
  • web.xml文件配置:
<filter>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.zlw.filter.EncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
  </filter>
    <filter-mapping>
     <filter-name>EncodingFilter</filter-name>
     <url-pattern>/*</url-pattern>
  </filter-mapping>

三、项目权限管理功能

1.需求:

不同的用户在对同一功能使用时,有的用户可以直接使用,有的用户会被提示权限不足。

1.功能实现思路:

(1)在数据库中创建一个URL权限表,该表存储了该系统需要被管理的URL。
(2)在数据库中创建用户权限中间表,用来进行权限分配。
(3)在数据库中将权限给用户分配好。
(5)在用户登录成功后查询该用户具备的URL权限,存储到该用户的session中。
(6)在过滤器中对当前发起请求的用户的请求地址进行校验,校验该用户是否具备该请求地址的权限,如果具备则放行执行,如果不具备则提示权限不足。

2.数据库创建:

URL权限表:t_url
编号: urlid
url地址 :location
描述:remark

用户权限中间表:t_user_url
uid
urlid
SQL语句的设计:查询当前登录用户的url信息
子查询:
select * from t_url where urlid in (select urlid from t_user_url where uid=?)
联合查询:
select * from t_url tu,t_user_url tul where tu.urlid=tul.urlid and tul.uid=?)

3.JDBC操作数据库:

//查询当前用户的URL权限信息
    @Override
    public List<Url>getUserUrlInfoDao(int uid){
        //声明jdbc变量
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        //声明变量
        String sql = "select * from t_url where urlid in (select urlid from t_user_url where uid=?)";
        List<Url> lu = null;
        
        try {
            conn = DBUtil.getConnection();
            ps = conn.prepareStatement(sql);
            ps.setInt(1, uid);
            rs = ps.executeQuery();
            lu = new ArrayList<Url>();
            while(rs.next()){
                Url ul = new Url();
                ul.setUrlid(rs.getInt("urlid"));
                ul.setLocation(rs.getString("location"));
                ul.setRemark(rs.getString("remark"));
                lu.add(ul);
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return lu;
        
    }

4.Filter监听器:

package com.zlw.filter;

import java.io.IOException;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.zlw.pojo.Url;
/**
 * * Filter案例之统一编码格式:
 *      在doFilter中使用
 *              //设置请求编码格式
*                   request.setCharacterEncoding("utf-8");
*               //设置响应编码格式
*                   response.setContentType("text/html;charset=utf-8");
*   Filter案例之session管理
*           在过滤器中获取session对象,然后查看session中的数据是否还在
*           如果数据没了,则因为session失效则重定向到登录页面。如果数据还在
*           session没有失效,则放行
*           
*           问题1:
*               在过滤器中使用session校验后发现登录页面的访问成了死循环,因为登录页面的
*               请求也就是login.jsp的请求也会被过滤器拦截,而此时session中没有相关数据的
*               造成又重定向到登录页面......
*           解决1:
*               对login.jsp和登录请求进行放行
*           问题2:
*               过滤器会拦截所有的请求,包括静态资源(css文件\js文件\image图片)请求也会拦截。
*               造成页面中的样式和动态效果等出不来
*           解决2:
*               对静态资源放行
                    
 *  @author zhang
 *
 */
public class MyFilter implements Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        //设置请求编码格式
        request.setCharacterEncoding("utf-8");
        //设置响应编码格式
        response.setContentType("text/html;charset=utf-8");
//      chain.doFilter(request, response);
        //强转Request对象
        HttpServletRequest req = ((HttpServletRequest)request);
        //强转response对象
        HttpServletResponse resp = ((HttpServletResponse)response);
        //获取此次请求的uri
        String uri = req.getRequestURI();
        //获取此次请求的method
        String method = req.getParameter("method");
        System.out.println("当前请求的method"+method);
        System.out.println("当前请求的uri为:"+uri);
        if("/project2/login.jsp".equals(uri)||"/project2/reg.jsp".equals(uri)||("/project2/data".equals(uri))&&"userLogin".equals(method)||uri.startsWith("/project2/css/")||uri.startsWith("/project3/js/")||uri.startsWith("/project2/images/")){
            
            //放行
            chain.doFilter(request, response);
            
        }else{
            
            //获取session对象
            HttpSession session = req.getSession();
            Object obj = session.getAttribute("user");
            //判断
            if(obj!=null){
                //获取权限信息
                    List<Url> li = (List<Url>)session.getAttribute("lu");
                    //权限校验
                    for (Url url : li) {
                        if(url.getLocation().equals(method)||url.getLocation().equals(uri)){
                            //放行
                            chain.doFilter(request, response);
                            return;
                        }
                    }
                //响应
                    resp.getWriter().write("power");
                    return;
            }else{
                //重定向到登录页面
                resp.sendRedirect("/project2/login.jsp");
            }
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }
}
  • web.xml文件配置:
<!-- 监听器的配置 -->
  <listener>
  <listener-class>com.zlw.listener.MyListener</listener-class>
  </listener>
张三登录
李四登录
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容