过滤器和监听器
一、过滤器
过滤器就是在原数据和目标数据之间起过来作用的中间组件。
在JSP
和Web
应用程序中,过滤器是一种在服务端运行的Web组件程序,它可以截取客户端给服务端发的请求,也可以截取服务器给客户端的响应。
1,1、过滤器使用的3个场景
- 不文明的词汇被
*
所代替;
(当用户提交评论时,评论内容先经过过滤器,过滤器将不文明的词汇替换成*
,过来后的评论内容传递到目标文件。) - 表单提交的中文需要进行请求编码设置,可以通过过滤器统一进行请求编码设置。
- 通过过滤器为上传的图片统一添加水印。
1.2、过滤器的简单工作过程
当Web容器
获得一个对资源的请求时,Web容器判断是否存在过滤器和这个资源关联。如果存在关联就把请求交给过滤器去处理,在过滤器中可以对请求的内容做出改变,然后再将请求转交给被请求的资源。
当请求的资源做出响应时,web容器
同样会将响应先转发给过滤器,在过滤器中可以对响应做出处理,然后再将响应发送给客户端。
在这整个过程中客户端和目标资源是不知道过滤器存在。
1.3、过滤器链
在一个web应用程序中可以配置多个过滤器,从而形成过滤器链。在请求资源时,过滤器链中的过滤器依次对请求作出处理。在接受到响应时再按照相反的顺序对响应作出处理。
注意:
在过滤器中不一定必须将请求发送给被请求资源,也可以直接给客户端做出响应。
1.4、开发过滤器的步骤
- 定义过滤器类,实现
java.servlet.Filter
接口; - 重写
init()
方法、doFilter()
方法和destory()
方法; - 配置过滤器。
实例1:开发过滤器
项目的信息
Dynamic Web Project项目 | 包 | 类 |
---|---|---|
testFilter | com.bennett.filter | FirstFilter |
第一步:创建过滤器类
package com.bennett.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class FirstFilter implements Filter {
public void init(FilterConfig config) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器1请求");
chain.doFilter(request, response);
System.out.println("过滤器1响应");
}
public void destroy() {
}
}
第二步:配置过滤器
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>testFilter</display-name>
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.bennett.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
解释:
1、 <filter>
节点描述该Filter对应的类;
2、 <filter-mapping>
中的<filter-name>
必须和<filter>节
点中的值相同;
3、<filter-class>
配置过滤器类的存储路径;
4、<url-pattern>
指定该过滤器关联的URL,比如/*
指的是对所有资源都过滤。/admin/*
指的是对admin
目录下的所有资源文件进行过滤
第三步:测试过滤器
实例2:开发过滤器链
项目的信息
Dynamic Web Project项目 | 包 | 类 |
---|---|---|
testFilter | com.bennett.filter | SecondFilter |
第一步:创建过滤器类
package com.bennett.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class SecondFilter implements Filter {
public void init(FilterConfig config) {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器2请求");
chain.doFilter(request, response);
System.out.println("过滤器2响应");
}
public void destroy() {
}
}
第三步:配置过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>testFilter</display-name>
<!-- 第一个过滤器的配置 -->
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.bennett.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 第二个过滤器的配置 -->
<filter>
<filter-name>secondFilter</filter-name>
<filter-class>com.bennett.filter.SecondFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>secondFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
第三步:测试过滤器
过滤器链工作流程
实例3:使用过滤器实现汉字编码过滤器
项目的信息
Dynamic Web Project项目 | 包 | 类 |
---|---|---|
testFilter | com.bennett.filter | CharacterFilter |
第一步:定义过滤器类
package com.bennett.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CharacterFilter implements Filter {
private String encode = "utf-8";
@Override
// 从web.xml配置文件中读取默认编码,如果没有配置编码,默认使用utf-8
public void init(FilterConfig filterConfig) {
// FilterConfig用于从web.xml中配置读取默认编码
encode = filterConfig.getInitParameter("encode");
if(encode == null) {
encode = "UTF-8";
}else {
encode = encode.toUpperCase();
}
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if("POST".equalsIgnoreCase(request.getMethod())) {
// request.setCharacterEncoding(encode);
request.setCharacterEncoding(encode);
response.setContentType("text/html;charset="+encode);
chain.doFilter(request, response);
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
第二步:配置过滤器
<!-- 第三个过滤器的配置 -->
<filter>
<filter-name>characterFilter</filter-name>
<filter-class>com.bennett.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第三步:测试过滤器
创建一个jsp文件:add.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试编码过滤器</title>
</head>
<body>
<form action="MyServlet" method="post">
请输入汉字:<input type="text" name="key" value="我是汉字">
<input type="submit" value="发送">
</form>
</body>
</html>
创建Servlet文件:MyServlet.java
package com.bennett.filter;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public MyServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String key = request.getParameter("key");
System.out.println("key = "+ key);
}
}
效果图展示
项目目录结构:
二、监听器
监听器的作用是监听Web应用程序中某一个对象,并根据应用程序的需求做出相应的处理,JavaWeb应用程序中,Servlet容器提供了多种监听器。
监听器 | 描述 |
---|---|
ServletRequestListener | 监听request对象的 创建和销毁 |
ServletRequestAttributeListener | 监听向request作用域赋值和取值 |
HttpSessionListener | 监听session对象的创建和销毁 |
HttpSessionAttributeListener | 监听向session作用域赋值和取值 |
ServletContextListener | 监听application对象的 创建和销毁 |
ServletContextAttributeListener | 监听向application作用域赋值和取值 |
开发过滤器的步骤:
- 定义监听器类,实现监听器接口;
- 重写相应的方法;
- 配置监听器
实例4:统计在线人数
思路如下:
当有用户访问时,web容器会创建会话,当有用户退出时,web容器会销毁会话。HttpSessionListener监听器能够监听会话的创建和销毁,在会话创建时,在线人数加1,在会话销毁时,在线人数减1。在线人数需要存储在变量中,这个变量的值需要能够在每一位访问者的页面上显示,因此该变量存储在application作用域中。
项目的信息
Dynamic Web Project项目 | 包 | 类 |
---|---|---|
online | com.bennett.listener | ServletContextListenerImpl |
HttpSessionListenerImpl |
第一步:创建application对象监听器
在com.bennett.listener
包中创建类ServletContextListenerImpl,实现java.servlet。ServletContextListener接口,用于监听application对象的创建和销毁。当application创建时(web容器启动时),设置在线人数为0,当application对象销毁时(web容器关闭),清空在线人数。
ServletContextListenerImpl.java
package com.bennett.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ServletContextListenerImpl implements ServletContextListener{
public void contextInitialized(ServletContextEvent event) {
int num = 0;
ServletContext application = event.getServletContext();
application.setAttribute("onLineNum", num);
}
public void contextDestroyed(ServletContextEvent event) {
ServletContext application = event.getServletContext();
application.removeAttribute("onLineNum");
}
}
解释:
1、ServletContextListener
监听器用于监听application
对象创建和销毁;
2、当application
创建时,监听器自动调用contextInitialized()
方法;
3、当application
对象销毁时,监听器自动调用contextDestory()
方法;
4、contextInitialized()
方法中的参数ServletContextEvent
的getServletContext()
方法用于获取创建的application
对象,并将在线人数0
保存到键为onLineNum
的application
作用域中。
5、当application
对象销毁时,在contextDestory()
方法中将为onLineNum
的对象从application
作用域中移除。
第二步:配置application监听器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>online</display-name>
<!-- 配置application监听器 -->
<listener>
<listener-class>com.bennett.listener.ServletContextListenerImpl</listener-class>
</listener>
</web-app>
解释:
1、 <listener>
节点配置监听器;
2、<listener-class>
指明监听器类的路径。
第三步:创建session监听器
HttpSessionListenerImpl.java
package com.bennett.listener;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class HttpSessionListenerImpl implements HttpSessionListener{
public void sessionCreated(HttpSessionEvent event) {
ServletContext application = event.getSession().getServletContext();
Integer num = (Integer) application.getAttribute("onLineNum");
if(num != null) {
int count = num;
count = count + 1;
application.setAttribute("onLineNum", count);
}else {
application.setAttribute("onLineNum", 1);
}
}
public void sessionDestoryed(HttpSessionEvent event) {
ServletContext application = event.getSession().getServletContext();
Integer num = (Integer) application.getAttribute("onLineNum");
int count = num;
count = count + 1;
application.setAttribute("onLineNum", count);
}
}
解释:
1、当session
被创建时,会调用监听器的sessionCreated()
方法;
2、当session
被注销时,会调用监听器的sessionDestoryed()
方法;
3、在sessionCreated()
方法中实现在线人数加1
的功能;
4、在sessionDestoryed()
方法中实现在线人数减1
的功能。
第四步:配置session监听器
<!-- 配置session监听器 -->
<listener>
<listener-class>com.bennett.listener.HttpSessionListenerImpl</listener-class>
</listener>
第五步:在界面上显示在线人数
在WebContent
目录下创建online.jsp
文件,用于显示在线人数。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
当前在线人数: ${onLineNum}
</body>
</html>
第六步:测试在线人数
将项目部署到tomcat
容器,启动tomcat
容器,在浏览器中访问该项目的online.jsp
文件,查看在线人数。
结果展示
不同的浏览器会产生不同的session对象,刷新之后就会显示最大数。