JSP 全称 Java Server Pages,是一种动态网页开发技术。JSP是一种 Java Servlet,通过结合 HTML、XHTML、XML以及嵌入 JSP 操作命令编写 JSP,主要实现 Java Wed 应用程序的用户界面显示。
1 工作原理
前言:在Tomcat中访问任何资源实际上都是在访问 Servlet。JSP实质上是一个 Servlet。Tomcat 服务器中的 web.xml 文件中配置了以 JSP 为后缀的 url-pattern ,服务器接收到 JSP 类型的文件,在第一次访问时,会通过 JspServlet 转化为一个 类文件,并编译成 class 文件。
2 生命周期
JSP的生命周期就是从创建到销毁的整个过程,类似 Servlet 生命周期,区别在于 JSP 生命周期还包括将 JSP 文件编译成 servelt;
-
编译阶段
servlet 容器编译 servelt 源文件,生成 servlet 类;
-
初始化阶段
加载与 JSP 对应的 servlet 类,创建其实例,并调用它的初始化方法;
-
执行阶段
调用与 JSP 对应的 servelt 实例的服务方法;
-
销毁阶段
调用与 JSP 对应的 servlet 实例的销毁方法,然后销毁 servlet 实例;
3 JSP语法
JSP 代码可分为两部分:
- 模板数据:即HTML代码;
- 元素:JSP 页面中的 java代码、JSP指令、JSP标签;
3.1 脚本
JSP 脚本指的是 JSP 页面中的 java 代码。JSP脚本必须使用 <% %>
括起来。JSP脚本有三种方式:
<% %>
:用于定义局部变量、编写语句;<%! %>
:用于定义类或方法;<%= %>
:表达式输出;用于输出各种类型变量,基本类型或对象;-
scriptlet 标签,该标签与
<% %>
有相同的功能;<jsp:scriptlet> String s = "hello world"; System.out.println(s); </jsp:scriptlet>
3.2 注释
<%--JSP注释--%>
//java 行注释
/*java多行注释*/
<!--HTML注释-->
<%--其中java和HTML注释会随JSP一起转译到类文件中--%>
3.3 指令
JSP指令用来设置整个 JSP 页面相关的属性,例如编码方式、文档类型等;语法格式为:
<%@directive attribute="value" %>
指令可以有多个属性,它们以键值对形式存在,并用逗号隔开;JSP 中有三种指令标签:
Ⅰpage指令
Page 指令时容器提供当前页面的使用说明。一个JSP页面可以包含多个Page指令。常用的 page 属性有:
Ⅱ include指令
include 指令用来包含其他文件。被包含的文件可以是 JSP 文件、HTML文件或文本文件。包含的文件就像是 JSP 文件的一部分,会被同时编译执行。
语法格式: <% @include file="文件相对 URL 地址" %>
。指令中的文件名实际上是一个相对 URL 地址。如果没有给文件关联路径,JSP 编译器会默认在当前路径寻找。
静态导入
上述所说即为静态导入——将一个 JSP 文件的内容与另一个 JSP 文件内容拼接在一起,转化成一个类文件。会导致的问题:两个JSP文件中声明相同的java变量,会产生错误。
动态引入
导入的 JSP 文件会独立转化为一个类文件。动态导入属于JSP动作元素——动态包含。后面会讲述。
Ⅲ Taglib指令
JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。Taglib指令引入一个自定义标签集合的定义,包含库路径、自定义标签。
语法格式:<%@ taglib uri="标签库位置" prefix="指定标签库的前缀" %>
4 JSP动作元素
JSP动作元素是 JSP 内置的预定义函数,是对JSP功能的抽象和封装。
常见的动作元素
所有的动作元素都有两个属性:
- id属性:动作元素的唯一标识。可由 PageContext 调用;
- scope属性:识别动作元素的生命周期。scope属性定义了相关联 id 对象的寿命;
4.1 <jsp:include>
用于包含静态或动态的文件。与 include 指令不同,如果包含的文件为 JSP,那该 JSP 会先转化为类文件,再写入。
<jsp:include page="相对url地址" flush="true">
<%--
page:包含页面的相对url地址;
flush:在包含资源前是否刷新缓存区;
--%>
4.2 <jsp:forward>
把请求转到另一个页面;
< jsp:forward page="相对URL地址" />
<%--传递参数,请内嵌param元素--%>
<jsp:forward page="URL">
<jsp:param name="key" value="value"/>
</jsp:forward>
相当于 servlet 中调用 request.getRequestDispatcher("url").forward(req,resp);
。
4.3 JavaBean
JavaBean是一个普通的java类,也称为简单java对象——POJO(Plain Ordinary Java Object),是Java程序设计中一种设计模式,是一种基于 Java 平台的软件组件思想。
JavaBean遵循特定的写法,通常有以下的规则:
- 有无参的构造函数;
- 成员属性私有化;
- 封装的属性如果需要被外部操作,必须编写 public 权限的 setter、getter 方法;
好处——封装、重用、可读
- 作为数据传递的载体,在 Java 端和 Web 页面之间传递,实现界面和 Java 代码分离;
- 解决代码重复编写,减少冗余;
Ⅰ JavaBean的三种行为元素
行为元素 | 描述 |
---|---|
< jsp:useBean > | 在JSP页面中查找JavaBean对象或实例化JavaBean对象 |
< jsp:setProperty > | 设置JavaBean的属性 |
< jsp:getProperty > | 获取JavaBean的属性 |
Ⅱ < jsp: useBean >
<%--(1)未使用 JSP 行为元素--%>
<% @page import="pojo.User" %>
<%
User user = new User();
user.setName("name");
%>
<%=user.getName()%>
<%--(2)使用 JSP 行为元素--%>
<jsp:useBean id="实例化对象的名称" class="类的全名" scope="所在域">
<%
User user = new User();
user.setName("name");
%>
<%=user.getName()%>
注意:使用 JavaBean时,POJO类中需要定义无参构造函数;如果没有无参构造函数,使用 JavaBean 动作元素会错误。原因是因为:内部在实例化对象时使用无参构造函数。
Ⅲ < jsp:setProperty >
设置 JavaBean 中私有属性的动作元素。语法如下:
<jsp:setProperty name ="对象名称" property="属性名" param="参数名" value="值"/>
案例:获取表单数据
<%--login.jsp--%>
<from action="main.jsp" method="post">
用户名:<input type="text" name="name" id="uname"><br/>
密码:<input type="password" name="password" id="password"><br/>
年龄:<input type="text" name="age" id="age"><br/>
<input type="submit" value="提交">
</from>
<%--main.jsp--%>
<jsp:useBean name="user" class="pojo.User" scope="page">
<jsp:setProperty name="user" property="name">
<jsp:setProperty name="user" property="password">
<jsp:setProperty name="user" property="age">
//pojo.User.java
public class User{
private String name;
private String password;
private int age;
}
从上述的案例可发现,这三处的属性名需要一致。具体的原理是通过反射机制,可查看编译后的 java 文件。
introspecthelper(_jspx_page_context.findAttribute("person"), "name", request.getParameter("name"), request, "name", false);
Ⅳ < jsp:getProperty >
获取 JavaBean 类的属性值。语法如下
<jsp:getProperty name="对象名" property="属性名"/>
5 内置对象
JSP 引擎将 JSP 文件转化为对应的 JspServlet 时,会创建9个与 web 开发相关的对象,便于在编写 JSP 时直接使用。JSP 内置对象有9个,分别为:
PageContext对象
pageContext 对象是javax.servlet.jsp.PageContext类的实例,代表整个 JSP 页面,主要作用是访问页面信息。通过pageContext 可以获取其他的8个内置对象。
四个域对象
- Request:一次请求中保存属性,服务器跳转有效,浏览器跳转无效;
- Session:一次会话范围中保存属性,关闭浏览器即无效
- pageContext:一个页面中保存属性,页面跳转无效
- ServletContext:曾哥服务器中保存属性,所有用户都可以使用;
以上域对象都有以下三个方法:
- setAttribute(String name,Object o):设置属性
- getAttribute(String name):获取属性
- removeAttribute(String):移除属性
PageContext对象有所不同。重载了上述三个方法:
- setAttribute(String name,Object o,int scope):在指定域设置属性
- getAttribute(String name,int scope):在指定域获取属性
- removeAttribute(String,int scope):在指定域移除属性
其中,scope 参数是 pageContext 中封装域对象的静态变量,当想在指定的域中操作属性,调用对象的 scope 变量。如若不指定,则默认是 page。
- PageContext.APPLICATION_SCOPE
- PageContext.SESSION_SCOPE
- PageContext.REQUEST_SCOPE
- PageContext.PAGE_SCOPE
PageContext 中还存在一个方法:findAttribute(String name);
。查找各域的属性,查找顺序为:page --> request --> session --> application 。
6 EL表达式
EL(Expression Language) 表达式语言,用于读取数据、运算或逻辑表达式,并显示内容。EL表达式能够便捷地读取数据。
EL表达式格式:${expr}
6.1 获取域属性
获取域属性:未指定作用域时,查找顺序为:page --> request --> session --> application,直到找到为至。若均未找到,返回的是空字符串,而不是null;
当然,除了指定域获取属性,还可以获取 JavaBean 对象的内容。
<%--未指定作用域查找--%>
${属性名}
<%--指定作用域查找--%>
${pageScope.属性名}
${sessionScope.属性名}
${requestScope.属性名}
${applicationScope.属性名}
<%--获取JavaBean对象数据--%>
${对象名.属性/方法}
6.2 获取集合数据
<%--读取list集合数据--%>
${list[index]}
<%--如果list存储的是对象--%>
${list[index].对象名}
<%--读取map集合数据--%>
${map[key]}
${map.key.对象名}
${map[key].对象名}
问题:在IDEA中创建泛型内容时,出现如下错误:
原因是:编译版本较低不支持泛型特性。但是,根据排查,项目配置的java编译版本和JDK版本为1.8,原来Tomcat服务器中编译 JSP 的版本配置为低版本。
解决方法:在Tomcat服务器的配置文件中添加 JSP 编译版本设置:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
<init-param>
<param-name>compilerSourceVM</param-name>
<param-value>1.8</param-value>
</init-param>
<init-param>
<param-name>compilerTargetVM</param-name>
<param-value>1.8</param-value>
</init-param>
</servlet>
6.3 表达式操作
在EL表达式中可以进行运算、逻辑运算表达式,并返回显示结果。在EL表达式中允许以下操作符:
6.4 EL内置对象
以上对象存储数据的结构均为Map集合,其中,paramValues 对象和 headerValues 对象中key对应的 value 值使用一个 String[] 数组,用于保存多个参数值。比如,提交数据时,含有多选框数据。
补充:
-
获取Cookie时,
${cookie.key}
获取的是一个 Cookie 对象;如果想获取Cookie下的属性,请使用${cookie.key.property}
。其中,key 为创建Cookie对象时的key(如下)。Cookie c = new Cookie(key,value);
7 JSTL标签库
JSTL全称 JSP Standard Tag Library,JSP标准标签库。JSTL作为基本的标签库,提供了一系列的 JSP 标签,能够实现基本的功能:集合的遍历、数据的输出、字符串处理、数据格式化等;
JSTL使用XML标签格式的语句代替逻辑代码,可以提升 JSP 页面的逻辑代码编码效率,使得JSP页面整洁、易读;
标准标签库种类
- 核心标签
- 格式化标签
- SQL标签
- XML标签
- JSTL函数
7.1 使用步骤
下载标准标签库,解压并将 standard.jar 和 jstl.jar 文件拷贝到 /WEB-INF/lib 目录下,在项目中jar包,并将所需的 tld 文件复制到 lib 目录;
-
在 web.xml 文件中配置标签库信息;
<jsp-config> <taglib> <taglib-uri>http://java.sun.com/jsp/jstl/core</taglib-uri> <taglib-location>/WEB-INF/c.tld</taglib-location> </taglib> <taglib> <taglib-uri>http://java.sun.com/jsp/jstl/core-rt</taglib-uri> <taglib-location>/WEB-INF/c-1_0-rt.tld</taglib-location> </taglib> </jsp-config>
-
在 JSP 页面上使用 taglib 指令引用标签库;完成以上步骤就可以使用JSTL标签库了;
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
7.2 core标签库
< c:out >
在 JSP 中显示数据,就像 <%= ... %>
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
value | true | Object | 指定要输出的内容 |
escapeXml | true | Boolean | 指定是否将>、<、&、'、" 等特殊字符进行HTML编码转换后再进行输出。默认为true |
default | true | Object | Value值为null时锁输出的默认值 |
< c:set >
用于保存数据。var 属性操作Integer、Double、String等可以直接操作的数据,target 属性操作 JavaBean 或 Map 对象的数据。
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
value | true | Object | 指定属性的值 |
var | false | String | 用于要指定设置作用域属性的名称 |
scope | false | String | 用于指定属性所在的作用域 |
target | true | Object | 用于指定要设置属性的对象 |
property | true | String | 用于指定对象的属性名称 |
<%--两种设置数据的方式--%>
<jsp:useBean name="user" class="pojo.User" scope="page">
<%
String a = null;
pageContext.setAttribute("a",a);
%>
<c:set value="Hello World" var="a" scope="page">
<c:set value="Hello World" target="${user}" property="name">
< c:remove >
删除域范围的属性。var 表示要删除的属性或对象;scope 表示属性所在作用域。
<c:remove var="user" scope="page">
< c:catch >
捕获标签内语句的产生的异常。var 属性用来存储错误信息的变量。
<c:catch var="massage">
<% int i = 10/0;%>
</c:catch>
< c:if>
用于判断表达式的值,相当于 if 语句。
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
test | true | boolean | 条件表达式,true则处理标签内语句 |
var | false | String | 将条件表达式的结果保存到变量中 |
scope | false | String | var 属性的作用域 |
< c:choose>
、< c:when>
、<c:otherwise>
多条件判断语句,相当于 if ... else if ... else ... 语句。
<c:choose>
<c:when test="条件判断">
执行语句 ...
</c:when>
<c:when test="条件判断">
执行语句 ...
</c:when>
<c:otherwise>
执行语句 ...
</c:otherwise>
</c:choose>
< c:forEach>
循环标签,相当于 java 中 while 和 for 循环。
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
var | false | String | 当前条目的变量名称 |
items | true | 任意类型 | 要被循环的信息 |
begin | true | int | 开始元素,以0开始 |
end | true | int | 结束元素,以0开始 |
step | true | int | 每一次迭代的步长 |
varStatus | false | LoopTagStatus | 代表循环状态的变量名称 |
varStatus为存储当前迭代信息的变量,其具有以下属性:
- index:当前对象的索引值,从0开始;
- count:记录遍历对象的个数,从1开始;
- current:记录当前对象;
- last:是否第一个,返回布尔值;
- first:是否最后一个,返回布尔值;
- begin:开始遍历位置,标签中未指定 begin ,该属性为空字符串;
- end:结束遍历位置,标签中未指定 end,该属性为空字符串;
- step:步长;
< c:forTokens>
该标签类似 String 类中的 split() 和 for 循环的一种集合。它与 <C:forEach>
都含有 begin、end、step、items、var、varStatus属性,不同的是 <C:forTokens>
多了 delims 属性, items 属性接收是字符串,items 的字符串会按 delims 字符进行分割并遍历。
<%--代码--%>
<c:forTokens items="Hello World.I am from China.I love China." delims="." var="str">
${str} <br>
</c:forTokens>
<%--输出结果--%>
Hello World
I am from China
I love China
< C:import>
类似 JSP 中的静态导入 <% @include file="">
和动态导入 <jsp:include page="">
属性
- URL:导入资源的URL,可以是相对路径和绝对路径,亦可以其他主机资源;
- context:访问当前web应用的其他资源,以
/
开头; - var:保存导入文件的内容,String 类型;
- scope:保存作用域,默认为 page;
- charEncoding:引入数据的字符编码,默认 ISO-8859-1;
- varReader:保存导入文件的内容,java.io.Reader对象变量;
<h4>导入外部资源</h4>
<c:import url="http://www.baidu.com" var="content" charEncoding="UTF-8"/>
<h4>导入内部资源</h4>
<c:import url="js/login.jsp" charEncoding="UTF-8" var="log"/>
< c:param>
可嵌套在 URL 地址标签后,为 URL 地址附加参数;
自动对嵌套的参数进行 URL 编码。
<c:param name="key" value="value"/>
< c:url>
将 URL 格式化一个字符串,然后存储到一个变量中。该标签知识用于调用 response.encodeURL()
方法的一种方法。
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
value | true | String | URL 字符串 |
var | false | String | 存储 URL 字符串的变量名 |
scope | false | String | 保存 URL 的作用域 |
context | true | String | web应用的名称 |
案例
<c:url value="http://www.baidu.com" var="baidu" scope="page">
<c:param name="param" value="value"/>
</c:url>
<a href="${baidu}">点击进入百度</a>
< c:redirect>
通过自动重写 URL 来讲浏览器重定向到一个新的 URL 。可以配合 param 标签使用;实现页面跳转和数据传递。
属性名 | 是否支持EL | 属性类型 | 描述 |
---|---|---|---|
url | true | String | 指定要转发或重定向的目标 URL |
context | true | String | 当使用相对路径重定向到同一个服务器下的其他web应用资源时,context为其他web应用的名称 |
简单用法
<c:redirect url="http://www.baidu.com">
<c:param name="uname" value="Chan"/>
</c:redirect>
除了 core 标签库之外,JSP 中还存在其他标签库,比如:格式化标签库、SQL标签库、XML标签库、JSTL函数库等,以及自定义标签内容等,后续有所使用再学习。
参考文章
- 菜鸟教程-JSP教程
-
java3y - GitHub
可关注大佬微信公众号:java3y