一、EL 表达式
1.1 EL表达式介绍
- EL(Expression Language) :表达式语言。
- 在JSP 2.0规范中加入的内容,也是Servlet规范的一部分。
作用:在JSP页面中获取数据。让我们的JSP脱离java代码块和JSP表达式。 - 语法: ${表达式内容}
1.2 EL表达式快速入门
1.创建一一个web项目。
2.在web目录下创建el01.jsp.
3.在文件中向域对象添加数据。
4.使用三种方式获取域对象中的数据(java代码块、JSP 表达式、EL 表达式)。
5.部署并启动项目。
6.通过浏览器测试。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%-- 1、向域对象中添加数据--%>
<%
request.setAttribute("username", "zhangsan");
%>
<%-- 2 获取数据 Java代码--%>
Java代码块获取数据: <% out.println(request.getAttribute("username"));%> <br>
<%-- 3 Jsp表达式来获取--%>
Jsp表达式获取数据: <%=request.getAttribute("username")%> <br>
<%-- 4 el表达式--%>
el表达式获取数据: ${username} <br>
</body>
</html>
1.3 EL表达式获取数据
1.获取基本数据类型的数据。
2.获取自定义对象类型的数据。
3.获取数组类型的数据。
4.获取List集合类型的数据。
5.获取Map集合类型的数据。
<%@ page import="com.itjc.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);
%>
<%--EL表达式中没有空指针异常--%>
自定义对象:${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表达式中没有索引越界异常--%>
8索引元素:${arr[8]} <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>
EL表达式注意事项:
1、EL表达式没有空指针异常。
2、EL表达式没有索弓|越界异常。
3、EL 表达式没有字符串的拼接。
1.4 EL表达式运算符
- 关系运算符
<%@ 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","women"); %>
<input type="radio" name="gender" value="men" ${gender == "men" ? "checked" : ""}>男
<input type="radio" name="gender" value="women" ${gender == "women" ? "checked" : ""}>女
</body>
</html>
1.5 EL表达式使用细节
- EL表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找。
- 还可以获取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>
<%--获取JSP中其他八个隐式对象 获取虚拟目录名称--%>
<%= request.getContextPath()%>
${pageContext.request.contextPath}
</body>
</html>
1.6 EL表达式隐式对象
<%@ 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>
二、JSTL
2.1 JSTL介绍
- JSTL(Java Server Pages Standarded Tag Library) : JSP标准标签库。
- 主要提供给开发人员一 一个标准通用的标签库。
开发人员可以利用这些标签取代,JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。
2.2 JSTL核心标签库
2.3 JSTL基本使用
1.创建一个web项目。
2.在web目录下创建一一个WEB-INF 目录。
3.在WEB-INF目录下创建一个libs 目录,将JSTL的jar包导入。
4.创建JSP文件,通过taglib导入JSTL标签库。
5.对流程控制和迭代遍历的标签进行使用。
6.部署并启动项目。
7.通过浏览器查看。
<%@ 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>
<%--向域对象中添加成绩数据--%>
${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>
<%@ 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>
三、Filter
3.1 过滤器介绍
- 在程序中访问服务器资源时, 当-一个请求来,服务嚣首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来, 完成-些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的!
- 过滤器一般用于完成通用的操作,例如:登录验证、统-编码处理、敏感字符过滤等等~~~
3.2 Filter介绍
- Filter是一个接口。如果想实现过滤器的功能,必须实现该接口!
- 核心方法
- 配置万式
注解方式
配置文件
3.3 FilterChain介绍
- FilterChain是- 个接口,代表过滤器链对象。由Servlet容器提供实现类对象。直接使用即可。
- 过滤器可以定义多个,就会组成过滤器链。
- 核心方法
如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依次类推。直到到达最终访问资源。
如果只有一一个过滤器,放行时,就会直接到达最终访问资源。
3.4 过滤器使用
- 需求说明
通过Filter过滤器解决多个资源写出中文乱码的问题。 - 最终目的
通过本需求,最终掌握Filter过滤器的使用。 - 实现步骤
1.创建一个web项目。
2.创建两个Servlet功能类,都向客户端写出中文数据。
3.创建一个Filter过滤器实现类,写doFilter核心方法。
4.在方法内解决中文乱码,并放行。
5.部署并启动项目。
6.通过浏览器测试。
ServletDemo01
package com.itjc.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.getWriter().write("ServletDemo01执行了···");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
ServletDemo02
package com.itjc.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.getWriter().write("ServletDemo02执行了···");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Filter
package com.itjc.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebFilter("/*")
public class FilterDemo01 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter do something···");
// 处理乱码问题
servletResponse.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
3.5 过滤器使用细节
- 配置方式
注解方式@WebFilter(拦截路径)
配置文件方式
- 多个过滤器使用顺序
如果有多个过滤器,取决于过滤器映射的顺序
3.6 过滤器生命周期
- 创建
当应用加载时实例化对象并执行init初始化方法。 - 服务
对象提供服务的过程,执行doFilter方法。 - 销毁
当应用卸载时或服务器停止时对象销毁。执行destroy方法。
3.7 FilterConfig介绍
- FilterConfig是一 个接口。代表过滤器的配置对象,可以加载- 些初始化参数。
- 核心方法
3.8 过滤器五种拦截行为
- Filter过滤器默认拦截的是请求,但是在实际开发中,我们还有请求转发和请求包含,以及由服务器触发调
用的全局错误页面。默认情况下过滤器是不参与过滤的,要想使用,就需要我们配置。 - 拦截方式
四、Listener
4.1 监听器介绍
-
观察者设计模式,所有的监听器都是基于观察者设计模式的!
-
三个组成部分
事件源:触发事件的对象
事件:触发的动作,封装了事件源
监听器:当事件源触发事件后,可以完成功能 -
在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听。
-
Servlet规范中共计8个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成。
4.2 监听对象的监听器
-
ServletContextListener :用于监听ServletContext对象的创建和销毁
-
核心方法
参数: ServletContextEvent代表事件对象
事件对象中封装了事件源,也就是ServletContext
真正的事件指的是创建或销毁ServletContext对象的操作 -
HttpSessionListener :用于监听HttpSession对象的创建和销毁
-
核心方法
参数: HttpSessionEvent代表事件对象
事件对象中封装了事件源,也就是HttpSession
真正的事件指的是创建或销毁HttpSession对象的操作 -
ServletRequestListener :用于监听ServletRequest对象的创建和销毁
-
核心方法
参数: ServletRequestEvent代表事件对象
事件对象中封装了事件源,也就是ServletRequest
真正的事件指的是创建或销毁ServletRequest对象的操作
4.3 监听域对象属性变化的监听器
-
ServletContextAttributeListener :用于监听ServletContext应用域中属性的变化
-
核心方法
参数: ServletContextAttributeEvent代表事件对象
事件对象中封装了事件源,也就是ServletContext
真正的事件指的是添加、移除、替换应用域中属性的操作 -
HttpSessionAttributeListener :用于监听HttpSession会话域中属性的变化
-
核心方法
参数: HttpSessionBindingEvent代表事件对象
事件对象中封装了事件源,也就是HttpSession
真正的事件指的是添加、移除、替换会话域中属性的操作 -
ServletRequestAttributeListener :用于监听ServletRequest请求域中属性的变化
-
核心方法
参数: ServletRequestAttributeEvent代表事件对象
事件对象中封装了事件源,也就是ServletRequest
真正的事件指的是添加、移除、替换请求域中属性的操作
4.4 监听会话相关的感知型监听器
- HttpSessionBindingListener :用于感知对象和会话域绑定的监听器
- 核心方法
参数: HttpSessionBindingEvent代表事件对象
事件对象中封装了事件源,也就是HttpSession
真正的事件指的是添加、移除会话域中数据的操作 - HttpSessionActivationListener :用于感知会话域中对象钝化和活化的监听器
- 核心方法
参数: HttpSessionEyent代表事件对象
事件对象中封装了事件源,也就是HttpSession
真正的事件指的是会话域中数据钝化、活化的操作
4.5 监听器的使用汇总
- 监听对象的
ServletContextListener
HttpSessionListener
ServletRequestListener
- 监听属性变化的
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener
- 会话相关的感知型
HttpSessionBindingListener
HttpSessionActivationListener
ServletContextAttributeListener
package com.itjc.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.annotation.WebListener;
@WebListener
public class ServletContextAttributeListener implements javax.servlet.ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的添加···");
//获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的移除···");
//获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("监听到了属性的替换···");
//获取应用域对象
ServletContext servletContext = servletContextAttributeEvent.getServletContext();
//获取属性
Object username = servletContext.getAttribute("username");
System.out.println(username);
}
}
ServletContextListener
package com.itjc.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;
@WebListener
public class ServletContextListener implements javax.servlet.ServletContextListener {
/*
ServletContext对象创建的时候执行此方法
*/
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的创建···");
ServletContext servletContext = servletContextEvent.getServletContext();
// System.out.println(servletContext);
//添加属性
servletContext.setAttribute("username", "zhagnsan");
//替换属性
servletContext.setAttribute("username", "lisi");
//移除属性
servletContext.removeAttribute("username");
}
/*
ServletContext对象销毁的时候执行此方法
*/
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的销毁···");
ServletContext servletContext = servletContextEvent.getServletContext();
System.out.println(servletContext);
}
}
<?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.itjc.listener.ServletContextAttributeListener</listener-class>
</listener>
<listener>
<listener-class>com.itjc.listener.ServletContextListener</listener-class>
</listener>
</web-app>
五、案例学生管理系统-系统改造
学生管理系统优化
- 解决乱码
使用过滤器实现所有资源的编码统一。 - 检查登录
使用过滤器实现校验是否登录问题。 - 优化JSP页面
通过EL表达式和JSTL替换之前的Java代码块和JSP表达式。
5.1 解决乱码问题
我们的学生管理系统中,肯定会有请求和响应的中文乱码问题。而乱码问题在学习Servlet的课程中已经讲解了如何解决了。只是在实际开发中,当有很多的Servlet时,肯定不能在每个Servlet中都编写一遍解决乱码的代码。因此,就可以利用我们今天学习的过滤器来实现统一解决请求和响应乱码的问题。
5.2 检查登录
在学生管理系统中,它包含了学生信息的录入和学生列表的查询,用户(员工)信息的录入以及查询。当然,我们实际的功能可能远远不止这些。但是就已有功能来说,也不是谁都可以通过地址栏直接输入访问的,它应该有权限的控制,只是我们课程在此处没法深入展开讲解权限,但最起码的登录,身份的认证还是必要的。
由此,就引出来一个问题,是在每次访问Servlet时,在Servlet的代码中加入是否认证过身份的判断吗?显然,是不合理的。那么,既然不是在每个Servlet中编写,就应该是统一管理和维护。此时,我们的过滤器就又可以出场了。
5.3 页面的java代码块和jsp表达式改造
我们今天除了学习了过滤器,还学习了EL表达式和JSTL标签库,它们的出现就是避免我们的JSP页面中有过多的java代码或者jsp表达式。我们要运用今天所学知识改造页面。
5.4 乱码问题过滤器
创建EncodingFilter类,解决乱码
package com.itjc.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
解决全局乱码问题
*/
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 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);
}
@Override
public void destroy() {
}
}
5.5 检查登录过滤器
检查登录,创建LoginFilter 类
package com.itjc.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(value = {"/addStudent.jsp","/listStudentServlet","/listStudent.jsp"})
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 1 . 将请求和响应对象转换为何HTTP协议相关
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 2 获取会话域当中的数据
Object username1 = request.getAttribute("username");
System.out.println(username1);
Object username = request.getSession().getAttribute("username");
System.out.println(username);
if (username == null || "".equals(username)) {
//重定向到登录页面
response.sendRedirect(request.getContextPath() + "/login.jsp");
return;
}
// 4 放行操作
filterChain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
5.6 jsp页面的改造
1,修改addStudent.jsp
的虚拟访问路径
<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>
2,修改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>
3,修改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>
<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>
4,修改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>