- Servlet,Filter,Listener称为JavaWeb的三大组件
- Filter:过滤器
1. web过滤器:
-- 当浏览器访问服务器资源时,过滤器可以将请求拦截下来,并可以增加其一些特殊功能
2. 过滤器作用:完成一些访问资源的通用操作
* 一般用于完成登陆校验功能,只有登陆过后才能看到其他资源
* 可以用于设置编码功能
* 敏感字符过滤
3. 实现过滤器步骤:
a. 自定义一个类,实现接口Filter
-- 组件servlet实现接口Servlet
-- 选择javax.servlet.*包下的Filter
b. 实现接口中的抽象方法
-- init:服务器启动时执行唯一一次 -- 一般用于申请加载资源
-- doFilter:实现过滤器的特殊功能,每有一次请求被拦截时,调用一次该方法
-- destroy:服务器正常关闭时,调用该方法 -- 一般用于释放资源
c. 配置过滤拦截路径
* 使用注解配置@WebFilter("servlet的urlPattern")
-- 在注解中添加urlPattern后,表示当访问该资源时,过滤器将起作用
例如:"/index.jsp" "/demoServlet"
-- "/*"表示拦截所有的资源请求
* web.xml中配置
1. 先声明filter
<filter>
<filter-name>demo1_filterName</filter-name>
<filter-class>过滤器类名的全路径</filter-class>
</filter>
2. 映射拦截路径
<filter-mapping>
<filter-name>demo1_filterName</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-- url-pattern表示拦截的路径
d. 拦截与放行请求:
-- 如果没有执行放行语句,则默认就是拦截下来
-- 在实现抽象方法doFilter中进行放行操作:
filterChain.doFilter(servletRequest, servletResponse);
4. 过滤器执行流程
a. 在doFilter成员方法中执行放行前操作:
* 一般对到来的request中存储的数据进行判定
* 因此,放行前操作一般是对请求进行增强操作
sout("放行前,被拦截了的操作!");
b. 在doFilter成员方法合适位置进行放行操作:
filterChain.doFilter(servletRequest, servletResponse);
-- 此时,请求到达资源,如果资源文件中有jsp脚本,则执行其中代码
c. 在doFilter成员方法中执行放行后操作:
* 放行后操作:指请求到达服务器后,服务器做出响应,此时响应再次经过Filter
* 此时,响应不再执行放行前操作,而是执行放行后操作
* 因此,放行后操作一般是对响应进行增强操作
5. Filter的拦截路径和拦截方式:
a. 拦截路径:
1. 具体路径:"/index.jsp"
只有访问该路径的具体资源时,过滤器才起作用
2. 目录拦截:"/user/*"
访问该目录下的所有资源时,过滤器被执行
-- 给不同的servlet(可以在不同的目录下)加上相同的urlPattern父目录,则表示这些servlet在同一目录下
-- 此时,访问该servlet资源时,同样需要加上该虚拟父目录
例如:
@WebServlet("/user/testServlet")
public class TestServet extends HttpServlet{}
@WebServlet("/user/demoServlet")
public class DemoServet extends HttpServlet{}
3. 后缀名拦截:"*.jsp"
访问所有jsp后缀资源时,过滤器被执行
4. 拦截所有:"/*"
访问所哟资源时,过滤器被执行
b. 拦截方式:
拦截方式配置:指对资源被访问的方式进行过滤拦截
-- 例如:浏览器直接请求访问,服务器内部转发
-- 配置拦截方式后,仅拦截通过该方式的资源访问
1. 拦截方式的属性:
* 注解配置:
a. 设置dispatcherTypes属性值:
1. REQUEST:默认值。浏览器直接访问资源
2. FORWARD:转发访问资源
3. INCLUDE:包含访问资源
4. ERROR:错误跳转资源 -- 即如果在jsp页面中设置了isErrorPage会发生错误跳转时过滤器生效
5. ASYNC:异步访问资源
b. dispatcherTypes属性值是一个数组,可以同时设置多个拦截方式{REQUEST,FORWARD}
* web.xml配置:
a. 配置<filter></filter>标签
b. 配置<filter-mapping></filter-mapping>标签
c. 在filter-mapping标签内添加<dispatcher></dispatcher>标签并设置拦截方式
6. 过滤器链(多个过滤器叠加)
a. 执行顺序:
1. 如果有多个过滤器Filter_1, Filter_2, ... Filter_n
2. 过滤器拦截时,依次执行Filter_1, Filter_2, ... Filter_n的放行前操作
3. 所有过滤器Filter_1, Filter_2, ... Filter_n都放行后,访问到资源
4. 请求返回时,依次执行Filter_n, ... Filter_2, Filter_1的放行后操作
b. 过滤器优先级
1. 注解配置:
* 按照类名的字符串比较规则比较,较小者优先执行
例如:AFilter先于BFilter先执行
2. web.xml配置:
* 哪个过滤器的filter-mapping定义在上面哪个先执行
- 增强对象功能:
1. 装饰者模式:
2. 代理模式:
a. 静态代理:
有明确的代理类文件定义
b. 动态代理:
代理类仅存在于内存中
1. 创建代理对象与真实对象需要实现的共同接口
2. 创建真实对象,实现该接口
3. 创建代理对象:
* 调用内置Proxy.newProxyInstance()成员方法创建一个代理对象
* 成员方法需要传入三个参数:
1. 真实对象的类构造器:真实对象.getClass().getClassLoader()
2. 真实对象实现的抽象接口:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler() {}
4. 实现匿名内部类(处理器)的成员方法,用于增强真实对象
* public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强的内容
}
* 处理器的成员方法三个参数:
1. 代理对象自身:proxy
2. 代理对象调用的成员方法:method -- 利用反射实现,将成员方法封装为一个Method对象
3. 代理对象调用成员方法的参数:args
5. 使用Proxy创建的代理对象调用接口中定义的方法
* 每次调用成员方法都会执行依次处理器中的invoke成员方法
* 增强逻辑都将写在invoke成员方法中
Object obj = method.invoke(真实对象, args);
代理对象调用哪个成员方法,在处理器的invoke成员方法中,就会利用反射实现真实对象使用args参数执行相同的method成员方法
obj为真实对象执行完成员方法的返回值
处理器中invoke成员方法的返回值,应该返回真实对象成员方法的返回值obj
3. 增强方式:
a. 增强参数列表
1. 在invoke方法中对args参数进行修改
2. 对明确的参数对象修改时进行强转修改
b. 增强返回值
1. 在invoke方法在,对method.invoke(真实对象, args)的返回值进行修改
2. 对明确的返回值对象进行修改时进行强转修改
c. 增强方法体
1. 在invoke方法中,在method.invoke()调用前后进行增强逻辑的书写
d. 增强方法名
由于每一次调用成员方法都会调用一次invoke方法
对于不同的成员方法不需要不同的增强时,需要在invoke中对method.getName()进行判定,再区分增强
4. 例如:增强过滤器中的getParameter方法,用于敏感词过滤
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1. 创建代理对象
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), (proxy, method, args) -> {
//2. 增强getParameter方法
if (method.getName().equals("getParameter")) {
//3. 增强返回值,进行敏感词替换
String words = (String) method.invoke(req, args);
for (String s : list) {
if (words.contains(s)) {
words.replaceAll(s, "***");
}
}
return words;
}
//3. 增强getParameterMap方法,过滤从map中获取的值
...
//4. 增强getParamterValue方法,过滤从数组中获取的值
...
//调用其他成员方法时,原封返回
return method.invoke(req, args);
});
chain.doFilter(proxy_req, resp);
}