Filter
和LIstener
Filter
过滤器
概念:web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
作用:一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
快速入门
步骤:
- 定义一个类,实现接口
Filter
- 重写方法
- 配置拦截路径
web.xml
文件方式- 注解方式
@WebFilter(urlPatterns = {"/*"})//表示拦截的资源路径
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 放行语句
filterChain.doFilter(servletRequest,servletResponse);
System.out.printf("放行后执行了相关的业务代码后,还要回执行过滤器后面的代码");
}
}
web.xml
方式
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.example.javawebServletFilter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<!--表示对所有的资源都进行拦截-->
<url-pattern>/*</url-pattern>
</filter-mapping>
注解方式
@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
过滤器细节
web.xml
配置
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.example.javawebServletFilter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<!--表示对所有的资源都进行拦截-->
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器执行流程
- 执行过滤器
- 执行放行后的业务逻辑
- 回来执行过滤器放行后面的代码
过滤器生命周期
1.web
服务器启动时,就会创建Filter
对象,然后调用init
方法,只执行一次,用于加载资源文件
2.doFilter
方法是每次一次请求都会被拦截资源时,会执行,执行多次
3.destroy
在服务器正常关闭时,Filter
对象被销毁时,就是会执行一次这【注意是正常关闭web
服务器】
过滤器配置详解
拦截路径配置
1.具体资源路径:
/index.jsp 只有访问`index.jsp`资源时,过滤器都会被执行
2.拦截目录
/user/* 访问`/user下的所有资源时,过滤器都会被执行
3.后缀名拦截
*.jsp 访问所有后缀名为`jsp`资源时,过滤器都会被执行
4.拦截所有资源
/* 访问所有资源时,过滤器都会被执行
拦截方式配置:资源被访问方式
方式一:注解配置
设置`dispatcherType`属性
1.REQUEST 默认传下,浏览器直接请求资源
2.FORWARD 转发访问资源
3.INCLUDE 包含访问资源
4.ERROR 错误跳转资源
5.ASYNC 异步访问资源
方式二:web.xml
配置
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.example.javawebServletFilter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<!--表示对所有的资源都进行拦截-->
<url-pattern>/*</url-pattern>
<!--配置拦截的方式-->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
过滤器链(配置多个过滤器)
执行顺序:如果有两个过滤器:过滤器1和过滤器2
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
过滤器先后顺序问题:
1.注解配置:按照类名的字符串比较,值小的先执行
如:AFilter和BFilter, AFilter就先执行了
2.web.xml配置:`<filter-mapping>谁定义在上边,谁先执行
登录验证案例:
需求:
1. 访问day17_case案例的资源。验证其是否登录
2. 如果登录了,则直接放行。
3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。
步骤:
- 编写一个
Filter
过滤器,将所有与登录有关的资源,进行放行,其他的则,不放行 - 再判断该用户是否登录过,如果没有登录过,直接跳转回登录页面
- 如果登录过直接放行
案例—2:敏感词汇过滤
需求:
1. 对day17_case案例录入的数据进行敏感词汇过滤
2. 敏感词汇参考《敏感词汇.txt》
3. 如果是敏感词汇,替换为 ***
分析:
- 由于在访问多个资源时,都需要对敏感词汇进行过滤,需要将
敏感词汇过滤
功能放在过滤器中 - 将请求
request
对象中封装的数据获取出来,进行过滤 - 由于
request
对象没有setParameter
方法,只能getParameter
方法 - 需要对
request
对象进行增强功能,增加的功能就是对敏感词汇进行过滤 - 过滤后,重新将增强
request
对象封装放行
增加对象的功能
设计模式:一些通用解决固定问题方式
1.装饰模式
2.代理模式
代理模式
概念:
- 真实对象:被代理的对象
- 代理对象
- 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
实现方式:
方式一:静态代理:有一个类文件描述代理模式
方式二:动态代理:在内存中形成代理类
动态代理实现步骤:
- 代理对象和真实对象实现相同的接口
- 代理对象
= public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
;` - 使用代理对象调用方法
method.invoke("传入真实对象","参数");
- 增加方法
//2.获取代理对象,调用Proxy类中的newProxyInstance()方法需要传入三个参数
/**
* 三个参数:
* 1. 类加载器:真实对象.getClass().getClassLoader()
* 2. 接口数组:真实对象.getClass().getInterfaces()
* 3. 处理器:new InvocationHandler()
*/
computer sell_Proxy = (computer) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(), new InvocationHandler() {
/**
* 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法的执行
* @param proxy 代理对象
* @param method 代理对象调用的方法,被封装成的对象
* @param args 代理对象调用的方法时,传递的实际参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke是否被调用了");
return null;
}
});
动态代理实现:
接口:
public interface computer {
public String sell(double money);
}
真实对象类:
public class RealObject implements computer{
@Override
public String sell(double money) {
return "卖出的电脑"+money+"钱";
}
}
获取代理对象并调用方法:
public class ProxyObject {
public static void main(String[] args) {
// 实现动态代理步骤
//1.代理对象和真实对象实现相同接口
// 创建真实现对象
RealObject realObject = new RealObject();
//2.获取代理对象,调用Proxy类中的newProxyInstance()方法需要传入三个参数
/**
* 三个参数:
* 1. 类加载器:真实对象.getClass().getClassLoader()
* 2. 接口数组:真实对象.getClass().getInterfaces()
* 3. 处理器:new InvocationHandler()
*/
computer sell_Proxy = (computer) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(), new InvocationHandler() {
/**
* 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法的执行
* @param proxy 代理对象
* @param method 代理对象调用的方法,被封装成的对象
* @param args 代理对象调用的方法时,传递的实际参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke是否被调用了");
return null;
}
});
// 动态代理的特点是:调用接口中的每一个方法都会触发invoke方法的执行
String sell = sell_Proxy.sell(8000);
System.out.printf("sell"+sell);
}
}
动态代理增强功能方式:
- 增加参数列表
- 增加返回值类型
- 增加方法体执行逻辑
public class ProxyObject {
public static void main(String[] args) {
// 实现动态代理步骤
//1.代理对象和真实对象实现相同接口
// 创建真实现对象
RealObject realObject = new RealObject();
//2.获取代理对象,调用Proxy类中的newProxyInstance()方法需要传入三个参数
/**
* 三个参数:
* 1. 类加载器:真实对象.getClass().getClassLoader()
* 2. 接口数组:真实对象.getClass().getInterfaces()
* 3. 处理器:new InvocationHandler()
*/
computer sell_Proxy = (computer) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
realObject.getClass().getInterfaces(), new InvocationHandler() {
/**
* 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法的执行
* @param proxy 代理对象
* @param method 代理对象调用的方法,被封装成的对象
* @param args 代理对象调用的方法时,传递的实际参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 对动态代理功能的增强
* 1.对参数进行参数列表增强
* 2.对返回值进行增强
* 3.对方法体进行增强
*/
// System.out.println("invoke是否被调用了");
// Object invoke = method.invoke(realObject, args);
// return invoke;
// 获取方法名,判断是sell,如果是才进行增强
if (method.getName().equals("sell")){
// 3.对象方体进行增强
System.out.println("您好买电脑不?");
// 1.对参数进行列表增强
double money = (double) args[0];
String invoke = (String) method.invoke(realObject, money);
System.out.println("免费送货到家!");
// 2.对象返回值进行增强
return invoke+"送给您一些礼品";
}else {
String invoke = (String) method.invoke(realObject, args);
return invoke;
}
}
});
// 动态代理的特点是:调用接口中的每一个方法都会触发invoke方法的执行
String sell = sell_Proxy.sell(8000);
System.out.printf("sell"+sell);
}
}
Listener
监听器
概念:web
的三大组件之一
事件监听机制:
- 事件:一件事情
- 事件源:事件发生的地方
- 监听器:一个对象
- 注册监听:将事件,事件源,监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码
ServletContextListener
:
作用:监听ServletContext
对象的创建和销毁
ServletContextListener
监听器是对ServletContext
的创建和销毁进行监听的,
在服务器启动时,创建ServletContext
对象,同时也创建了ServletContexListener
对象,并且调用了ServletContexListener
中的contextInitialzed
方法用于加载一些资源文件
在服务器正常关闭时,ServletContext
被销毁,同时执行ServletContexListener
中的contextDestroyed
方法一般用于释放资源
方法:
void contextDestroyed(ServletContextEvent sce):`servletContext`对象被销毁之前会调用该方法【一般用于释放一些资源】
void contextInitialzed(ServletContextEven sce):`ServletContext`对象创建后会调用该方法【一般用于加载一些资源】
监听器的使用步骤:
-
定义一个类,实现
ServletContexListener
接口 -
重写方法
-
配置
-
web.xml
方式@WebListener//说明该类是监听器,用于监听ServletListener的创建销毁
-
注解方法
<listener> <listener-class>com.example.javawebServletFilter.listener_.ServletListener</listener-class> </listener>
-
案例:
@WebListener//说明该类是监听器,用于监听ServletListener的创建销毁
public class ServletListener implements ServletContextListener {
/**
* 监听ServletContext对象的创建,自动的调用contextInitialized方法
* 用于加载资源文件
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象被创建了,用于加载资源 ");
}
/**
* 用于监听ServletContext对象的销毁
* 用于释放一些资源文件
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁了,用于释放资源");
}
}
<listener>
<listener-class>com.example.javawebServletFilter.listener_.ServletListener</listener-class>
</listener>