EL&Filter&Listener:EL表达式和JSTL,Servlet规范中的过滤器,Servlet规范中的监听器,观察着设计模式,监听器的使用,综合案例学生管理系统
EL&Filter&Listener-授课
1 EL表达式和JSTL
1.1 EL表达式
1.1.1 EL表达式介绍 ***
- EL(Expression Language):表达式语言 
- 在 JSP 2.0 规范中加入的内容,也是 Servlet 规范的一部分 
- 作用:在 JSP 页面中获取数据。让我们的 JSP 脱离 java 代码块和 JSP 表达式 
- 语法: - ${ 表达式内容 }
- 例如: 

1.1.2 EL表达式的快速入门
- 创建一个 web 项目:el_demo,虚拟目录/el 
- 在 web 目录下创建 el01.jsp 
- 在文件中向域对象添加数据 
- 使用三种方式获取域对象中的数据(java 代码块、JSP 表达式、EL 表达式) - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>EL表达式快速入门</title>
 </head>
 <body>
 <%--1.向域对象中添加数据--%>
 <% request.setAttribute("username","zhangsan"); %>
 
 <%--2.获取数据--%>
 Java代码块:<% out.println(request.getAttribute("username")); %> <br>
 
 JSP表达式:<%= request.getAttribute("username")%> <br>
 
 EL表达式:${username}
 </body>
 </html>
- 部署并启动项目 
- 通过浏览器测试  
1.1.3 EL表达式获取不同类型数据 ***
- 要获取的数据类型 - 获取基本数据类型的数据 
- 获取自定义对象类型的数据 
- 获取数组类型的数据 
- 获取 List 集合类型的数据 
- 获取 Map 集合类型的数据 
 
- 案例:新建el02.jsp - <%@ page import="com.itheima.bean.Student" %> 
 <%@ page import="java.util.ArrayList" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <html>
 <head>
 <title>EL表达式获取不同类型数据</title>
 </head>
 <body>
 <%--1.获取基本数据类型--%>
 <% pageContext.setAttribute("num",10); %>
 基本数据类型:${num} <br>
 
 <%--2.获取自定义对象类型--%>
 <%
 Student stu = new Student("张三",23);
 pageContext.setAttribute("stu",stu);
 %>
 自定义对象:${stu} <br>
 <%--stu.name 实现原理 getName()--%>
 学生姓名:${stu.name} <br>
 学生年龄:${stu.age} <br>
 
 <%--3.获取数组类型--%>
 <%
 String[] arr = {"hello","world"};
 pageContext.setAttribute("arr",arr);
 %>
 数组:${arr} <br>
 0索引元素:${arr[0]} <br>
 1索引元素:${arr[1]} <br>
 <%--EL表达式中没有字符串拼接--%>
 0索引拼接1索引的元素:${arr[0]} + ${arr[1]} <br>
 
 <%--4.获取List集合--%>
 <%
 ArrayList<String> list = new ArrayList<>();
 list.add("aaa");
 list.add("bbb");
 pageContext.setAttribute("list",list);
 %>
 List集合:${list} <br>
 0索引元素:${list[0]} <br>
 
 <%--5.获取Map集合--%>
 <%
 HashMap<String,Student> map = new HashMap<>();
 map.put("hm01",new Student("张三",23));
 map.put("hm02",new Student("李四",24));
 pageContext.setAttribute("map",map);
 %>
 Map集合:${map} <br>
 第一个学生对象:${map.hm01} <br>
 第一个学生对象的姓名:${map.hm01.name}
 
 </body>
 </html>
 
- 访问  
1.1.4 EL表达式的注意事项
- EL 表达式没有空指针异常 
- EL 表达式没有索引越界异常 
- EL 表达式没有字符串的拼接(el表达式中+只能对数字相加) 
- 代码 - 空指针  
- 越界和字符串拼接  
 
- 访问  
1.1.5 EL表达式的运算符
- 关系运算符  
- 逻辑运算符  
- 其他运算符  - 容器元素是否为0,就是容器的长度是否为0(其实就是检查容器是否为空) 
 
- 案例:新建el03.jsp - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>EL表达式运算符</title>
 </head>
 <body>
 <%--empty--%>
 <%
 String str1 = null;
 String str2 = "";
 int[] arr = {};
 %>
 ${empty str1} <br>
 ${empty str2} <br>
 ${empty arr} <br>
 
 <%--三元运算符。获取性别的数据,在对应的按钮上进行勾选 ***--%>
 <% pageContext.setAttribute("gender","men"); %>
 <input type="radio" name="gender" value="men" ${gender == "men" ? "checked" : ""}>男
 <input type="radio" name="gender" value="women" ${gender == "women" ? "checked" : ""}>女
 </body>
 </html>
- 访问  
1.1.6 EL表达式使用细节 ***
- EL 表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找 
- 还可以获取 JSP 其他八个隐式对象,并调用对象中的方法 
- 案例:el04.jsp - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>EL表达式使用细节</title>
 </head>
 <body>
 <%--获取四大域对象中的数据--%>
 <%
 //pageContext.setAttribute("username","zhangsan");
 request.setAttribute("username","zhangsan");
 //session.setAttribute("username","zhangsan");
 //application.setAttribute("username","zhangsan");
 %>
 ${username} <br>
 
 <%--pageContext页面域获取JSP中其他八个隐式对象 获取虚拟目录名称--%>
 <%= request.getContextPath()%> <%--jsp中可以直接获取request四大域对象,因为有这几个隐式对象--%>
 ${pageContext.request.contextPath} <%--el表达式,只能通过页面域获取其他八大隐身对象--%>
 <%--${request.contextPath} <%--el表达式,不能直接访问八大隐式对象–%>--%>
 ${contextPath} <%--el表达式,可以直接访问四大域中的共享数据,可不是属性--%>
 </body>
 </body>
 </html>
- 访问  
1.1.7 EL表达式的11个隐式对象
EL表达式也为我们提供隐式对象,可以让我们不声明直接来使用,十一个对象见下表,需要注意的是,它和JSP的隐式对象不是一回事:
| EL中的隐式对象 | 类型 | 对应JSP隐式对象 | 备注 | 
|---|---|---|---|
| PageContext *** | Javax.serlvet.jsp.PageContext | PageContext | 完全一样 | 
| ApplicationScope | Java.util.Map | 没有 | 操作应用域对象数据 | 
| SessionScope | Java.util.Map | 没有 | 操作会话域对象数据 | 
| RequestScope | Java.util.Map | 没有 | 操作请求域对象数据 | 
| PageScope | Java.util.Map | 没有 | 操作页面域对象数据 | 
| Header | Java.util.Map | 没有 | 根据key获取请求消息头,值是一个 | 
| HeaderValues | Java.util.Map | 没有 | 根据key获取请求消息头,值是多个(数组) | 
| Param | Java.util.Map | 没有 | 根据key获取请求参数,值是一个 | 
| ParamValues | Java.util.Map | 没有 | 根据key获取请求参数,值是多个(数组) | 
| InitParam | Java.util.Map | 没有 | 根据key获取全局参数,value是参数值 | 
| Cookie | Java.util.Map | 没有 | 根据key获取cookie的值 | 
- 案例 - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>EL表达式11个隐式对象</title>
 </head>
 <body>
 <%--pageContext对象 可以获取其他三个域对象和JSP中八个隐式对象--%>
 ${pageContext.request.contextPath} <br>
 
 <%--applicationScope sessionScope requestScope pageScope 操作四大域对象中的数据--%>
 <% request.setAttribute("username","zhangsan"); %>
 ${username} <br>
 ${requestScope.username} <br>
 
 <%--header headerValues 获取请求头数据--%>
 ${header["connection"]} <br>
 ${headerValues["connection"][0]} <br>
 
 <%--param paramValues 获取请求参数数据--%>
 ${param.username} <br>
 ${paramValues.hobby[0]} <br>
 ${paramValues.hobby[1]} <br>
 
 <%--initParam 获取全局配置参数--%>
 ${initParam["pname"]} <br>
 
 <%--cookie 获取cookie信息--%>
 ${cookie} <br> <%--获取Map集合--%>
 ${cookie.JSESSIONID} <br> <%--获取map集合中第二个元素--%>
 ${cookie.JSESSIONID.name} <br> <%--获取cookie对象的名称--%>
 ${cookie.JSESSIONID.value} <%--获取cookie对象的值--%>
 
 
 </body>
 </html>
 
- 访问  
- 总结 - 1. 获取四大域中的共享数据: ${数据的name} (都是通过xxx.setAttribute())
 2. 根据pageContext获取其他隐式对象:${pageContext.request.contextpath}
 注意: contextpath 不是共享数据,他是虚拟路径,是一个属性,有对应的一个getter方法:getContextPath
 <% request.getContextPath() %>
1.2 JSTL
1.2.1 JSTL的介绍
- JSTL(Java Server Pages Standarded Tag Library):JSP 标准标签库 
- 主要提供给开发人员一个标准通用的标签库 
- 开发人员可以利用这些标签取代 JSP 页面上的 Java 代码,从而提高程序的可读性,降低程序的维护难度 
- 它由以下5个部分组成: 

1.2.2 核心标签库
1)核心库介绍
在我们实际开发中,用到的jstl标签库主要以核心标签库为准,偶尔会用到国际化标签库的标签。下表中把我们经常可能用到的标签列在此处,其余标签库请同学们参考【JSTL标签库.doc】文档。
| 标签名称 | 功能分类 | 分类 | 作用 | 
|---|---|---|---|
| <c:if> | 流程控制 | 核心标签库 | 用于判断 | 
| <c:choose> ,<c:when>,<c:otherwise> | 流程控制 | 核心标签库 | 用于多个条件判断 | 
| <c:foreache> | 迭代操作 | 核心标签库 | 用于循环遍历 | 
2)案例 ***
- 创建一个 web 项目:jstl_demo 
- 在 web 目录下创建一个 WEB-INF 目录 
- 在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入 - (jar包目录:day05_el表达式过滤器监听器\资料\JSTL的jar包) 
- 添加引用库 
  
- 创建 JSP 文件,通过 taglib 导入 JSTL 标签库 
- 对流程控制和迭代遍历的标签进行使用 - 新建jstl01.jsp:流程控制 - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <!--prefix给jstl core核心库起个前缀名,使用的标签就以c开头-->
 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 <html>
 <head>
 <title>流程控制</title>
 </head>
 <body>
 <%--向域对象中添加成绩数据--%>
 ${pageContext.setAttribute("score","T")}
 
 <%--对成绩进行判断--%>
 <c:if test="${score eq 'A'}">
 优秀
 </c:if>
 
 <%--对成绩进行多条件判断--%>
 <c:choose>
 <c:when test="${score eq 'A'}">优秀</c:when>
 <c:when test="${score eq 'B'}">良好</c:when>
 <c:when test="${score eq 'C'}">及格</c:when>
 <c:when test="${score eq 'D'}">较差</c:when>
 <c:otherwise>成绩非法</c:otherwise>
 </c:choose>
 </body>
 </html>
 
- 新建jstl02.jsp:迭代遍历 - <%@ page import="java.util.ArrayList" %> 
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 <html>
 <head>
 <title>循环</title>
 </head>
 <body>
 <%--向域对象中添加集合--%>
 <%
 ArrayList<String> list = new ArrayList<>();
 list.add("aa");
 list.add("bb");
 list.add("cc");
 list.add("dd");
 pageContext.setAttribute("list",list);
 %>
 
 <%--遍历集合--%>
 <c:forEach items="${list}" var="str">
 ${str} <br>
 </c:forEach>
 </body>
 </html>
 
 
- 部署并启动项目 
- 通过浏览器查看 - 访问jstl01  
- 访问jstl02  
 
- 问题:项目运行报错  
- 解决:  
2 Servlet规范中的过滤器-Filter
2.1 过滤器入门
2.1.1 过滤器的介绍 ***
- 过滤器——Filter,它是JavaWeb三大组件之一。另外两个是Servlet和Listener 
- 它可以对web应用中的所有资源进行拦截,并且在拦截之后进行一些特殊的操作 
- 在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的! 
- 过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等等~~~ - 处理通用操作: 统一编码处理 
- 处理拦截操作:权限校验,如果有权限那就放行,如果没有就拦截 
- 过滤器会做两件事情:拦截,筛选/过滤 
 
- 过滤器图示  
- 生活中的例子  - 比如一对新人结婚,规定:只有带红包的客人可以吃酒席,不带的就不能吃 
- 那么这项工作不可能由新人自己完成,他们请了俩人,一个管收钱,一个管记账(这俩人就是过滤器) 
 
2.1.2 Filter介绍 ***
- Filter 是一个接口,如果想实现过滤器的功能,必须实现该接口 
- 核心方法  
- 配置方式 - 注解方式 
- 配置文件 
 
- Filter官网介绍  
2.1.3 FilterChain ***
- FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象,直接使用即可。 - chain: [tʃeɪn] 链子 
 
- 过滤器可以定义多个,就会组成过滤器链 
- 核心方法  
- 官网介绍  
2.1.4 过滤器的使用 ***
- 需求说明 - 通过 Filter 过滤器解决多个资源写出中文乱码的问题 
 
- 最终目的 - 通过本需求,最终掌握 Filter 过滤器的使用 
 
- 实现步骤 - 创建一个 web 项目:filter_demo,虚拟路径/filter 
- 创建两个 Servlet 功能类,都向客户端写出中文数据 - 新建ServletDemo01: - 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("/servletDemo01")
 public class ServletDemo01 extends HttpServlet {
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 System.out.println("servletDemo01执行了...");
 //resp.setContentType("text/html;charset=UTF-8");
 resp.getWriter().write("servletDemo01执行了...");
 }
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 doGet(req,resp);
 }
 }
 
- 新建ServletDemo02: - 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("/servletDemo02")
 public class ServletDemo02 extends HttpServlet {
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 System.out.println("servletDemo02执行了...");
 //resp.setContentType("text/html;charset=UTF-8");
 resp.getWriter().write("servletDemo02执行了...");
 }
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 doGet(req,resp);
 }
 }
 
- 访问  
- 发现demo1和demo2都是乱码 
- 之前都是在代码里添加: - resp.setContentType("text/html;charset=UTF-8");去解决乱码问题
- 但是如果有100个Servlet需要解决乱码问题呢?我们要写一百次么? 
- 不用,只需要使用过滤器即可 
 
- 创建一个 Filter 过滤器实现类,重写 doFilter 核心方法 
- 在方法内解决中文乱码,并放行 - package com.itheima.filter; 
 
 import javax.servlet.*;
 import java.io.IOException;
 
 /*
 过滤器基本使用
 /*:表明访问当前应用下任何资源,此过滤器都会起作用
 */
 @WebFilter("/*")
 public class FilterDemo01 implements Filter{
 
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 System.out.println("filterDemo01执行了...");
 
 //处理乱码
 servletResponse.setContentType("text/html;charset=UTF-8");
 
 //放行
 filterChain.doFilter(servletRequest,servletResponse);
 }
 }
 
- 部署并启动项目 
- 通过浏览器测试  
 
2.1.5 Filter过滤器的使用细节
- 配置方式 - 注解方式 @WebFilter(拦截路径) 
- 配置文件方式 
  
- 多个过滤器使用顺序 - 如果有多个过滤器,取决于过滤器映射的顺序 
- 也就是filter-mapping配置的先后顺序 
 
- 案例 - 将demo1的WebFilter注解屏蔽 
- 新建FilterDemo02: - package com.itheima.filter; 
 
 import javax.servlet.*;
 import java.io.IOException;
 
 /*
 过滤器基本使用
 */
 //@WebFilter("/*")
 public class FilterDemo02 implements Filter{
 
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 System.out.println("filterDemo02执行了...");
 
 //处理乱码
 servletResponse.setContentType("text/html;charset=UTF-8");
 
 //放行
 filterChain.doFilter(servletRequest,servletResponse);
 }
 }
- 配置filter - <filter> 
 <filter-name>filterDemo01</filter-name>
 <filter-class>com.itheima.filter.FilterDemo01</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>filterDemo01</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>
 
 <filter>
 <filter-name>filterDemo02</filter-name>
 <filter-class>com.itheima.filter.FilterDemo02</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>filterDemo02</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>
 
- 访问  
2.1.6 生命周期
- 创建(出生) - 当应用加载时实例化对象并执行 init 初始化方法 
 
- 服务(活着) - 对象提供服务的过程,执行 doFilter 方法 
- 只要应用一直提供服务,对象就一直存在 
 
- 销毁(死亡) - 当应用卸载时或服务器停止时对象销毁。执行 destroy 方法 
 
- Filter的实例对象在内存中也只有一份。所以也是单例的。 
- 案例:新建FilterDemo03 - package com.itheima.filter; 
 
 import javax.servlet.*;
 import java.io.IOException;
 
 /*
 过滤器生命周期
 */
 //@WebFilter("/*")
 public class FilterDemo03 implements Filter{
 
 /*
 初始化方法
 */
 @Override
 public void init(FilterConfig filterConfig) {
 System.out.println("对象初始化成功了...");
 }
 
 /*
 提供服务方法
 */
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 System.out.println("filterDemo03执行了...");
 
 //处理乱码
 servletResponse.setContentType("text/html;charset=UTF-8");
 
 //放行
 filterChain.doFilter(servletRequest,servletResponse);
 }
 
 /*
 对象销毁
 */
 @Override
 public void destroy() {
 System.out.println("对象销毁了...");
 }
 }
- 配置:为了不影响测试,给之前的俩过滤器的配置代码屏蔽掉 - <filter> 
 <filter-name>filterDemo03</filter-name>
 <filter-class>com.itheima.filter.FilterDemo03</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>filterDemo03</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>
- 访问  
2.1.7 FilterConfig过滤器配置对象
- FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数。 - 与ServletConfig类似 
 
- 核心方法  
- 官网介绍  
- 案例:新建FilterDemo04 - package com.itheima.filter; 
 
 import javax.servlet.*;
 import java.io.IOException;
 
 /*
 过滤器配置对象的使用
 */
 //@WebFilter("/*")
 public class FilterDemo04 implements Filter{
 
 /*
 初始化方法
 */
 @Override
 public void init(FilterConfig filterConfig) {
 System.out.println("对象初始化成功了...");
 
 //获取过滤器名称
 String filterName = filterConfig.getFilterName();
 System.out.println(filterName);
 
 //根据name获取value
 String username = filterConfig.getInitParameter("username");
 System.out.println(username);
 }
 
 /*
 提供服务方法
 */
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 System.out.println("filterDemo04执行了...");
 
 //处理乱码
 servletResponse.setContentType("text/html;charset=UTF-8");
 
 //放行
 filterChain.doFilter(servletRequest,servletResponse);
 }
 
 /*
 对象销毁
 */
 @Override
 public void destroy() {
 System.out.println("对象销毁了...");
 }
 }
- filter配置 - <filter> 
 <filter-name>filterDemo04</filter-name>
 <filter-class>com.itheima.filter.FilterDemo04</filter-class>
 <init-param>
 <param-name>username</param-name>
 <param-value>zhangsan</param-value>
 </init-param>
 </filter>
 <filter-mapping>
 <filter-name>filterDemo04</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>
- 启动tomcat  
3 Servlet规范中的监听器-Listener
3.1 观察者设计模式 ***
- 在介绍监听器之前,先跟同学们普及一个知识,观察者设计模式。 
- 因为所有的监听器都是观察者设计模式的体现。 
- 那什么是观察者设计模式呢? 
- 它是事件驱动的一种体现形式。就好比在做什么事情的时候被人盯着,当对应做到某件事时,触发事件。 
- 观察者模式通常由以下三部分组成: - 事件源:触发事件的对象。 
- 事件:触发的动作,里面封装了事件源。 
- 监听器:当事件源触发事件时,要做的事情。一般是一个接口,由使用者来实现。(此处的思想还涉及了一个设计模式,我们在JDBC的第二天课程中就给同学们讲解,策略模式) - 事件源触发某个事件之后,监听器监听到了这个过程,进而执行一个逻辑 
 
- 例子:狗发现人从门前过,就会狂吠 (看门狗) 
 
- 生活中的例子  - 老师定了一个规矩,老师一旦发现学生9点之后来的话就算迟到,那就惩罚,9点之前来的学生不惩罚 
- 在这个例子中,事件源是学生 
- 事件是迟到 
- 监听器就是老师 
 
- 监听器介绍 - 在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听 
- Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成 
 
3.2 监听对象的监听器
1) ServletContextListener ***
- ServletContextListener:用于监听 ServletContext 对象的创建和销毁 
- 核心方法  - 参数:ServletContextEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 ServletContext 
- 真正的事件指的是创建或销毁 ServletContext 对象的操作 
 
2) HttpSessionListener
- HttpSessionListener:用于监听 HttpSession 对象的创建和销毁 
- 核心方法  - 参数:HttpSessionEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 HttpSession 
- 真正的事件指的是创建或销毁 HttpSession 对象的操作 
 
3) ServletRequestListener
- ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁 
- 核心方法  - 参数:ServletRequestEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 ServletRequest 
- 真正的事件指的是创建或销毁 ServletRequest 对象的操作 
 
3.3 监听域对象属性变化的监听器
1) ServletContextAttributeListener
- ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化 
- 核心方法  - 参数:ServletContextAttributeEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 ServletContext 
- 真正的事件指的是添加、移除、替换应用域中属性的操作 
 
2) HttpSessionAttributeListener
- HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化 
- 核心方法  - 参数:HttpSessionBindingEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 HttpSession 
- 真正的事件指的是添加、移除、替换会话域中属性的操作 
 
3) ServletRequestAttributeListener
- ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化 
- 核心方法  - 参数:ServletRequestAttributeEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 ServletRequest 
- 真正的事件指的是添加、移除、替换请求域中属性的操作 
 
3.4 监听会话相关的感知性监听器
1) HttpSessionBindingListener
- HttpSessionBindingListener:用于感知对象和会话域绑定的监听器 
- 核心方法  - 参数:HttpSessionBindingEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 HttpSession 
- 真正的事件指的是添加、移除会话域中数据的操作 
 
- HttpSessionBindingListener和HttpSessionAttributeListener区别: - 1.只有实现了HttpSessionBindingListener的类,添加移除到session域中才会触发绑定,解绑方法。 2.任何对象(不论其是否实现了HttpSessionAttributeListener)在变化时均触发对应的事件。 
2) HttpSessionActivationListener
- HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器 
- 核心方法  - 参数:HttpSessionEvent 代表事件对象 
- 事件对象中封装了事件源,也就是 HttpSession 
- 真正的事件指的是会话域中数据钝化、活化的操作 
 
3.4 监听器的使用
- 在实际开发中,我们可以根据具体情况来从这8个监听器中选择使用 
- 感知型监听器由于无需配置,只需要根据实际需求编写代码,所以此处我们就不再演示了 
- 我们在剩余6个中分别选择一个监听对象创建销毁和对象域中属性发生变化的监听器演示一下 
- 演示下边两个 

3.4.1 ServletContextListener的使用 ***
- 创建项目:listener_demo,虚拟路径/listener 
- 创建com.itheima.listener.ServletContextListenerDemo - package com.itheima.listener; import javax.servlet.ServletContext; 
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener; /*
 ServletContext对象的创建和销毁的监听器
 //配置监听器:@WebListener
 */
 @WebListener
 public class ServletContextListenerDemo implements ServletContextListener{
 /*
 ServletContext对象创建的时候执行此方法
 */
 @Override
 public void contextInitialized(ServletContextEvent sce) {
 System.out.println("监听到了对象的创建..."); //获取对象
 ServletContext servletContext = sce.getServletContext();
 System.out.println(servletContext); } /*
 ServletContext对象销毁的时候执行此方法
 */
 @Override
 public void contextDestroyed(ServletContextEvent sce) {
 System.out.println("监听到了对象的销毁...");
 }
 }
- 启动项目:ServletContext是项目启动都会创建的,所以这里只需要启动tomcat  
3.4.2 ServletContextAttributeListener的使用
- 新建ServletContextAttributeListenerDemo - package com.itheima.listener; import javax.servlet.ServletContext; 
 import javax.servlet.ServletContextAttributeEvent;
 import javax.servlet.ServletContextAttributeListener; /*
 应用域对象中的属性变化的监听器
 */
 @WebListener
 public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener{
 /*
 向应用域对象中添加属性时执行此方法
 */
 @Override
 public void attributeAdded(ServletContextAttributeEvent scae) {
 System.out.println("监听到了属性的添加..."); //获取应用域对象
 ServletContext servletContext = scae.getServletContext();
 //获取属性
 Object value = servletContext.getAttribute("username");
 System.out.println(value);
 } /*
 向应用域对象中替换属性时执行此方法
 */
 @Override
 public void attributeReplaced(ServletContextAttributeEvent scae) {
 System.out.println("监听到了属性的替换..."); //获取应用域对象
 ServletContext servletContext = scae.getServletContext();
 //获取属性
 Object value = servletContext.getAttribute("username");
 System.out.println(value);
 } /*
 向应用域对象中移除属性时执行此方法
 */
 @Override
 public void attributeRemoved(ServletContextAttributeEvent scae) {
 System.out.println("监听到了属性的移除..."); //获取应用域对象
 ServletContext servletContext = scae.getServletContext();
 //获取属性
 Object value = servletContext.getAttribute("username");
 System.out.println(value);
 }
 }
- 修改ServletContextListenerDemo:在contextInitialized中增加如下代码: - //添加属性 
 servletContext.setAttribute("username","zhangsan"); //替换属性
 servletContext.setAttribute("username","lisi"); //移除属性
 servletContext.removeAttribute("username");
- 启动tomcat  
- 注解配置监听器,改为xml手动配置 - 注释两个demo中的 - //@WebListener
- web.xml增加如下配置 
 - <!--配置监听器--> 
 <listener>
 <listener-class>com.itheima.listener.ServletContextListenerDemo</listener-class>
 </listener> <listener>
 <listener-class>com.itheima.listener.ServletContextAttributeListenerDemo</listener-class>
 </listener>
4 综合案例-学生管理系统改造 ***
4.1 需求说明
4.1.1 解决乱码问题
我们的学生管理系统中,肯定会有请求和响应的中文乱码问题。而乱码问题在学习Servlet的课程中已经讲解了如何解决了。只是在实际开发中,当有很多的Servlet时,肯定不能在每个Servlet中都编写一遍解决乱码的代码。因此,就可以利用我们今天学习的过滤器来实现统一解决请求和响应乱码的问题。
4.1.2 检查登录
在学生管理系统中,它包含了学生信息的录入和学生列表的查询,用户(员工)信息的录入以及查询。当然,我们实际的功能可能远远不止这些。但是就已有功能来说,也不是谁都可以通过地址栏直接输入访问的,它应该有权限的控制,只是我们课程在此处没法深入展开讲解权限,但最起码的登录,身份的认证还是必要的。
由此,就引出来一个问题,是在每次访问Servlet时,在Servlet的代码中加入是否认证过身份的判断吗?显然,是不合理的。那么,既然不是在每个Servlet中编写,就应该是统一管理和维护。此时,我们的过滤器就又可以出场了。
4.1.3 页面的java代码块和jsp表达式改造
我们今天除了学习了过滤器,还学习了EL表达式和JSTL标签库,它们的出现就是避免我们的JSP页面中有过多的java代码或者jsp表达式。我们要运用今天所学知识改造页面。
4.2 案例实现
4.2.1 过滤器解决全局乱码问题
- 代码 - package com.itheima.filter; import javax.servlet.Filter; 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.annotation.WebFilter;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse; /*
 解决全局乱码问题
 */
 @WebFilter("/*")// /* 代表过滤所有的url
 public class EncodingFilter implements Filter{
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
 try{
 //1.将请求和响应对象转换为和HTTP协议相关
 HttpServletRequest request = (HttpServletRequest) servletRequest;
 HttpServletResponse response = (HttpServletResponse) servletResponse; //2.设置编码格式
 request.setCharacterEncoding("UTF-8");
 response.setContentType("text/html;charset=UTF-8"); //3.放行
 filterChain.doFilter(request,response);
 } catch (Exception e) {
 e.printStackTrace();
 } }
 }
4.2.2 过滤解决检查登陆
- 代码 - package com.itheima.filter; import javax.servlet.Filter; 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.annotation.WebFilter;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse; /*
 检查登录
 */
 @WebFilter(value = {"/addStudent.jsp","/listStudentServlet"})//过滤某些url通过value来指定
 public class LoginFilter implements Filter{
 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
 try{
 //1.将请求和响应对象转换为和HTTP协议相关
 HttpServletRequest request = (HttpServletRequest) servletRequest;
 HttpServletResponse response = (HttpServletResponse) servletResponse; //2.获取会话域对象中数据
 Object username = request.getSession().getAttribute("username"); //3.判断用户名
 if(username == null || "".equals(username)) {
 //重定向到登录页面
 response.sendRedirect(request.getContextPath() + "/login.jsp");
 return;
 } //4.放行
 filterChain.doFilter(request,response);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 }
4.2.3 EL表达式和JSTL优化JSP界面
- addStudent.jsp - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>添加学生</title>
 </head>
 <body>
 <%--注意:el表达式中如果想获取request对象,只能通过pageContext页面域获取
 pageContext.request,相当于java代码块里的pageContext.getRequest()
 --%>
 <form action="${pageContext.request.contextPath}/addStudentServlet" method="get" autocomplete="off">
 学生姓名:<input type="text" name="username"> <br>
 学生年龄:<input type="number" name="age"> <br>
 学生成绩:<input type="number" name="score"> <br>
 <button type="submit">保存</button>
 </form>
 </body>
 </html>- 重点:在jsp中通过EL表达式获取项目虚拟路径:${pageContext.request.contextPath} 
 
- index.jsp - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 <html>
 <head>
 <title>学生管理系统首页</title>
 </head>
 <body>
 <%--
 获取会话域中的数据
 如果获取到了则显示添加和查看功能的超链接
 如果没获取到则显示登录功能的超链接
 --%>
 <c:if test="${sessionScope.username eq null}">
 <a href="${pageContext.request.contextPath}/login.jsp">请登录</a>
 </c:if> <c:if test="${sessionScope.username ne null}">
 <a href="${pageContext.request.contextPath}/addStudent.jsp">添加学生</a>
 <a href="${pageContext.request.contextPath}/listStudentServlet">查看学生</a>
 </c:if> </body>
 </html>- 注意:EL表达式会自动查找四大域对象中的共享数据,所以 - ${sessionScope.username eq null}中的- sessionScope可以省略,写成- ${username eq null}
 
- listStudent.jsp - <%@ page import="com.itheima.bean.Student" %> 
 <%@ page import="java.util.ArrayList" %>
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 <html>
 <head>
 <title>查看学生</title>
 </head>
 <body>
 <table width="600px" border="1px">
 <tr>
 <th>学生姓名</th>
 <th>学生年龄</th>
 <th>学生成绩</th>
 </tr>
 <%-- s是students遍历出来的每一个对象,EL表达式中可以使用此遍历 --%>
 <c:forEach items="${students}" var="s">
 <tr align="center">
 <td>${s.username}</td>
 <td>${s.age}</td>
 <td>${s.score}</td>
 </tr>
 </c:forEach>
 </table>
 </body>
 </html>
 
- login.jsp - <%@ page contentType="text/html;charset=UTF-8" language="java" %> 
 <html>
 <head>
 <title>学生登录</title>
 </head>
 <body>
 <form action="${pageContext.request.contextPath}/loginStudentServlet" method="get" autocomplete="off">
 姓名:<input type="text" name="username"> <br>
 密码:<input type="password" name="password"> <br>
 <button type="submit">登录</button>
 </form>
 </body>
 </html>
EL&Filter&Listener:EL表达式和JSTL,Servlet规范中的过滤器,Servlet规范中的监听器,观察着设计模式,监听器的使用,综合案例学生管理系统的更多相关文章
- [转]EL表达式和JSTL表达式实例
		/* **Title:EL表达式和JSTL表达式实例 **Author:Insun **Blog:http://yxmhero1989.blog.163.com/ */ 为了方便写JSP,我们引入了E ... 
- Struts标签、Ognl表达式、el表达式、jstl标签库这四者之间的关系和各自作用
		我之前虽然会用,但是一直分不清彼此之间有什么区别,所以查找资料,将它们进行整合区分,加深了解, 一 介绍 1.Struts2的作用 Struts2标签库提供了主题.模板支持,极大地简化了视图页面的 ... 
- JSP和El表达式和JSTL标签库使用
		核心标签库: <%@ page language="java" import="java.util.*" pageEncoding="utf-8 ... 
- EL表达式和JSTL核心标签库
		1 EL表达式 1.1 EL的概述 EL,全名为Expression Language. 主要作用: ①EL表达式主要用于替换jsp页面中的脚本表达式,以便于从各种类型的web域中检索java对象(某 ... 
- EL表达式、 jstl标签
		https://www.cnblogs.com/zhaotiancheng/p/6391894.html https://blog.csdn.net/zdwzzu2006/article/detail ... 
- 个人整理的jsp、EL表达式、JSTL标签库的笔记,少概念多实用,需要的留下邮箱,会第一时间分享原稿PDF给大家!
		jsp 第一章 jsp介绍及对比servlet 作用: 动态网页技术,动态的从数据库获取数据 jsp和servlet的优缺点: jsp优点:页面表现方便,利于写html代码 jsp缺点:业务逻辑处理麻 ... 
- Javaweb学习笔记6—EL表达式与JSTL及自定义标签
		今天来讲javaweb的第六阶段学习. EL表达式与JSTL及自定义标签是对上篇文章介绍的JSP的扩展,不能说是很重要的东西,但是也要了解. 老规矩,首先先用一张思维导图来展现今天的博客内容. ps: ... 
- EL表达式和JSTL(三)——EL表达式
		在JSP的开发中,为了获取Servlet中存储的数据,通常需要很多的Java代码,这样的做法使的JSP页面非常混乱,为此,JSP2.0中提供了一种EL规范,是一种简单的数据访问语言. 1.初识EL E ... 
- jsp(3,6,9) EL表达式及JSTL
		1. jsp 1.1jsp是什么 全称: Java Server Pages,java服务器页面.和Servlet一样,是sun公司定义的一种动态网页开发技术. 特点:基于html模版,可以在h ... 
随机推荐
- 仵航说 前后端分离,文件上传下载(springBoot+vue+elementUI)仵老大
			1.介绍  本文主要是介绍前后端分离的上传下载,后端使用的是SpringBoot,持久层用的是mybatis-plus,前端用的Vue,UI用的elementUI,测试了一下,文本,图片,excel ... 
- Python高级语法-对象实例对象属性-类与实例,class方法静态方法等(4.6.1)
			@ 目录 1.说明 2.代码 关于作者 1.说明 python中属性:类属性,实例属性 方法:类方法,实例方法,静态方法 想修改类属性,只能是类方法,因为只有类方法把cls(类)传入数据里面 静态方法 ... 
- SSRF  CTF 例题
			一道ctf题目,有两个文件:ssrf3.php和flag.php 题目意思是flag只能127.0.0.1访问,还进行了post验证,这就需要gopher提交post数据来绕过 curl设置了302跳 ... 
- 安利一波这12个IDEA插件,太香了!
			这里补充一下常用的插件, 非常值得安利一波! 1.日晒主题 Solarized Themes 推荐指数:☆☆☆☆☆ 推荐理由:日晒主题本身是为vim定制的.后来移植到ide 非常酷!配色非常耐看. ... 
- ADO.NET 帮助类 参数传递 存储过程  分页
			SQLHelper public class SqlHelper { private readonly string _constr = ConfigurationManager.Connection ... 
- DataTable添加checkbox实现表格数据全选,单选(点选)
			Datatables是一款jquery表格插件.它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能. 分页,即时搜索和排序 几乎支持任何数据源:DOM, javascript, Ajax ... 
- Core3.0使用Swagger接口文档
			前言 此方法为百度搜索结果,原文链接找不到了 步骤 1.引用Nuget Swashbuckle.AspNetCore 2.Startup.cs配置 //注册swagger服务,定义1个或者多个swag ... 
- C# 9 新特性 —— 增强的 foreach
			C# 9 新特性 -- 增强的 foreach Intro 在 C# 9 中增强了 foreach 的使用,使得一切对象都有 foreach 的可能 我们来看一段代码,这里我们试图遍历一个 int 类 ... 
- MyBatis-Plus 多表联查+分页
			在写东西的过程中,多表联查和分页功能必不可少.当然,crud也很重要 但是又不想写代码和xml. 通过苦苦的查找.发现MyBatis-Plus一款国产的框架.优化了许多操作 本次主要记录一下,多表联查 ... 
- Trick:如何去掉html标签点击时的蓝色边框
			我们在用html标签时,如input.button.select,img标签时,点击标签经常出现一个蓝色的边框,这个边框真的很low,想要去掉怎么办 其实,css有样式可以设置一下,这个问题就轻松 ... 
