servlet+filter+listener被称为javaweb的三大组件
Filter(重要)
-
Filter: 过滤器
- 生活中的过滤器: 如生活中的净水器,空气净化器等都是过滤器.
- web中的过滤器: 当浏览器通过请求访问服务器资源时,过滤器可以将请求拦截下来,来完成一些特殊的功能.
-
过滤器的作用
- 一般用于完成通用的操作.
- 登录验证(类似淘宝要加入购物车必须先登录这样子).
- 统一编码处理,我们当提交表单的方式为post的时候,我们都要设置request的编码防止乱码.
- 敏感字符过滤.
- …
- 一般用于完成通用的操作.
-
filter快速入门
- 步骤
- 定义一个类,实现接口Filter,和servlet类似的.
- 复写接口中的方法.
- 配置拦截路径(即访问什么样的资源过滤器会生效),servlet配置的是访问路径.
- 第一种配置方式: web.xml.
- 第二种配置方式: 注解(常用),和servlet一样,写在
urlPattern
后面,且urlPattern
几个字可以省略,一般后面写/*
,表示访问所有资源之前都要先执行过滤器,写/demo.jsp
则表示只有访问demo.jsp的时候才会执行过滤器.
- 放行,即让访问的资源中的内容显示出来
chain.doFilter(req, resp);
, 其中的chain
,req
,resp
这都是doFilter
中的参数.
- 过滤器快速入门代码.
- 过滤器快速入门index.jsp页面.
- 这里有一个点要注意一下,就是如果你配置过滤器为
/*
的时候,就表示访问所有资源都要先执行过滤器,此时运行服务器,通过上面的代码,访问index.jsp,会发现index.jsp中的内容不会被显示出来,这个就可以理解为这样子: 假设我要回家.路上有土匪,这个土匪就相当于那个过滤器,我能不能过去,就要看土匪能不能放我过去,这就相当于上面的我访问index.jsp前执行了过滤器,我能不能显示index.jsp的内容,要看过滤器让不让我看这样子.
- 步骤
-
过滤器的细节
-
web.xml配置(反正我一般不用hhh,知道就行)
<filter> <filter-name>demo1</filter-name> <filter-class>这里填的是src下(不包括src)到资源文件的路径(就是包名.包名...类名)如`filters.IntroductionOfFilter`</filter-class> </filter> <filter-mapping> <filter-name>demo1</filter-name> <url-pattern>/*(注意这个是拦截路径,不是访问路径)</url-pattern> </filter-mapping>
-
过滤器执行流程
- 大体来说就是,先通过对应的url访问资源,然后途中经过过滤器,过滤器经过处理后放行,放行后执行url对应资源的内容,结束之后又回到过滤器中,执行放行语句后面的操作.
- 放行语句前,会收到浏览器传来的请求,如果有操作request的语句,它会先执行操作request的语句.
- 执行放行语句,回到资源文件中执行相应操作.
- 资源文件执行结束后,回到过滤器中,执行放行语句下面的操作,即对相应消息的操作.
-
过滤器生命周期方法(三个)
- 服务器启动时创建Filter对象,然后由该对象执行init()方法去加载资源,而且只执行一次 —> 每一次浏览器访问服务器经过过滤器时,由Filter对象去执行doFilter()方法,可以执行多次 —>服务器停止时,Filter对象被销毁,如果服务器正常关闭(就是点红色的点,不是直接关闭之前说的tomcat窗口,反正我们在集成开发环境中点击关闭都是正常关闭的),此时执行destroy()去释放资源,只执行一次.
-
过滤器配置详解
- 拦截路径配置(有4种)
- 拦截具体的资源路径:
/index.jsp
, 表示只有访问index.jsp资源时,过滤器才会被执行.- 注意,这里是不存在一个项目中有两个同名的index.jsp的,不管你在什么地方,都会报错的.
- 拦截具体目录:
/user/*
, 表示访问/user
下的所有资源时,过滤器都会被执行- 这里的
/user/*
不一定非得是一定存在user这个目录,也就是说/user/servlet
并不一定表示servlet就放在真正存在的user包下,它只是表示所有前面有/user
的url都会被user这个东西限制,也就是会经过过滤器. - 如果真的是有这个目录,那么就要把东西放在目录下,同时在idea中要注意这里拦截的是具体目录不是模块包哈,目录和模块包有区别的,目录是自己新建的,模块包是idea生成的,如src,web模块包等,同时这样设置以后,访问的url也要变了,要加上目录了就要.
- 这里的
- 后缀名拦截的方式:
*.jsp
, 表示访问所有后缀名为.jsp资源时,过滤器都会被执行,注意前面没有斜杠. - 拦截所有资源:
/*
, 表示访问所有资源时,过滤器都会被执行. - 拦截路径设置代码.
- 拦截具体的资源路径:
- 拦截方式配置(两种方式): 指的是资源被访问的方式, 也就是说,比如我设置了浏览器直接访问资源的过滤器,当我从服务器内部转发的时候,就不会被拦截,但是重定向这种两次请求的就也会被拦截.
- 注解配置: 在注解filter注解中设置dispatcherTypes属性(有5种取值)
- REQUEST: 默认值.表示浏览器直接请求资源url,即直接在地址栏输入url路径访问.
- FORWEAD: 服务器内部转发访问资源.
- INCLUDE: 包含访问资源(了解)
- ERROR: 错误跳转资源(了解)
- ASYNC: 异步访问资源(了解)
- 当我既要在直接访问时能被过滤器加强,还要在内部转发时也被过滤器加强怎么办呢?
- 其实很简单,我们通过看webfilter的源码知道,它的dispatcherTypes属性是一个数组,所以我们直接这样写:
dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST}
.
- 其实很简单,我们通过看webfilter的源码知道,它的dispatcherTypes属性是一个数组,所以我们直接这样写:
- 当这样写的时候:
urlPatterns = "/*", dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST}
, 表示转发和直接请求访问所有类型资源都会被过滤器加强,但是这样子的话,假如是以请求转发的方式访问index.jsp,过滤器就会被执行两次.
- web.xml配置:
- 配置资源路径的时候多设置这样一个标签即可,也有上述五个取值,一样的.
- 注解配置拦截方式代码.
- 注解配置: 在注解filter注解中设置dispatcherTypes属性(有5种取值)
- 拦截路径配置(有4种)
-
过滤器链(配置多个过滤器)
-
执行顺序: 如果有两个过滤器(过滤器1,过滤器2)
- 过滤器1先执行
- 过滤器2再执行
- 资源执行
- 过滤器2回来执行
- 过滤器1回来执行
-
这个怎么测试呢?其实很简单,你就直接写两个过滤器,采用注解配置,其中过滤的url写成
/*
,然后随便访问一个路径,比如index.jsp的路径,然后你就会发现它两个都执行了(在注解配置中只要两个的filterName
不一样,就会都执行,两个名字一样就只会执行前一个).
-
@WebFilter(filterName = "FilterDemo4", urlPatterns = "/*") public class FilterDemo4 implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { System.out.println("FilterDemo4执行了"); chain.doFilter(req, resp); System.out.println("FilterDemo4回来了"); } public void init(FilterConfig config) throws ServletException { } }
3. 过滤器的先后顺序问题(两种): 1. 注解配置的过滤器: 根据类名,按照字符串比较规则去比较,值小的先执行. * 例如: AFilter和BFilter,它会先第一个字符比较,然后第二个字符比较...一次类推,在这里,第一个字符`A`<`B`,就比较出来了,所以先执行AFilter. * 又比如: `Filter6`和`Filter17`,它依次比较,比较到`6` > `1`,所以Filter17会先执行. 2. web.xml配置: 谁定义在上面谁先执行,就是谁写在前面就先执行谁,知道就好了.
-
Filter案例
- 案例1_登录验证
- 需求
- 访问之前的用户增删查改的案例的资源。验证其是否登录,即权限控制.
- 如果登录了,则直接放行。
- 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录".
- 访问之前的用户增删查改的案例的资源。验证其是否登录,即权限控制.
- 需求
- 案例2_敏感词汇过滤
- 需求
- 对用户增删查改案例录入的数据进行敏感词汇过滤
- 敏感词汇比如
坏蛋``菜鸟
等. - 如果是敏感词汇,替换为 ***.
- 分析:
- 对request对象进行增强,增强获取参数的方法,获取敏感词汇变成***以后要将***再放回到request中,而request没有addParameter方法.
- 增强后,放行,传递代理对象.
- 增强对象的功能:
- 设计模式: 一些通用的解决固定问题的方式.
- 装饰模式.
- 代理模式(我们用这个).
- 概念: 可以理解为代理商,代购
- 真实对象: 即被代理的对象,比如说我们要买国外的东西,找了代购,国外的东西就是真实对象.
- 代理对象: 即代理的对象,比如说我们要买东西的找的代购,就是代理对象,但是代理对象还是要去国外买真实对象,然后赚取差价.
- 代理模式: 代理对象代理真实对象,达到增强真实对象的目的.
- 可以这么理解,代理商并没有卖电脑的功能,它只是增强总部卖电脑的动能,它要卖电脑,它就要去总部,也就是真实对象那里获取它卖电脑的功能.
- 实现方式
- 静态代理: 代理对象的生成方式—>有一个java的类文件描述代理模式.
- 动态代理: 代理对象的生成方式—>在内存中动态形式代理类,我们这里用动态代理.
- 实现步骤:
- 代理对象和真实对象实现相同的接口.
- 在使用代理对象的方法中,通过语句:
代理对象=Proxy.newProxyInstance()
创建代理对象. - 使用代理对象去调用对应方法.
- 增强方法.
- 增强方式:
- 增强参数列表.
- 增强返回值类型.
- 增强方法体执行逻辑
- 概念: 可以理解为代理商,代购
- 动态代理案例代码.
- 设计模式: 一些通用的解决固定问题的方式.
- 需求
- 实现上述功能后完整代码.
Listener
-
Listener: 监听器,web的三大组件之一,不过用的比较少,我就没怎么管嘿嘿嘿.
-
事件监听机制
- 事件: 一件事情.
- 事件源: 时间发生的地方.
- 监听器: 一段代码或一个对象.
- 注册监听: 将事件,事件源,监听器绑定在一起,当事件源发生时间后,执行监听器代码.
-
servletContextListener(接口,自己写实现类作为监听器对象): 表示监听servletContext对象的创建和销毁.
- void contextInitialized(ServletContextEvent sce): servletContext对象创建后会调用该方法.
- void contextDestroyed(ServletContextEvent sce): servletContext对象销毁前会调用此方法.
-
步骤:
- 定义一个类实现servletContextListener接口.
- 重写方法.
- 配置
- web.xml配置.
- xml配置只需要配置一个就可以了,注意这里的路径是全路径,就是src下从包名开始.包名.类名.
- 注解配置.
- 直接写一个
@WebListener
就完事了.
- 直接写一个
- web.xml配置.
- 案例代码.