Jsp
Java Server Pages:java服务端页面,同 Servlet 一样用于动态Web技术
写Jsp就像写HTML,可以嵌入Java代码以提供动态服务
Jsp本质依然是Servlet,Tomcat等Servlet容器会在这些jsp文件首次被访问时自动转换为java文件(借助Jasper)并编译为class文件
访问 jsp 页面时注意添加 .jsp 后缀名
模块创建
新建模块
参见前文
载入依赖
<!-- servlet 依赖库 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</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</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
新建Java目录
参见前文
Tomcat配置
参见前文
Jsp语法及源码解析
demo01.jsp
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>JSP</h1>
<!-- 这是 HTML 注释,会出现在 HTML 页面 -->
<%-- 这是 JSP 注释,和 HTML 注释不同,不会出现在 HTML 页面中 --%>
<%-- jsp 表达式 --%>
<%= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) %>
<%-- 等价于 --%>
<%-- <% --%>
<%-- String date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()); --%>
<%-- out.write(date); --%>
<%-- %> --%>
<%-- jsp 脚本片段1 --%>
<%
int sum = 0;
for (int i = 1; i <= 5; i++) {
out.print("<p>" + "当前循环数值为: " + i + "</p>");
sum += i;
}
out.print("<p>" + "求和结果为: " + sum + "</p>");
%>
<%-- jsp 脚本片段2, 嵌套 HTML --%>
<% int n = 6; %>
<% if (n > 5) { %>
<p>数字大于5</p>
<% } else { %>
<p>数字小于等于5</p>
<% } %>
<%-- jsp 声明, 在 jsp 编译后会作为 Servlet 类的静态内部块、成员属性、成员方法 --%>
<%!
static {
System.out.println("Loading Servlet!");
}
private int globalvar = 10;
public void meth1() {
System.out.println("这是自定义方法");
}
%>
<%-- 直接使用 --%>
<%= globalvar %>
<%-- 直接使用 --%>
<%
meth1();
%>
</body>
</html>
demo01_jsp.java
该文件取自idea_cache\system\tomcat\randomdirname\work\Catalina\localhost\projectname_war\org\apache\jsp目录
idea_cache是Idea缓存所在的路径,视idea版本和个人配置而定
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.Date;
import java.text.SimpleDateFormat;
// HttpJspBase 继承自 HttpServlet
public final class demo01_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
// jsp 声明 编译后在这里
static {
System.out.println("Loading Servlet!");
}
private int globalvar = 10;
public void meth1() {
System.out.println("这是自定义方法");
}
// 省略
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
// 省略
try {
// jsp 编译后会默认设置响应的内容类型为该值
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
// 页面上下文对象, jsp 特有对象
_jspx_page_context = pageContext;
// 本质是容器级上下文对象
application = pageContext.getServletContext();
// 本质是Servlet级配置对象
config = pageContext.getServletConfig();
// 这里调用了 getSession(), 意味着当访问该页面时如果不存在 session 会自动创建
session = pageContext.getSession();
// 本质是 getWriter() 获得的 PrintWriter 对象
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>Title</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write(" <h1>JSP</h1>\r\n");
// html 注释 编译后在这里
out.write(" <!-- 这是 HTML 注释,会出现在 HTML 页面 -->\r\n");
// jsp 注释 编译后被去除
out.write(" ");
out.write("\r\n");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
// jsp 表达式 编译后在这里
out.print( new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) );
out.write("\r\n");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
// jsp 脚本片段1 编译后在这里
int sum = 0;
for (int i = 1; i <= 5; i++) {
out.print("<p>" + "当前循环数值为: " + i + "</p>");
sum += i;
}
out.print("<p>" + "求和结果为: " + sum + "</p>");
out.write("\r\n");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
// jsp 脚本片段2, 嵌套 HTML 编译后在这里
int n = 6;
out.write("\r\n");
out.write(" ");
if (n > 5) {
out.write("\r\n");
out.write(" <p>数字大于5</p>\r\n");
out.write(" ");
} else {
out.write("\r\n");
out.write(" <p>数字小于等于5</p>\r\n");
out.write(" ");
}
out.write("\r\n");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
// 通过 jsp 表达式 使用 jsp 声明 的变量
out.print( globalvar );
out.write("\r\n");
out.write(" ");
out.write("\r\n");
out.write(" ");
// 通过 jsp 代码片段 使用 jsp 声明 的方法
meth1();
out.write("\r\n");
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
// 省略
} finally {
// 省略
}
}
}
Jsp指令
概览
page | <%@ page ... %> |
控制整个 JSP 页面的行为,比如编码方式、内容类型、是否启用 session 等。 |
include | <%@ include file="..." %> |
在 JSP 编译阶段静态包含另一个文件的内容(如 HTML、JSP 片段)。 |
taglib | <%@ taglib uri="..." prefix="..." %> |
声明并引入一个自定义标签库或标准标签库(如 JSTL)。 |
<%@ page ...args %>
args
language |
java |
指定 JSP 页面使用的脚本语言(目前只支持 Java) |
extends |
- | 指定生成的 Servlet 所继承的父类(一般不建议修改) |
import |
- | 导入 Java 包或类,多个用逗号分隔,如:import="java.util.*, java.sql.* |
session |
true |
是否允许使用 session 对象,设为 false 表示禁用 Session |
isThreadSafe |
true |
控制生成的 Servlet 是否实现 SingleThreadModel 接口,false 时容器会确保线程安全处理(已过时) |
errorPage |
- | 指定当前页面出错后跳转的错误处理页面,例如:errorPage="error.jsp" |
isErrorPage |
false |
表示该页面是否是一个错误处理页面(可访问 exception 内置对象) |
contentType |
text/html |
设置响应的 MIME 类型和字符编码,常用:contentType="text/html;charset=UTF-8" |
pageEncoding |
服务器默认编码(通常是 ISO-8859-1) | 设置当前 JSP 文件的字符编码(推荐设置为 UTF-8) |
isELIgnored |
false |
是否忽略 EL 表达式(${...} ,设为 true 后 EL 不会被解析 |
buffer |
8kb |
设置 JSP 输出流(out )的缓存大小,如:buffer="16kb" |
autoFlush |
true |
缓冲区满时是否自动刷新输出,若为 false ,缓冲区满时抛出异常 |
trimDirectiveWhitespaces |
false |
是否移除 JSP 标签之间的空白字符(优化 HTML 输出) |
demo02.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 指定当前页面出错后显示的错误页面 --%>
<%@ page errorPage="error/500.jsp" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 例如出现了0除错误 --%>
<%
int x = 1 / 0;
%>
</body>
</html>
500.jsp
在webapp/error目录下创建
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>自定义的错误页面500</h1>
</body>
</html>
<%@ include file="path/to/your_jsp.jsp" %>
静态包含,不推荐使用
demo03.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%@ include file="commons/header.jsp" %>
<%
int x = 20;
%>
<h1>DEMO03</h1>
<%-- 载入公共的脚本HTML片段 --%>
<%-- 编译为Servlet时会直接把该片段编译进当前页面 --%>
<%-- 由于当前页面和载入的 footer 片段页面均定义了x,会产生错误(变量重复声明定义) --%>
<%--<%@ include file="commons/footer.jsp"%>--%>
<%-- 解决办法是使用jsp标签(推荐用法),这样不会直接编译进当前页面,而是作为外部引用 --%>
<jsp:include page="commons/footer.jsp" />
</body>
</html>
header.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>这是HTML头部片段</h1>
footer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<h1>这是脚部HTML片段</h1>
<%
int x = 10;
%>
<%@ taglib ...args %>
用于引用外部标签库,例如:jstl标准标签库,见后文
内置对象
九大对象
pageContext |
javax.servlet.jsp.PageContext |
提供对页面所有其他内置对象的访问,支持属性管理(page/request/session/application)和包含/转发操作 |
request |
javax.servlet.http.HttpServletRequest |
表示客户端的 HTTP 请求,用于获取请求参数、请求头、设置/获取属性等 |
response |
javax.servlet.http.HttpServletResponse |
用于向客户端发送响应数据,如设置状态码、响应头、重定向等 |
session |
javax.servlet.http.HttpSession |
用于在多个请求之间保存用户信息,比如登录状态、用户偏好等 |
application |
javax.servlet.ServletContext |
表示整个 Web 应用上下文,用于共享全局数据、获取配置参数等 |
config |
javax.servlet.ServletConfig |
表示当前 JSP 页面的配置信息,用于获取初始化参数 |
out |
javax.servlet.jsp.JspWriter |
用于向浏览器输出内容(相当于 PrintWriter ),常用于 <%= %> 输出 |
page |
java.lang.Object (实际是 this ) |
表示当前 JSP 页面本身(即生成的 Servlet 实例),类似 Java 中的 this |
exception |
java.lang.Throwable |
表示运行时异常或错误,仅在设置了 isErrorPage="true" 的页面中可用 |
四大对象作用域
pageContext |
页面作用域 | 当前页面创建到处理完成 | 仅当前页面有效 | 存储页面级别的临时数据,如页面内共享变量 | 数据只在当前页面有效,离开即失效 |
request |
请求作用域 | 请求开始到响应结束 | 同一个请求链(包括转发) | 在多个 Servlet/JSP 之间传递数据 | 支持请求转发时共享,重定向后数据丢失 |
session |
会话作用域 | 用户首次访问到会话超时或销毁 | 整个用户会话期间 | 存储用户登录状态、购物车等需要跨请求保持的数据 | 可跨多个页面和请求,适合跟踪用户行为 |
application |
应用作用域 | Web应用启动到停止或重新部署 | 整个Web应用的所有用户 | 存放全局配置、公共资源(如数据库连接池、全局计数器等) | 所有用户共享,修改需谨慎,避免并发问题 |
demo04
<%@ page import="java.io.IOException" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 放在html标签开始之前,请求转发 --%>
<%--<% pageContext.forward("index.jsp"); %>--%>
<%-- 等价于 --%>
<%--<% request.getRequestDispatcher("hello.jsp").forward(request, response); %>--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 动态包含 --%>
<%--<% pageContext.include("commons/header.jsp"); %>--%>
<%
pageContext.setAttribute("name1", "ssydxp_1");
request.setAttribute("name1", "ssydxr_1");
request.setAttribute("name2", "ssydxr_2");
session.setAttribute("name1", "ssydxs_1");
session.setAttribute("name2", "ssydxs_2");
session.setAttribute("name3", "ssydxs_3");
application.setAttribute("name1", "ssydxa_1");
application.setAttribute("name2", "ssydxa_2");
application.setAttribute("name3", "ssydxa_3");
application.setAttribute("name4", "ssydxa_4");
%>
<%-- 按照 pageContext > request > session > application 顺序依次查找指定属性名,如果最终不存在则返回 null --%>
<%-- 此过程就类似类加载的双亲委派机制 --%>
<h1><%= pageContext.findAttribute("name1")%></h1>
<h1><%= pageContext.findAttribute("name2")%></h1>
<h1><%= pageContext.findAttribute("name3")%></h1>
<h1><%= pageContext.findAttribute("name4")%></h1>
<h1><%= pageContext.findAttribute("name5")%></h1>
<%-- 同上, 但查找不到返回空(底层就是调用了 pageContext.findAttribute, 但对 null 进行了处理)--%>
<%-- 即 ${} (EL表达式) 取的是四大对象内的属性而不是变量 --%>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1>
</body>
</html>
特性 ${name}
<%= pageContext.findAttribute("name") %>
查找机制 完全相同 完全相同 返回 null 时的行为 不输出任何内容(视觉上“消失”) 输出字符串 "null"
HTML 转义 自动进行 不自动进行 推荐使用场景 JSP 页面展示数据 需要 Java 控制逻辑时 可读性 更好 较差 是否适合 MVC 推荐 不推荐用于视图展示
拓展
双亲委派机制:一个类加载器收到加载请求时优先委托给其父类加载器(此过程递归向上到顶级加载器),如果父类加载器无法完成加载请求(即其搜索范围内没有所需的类)则通知子加载器(递归向下到发出委托的子加载器为止)由子加载器进行加载
此机制有效避免了同名类导致的问题,即自己定义的类覆盖系统类
jsp标签
标签一览表
<jsp:include> |
包含另一个页面的内容到当前页面 | 动态包含其他 JSP 页面或资源,适用于需要在运行时合并多个页面的情况 |
<jsp:forward> |
将请求转发到另一个页面 | 当前页面处理完后将请求转发给另一个页面,常用于页面导航 |
<jsp:param> |
作为子元素传递参数给 <jsp:include> 或 <jsp:forward> |
需要向被包含或转发的页面传递参数时使用 |
<jsp:useBean> |
在指定的作用域中查找或创建一个 JavaBean 实例 | 使用 JavaBean 组件管理数据状态 |
<jsp:setProperty> |
设置 JavaBean 的属性值 | 初始化或更新 JavaBean 的属性 |
<jsp:getProperty> |
获取 JavaBean 的属性值并输出 | 显示 JavaBean 中的数据 |
<jsp:text> |
输出纯文本内容 | 当你需要确保某些文本不被解释为HTML或XML时 |
<jsp:element> |
动态定义XML元素 | 在JSP页面中动态生成XML内容 |
<jsp:body> |
定义自定义标签体的内容 | 自定义标签开发时定义标签体 |
<jsp:attribute> |
定义自定义标签库中的标签的属性 | 自定义标签开发时定义标签属性 |
<jsp:plugin> |
生成客户端浏览器中使用的插件(如 Java Applet)所需的 HTML 标记 | 已很少使用,主要用于早期支持嵌入式Java应用程序 |
demo05
<%@ page import="xyz.ssydx.entity.People" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--<jsp:forward page="hello.jsp" />--%>
<%--<jsp:forward page="hello.jsp">--%>
<%-- <jsp:param name="name" value="value"/>--%>
<%--</jsp:forward>--%>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--<jsp:include page="commons/footer.jsp">--%>
<%-- <jsp:param name="name" value="value"/>--%>
<%--</jsp:include>--%>
<%--<%--%>
<%-- People people = new People();--%>
<%-- people.setName("zhangsan");--%>
<%-- people.setAge(24);--%>
<%-- pageContext.setAttribute("people", people);--%>
<%--%>--%>
<%--${people.name}--%>
<%--${people.age}--%>
<%-- 等价 --%>
<jsp:useBean id="people" class="xyz.ssydx.entity.People" scope="page" />
<jsp:setProperty name="people" property="name" value="zhangsan" />
<jsp:setProperty name="people" property="age" value="24" />
<jsp:getProperty name="people" property="name"/>
<jsp:getProperty name="people" property="age"/>
</body>
</html>
People.java
package xyz.ssydx.entity;
public class People {
private Integer id;
private String name;
private Integer age;
public People(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public People() {}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
EL表达式
隐式对象
pageScope | page 作用域 |
requestScope | request 作用域 |
sessionScope | session 作用域 |
applicationScope | application 作用域 |
param | Request 对象的参数,字符串 |
paramValues | Request对象的参数,字符串集合 |
header | HTTP 信息头,字符串 |
headerValues | HTTP 信息头,字符串集合 |
initParam | 上下文初始化参数 |
cookie | Cookie值 |
pageContext | 当前页面的pageContext |
demo06
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page import="xyz.ssydx.entity.People" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 引入标准函数标签库 --%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
List<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
request.setAttribute("list", list);
String[] strings = {"zs", "ls", "ww"};
request.setAttribute("strings", strings);
People people = new People(1, "ssydx", 35);
request.setAttribute("people", people);
session.setAttribute("name", "ssydx");
session.setAttribute("age", 25);
%>
<%-- EL表达式应该专注于获取数据而不是执行写入操作(很多涉及写入的操作(put方法, set方法等)都是非法的) --%>
<h1>支持大多数的Java运算符</h1>
<p>计算3+5:${3+5}</p>
<p>判断3!=5:${3 != 5}</p>
<p>判断列表是否为空:${empty list}</p>
<p>获取列表第一个值:${list.get(1)}</p>
<p>获取字符串数组第二个元素:${strings[2]}</p>
<p>获取年龄:${people.age}</p>
<p>获取姓名的长度:${fn:length(people.name)}</p>
<h1>登录表单</h1>
<%-- 提交到当前页 --%>
<form action="demo06.jsp" method="get">
<input type="text" name="username" value="user" /> <br />
<input type="checkbox" name="hobbies" value="小说" checked>小说
<input type="checkbox" name="hobbies" value="电影">电影
<input type="checkbox" name="hobbies" value="manga" checked>漫画
<input type="checkbox" name="hobbies" value="music">音乐 <br />
<input type="submit" value="确定">
</form>
<%-- 请求中的请求参数 --%>
<p>用户姓名:${param.username}</p>
<p>用户爱好:${paramValues.hobbies[0]}</p>
<%-- 请求中的cookie --%>
<p>获取JSESSIONID的值:${cookie.get("JSESSIONID").value}</p>
<%-- 作用域对象, 类同四大对象作用域 --%>
<p>获取会话作用域的属性name的值:${sessionScope["name"]}</p>
<p>获取会话作用域的属性age的值:${sessionScope.age}</p>
<%-- tomcat9可以生效, 但这是非标准写法, 不推荐 --%>
${pageContext.include("commons/footer.jsp")}
</body>
</html>
jstl标签
核心标签
核心标签一览表
<c:out> |
用于在 JSP 中显示数据,类似于 <%= ... %> |
<c:if> |
条件判断标签,与一般程序中使用的 if 类似 |
<c:choose> |
作为 <c:when> 和 <c:otherwise> 的父标签,用于组合多条件判断 |
<c:when> |
<c:choose> 的子标签,用于判断某个条件是否成立 |
<c:otherwise> |
<c:choose> 的子标签,当所有 <c:when> 都为 false 时执行 |
<c:forEach> |
基础迭代标签,支持多种集合类型(如 List、Map、数组等) |
<c:set> |
用于保存数据(设置变量) |
<c:remove> |
用于删除某个作用域中的变量 |
<c:catch> |
用来处理产生错误的异常状况,并且将错误信息储存起来 |
<c:import> |
检索一个绝对或相对 URL,并将其内容暴露给当前页面 |
<c:forTokens> |
根据指定的分隔符分割字符串并进行迭代输出 |
<c:param> |
用于给包含(include)或重定向(redirect)的页面传递参数 |
<c:redirect> |
将用户请求重定向到一个新的 URL |
<c:url> |
创建一个带有可选查询参数的 URL(可用于防止 URL 重写问题) |
demo07.jsp
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 引入标准核心标签库 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录表单</h1>
<%-- 提交到当前页 --%>
<form action="demo07.jsp" method="get">
<input type="text" name="username" value="user" /> <br />
<input type="number" name="score" value="5" max="10" min="0" /> <br />
<input type="submit" value="确定">
</form>
<h1>条件语句if</h1>
<%-- var存储判断结果 --%>
<c:if test="${param.username == 'admin'}" var="isAdmin">
<p><c:out value="欢迎登录" /></p>
</c:if>
<p>是否为admin? <c:out value="${isAdmin}" /></p>
<h1>条件语句choose</h1>
<p>
<c:choose>
<c:when test="${param.score >= 5}">
好
</c:when>
<c:when test="${param.score >= 3}">
中
</c:when>
<c:otherwise>
坏
</c:otherwise>
</c:choose>
</p>
<h1>循环语句forEach1</h1>
<c:forEach var="i" begin="1" end="5" step="1">
<p><c:out value="${i}" /></p>
</c:forEach>
<h1>循环语句forEach2</h1>
<%
List<String> list = new ArrayList<>();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
request.setAttribute("list", list);
%>
<c:forEach var="str" items="${list}">
<p><c:out value="${str}" /></p>
</c:forEach>
</body>
</html>
web.xml其他配置
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
#java##javaweb#JavaWeb 文章被收录于专栏
此专栏由于更新观看不便,不会保持及时更新,最新更新见计算机合集专栏https://www.nowcoder.com/creation/manager/columnDetail/04yp33