提前阅读:https://blog.csdn.net/Su_Levi_Wei/article/details/50665835
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■↓↓↓↓↓↓↓↓↓ Servlet过滤器 ↓↓↓↓↓↓↓↓↓↓↓■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
Servlet过滤器;
为什么要有?
如果有N多个Servlet要执行一样的操作的时候,
没有必须要在所有的Servlet都进行相同的代码操作,
那样会造成代码冗余性变大,也会使得开发效率低下。
是什么?
是Servlet中的三大组件之一,是由SUN公司制定的标准/接口
过滤器的本质就是一个java应用中的一个对象而已。。。。。。
作用;
过滤器可以在一个请求资源【动态或静态】的资源时,
或者是在响应资源时,执行过滤任务【代码逻辑】
◆ 因为是在Serlvet业务逻辑之前执行的,
所以可以进行一些关键的操作,
用于提高用户体验,以及提高开发效率
因为没有必须都写在所有要使用
这个业务逻辑代码的Servlet中写,
只是需要把对应的Servlet和
服务器进行关联
如;1.在请求资源和响应资源的时候所有Servlet的编码集
2.用户统一登录的权限,就是只有用户登录了才可以进行访问某些资源。
特点;
需要在web.xml文件中配置
运行在web服务器中
◆在进行Servlet业务逻辑的之前执行的
-----------------------------------↓↓↓↓↓↓↓Servlet过滤器 —— 开发步骤↓↓↓↓↓↓↓------------------------------------------------
Serlvet过滤器开发步骤;
1.编写一个自定义类,实现Filter接口
2.重写doFilter()核心过滤器方法
代码;
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain){
}
3.在doFilter()方法写需要进行过滤的业务逻辑代码
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
4.使用FilterChain接口的doFilter方法放行 ---> (类似转发)
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain){
chain.doFilter(request,response);
}
5.在web.xml文件中配置过滤器
--------------------------------↓↓↓↓↓↓↓Servlet过滤器 —— 运行过程↓↓↓↓↓↓↓------------------------------------------------
过滤器运行过程;
1.在服务器启动加载所有的*.tld文件和web.xml文件的时候
就创建了一个过滤器的对象,而且只创建一次,所以是一个单例的
方法;
会调用Filter接口的init()方法 ---> Filter接口
可以通过这个方法的FilterConfig对象获取到
web.xml文件的<init-param>信息
2.当用户访问与过滤器关联的Servlet的时候会先到过滤器,
的doFilter方法执行过滤器的业务逻辑代码,
在这时是否允许访问Servlet则是由过滤器代码决定的。
a)过滤器逻辑代码通过了允许访问对应的Servlet,---> FiilterChain接口
那么则会调用FiilterChain接口的doFilter方法,
将用户访问的request和response请求带到对应的Servler中
◆◆ b)当访问了Servlet资源之后要将响应信息返回,
给用户不是直接返回的,而是通过过滤器返回的
方法;
访问与过滤器关联的Servlet的时候都会调用doFilter方法 ---> Filter接口
3.过滤器对象销毁,或者是服务器正常关闭
方法;
destroy()
◆◆◆◆◆注;过滤器对象是一个单例的,
过滤器也是一个双向过滤,
◆ 因为请求和响应都需要经过过滤器。
--------------------------------↓↓↓↓↓↓↓Servlet过滤器 —— 过滤器链↓↓↓↓↓↓↓------------------------------------------------
过滤器链;
某一个Servlet资源被多个过滤器进行过滤叫做过滤器链。
FilterChain;是一个过滤器类的主要对象
使用执行下一个过滤器
如果当前的过滤器是最后一个过滤器则执行目标资源
也是通过这个接口的doFilter()方法把用户的请求信息和响应信息返回给用户端
--------------------------------↓↓↓↓↓↓↓Servlet过滤器 —— Web文件配置↓↓↓↓↓↓↓------------------------------------------------
过滤器web.xml文件配置;
<filter>
<filter-name>自定义标识唯一名</filter-name>
<filter-class>过滤器绝对路径【包名+类名】</filter-class>
<〓
<init-param>是设置过滤器的初始化过滤参数的
〓>
<init-param>
<param-name>参数名</param-name>
<param-value>参数值</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>对应的唯一标识名</filter-name>
<〓--
1、url-pattern;是指定需要过滤的serlvet路径
精确过滤;/x ---> http://localhost:8080/xx/xx
模糊过滤;/* ---> http://localhost:8080/xx/yy
/包名/* ---> http://localhost:8080/包名/xx
* ---> http://localhost:8080/xx/xx
*.do ---> http://localhost:8080/xx/xx.do
*.html
。。。
◆◆◆注;在进行模糊过滤查询的时候,
需要是符合url-pattern的语法的时候,
则会执行过滤器,无论是否存在的Servlet
【个人看法】建议不使用模糊过滤,即便写100个url-pattern,
因为耗费服务器资源,过滤器是在服务器执行的
2、servlet-name;是可以根据对应的Servlet在web.xml配置
的name属性值进行关联
3、dispatcher;是设置要进行过滤的请求类型
a_)request是设置过滤请求信息 ---> 默认
b_)include是设置过滤包含信息
c_)forword是设置过滤转发信息
d_)error是设置过滤错误信息 ---> 触发<error-page>标签
--〓>
<url-pattern>/过滤的Servlet</url-pattern>
<servlet-name>对应的servlet配置名</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWOED</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<〓--
这个是发生错误的时候,触发的
--〓>
<error-page>
<error-code>500</error-code> ---> 设置发生错误的码号
<location>/地址</location> ---> 发生错误要进行跳转的地址
</error-page>
■■■■■■■■■■■■■■■■■■■--------------------------↓↓↓↓↓↓↓ 装饰者模式 ↓↓↓↓↓↓↓-------------------------■■■■■■■■■■■■■■■■■■■■
装饰者模式;
是用于对一个类的特定方法进行增强的,
而这个类只会是实体类,基本不会是抽象类,
因为如果是抽象类则需要实现所有的抽象方法,
也违反了装饰者模式的概念,是对特定的方法增强。
反射和装饰者模式的区别;
反射是用于获取到一个类的方法的访问权,
从而操作这个类的方法,甚至改变这个方法的输出内容,
而反射可以是抽象类等。
装饰者模式只是做一个在原有的基础上进行的增强。
开发所需;
1.被装饰者,需被增强的类
2.装饰者,增强这个方法的类
3.装饰方法,需被增强的方法
开发步骤;
1.编写一个装饰类继承被装饰类【非find】
2.在装饰类中声明一个被装饰类的变量
3.在装饰类的构造方法的形参要求传入一个被装饰类的对象
4.对需要被装饰的方法进行重写
-----------------------------------↓↓↓↓↓↓↓装饰者模式 —— 案例 —— 过滤器链↓↓↓↓↓↓↓------------------------------------------------
编写一个请求统一编码集的方法。。。。。。
//继承HttpServletRequestWrapper类
public class MyTrimmer extends HttpServletRequestWrapper {
//声明一个这个被装饰类的成员变量
private HttpServletRequest request;
public MyTrimmer(HttpServletRequest request) {
super(request);
//获取到这传进来的对象
this.request = request;
}
/**
* 重写被装饰类需要增强功能的getParameter方法
*/
@Override
public String getParameter(String name) {
try {
//判断这个提交是否是GET提交
if("GET".equals(request.getMethod())){
//获取到这个参数的值,进行转码操作,因为Get提交默认都是ISO-8859-1
String temp = new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
//返回这个转了码的参数值
return temp;
}
//否则则是Post提交则设置编码集为UTF-8
request.setCharacterEncoding("UTF-8");
//返回这个参数值
return request.getParameter(name);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/**
* 重写这个被装饰类需要增强功能的getParameterValues方法
*/
@Override
public String[] getParameterValues(String name) {
try{
//判断是否是Get提交的
if("GET".equals(request.getMethod())){
//获取到这参数名的所有值
String[] arr = request.getParameterValues(name);
//遍历这个数组
for (int i = 0; i < arr.length; i++) {
//转换这个数组的每一个元素的编码集
arr[i] = new String(arr[i].getBytes("ISO-8859-1"),"UTF-8");
}
//返回这个转换好编码集元素的数组
return arr;
}
//否则是Post提交则直接设置编码集
request.setCharacterEncoding("UTF-8");
//返回这个原有的数据
return request.getParameterValues(name);
}catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
/**
* 重写这个被装饰类需要增强功能的getParameterMap方法
*/
@Override
public Map getParameterMap() {
try{
//判断是否是Get提交方法
if("GET".equals(request.getMethod())){
//获取到这个参数的Map集合
Map<String,String[]> map = request.getParameterMap();
//遍历这个集合
for (Entry<String,String[]> en : map.entrySet()) {
//遍历这个Entry的Value数组
for (int i = 0; i < en.getValue().length; i++) {
//设置转换编码集
en.getValue()[i] = new String(en.getValue()[i].getBytes("ISO-8859-1"),"UTF-8");
}
}
//返回这个集合
return map;
}
//否则则是Post提交则直接设置编码集
request.setCharacterEncoding("UTF-8");
//返回这个集合
return request.getParameterMap();
}catch(Exception e ){
e.printStackTrace();
throw new RuntimeException();
}
}
}
来源:CSDN
作者:Levi_
链接:https://blog.csdn.net/Su_Levi_Wei/article/details/104814438