过滤器
1
什么是过滤器
在生活中有很多跟过滤相关的东西:净水器,空气净化器这些都可以称为过滤器;他们主要的作用就是过滤杂质的。
在web项目中:当客户端的请求到达服务器的时候,这个请求可以被过滤器拦截下来,过滤器就可以针对这个请求进行一系列过滤操作。最后可以选择是否放行这个请求,如果选择了放行,那么这个请求就可以到达目标资源(servlet html css 图片等资源),目标资源处理完成后会给客户端响应,这个响应又会经过一次过滤器
过滤器的作用
一般来说就是用来处理,登录校验,编码处理,处理敏感字符等
能够统一处理的一般都可以选择交给过滤器处理
类似于进门 与出门
1
过滤器的执行流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BSOEAQet-1681801915116)(servlet.assets/image-20220412105152584.png)]
过滤器的实现
定义一个类,实现Filter接口
实现接口中的方法
配置过滤器:xml配置或注解配置
xml配置
实现乱码处理
package com.zlt.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class CharsetFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init");
}
/**
* 执行过滤的方法
* @param req
* @param resp
* @param chain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
if("get".equalsIgnoreCase(request.getMethod())){
request = new MyRequest(request);
} else if("post".equalsIgnoreCase(request.getMethod())){
request.setCharacterEncoding("UTF-8");
}
//放行 方法之前是目标方法之前执行 方法之后是目标方法之后执行 不写这个方法目标方法就不会执行
chain.doFilter(request,resp);
System.out.println("after");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
在web.xml中进行配置
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="false">
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>charset</filter-name>
<filter-class>com.zlt.filter.CharsetFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>charset</filter-name>
<!--决定了哪些请求会经过这个过滤器-->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
注解配置
//用户登录校验
package com.zlt.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@WebFilter(value = "/*",initParams = @WebInitParam(name="uris",value = "/user/update,/user/updateDo"))
public class LoginFilter implements Filter {
private List<String> uris;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//可以获取初始化参数
String s = filterConfig.getInitParameter("uris");
uris = Arrays.asList(s.split(","));
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String requestURI = req.getRequestURI();// /userManager/user/update
requestURI = requestURI.substring(req.getContextPath().length());
if(uris.contains(requestURI)){
Object cur_user = req.getSession().getAttribute("CUR_USER");
if(cur_user == null){
resp.sendRedirect("/userManager/user/login");
return;
}
}
chain.doFilter(req,response);
}
@Override
public void destroy() {
}
}
过滤器的细节
注解配置过滤器需要servlet3.0及以上的版本
xml配置是没有版本限制的
<filter-mapping>
<filter-name>charset</filter-name>
<!--决定了哪些请求会经过这个过滤器-->
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
dispatcher 配置
FORWARD 转发到对应的资源
INCLUDE 当一个资源包含另一个资源的时候,加载另一个资源会经过过滤器 主要用于动态包含
REQUEST 默认值 浏览器请求资源的时候
ASYNC 异步访问的时候
ERROR 错误跳转到资源的时候
拦截配置 url-pattern
/user 只会拦截 /user
/user/* 拦截user下面的所有请求
*.jsp 只会拦截jsp页面
/* 拦截所有请求
过滤器的执行流程
1.请求到达服务器的时候先执行过滤器
2.过滤器的doFilter方法是在执行过滤
3. chain.doFilter(req,response); 是在执行目标资源
4.chain.doFilter(req,response); 之后的代码是目标资源执行完成在响应之前会执行的东西
5.如果有多个过滤器就会组成过滤链
过滤链的顺序
xml顺序 <filter-mapping> 谁在前谁先执行
注解顺序 按类名字母顺序 AFilter 会比BFilter先执行
假设有两个过滤器 AFilter BFilter
1. AFilter
2. BFilter
3. 目标资源
4. BFilter
5. AFilter
过滤器的生命周期
服务器启动的时候创建对象 执行一次init方法
请求到达过滤器就执行doFilter 方法执行过滤 每个请求会执行一次
服务器关闭的时候对象销毁 销毁之前会执行一次destroy方法
错误页面配置
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/404.html</location>
</error-page>
监听器
1
监听器也是三大组件之一
事件监听机制
事件源 事件发生的地方
事件对象 事件发生的各种信息
事件监听器 事件发生后的处理方法
对于web程序而言,事件监听器主要分为如下几种
对于三种作用域的监听
监听作用域的创建与销毁
ServletRequestListener 监听request的创建与销毁
public void requestDestroyed(ServletRequestEvent sre); 监听request的销毁 请求结束了
public void requestInitialized(ServletRequestEvent sre); 监听request的创建 接收新的请求
HttpSessionListener 监听session的创建与销毁
public void sessionCreated(HttpSessionEvent se); session的创建 会话的新建
public void sessionDestroyed(HttpSessionEvent se); session的销毁 会话的关闭
ServletContextListener 监听上下文的创建和销毁
public void contextInitialized(ServletContextEvent sce); 上下文的初始化 服务器启动
public void contextDestroyed(ServletContextEvent sce); 上下文的销毁 服务器关闭
监听作用域的数据改变 一般三个方法 添加 删除 替换
ServletRequestAttributeListener
HttpSessionAttributeListener
ServletContextAttributeListener
public void attributeAdded(ServletRequestAttributeEvent srae); 作用域中数据的添加
public void attributeRemoved(ServletRequestAttributeEvent srae); 数据的删除
public void attributeReplaced(ServletRequestAttributeEvent srae); 数据的替换
实现一个监听器一般根据需要实现上面6个接口中的一个或多个,然后进行配置即可
利用监听器实现在线人数统计
先监听服务器的启动,放入初始数字到上下文对象中
package com.zlt.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//先获取到servletContext的对象
System.out.println("application创建成功");
sce.getServletContext().setAttribute("onLineCount",0);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
xml配置监听器
<listener>
<listener-class>com.zlt.listener.MyServletContextListener</listener-class>
</listener>
登录成功后需要将在线人数+1
//登录成功
HttpSession session = request.getSession();
session.setAttribute("CUR_USER",user);
Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setPath("/userManager");
cookie.setMaxAge(60 * 60);
response.addCookie(cookie);
//在线人数+1
int onLineCount = (int) request.getServletContext().getAttribute("onLineCount");
request.getServletContext().setAttribute("onLineCount",onLineCount + 1);
response.sendRedirect("/userManager/user/main");
监听session的销毁
package com.zlt.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionBindingEvent;
@WebListener
public class MySessionListener implements HttpSessionListener {
// Public constructor is required by servlet spec
public MySessionListener() {
}
// -------------------------------------------------------
// HttpSessionListener implementation
// -------------------------------------------------------
public void sessionCreated(HttpSessionEvent se) {
/* Session is created. */
}
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
// session销毁的时候如果里面有CUR_USER 则表示离线了
Object cur_user = se.getSession().getAttribute("CUR_USER");
if(cur_user != null){
ServletContext servletContext = se.getSession().getServletContext();
int onLineCount = (int) servletContext.getAttribute("onLineCount");
servletContext.setAttribute("onLineCount",onLineCount - 1);
}
}
}
1
d());
cookie.setPath(“/userManager”);
cookie.setMaxAge(60 * 60);
response.addCookie(cookie);
//在线人数+1
int onLineCount = (int) request.getServletContext().getAttribute(“onLineCount”);
request.getServletContext().setAttribute(“onLineCount”,onLineCount + 1);
response.sendRedirect(“/userManager/user/main”);
监听session的销毁
```java
package com.zlt.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.servlet.http.HttpSessionBindingEvent;
@WebListener
public class MySessionListener implements HttpSessionListener {
// Public constructor is required by servlet spec
public MySessionListener() {
}
// -------------------------------------------------------
// HttpSessionListener implementation
// -------------------------------------------------------
public void sessionCreated(HttpSessionEvent se) {
/* Session is created. */
}
public void sessionDestroyed(HttpSessionEvent se) {
/* Session is destroyed. */
// session销毁的时候如果里面有CUR_USER 则表示离线了
Object cur_user = se.getSession().getAttribute("CUR_USER");
if(cur_user != null){
ServletContext servletContext = se.getSession().getServletContext();
int onLineCount = (int) servletContext.getAttribute("onLineCount");
servletContext.setAttribute("onLineCount",onLineCount - 1);
}
}
}
1