过滤器和监听器

过滤器和监听器

1. 过滤器

1.1 过滤器定义

//也可以通过注解配置filter:@WebFilter("/*"),拦截所有请求
public class EncodFilter implements Filter {
    
    //初始化的方法,可以通过FilterConfig获得xml配置的参数
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
    
	//过滤器处理业务的方法,完成业务处理之后一定要放行。
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        
        //放行
        filterChain.doFilter(req,resp);
    }

    //销毁filter时执行的方法
    @Override
    public void destroy() {}
}

1.2 过滤器配置

<filter>                                                            
    <filter-name>encode</filter-name>                               
    <filter-class>com.yogie.lesson.filter.EncodFilter</filter-class>
    //配置参数
    <init-param>                                                    
        <param-name>encoding</param-name>                           
        <param-value>utf-8</param-value>                            
    </init-param>                                                   
    <init-param>                                                    
        <param-name>force</param-name>                              
        <param-value>true</param-value>                             
    </init-param>                                                   
</filter>
<filter-mapping>                     
    <filter-name>encode</filter-name>
    //配置过滤路径:所有请求都要经过encode过滤器
    <url-pattern>/*</url-pattern>    
</filter-mapping>                    

1.3 过滤器的生命周期

​ 启动tomcat的时候开始,先创建FilterConfig,再调用init方法,filter是单例模式,只有一个对象。关闭tomcat服务器或者停止虚拟机运行的时候,过滤器调用destroy方法。

1.4 过滤器的应用

​ 1、对字符进行编码。

<filter>                                                               
    <filter-name>encoding</filter-name>                                
    <filter-class>com.yogie.lesson.filter.EncodingFilter</filter-class>
    <init-param>                                                       
        <param-name>charset</param-name>                               
        <param-value>UTF-8</param-value>                               
    </init-param>                                                      
    <init-param>                                                       
        <param-name>force</param-name>                                 
        <param-value>true</param-value>                                
    </init-param>                                                      
</filter>
<filter-mapping>                       
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>      
</filter-mapping>                      
public class EncodingFilter implements Filter {
    private String charset;
    private Boolean force;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //读取配置文件中filter中的配置
        charset = filterConfig.getInitParameter("charset");
        //如果用户没有配置编码方式
        if(charset==null || "".equals(charset)){
            //设置一个默认的编码
            charset = "UTF-8";
        }
        //Boolean.parseBoolean(null)的结果也为false
        force = Boolean.parseBoolean(filterConfig.getInitParameter("force"));

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse)servletResponse;
        //获取请求对象携带过来的编码方式
        String ce = req.getCharacterEncoding();
        if( ce==null || "".equals(ce) || force){
            //如果request请求中没有设置编码方式,
            //如果配置了强制使用配置中的编码方式
            req.setCharacterEncoding(charset);
        }
        filterChain.doFilter(req,resp);
    }

    @Override
    public void destroy() {

    }
}

​ 2、让浏览器不缓存。
​ 3、屏蔽非法文字(敏感词过滤处理)。

  • 关键字过滤器
@WebFilter("/*")
public class SensitiveFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //将servletRequest转换成HttpServletRequest对象
        HttpServletRequest req = (HttpServletRequest)servletRequest;
        //HttpServletRequest转换成MyHttpRequestWapper,
        //在这个转换的过程中,请求对象所携带的文本信息中的敏感信息被过滤掉了
        MyHttpRequestWapper requestWapper = new MyHttpRequestWapper(req);
        //放行后,request对象已经是经过包装的request对象了
        filterChain.doFilter(requestWapper, servletResponse);
    }

    @Override
    public void destroy() {

    }
}
  • 请求对象的装饰类
public class MyHttpRequestWapper extends HttpServletRequestWrapper {
    private HttpServletRequest req = null;
    public MyHttpRequestWapper(HttpServletRequest request) {
        //必须显示调用父类的构造方法,因为父类没有默认的无参构造方法
        super(request);
        //将HttpServletRequest对象赋值给字段
        req = request;
    }

    @Override
    public String getParameter(String name) {
        //根据参数名获取请求对象中的对应的值
        String value = req.getParameter(name);
        return SensitiveUtil.filterWords(value,"*");
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        //获取请求对象中的键值对map
        Map<String, String[]> map = req.getParameterMap();
        //准备一个返回的map
        Map<String, String[]> result = new HashMap<>();
        //取出其中所有的键值对集合
        Set<Map.Entry<String, String[]>> entries = map.entrySet();
        //遍历集合
        for (Map.Entry<String, String[]> entry : entries) {
            //key
            String key = entry.getKey();
            //value:有的字段可能对应多个值,例如select标签
            String[] value = entry.getValue();
            //设计一个与value一致长度的数组
            String[] arr = new String[value.length];
            //遍历这个vlaue数组,将数组中每个元素的字符串都进行敏感词过滤
            for (int i = 0; i < value.length; i++) {
                arr[i] = SensitiveUtil.filterWords(value[i],"*");
            }
            //将过滤后的值保存到map集合中
            result.put(key,arr);
        }
        return result;
    }
}
  • 敏感词替换的工具类
public class SensitiveUtil {

    private static List<String> keyWords = new ArrayList<>();

    static{
        Scanner sc = new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("sensitive.txt"),"UTF-8");
        while (sc.hasNextLine()){
            String line = sc.nextLine();
            if(line!=null || !"".equals(line)){
                keyWords.add(line);
            }
        }
        sc.close();
    }

    /**
     * 将str中的敏感词替换为指定字符拼接成的字符串
     * @param str
     * @param mask
     * @return
     */
    public static String filterWords(String str,String mask){
        for (String keyWord : keyWords) {
            if(str!=null && str.indexOf(keyWord) >= 0){
                str = str.replaceAll(keyWord,buildMask(keyWord,mask));
            }
        }
        return str;
    }

    /**
     * 配置keyword长度的替代字符
     * @param keyWord
     * @param mask
     * @return
     */
    private static String buildMask(String keyWord, String mask) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keyWord.length(); i++) {
            sb.append(mask);
        }
        return sb.toString();
    }
}

​ 4、登录权限验证。

  • 登录权限的过滤器
public class LoginFilter implements Filter {
    String[] strs = null;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //将配置中不用验证的资源放入strs数组中
        strs = filterConfig.getInitParameter("outs").split(",");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;
        //从session中获得key为username的对象
        Object obj = req.getSession().getAttribute("NAME_IN_SESSION");
        //获取到请求路径中的uri描述,并按照反斜杠分割
        String[] split = req.getRequestURI().split("/");
        //将配置中的路径放到list中
        List<String> list = Arrays.asList(strs);
        //如果配置的路径中不包含此次请求资源且session为空,不能放行
        if(!list.contains(split[split.length-1]) && obj==null){
            resp.sendRedirect("/xx/index.html");
            return;
        }
        //放行
        filterChain.doFilter(req,resp);
    }

    @Override
    public void destroy() {

    }
}
  • 配置
<filter>
    <filter-name>login</filter-name>
    <filter-class>com.yogie.lesson.filter.LoginFilter</filter-class>
    <init-param>
        <param-name>outs</param-name>
        <!--除了这两个资源,其他都要验证权限-->
        <param-value>index.html,login</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>login</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 登录的servlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet{

    StudentDao dao = new StudentDaoImpl();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Student stu = BeanUtil.getBean(req, Student.class);
        Student stu1 = dao.queryByUsernameAndPassword(stu.getUsername(),stu.getPassword());
        if(stu1!=null){
            //登录成功,将用户名存入session
            req.getSession().setAttribute("NAME_IN_SESSION",stu.getUsername());
            //跳转到系统列表
            resp.sendRedirect("/xx/controller?cmd=query");
        }else{
            //登录失败,返回登录页面
            resp.sendRedirect("/xx/index.html");
        }
    }
}

​ 5、请求分发器。
​ 6、页面伪静态化处理。

2. 过滤器链

​ 多个过滤器链形成的一组过滤器,然后我们在访问最终的资源的时候会经过这一组过滤器,在返回的时候还会经过这一组过滤器。过滤器链的执行顺序是按照filter-mapping的顺序执行的。

3. FilterConfig对象

String getFilterName();  获取filter的名称(配置的name)。
ServletContext getServletContext();  获得web项目的上下文对象。
String getInitParameter(String var1);  根据参数名获取filter配置中的init-param的value。
Enumeration<String> getInitParameterNames();  获取所有参数配置的name。

4. 特殊的请求过滤

4.1 请求转发过滤

<filter-mapping>
    <filter-name>a</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

4.2 重定向过滤

<filter-mapping>
    <filter-name>b</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REDIRECT</dispatcher>
</filter-mapping>

4.3 默认情况

<filter-mapping>
    <filter-name>b</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

5. 监听器

在web中,监听器的监听内容一般有:
1、监听四大作用的生命周期(主要是创建与销毁)。
2、监听作用域属性的变化(主要是增删改查)。

5.1 作用域监听器接口

ServletRequestListener  -> 对request作用域监听器
HttpSessionListener     -> 对session作用域监听器
ServletContextListener  -> 对application作用域监听器
ServletRequestAttributeListener  -> 对request作用域的属性监听器
HttpSessionAttibuteListener      -> 对session作用域的属性监听器
ServletContextAttributeListener  -> 对application作用域的属性监听器

需要创建哪一种监听器,就去实现对应的接口。

5.2 监听器的配置

<listener>
	<listener-class>com.yogie.filter.MyFilter</listener-class>
</listener>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章