服务端技术|过滤器及监听器

1.过滤器技术

1.1.filter简介

filter是对客户端访问资源的过滤,符合条件放行,不符合条件不放行,并且可以对目标资源访问前后进行逻辑处理

1.2.filter快速入门

步骤:

新建一个过滤器

1
2
public class Demo1Filter implements Filter{
}

实现接口中尚未实现的方法(着重实现doFilter方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Demo1Filter implements Filter{

public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub

}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器执行了.....");

}

public void destroy() {
// TODO Auto-generated method stub

}

}

在web.xml中进行配置(主要是配置要对哪些资源进行过滤)

1
2
3
4
5
6
7
8
<filter>
<filter-name>filterdemo</filter-name>
<filter-class>com.yueqian.filter.Demo1Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filterdemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

仔细观察:

但是servlet程序没有去执行!

因为,servlet程序在执行的时候,被filter拦截了,需要进行放行!

1
2
3
4
5
6
7
8
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器执行了.....");

// 放行请求
chain.doFilter(request, response);

}

再次观察效果:

再仔细观察一个细节,客户端请求服务端,是先走的filter,再走的servlet程序!

1.3.filter执行流程原理

1.4.filter中API详解

1.4.1.filter生命周期

Filter接口有三个方法,并且这个三个都是与Filter的生命相关的方法

init(Filterconfig):代表filter对象初始化方法 filter对象创建时执行

doFiltr(ServletRequest,ServletResponse,FilterCha):代表filter执行过滤的核心方法,如果某资源在已经被配置到这个filter进行过滤的话,那么每次访问这个资源都会执行doFilter方法

destory():代表是filter销毁方法 当filter对象销毁时执行该方法

Filter对象的生命周期:

Filter何时创建:服务器启动时就创建该filter对象

Filter何时销毁:服务器关闭时filter销毁

1.4.2.filter中的API

1)init(FilterConfig)

其中参数config代表 该Filter对象的配置信息的对象,内部封装是该filter的配置信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void init(FilterConfig filterConfig) throws ServletException {

//1.获取过滤器名称
String filterName = filterConfig.getFilterName();
System.out.println("filterName:"+filterName);

//2.获取初始化参数
String initValue = filterConfig.getInitParameter("aaa");
System.out.println("initValue:"+initValue);

//3.获取ServletContext
ServletContext servletContext = filterConfig.getServletContext();

}

2)destory()方法

filter对象销毁时执行

3)doFilter方法

doFilter(ServletRequest,ServletResponse,FilterChain)

其中的参数:

ServletRequest/ServletResponse:每次在执行doFilter方法时 web容器负责创建一个request和一个response对象作为doFilter的参数传递进来。该request个该response就是在访问目标资源的service方法时的request和response。

FilterChain:过滤器链对象,通过该对象的doFilter方法可以放行该请求

思考:如果在doFilter方法中使用response和request中一些方法,我们应该怎么办呢?

思考:为何先执行filter1,后执行filter2呢?

1.5.filter配置详解

1
2
3
4
5
6
7
8
<filter>
<filter-name>bbb</filter-name>
<filter-class>comm.yueqian.filter.FilterDemo2</filter-class>
</filter>
<filter-mapping>
<filter-name>bbb</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

url-pattern配置时

1)完全匹配 /sertvle1

2)目录匹配 /com/controller/* —-最多的

/jsp/*–匹配jsp的资源

/user/*:访问前台的资源进入此过滤器

/admin/*:访问后台的资源时执行此过滤器

3)扩展名匹配 *.java *.jsp

注意:url-pattern可以使用servlet-name替代,也可以混用

dispatcher:访问的方式(了解)

REQUEST:默认值,代表直接访问某个资源时执行filter

FORWARD:转发时才执行filter

INCLUDE: 包含资源时执行filter

ERROR:发生错误时 进行跳转是执行filter

总结Filter的作用?

1)公共代码的提取

​ 整个网站的字符编码问题

​ 登录功能的判断

2)可以对request和response中的方法进行增强(装饰者模式/动态代理)

3)进行权限控制

1.6.filter案例

解决乱码问题

处理post请求乱码问题

1
2
3
4
5
6
7

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

// 处理request请求编码问题
request.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8");
chain.doFilter(request, response);
}

案例:

模拟淘宝,购物商场中如果没有登录时不可以查看,购物车,订单,是直接跳转到登录页面

思考:那些页面不用执行这个过滤器?:首页,登录页面,注册?如何将这三个页面踢掉,也就是过滤器不起作用

代码:

\1) 定义一个登陆过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//从session域中获取username,将request,response强转
HttpServletRequest httpRequest=(HttpServletRequest)request;
HttpServletResponse httpResponse=(HttpServletResponse) response;
HttpSession session=httpRequest.getSession();
String username=(String) session.getAttribute("username");
//先将三个页面踢开
//请求路径
String path=httpRequest.getRequestURI();
if(path.indexOf("/head.jsp")!=-1) {
chain.doFilter(request, response);
return;
}
if(path.indexOf("/login.jsp")!=-1) {
chain.doFilter(request, response);
return;
}
if(path.indexOf("/register.jsp")!=-1) {
chain.doFilter(request, response);
return;
}
if(username!=null) {
chain.doFilter(request, response);
}else {
httpResponse.sendRedirect(httpRequest.getContextPath()+"/login.jsp");
}

\2) 配置xml文件

1
2
3
4
5
6
7
8
9
 <!-- 用户登录过滤 -->
<filter>
<filter-name>FilterServlet3</filter-name>
<filter-class>com.shop.FilterServlet3</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterServlet3</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

3)登陆的servlet

1
2
3
4
5
6
7
 //获取用户名 
String username=request.getParameter("username");
//用户信息存入session中
HttpSession session=request.getSession();
session.setAttribute("username", username);
//重定向
response.sendRedirect(request.getContextPath()+"/head.jsp");

4)head.jsp

1
2
3
4
5
6
7
8
9
<h1>
<a href="">首页</a>
欢迎:${username }
<hr/>
</h1>
<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
<a href="${pageContext.request.contextPath}/register.jsp">注册</a>
<a href="${pageContext.request.contextPath}/buycar.jsp">购物车</a>
<a href="${pageContext.request.contextPath}/order.jsp">订单</a>

2. 监听器技术

javaEE包括13门规范 在课程中主要学习 servlet技术 和 jsp 技术

其中 servlet规范包括三个技术点:servlet listener filter

2.1.监听器简介

监听器就是监听某个对象的的状态变化的组件

监听器的相关概念:

事件源:被监听的对象(女朋友) —– 三个域对象 request session servletContext

监听器:监听事件源对象 事件源对象的状态的变化都会触发监听器 —- 6+2

注册监听器(将监听器安装在你女朋友身上):将监听器与事件源进行绑定

响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 —- 程序员编写代码

2.2.监听器有哪些

2.3.监听三大域对象2

2.3.1.ServletContextListener

监听器三步曲:

1)创建一个类去实现接口

1
2
public class Demo1Listren implements ServletContextListener{
}

2)覆盖其中的2个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Demo1Listren implements ServletContextListener{

public void contextInitialized(ServletContextEvent sce) {

System.out.println("contextInitialized...........");
}

public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed...........");
}

}

3)配置监听器对象

1
2
3
4
5
<!--注册监听器  -->

<listener>
<listener-class>linstern.Demo1Listren</listener-class>
</listener>

观察打印:

  1. 销毁

监听器的方法参数

1
2
3
4
5
6
7
8
9
10
11
12
public void contextInitialized(ServletContextEvent sce) {

System.out.println("contextInitialized...........");

ServletContext servletContext = sce.getServletContext();


//Object source = sce.getSource();
ServletContext servletContext2 = (ServletContext) sce.getSource();

// 方法是等价的
}

ServletContextListener监听器的主要作用

a、初始化的工作:初始化对象 初始化数据 —- 加载数据库驱动 连接池的初始 化

b、加载一些初始化的配置文件 — spring的配置文件

c、任务调度—-定时器—-Timer/TimerTask

2.3.2. HttpSessionListener

思考:在页面请求一个jsp页面,sessionCreated会不会执行呢?

1
2
3
public void sessionCreated(HttpSessionEvent se) {
System.out.println("HttpSessionEvent............"+se.getSession().getId());
}

既然我们都知道session在我们服务端会有很多很多个,那么我现在换一个浏览器,sessionCreated会不会再次调用呢?

会调用

HttpSession对象的生命周期

何时创建:第一次调用request.getSession时创建

何时销毁:服务器关闭销毁 session过期 手动销毁

思考:session监听器有啥用呢?

2.3.3. ServletRequestListener

ServletRequest的生命周期

创建:每一次请求都会创建request

销毁:请求结束

步骤:

1)创建一个类 实现 接口

1
2
public class MyHttpRequestLis implements ServletRequestListener{
}

2)覆盖其中的方法

1
2
3
4
5
6
7
8
9
public class MyHttpRequestLis implements ServletRequestListener{
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("requestInitialized............");
}
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("requestDestroyed...........");

}
}

3)配置

1
2
3
4
<!-- 配置request监听器 -->
<listener>
<listener-class>linstern.MyHttpRequestLis</listener-class>
</listener>

2.4.监听三个域对象的属性变化

域对象的通用的方法:

setAttribute(name,value)

— 触发添加属性的监听器的方法

— 触发修改属性的监听器的方法

getAttribute(name)

removeAttribute(name)

— 触发删除属性的监听器的方法

ServletContextAttibuteListener监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ServletContextAttibuteLis implements ServletContextAttributeListener{

// 监听添加
public void attributeAdded(ServletContextAttributeEvent scab) {
System.out.println("添加属性了:"+scab.getName()+":"+scab.getValue());

}

// 监听删除
public void attributeRemoved(ServletContextAttributeEvent scab) {
System.out.println("删除属性了:"+scab.getName()+":"+scab.getValue());

}
// 监听修改
public void attributeReplaced(ServletContextAttributeEvent scab) {
System.out.println("修改属性了:"+scab.getName()+":"+scab.getValue());

}

}
1
2
3
<listener>
<listener-class>linstern.ServletContextAttibuteLis</listener-class>
</listener>
1
2
3
4
5
6
7
8
9
10
11
12
13
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();

// 存数据
servletContext.setAttribute("name", "tom");

//修改
servletContext.setAttribute("name", "lucy");

// 删除
servletContext.removeAttribute("name");

}

HttpSessionAttributeListener监听器(同上)

ServletRequestAriibuteListenr监听器(同上)