EL(Expression Language):表达式语言
在 JSP 2.0 规范中加入的内容,也是 Servlet 规范的一部分
作用:在 JSP 页面中获取数据。让我们的 JSP 脱离 java 代码块和 JSP 表达式
语法:${ 表达式内容 }
例如:
创建一个 web 项目:el_demo,虚拟目录/el
在 web 目录下创建 el01.jsp
在文件中向域对象添加数据
使用三种方式获取域对象中的数据(java 代码块、JSP 表达式、EL 表达式)
<%
部署并启动项目
通过浏览器测试
要获取的数据类型
获取基本数据类型的数据
获取自定义对象类型的数据
获取数组类型的数据
获取 List 集合类型的数据
获取 Map 集合类型的数据
案例:新建el02.jsp
<%
访问
EL 表达式没有空指针异常
EL 表达式没有索引越界异常
EL 表达式没有字符串的拼接(el表达式中+只能对数字相加)
代码
空指针
越界和字符串拼接
访问
关系运算符
逻辑运算符
其他运算符
容器元素是否为0,就是容器的长度是否为0(其实就是检查容器是否为空)
案例:新建el03.jsp
<%
访问
EL 表达式能够获取四大域对象的数据,根据名称从小到大在域对象中查找
还可以获取 JSP 其他八个隐式对象,并调用对象中的方法
案例:el04.jsp
<%
访问
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的值 |
案例
<%
访问
总结
1. 获取四大域中的共享数据: ${数据的name} (都是通过xxx.setAttribute())
2. 根据pageContext获取其他隐式对象:${pageContext.request.contextpath}
注意: contextpath 不是共享数据,他是虚拟路径,是一个属性,有对应的一个getter方法:getContextPath
<% request.getContextPath() %>
JSTL(Java Server Pages Standarded Tag Library):JSP 标准标签库
主要提供给开发人员一个标准通用的标签库
开发人员可以利用这些标签取代 JSP 页面上的 Java 代码,从而提高程序的可读性,降低程序的维护难度
它由以下5个部分组成:
在我们实际开发中,用到的jstl标签库主要以核心标签库为准,偶尔会用到国际化标签库的标签。下表中把我们经常可能用到的标签列在此处,其余标签库请同学们参考【JSTL标签库.doc】文档。
标签名称 | 功能分类 | 分类 | 作用 |
---|---|---|---|
<c:if> |
流程控制 | 核心标签库 | 用于判断 |
<c:choose> ,<c:when>,<c:otherwise> |
流程控制 | 核心标签库 | 用于多个条件判断 |
<c:foreache> |
迭代操作 | 核心标签库 | 用于循环遍历 |
创建一个 web 项目:jstl_demo
在 web 目录下创建一个 WEB-INF 目录
在 WEB-INF 目录下创建一个 libs 目录,将 JSTL 的 jar 包导入
(jar包目录:day05_el表达式过滤器监听器\资料\JSTL的jar包)
添加引用库
创建 JSP 文件,通过 taglib 导入 JSTL 标签库
对流程控制和迭代遍历的标签进行使用
新建jstl01.jsp:流程控制
<%
新建jstl02.jsp:迭代遍历
<%
部署并启动项目
通过浏览器查看
访问jstl01
访问jstl02
问题:项目运行报错
解决:
过滤器——Filter,它是JavaWeb三大组件之一。另外两个是Servlet和Listener
它可以对web应用中的所有资源进行拦截,并且在拦截之后进行一些特殊的操作
在程序中访问服务器资源时,当一个请求到来,服务器首先判断是否有过滤器与请求资源相关联,如果有,过滤器可以将请求拦截下来,完成一些特定的功能,再由过滤器决定是否交给请求资源。如果没有则像之前那样直接请求资源了。响应也是类似的!
过滤器一般用于完成通用的操作,例如:登录验证、统一编码处理、敏感字符过滤等等~~~
处理通用操作: 统一编码处理
处理拦截操作:权限校验,如果有权限那就放行,如果没有就拦截
过滤器会做两件事情:拦截,筛选/过滤
过滤器图示
生活中的例子
比如一对新人结婚,规定:只有带红包的客人可以吃酒席,不带的就不能吃
那么这项工作不可能由新人自己完成,他们请了俩人,一个管收钱,一个管记账(这俩人就是过滤器)
Filter 是一个接口,如果想实现过滤器的功能,必须实现该接口
核心方法
配置方式
注解方式
配置文件
Filter官网介绍
FilterChain 是一个接口,代表过滤器链对象。由 Servlet 容器提供实现类对象,直接使用即可。
chain: [t?e?n] 链子
过滤器可以定义多个,就会组成过滤器链
核心方法
官网介绍
需求说明
通过 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;
?
新建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;
?
访问
发现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(拦截路径)
配置文件方式
多个过滤器使用顺序
如果有多个过滤器,取决于过滤器映射的顺序
也就是filter-mapping配置的先后顺序
案例
将demo1的WebFilter注解屏蔽
新建FilterDemo02:
package com.itheima.filter;
?
import javax.servlet.*;
import java.io.IOException;
?
/*
过滤器基本使用
*/
//@WebFilter("/*")
public class FilterDemo02 implements Filter{
?
配置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>
访问
创建(出生)
当应用加载时实例化对象并执行 init 初始化方法
服务(活着)
对象提供服务的过程,执行 doFilter 方法
只要应用一直提供服务,对象就一直存在
销毁(死亡)
当应用卸载时或服务器停止时对象销毁。执行 destroy 方法
Filter的实例对象在内存中也只有一份。所以也是单例的。
案例:新建FilterDemo03
package com.itheima.filter;
?
import javax.servlet.*;
import java.io.IOException;
?
/*
过滤器生命周期
*/
//@WebFilter("/*")
public class FilterDemo03 implements Filter{
?
/*
初始化方法
*/
配置:为了不影响测试,给之前的俩过滤器的配置代码屏蔽掉
<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>
访问
FilterConfig 是一个接口。代表过滤器的配置对象,可以加载一些初始化参数。
与ServletConfig类似
核心方法
官网介绍
案例:新建FilterDemo04
package com.itheima.filter;
?
import javax.servlet.*;
import java.io.IOException;
?
/*
过滤器配置对象的使用
*/
//@WebFilter("/*")
public class FilterDemo04 implements Filter{
?
/*
初始化方法
*/
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
在介绍监听器之前,先跟同学们普及一个知识,观察者设计模式。
因为所有的监听器都是观察者设计模式的体现。
那什么是观察者设计模式呢?
它是事件驱动的一种体现形式。就好比在做什么事情的时候被人盯着,当对应做到某件事时,触发事件。
观察者模式通常由以下三部分组成:
事件源:触发事件的对象。
事件:触发的动作,里面封装了事件源。
监听器:当事件源触发事件时,要做的事情。一般是一个接口,由使用者来实现。(此处的思想还涉及了一个设计模式,我们在JDBC的第二天课程中就给同学们讲解,策略模式)
事件源触发某个事件之后,监听器监听到了这个过程,进而执行一个逻辑
例子:狗发现人从门前过,就会狂吠 (看门狗)
生活中的例子
老师定了一个规矩,老师一旦发现学生9点之后来的话就算迟到,那就惩罚,9点之前来的学生不惩罚
在这个例子中,事件源是学生
事件是迟到
监听器就是老师
监听器介绍
在程序当中,我们可以对:对象的创建销毁、域对象中属性的变化、会话相关内容进行监听
Servlet 规范中共计 8 个监听器,监听器都是以接口形式提供,具体功能需要我们自己来完成
ServletContextListener:用于监听 ServletContext 对象的创建和销毁
核心方法
参数:ServletContextEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是创建或销毁 ServletContext 对象的操作
HttpSessionListener:用于监听 HttpSession 对象的创建和销毁
核心方法
参数:HttpSessionEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是创建或销毁 HttpSession 对象的操作
ServletRequestListener:用于监听 ServletRequest 对象的创建和销毁
核心方法
参数:ServletRequestEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是创建或销毁 ServletRequest 对象的操作
ServletContextAttributeListener:用于监听 ServletContext 应用域中属性的变化
核心方法
参数:ServletContextAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletContext
真正的事件指的是添加、移除、替换应用域中属性的操作
HttpSessionAttributeListener:用于监听 HttpSession 会话域中属性的变化
核心方法
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除、替换会话域中属性的操作
ServletRequestAttributeListener:用于监听 ServletRequest 请求域中属性的变化
核心方法
参数:ServletRequestAttributeEvent 代表事件对象
事件对象中封装了事件源,也就是 ServletRequest
真正的事件指的是添加、移除、替换请求域中属性的操作
HttpSessionBindingListener:用于感知对象和会话域绑定的监听器
核心方法
参数:HttpSessionBindingEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是添加、移除会话域中数据的操作
HttpSessionBindingListener和HttpSessionAttributeListener区别:
1.只有实现了HttpSessionBindingListener的类,添加移除到session域中才会触发绑定,解绑方法。 2.任何对象(不论其是否实现了HttpSessionAttributeListener)在变化时均触发对应的事件。
HttpSessionActivationListener:用于感知会话域中对象钝化和活化的监听器
核心方法
参数:HttpSessionEvent 代表事件对象
事件对象中封装了事件源,也就是 HttpSession
真正的事件指的是会话域中数据钝化、活化的操作
在实际开发中,我们可以根据具体情况来从这8个监听器中选择使用
感知型监听器由于无需配置,只需要根据实际需求编写代码,所以此处我们就不再演示了
我们在剩余6个中分别选择一个监听对象创建销毁和对象域中属性发生变化的监听器演示一下
演示下边两个
创建项目: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
新建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>
我们的学生管理系统中,肯定会有请求和响应的中文乱码问题。而乱码问题在学习Servlet的课程中已经讲解了如何解决了。只是在实际开发中,当有很多的Servlet时,肯定不能在每个Servlet中都编写一遍解决乱码的代码。因此,就可以利用我们今天学习的过滤器来实现统一解决请求和响应乱码的问题。
在学生管理系统中,它包含了学生信息的录入和学生列表的查询,用户(员工)信息的录入以及查询。当然,我们实际的功能可能远远不止这些。但是就已有功能来说,也不是谁都可以通过地址栏直接输入访问的,它应该有权限的控制,只是我们课程在此处没法深入展开讲解权限,但最起码的登录,身份的认证还是必要的。
由此,就引出来一个问题,是在每次访问Servlet时,在Servlet的代码中加入是否认证过身份的判断吗?显然,是不合理的。那么,既然不是在每个Servlet中编写,就应该是统一管理和维护。此时,我们的过滤器就又可以出场了。
我们今天除了学习了过滤器,还学习了EL表达式和JSTL标签库,它们的出现就是避免我们的JSP页面中有过多的java代码或者jsp表达式。我们要运用今天所学知识改造页面。
代码
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(); } } }
代码
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(); } } }
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
<%
login.jsp
<%
EL&Filter&Listener:EL表达式和JSTL,Servlet规范中的过滤器,Servlet规范中的监听器,观察着设计模式,监听器的使用,综合案例学生管理系统
原文:https://www.cnblogs.com/859630097com/p/14320985.html