个人主页:Hello Code. 本文专栏:《Java WEB从入门到实战》 Java WEB完整内容请点击前往Java WEB从入门到实战 查看 如有问题,欢迎指正,一起学习~~
EL表达式
- EL(Expression Language):表达式语言
- 在 JSP 2.0 规范中加入的内容,也是 Servlet 规范的一部分
- 作用:在 JSP 页面中获取数据,让我们的 JSP 脱离 Java代码块和 JSP 表达式
- 语法:
${表达式内容}
快速入门
- 创建一个web 项目
- 在web 目录下创建 jsp文件
- 在文件中向域对象添加数据
- 使用三种方式获取域对象中的数据(Java代码块、JSP表达式、EL表达式)
- 部署并启动项目
- 通过浏览器测试
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:04
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式快速入门</title>
</head>
<body>
<% request.setAttribute("username","zhangsan"); %>
<%--java代码块--%>
<% out.println(request.getAttribute("username")); %><br>
<%-- jsp表达式 --%>
<%=request.getAttribute("username")%><br>
<%--EL表达式--%>
${username}
</body>
</html>
获取数据
- 获取基本数据类型的数据
${数据名} - 获取自定义对象类型的数据
${对象名.属性名} 这里获取到对象的成员变量的原理是通过调用get方法获取,所以不必担心private私有问题 - 获取数组类型的数据
${数组名[索引]} - 获取List 集合类型的数据
${集合[索引]} - 获取 Map 集合类型的数据
${集合.key值} :获取key对应的value
<%@ page import="study.servlet.bean.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %><%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:10
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>EL表达式获取数据</title>
</head>
<body>
<%
Student stu = new Student("张三",23);
int[] arr = {1,2,3,4,5};
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
HashMap<String,String> map = new HashMap<>();
map.put("user","zhangsan");
map.put("age","28");
pageContext.setAttribute("stu",stu);
pageContext.setAttribute("arr",arr);
pageContext.setAttribute("list",list);
pageContext.setAttribute("map",map);
%>
<%--EL表达式获取数据--%>
${stu.name}<br> <%--获取自定义对象类型的数据--%>
${arr[2]}<br> <%--获取数组类型的数据--%>
${list[1]}<br> <%--获取List 集合类型的数据--%>
${map.user} <%--获取 Map 集合类型的数据--%>
</body>
</html>
注意事项
- EL 表达式没有空指针异常
- EL 表达式没有索引越界异常
- EL 表达式没有字符串的拼接
使用细节
- EL 表达式能够获取到四大域对象的数据,根据名称从小到大在域对象中查找
- 还可以获取 JSP 其他八个隐式对象,并调用对象中的方法
运算符
- 关系运算符
运算符 | 作用 | 示例 | 结果 |
---|
== 或 eq | 等于 | ${5 == 5} 或 ${5 eq 5} | true | != 或 ne | 不等于 | ${5 != 5} 或 ${5 ne 5} | false | < 或 lt | 小于 | ${3 < 5} 或 ${3 lt 5} | true | > 或 gt | 大于 | ${3 > 5} 或 ${3 gt 5} | false | <= 或 le | 小于等于 | ${3 <= 5} 或 ${3 le 5} | true | >= 或 ge | 大于等于 | ${3 >= 5} 或 ${3 ge 5} | false | - 逻辑运算符
运算符 | 作用 | 示例 | 结果 |
---|
&& 或 and | 并且 | ${A && B} 或 ${A and B} | true / false | || 或 or | 或者 | ${A || B} 或 ${A or B} | true / false | ! 或 not | 取反 | ${!A} 或 ${not A} | true / false | - 其他运算符
运算符 | 作用 |
---|
empty | 1. 判断对象是否为null 2. 判断字符串是否为空字符串 3. 判断容器元素是否为0 | 条件 ? 表达式1 : 表达式2 | 三元运算符 |
隐式对象
隐式对象名称 | 对应JSP隐式对象 | 说明 |
---|
pageContext | pageContext | 功能完全相同 | applicationScope | 无 | 操作应用域对象数据 | sessionScope | 无 | 操作会话域对象数据 | requestScope | 无 | 操作请求域对象数据 | pageScope | 无 | 操作页面域对象数据 | header | 无 | 获取请求头数据 | headerValues | 无 | 获取请求头数据(多个值) | param | 无 | 获取请求参数数据 | paramValues | 无 | 获取请求参数数据(多个值) | initParam | 无 | 获取全局配置参数数据 | cookie | 无 | 获取Cookie对象 |
<%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>隐式对象</title>
</head>
<body>
<%--pageContext对象,可以获取其他三个域对象和JSP中八个隐式对象--%>
${pageContext.request.requestURL}<br>
<%--applicationScope sessionScope requestScope pageScope 操作四大域对象中的数据--%>
${pageContext.setAttribute("username","zhangsan")}
${pageScope.username}<br>
<%--header headerValues 获取请求头数据--%>
${header["connection"]}
${headerValues["connection"][0]}
${header.connection}<br>
<%--param paramValues 获取请求参数数据--%>
${param.username}
${paramValues.hobby[0]}<br>
<%--initParam 获取全局配置参数--%>
${initParam.globaldesc}<br>
<%--cookie 获取cookie信息--%>
${cookie} <%--直接写cookie获取到的是一个map集合--%>
<br>
${cookie.JSESSIONID.value}
</body>
</html>
JSTL
- JSTL(Java Server Pages Standarded Tag Library):JSP 标准标签库
- 主要提供给开发人员一个标准通用的标签库
- 开发人员可以利用这些标签来取代 JSP 页面上的Java代码,从而提高程序的可读性,降低程序的维护难度
组成 | 作用 | 说明 |
---|
core | 核心标签库 | 通用的逻辑处理 | fmt | 国际化 | 不同地域显示不同语言 | functions | EL 函数 | EL 表达式可以使用的方法 | sql | 操作数据库 | 了解 | xml | 操作XML | 了解 |
核心标签
标签名称 | 功能分类 | 属性 | 作用 |
---|
<标签名:if> | 流程控制 | 核心标签库 | 用于条件判断 | <标签名:choose> <标签名:when> <标签名:otherwise> | 流程控制 | 核心标签库 | 用于多条件判断 | <标签名:forEach> | 迭代遍历 | 核心标签库 | 用于循环遍历 |
使用步骤
- 创建一个 web 项目
- 在 web目录下创建一个 WEB-INF 目录
- 在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入
- 创建 JSP 文件,通过 taglib 导入 JSTL 标签库
- 对流程控制和迭代遍历的标签进行使用
- 部署并启动项目
- 通过浏览器查看
<%@ page import="java.util.ArrayList" %><%--
Created by IntelliJ IDEA.
User: lihao
Date: 2022/2/25
Time: 10:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--导入核心库并起标签名--%>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<html>
<head>
<title>JSTL【JSP标准标签库】</title>
</head>
<body>
${pageContext.setAttribute("score","A")}
<%--对成绩进行判断--%>
<c:if test="${score eq 'A'}">
优秀
</c:if>
<hr>
<%--多条件判断--%>
<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>
<hr>
<%--循环遍历--%>
<%
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
pageContext.setAttribute("list",list);
%>
<c:forEach items="${list}" var="str">
${str}<br>
</c:forEach>
</body>
</html>
Filter
- 在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有相关联的过滤器则像之前那样直接请求资源了。响应也是类似的
- 过滤器一般完成用于通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等等…
概述
- 是一个接口。如果想实现过滤器的功能,必须实现该接口
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | init(FilterConfig config) | 初始化方法 | void | doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 对请求资源和响应资源过滤 | void | destroy() | 销毁方法 | - 配置方式
方式一:配置文件(web.xml) 方式二:注解方式
FilterChain
- FilterChain 是一个接口,代表过滤器链对象。由Servlet 容器提供实现类对象。直接使用即可
- 过滤器可以定义多个,就会组成过滤器链
- 核心方法
返回值 | 方法名 | 说明 |
---|
void | doFilter(ServletRequest request, ServletResponse response) | 放行方法 |
如果有多个过滤器,在第一个过滤器中调用下一个过滤器,依此类推。直到到达最终访问资源。 如果只有一个过滤器,放行时,就会直接到达最终访问资源
过滤器使用
- 需求说明:通过 Filter 过滤器解决多个资源写出中文乱码的问题
- 实现步骤
- 创建一个 web 项目
- 创建两个 Servlet 功能类,都向客户端写出中文数据
- 创建一个 Filter 过滤器实现类,重写 doFilter 核心方法
- 在方法内解决中文乱码,并放行
- 部署并启动项目
- 通过浏览器测试
package study.servlet.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/filter01")
public class filter 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执行了");
servletResponse.setContentType("text/html;charset=UTF-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}
使用细节
生命周期
- 创建
当应用加载时实例化对象并执行init初始化方法 - 服务
对象提供服务的过程,执行 doFilter 方法 - 销毁
当应用卸载时或服务器停止时对象销毁。执行 destroy 方法
FilterConfig
五种拦截行为
全局错误页面配置
<error-page>
<exception-type>java.lang.exception</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
Listener
- 观察者设计模式,所有的监听器都是基于观察者设计模式的
- 三个组成部分
- 事件源:触发事件的对象
- 事件:触发的动作,封装了事件源
- 监听器:当事件源触发事件后,可以完成功能
- 在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听
- Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成
监听器
监听对象的创建和销毁的监听器
- ServletContextListener:用于监听 ServletContext 对象的创建和销毁
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | contextInitialized(ServletContextEvent sce) | 对象创建时执行该方法 | void | contextDestroyed(ServletContextEvent sce) | 对象销毁时执行该方法 |
参数:ServletContextEvent 代表事件对象 事件对象中封装了事件源,也就是 ServletContext 真正的事件指的是创建或销毁 ServletContext 对象的操作
- HttpSessionListener:用于监听 HttpSession 对象的创建和销毁
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | sessionCreated(HttpSessionEvent se) | 对象创建时执行该方法 | void | sessionDestroyed(HttpSessionEvent se) | 对象销毁时执行该方法 |
参数:HttpSessionEvent 代表事件对象 事件对象中封装了事件源,也就是 HttpSession 真正的事件指的是创建或销毁 HttpSession 对象的操作
- ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | requestInitialized(ServletRequestEvent sre) | 对象创建时执行该方法 | void | requestDestroyed(ServletRequestEvent sre) | 对象销毁时执行该方法 |
参数:ServletRequestEvent 代表事件对象 事件对象中封装了事件源,也就是 ServletRequest 真正的事件指的是创建或销毁 ServletRequest 对象的操作
监听域对象属性变化的监听器
- ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | attributeAdded(ServletContextAttributeEvent scae) | 域中添加属性时执行该方法 | void | attributeRemoved(ServletContextAttributeEvent scae) | 域中移除属性时执行该方法 | void | attributeReplaced(ServletContextAttributeEvent scae) | 域中替换属性时执行该方法 |
参数:ServletContextAttributeEvent 代表事件对象 事件对象中封装了事件源,也就是 ServletContext 真正的事件指的是添加、移除、替换应用域中属性的操作
- HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | attributeAdded(HttpSessionBindingEvent se) | 域中添加属性时执行该方法 | void | attributeRemoved(HttpSessionBindingEvent se) | 域中移除属性时执行该方法 | void | attributeReplaced(HttpSessionBindingEvent se) | 域中替换属性时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象 事件对象中封装了事件源,也就是 HttpSession 真正的事件指的是添加、移除、替换会话域中属性的操作
- ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | attributeAdded(ServletRequestAttributeEvent srae) | 域中添加属性时执行该方法 | void | attributeRemoved(ServletRequestAttributeEvent srae) | 域中移除属性时执行该方法 | void | attributeReplaced(ServletRequestAttributeEvent srae) | 域中替换属性时执行该方法 |
参数:ServletRequestAttributeEvent 代表事件对象 事件对象中封装了事件源,也就是 ServletRequest 真正的事件指的是添加、移除、替换请求域中属性的操作
监听会话相关的感知型监听器
感知型监听器:在定义好之后就可以直接使用,不需要再通过注解或xml文件进行配置
- HttpSessionBindingListener:用于感知对象和会话域绑定的监听器
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | valueBound(HttpSessionBindingEvent event) | 数据添加到会话域中(绑定)时执行该方法 | void | valueUnbound(HttpSessionBindingEvent event) | 数据从会话域中移除(解绑)时执行该方法 |
参数:HttpSessionBindingEvent 代表事件对象 事件对象中封装了事件源,也就是 HttpSession 真正的事件指的是添加、移除会话域中数据的操作
- HttpSessionActivationListener:用于感知会话域对象钝化和活化的监听器
- 核心方法
返回值 | 方法名 | 作用 |
---|
void | sessionWillPassivate(HttpSessionEvent se) | 会话域中数据钝化时执行该方法 | void | sessionDidActivate(HttpSessionEvent se) | 会话域中数据活化时执行该方法 |
参数:HttpSessionEvent 代表事件对象 事件对象中封装了事件源,也就是 HttpSession 真正的事件指的是会话域中数据钝化、活化的操作
监听器的使用
- 监听对象的
ServletContextListener HttpSessionListener ServletRequestListener
package study.servlet.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.annotation.WebServlet;
@WebServlet("/listener01")
@WebListener
public class listener01 implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的创建");
ServletContext servletContext = servletContextEvent.getServletContext();
servletContext.setAttribute("username","张三");
servletContext.setAttribute("username","李四");
servletContext.removeAttribute("username");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("监听到了对象的销毁");
}
}
- 监听属性变化的
ServletContextAttributeListener HttpSessionAttributeListener ServletRequestAttributeListener
package study.servlet.listener;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
@WebServlet("/listener02")
public class listener02 implements 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);
}
}
- 会话相关的感知型
HttpSessionBindingListener HttpSessionActivationListener
配置监听器
学生管理系统优化
解决乱码
使用过滤器实现所有资源的编码统一
- 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
- 设置编码格式
- 放行
package studentSystem.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 设置编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 放行
filterChain.doFilter(request, response);
}
}
检查登录
使用过滤器解决登录检查
- 将请求和响应对象转换为和HTTP相关的HttpServletRequest和HttpServletResponse
- 获取会话域对象中的数据
- 判断用户名
- 重定向(或定时刷新)到登录页面或放行
注解配置过滤器时指定多个拦截路径 @WebFilter(value = {"/拦截路径一", "/拦截路径二", ...})
package studentSystem.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;
@WebFilter(value = {"/add.jsp", "/list.jsp"})
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
Object username = session.getAttribute("username");
Object password = session.getAttribute("password");
if("admin".equals(username) && "abc123".equals(password)){
filterChain.doFilter(request, response);
}else{
response.getWriter().write("您还未登录,请登录后再试。(2s后为您跳转到登录页面)");
response.setHeader("Refresh","2:URL=/login.jsp");
}
}
}
优化JSP页面
通过EL表达式和JSTL替换之前的Java代码块和JSP表达式
完整代码:https://github.com/HelloCode66/StudentSystem
推荐阅读:【Java WEB】MySQL从基础到高级
|