8. JSP
新建一个 jsp,hello.jsp,内容和 html 几乎一样,但是要处理动态页面,要请求 Servlet 类
8.1、什么是 JSP
Java Server Pages : Java 服务器端页面,也和 Servlet 一样,用于动态Web技术!
最大的特点:
- 写JSP就像在写HTML
- 区别:
- HTML只给用户提供静态的数据
- JSP页面中可以嵌入JAVA代码,为用户提供动态数据;
8.2、JSP原理
思路:JSP到底怎么执行的!
- 代码层面没有任何问题
- 服务器内部工作
Tomcat 中有一个 work 目录;在安装包下去找
IDEA 中使用 Tomcat 的会在 IDEA 的 Tomcat 中产生一个 work 目录,进入 IDEA → \to → Help → \to → Show Log in Explorer,会弹出 IDEA 的安装目录
点击进入目录下的 tomcat 目录,选择某个项目进入到如下目录:会发现 jsp 的文件就在这里(C:\Users\86182\AppData\Local\JetBrains\IntelliJIdea2023.1\tomcat
)
我的目录如下:
C:\Users\15592\AppData\Local\JetBrains\IntelliJIdea2022.1\tomcat\3e92441c-ce9e-47df-b69e-9b63cc373253\work\Catalina\localhost\request\org\apache\jsp
发现页面转变成了Java 程序!
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问 Servlet!
JSP最终也会被转换成为一个 Java 类!
记事本点开上面的某个 jsp.java ,看一看源码,看到 index_jsp 继承了 HttpJspBase 这个父类,暂时没看到继承 Servlet
要查看 HttpJspBase 类,首先要到 maven 仓库找到 Jasper Runtime
添加 maven 依赖
<!-- https://mvnrepository.com/artifact/tomcat/jasper-runtime -->
<dependency>
<groupId>tomcat</groupId>
<artifactId>jasper-runtime</artifactId>
<version>5.5.23</version>
</dependency>
然后进入到 HttpJspBase 类里面发现继承了 HttpServlet
JSP 本质上就是一个Servlet!
再看我们在 IDEA 中写的 index.jsp,如下:
在 index_jsp.java 中有对应的实现,如下:
因此我们在撰写 index.jsp 的时候只需要简单的撰写(如同 html 一样),内部会转换好,继续看 index_jsp.java 中的实现方法
从下面可以看出,JSP 本质上就是一个Servlet
//初始化
public void _jspInit() {
}
//销毁
public void _jspDestroy() {
}
//JSPService
public void _jspService(.HttpServletRequest request,HttpServletResponse response)
下面分析 JSP 执行过程
1. _jspService 中首先执行判断请求
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
- 该段代码的主要目的是确保只有合法的 HTTP 请求方法(GET, POST, HEAD 或 OPTIONS)能够通过,其他方法将返回 405 错误,提示客户端不支持的请求方法。
- 它特别适用于处理 JSP 页面请求,并为
OPTIONS
请求提供特别处理,明确指示服务器支持哪些方法。
2. 内置一些对象(很重要,记住!!!)
final javax.servlet.jsp.PageContext pageContext; //页面上下文
javax.servlet.http.HttpSession session = null; //session
final javax.servlet.ServletContext application; //applicationContext
final javax.servlet.ServletConfig config; //config
javax.servlet.jsp.JspWriter out = null; //out
final java.lang.Object page = this; //page:当前页
HttpServletRequest request //请求
HttpServletResponse response //响应
- applicationContext 实质上就是 servletContext
3. 输出页面前增加的代码
response.setContentType("text/html"); //设置文本响应的页面类型为 html
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext(); // ServletContext
config = pageContext.getServletConfig(); // Servlet 配置
session = pageContext.getSession(); // 获取 Session
out = pageContext.getOut();
_jspx_out = out;
这段代码展示了如何设置响应类型、初始化页面上下文、以及获取与 JSP 页面的执行相关的各个对象。每一行代码都在为 JSP 页面的执行做准备,确保请求被正确处理并生成适当的响应。
1.
response.setContentType("text/html");
- 含义:设置响应的内容类型为
text/html
,即告诉浏览器该响应是一个 HTML 页面。这是一个标准的 HTTP 头部,用于指示响应内容的 MIME 类型。在这里,它告诉客户端(如浏览器)返回的数据是 HTML 格式。- 如何使用:通常,JSP 页面在生成响应时会自动设置内容类型,但在某些情况下,也可以手动设置此内容类型。它通常在页面的开头部分调用。
2.
pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
含义:
_jspxFactory.getPageContext()
方法用于创建一个PageContext
对象。PageContext
是 JSP 页面中用于存储页面级别的信息和与请求/响应相关的对象的上下文。它是 JSP 页面的执行环境,提供了对页面范围内的各种对象(如request
、response
、session
、application
等)的访问。
this
: 当前的 JSP 页面实例。request
: HTTP 请求对象,包含来自客户端的请求信息。response
: HTTP 响应对象,用于设置响应信息并返回给客户端。null
: 在此处通常表示errorPage
,如果页面没有错误页处理器,则为null
。true
: 表示是否自动生成错误页面。8192
: 表示缓存的缓冲区大小(字节数)。true
: 是否自动刷新输出流。
getPageContext()
方法会返回一个PageContext
对象,这个对象会为 JSP 页面提供运行时环境。3.
_jspx_page_context = pageContext;
- 含义:将刚才获取的
pageContext
对象赋值给_jspx_page_context
(一个内部变量)。这个操作是为了让后续的代码可以使用这个PageContext
对象来访问 JSP 的上下文信息。4.
application = pageContext.getServletContext();
含义:从
pageContext
中获取ServletContext
对象,ServletContext
是表示整个 Web 应用的上下文。它用于提供关于 Web 应用的信息,并允许各个组件(如 Servlet 和 JSP)共享数据。
- 用途:你可以使用
application
对象在整个 Web 应用中存储数据(通过setAttribute()
),并可以通过getAttribute()
获取共享的数据。5.
config = pageContext.getServletConfig();
含义:从
pageContext
获取ServletConfig
对象,ServletConfig
是每个 Servlet(包括 JSP 页面)在启动时的配置信息。它提供了与当前 Servlet 相关的初始化参数和其他配置项。
- 用途:
config
可以用来获取 JSP 页面或 Servlet 的初始化参数(通过getInitParameter()
)。6.
session = pageContext.getSession();
含义:从
pageContext
获取HttpSession
对象,HttpSession
用于存储与特定用户会话相关的数据。
- 用途:
session
对象允许你存储和检索与当前会话相关的数据(例如,用户登录状态、购物车信息等)。你可以使用session.setAttribute()
来保存会话数据,使用session.getAttribute()
来访问数据。7.
out = pageContext.getOut();
含义:从
pageContext
获取JspWriter
对象,JspWriter
是用于输出 HTML 内容的对象。
- 用途:
out
用于在 JSP 页面中输出动态生成的内容。你可以使用out.print()
或out.println()
方法来输出 HTML 内容或其他文本到客户端浏览器。8.
_jspx_out = out;
- 含义:将
out
对象赋值给_jspx_out
(一个内部变量)。这个操作确保可以在后续的代码中继续使用out
对象进行内容输出。总结
- 这段代码展示了 JSP 页面底层如何设置响应类型、创建和管理页面上下文、以及获取与页面相关的各类对象(如
ServletContext
、HttpSession
、JspWriter
等)。这些对象在 JSP 页面的执行过程中用于与客户端和服务器进行交互。
4. 以上的这些个对象我们可以在JSP页面中直接使用!
比如页面设置
请求
Session 获取与设置
同时 JSP 内可以写 java 代码,为什么可以直接用,是因为第 3 步,输出页面前增加的代码部分已经配置好了,写 java 代码时,放入到 <% %>
中
在 JSP 页面中,内置对象如 response
、application
、config
、session
、out
和 request
可以用于多种不同的用途。以下是每个对象的多种使用示例:
1. response
(HttpServletResponse
)
-
设置内容类型:
<% response.setContentType("text/html"); %>
-
设置响应头:
<% response.setHeader("Cache-Control", "no-cache"); %>
-
重定向到另一个页面:
<% response.sendRedirect("https://www.example.com"); %>
-
发送错误响应:
<% response.sendError(HttpServletResponse.SC_NOT_FOUND, "Page not found"); %>
2. application
(ServletContext
)
-
设置全局属性:
<% application.setAttribute("appVersion", "1.0.0"); %>
-
获取全局属性:
<% String version = (String) application.getAttribute("appVersion"); out.println("App Version: " + version); %>
-
共享数据:
<% application.setAttribute("totalVisitors", 1000); %>
-
获取应用初始化参数:
<% String dbUrl = application.getInitParameter("databaseURL"); out.println("Database URL: " + dbUrl); %>
3. config
(ServletConfig
)
-
获取初始化参数:
<% String param = config.getInitParameter("maxConnections"); out.println("Max Connections: " + param); %>
-
获取当前 Servlet 名称:
<% String servletName = config.getServletName(); out.println("Servlet Name: " + servletName); %>
4. session
(HttpSession
)
-
设置会话属性:
<% session.setAttribute("username", "john_doe"); %>
-
获取会话属性:
<% String user = (String) session.getAttribute("username"); out.println("Welcome, " + user); %>
-
获取会话 ID:
<% String sessionId = session.getId(); out.println("Session ID: " + sessionId); %>
-
检查会话是否存在:
<% if (session.isNew()) { out.println("This is a new session."); } %>
5. out
(JspWriter
)
-
输出文本:
<% out.println("Hello, JSP World!"); %>
-
输出 HTML 元素:
<% out.println("<h1>Welcome to the JSP page!</h1>"); %>
-
输出 JavaScript 代码:
<% out.println("<script>alert('Page Loaded');</script>"); %>
-
格式化输出:
<% out.printf("Current time: %tT", new java.util.Date()); %>
6. request
(HttpServletRequest
)
-
获取请求参数:
<% String name = request.getParameter("name"); out.println("Hello, " + name); %>
-
获取请求头信息:
<% String userAgent = request.getHeader("User-Agent"); out.println("User-Agent: " + userAgent); %>
-
获取客户端 IP 地址:
<% String clientIp = request.getRemoteAddr(); out.println("Client IP: " + clientIp); %>
-
获取请求方法:
<% String method = request.getMethod(); out.println("Request Method: " + method); %>
-
获取请求中的属性:
<% String attribute = (String) request.getAttribute("userRole"); out.println("User Role: " + attribute); %>
假设我们现在新建一个 hello.jsp 内容如下,然后重启 tomcat
在启动 tomcat 还未完成的过程中,找到刚刚 IDEA 中的 tomcat 对应的项目目录下,发现之前的什么都没有了 (本来应该有:C:\Users\15592\AppData\Local\JetBrains\IntelliJIdea2022.1\tomcat\28f4f38f-a9f6-4d87-ad9e-3e377fc1b4d3\work\Catalina\localhost\ROOT\org\apache\jsp)
启动完成后才出现了 index_jsp.java
然后请求 hello.jsp,成功
刚刚的文件夹产生了 hello_jsp.java !
进入到 hello_jsp.java ,发现除了下图这里输出部分不一样,其他都一样
通过上面的流程,我们知道要去访问浏览器才会生成对应 jsp 的 java 代码!
执行流程总结: 程序员通过电脑上网,上网本质是访问服务器,服务器中存在多个 web 容器(tomcat),tomcat 可以存放很多网站,访问到 web 容器,回去判断对应的请求,如果是 JSP,会去找 JSP 的页面,找到 JSP 不能直接使用,首先需要进行转换为 JAVA 文件,这是 web 容器去做得,转换后得到 xxx_jsp.java,然后将 xxx_jsp.java 编译为 class 文件,xxx_jsp.class,xxx_jsp.class 返回给服务器,然后我们得到的就是这个服务器处理完的 xxx_jsp.class ,这个就是 Servlet!访问 JSP 本质还是 Servlet
下面我们在 hello.jsp 中撰写一段 java 代码,<%=name%>
是把 name 取出
然后重启 tomcat
此时文件夹中还没有 hello.jsp
下面请求 hello.jsp,成功取出数据
进入到 hello_jsp.java,发现 java 代码原封不动的放入了进入,并执行了 out.print(name); 输出
在JSP页面中;只要是 JAVA代码就会原封不动的输出;如果是HTML代码,就会被转换为:
out.write("<html>\r\n");
这样的格式,输出到前端!
8.3、JSP基础语法
先新建一个 JSP 项目
注意新项目配置 maven 仓库
pom.xml 中导入依赖,比之前多了一个 jstl-api
还需要一个 standard
<dependencies>
<!-- servelt 依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- jsp 依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<!-- jstl 表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- jstl 依赖的一些 standard 标签 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
配置好 tomcat。
最后将原始创建的 index.jsp 删除掉,再新建一个 index.jsp,为什么这样,因为新建的 index.jsp 多了一行
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
这一行可以解决中文乱码问题,否则后续操作就会产生中文乱码现象!
任何语言都有自己的语法,JAVA 中有。 JSP 作为 java 技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java所有语法都支持!
8.3.1、JSP表达式
在 index.jsp 中添加如下代码
<%--JSP表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>
在 tomcat 启动的状态下,按下 Ctrl + F10,弹出如下框,选择 Redeploy,实际上是 tomcat 的热部署,就不需要重新启动 tomcat 了
访问后就成功打印时间了!
<hr>
:分割线
8.3.2、jsp脚本片段
<%--jsp脚本片段--%>
<%
int sum = 0;
for (int i = 1; i <=100 ; i++) {
sum+=i;
}
out.println("<h1>Sum="+sum+"</h1>");
%>
在 tomcat 启动的状态下,按下 Ctrl + F10,弹出如下框,选择 Redeploy,实际上是 tomcat 的热部署,就不需要重新启动 tomcat 了,然后刷新浏览器
下面这个情况是不被允许的,因为上面那个片段已经产生了 x 这个变量,下面就不能再定义了,但是下面那个片段可以直接使用上面定义好的。
打印输出
<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 2;
out.println(y);
%>
<hr>
在代码嵌入HTML元素
<%--在代码嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h5>Hello,World <%=i%> </h5>
<%
}
%>
下面看一下 通过 编译产生的 xxx_ jsp.java 代码,该有的都有
8.3.3 JSP 声明: <%! %>
定义方法和全局变量
<%!
static {
System.out.println("Loading Servlet!");
}
private int globalVar = 0;
public void kuang(){
System.out.println("进入了方法Kuang!");
}
%>
JSP声明: 会被编译到JSP生成Java的类中!其他的,就会被生成到_jspService
方法中!
在JSP中嵌入Java代码即可!
除了上述通过 <%=%>
取值外,还可以通过 ${}
的方式取值
<%%> 片段
<%=%> 表达式输出值
<%!%> 定义全局方法变量
<%–注释–%> 注释
JSP 中同样可以用 html 的注释,我们来看下区别
<%--我是 JSP 的注释--%>
<!-- 我是 html 的注释-->
代码中写入
热部署 tomcat,然后刷新页面,注释没有被显示出来
右击页面,查看页面源代码,能够看到 html 的注释,而看不到 jsp 的注释
JSP的注释,不会在客户端显示,HTML就会!
下面新建 jsp2,输入一个除 0 错误,
热部署 tomcat,并访问 jsp2.jsp,报错异常
下面有这样一个需求:当发生如下错误时,不弹出如上的页面,而是弹出我们指定的页面
额外tips:JSP 也支持像 java import 那样导包,比如如下
新建文件夹 error,新建 500.jsp,并放入如下内容:
然后在 jsp2.jsp 中添加错误跳转操作:<%@ page errorPage="error/500.jsp" %>
热部署 tomcat,请求 jsp2.jsp,跳转到了我们自定义的界面
下面不显示字,跳转后显示图片,新建 img,随便放入一张图,更改 jsp2.jsp 的内容:<img src="../img/500.jpg" alt="500">
热部署 tomcat,请求 jsp2.jsp,跳转到了我们定义好了图片的界面。注意如果代码没有错是不会跳的
上面是 500 错误,可能还会有 404 错误,erro 文件夹中增加 404.jsp,如下内容
然后配置 web.xml,配置信息表示出那种错误,对应去找到对应的 jsp
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
热部署 tomcat,请求 jsp2.jsp,正常显示之前的信息,然后输入一个肯定不存在的页面,回车
进入了 404 错误页面
错误跳转:
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
与
<%@ page errorPage="error/500.jsp" %>
这两种方式都用于处理 JSP 页面中的错误,但它们在应用范围和使用场景上有所不同。下面是两者的对比和详细解释:
1. <error-page>
配置(在 web.xml
中)
这是在 web.xml
配置文件中为 HTTP 错误代码设置错误页面的方式。它是 Web 应用级别的配置,适用于整个应用中的所有请求,而不仅仅是某个特定的 JSP 页面。
示例:
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
解释:
<error-page>
配置指示当服务器发生特定的 HTTP 错误时(如 404 或 500),应该跳转到哪个错误页面。<error-code>
:指定捕获的错误代码(如 404 或 500)。<location>
:指定错误页面的 URL,当发生指定的错误时,用户会被重定向到该页面。
使用场景:
- 全局配置:它适用于整个 Web 应用。当某个特定错误(如 404 或 500)发生时,无论是来自哪个 Servlet 或 JSP 页面,都会跳转到指定的错误页面。
- 适用 HTTP 错误:此配置捕获的是 HTTP 错误(如 404、500、403 等)并将其重定向到自定义页面。
示例:
- 当用户访问不存在的页面时(如
/nonexistent.jsp
),Web 容器会返回 404 错误并重定向到/error/404.jsp
页面。 - 当服务器发生内部错误时(如空指针异常),Web 容器会返回 500 错误并重定向到
/error/500.jsp
页面。
2. <%@ page errorPage="error/500.jsp" %>
配置(JSP 指令)
这是在 JSP 页面中指定错误处理页面的方式。它用于在当前 JSP 页面发生异常时,转向指定的错误页面。
示例:
<%@ page errorPage="error/500.jsp" %>
解释:
errorPage
指令用于指定当当前 JSP 页面抛出异常时,转向哪个错误页面。- 在当前页面发生未捕获的异常时,JSP 容器会自动将用户重定向到指定的错误页面。
使用场景:
- 局部配置:它仅适用于当前的 JSP 页面。只有在该页面内部发生异常时,才会跳转到指定的错误页面。
- 适用 JSP 内部错误:它只捕获 JSP 页面内抛出的异常,而不会捕获 HTTP 错误或其他类型的错误。
示例:
- 如果在
index.jsp
页面中发生了未处理的异常(如NullPointerException
),并且该页面配置了errorPage
指令,用户会被重定向到error/500.jsp
页面。
3. 对比:<error-page>
配置 vs <%@ page errorPage="..." %>
指令
特性 | <error-page> 配置 (web.xml ) | <%@ page errorPage="..." %> 指令 |
---|---|---|
作用范围 | Web 应用级别,全局配置 | 单个 JSP 页面 |
捕获类型 | HTTP 错误(如 404、500 等) | JSP 页面内抛出的异常(如 NullPointerException 等) |
配置位置 | web.xml 配置文件 | JSP 页面顶部的指令 |
错误处理 | 处理所有请求中的 HTTP 错误 | 仅处理当前 JSP 页面中的异常 |
适用场景 | 用于 HTTP 错误(如 404、500) | 用于 JSP 页面内的异常处理(如编程错误、空指针等) |
错误页面 | 可以为不同的错误代码配置不同的错误页面 | 仅为该 JSP 页面配置一个错误页面 |
4. 总结
-
<error-page>
配置 是全局配置,适用于整个 Web 应用,捕获 HTTP 错误(如 404、500)并重定向到指定的错误页面。它位于web.xml
文件中,并且不依赖于单个 JSP 页面。 -
<%@ page errorPage="..." %>
指令 是局部配置,仅在当前 JSP 页面中适用。它捕获该页面内的异常,并跳转到指定的错误页面,通常用于处理编程错误或其他运行时异常。
因此:
- 如果你需要处理 HTTP 错误(例如页面未找到、服务器内部错误等),可以使用
web.xml
中的<error-page>
配置。 - 如果你只需要处理单个 JSP 页面内的异常,应该使用
<%@ page errorPage="..." %>
指令。
8.4、JSP指令(了解即可,重点是上面基础语法部分)
<%@page args.... %>
<%@include file=""%>
<%--@include会将两个页面合二为一--%>
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@include file="common/footer.jsp"%>
<hr>
<%--jSP标签
jsp:include:拼接页面,本质还是三个
--%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
<%@include file=""%>
,包含其他的 jsp 文件进来,比如在 common 文件夹下定义 header.jsp 和 footer.jsp,然后最外层文件夹创建一个 jsp3.jsp 为主页面,并调用 header.jsp 和 footer.jsp
jsp3.jsp 页面内容如下
热部署 tomcat,请求 jsp3.jsp
如何直接访问 header 页面,通过项目下完整的目录:localhost:8080/common/header.jsp
下面使用 jsp 标签
<%--jSP标签
jsp:include:拼接页面,本质还是三个
--%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
同样达到了上面的效果
下面看一下两者的区别,进入到 jsp3_jsp.java 的代码当中。
先看如下代码情况:
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>
相当于拼接页面,本质还是三个(推荐使用的方式)
下面这种情况
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@include file="common/footer.jsp"%>
将其他两个 jsp 中的内容一起放入到了 jsp3.jsp 当中!,使其合二为一了
合二为一会出现一个问题,比如在 header.jsp 中我定义了一个 int i,然后在主页面 jsp3.jsp 中,我先引入 header.jsp ,然后又定义了一个 int i,请求的时候就会报 500 的错!
main 下面就只放 java 和 resources 文件夹,不要存放其他任何文件夹
8.5、9 大内置对象
- PageContext 代表一个页面,存东西
- Request 存东西
- Response
- Session 存东西
- Application 【SerlvetContext】 存东西
- config 【SerlvetConfig】 配置
- out 输出
- page ,不用了解
- exception
新建一个 pageContextDemo01.jsp,放入以下内容,实现存东西
脚本片段 <% %>
中的代码,会原封不动的生成到 JSP.java 中,这里面的代码必须保证 java 语法的正确性!即不能出现 JSP 类型的注释,如:<%--取出保存的值--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--内置对象--%>
<%--从底层到高层作用于:page -> request -> session -> application,application--%>
<%
pageContext.setAttribute("name1","future1号"); //保存的数据只在一个页面中有效
request.setAttribute("name2","future2号"); //保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","future3号"); //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","future4号"); //保存的数据只在服务器中有效,从打开服务器到关闭服务器
%>
<%--取出保存的值--%>
<%
String name1 = (String) pageContext.getAttribute("name1");
String name2 = (String) request.getAttribute("name2");
String name3 = (String) session.getAttribute("name3");
String name4 = (String) application.getAttribute("name4");
String name5 = (String) application.getAttribute("name5"); // 不存在
%>
<%--使用 EL 表达式输出--%>
<h1>取出的值为:</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1><%=name4%></h1>
<h1><%=name5%></h1>
</body>
</html>
热部署 tomcat,请求 pageContextDemo01.jsp,不存在的值打印出了 null(因为使用 <%=name5%>
取值),如果使用 ${name5}
,会自动过滤,不会打印出任何东西
现有三个 page,三个 Servlet 请求:s1, s2, s3,三个 page 是三个不一样的浏览器,但是现在想存东西。下面有几种方法,首先是 request 作用域:比如第一个 page 请求 s1,携带了一个 name 数据,如果 s1 不转发,这个数据就不会存在了,但是可以通过转发,比如 s1 转发到 s2,s2 就拿到了这个数据
可以在服务器中存数据(session),三个浏览器 page,会产生三个 sesison,每个浏览器对应一个 session,但是无论是在 session 几存东西,所有 page 都可以拿到 session 1, 2, 3 的数据,因为数据是在服务器上的。
从底层到高层作用于:page -> request -> session -> application,application 都没找到,就不存在了,JVM 有一个双亲委派机制,也是逐渐找包的过程
pageContextDemo01.jsp 代码以及内容如下
<%--
Created by IntelliJ IDEA.
User: 15592
Date: 2024/7/28
Time: 20:37
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--内置对象--%>
<%
pageContext.setAttribute("name1","future1号"); //保存的数据只在一个页面中有效
request.setAttribute("name2","future2号"); //保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3","future3号"); //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4","future4号"); //保存的数据只在服务器中有效,从打开服务器到关闭服务器
%>
<%--取出保存的值--%>
<%
String name1 = (String) pageContext.getAttribute("name1");
String name2 = (String) request.getAttribute("name2");
String name3 = (String) session.getAttribute("name3");
String name4 = (String) application.getAttribute("name4");
String name5 = (String) application.getAttribute("name5"); // 不存在
%>
<%--使用 EL 表达式输出--%>
<h1>取出的值为:</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1><%=name4%></h1>
<h1><%=name5%></h1>
</body>
</html>
下面新建 pageDemo02.jsp,内容如下:(相当于只保留了 pageContextDemo01.jsp 中取值的部分)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--取出保存的值--%>
<%
String name1 = (String) pageContext.getAttribute("name1");
String name2 = (String) request.getAttribute("name2");
String name3 = (String) session.getAttribute("name3");
String name4 = (String) application.getAttribute("name4");
String name5 = (String) application.getAttribute("name5"); // 不存在
%>
<%--使用 EL 表达式输出--%>
<h1>取出的值为:</h1>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1><%=name4%></h1>
<h1><%=name5%></h1>
</body>
</html>
上述两个 pageDemo02 ,pageContextDemo01 是完全不同的页面,热部署 tomcat 后,先请求 pageContextDemo01 再请求 pageDemo02
发现只能取出 3 号,4 号,1, 2 号没有了,因为 3 4 号是用 session 和 application,1,2 号是使用 pageContext 和 request。
新建一个 pageDemo03.jsp ,找到 pageContext.setAttribute 的实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--
public static final int PAGE_SCOPE = 1;
public static final int REQUEST_SCOPE = 2;
public static final int SESSION_SCOPE = 3;
public static final int APPLICATION_SCOPE = 4;
// scope 作用域
public void setAttribute(String name, Object attribute, int scope) {
switch (scope) {
case 1:
this.mPage.put(name, attribute);
break;
case 2:
this.mRequest.put(name, attribute);
break;
case 3:
this.mSession.put(name, attribute);
break;
case 4:
this.mApp.put(name, attribute);
break;
default:
throw new IllegalArgumentException("Bad scope " + scope);
}
}
--%>
<%
pageContext.setAttribute("hello1", "hello", PageContext.SESSION_SCOPE);
session.setAttribute("hello1", "hello");
%>
</body>
</html>
PageContext 类下有如下的 scope,用于设置作用域,默认是在当前页面有效,pageContext.setAttribute(“hello1”, “hello”, PageContext.SESSION_SCOPE); 等价于 session.setAttribute(“hello1”, “hello”); 提高到了 session 作用域下
public static final int PAGE_SCOPE = 1;
public static final int REQUEST_SCOPE = 2;
public static final int SESSION_SCOPE = 3;
public static final int APPLICATION_SCOPE = 4;
新建 pageContextDemo02.jsp,内容如下,实现跳转,下面两种跳转方式等价
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
pageContext.forward("/index.jsp"); // 页面端跳转
// request.getRequestDispatcher("/index.jsp").forward(request,response); // servlet 后台跳转
%>
</body>
</html>
成功跳转
request:客户端向服务器发送请求,产生的数据,用户看完就没用了,比如:新闻,用户看完没用的!
session:客户端向服务器发送请求,产生的数据,用户用完一会还有用,比如:购物车;
application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如:聊天数据;
pageContext.forward("/index.jsp");
这种类型实际上就是实现了请求转发,这样 request 携带的内容可以在转发的页面中读取到
8.6、JSP标签、JSTL标签、EL表达式
EL表达式: ${ }
- 获取数据
- 执行运算
- 获取web开发的常用对象
使用需要导入依赖
<!-- JSTL表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
JSP标签部分使用:
新建 jsptag.jsp ,内容如下:(通过 JSP 标签,跳转页面到)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<jsp:forward page="/jsptag2.jsp"></jsp:forward>
</body>
</html>
新建 jsptag2.jsp ,内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1> 这是一个 JSPtag2 页面 </h1>
</body>
</html>
热部署 tomcat,请求 jsptag.jsp,跳转成功
重写 jsptag.jsp 如下:(使其转发时携带参数)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<jsp:forward page="/jsptag2.jsp">
<jsp:param name="name" value="future"></jsp:param>
<jsp:param name="age" value="12"></jsp:param>
</jsp:forward>
</body>
</html>
测试 jsptag2.jsp 取出参数
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
名字: <%=request.getParameter("name")%>
年龄: <%=request.getParameter("age")%>
</body>
</html>
热部署 tomcat,请求 jsptag,获取成功
前面还讲了一个 <jsp:include>
标签,这里不再赘述
JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义许多标签,可以供我们使用,标签的功能和Java代码一样!
格式化标签(基本不用)
SQL标签(基本不用)
XML 标签(基本不用)
核心标签 (掌握部分)
上述的代码不需要记忆,查找即可,查找地址: https://www.runoob.com/jsp/jsp-jstl.html
JSTL 可以不使用,写 java 代码一样的可以!
JSTL 标签库使用步骤
- 引入对应的 taglib
- 使用其中的方法
- 在Tomcat 也需要引入 jstl 的包,否则会报错:JSTL解析错误
c:if
if 测试,新建一个 coreif.jsp,内容如下:<form action="coreif.jsp" method="get">
表示自己请求自己,然后 get 获取自己的表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入 JSTL 核心标签库,我们才能使用 JSTL 标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h4>if测试</h4>
<hr>
<form action="coreif.jsp" method="get">
<%--
EL表达式获取表单中的数据:${param.参数名}
--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
</body>
</html>
由于 tomcat 中没有 jstl 和 standard 的包,要手动粘贴到 tomcat 的 lib 文件夹下
加入包后重新启动 tomcat,请求 coreif.jsp
继续用 coreif.jsp 下执行 if 条件命令,如果用户名输入成功则返回 true,否则返回 false
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入 JSTL 核心标签库,我们才能使用 JSTL 标签--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h4>if测试</h4>
<hr>
<%----%>
<form action="coreif.jsp" method="get">
<%--
EL表达式获取表单中的数据
${param.参数名}
--%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断如果提交的用户名是管理员,则登录成功--%>
<c:if test="${param.username=='admin'}" var="isAdmin"> <%-- 这个过程会获取到 isAdmin 为 true or false --%>
<c:out value="管理员欢迎您!"/>
</c:if>
<%--自闭合标签--%>
<c:out value="${isAdmin}"/> <%-- 输出上述的登录状态 --%>
</body>
</html>
c:choose、c:when
新建一个 corewhen.jsp ,内容如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--定义一个变量score,值为85--%>
<c:set var="score" value="55"/>
<c:choose>
<c:when test="${score>=90}">
你的成绩为优秀
</c:when>
<c:when test="${score>=80}">
你的成绩为一般
</c:when>
<c:when test="${score>=70}">
你的成绩为良好
</c:when>
<c:when test="${score<=60}">
你的成绩为不及格
</c:when>
</c:choose>
</body>
</html>
不知道啥情况
c:forEach
<%
ArrayList<String> people = new ArrayList<>();
people.add(0,"张三");
people.add(1,"李四");
people.add(2,"王五");
people.add(3,"赵六");
people.add(4,"田六");
request.setAttribute("list",people);
%>
<%--
var , 每一次遍历出来的变量
items, 要遍历的对象
begin, 哪里开始
end, 到哪里
step, 步长
--%>
<c:forEach var="people" items="${list}">
<c:out value="${people}"/> <br>
</c:forEach>
<hr>
<c:forEach var="people" items="${list}" begin="1" end="3" step="1" >
<c:out value="${people}"/> <br>
</c:forEach>