WEB阶段6:过滤器监听器全局字符修改案例用户权限过滤案例装饰者模式过滤敏感词汇统计当前网站在线人数

news/2024/5/20 6:42:28/文章来源:https://blog.csdn.net/weixin_42530572/article/details/108391437

过滤器&监听器&全局字符修改案例&用户权限过滤案例&装饰者模式过滤敏感词汇&统计当前网站在线人数

回顾

  1. JSP的页面脚本元素
组成部分语法格式
JSP代码片段<% Java代码 %>
JSP声明<%! 声明全局变量 %>
JSP脚本表达式<%= 变量值 %>
注释<%-- --%>
2. EL表达式如何获取不同类型的数据
EL表达式获取不同数据说明
获取JavaBean的属性值${对象名.属性名}
获取数组和List中的值${集合或数组[索引]}
获取Map中的值${map.键} 或 ${map[“键”]}
  1. 判断标签
<c:if test="${判断条件}">
</c:if>
  1. 多分支标签
<c:choose><c:when test="${判断条件}"></c:when><c:when test="${判断条件}"></c:when><c:otherwise></c:otherwise>
</c:choose>
  1. 遍历标签 forEach
属性名属 性 描 述
var每个要遍历的元素,放在页面域中
varStatus变量的状态对象,包含了四个属性:index, count, first, last
items要遍历的集合或数组,放在作用域中
begin从哪个元素开始遍历
end到哪个元素结束
step步长,每次跨几个元素
  1. 什么是MVC
MVC描述Java Web的实现技术
MModel:模型JavaBean, Service, Dao
VView:视图JSP, JSTL, EL
CController:控制器Servlet
1. 获取用户提交的参数值
2. 调用业务层的方法
3. 控制页面的跳转

学习目标

  1. 过滤器

    1. 能够说出过滤器的作用
    2. 能够编写过滤器
    3. 能够说出过滤器生命周期相关方法
    4. 能够根据过滤路径判断指定的过滤器是否起作用
    5. 能够说出什么是过滤器链
    6. 能够编写过滤器解决全局乱码
  2. 监听器

    1. 能够说出监听器的作用
    2. 能够使用ServletContextListener监听器

学习内容

1. 过滤器的基本概念

目标

  1. 过滤器的概念

  2. JavaWeb的三种组件

  3. 过滤器的使用场景

Java Web的三种基本组件

组件作用
Servlet运行在Web容器中Java程序,在MVC中做的控制器使用,生成动态网页。
过滤器Filter用来处理一些公共的,通用的功能
1. 拦截用户的请求
2. 修改用户的请求和响应
监听器Listener对作用域进行监听
1. 监听作用域的创建和销毁
2. 监听作用域中属性的变化

过滤器所处的位置

image-20200903085733970

过滤器的使用场景:

  1. 可以集中处理汉字乱码的问题,把处理乱码的代码写在过滤器中,让所有通过这个过滤器的请求都没有乱码的问题

  2. 用户登录权限的判断,只需要在过滤器中判断请求,如果登录了就放行,没有登录就拦截。

  3. 可以对用户发送的内容进行过滤,让最终的内容发生变化或拦截

小结

  1. JavaWeb的三种组件
    1. Servlet
    2. Filter
    3. Listener
  2. 过滤器的使用场景:对请求和响应进行修改或拦截

2. 案例:编写第1个过滤器【重点】

目标

  1. 过滤器的开发步骤

  2. 编写第1个过滤器

过滤器的演示案例:

需求

  1. Web资源是:HelloServlet
  2. 过滤器:HelloFilter

创建一个过滤器HelloFilter,在运行HelloServlet前和后分别输出一句话,在HelloServlet中也输出一句话,观察控制台的运行效果。

执行效果:

1552917350933

Servlet的代码

package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/demo1")
public class Demo1HelloServlet 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);}
}

使用注解的方式

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;/*** 创建过滤器的步骤:* 1. 创建一个类,实现javax.servlet.Filter接口 (注意不要选错)* 2. 要重写接口中所有的方法,其中doFilter方法就是执行过滤功能的方法* 3. 要在web.xml中配置过滤器的过滤地址或使用@WebFilter注解来配置*/
@WebFilter("/demo1")  //可以过滤所有的资源或过滤某些指定的资源,这是它过滤的地址,不是访问地址
public class Demo1HelloFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}/*** 执行过滤的功能* @param req 请求对象,它是HttpServletRequest的父接口,其实是同一个对象* @param resp 响应对象,它是HttpServletResponse的父接口,其实是同一个对象* @param chain 过滤器链*/@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {System.out.println("过滤器:请求的时候执行");//调用过滤器链的方法,如果执行这句话,请求被放行,到达web资源;如果没有执行,请求就被拦截chain.doFilter(req,resp);System.out.println("过滤器:响应的时候执行");}@Overridepublic 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>demo1</filter-name><!--过滤器的类全名--><filter-class>com.itheima.filter.Demo1HelloFilter</filter-class></filter><!--指定过滤器的过滤地址--><filter-mapping><!--与上面的名字相同--><filter-name>demo1</filter-name><!--这是过滤地址,不是访问地址,必须以/开头--><url-pattern>/demo1</url-pattern></filter-mapping>
</web-app>

小结

  1. 过滤器的编写要实现哪个接口?

    javax.servlet.Filter
    
  2. 过滤的方法是哪个?

    doFilter(请求,响应,过滤链)
    
  3. @WebFilter注解

@WebFilter注解属性说明
filterName过滤器的名字
urlPatterns过滤的地址:是一个字符串的数组,可以指定多个
value同上

3. 过滤器的执行流程

目标

过滤器的执行流程

过滤器的执行流程

过滤器也是运行在Web容器中

1552917794230

过滤器的执行流程如下:

  1. 用户发送请求,请求的是Web资源。
  2. 如果请求的资源访问地址与过滤器过滤的地址匹配,就会执行过滤器
  3. 执行过滤器中doFilter方法
  4. 在doFilter中再调用一个chain.doFilter()方法放行,如果没有执行这句话就是拦截
  5. 如果放行,就会到达web资源
  6. 响应回来的时候还会再次经过过滤器,并且执行doFilter()放行后面的代码
  7. 返回到浏览器端

4. 过滤器的生命周期【重点】

目标

过滤器的生命周期有哪些方法

过滤器加载的时机:

  • 回顾:以前Servlet是什么时间加载的?

    用户第一次访问的时候加载
    
  • Filter什么时候加载呢?

    因为过滤器要拦截其它的资源,所以必须比其它资源更早实例化。在服务器启动的时候就加载了。
    

生命周期的方法

Filter接口中的方法作用和执行次数
void init(FilterConfig filterConfig)初始化的时候执行,执行1次
void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
只要匹配过滤的地址,每次请求都会执行,执行多次
public void destroy()服务器关闭的时候,销毁执行1次

示例:生命周期的过程

执行效果

image-20200903095805088

案例代码

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.sql.Timestamp;/*
filterName:表示过滤器的名字,不要出现同名
urlPatterns:过滤的地址*/
@WebFilter(filterName = "Demo2LifeCycleFilter", urlPatterns = "/demo1")
public class Demo2LifeCycleFilter implements Filter {//初始化的方法,在tomcat启动的时候,执行1次public void init(FilterConfig config) throws ServletException {System.out.println(new Timestamp(System.currentTimeMillis()) + " 初始化过滤器");}//每次请求都会执行public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println(new Timestamp(System.currentTimeMillis()) + "过滤器:请求的时候执行");//放行chain.doFilter(req, resp);System.out.println(new Timestamp(System.currentTimeMillis()) + "过滤器:响应的时候执行");}//销毁的时候执行1次public void destroy() {System.out.println(new Timestamp(System.currentTimeMillis()) + "过滤器销毁");}}

小结

  1. 过滤器什么时候执行初始化?服务器启动
  2. 过滤的方法执行多少次?多次
  3. 过滤器什么时候销毁?服务器关闭的时候

5. FilterConfig接口

目标

学习FilterConfig接口的方法

方法

使用配置文件的方式中

FilterConfig接口中的方法功能
String getInitParameter(“参数名”)通过参数名获取配置文件中初始的参数值
Enumeration<String> getInitParameterNames()获取配置文件中所有的初始参数名

代码

过滤器代码

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.Enumeration;/*** 读取配置参数,所以使用配置的方式*/
public class Demo3ConfigFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//放行chain.doFilter(req, resp);}//过滤器的配置对象,通过init方法传递进来,可以在方法中直接使用public void init(FilterConfig config) throws ServletException {//通过参数名读取一个初始的参数值String user = config.getInitParameter("user");System.out.println("参数:" + user);//读取所有的初始参数名字Enumeration<String> parameterNames = config.getInitParameterNames();//遍历while (parameterNames.hasMoreElements()) {String name = parameterNames.nextElement();  //获取名字String value = config.getInitParameter(name);  //通过名字获取值System.out.println("初始参数名:" + name + ",值:" + value);}}}

web.xml

<filter><filter-name>demo3</filter-name><filter-class>com.itheima.filter.Demo3ConfigFilter</filter-class><!--添加初始的参数--><init-param><param-name>user</param-name><param-value>Rose</param-value></init-param><init-param><param-name>age</param-name><param-value>20</param-value></init-param>
</filter>
<filter-mapping><filter-name>demo3</filter-name><url-pattern>/demo1</url-pattern>
</filter-mapping>

效果

只要启动服务器就被初始化,就执行了init()方法中代码

参数:Rose
初始参数名:user,值:Rose
初始参数名:age,值:20

小结

FilterConfig接口中有以下两个方法:

getInitParameter() 通过初始的参数名,获取参数值
getInitParameterNames() 获取所有的初始参数名字

6. 过滤器映射的访问路径

目标

理解过滤器的映射路径的写法

Servlet中与过滤器中映射路径的区别

  • Servlet:路径就是它的访问地址

    @WebServlet("/demo1")
    
  • Filter:不是它的访问地址,是它的过滤地址

    @WebFilter("/demo1") 
    
  • 疑问:浏览器访问目标资源的路径,如果目标地址不存在,过滤器会不会运行?

    只要匹配过滤地址,无论目标资源是否存在,都会执行过滤器
    

过滤地址编写方式

匹配方式匹配哪些资源示例
以/开头精确匹配,访问的资源地址与过滤的地址完全一样/demo1
目录匹配,过滤的是某个目录下所有的资源/admin/*
过滤所有的资源,整个web模块下所有的资源都会过滤/*
以扩展名结尾匹配指定的扩展名就会被过滤*.do
  • 疑问:以/开头的匹配模式和以扩展名结尾的配置,同时出现会怎样?

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJnxNvJP-1599131780590)(assets/image-20200903101959187.png)]

    Caused by: java.lang.IllegalArgumentException: 过滤器映射中的<url-pattern> [/*.do] 无效
    结论:不能同时出现/开头和扩展名结尾,否则会导致tomcat加载这个模块失败,所有的资源都不能正常访问
    

过滤多个地址的写法

因为它的过滤地址是一个字符串的数组,可以指定多个过滤的地址

过滤器匹配多个地址说明
@WebFilter({"/demo1","/demo2"})同时过滤demo1和demo2
image-20200903102146383过滤admin目录下所有的资源和所有的JSP页面
过滤的地址是所有过滤地址的并集,不是交集

小结:根据过滤路径判断指定的过滤器是否起作用

浏览器的访问地址过滤器的配置是否起作用
http://localhost:8080/项目地址/aaa/*
http://localhost:8080/项目地址/aaa/aaa是,精确匹配
http://localhost:8080/项目地址/aaa.do*.do是,扩展名匹配
http://localhost:8080/项目地址/aaa/bbb/aaa/*是,目录匹配
http://localhost:8080/项目地址/bbb.do/*.do否,错误
http://localhost:8080/项目地址/aaa/bbb.action/aaa/*.action否,错误

7. 过滤器的三种拦截方式

目标

过滤器常用的两种拦截方式

默认的拦截方式

在默认的情况下只有直接在地址栏上输入的访问地址,才会经过过滤器。这种拦截方式称为REQUEST拦截

案例

1). 在index.jsp转发到HelloServlet

2). 过滤器的配置

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>首页</title></head><body><%-- 转发 --%><%--<jsp:forward page="/demo1"></jsp:forward>--%><%--包含页面--%><jsp:include page="/demo1"/></body>
</html>

配置方式1:注解的方式:

/*
filterName:表示过滤器的名字,不要出现同名
urlPatterns:过滤的地址
dispatcherTypes: 指定拦截方式DispatcherType.FORWARD 拦截转发DispatcherType.REQUEST 拦截直接在浏览器上输入的请求DispatcherType.INCLUDE 拦截包含的页面*/
@WebFilter(filterName = "Demo2LifeCycleFilter", urlPatterns = "/demo1",dispatcherTypes = {DispatcherType.FORWARD, DispatcherType.REQUEST, DispatcherType.INCLUDE})

配置方式2:web.xml文件

<!--使用配置的方式指定过滤器-->
<filter><!--过滤器的名字--><filter-name>demo1</filter-name><!--过滤器的类全名--><filter-class>com.itheima.filter.Demo1HelloFilter</filter-class>
</filter>
<!--指定过滤器的过滤地址-->
<filter-mapping><!--与上面的名字相同--><filter-name>demo1</filter-name><!--这是过滤地址,不是访问地址,必须以/开头--><url-pattern>/demo1</url-pattern><!--拦截方式--><dispatcher>FORWARD</dispatcher><dispatcher>REQUEST</dispatcher><dispatcher>INCLUDE</dispatcher>
</filter-mapping>

小结:过滤器的拦截类型

过滤类型作用
REQUEST对正常的请求进行拦截
FORWARD对转发进行拦截
INCLUDE对包含进行拦截

8. 案例:使用过滤器过滤全局汉字乱码问题【重点】

目标

编写过滤器,过滤所有Servlet中使用POST方法提交的汉字的编码。

分析

image-20200903105446999

开发步骤

  1. 有2个Servlet,一个是LoginServlet登录,一个是RegisterServlet注册
  2. 有2个JSP页面,1个是login.jsp,有表单,登录名。1个register.jsp,有表单,有注册的名字。都使用POST提交用户名使用汉字提交。
  3. 使用过滤器,对所有的Servlet的POST方法进行过滤。
  4. 在没有使用过滤器之前,每个Servlet必须加上汉字编码:request.setCharacterEncoding(字符集); 字符集与网页的编码要一致

代码

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<h2>登录页面</h2>
<form action="login" method="post">登录名:<input type="text" name="user"><br><input type="submit" value="登录">
</form>
</body>
</html>

register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户注册</title>
</head>
<body>
<h2>用户注册</h2>
<form action="register" method="post">注册名:<input type="text" name="name"><br><input type="submit" value="注册">
</form>
</body>
</html>

LoginServlet.java

package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/login")
public class LoginServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//获取提交的用户名String user = request.getParameter("user");out.print("登录名是:" + user);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}

RegisterServlet.java

package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/register")
public class RegisterServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();//获取参数String name = request.getParameter("name");out.print("注册的名字:" + name);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}

EncodeFilter.java

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;/*** 设置为过滤所有的Servlet*/
@WebFilter(filterName = "CharacterEncodingFilter", urlPatterns = "/*")
public class CharacterEncodingFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//1.判断是否是POST方法HttpServletRequest request = (HttpServletRequest) req;//2.这里POST是大写if (request.getMethod().equals("POST")) {//3.对POST方法进行编码request.setCharacterEncoding("utf-8");}//4.要放行chain.doFilter(req, resp);}public void init(FilterConfig config) throws ServletException {}}

小结

编写一个过滤器就可以对所有的Servlet进行汉字编码

  1. 使用哪个方法编码:request.setCharacterEncoding(“utf-8”)
  2. 过滤的地址: /*
  3. 放行使用哪个方法:chain.doFilter(请求,响应)

9. 案例:用户权限的过滤器【重点】

目标:

使用过滤器进行权限的控制,实现正确的访问

  • add.jsp 添加数据,需要登录才可访问
  • update.jsp 修改数据,需要登录才可访问
  • list.jsp 查询数据,不用登录
  • login.jsp 登录页面

项目结构

 1552919494358

流程

image-20200903112110640

实现步骤:

  1. 在Web下创建4个页面 login.jsp上使用${msg},显示信息。
  2. 创建LoginServlet, 判断用户名密码是否正确,如果正确,则在会话域中保存用户信息。登录成功跳转到add.jsp,登录失败则在域中写入登录失败的信息,并且跳转到login.jsp。
  3. 使用过滤器解决:创建AuthorityFilter
    1. 得到HttpServletRequest、HttpSession对象
    2. 如果会话中没有用户信息,则转到登录页面,并return。
    3. 否则继续访问后续的Web资源

案例代码:

登录页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>登录页面</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login" method="post">用户名:<input type="text" name="username"> <span id="info">${msg}</span><br>密码:<input type="password" name="password"><br><input type="submit" value="登录">
</form>
</body>
</html>

LoginServlet

package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/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.如果正确,就把用户的信息放在会话域中HttpSession session = request.getSession();session.setAttribute("username", username);//4.重定向到add.jsp (添加页面)response.sendRedirect(request.getContextPath() + "/admin/add.jsp");}//5.登录失败,向请求域中添加信息,转发到JSP页面上显示else {request.setAttribute("msg", "用户名或密码错误");//这里必须使用转发,因为要保留请求域中数据request.getRequestDispatcher("/login.jsp").forward(request, response);}}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}

AuthorityFilter

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;/*** 注:这个过滤地址不能指定为/*所有,必须要修改为/admin/** 没有登录进行拦截,将用户重定向到登录页面*/
@WebFilter(filterName = "AuthorityFilter", urlPatterns = "/admin/*")
public class AuthorityFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//1. 过滤器中判断会话域是否有用户的信息//将父接口转成子接口HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;//获取会话对象HttpSession session = request.getSession();String username = (String) session.getAttribute("username");if (username != null) {//2. 如果有表示已经登录,放行chain.doFilter(req, resp);}else {//3. 如果没有就不能访问,进行拦截response.sendRedirect(request.getContextPath() + "/login.jsp");}}public void init(FilterConfig config) throws ServletException {}}

小结

  1. 过滤的地址是:/admin/*
  2. 注:过滤器中使用的是请求对象和响应对象都是父接口,如果要使用子接口中方法,必须进行强转

10. 过滤器链FilterChain的使用

目标

  1. 什么是过滤器链

  2. 过滤器链的执行顺序是怎样的

过滤器链的概念

浏览器端请求Web资源,如果经过了多个过滤器,这多个过滤器就组成了一个过滤器链。

链条中每个过滤器处理方式是一样的:如果下一个是过滤器就会把请求放行给过滤器,如果下一个是Web资源,当前就是最后一个过滤器,请求就交给Web资源。

组成过滤器链前提是:这些过滤器的过滤地址都能过滤同一个Web资源。

过滤器链有一个接口:FilterChain

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X9LvtSEi-1599131780597)(assets/1552919196802.png)]

FilterChain接口中的方法

void doFilter(ServletRequest request, ServletResponse response)  
参数1:请求对象  参数2:响应对象
将请求和响应向后传递,导致调用链中的下一个过滤器,或者如果调用过滤器是链中的最后一个过滤器,则导致调用链末端的Web资源。

示例:过滤器链 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOw3LQ4Z-1599131780655)(assets/1552919236666.png)]

需求

创建两个过滤器OneFilter和TwoFilter,访问ResourceServlet,每个过滤器的请求和响应各输出一句话,观察过滤器的执行过程。

执行效果:

 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J6xQu2Ct-1599131780658)(assets/1552919267302.png)]

第一个过滤器

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.sql.Time;@WebFilter(filterName = "OneFilter", urlPatterns = "/*")
public class OneFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println(new Time(System.currentTimeMillis()) + " 执行过滤器1的请求");chain.doFilter(req, resp);  //过滤器链的方法,放行System.out.println(new Time(System.currentTimeMillis()) + " 执行过滤器1的响应");}public void init(FilterConfig config) throws ServletException {}}

第二个过滤器

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.sql.Time;@WebFilter(filterName = "TwoFilter", urlPatterns = "/*")
public class TwoFilter implements Filter {public void destroy() {}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {System.out.println(new Time(System.currentTimeMillis()) + " 执行过滤器2的请求");chain.doFilter(req, resp);System.out.println(new Time(System.currentTimeMillis()) + " 执行过滤器2的响应");}public void init(FilterConfig config) throws ServletException {}}

Web资源

package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Time;/*** 这是web资源*/
@WebServlet("/resource")
public class ResourceServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println(new Time(System.currentTimeMillis()) + " 访问Web资源");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}

疑问:过滤器链的执行顺序是怎样的?

注:要么使用注解,要么使用配置的方式

  1. 使用web.xml的配置方式:
<?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>one</filter-name><filter-class>com.itheima.filter.OneFilter</filter-class></filter><filter-mapping><filter-name>one</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter><filter-name>two</filter-name><filter-class>com.itheima.filter.TwoFilter</filter-class></filter><filter-mapping><filter-name>two</filter-name><url-pattern>/*</url-pattern></filter-mapping></web-app>
  1. 使用注解的配置方式:
按过滤器类名的字母顺序排序,哪个在前面,哪个就先执行

小结

过滤器链的执行顺序是?

  1. 配置:按出现在web.xml中先后顺序
  2. 注解:按过滤器类名的字母顺序排序,哪个在前面,哪个就先执行

11. 案例:过滤敏感词汇

需求

当用户发帖的时候,如果发出敏感词汇就进行过滤,并提示发贴失败,否则显示正常的发贴内容。

案例效果

  1. 在表单中输入含有非法字符的言论,点击提交按钮

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aMHgMS3F-1599131780663)(assets/Snipaste_2020-03-27_11-00-41.png)]

  1. 控制台显示如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lW9anHB7-1599131780666)(assets/Snipaste_2020-03-27_11-00-32.png)]

  1. 正常发贴的情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-94Ar7qTZ-1599131780675)(assets/Snipaste_2020-03-27_11-00-58.png)]

案例分析

  1. 创建一个表单用于发表言论。
  2. 创建一个PostWordServlet,正常接收用户的输入信息,并且打印到浏览器
  3. 创建一个words.txt文件,其中存入非法字符。
  4. 创建一个Filter,只过滤PostWordServlet。
    1. 在init方法中将txt文件中的非法字符读取到List集合中。注:指定字符的编码为utf-8
    2. 在doFilter方法中,获取请求中的参数,遍历上面的List集合,判断请求的文字中是否包含非法字符。
    3. 如果言论中含有非法字符,就拦截,并且直接在过滤器中打印提示:非法言论,退出过滤器。
    4. 否则就放行

实现步骤

  1. 创建一个表单,用于发表言论
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>发贴</title>
</head>
<body>
<form method="post" action="PostWordServlet">发贴:<br><textarea name="message" rows="5" cols="40"></textarea></br> <hr/><input type="submit" value="提交">
</form>
</body>
</html>
  1. 创建一个txt文件,存入非法字符。要注意,文件存储使用的UTF-8字符集,否则可能出现乱码。
    建议直接使用提供的word.txt文件,放在src目录下。
穷逼
笨蛋
白痴
王八
贱人
傻逼
  1. 创建一个servlet用于接受表单提交的内容
package com.itheima.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/PostWordServlet")
public class PostWordServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("<h2>你发贴的内容如下:</h2>");//获取文本域的内容String message = request.getParameter("message");out.print(message);}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}
}
  1. 创建一个过滤器,用来拦截请求,过滤请求中发表的言论的非法字符
package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** 要过滤Servlet*/
@WebFilter(filterName = "WordFilter", urlPatterns = "/PostWordServlet")
public class WordFilter implements Filter {//保存文件中非法字符private List<String> words = new ArrayList<>();//在初始化的方法中读取文本文件的内容,放在一个集合中public void init(FilterConfig config) throws ServletException {//1.获取文件words.txt的输入流,类加载器默认从根目录下读取资源,类对象默认是从当前类所在的包中读取资源InputStream in = this.getClass().getResourceAsStream("/words.txt");//2.使用转换流把字节流转成字符流try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"))) {String line = null;//3. 如果不为空,就继续向下读取一行while ((line = reader.readLine()) != null) {//每一行要添加到集合中words.add(line);}} catch (IOException e) {e.printStackTrace();}System.out.println("读取到的集合:" + words);}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;//解决汉字乱码的问题request.setCharacterEncoding("utf-8");//获取用户提交的内容String message = request.getParameter("message");//遍历集合for (String word : words) {//判断文字中是否包含非法字符,如果包含就拦截if (message.contains(word)) {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("您的言论非法,发贴无效");//退出方法,没有放行,不会进入到Servlet中去return;}}//不包含就放行chain.doFilter(req, resp);}public void destroy() {}}

小结

过滤敏感词汇过滤器的开发步骤:

  1. 读取src下文本文件,放在一个集合中
  2. 在过滤的方法中去判断用户的输入是否包含指定的字符
  3. 如果包含就拦截,没有包含就放行

12. 扩展:使用装饰者模式进行改进

目标

使用装饰者模式改进上面的功能,只替换敏感词汇为*号,其它内容不变

回顾装饰者模式

什么是装饰者模式

装饰者模式是在不改变原类文件,使用继承的情况下,动态地扩展一个类的功能。

它是通过创建一个子类对象,也就是装饰对象来包裹真实的对象。

image-20200616123554044

使用场景

在开发过程中,如果发现某个类的某个(某些)方法不满足需求(不够用),那么可以使用装饰者模式对该类
进行装饰,增强这个类的方法。

装饰者模式的作用:专门对类的方法进行增强!

装饰者模式中的各个角色

  1. 抽象角色(HttpServletRequest接口):给出一个抽象接口或父类,以规范准备接收附加功能的对象(即具体角色)。
  2. 具体角色(HttpServletRequestWrapper实现类):定义一个将要接收附加功能的类。
  3. 装饰角色(继承于HttpServletRequestWrapper):持有一个具体角色的实例,继承于抽象角色或具体角色,给具体角色添加附加功能的类。

步骤

  1. 继承于被装饰的类(要进行功能增强类HttpServletRequestWrapper)
  2. 需要在构造方法中传入原来的对象
  3. 重写需要增强的方法:getParameter()
  4. 重写的方法中调用原来的方法,对结果进行增强
    1. 调用原来的方法,包含有脏话的内容
    2. 对脏话的集合进行遍历
    3. 如果信息中包含了某个元素
    4. 使用replaceAll进行替换
    5. 返回替换好的字符串
  5. 过滤器中需要放行增强后的请求对象

代码

package com.itheima.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** 要过滤Servlet*/
@WebFilter(filterName = "WordFilter", urlPatterns = "/PostWordServlet")
public class WordFilter implements Filter {//保存文件中非法字符private List<String> words = new ArrayList<>();//在初始化的方法中读取文本文件的内容,放在一个集合中public void init(FilterConfig config) throws ServletException {//1.获取文件words.txt的输入流,类加载器默认从根目录下读取资源,类对象默认是从当前类所在的包中读取资源InputStream in = this.getClass().getResourceAsStream("/words.txt");//2.使用转换流把字节流转成字符流try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"))) {String line = null;//3. 如果不为空,就继续向下读取一行while ((line = reader.readLine()) != null) {//每一行要添加到集合中words.add(line);}} catch (IOException e) {e.printStackTrace();}System.out.println("读取到的集合:" + words);}public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse response = (HttpServletResponse) resp;//解决汉字乱码的问题request.setCharacterEncoding("utf-8");//创建一个增强以后的请求对象WordRequestWrapper requestWrapper = new WordRequestWrapper(request);//放行的是增强以后的请求对象chain.doFilter(requestWrapper, resp);}public void destroy() {}/*** 写成一个内部类,可以直接使用List集合* HttpServletRequestWrapper类没有无参的构造方法*/class WordRequestWrapper extends HttpServletRequestWrapper {//请求对象,没有增强前的对象private HttpServletRequest request;//构造方法,接收外面传递进来的请求对象,这个请求对象就是我们要增强的对象public WordRequestWrapper(HttpServletRequest request) {super(request);this.request = request;}//重写父类的这个方法,对这个方法进行增强@Overridepublic String getParameter(String name) {//调用原来的方法,获取用户发贴的内容String message = request.getParameter(name);//遍历非法内容的集合for (String word : words) {//判断内容是否包含脏话if (message.contains(word)) {//将文本中的脏话换成*号message = message.replaceAll(word, "**");}}//到这里message就是已经替换完成了return message;}}}

小结

装饰者模式:对现在的类方法的功能进行增强,不用修改原有的类

13. 监听器的概述

目标

  1. 监听器的作用

  2. 常用的监听器有哪些

作用

  1. 监听作用域的创建和销毁
  2. 监听作用域中属性的变化

回顾:三种作用域的创建与销毁时机

作用域接口名作用范围生命周期
请求域HttpServletRequest一个用户的一次请求一次请求结束
会话域HttpSession一个用户的所有请求会话过期
上下文域ServletContext所有用户的所有请求服务器关闭的时候

监听器接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cUElCnqy-1599131780678)(assets/1552919771117.png)]

小结

  1. 上下文域创建和销毁的监听接口:ServletContextListener
  2. 上下文域属性修改的监听接口:ServletContextAttributeListener

14. ServletContextListener监听器【重点】

目标

  1. ServletContextListener接口有哪些方法

  2. 编写ServletContextListener监听器

ServletContextListener监听器的概述

  1. 作用:监听上下文域的创建和销毁
  2. 创建时机: 服务器启动并且加载当前项目的时候
  3. 销毁时机: 服务器关闭的时候

案例:ServletContextListener的应用

需求:

在Web项目加载和结束的时候在控制台各打印输出现在的时间戳,并且输出一句话

代码

监听器
package com.itheima.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import java.sql.Timestamp;/*** 监听器类似于JS中事件* 创建监听器的步骤* 1. 创建一个类实现ServletContextListener接口* 2. 重写接口中方法,包含两个方法,分别对应创建和销毁* 3. 在web.xml中配置监听器或使用注解@WebListener*/
//@WebListener
public class MyContextListener implements ServletContextListener {//监听上下文对象的创建@Overridepublic void contextInitialized(ServletContextEvent event) {System.out.println(event.getServletContext() + "创建了上下文对象");System.out.println(new Timestamp(System.currentTimeMillis()) + "上下文对象创建");}//监听上下文对象的销毁@Overridepublic void contextDestroyed(ServletContextEvent event) {System.out.println(new Timestamp(System.currentTimeMillis()) + "上下文对象销毁");}
}
web.xml
<?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"><!--配置监听器--><listener><listener-class>com.itheima.listener.MyContextListener</listener-class></listener>
</web-app>

执行效果

org.apache.catalina.core.ApplicationContextFacade@d7685c6创建了上下文对象
2020-09-03 16:10:09.16上下文对象创建2020-09-03 16:10:25.959上下文对象销毁

小结

ServletContextListener接口中的方法

接口中的方法功能执行次数
void contextDestroyed(ServletContextEvent sce)监听上下文对象的销毁1次
void contextInitialized(ServletContextEvent sce)监听上下文对象的创建1次

ServletContextEvent事件对象的方法

ServletContextEvent中的方法功能
ServletContext getServletContext()获取创建的上下文对象

15. ServletContextAttributeListener监听器

目标

  1. ServletContextAttributeListener监听器触发的时机

  2. ServletContextAttributeListener接口方法中的方法

ServletContextAttributeListener监听器的作用

  1. 作用:监听上下文域中属性的增删改操作

  2. 时机:

    1. 增加属性:setAttribute()
    2. 删除属性:removeAttribute()
    3. 修改属性:setAttribute(同名)

ServletContextAttributeListener监听器的示例

案例需求

  1. 创建一个ServletContextAttributeListener监听器的实现类,重写接口中所有的方法,输出属性名和属性值

  2. 创建一个Servlet,向context上下文中添加一个属性,修改一个属性,删除一个属性。

  • 注:修改后的属性值,要通过上下文对象来取得。

案例效果

向上下文域中添加了属性名:user,值:孙悟空
修改了上下文域中属性名:user,修改前的值:孙悟空,修改后的值:白骨精
删除了上下文域中属性名:user,值:白骨精

案例代码

package com.itheima.listener;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebListener;
import java.sql.Timestamp;/*** 监听器类似于JS中事件* 创建监听器的步骤* 1. 创建一个类实现ServletContextListener接口* 2. 重写接口中方法,包含两个方法,分别对应创建和销毁* 3. 在web.xml中配置监听器或使用注解@WebListener*/
//@WebListener
public class MyContextListener implements ServletContextListener, ServletContextAttributeListener {//监听上下文对象的创建@Overridepublic void contextInitialized(ServletContextEvent event) {System.out.println(event.getServletContext() + "创建了上下文对象");System.out.println(new Timestamp(System.currentTimeMillis()) + "上下文对象创建");}//监听上下文对象的销毁@Overridepublic void contextDestroyed(ServletContextEvent event) {System.out.println(new Timestamp(System.currentTimeMillis()) + "上下文对象销毁");}//监听上下文域属性添加@Overridepublic void attributeAdded(ServletContextAttributeEvent event) {//getName()获取属性名, getValue()获取属性值System.out.println("向上下文域中添加了属性名:" + event.getName() + ",值:" + event.getValue());}//监听上下文域属性删除@Overridepublic void attributeRemoved(ServletContextAttributeEvent event) {System.out.println("删除了上下文域中属性名:" + event.getName() + ",值:" + event.getValue());}//监听上下文域属性修改@Overridepublic void attributeReplaced(ServletContextAttributeEvent event) {//获取上下文对象ServletContext application = event.getServletContext();//通过名字获取值,获取修改后的Object value = application.getAttribute(event.getName());System.out.println("修改了上下文域中属性名:" + event.getName() + ",修改前的值:" + event.getValue() + ",修改后的值:" + value);}
}

小结

ServletContextAttributeListener接口中的方法

接口中的方法功能
void attributeAdded(ServletContextAttributeEvent event)监听上下文域的添加事件
void attributeRemoved(ServletContextAttributeEvent event)监听上下文域的删除事件
void attributeReplaced(ServletContextAttributeEvent event)监听上下文域的修改事件

ServletContextAttributeEvent对象中的方法

ServletContextAttributeEvent对象中的方法功能
String getName()获取属性名
Object getValue()获取属性值

16. 案例:统计网站当前在线人数

执行效果

页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ILwkvo3-1599131780680)(assets/image-20200903165954858.png)]

服务器控制台信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2EJypeDJ-1599131780682)(assets/Snipaste_2020-03-27_16-30-54.png)]

分析

每当一个用户访问项目的时候,都会创建一个session会话。所以当session会话被创建,当前在线用户+1,每当session会话被销毁,当前在线用户-1。

HttpSessionListener可以用来监听session对象的创建和销毁的。所以可以在HttpSessionListener中的监听session对象创建和销毁的方法中控制在线人数的加减。

步骤

  1. 创建一个监听器 SessionCountListener

  2. 创建一个成员变量AtomicInteger,用于计数。注:必须是同一个对象

    a) 监听会话创建的方法

​ i. 从上下文域中取出当前的计数对象

​ ii. 如果为空,表示是第1个用户,设置值为1,并且添加到上下文域中

​ iii. 不为空则加1,不用更新上下文域

​ b) 监听会话销毁的方法

​ i. 从上下文域中得到当前在线的人数

​ ii. 减1即可

  1. 创建一个注销的LogoutServlet

    a) 让会话失效

    b) 打印输出:您已经安全退出网站

  2. 编写JSP

    a) 在JSP上取出上下文域中用户数显示

    b) 显示安全退出的链接

代码

监听器

package com.itheima.listener;import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.concurrent.atomic.AtomicInteger;/*** 创建一个监听器,监听会话的创建和销毁*/
@WebListener
public class SessionCountListener implements HttpSessionListener {//创建一个成员变量计数,考虑线程安全问题private AtomicInteger number;//监听会话的创建@Overridepublic void sessionCreated(HttpSessionEvent event) {//获取会话对象HttpSession session = event.getSession();//通过会话对象获取上下文对象ServletContext application = session.getServletContext();//从上下文域中获取number的值number = (AtomicInteger) application.getAttribute("number");//第1个用户访问的时候number是为空if (number == null) {//创建一个1的值number = new AtomicInteger(1);application.setAttribute("number", number);}else {//不为空,加1number.incrementAndGet();//因为AtomicInteger这是一个引用类型,获取的是它的地址,不需要进行更新}//在控制台输出System.out.println("创建会话:" + session.getId() + ",当前在线人数:" + number);}//监听会话的销毁@Overridepublic void sessionDestroyed(HttpSessionEvent event) {//获取会话对象HttpSession session = event.getSession();//通过会话对象获取上下文对象ServletContext application = session.getServletContext();//从上下文域中获取number的值number = (AtomicInteger) application.getAttribute("number");//减1number.decrementAndGet();//在控制台输出System.out.println("销毁会话:" + session.getId() + ",当前在线人数:" + number);}
}

退出

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>退出</title>
</head>
<body>
退出成功
<%session.invalidate();
%>
</body>
</html>

显示人数的JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>显示在线人数</title></head><body><%--所有的用户都可以访问,这个计数的值放在上下文域中--%><h3>当前在线人数是:${applicationScope.number}</h3><a href="logout.jsp">退出</a></body>
</html>

小结

  1. HttpSessionListener接口的作用是什么?

    监听会话的创建和销毁
    
  2. 说说以下方法的作用:

HttpSessionListener接口中的方法作用
void sessionCreated(HttpSessionEvent event)监听会话的创建
void sessionDestroyed(HttpSessionEvent event)监听会话的销毁

学习总结

  1. 能够说出过滤器的作用

    1. 修改请求
    2. 拦截请求

    应用场景:

    1. 全局乱码问题
    2. 用户权限拦截
    3. 过滤敏感词汇
  2. 能够编写过滤器

    1. 创建一个类实现javax.servlet.Filter接口
    2. 重写所有的方法,其中doFilter方法是执行过滤的方法
    3. 使用web.xml配置或@WebFilter("/过滤地址")注解进行配置
  3. 能够说出过滤器生命周期相关方法

    Filter接口中的方法作用和执行次数
    void init(FilterConfig filterConfig)初始化的时候执行1次,服务器启动的时候
    void doFilter(ServletRequest request,
    ServletResponse response, FilterChain chain)
    每次请求都会执行
    public void destroy()服务器关闭的时候执行,执行1次
  4. 能够根据过滤路径判断指定的过滤器是否起作用

    匹配方式匹配哪些资源
    以/开头精确匹配:/demo1
    目录匹配: /目录/*
    匹配所有的资源:/*
    以扩展名结尾*.扩展名
    注:/开头和扩展名结尾不能同时出现
  5. 能够说出什么是过滤器链

    执行顺序:

    1. xml配置方式:哪个配置在前面就先执行哪个
    2. 注解的方式:按过滤器类名的字母先后顺序

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZARWRwTu-1599131780683)(assets/1552919236666.png)]

  6. 能够编写过滤器解决全局乱码

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RlMeEY3T-1599131780685)(assets/1552918911663.png)]

  7. 能够说出监听器的作用

    1. 监听作用域的创建和销毁
    2. 监听作用域的属性变化
  8. 能够使用ServletContextListener监听器

    1. 创建一个类实现ServletContextListener接口
    2. 重写监听创建和销毁的方法
    3. 在web.xml中配置或使用@WebListener注解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_878439.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

扩展 jQuery EasyUI Datagrid 数据行鼠标悬停/离开事件(onMouseOver/onMouseOut)

客户需求&#xff1a; jQuery EasyUI Datagrid 用户列表鼠标悬停/离开数据行时显示人员头像&#xff08;onMouseOver/onMouseOut&#xff09; 如图所示&#xff0c;Datagrid 鼠标悬停/离开数据行时切换了不同的样式显示&#xff1a; 此时用谷歌开发者工具审查鼠标悬停行元素时…

推荐一款在线伪原创工具,很适合做seo的朋友

打开常用浏览器,360极速&#xff0c;UC&#xff0c;谷歌浏览器均可这里就打开谷歌做演示 浏览器中输入http://www.yzcopen.com/选着站长seo工具 找到第一行"文章伪原创"工具 复制自己的文章即可点击生成伪原创 伪原创文章对于各大搜索引擎来说&#xff0c;收录会很不…

分享一波我是怎么让一个新网站IP量一天翻15倍的,腾讯云:DDOS攻击

一直想写一篇文章&#xff0c;和大家分享一下我的一个在线工具网站如何将网站的日IP访问量做到一天翻15倍的技巧。现在想想是时候可以分享一些了&#xff01;正如标题所说&#xff0c;在一定时间内做一个日IP访问量一天翻15倍的的网站有可能吗&#xff1f;当然有可能了。这也是…

查看当前网站的cookie的两种快捷方法

1.在浏览器的地址栏输入&#xff1a;javascript:alert(document.cookie) (不区分大小写)&#xff0c;就会弹出你在当前网页登录的cookie信息。 注意&#xff1a;你把以上复制进入地址栏后会发现&#xff0c;“javascript”字符串消失不见&#xff0c;不管“javascript”里面哪…

大型网站后台架构的演变

随着用户访问量的不断增加&#xff0c;网站的后台也会不断变化以应对需求。本文主要从一个小型网站到大型网站的过度与变化来陈述。 1.1 网站后台架构 主要指由web server 、应用服务器、数据库、存储、监控等组成的网站后台系统。 1.2 架构演变 个人站点后台架构。如图2-1…

大型网站的高可用分析

本文主要分析网站的高可用性&#xff0c;从应用需求、用户角度展开分析。 1.1 高可用性 “高可用性”(High Availability) 通常用来描述一个系统&#xff0c;经过特殊设计&#xff0c;减少停止服务的时间&#xff0c;从而使其服务保持高度的可使用性。 计算机系统的可靠性用…

大型网站后台架构的web server与缓存

网站的web server与缓存 1.1 Web server Webserver 用来解析HTTP协议。当web 服务器接收到一个HTTP请求时&#xff0c;会返回一个HTTP响应&#xff0c;例如送回一个HTML页面。为了处理一个请求&#xff0c;web服务器可以响应一个静态页面或者图片。进行页面跳转&#xff0c;…

大型网站的负载均衡器、db proxy和db

大型网站的负载均衡器、db proxy和db 本文主要分析网站后台架构中的负载均衡器&#xff0c;企业常用的硬件负载均衡器软件负载均衡器、数据库代理服务器和数据库。 1.1 负载均衡 在大型网站部署中&#xff0c;负载均衡至少有三层部署。第一层为web server或者缓存代理之上的…

大型网站的存储

本文主要论述一下常用的存储产品和技术。 1.1 存储 存储设备是网站后台架构中&#xff0c;最底层的部分。也是最重要的部分。因为一旦存储设备出现问题&#xff0c;将直接导致上层的数据层和应用层的服务停止。严重的存储设备的损坏以及不可恢复的数据丢失会给企业造成巨大的…

大型网站的监控、报警与故障转移

本章主要从大型网站的后台监控机制、报警机制和故障转移、服务切换等内容来论述。然后给出一个监控、报警和故障转移的解决方案。 1.1 监控预警 现代大型互联网公司主要有电子商务公司、社交网站公司和搜索引擎公司。在电子商务网站公司中&#xff0c;taobao.com的点击量在国…

【项目记录】移动端购物网站首页/登录页/注册页

1-1初始化 1&#xff09;vue create jingdong 勾选sass语法、哈希路由 删除git相关 2&#xff09;npm run serve启动 1-2目录简介 插件 Vetur高亮显示、Eslint校验语法 入口文件&#xff1a;main.js 1.创建一个APP实例 2.使用router 3.使用store&#xff08;属vuex&#xff0c;…

基于javaweb大棚蔬菜管理系统网站加后台

软件环境&#xff1a;eclipse2020 tomcat9.0 mysql5.5, jdk1.8 开发技术&#xff1a;java, jsp, servlet,layui,bootstrap&#xff0c;ajax 系统功能&#xff1a; 基础功能&#xff1a;登录注册 1、后台管理&#xff08;管理员端&#xff09; &#xff08;1&#xff09;用…

基于javaweb流浪动物救助网站(前端+后端)

一、系统简介 本项目采用eclipse工具开发&#xff0c;layuijspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;领养用户&#xff0c;管理员 二、模块简介 管理员 1、登录 2、个人信息管理 3、…

基于javaweb新闻网站管理系统

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为3个角色分别是&#xff1a;用户&#xff0c;管理员&#xff0c;编辑者 二、模块简介 管理员 1、登录 2、个人信息…

基于javawe城市旅游网站系统

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;管理员&#xff0c;用户 二、模块简介 管理员 1、登录 2、个人信息管理 3、用户管理 …

基于javaweb的中药材网站管理系统+在线购物

一、系统简介 本项目采用eclipse工具开发&#xff0c;jspservletjquery技术编写&#xff0c;数据库采用的是mysql&#xff0c;navicat开发工具。 系统一共分为2个角色分别是&#xff1a;管理员&#xff0c;用户 二、模块简介 管理员 1、登录 2、用户管理 3、药材管理 4、…

通信学习网站链接

1&#xff0c;http://www.techplayon.com/5gnr/ 有视频讲解&#xff0c;新发现的比较好的通信网站之一。 2&#xff0c;http://www.sharetechnote.com/ 涵盖通信的各个层面&#xff0c;概念讲解非常透彻。

pycharm下载第三方库(镜像网站+终端)

例如下载bs4包 1.打开终端&#xff08;WINR后输入cmd&#xff09; 2.输入&#xff1a; pip install --targetc:\users\lenovo\appdata\local\programs\python\python310\lib\site-packages -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com bs4 c:\users\len…

使用python爬取图书网站的信息并保存至excel

首先介绍python中xlwt库 引入xlwt包 import xlwt创建简单的工作表 # 创建工作簿 workBook xlwt.Workbook("UTF-8")# 创建工作表 oneWorkSheet workBook.add_sheet("sheet1")# 写入数据(行, 列, 数据) oneWorkSheet.write(0, 0, "hello") on…

访问网站提示“您的时钟快了” 如何解决?阿里云如何部署SSL证书?

今天访问自己的网站&#xff0c;发现提示 您的时钟快了 您计算机的日期和时间&#xff08;2022年5月16日星期一 上午9:29:29&#xff09;不正确&#xff0c;因此无法与 建立私密连接。刚开始以为是电脑本地时间问题&#xff0c;最后发现百度了一波&#xff0c;发现问题出现是…