一、过滤器程序的基本结构、web.xml文件的配置过程和过滤器的执行过程
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
<init-param>
<param-name>course</param-name>
<param-value>Java EE</param-value>
</init-param>
</filter>
<!-- 配置FirstFilter只拦截test.html -->
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/test.html</url-pattern>
</filter-mapping>
</web-app>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Title</title>
</head>
<body>
这是一个测试过滤器
</body>
</html>
package filter;
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
public class FirstFilter implements Filter { //实现Filter接口
FilterConfig config = null;//定义一个FilterConfig对象为类的实例变量
public void init(FilterConfig filterConfig) throws ServletException {
config = filterConfig;//获取FilterConfig对象引用
}
public void destroy() {
config = null;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
String str = config.getInitParameter("course");//获取过滤器初始参数
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<font color=blue>前置程序块<br>");
out.println("过滤器初始参数:course=" + str + "</font><br><br>");
chain.doFilter(request, response);//调用"过滤器链"方法
out.println("<br><font color=blue>后置程序块</font><br>");
}
}
过滤器需要实现Filter接口,并重写Filter的三个方法:init()、destory()、doFilter()
过滤器的执行顺序:多个过滤器的拦截路径相同时,首先按照<filter-mapping>标记在web.xml中出现的先后顺序执行过滤器,然后按照过滤器类名的字典顺序执行注解的过滤器。
二、注解配置过滤器:字符编码过滤器及权限验证过滤器的实现
package filter;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
@WebFilter(filterName = "EncodingFilter", urlPatterns = "/*",
initParams = {@WebInitParam(name = "encode", value = "UTF-8")})
public class EncodingFilter implements Filter {
private String encode = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
encode = filterConfig.getInitParameter("encode");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(encode);
servletResponse.setContentType("text/html;charset="+encode);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
package filter;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter(filterName = "ValidationFilter", value = "/admin/*")
public class ValidationFilter implements Filter {
@Override
public void init(FilterConfig Config) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpSession session = ((HttpServletRequest) request).getSession();
if(session.getAttribute("user") == null){
((HttpServletResponse) response).sendRedirect("login.jsp");
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
<form action="loginServlet">
<div id="table_div">
<table align="center">
<tr>
<td colspan="2"><h2>学生信息管理系统</h2></td>
</tr>
<tr>
<td>账号:</td>
<td><input class="inputinfo" type="text" name="account" placeholder="账号" /></td>
</tr>
<tr >
<td>密码:</td>
<td><input class="inputinfo" type="password" name="password" placeholder="密码" /></td>
</tr>
<tr>
<td colspan="2"><input id="btn_submit" type="submit" value="登录" /></td>
</tr>
</table>
</div>
</form>
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Servlet implementation class LoginServlet
*/
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String account = request.getParameter("account");
String password = request.getParameter("password");
if (account.equals("Sarah") && password.equals("123456")) {
request.getSession().setAttribute("user", account);
response.sendRedirect("admin/showAllBooks");
} else {
response.sendRedirect("login.jsp");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
三、application、session两类对象的创建与销毁时间监听
package listener;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.annotation.WebListener;
import jakarta.servlet.http.HttpSessionEvent;
import jakarta.servlet.http.HttpSessionListener;
//添加监听器注解
@WebListener
//由MyListener类实现ServletContext、HttpSession、ServletRequest三类对象创建、销毁事件的监听
public class MyListener implements ServletContextListener, HttpSessionListener, ServletRequestListener {
public void contextInitialized(ServletContextEvent sce) {
System.out.println("\n ServletContext对象被创建了");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("\n ServletContext对象被销毁了");
}
public void sessionCreated(HttpSessionEvent se) {
System.out.println("\n HttpSession对象被创建了");
}
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("\n HttpSession对象被销毁了");
}
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("\n servletRequest对象被销毁了");
}
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("\n servletRequest对象被创建了");
}
}
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(value="/test")
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession();//得到会话:如果没有会话,就创建一个
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet事件监听</title>");
out.println("</head>");
out.println("<body>");
out.println("<h2>创建了一个会话!</h2>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<html>
<head>
<title>servlet事件监听器</title>
</head>
<body>
<h2>
用html文档测试servlet事件监听器
</h2>
</body>
</html>
(1)启动Tomcat服务器(如果Tomcat已启动,请先关闭),观察控制台输出的信息。这说明了什么?
答:服务器启动时执行contextInitialized(ServletContextEvent sce)方法。首先servletContext全局对象被创建
(2)打开浏览器,输入http://127.0.0.1:8080/lab6_3/index.html网址,观察控制台输出的信息。这又说明了什么?
答:执行requestInitialized(ServletRequestEvent sre)方法,servletRequest对象被创建,随后自动执行requestDestory(ServletRequestEvent sre)方法,servletRequest对象被销毁了
(3)打开浏览器,输入http://127.0.0.1:8080/lab6_3/test网址,观察控制台输出的信息。这又说明了什么?
答:执行requestInitialized(ServletRequestEvent sre)方法,servletRequest对象被创建,紧接着执行了sessionCreated(HttpSessionEvent se)方法,HttpSession对象被创建,最后自动执行requestDestroyed(ServletRequestEvent sre)方法,servletRequest对象被销毁
问题:web.xml中的如下标记实现什么功能?
<session-config>
<session-timeout>1</session-timeout>
</session-config>
(4)过1分钟之后,再次观察控制台输出的信息。这又说明了什么?
答:实现了1分钟后执行sessionDestoryed(HttpSessionEvent se)方法
请总结application、session两类对象创建、销毁事件监听的方法与步骤。注意:不同监听接口、事件、方法的差异。
答:首先要实现ServletContextListener、HttpSessionListener、ServletRequestListener。重写三类对象创建和销毁的事件以便监听。当触发相应的Servlet对象就可以实现相应的监听。
- ServletContextListener:监听application的产生与销毁
- HttpSessionListener:监听session的产生与销毁
- ServletRequestListener:监听request的产生与销毁
四、application、session两类对象属性变化事件监听
package listener;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
//由MySttributeListener类实现application、session两类对象属性变化事件的监听
public class MyAttributeListener implements ServletContextAttributeListener, HttpSessionAttributeListener {
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("\n application对象中增加了一个名为" + scae.getName()
+ "的属性,该属性值为" + scae.getValue());
}
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("\n application对象中的" + scae.getName() + "属性被删除了\n");
}
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("\n application对象中" + scae.getName() + "的属性值被替换成了"
+ scae.getServletContext().getAttribute(scae.getName()));
}
public void attributeAdded(HttpSessionBindingEvent hbe) {
System.out.println("\n session对象中增加了一个名为" + hbe.getName()
+ "的属性,该属性值为" + hbe.getValue());
}
public void attributeRemoved(HttpSessionBindingEvent hbe) {
System.out.println("\n session对象中的" + hbe.getName() + "属性被删除了\n");
}
public void attributeReplaced(HttpSessionBindingEvent hbe) {
System.out.println("\n session对象中" + hbe.getName() + "的属性值被替换成了"
+ hbe.getSession().getAttribute(hbe.getName()));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<!-- <session-config>-->
<!-- <session-timeout>1</session-timeout>-->
<!-- </session-config>-->
<!-- 把MyAttributeListener类设置事件为监听器 -->
<listener>
<listener-class>listener.MyAttributeListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
<html>
<head>
<title>测试session对象属性变化</title>
</head>
<body>
<%@ page contentType="text/html;charset=gb2312"%>
<H4>
这是一个测试session对象属性变化的页面
</H4>
<%
session.setAttribute("width", "98.7654");
session.setAttribute("width", "9876.54");
session.removeAttribute("width");
%>
</body>
</html>
<html>
<head>
<title>测试application对象属性变化</title>
</head>
<body>
<%@ page contentType="text/html;charset=gb2312"%>
<H4>
这是一个测试application对象属性变化的页面
</H4>
<%
application.setAttribute("length", "123.45");
application.setAttribute("length", "1234.5");
application.removeAttribute("length");
%>
</body>
</html>
application、session两种事件对象的getName()、getValue()的功能是什么?如何获得变化过的属性值?
答:getName()获取application或session的属性名;getValue()获取application或session的属性值。
application对象获得变化过的属性值:getServletContext().getAttribute(getName())
session对象获得变化过的属性值:getSession().getAttribute(getName());
(1)打开浏览器,输入http://127.0.0.1:8080/lab6_4/ServletContextAttributeTest.jsp网址,观察控制台输出的信息。这说明了什么?
答:application对象设置属性时调用attributeAdded(ServletContextAttributeEvent scae)方法,重新更改属性时调用attributeReplaced(ServletContextAttributeEvent scae)方法,删除属性时调用attributeRemoved(ServletContextAttributeEvent scae)方法
(2)在浏览器输入http://127.0.0.1:8080/lab6_4/HttpSessionAttributeTest.jsp网址,观察控制台输出的信息。这又说明了什么?
答:session对象设置属性时调用attributeAdded(HttpSessionBindingEvent hbe)方法,重新更改属性时调用attributeReplaced(HttpSessionBindingEvent hbe)方法,删除属性时调用attributeRemoved(HttpSessionBindingEvent hbe)方法
请总结application、session两类对象属性变化事件监听的方法与步骤。注意:不同监听接口、事件差异,在方法名上有什么相似之处?
答:session对象和application对象都是设置属性时调用attributeAdded()方法,重新更改属性时调用attributeReplaced()方法,删除属性时调用attributeRemoved()方法。
ServletContextAttributeListener和HttpSessionAttributeListener包含的方法名称相同,只是参数不同。