男儿西北有神州,莫滴水西桥畔泪

1. 过滤器

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

英文 Filter

1) 定义过滤器

@WebFilter(urlPattern="要过滤哪些路径")
class 过滤器类 implements Filter {

    // 初始化操作
    public void init() { }

    // 销毁操作
    public void destroy() { }

    // 过滤方法 子类对象 子类对象 过滤器链
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain ) throws ... {
        // 要统一执行的代码
        //chain.doFilter(request, response); // 调用此方法,让请求继续前进
    }
}

2) 过滤路径格式

  1. 精确匹配 /servlet1, 只会进入servlet1之前进入过滤器
  2. 后缀匹配 *.jsp , 只要请求的后缀是 jsp 结尾的,就会进入过滤器
  3. 前缀匹配 /user/* , 例如 /user/insert /user/update, 都会经过此过滤器

只要过滤器的路径与目标路径匹配,这个过滤器就会被执行,因此,在请求前进的过程中会经过多个过滤器

顺序和过滤器的名字有关, 按名字排序

3) request和response的类型转换

filter中的request,response 声明的是父类型,有些方法没有,需要转为子类型对象(实际就是子类对象,可以安全转换)

HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;

4) 过滤器的应用

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

  2. 登录检查过滤器 (见 cookie和 session的代码)
    /*
    req.getRequestURI 排除一些特殊的路径

    /user/insert.jsp
    重定向到 index.jsp 如果没有加/ 是相对路径
    http://localhost:8080/user/index.jsp

    如果加了 / ,就是相对于主机名和端口号 也就是直接在路径前加 http://localhost:8080

    结论:如果路径中有多层目录,建议以 / 写一个完整路径

  3. cookie 自动登录过滤器

在 LoginServlet 中登录成功后,补充代码

// 如果勾选了 自动登录
String autoLogin = req.getParameter("autoLogin");
if(autoLogin != null && autoLogin.equals("true")) {
    Cookie cookie = new Cookie("up", username + ":" + password);
    cookie.setMaxAge(24 * 3600);
    resp.addCookie(cookie);
}

在 LoginFilter 过滤器中补充代码:

// 找到 up cookie
Cookie[] cookies = req.getCookies();
Cookie up = null;
for(Cookie c : cookies) {
    if (c.getName().equals("up")) {
        up = c;
        break;
    }
}
if(up != null) {
    String[] split = up.getValue().split(":");
    String name = split[0];
    String password = split[1];
    // 验证cookie 用户名密码是否正确
    User user = userDao.findByUsername(name);
    if(user!=null && user.getPassword().equals(password)) {
        // 正确了,向 session中存入登录标记并放行
        req.getSession().setAttribute("username", username);
        chain.doFilter(req, resp);
        return;
    }
}

在注销时:

// 删除 自动登录 cookie
Cookie up = new Cookie("up", "");
up.setMaxAge(0);
resp.addCookie(up);

2. ***

Listener 没有路径,特定事件发生时,会执行***代码

  • ServletRequestListener 在请求对象初始化和销毁时

  • HttpSessionListener 在 session 对象创建后和销毁时

  • ServletContextListener application 对象创建和销毁时

  • ServletRequestAttributeListener 请求中作用域变量发生改变时

  • HttpSessionAttributeListener session 中作用域变量发生改变时

  • ServletContextAttributeListener application 中作用域变量发生改变时

  • HttpSessionActivationListener 在session 钝化(内存存入磁盘)和活化(从磁盘恢复到内存)
    session 中存储对象,对象要实现 Serializable 接口

  • HttpSessionBindingListener