Filter:过滤器
生活中的过滤器:净水器,空气净化器。
web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
过滤器的作用:一般用于通用的操作。如登录验证、统一编码处理、敏感字符过滤…
快速入门
步骤:
- 定义一个类,实现接口Filter
- 复写方法
- 配置拦截路径
- web.xml
- 注解
代码:
url-pattern原是@WebFilter中的,也为value,只有一个值,可省略
@WebFilter("/*")//访问所有资源之前都会执行该过滤器
public class FilterDemo1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//放行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
过滤器细节
web.xml配置
<filter>
<filter-name>demo1</filter-name>
<filter-class>cn.huangyy.web.filter.FilterDemo1</filter-class>
</filter>
<filter-mapping>
<filter-name>demo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器执行流程
- 执行过滤器
- 执行放行后的资源
- 回来执行过滤器放行代码下边的代码
过滤器的生命周期
init:
在服务器启动后,会创建Filter对象,然后调用init方法。用于加载资源
doFilter:
每次请求被拦截资源时,会执行。执行多次。
destroy:
在服务器关闭后,Filter对象被销毁。如果正常关闭,会执行destroy方法。用于释放资源
过滤器配置详解
拦截路径配置
- 具体资源路径:
/index.jsp
,只有访问index资源时,过滤器才会被执行。 - 拦截目录:
/user/*
,访问/user下的所有资源时,过滤器都会被执行 - 后缀名拦截:
*.jsp
,访问所有后缀名为jsp的资源时,过滤器都会被执行 - 拦截所有资源:
/*
拦截方式配置:资源被访问的方式
-
注解配置
设置dispatcherTypes属性
REQUEST:默认值。浏览器直接请求资源
FORWARD:转发访问资源
INCLUDE:包含访问资源
ERROR:错误跳转资源
ASYNC:异步访问资源 -
web.xml配置
设置dispatcher标签,也有五个
过滤器链(配置多个过滤器)
执行顺序:
如果有两个过滤器:过滤器1和过滤器2
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
过滤器先后顺序问题:
注解配置的,按照类名字符串比较规则比较,值小的先执行。
web.xml配置的,谁定义在上面,谁就先执行
案例:
1.登录案例
@WebFilter("/*")
public class LoginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request= (HttpServletRequest) req;
String uri = request.getRequestURI();
if (uri.contains("/login.jsp")||uri.contains("/loginServlet")||
uri.contains("/css/")||uri.contains("/js/")||uri.contains("/fonts/")||uri.contains("/checkCodeServlet")){//要注意css/js/图片/验证码等资源
chain.doFilter(req, resp);
}else {
Object user = request.getSession().getAttribute("user");
if (user!=null){
chain.doFilter(req,resp);
}else {
request.setAttribute("login_msg","您尚未登录,请登录");
request.getRequestDispatcher("/login.jsp").forward(request,resp);
}
}
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
2.敏感词汇
功能增强,可用代理模式
- 真实对象:被代理的对象
- 代理对象
- 代理模式:代理模式代理真实对象,达到增强真实对象功能的目的
静态代理:有一个类文件描述代理模式
动态代理:在内存中形成代理类
实现步骤:
代理对象和真实对象实现相同的接口
代理对象=Proxy.newInstance();
使用代理对象调用方法
增强方式:
增强参数列表
增强返回值类型
增强方法体执行逻辑
回到敏感词汇:
对request对象进行增强。增强获取参数相关的方法
放行。传递代理对象
如:
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//创建代理对象,增强getParameter方法
//放行
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getParameter")){
String value = (String) method.invoke(req, args);
if (value!=null){
for (String str:list) {
if (value.contains(str)){
value.replaceAll(str,"***");
}
}
}
return value;
}
return method.invoke(req,args);
}
});
chain.doFilter(proxy_req, resp);
}
private List<String> list=new ArrayList<>();
public void init(FilterConfig config) throws ServletException {
try {
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("?WEB-INF/classes/敏感词汇表.txt");
BufferedReader reader=new BufferedReader(new FileReader(realPath));
String line=null;
while ((line=reader.readLine())!=null){
list.add(line);
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void destroy() {
}
}
Listener监听器
web的三大组件之一。
事件监听机制
事件:一件事情
事件源:事情发生的地方
监听器:一个对象
注册监听:将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码
ServletContextListener
监听ServletContext对象的创建和销毁
void contextDestroyed(ServletContextEvent sce):ServletContext对象被销毁之前会调用该方法
void contextInitialized(ServletContextEvent sce):ServletContext对象创建后会调用该方法
步骤:
定义一个类实现ServletContextListener接口
复写方法
配置
注解:
@WebListener
xml:
还可指定初始化参数
<listener>
<listener-class>cn.huangyy.web.listen.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
如:
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContext=sce.getServletContext();
String contextConfigLocation= servletContext.getInitParameter("contextConfigLocation");
String realPath = servletContext.getRealPath(contextConfigLocation);
FileInputStream fis=new FileInputStream(realPath);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}