掌握JavaWeb开发的必备技能:Servlet、JSP、Cookie、Session、EL、JSTL详解 ~~~~B站老杜--Servlet-JSP-课堂笔记(三)

简介: 当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。思考一个业务场景

🍓🍓EL表达式

EL表达式是干什么用的?


Expression Language(表达式语言)

EL表达式可以代替JSP中的java代码,让JSP文件中的程序看起来更加整洁,美观。

JSP中夹杂着各种java代码,例如<% java代码 %>、<%=%>等,导致JSP文件很混乱,不好看,不好维护。所以才有了后期的EL表达式。

EL表达式可以算是JSP语法的一部分。EL表达式归属于JSP。

EL表达式出现在JSP中主要是:


从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器。这就是EL表达式的功效。三大功效:

第一功效:从某个域中取数据。

四个域:

pageContext

request

session

application

第二功效:将取出的数据转成字符串。

如果是一个java对象,也会自动调用java对象的toString方法将其转换成字符串。

第三功效:将字符串输出到浏览器。

和这个一样:<%= %>,将其输出到浏览器。

EL表达式很好用,基本的语法格式:


${表达式}

EL表达式的使用:




<%
  // 创建User对象
  User user = new User();
  user.setUsername("jackson");
  user.setPassword("1234");
  user.setAge(50);
  // 将User对象存储到某个域当中。一定要存,因为EL表达式只能从某个范围中取数据。
  // 数据是必须存储到四大范围之一的。
  request.setAttribute("userObj", user);
%>
<%--使用EL表达式取--%>
${这个位置写什么????这里写的一定是存储到域对象当中时的name}
要这样写:
${userObj}
等同于java代码:<%=request.getAttribute("userObj")%>
你不要这样写:${"userObj"}
面试题:
  ${abc} 和 ${"abc"}的区别是什么?
    ${abc}表示从某个域中取出数据,并且被取的这个数据的name是"abc",之前一定有这样的代码: 域.setAttribute("abc", 对象);
    ${"abc"} 表示直接将"abc"当做普通字符串输出到浏览器。不会从某个域中取数据了。
${userObj} 底层是怎么做的?从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器。
<%--如果想输出对象的属性值,怎么办?--%>
${userObj.username} 使用这个语法的前提是:User对象有getUsername()方法。
${userObj.password} 使用这个语法的前提是:User对象有getPassword()方法。
${userObj.age} 使用这个语法的前提是:User对象有getAge()方法。
${userObj.email} 使用这个语法的前提是:User对象有getEmail()方法。
EL表达式中的. 这个语法,实际上调用了底层的getXxx()方法。
注意:如果没有对应的get方法,则出现异常。报500错误。
${userObj.addr222.zipcode}
以上EL表达式对应的java代码:
user.getAddr222().getZipcode()

EL表达式优先从小范围中读取数据。


pageContext < request < session < application

EL表达式中有四个隐含的隐式的范围:


pageScope 对应的是 pageContext范围。

requestScope 对应的是 request范围。

sessionScope 对应的是 session范围。

applicationScope 对应的是 application范围。

EL表达式对null进行了预处理。如果是null,则向浏览器输出一个空字符串。


EL表达式取数据的时候有两种形式:


第一种:. (大部分使用这种方式)

第二种:[ ] (如果存储到域的时候,这个name中含有特殊字符,可以使用 [ ])

request.setAttribute(“abc.def”, “zhangsan”);

${requestScope.abc.def} 这样是无法取值的。

应该这样:${requestScope[“abc.def”]}

掌握使用EL表达式,怎么从Map集合中取数据:


${map.key}

掌握使用EL表达式,怎么从数组和List集合中取数据:


${数组[0]}

${数组[1]}

${list[0]}

page指令当中,有一个属性,可以忽略EL表达式


<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>

isELIgnored="true" 表示忽略EL表达式

isELIgnored="false" 表示不忽略EL表达式。(这是默认值)


isELIgnored="true" 这个是全局的控制。


可以使用反斜杠进行局部控制:\${username} 这样也可以忽略EL表达式。

<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>
isELIgnored="true" 表示忽略EL表达式
isELIgnored="false" 表示不忽略EL表达式。(这是默认值)
isELIgnored="true" 这个是全局的控制。
可以使用反斜杠进行局部控制:\${username} 这样也可以忽略EL表达式。

通过EL表达式获取应用的根:


${pageContext.request.contextPath}

EL表达式中其他的隐式对象:


pageContext

param

paramValues

initParam

EL表达式的运算符


算术运算符

+、-、*、/、%

关系运算符

== eq != > >= < <=

逻辑运算符

! && || not and or

条件运算符

? :

取值运算符

[ ]和.

empty运算符

empty运算符的结果是boolean类型

${empty param.username}

${not empty param.username}

${!empty param.password}

🍓🍓JSTL标签库

什么是JSTL标签库?


Java Standard Tag Lib(Java标准的标签库)

JSTL标签库通常结合EL表达式一起使用。目的是让JSP中的java代码消失。

标签是写在JSP当中的,但实际上最终还是要执行对应的java程序。(java程序在jar包当中。)

使用JSTL标签库的步骤:


第一步:引入JSTL标签库对应的jar包。


tomcat10之后引入的jar包是:

jakarta.servlet.jsp.jstl-2.0.0.jar

jakarta.servlet.jsp.jstl-api-2.0.0.jar

在IDEA当中怎么引入?

在WEB-INF下新建lib目录,然后将jar包拷贝到lib当中。然后将其“Add Lib…”

一定是要和mysql的数据库驱动一样,都是放在WEB-INF/lib目录下的。

什么时候需要将jar包放到WEB-INF/lib目录下?如果这个jar是tomcat服务器没有的。

第二步:在JSP中引入要使用标签库。(使用taglib指令引入标签库。)


JSTL提供了很多种标签,你要引入哪个标签????重点掌握核心标签库。


<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
这个就是核心标签库。
prefix="这里随便起一个名字就行了,核心标签库,大家默认的叫做c,你随意。"

第三步:在需要使用标签的位置使用即可。表面使用的是标签,底层实际上还是java程序。


JSTL标签的原理


<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
以上uri后面的路径实际上指向了一个xxx.tld文件。
tld文件实际上是一个xml配置文件。
在tld文件中描述了“标签”和“java类”之间的关系。
以上核心标签库对应的tld文件是:c.tld文件。它在哪里。
在jakarta.servlet.jsp.jstl-2.0.0.jar里面META-INF目录下,有一个c.tld文件。


源码解析:配置文件tld解析


<tag>
    <description>对该标签的描述</description>
    <name>catch</name> 标签的名字
    <tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class> 标签对应的java类。
    <body-content>JSP</body-content> 标签体当中可以出现的内容,如果是JSP,就表示标签体中可以出现符合JSP所有语法的代码。例如EL表达式。
    <attribute>
        <description>
          对这个属性的描述
        </description>
        <name>var</name> 属性名
        <required>false</required> false表示该属性不是必须的。true表示该属性是必须的。
        <rtexprvalue>false</rtexprvalue> 这个描述说明了该属性是否支持EL表达式。false表示不支持。true表示支持EL表达式。
    </attribute>
  </tag>
<c:catch var="">
  JSP....
</c:catch>


jstl中的核心标签库core当中有哪些常用的标签呢?


c:if


<c:if test=“boolean类型,支持EL表达式”></c: if>

c:forEach


<c:forEach items=“集合,支持EL表达式” var=“集合中的元素” varStatus=“元素状态对象”> ${元素状态对象.count} </c: forEach>

<c:forEach var=“i” begin=“1” end=“10” step=“2”> ${i} </c: forEach>

c:choose c:when c:otherwise


<c:choose>
    <c:when test="${param.age < 18}">
        青少年
    </c:when>
    <c:when test="${param.age < 35}">
        青年
    </c:when>
    <c:when test="${param.age < 55}">
        中年
    </c:when>
    <c:otherwise>
        老年
    </c:otherwise>
</c:choose>

🥭🥭改造OA

使用什么技术改造呢?


Servlet + JSP + EL表达式 + JSTL标签。进行改造。

在前端HTML代码中,有一个标签,叫做base标签,这个标签可以设置整个网页的基础路径。


这是Java的语法,也不是JSP的语法。是HTML中的一个语法。HTML中的一个标签。通常出现在head标签中。


< base href=“http://localhost:8080/oa/”>


在当前页面中,凡是路径没有以“/”开始的,都会自动将base中的路径添加到这些路径之前。


< a href=“ab/def”></ a>

等同于:< a href=“http://localhost:8080/oa/ab/def”></ a>

需要注意:在JS代码中的路径,保险起见,最好不要依赖base标签。JS代码中的路径最好写上全路径。


<base

href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">

🍓🍓Filter过滤器

过滤器实现原理


a0eddbc75621b1d57602d4620dbb0459_fde7a01274624c85b7a861e2c86bc1e6.png

当前的OA项目存在什么缺陷?


DeptServlet、EmpServlet、OrderServlet。每一个Servlet都是处理自己相关的业务。在这些Servlet执行之前都是需要判断用户是否登录了。如果用户登录了,可以继续操作,如果没有登录,需要用户登录。这段判断用户是否登录的代码是固定的,并且在每一个Servlet类当中都需要编写,显然代码没有得到重复利用。包括每一个Servlet都要解决中文乱码问题,也有公共的代码。这些代码目前都是重复编写,并没有达到复用。怎么解决这个问题?

可以使用Servlet规范中的Filter过滤器来解决这个问题。

Filter是什么,有什么用,执行原理是什么?


Filter是过滤器。

Filter可以在Servlet这个目标程序执行之前添加代码。也可以在目标Servlet执行之后添加代码。之前之后都可以添加过滤规则。

一般情况下,都是在过滤器当中编写公共代码。

一个过滤器怎么写呢?


第一步:编写一个Java类实现一个接口:jarkata.servlet.Filter。并且实现这个接口当中所有的方法。


init方法:在Filter对象第一次被创建之后调用,并且只调用一次。

doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求,则执行N次。在这个方法中编写过滤规则。

destroy方法:在Filter对象被释放/销毁之前调用,并且只调用一次。

第二步:在web.xml文件中对Filter进行配置。这个配置和Servlet很像。


<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.bjpowernode.javaweb.servlet.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>


或者使用注解:@WebFilter({“*.do”})


注意:


Servlet对象默认情况下,在服务器启动的时候是不会新建对象的。

Filter对象默认情况下,在服务器启动的时候会新建对象。

Servlet是单例的。Filter也是单例的。(单实例。)

目标Servlet是否执行,取决于两个条件:


第一:在过滤器当中是否编写了:chain.doFilter(request, response); 代码。

第二:用户发送的请求路径是否和Servlet的请求路径一致。

chain.doFilter(request, response); 这行代码的作用:


执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet。

注意:Filter的优先级,天生的就比Servlet优先级高。


/a.do 对应一个Filter,也对应一个Servlet。那么一定是先执行Filter,然后再执行Servlet。

关于Filter的配置路径:


/a.do、/b.do、/dept/save。这些配置方式都是精确匹配。

/* 匹配所有路径。

*.do 后缀匹配。不要以 / 开始

/dept/* 前缀匹配。

在web.xml文件中进行配置的时候,Filter的执行顺序是什么?


依靠filter-mapping标签的配置位置,越靠上优先级越高。

过滤器的调用顺序,遵循栈数据结构。


使用@WebFilter的时候,Filter的执行顺序是怎样的呢?


执行顺序是:比较Filter这个类名。

比如:FilterA和FilterB,则先执行FilterA。

比如:Filter1和Filter2,则先执行Filter1.

Filter的生命周期?


和Servlet对象生命周期一致。

唯一的区别:Filter默认情况下,在服务器启动阶段就实例化。Servlet不会。

Filter过滤器这里有一个设计模式:


责任链设计模式。

过滤器最大的优点:

在程序编译阶段不会确定调用顺序。因为Filter的调用顺序是配置到web.xml文件中的,只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。显然Filter的执行顺序是在程序运行阶段动态组合的。那么这种设计模式被称为责任链设计模式。

责任链设计模式最大的核心思想:

在程序运行阶段,动态的组合程序的调用顺序。

使用过滤器改造OA项目。


🍓🍓Listener监听器

什么是监听器?


监听器是Servlet规范中的一员。就像Filter一样。Filter也是Servlet规范中的一员。

在Servlet中,所有的监听器接口都是以“Listener”结尾。

监听器有什么用?


监听器实际上是Servlet规范留给我们javaweb程序员的特殊时机。

特殊的时刻如果想执行这段代码,你需要想到使用对应的监听器。

Servlet规范中提供了哪些监听器?


jakarta.servlet包下:

ServletContextListener

ServletContextAttributeListener

ServletRequestListener

ServletRequestAttributeListener

jakarta.servlet.http包下:

HttpSessionListener

HttpSessionAttributeListener

该监听器需要使用@WebListener注解进行标注。

该监听器监听的是什么?是session域中数据的变化。只要数据变化,则执行相应的方法。主要监测点在session域对象上。

HttpSessionBindingListener

该监听器不需要使用@WebListener进行标注。

假设User类实现了该监听器,那么User对象在被放入session的时候触发bind事件,User对象从session中删除的时候,触发unbind事件。

假设Customer类没有实现该监听器,那么Customer对象放入session或者从session删除的时候,不会触发bind和unbind事件。

HttpSessionIdListener

session的id发生改变的时候,监听器中的唯一一个方法就会被调用。

HttpSessionActivationListener

监听session对象的钝化和活化的。

钝化:session对象从内存存储到硬盘文件。

活化:从硬盘文件把session恢复到内存。

实现一个监听器的步骤:以ServletContextListener为例。


第一步:编写一个类实现ServletContextListener接口。并且实现里面的方法。


void contextInitialized(ServletContextEvent event)
void contextDestroyed(ServletContextEvent event)


第二步:在web.xml文件中对ServletContextListener进行配置,如下:


<listener>
    <listener-class>com.bjpowernode.javaweb.listener.MyServletContextListener</listener-class>
</listener>


当然,第二步也可以不使用配置文件,也可以用注解,例如:@WebListener


注意:所有监听器中的方法都是不需要javaweb程序员调用的,由服务器来负责调用?什么时候被调用呢?


当某个特殊的事件发生(特殊的事件发生其实就是某个时机到了。)之后,被web服务器自动调用。

思考一个业务场景:


请编写一个功能,记录该网站实时的在线用户的个数。

我们可以通过服务器端有没有分配session对象,因为一个session代表了一个用户。有一个session就代表有一个用户。如果你采用这种逻辑去实现的话,session有多少个,在线用户就有多少个。这种方式的话:HttpSessionListener够用了。session对象只要新建,则count++,然后将count存储到ServletContext域当中,在页面展示在线人数即可。

业务发生改变了,只统计登录的用户的在线数量,这个该怎么办?

session.setAttribute(“user”, userObj);

用户登录的标志是什么?session中曾经存储过User类型的对象。那么这个时候可以让User类型的对象实现HttpSessionBindingListener监听器,只要User类型对象存储到session域中,则count++,然后将count++存储到ServletContext对象中。页面展示在线人数即可。

实现oa项目中当前登录在线的人数。


什么代表着用户登录了?

session.setAttribute(“user”, userObj); User类型的对象只要往session中存储过,表示有新用户登录。

什么代表着用户退出了?

session.removeAttribute(“user”); User类型的对象从session域中移除了。

或者有可能是session销毁了。(session超时)

目录
相关文章
|
29天前
|
Java
学校教师管理系统【JSP+Servlet+JavaBean】(Java课设)
学校教师管理系统【JSP+Servlet+JavaBean】(Java课设)
21 1
|
29天前
|
Java
人事管理系统【JSP+Servlet+JavaBean】(Java课设)
人事管理系统【JSP+Servlet+JavaBean】(Java课设)
19 0
|
2月前
|
Java
jsp中使用cookie时报错……
jsp中使用cookie时报错……
9 0
|
2月前
|
Java 数据安全/隐私保护
jsp使用cookie实现记住用户名和密码
jsp使用cookie实现记住用户名和密码
12 0
|
2月前
使用Servlet上传多张图片——前台页面层(Index.jsp)
使用Servlet上传多张图片——前台页面层(Index.jsp)
14 0
|
1天前
|
存储
Servlet 教程 之 Servlet Cookie 处理 7
Servlet教程展示了如何删除Cookie。Servlet `DeleteCookies`通过设置setMaxAge()为零,从响应头移除名为&quot;url&quot;的Cookie。当运行此Servlet,之前的ReadCookies返回的url将是null。代码包括检查请求中的Cookie,匹配名称后删除,并显示删除确认信息。
4 0
|
1天前
Servlet 教程 之 Servlet Cookie 处理 6
该教程展示了如何使用Servlet读取Cookie。在`doGet`方法中,通过`HttpServletRequest`的`getCookies()`获取Cookie数组,然后遍历并使用`getName()`和`getValue()`获取每个Cookie的详细信息。如果找到名为&quot;name&quot;的Cookie,将其最大生存期设为0以删除。输出显示Cookie的名称和解码后的值。当无Cookie时,则显示相应消息。
4 0
|
2天前
|
XML 数据格式
Servlet 教程 之 Servlet Cookie 处理 5
Servlet教程展示了如何处理Cookie。创建Cookie涉及构造函数(键值对),设置最大生存周期(如24小时)并将其添加到HTTP响应头。给定示例显示了一个Servlet,它从表单接收名字和URL,编码为Cookie,设置过期时间,然后在响应中发送。HTML表单用于触发Servlet。需在web.xml配置Servlet并用HTML页面调用。
7 1
|
2天前
|
安全 网络安全 数据安全/隐私保护
Servlet 教程 之 Servlet Cookie 处理 3
Servlet教程中的Cookie处理介绍了12个关键方法:设置/获取域名、最大生存时间、名称、值、路径和安全属性,以及评论的设置与获取。这些方法用于在Servlet中创建和管理Cookie的行为,如设定有效期、作用域及安全性。
9 1
|
3天前
|
存储 JavaScript 前端开发
Servlet 教程 之 Servlet Cookie 处理 2
Servlet教程探讨了Cookie处理,用于识别返回用户。服务器发送Cookie到浏览器,浏览器存储并随后续请求发送。处理中文Cookie需用URLEncoder/URLDecoder进行编码解码。设置Cookie通过HTTP头的Set-Cookie字段,包含名值对、过期时间、路径和域。浏览器在到期前保存并自动发送匹配的Cookie。Servlet利用request.getCookies()获取Cookie数组。
8 0

相关实验场景

更多