生活中的过滤器:净水器、空气净化器等
web 中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能
步骤:
web.xml
注解使用:
@WebFilter("/*") // 访问所有资源之前,都会执行该过滤器
public class FilterTest01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterTest01 被执行了!");
// 放行,否则不会显示访问内容
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
web.xml
<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>test01filter-name>
<filter-class>com.example.filter_listener_test.FilterTest01filter-class>
filter>
<filter-mapping>
<filter-name>test01filter-name>
<url-pattern>/*url-pattern>
filter-mapping>
web-app>
@WebFilter("/*")
public class FilterTest02 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 对 request 对象请求消息增强
System.out.println("FilterTest02 执行了!");
filterChain.doFilter(servletRequest, servletResponse);
// 放行之后的代码
// 对 response 对象的响应消息增强
System.out.println("FilterTest02 返回了!");
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@WebFilter("/*")
public class FilterTest03 implements Filter {
/**
* 在服务器启动后,会创建 Filter 对象,然后调用 init 方法,只会执行一次,用于加载资源
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init 方法!");
Filter.super.init(filterConfig);
}
/**
* 每一次请求被拦截时,会执行,可以执行多次
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter 方法!");
}
/**
* 在服务器关闭后,Filter 对象被销毁,如果服务器正常关闭,则会正常执行 destroy 方法,只会执行一次,用于释放资源
*/
@Override
public void destroy() {
System.out.println("destroy 方法!");
Filter.super.destroy();
}
}
/index.jsp
→ 只有访问 index.jsp
资源时,过滤器才会被执行/user/*
→ 访问 /user
路径下的所有资源时,过滤器都会被执行*.jsp
→ 访问所有后缀名为 jsp
资源时,过滤器都会被执行/*
→ 访问所有资源时,多滤器都会被执行// @WebFilter("/index.jsp") // 具体资源路径配置:/index.jsp → 只有访问 index.jsp 资源时,过滤器才会被执行
// @WebFilter("/user/*") // 拦截目录:/user/* → 访问 /user 路径下的所有资源时,过滤器都会被执行
@WebFilter("*.jsp") // 后缀名拦截:*.jsp → 访问所有后缀名为 jsp 资源时,过滤器都会被执行
// @WebFilter("/*") // 拦截所有资源:/* → 访问所有资源时,多滤器都会被执行
public class FilterTest04 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterTest04 执行!");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@WebServlet("/user/findAllServlet")
public class ServletTest01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("findAllServlet 开启!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/user/updateServlet")
public class ServletTest02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("updateServlet 开启!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
拦截方式配置:资源被访问的方式
web.xml
配置:配置
标签即可// 浏览器直接请求资源时,该过滤器会被执行
// @WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.REQUEST)
// 浏览器只有转发访问 index.jsp 时,过滤器才会被执行
// @WebFilter(value = "/index.jsp",dispatcherTypes = DispatcherType.FORWARD)
// 配置多个,浏览器直接请求资源或者转发访问,过滤器会被执行
@WebFilter(value = "/index.jsp",dispatcherTypes ={ DispatcherType.FORWARD,DispatcherType.REQUEST})
public class FilterTest05 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterTest05 被访问了!");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@WebServlet("/user/updateServlet")
public class ServletTest02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("updateServlet 开启!");
// 转发到 index.jsp
request.getRequestDispatcher("/index.jsp").forward(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
<filter>
<filter-name>test01filter-name>
<filter-class>com.example.filter_listener_test.FilterTest01filter-class>
filter>
<filter-mapping>
<filter-name>test01filter-name>
<url-pattern>/*url-pattern>
<dispatcher>REQUESTdispatcher>
filter-mapping>
- 执行顺序:如果有两个过滤器:过滤器1和过滤器2
- 过滤器1
- 过滤器2
- 资源执行
- 过滤器2
- 过滤器1
@WebFilter("/*")
public class FilterTest06 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterTest06 执行了!");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("filterTest06 回来执行了!");
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@WebFilter("/*")
public class FilterTest07 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filterTest07 执行了!");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("filterTest07 回来执行了!");
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
访问 index.jsp
执行结果:
web.xml
配置:在
标签中,谁定义在上边,谁就先执行#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
#if ($JAVAEE_TYPE == "jakarta")
import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
#else
import javax.servlet.*;
import javax.servlet.annotation.*;
#end
import java.io.IOException;
@WebFilter(filterName = "${Entity_Name}")
public class ${Class_Name} implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
chain.doFilter(request, response);
}
}
案例资源【JSP 基础】
对其中的案例进行优化配置
需求:
分析:在案例资源中编写 LoginFilter 过滤器
@WebFilter("/*")
public class LoginFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
// 由于此 ServletRequest 对象中没有 Request 对象,所以要进行强制转换
HttpServletRequest requestA=(HttpServletRequest) request;
// 1. 获取资源请求路径
String uri= requestA.getRequestURI();
// 2. 判断是否包含登录相关的资源路径(CSS、JavaScript、图片、验证码等样式资源)
if (uri.contains("/login.jsp")||uri.contains("/loginServlet")||uri.contains("/css/")||uri.contains("/js/")||uri.contains("/fonts/")||uri.contains("/checkCodeServlet")){
// 包含,说明用户想要登录,或者正在登录界面,放行
chain.doFilter(request,response);
}else {
// 不包含,需要验证用户是否登录
// 3. 从获取的 Session 中获取 user
Object user = requestA.getSession().getAttribute("user");
if (user!=null){
// 登录了,放行
chain.doFilter(request,response);
}else {
// 没有登录,跳转登录界面
requestA.setAttribute("login_msg","您尚未登录,请先登录!");
// 进行页面跳转
requestA.getRequestDispatcher("/login.jsp").forward(requestA,response);
}
}
}
}
getParameter()
方法进行增强,产生一个新的 Request 对象(增强获取参数相关方法)代理对象 = Proxy.newProxyInstance();
简单了解使用动态代理
public interface SalePhone {
public String sale(double money);
public void show();
}
/**
* 真实类
*/
public class Apple implements SalePhone{
@Override
public String sale(double money) {
System.out.println("花费"+money+"元买了一台苹果手机!");
return "苹果手机";
}
@Override
public void show() {
System.out.println("展示苹果手机!");
}
}
public class ProxyTest {
public static void main(String[] args) {
// 1. 创建真实对象
Apple apple = new Apple();
// 2. 动态代理增强 Apple 对象
/*
* 三个参数:
* 1. 类加载器:真实对象.getClass().getClassLoader()
* 2. 接口数组:真实对象.getClass().getInterfaces()
* 3. 处理器:new InvocationHandler()
*/
SalePhone proxy_apple = (SalePhone) Proxy.newProxyInstance(apple.getClass().getClassLoader(), apple.getClass().getInterfaces(), new InvocationHandler() {
/*
* 代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
* 参数:
* 1. proxy:代理对象
* 2. method:代理对象调用的方法,被封装为的对象
* 3. args:代理对象调用的方法,传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强代码逻辑就会在这个方法中编写并执行
System.out.println("该方法执行了!");
System.out.println(method.getName());
System.out.println(args[0]);
return null;
}
});
// 3. 调用方法
String phone = proxy_apple.sale(8999);
System.out.println(phone);
// proxy_apple.show();
}
}
简单练习动态代理的增强方式,增强某些功能
public class ProxyTest {
public static void main(String[] args) {
// 1. 创建真实对象
Apple apple = new Apple();
// 2. 动态代理增强 Apple 对象
SalePhone proxy_apple = (SalePhone) Proxy.newProxyInstance(apple.getClass().getClassLoader(), apple.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否是 sale 方法
if (method.getName().equals("sale")){
// 1. 增强参数
double money=(double) args[0];
money=money*0.85;
System.out.println("专车接送用户!");
// 使用真实对象调用改方法
Object obj = method.invoke(apple, money);
System.out.println("免费送货上门!");
// 2. 增强返回值
return obj+"+附赠+充电器";
}else {
Object obj = method.invoke(apple, args);
return obj;
}
}
});
// 3. 调用方法
String phone = proxy_apple.sale(8999);
System.out.println(phone);
proxy_apple.show();
}
}
敏感词汇.txt
文件导入到 IDEA 中配置文件 resources 资源目录下(Maven 框架下的 resources 资源目录 【Maven 基础】),如果没有使用 Maven 框架则直接将配置文件放在src/com
目录下
注意:编码格式的更改,防止乱码
辣鸡
笨猪
牛逼
@WebFilter("/*")
public class SensitiveWordsFilter implements Filter {
// 存放敏感词汇的集合
private List<String> list=new ArrayList<>();
public void init(FilterConfig config) throws ServletException {
try {
// 1. 获取文件的真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
// 2. 读取文件
BufferedReader bufferedReader = new BufferedReader(new FileReader(realPath));
// 3. 将文件的每一行数据添加到 list 集合中
String line=null;
while ((line=bufferedReader.readLine())!=null){
list.add(line);
}
bufferedReader.close();
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
// 1. 创建代理对象,增强 getParameter 方法
ServletRequest proxy_request = (ServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强 getParameter 方法
// 判断是否是 getParameter 方法
if (method.getName().equals("getParameter")){
// 增强返回值
// 获取返回值
String value=(String) method.invoke(request,args);
if (value!=null){
for (String str :list) {
if (value.contains(str)){
value=value.replaceAll(str,"**");
}
}
}
return value;
}
return method.invoke(request,args);
}
});
// 判断方法名是否是 getParameterMap
// 判断方法名是否是 getParameterValue
// 2. 放行
chain.doFilter(proxy_request, response);
}
}
@WebServlet("/testServlet")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name=request.getParameter("name");
String msg = request.getParameter("msg");
System.out.println(name+":"+msg);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
http://localhost:8080/test/testServlet?name=张三&msg=你个大辣鸡
(具体要查看自己的资源访问路径)Web 三大组件之一
监听 ServletContext 对象的创建和销毁
void contextDestroyed(ServletContextEvent sce)
:ServletContext 对象被销毁之前会调用该方法void contextInitialized(ServletContextEvent sce)
:ServletContext 对象创建后会调用该方法web.xml
public class ContextLoaderListener implements ServletContextListener {
/**
* 用于监听 ServletContext 对象的创建,ServletContext 对象服务器启动后自动创建
* 该方法在服务器启动后自动调用
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext 对象被创建了!");
}
/**
* 在服务器关闭后,ServletContext 对象被销毁,当服务器正常关闭后该方法被调用
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext 对象被销毁了!");
}
}
web.xml
即可使用
<listener>
<listener-class>com.example.filter_listener_test.ContextLoaderListenerlistener-class>
listener>
@WebListener
注解public class ContextLoaderListener implements ServletContextListener {
/**
* 用于监听 ServletContext 对象的创建,ServletContext 对象服务器启动后自动创建
* 该方法在服务器启动后自动调用
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
// 加载资源文件
// 1. 获取 ServletContext 对象
ServletContext servletContext = sce.getServletContext();
// 2. 加载资源文件
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
// 3. 获取真实路径
String realPath = servletContext.getRealPath(contextConfigLocation);
// 4. 加载进内存
try {
FileInputStream fileInputStream = new FileInputStream(realPath);
// 打印,判断是否获取到流对象
System.out.println(fileInputStream);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("ServletContext 对象被创建了!");
}
/**
* 在服务器关闭后,ServletContext 对象被销毁,当服务器正常关闭后该方法被调用
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext 对象被销毁了!");
}
}
web.xml
配置:
<listener>
<listener-class>com.example.filter_listener_test.ContextLoaderListenerlistener-class>
listener>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/classes/applicationContext.xmlparam-value>
context-param>
applicationContext.xml
配置文件,如果使用 Maven 框架,则将该文件放到 resources 资源目录下(Maven 框架下的 resources 资源目录 【Maven 基础】),如果没有使用 Maven 框架则直接将配置文件放在 src/com
目录下
<bean>bean>