web层
Filter
Web核心中一共涉及的三大技术
 Servlet : server applet 服务器端的小程序(主要处理请求响应的部分)
 Filter: 过滤器 , 过滤: 将自己所需要的内容留下 不需要的内容剔除
 Listener : 监听器
概述

需要配置web.xml(重点)
filter创建步骤
- 创建类
- 实现javax.servlet.Filter的规范(接口)
/**
 * 1. 创建类
 * 2. 实现javax.servlet.Filter的规范(接口)
 * 3. 通知tomcat我们配置了过滤器 (web.xml进行配置)
 * 4. 正常编写过滤器的代码即可
 */
public class HelloFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    /**
     * 执行过滤的方法 , 每次执行到过滤器都会执行此方法 相当于servlet的service方法
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("HelloFilter 被执行了 A");
        //放行代码
        filterChain.doFilter(request, response);
        System.out.println("HelloFilter 放行后的代码 B");
    }
    @Override
    public void destroy() {
    }
}
3.通知tomcat我们配置了过滤器 (配置web.xml)
<!--
     <filter> 通知tomcat我们需要增加一个过滤器
        <filter-name>HelloFilter</filter-name>  filter的名称(别名) 整个web.xml中必须唯一
        <filter-class>com.llz.web.a_filter.HelloFilter</filter-class> 过滤器的位置,全限定类名
    </filter>
    <filter-mapping> filter映射路径配置
        <filter-name>HelloFilter</filter-name> 使用别名
        <url-pattern>/DemoServlet</url-pattern> 过滤器的过滤路径
    </filter-mapping>
-->
<filter>
    <filter-name>HelloFilter</filter-name>
    <filter-class>com.llz.web.a_filter.HelloFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HelloFilter</filter-name>
    <url-pattern>/DemoServlet</url-pattern>
</filter-mapping>
4.正常编写过滤器代码即可
filter的执行流程

 过滤器作用:全站编码,过滤非法字符……
filter的创建方式
a.配置web.xml
 b.@WebFilter注解
/**
 * 1.创建类
 * 2.实现javax.servlet.Filter 接口
 * 3.配置web.xml
 *     <filter>
 *         <filter-name>XmlFilter</filter-name>
 *         <filter-class>com.llz.web.b_filter.XmlFilter</filter-class>
 *     </filter>
 *     <filter-mapping>
 *         <filter-name>XmlFilter</filter-name>
 *         <url-pattern>/DemoServlet</url-pattern>
 *     </filter-mapping>
 *     给Filter一个拦截路径
 * 4.编写放行代码
 */
@WebFilter(urlPatterns = "/DemoServlet")
public class AnnoFilter implements Filter {
过滤器的其他知识点
生命周期
含义:类什么时候创建 什么时候销毁
 init :在项目启动就执行(只执行一次) : servlet默认情况下是第一次访问servlet才初始化
 doFilter:每次访问只要被拦截 必然执行该方法 每一次都执行
 destroy :项目停止时 执行销毁 只执行一次
拦截路径的配置
servlet的url-pattern设置 , 访问到servlet入口 (四种)
 完全匹配: /a/b/c/Servlet
 不完全匹配(目录匹配): /a/b/c/*
 后缀名匹配: *.jsp *.html *.do *.abc
 缺省匹配: / 以上三种都没有匹配成功 执行默认的缺省匹配(tomcat里面有默认设置 404 )
filter的拦截路径设置 只有三种(匹配到 就进行拦截)
 完全匹配: /a/b/c/Servlet
 不完全匹配(目录匹配): /a/b/c/*
 后缀名匹配: *.jsp *.html *.do *.abc
 filter没有缺省匹配
拦截方式配置(使用默认的即可)
过滤器执行时机
 
 REQUEST: 默认值 , 表示请求开始就进行拦截
 
 FORWARD: 请求转发进行拦截
<filter>
     <filter-name>MyDispatcherFilter</filter-name>
     <filter-class>com.llz.web.d_dispatcher.MyDispatcherFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>MyDispatcherFilter</filter-name>
     <url-pattern>/DemoServlet</url-pattern>
     <!--配置filter拦截的时机, 默认值: REQUEST-->
     <!--FORWARD: 请求转发时进行拦截-->
     <dispatcher>FORWARD</dispatcher>
 </filter-mapping>

过滤器链
服务器中允许存在多个过滤器 , 这一组过滤器 称之为叫过滤器链
 过滤器链xml , 执行的顺序问题 ,xml方式中 是 web.xml自上而下 filter的配置顺序就是执行顺序
 过滤器链注解Filter执行顺序问题 : 类名决定顺序
filter的创建方式优缺点
xml :
  优点: 配置清晰 解耦(解除耦合,代码关联度) 利于修改(所有的内容都在一起)
  缺点: 配置麻烦 , 要编写大量的内容 表示一段配置
注解:
  优点: 简单使用 不需要大量的配置
  缺点: 不利于修改 每个类中嵌入的注解(耦合度太高) 建议使用注解的类不应该经常修改
全站编码
/**
 * 注意事项:
 * 1.urlPatterns = "/*" 对服务器中所有的资源都进行处理
 * 2.必须有放行 不能够影响原来的业务逻辑
 * chain.doFilter(req, resp);
 */
@WebFilter(filterName = "EncodingFilter" , urlPatterns = "/*")
public class EncodingFilter implements Filter {
    public void destroy() {
    }
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("过滤器执行了");
        //处理请求响应编码
        req.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //必须有放行 不能够影响原来的业务逻辑
        chain.doFilter(req, resp);
    }
    public void init(FilterConfig config) throws ServletException {
    }
}
filter过滤非法字符
@WebFilter(filterName = "IllEgalFilter",urlPatterns = "/*")
public class IllEgalFilter implements Filter {
    //存储脏字字符 -- 提升作用于 让多个方法都可以使用
    List<String> list = new ArrayList<String>();
    /**
     * 初始化方法: 将脏字的集合 在此处初始化 一次即可
     */
    public void init(FilterConfig config) throws ServletException {
        //存储脏字字符
        //List<String> list = new ArrayList<String>();
        list.add("大爷");
        list.add("曰");
        list.add("你 女未");
    }
    /**
     * 1.准备处理脏字的List集合 - 在init初始化的 因为只初始化一次
     * 2.在doFilter 先获得 字符
     * @param req
     * @param resp
     * @param chain
     * @throws ServletException
     * @throws IOException
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //强转对象 : 使用熟悉的对象
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("textml;charset=utf-8");
        //1.拿到请求字符
        String username = request.getParameter("username");
        System.out.println("filter中未被处理的username:" + username);
        //2.遍历脏字的字符集
        for (String word : list) {
            //3.判断 请求的字符是否含有脏字 , 必须是每一种脏字都判断
            if(username.contains(word)){//contains 包含  大爷去跳广场舞 大爷  曰  你妹
                username = username.replaceAll(word  , "*");
            }
        }
        System.out.println("filter中已经处理的username:" + username);
        //传入的对象是我们转换以后的对象
        chain.doFilter(request, response );//放行
    }
    public void destroy() {
    }
}
上述代码问题
问题的产生 : request.getParameter(“key”) 获得的是原始的数据,执行chain.doFilter(request, response )放行时还是会将脏字带过去。(即未起到我们想让它起到的效果)
 解决方法:只要复写request.getParameter 方法即可 (修改代码逻辑)
 
 解决方案:tomcat已经考虑到这个问题了 所以已经提供了一个 HttpServletRequest对象的实现类。
 要求 :我们创建类 必须继承 , 但是必须提供有参构造。重写我们需要执行我们自己逻辑的方法,其他方法直接调用父类方法 (这就是包装思想)
包装类代码
public class MyHttpServletRequest extends HttpServletRequestWrapper{
    //非法字符准备的数据
    List<String> list = new ArrayList<String>();
    HttpServletRequest request2 ; //在自己本类中可以使用request对象
    public MyHttpServletRequest(HttpServletRequest request) {
        super(request); //传入到父类 所有的代码 全部实现(这里不需要复写的代码 父类全部已经完成)
        this.request2 = request;
    }
    //不需要复写的代码 父类全部已经完成
    //考虑需要被复写的代码
    @Override
    public String getParameter(String name) {
        //准备数据
        list.add("大爷");
        list.add("曰");
        list.add("你 女未");
        //System.out.println("MyHttpServletRequest-->getParameter被执行了");
        if(name==null || "".equals(name)){//防止代码错误 参数传递错误
            return null; //后续代码不再执行
        }
        //获得原来的数据
        String oldParameter = request2.getParameter(name);
        if(oldParameter==null || "".equals(oldParameter)){//防止代码错误 参数传递错误
            return null; //后续代码不再执行
        }
        //逻辑代码 -> 一定是有参数 并且 已经获得请求的数据
        for (String word : list) {
            //if(oldParameter.contains(word)){
                oldParameter = oldParameter.replaceAll(word , "*");
            //}
        }
        //只要最后返回的值是处理过后的字符串 效果达到
        return oldParameter;
    }
 }
修改之前的filter类
WebFilter(filterName = "IllEgalFilter",urlPatterns = "/*")
public class IllEgalFilter implements Filter {
    public void init(FilterConfig config) throws ServletException {
    }
    /**
     * 1.准备处理脏字的List集合 - 在init初始化的 因为只初始化一次
     * 2.在doFilter 先获得 字符
     * @param req
     * @param resp
     * @param chain
     * @throws ServletException
     * @throws IOException
     */
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //强转对象 : 使用熟悉的对象
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        //自己定义的request 对方法进行修改了
        MyHttpServletRequest myHttpServletRequest = new MyHttpServletRequest(request);
        //传入的对象是我们转换以后的对象
        chain.doFilter(myHttpServletRequest, response );//放行
    }
    public void destroy() {
    }
}










