文章目录
- 过滤器 & 监听器
- 目标
- 01_JavaWeb 三大组件概述-[★★]
- 02_过滤器概述和应用场景-[★★]
- 03_过滤器入门案例-[★★★]
- 04_过滤器的执行流程-[★★]
- 05_过滤器的生命周期-[★★★]
- 06_过滤器的映射路径-[★★★]
- 07_过滤器默认拦截方式-[★★★]
- 08_修改过滤器拦截方式-[★★★]
- 09_过滤器链概述和演示-[★★★]
- 10_过滤器链的执行顺序-[★★★]
- 11_过滤器案例01:解决全局乱码-[★★★★]
- 12_过滤器案例02:用户权限的控制-[★★★★]
- 13_监听器概述-[★★]
- 14_ServletContextAttributeListener监听器演示-[★★★]
- 15_ServletContextListener应用案例-[★★★]
- 16_补充内容- junit
- 总结
过滤器 & 监听器
目标
- 能够说出过滤器的作用
- 能够编写过滤器
- 能够说出过滤器生命周期相关方法
- 能够根据过滤路径判断指定的过滤器是否起作用
- 能够说出什么是过滤器链
- 能够编写过滤器解决全局乱码
- 能够说出监听器的作用
- 能够使用ServletContextListener监听器
01_JavaWeb 三大组件概述-[★★]
- JavaWeb三大组件
JavaWeb三大组件 | 作用 | 实现接口 |
---|---|---|
Servlet | 小程序:用来处理用户请求并相应数据 | javax.servlet.Servlet |
Filter | 过滤器:用来拦截用户请求和响应 | javax.servlet.Filter |
Listener | 监听器:监听web项目运行过程产生的事件。 | javax.servlet.XxxListener |
02_过滤器概述和应用场景-[★★]
过滤器的作用:
拦截用户请求:可以在请求达到目标资源之前对请求进行处理,然后根据需求决定放行请求(将请求传递给目标资源)
拦截服务器响应:可以对响应数据进行处理,然后将处理后的结果返回给浏览器。
03_过滤器入门案例-[★★★]
过滤器开发步骤小结
- 创建类实现Filter接口
- 重写接口的所有抽象方法
- 在doFilter方法中拦截请求和响应
- 配置过滤器的过滤路径:xml配置或注解配置
- 部署项目
-
需求:创建一个过滤器HelloFilter,在运行HelloServlet(Web资源)前和后分别输出一句话,在HelloServlet中也输出一句话,观察控制台的运行效果。
-
HellServlet
代码
@WebServlet(urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Web资源:到达了Servlet中");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
HelloFilter
代码
/**
* 目标:掌握过滤器的开发步骤
需求:创建一个过滤器HelloFilter,在运行HelloServlet(Web资源)前和后分别输出一句话,
在HelloServlet中也输出一句话,观察控制台的运行效果。
开发步骤
1. 创建一个类实现Filter接口
2. 重写接口中的所有方法
3. 在doFilter方法中拦截请求和响应
4. 配置过滤器的过滤路径:指定对哪些资源进行过滤
4.1 可以通过web.xml配置
4.2 可以通过注解配置
5. 部署项目并通过浏览器访问目标资源测试
*/
// 1. 创建一个类实现Filter接口
@WebFilter(urlPatterns = "/hello")
public class HelloFilter implements Filter {
// 2. 重写接口中的所有方法
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
// 3. 在doFilter方法中拦截请求和响应
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器:我是请求到达的时候执行的");
// 放行请求:将请求传递给下一个资源(Servlet)
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("过滤器:我是响应回来的时候执行的");
}
@Override
public void destroy() {
}
}
- 使用配置文件配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置过滤器信息-->
<filter>
<!--过滤器名字-->
<filter-name>hello</filter-name>
<!--过滤器的类全名字符串-->
<filter-class>com.pkx._01filter._01filter_demo.HelloFilter</filter-class>
</filter>
<filter-mapping>
<!--过滤器名字:必须和上面的一种-->
<filter-name>hello</filter-name>
<!--过滤器的过滤路径:必须以/开头-->
<url-pattern>/hello</url-pattern>
</filter-mapping>
</web-app>
- 使用注解方式配置
@WebFilter(urlPatterns = "/hello")
04_过滤器的执行流程-[★★]
- 执行流程图
- 浏览器请求web资源:可以是静态资源(HTML/JS/CSS/图片),也可以是动态资源(JSP、Servlet)
- 当过滤器的过滤路径和web资源的访问路径相匹配时,则请求会先经过过滤器处理
- 由过滤器决定是否将请求传递给下一个资源,如果要传递给下一个资源则要调用过滤器链的doFilter方法
- Web资源响应数据到浏览器之前,也会经过过滤器处理:将处理后的结果响应给浏览器显示。
05_过滤器的生命周期-[★★★]
- Filter接口中的方法
Filter接口中的方法 | 作用和调用次数 |
---|---|
void init(FilterConfig filterConfig) | 执行初始化操作 执行1次 |
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 过滤请求和响应 每次拦截到请求都会执行1次 |
public void destroy() | 销毁资源 执行1次 |
- 示例代码
/**
* 目标:过滤器的生命周期
过滤器的创建时间:在服务器启动时创建
过滤器的销毁时间:在服务器关闭或重启
注意:过滤器是不能直接被用户访问的。
*/
@WebFilter(urlPatterns = "/life")
public class LifeFilter implements Filter {
// 0 无参数构造方法 执行1次
public LifeFilter(){
System.out.println("LifeFilter构造方法");
}
// 1. 初始化方法:执行初始化操作 执行1次
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init...");
}
// 2. 过滤方法:拦截请求和响应 每拦截到请求都会执行1次
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter...");
// 放行请求:将请求传递给下一个资源(Servlet)
filterChain.doFilter(servletRequest,servletResponse);
}
// 3. 销毁方法:在服务器关闭或重启执行,用来释放资源 执行1次
@Override
public void destroy() {
System.out.println("destroy...");
}
}
06_过滤器的映射路径-[★★★]
过滤器映射路径的配置方式
1. 精确路径匹配
特点:过滤的路径和要访问的资源路径完全相同
须知:过滤器可以过滤任何资源:
servlet,index.jsp,index.html,a.png
2. 模糊路径匹配:使用通配符*,* 代表匹配所有资源
1. 前缀匹配:过滤路径必须以/开头,以结尾
比如:/ 过滤当前项目下所有资源
/manager/* 过滤manager目录下的所有资源
2. 后缀匹配:过滤路径必须以开头,以扩展名结尾
比如:.do 过滤所有以.do结尾的资源
.action 过滤所有以.action结尾的资源
3. 错误写法:/.do
不能同时出现/开头和扩展名结尾配置方式,
导致整个web项目加载失败,所有资源都无法访问。
以/ 开关的匹配模式和以扩展名结尾的配置不能同时出现:比如:/manager/*.html
- 示例代码
/**
目标:掌握过滤器映射路径的两种配置方式
两种配置方式
1. 精确路径配置
* 过滤器的过滤地址和目标资源的访问地址必须完全一致
* 比如:过滤器的过滤地址是:/url 则目标资源的地址必须也是/url才会触发该过滤器的执行
2. 模糊路径配置:使用通配符 * : 代表任意路径
2.1 前缀路径配置
* 格式: 必须以/开头,以* 结尾
* 比如: /* :该过滤器可以过滤项目中的所有资源。
* 比如: /manager/*:该过滤器要过滤manager目录下所有资源
2.2 后缀路径配置
* 格式:必须以*开头,以扩展名结尾
* 比如:*.do 或 *.action :过滤以do或action结尾的资源
3. 注意事项
错误写法:/*.do
不能同时出现/开头和扩展名结尾配置方式,
导致整个web项目加载失败,所有资源都无法访问。
Invalid <url-pattern> /*.do in filter mapping
*/
@WebFilter(urlPatterns = "*.do")
public class URLPatternFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("URLPatternFilter...doFilter进来了吗....");
// 放行
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
07_过滤器默认拦截方式-[★★★]
过滤器默认的拦截方式
- 只对从浏览器直接发送过来的请求进行拦截
-
需求说明:
1.创建过滤器:DispatchTypeFilter,过滤路径:/two
2.创建 OneServlet,访问路径为:/one
,在 OneServlet 中重定向到TwoServlet
3.创建 TwoServlet,访问路径为:/two
-
DispatchTypeFilter 代码
/**
目标:学习过滤器默认的拦截方式
默认拦截方式:只对浏览器发出的请求进行拦截(包括重定向)
需求说明:
- 创建过滤器:DispatchTypeFilter,过滤路径:/two
- 创建OneServlet,访问路径为:/one,在OneServlet中重定向到TwoServlet
- 创建TwoServlet,访问路径为:/two
问题1:浏览器直接访问OneServlet,会触发当前过滤器执行吗?会触发
问题2:浏览器直接访问TwoServlet,会触发当前过滤器执行吗?会触发
*/
@WebFilter(urlPatterns = "/two")
public class DispatchTypeFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("DispatchTypeFilter...");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
- OneServlet 代码
// 需求:在OneServlet中重定向到TwoServlet
@WebServlet(urlPatterns = "/one")
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在OneServlet中重定向到TwoServlet
response.sendRedirect("two");
// 使用转发跳转到TwoServlet
// request.getRequestDispatcher("two").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
- TwoServlet 代码
@WebServlet(urlPatterns = "/two")
public class TwoServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
out.println("我是TwoServlet的响应");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
访问方式如下
- 浏览器直接访问OneServlet,观察是否执行了过滤器?会
- 浏览器直接访问TwoServlet,观察是否执行了过滤器?会
08_修改过滤器拦截方式-[★★★]
-
需求说明:
1.创建过滤器:ForwardRequestFilter,过滤路径:/second
2.创建 FirstServlet,访问路径为:/first
,在 FirstServlet 中转发到SecondServlet
3.创建 SecondServlet,访问路径为:/second
-
ForwardRequestFilter 代码
/**
目标:修改默认的拦截方式并实现多个拦截方式共用
问题1:直接访问SecondServlet会执行该过滤器吗?会执行
问题2:直接访问FirstServlet会执行该过滤器吗?
修改过滤器拦截方式
1. 通过web.xml修改
2. 通过注解dispatcherTypes属性修改
* DispatcherType.REQUEST:默认值:只对浏览器发送的请求拦截
* DispatcherType.FORWARD:对转发的请求进行拦截
*/
@WebFilter(urlPatterns = "/second",
dispatcherTypes = {
DispatcherType.FORWARD, // 对转发的请求进行拦截
DispatcherType.REQUEST,// 默认值:只对浏览器发送的请求拦截
})
public class ForwardRequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("ForwardRequestFilter....");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
- FirstServlet 代码
// 需求:在FirstServlet中转发到SecondServlet
@WebServlet(urlPatterns = "/first")
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在OneServlet中重定向到TwoServlet
// response.sendRedirect("two");
// 使用转发跳转到SecondServlet
request.getRequestDispatcher("second").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
- SecondServlet 代码
@WebServlet(urlPatterns = "/second")
public class SecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
out.println("我是SecondServlet的响应");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
修改默认拦截方式
拦截方式 | 说明 |
---|---|
REQUEST | 默认值:只对浏览器发送的请求拦截(包括重定向) |
FORWARD | 对转发的请求进行拦截 |
- 在配置文件中修改:web.xml
<filter>
<filter-name>forward</filter-name>
<filter-class>com.pkx._01filter._03filter_type.ForwardRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>forward</filter-name>
<url-pattern>/second</url-pattern>
<!--配置拦截方式-->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
- 在注解中修改:@WebFilter
@WebFilter(urlPatterns = "/second",
dispatcherTypes = {
DispatcherType.FORWARD, // 对转发的请求进行拦截
DispatcherType.REQUEST,// 默认值:只对浏览器发送的请求拦截
})
09_过滤器链概述和演示-[★★★]
什么是过滤器链:由多个过滤器连接一起组成的链条
-
需求:创建两个过滤器OneFilter和TwoFilter,访问ResourceServlet,每个过滤器的请求和响应各输出一句话,观察过滤器的执行过程。
-
第一个过滤器:
OneFilter
/**
需求:创建两个过滤器OneFilter和TwoFilter,
访问ResourceServlet,每个过滤器的请求和响应各输出一句话,观察过滤器的执行过程。
*/
@WebFilter(urlPatterns = "/resource")
public class OneFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器1:请求");
// 放行请求:将请求传递下去
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("过滤器1:响应");
}
@Override
public void destroy() {
}
}
- 第二个过滤器:
TwoFilter
@WebFilter(urlPatterns = "/resource")
public class TwoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器2:请求");
// 放行请求
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("过滤器2:响应");
}
@Override
public void destroy() {
}
}
- Web资源:
ResourceServelt
@WebServlet(urlPatterns = "/resource")
public class ResourceServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("我是web资源Resource");
}
}
10_过滤器链的执行顺序-[★★★]
- 过滤器链的执行顺序由什么决定?
web.xml配置方式:将需要先执行的过滤器配置在前面
注解配置方式:只需要修改名称即可,不同系统效果不一样(如果需要严格控制过滤器链过滤器的执行顺序不推荐使用注解配置)- 过滤器链的注意事项
如果过滤器执行完过滤操作之后不放行请求,下一个过滤器无法拦截到请求。
- 修改过滤器链的执行顺序
- 注解配置方式:只需要修改名称即可
- web.xml配置方式:将需要先执行的过滤器配置在前面
11_过滤器案例01:解决全局乱码-[★★★★]
-
需求说明:编写过滤器,过滤所有Servlet中使用POST方法提交的汉字的编码。
-
步骤分析:
1.创建login.jsp页面:准备登录表单,表单提交给LoginServlet
2.创建register.jsp页面:准备注册表单,表单提交给RegisterServlet
3.创建LoginServlet和RegisterServlet接收表单参数信息
4.创建EncodeFilter过滤LoginServlet和RegisterServlet解决请求参数乱码问题 -
login.jsp
代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
register.jsp
代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册页面</title>
</head>
<body>
<form action="register" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
LoginServlet
代码
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数:用户名
String username = request.getParameter("username");
System.out.println("username = " + username);
}
}
RegisterSerlvet
代码
@WebServlet(urlPatterns = "/register")
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取请求参数:用户名
String username = request.getParameter("username");
System.out.println("username = " + username);
}
}
EncodeFilter
代码
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 将父类类型转换子类类型的对象
HttpServletRequest request = (HttpServletRequest) servletRequest;
// 获取请求方式
String method = request.getMethod();
// 判断请求方式是GET还是POST
if ("GET".equals(method)){
// 处理GET请求乱码问题
} else {
// 设置请求参数乱码:POST请求乱码处理方式
servletRequest.setCharacterEncoding("utf-8");
}
// 放行请求
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
12_过滤器案例02:用户权限的控制-[★★★★]
当多个资源需要执行相同的处理逻辑时,可以统一使用过滤器实现该处理逻辑,简化代码。
- 案例需求
使用过滤器进行权限的控制,实现正确的访问
add.jsp 添加数据,需要登录才可访问
update.jsp 修改数据,需要登录才可访问
list.jsp 查询数据,不用登录
login.jsp 登录页面
- 实现步骤
- 在web目录下准备4个页面:add.jsp、update.jsp、list.jsp、login.jsp
- 创建LoginServlet处理登录逻辑
* 判断用户名密码是否正确,如果正确,则在会话域中保存用户信息。登录成功跳转到list.jsp
* 登录失败则在域中写入登录失败的信息,并且跳转到login.jsp- 使用过滤器解决:创建AuthorityFilter
* 获得HttpServletRequest、HttpSession对象
* 如果会话域中没有用户信息,则跳转到登录页面:login.jsp
* 如果会话域中有用户信息,则放行运行访问资源。
- 用户权限分析图
LoginServlet
代码
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 判断用户名和密码是否正确
if ("admin".equals(username) && "123".equals(password)){
// 3. 如果正确则保存用户信息到会话域中
request.getSession().setAttribute("user", username);
// 3.1 跳转到主界面
response.sendRedirect("list.jsp");
} else {
// 4. 如果不正确则保存错误信息到请求域中
request.setAttribute("errorMsg", "用户名或密码错误");
// 4.1 转发的登录页面
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
AuthorFilter
代码
/**
* 目标:拦截manager目录下资源的访问,需要登录才能访问
*/
@WebFilter(urlPatterns = "/manager/*")
public class AuthorFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 1. 获取会话域对象
// 1.1 类型转换
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 1.2 获取会话域对象
HttpSession session = request.getSession();
// 2. 从会话域中获取用户数据
Object user = session.getAttribute("user");
// 3. 有用户数据则代表已经登录了
if (user != null) {
// 则放行请求
filterChain.doFilter(request, response);
} else {
// 4. 没有用户数据则代表没有登录,则重定向到登录页面
response.sendRedirect(request.getContextPath() + "/login.jsp");
}
}
@Override
public void destroy() {
}
}
13_监听器概述-[★★]
- 监听器的作用:监听作用域的创建和销毁,以及属性增删改查操作。
- 监听器的开发步骤:
1. 创建类实现监听器接口
2. 重写接口中的所有抽象方法
3. 配置监听器(web.xml或注解配置)
- 监听器的分类
监听器接口 | 作用 |
---|---|
ServletContextListener | 监听上下文域的创建和销毁 |
ServletContextAttributeListener | 监听上下文域属性的增删改查操作 |
HttpSessionListener | 监听会话域的创建和销毁 |
HttpSessionAttributeListener | 监听会话域属性的增删改查操作 |
ServletRequestListener | 监听请求域的创建和销毁 |
ServletRequestAttributeListener | 监听请求域属性的增删改查操作 |
14_ServletContextAttributeListener监听器演示-[★★★]
- ServletContextAttributeListener接口中方法
ServletContextAttributeListener接口中方法 | 调用时机 |
---|---|
void attributeAdded(ServletContextAttributeEvent event) | 往上下文域添加键值对数据调用 |
void attributeRemoved(ServletContextAttributeEvent event) | 从上下文域删除键值对数据调用 |
void attributeReplaced(ServletContextAttributeEvent event) | 修改上下文域键值对数据调用 |
- ServletContextAttributeEvent对象中的方法
ServletContextAttributeEvent对象中的方法 | 功能 |
---|---|
String getName() | 获得属性名 |
Object getValue() | 获得属性值 |
-
需求
1.创建一个ServletContextAttributeListener监听器的实现类
重写接口中所有的方法,输出属性名和属性值。
2.创建一个Servlet,向context上下文中添加一个属性,修改一个属性,删除一个属性。 -
Servlet代码
/**
* 需求:向context上下文中添加一个属性,修改一个属性,删除一个属性。
*/
@WebServlet(urlPatterns = "/context")
public class ServletContextServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得上下文域对象
ServletContext context = getServletContext();
// 添加键值对数据
context.setAttribute("username", "jack");
// 更新键值对数据
context.setAttribute("username", "rose");
// 删除键值对数据
context.removeAttribute("username");
}
}
- 监听器代码
/**
需求:
1. 创建一个ServletContextAttributeListener监听器的实现类
- 重写接口中所有的方法,输出属性名和属性值。
2. 创建一个Servlet,向context上下文中添加一个属性,修改一个属性,删除一个属性。
3. 控制台输出效果:
*/
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
// 当往上下文域添加属性时调用
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
// 获得属性名
String name = event.getName();
// 获得属性值
Object value = event.getValue();
System.out.println("attributeAdded:" + name + "=" + value);
}
// 当从上下文域中删除属性时调用
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
// 获得属性名
String name = event.getName();
// 获得属性值
Object value = event.getValue();
System.out.println("attributeRemoved:" + name + "=" + value);
}
// 当更新上下文域中属性时调用
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
// 获得属性名
String name = event.getName();
// 获得属性值:修改前的值
Object value = event.getValue();
// 获得属性值:修改后的值
Object newValue = event.getServletContext().getAttribute(name);
System.out.println("attributeReplaced:" + name + "=" + value + "," + newValue);
}
}
15_ServletContextListener应用案例-[★★★]
-
ServletContextListener常见操作
1.加载第三方配置文件
2.开启定时任务(比如每天凌晨给过当天生日的用户发生日祝福邮件) -
需求说明:在项目启动之后,开启一个定时任务,每隔3秒在控制台输出一句话。
/**
* 需求说明:在项目启动之后,开启一个定时任务,每隔3秒在控制台输出一句话。
*/
@WebListener
public class MyServletContextListener implements ServletContextListener {
// 在服务器启动时执行(上下文域创建)
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("contextInitialized");
// 开启一个定时任务,每隔3秒在控制台输出一句话。
// 创建定时器对象
Timer timer = new Timer();
// 安排定时任务
/**
* 参数1:task:TimerTask对象:用来封装任务代码
等价于Runnable接口:用来封装线程任务代码
* 参数2:firstTime:任务第1次开始执行的时间
* 参数3:period:时间间隔,单位毫秒
*/
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("定时任务...");
}
},new Date(),3000);
}
// 在服务器关闭时执行(上下文域销毁)
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("contextDestroyed");
}
}
16_补充内容- junit
-
什么是junit
junit是第三方提供的单元测试框架(工具)什么是单元测试
* 在Java中一个类就是一个单元
* 单元测试:程序猿编写的一小段代码对某个类中的某个方法进行测试,最大限度避免bug
保证方法执行的正确性和稳定性。 -
junit使用步骤
2.1 编写业务类:实现某一业务功能的类,比如对学生进行增删改查的类。
编写业务方法:实现某一功能的方法,比如登录,查询学生,注册…2.2 编写测试类
命名规范:
* 以Test开头,以业务类名结尾,比如业务类名:StudentDao,则测试类名:TestStudentDao
* 以Test结尾,以业务类名开头,比如业务类名:StudentDao,则测试类名:StudentDaoTest2.3 编写测方式:在测试类中编写测试方法
命名规范:
* 一般以test开头,以业务方法名结尾,比如业务方法名:save,则测试方法名:testSave
声明要求:必须是public修饰的,必须是没有返回值,必须是没有参数,必须使用@Test修饰 -
junit使用演示
-
junit常用注解
junit4.x版本
@Before:用来修饰方法,该方法会在每个测试方法执行之前执行1次
@After:用来修饰方法,该方法会在每个测试方法执行之后执行1次
@BeforeClass:用来修饰静态方法,该方法会在所有测试方法执行之前执行1次
@AfterClass:用来修饰静态方法,该方法会在所有测试方法执行之后执行1次junit5.x版本
@BeforeEach:用来修饰方法,该方法会在每个测试方法执行之前执行1次
@AfterEach:用来修饰方法,该方法会在每个测试方法执行之后执行1次
@BeforeAll:用来修饰静态方法,该方法会在所有测试方法执行之前执行1次
@AfterAll:用来修饰静态方法,该方法会在所有测试方法执行之后执行1次
// 测试类
public class TestStudentDao {
// 创建数据访问层对象
private static StudentDao dao = null;
// 用来修饰方法,该方法会在每个测试方法执行之前执行1次
/*@Before
public void init(){
dao = new StudentDao();
}*/
// 用来修饰静态方法,该方法会在所有测试方法执行之前执行1次
@BeforeAll
public static void init(){
System.out.println("init");
dao = new StudentDao();
}
// 用来修饰方法,该方法会在每个测试方法执行之后执行1次
/*@After
public void destory(){
dao = null;
}*/
// 用来修饰静态方法,该方法会在所有测试方法执行之后执行1次
@AfterAll
public static void destory(){
System.out.println("destory");
dao = null;
}
/**
* 测试方法
*/
@Test
public void testSaveStudent(){
// 创建学生对象
Student stu = new Student();
// 调用保存方法保存学生
boolean b = dao.saveStudent(stu);
/*
断言:预先判断某个条件一定满足,如果条件不满足则直接崩溃
message: 异常提示信息
expected: 期望值:调用方法期望获得的返回值
actual: 实际值:调用方法返回的实际结果
*/
// Assert.assertEquals("期望值和实际值不一致", true,b);
System.out.println("b = " + b);
}
@Test
public void testDeleteById(){
// 创建数据访问层对象
// StudentDao dao = new StudentDao();
// 根据id删除学生
dao.deleteById(1);
}
}
总结
过滤器
- 作用:拦截用户有请求和服务器响应
- 步骤:
1.创建类实现Filter接口
2.重写接口的所有抽象方法
3.在doFilter方法中拦截请求和响应
4.配置过滤器的过滤路径:xml配置或注解配置
5.部署项目- Filter接口:
void init(FilterConfig filterConfig)
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
public void destroy()
监听器
- 作用:监听作用域的创建和销毁,以及属性增删改查操作。
- 监听器接口:
ServletContextListener
ServletContextAttributeListener
HttpSessionListener
HttpSessionAttributeListener
ServletRequestListener
ServletRequestAttributeListener