第2章 JSP核心
2.1 内置对象
2.1.1 pageContext
javax.servlet.jsp.PageContext
页面上下文,具有一个只在当前页面范围的域属性空间,即其具有setAttribute()方法和getAttribute()方法。
EL表达式,访问变量时,只能访问域属性空间内的变量。因此,可以将变量先存放到该域属性空间,或其它三个域属性空间(request、session、application)。
pageContext具有一些get方法,可以获取Request、Response、Session、ServletContext、ServletConfig、page(即当前Servlet)、exception、out等其它八个内置对象
2.1.2 application
即ServletContext
ServletContext所具有的方法,application都有。
常用的方法,例如:
void setAttribute(String name, Object object);
Object getAttribute(String name);
Object removeAttribute(String name);
2.1.3 out
所属类型:javax.servlet.jsp.JspWriter
JspWriter类继承自IO流的Writer类。
即out就是一个输出流。
2.1.4 page
查看jsp翻译的servlet,page对象即Servlet对象本身。
final java.lang.Object page = this.
2.1.5 exception
普通的jsp页面中,不能使用exception内置对象。因为打开jsp翻译的servlet,发现其中并没有exception对象。
若要在页面中直接使用exception对象,则需要配合着page指令使用。
2.1.6 其它对象
request,response,session,config,用法与servlet时的用法相同。
2.2 JSP指令(directive)
jsp中包含三类指令:
page指令
include指令
taglib标签库指令
<%@ 指令名称 属性名 = 属性值 属性名 = 属性值 %>
2.1.1 page指令
(1)、pageEncodeing属性
<%@ page pageEncoding = “utf-8”%>
默认的MIME类型为text/html
//servlet
response.setContentType(“text/html;charset=UTF-8”);
(2)、contentType属性
<%@ page contentType = “text/html; charset=UTF-8” %>
//servlet
response.setContentType(“text/html;charset=UTF-8”);
可以对pageEncoding默认的MIMe类型进行修改
(3)、import属性
<%@ page import = “java.util.Date”%>
(4)、errorPage\isErrorPage属性
<%@ page errorPage = "/error.jsp" %>
//error.jsp
<%@ page isErrorPage = "true"%>
<html>
<body>
error page<br />
ex = <%=exception.getMessage() %>
</body>
</html>
//serlvet
public void _jspService(...){
...
java.lang.Throwable exception = ...;
...
}
(5)、Session属性
//hello1.jsp
<body>
<%
session.setAttribute("user","zhangsan");
%>
</body>
//servlet
session = pageContext.getSession();
查看源码发现,返回的还是request.getSession()
1、 设置
HttpSession session = request.getSession(true);
session.setAttribute(…);
设为true,意味着没有session对象时才创建,有则不创建。
2、读取
HttpSession session = request.getSession(false);
if(session != null){
session.getAttribute(“…”);
}
设为false,意味着获取现有的session对象,如果没有,也不创建。
//hello2.jsp
<%@ page contentType = "text/html; charset = UTF-8"%>
<%-- 清除内置的Session对象 --%>
<%@ page session = "fasle"%>
<body>
HttpSession session = request.getSession(false);
if(session != null){
String user = (String) session.getAttribute("user");
out.print("user = " + user);
}
<body/>
2.2.2 include指令
(1)、用法
可以包含动态文件也可以包含静态页面文件。
index.jsp
<html>
<body>
index page before<br />
<%@ include file = "/next.jsp"%>
index page after<br />
</body>
</html>
next.jsp
<html>
<body>
next page
</body>
</html>
(2)、静态联编
只生成了一个index_jsp.java的servlet源文件,没有生成next_jsp.java文件。
jsp翻译引擎,将include指令包含的next.jsp文件直接翻译到了index.jsp对应的servlet中,形成了一个.java文件。
该包含操作是在编译之前,由jsp翻译引擎完成的,而不是在程序运行期间完成的。
这种包含是一种静态包含,称为静态联编。
整个过程只一个_jspService()方法。也就是说,index.jsp和next.jsp之间是可以相互访问局部变量的。
2.3 JSP动作(Action)
页面中,应该使用EL表达式、JSTL标签及JSP动作,来代替java代码块、表达式。
JSP动作的语法格式
<jsp:动作名称 属性名 = 属性值 属性名 = 属性值 ...></jsp:动作名称>
或
<jsp:动作名称 属性名 = 属性值 属性名 = 属性值 ... />
实际开发中,常用的就两个forward和include。
底层使用的是request.getRequestDispatcher("").forward(...)和.include()
。
2.3.1 forward动作
index.jsp
<body>
index page befor <br />
<jsp:forward page="/next.jsp"></jsp:forward>
index page after <br />
<body/>
next.jsp
<body>
next page
</body>
forward跳转时,只显示
next page
2.3.2 include动作
index.jsp
<body>
index page befor <br />
<jsp:include page="/next.jsp"></jsp:include>
index page after <br />
<body/>
next.jsp
<body>
next page
</body>
include跳转时,全显示
index page befor
next page
index page after
(注):
生成了两个.java文件:index_jsp.java与left_jsp.java。
这个包含动作是在程序运行过程中,由index_jsp文件中的_jspService()方法通过JspRuntimeLibrary类的include()方法调用了left_jsp文件中的_jspService()方法完成的。
这种在运行期执行的包含,称为动态联编。
2.4 EL表达式
Expression Language,表达式语言。
${expression}获取到指定表达式的值。
2.4.1 获取数据
(1)、EL只能从四大域中获取数据
其查找数据的顺序是,依次按照由小到大的范围,从四大域中查找指定名称的属性值,找到后就不再继续往下查找。
<body>
<%
String username = "abc";
pageContext.setAttribute("username", username);
request.setAttribute("username", username);
session.setAttribute("username", username);
application.setAttribute("username", username);
%>
//从四大域属性空间中依次查找
username = ${username}
</body>
(2)、从指定域中获取数据
//通过EL的内置对象,从指定的域属性空间中查找
username = ${requestScope.username}
(3)、访问Bean的属性
<body>
<%
School school = new School("qinghua","beijing");
Student studentb = new Student("zhangsan",23);
pageContext.setAttribute("student", student);
%>
student = ${student}
name = ${student.name}
schoolName = ${student.school.sname}
</body>
(4)、获取数组中的元素
<body>
<%
String[] names = {"zhangsan", "lisi", "wangwu"};
pageContext.setAttribute("names", names);
%>
names[1] = ${names[1]}
<%
School[] schools = new School[3];
schools[0] = new School("qinghua", "beijing");
schools[1] = new School("haiyang", "qingdao");
schools[2] = new School("shanda", "shandong");
pageContext.setAttribute("chools", schools);
%>
chools[2].sname = ${schools[2].sname}
</body>
(5)、获取List中的元素
EL可以通过索引访问List,但无法访问Set。因为Set中没有索引的概念。
<body>
<%
List<String> names = new ArrayList<String>();
names.add("zhangsan");
names.add("lisi");
names.add("wangwu");
pageContext.setAttribute("names",names);
%>
names[2] = ${names[2]};
<body/>
(6)、获取Map中的元素
<body>
<%
Map<String, Object> map = new Map<>();
map.put("school", new School("qinghua", "beijing"));
map.put("mobile", "1111111");
map.put("age", 21);
pageContext.setAttribute("map", map);
%>
school.name = ${map.school.sname}
mobile = ${map.mobile};
age = ${map.age};
</body>
2.4.2 运算符
算术运算符,关系运算符,逻辑运算符,条件运算符,取值运算符
除了这些,还有一个empty
${empty 变量}
- 变量未定义,返回true
- 变量为String类型,空串返回true
- 变量为引用类型,其值为null返回true
- 变量为集合类型,不包含任何元素,返回true
2.4.3 EL内置对象
EL中表示四个域属性空间的内置对象:pageScope requestScope sessionScope applicationScope
其它的常用内置对象还有:
(1)、pageContext
EL中的pageContext与JSP中内置对象中的pageContext是同一个对象。
通过该对象,可以获取request、response、session、servletContext、servletConfig等对象。
${pageContext.request.contextPath}
,获取项目根目录,一般用在JSP页面的路径前。
pageContext.request 其底层实际调用的是pageContext.getRequest()方法
在EL的11个内置对象中,除了pageContext外,其它10个内置对象,其类型均为java.util.Map类型。
(2)、param
获取请求中指定参数的值
GET: http:localhost:8080/textproject/index.jsp?name=abc
//index.jsp
param.name = ${param.name}
POST:
<form action = "${pageContext.request.contextPath/show.jsp}">
姓名:<input type = "text" name = "name" />
年龄:<input type = "text" name = "age" />
爱好:
<input type = "checkbox" name = "hobby" value = "swimming" />
<input type = "checkbox" name = "hobby" value = "climbing" />
<input type = "checkbox" name = "hobby" value = "reading" />
</form>
//show.jsp
name = ${param.name}
age = ${param.age}
(3)、paramValues
hobby[0] = ${paramValues.hobby[0]}
hobby[1] = ${paramValues.hobby[0]}
hobby[2] = ${paramValues.hobby[0]}
(4)、initParam
获取web.xml中初始化参数
web.xml
<context-param>
<param-name>company<param-name/>
<param-value>powernode<param-value/>
</context-param>
jsp页面
company = ${initParam.company}
2.4.4 自定义EL函数
自定义EL函数,实际字符串连接的功能
1、定义类
public class ELFunctions{
public static String lowerToUpper(String source){
return source.toUpperCase();
}
public static String upperToLower(String source){
return source.toLowerCase();
}
}
2、标签库定义 注册
自定义的类及其函数,需要在扩展名为.tld的XML文件中进行注册
XML文件是需要约束的,即需要配置文件头部。这个头部约束可以从以下文件中复制。
comcat-9/webapps/examples/web-inf/jsp2/jsp2-example-taglib.tld
//WEB-INF/myElFuns.tld
<tablib ...>
//定义标签库信息
<tlib-version>1.0</tlib-version>
<show-name>myElFuncs</short-name>
<uri>http://www.test.com/myproject/jsp/el/customElFuncs</uri>
//注册函数
<function>
<name>myLowerToUpper</name>
<function-class>myproject.testpackage. ELFunctions</function-class>
<function-signature>java.lang.String. lowerToUpper(java.lang.String)</function-signature>
<function/>
<function>
<name>myUpperToLower</name>
<function-class>myproject.testpackage. ELFunctions</function-class>
<function-signature>java.lang.String. upperToLower(java.lang.String)</function-signature>
<function/>
</tablib>
//index.jsp
<%@ taglib uri = "http://www.test.com/myproject/jsp/el/customElFuncs" prefix = "myElFuncs"%>
<body>
${myElFuncs:myLowerToUpper("abc")}
</body>
2.4.5 JSTL中的EL函数
JSTL,JSP Standard Tag Library,即JSP标准标签库。
该标签库中,定义好了一套处理字符串的函数标签库。
将JSTL的Jar包导入WEb/lib后,在jsp页面中即可直接使用。
//index.jsp
<%@ taglib uri = "http://java.sun.com/jsp/jstl/functions" prefix = "fn"%>
<body>
${fun.substring("abcdefg", 2, 5)}
.....
.....
</body>
2.4.6 EL总结
- EL不能出现在java代码块、表达式块等jsp动态代码部分
- EL只能从pageContext、request、session、application四大域属性空间中获取数据
- EL不会抛出空指针异常
- EL不会抛出数组访问越界异常
- EL不具有字符串处理能力,只能通过JSTL标签库来处理
2.5 自定义标签
简化代码,替代java代码块。
2.5.1 基本用法
(1)、需求
自定义标签,输出客户端Ip
(2)、定义标签处理器
实现处理器接口:javax.servlet.jsp.tagext.simpleTag
//定义标签处理器
public class ClientIpTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//获取pageContext
PageContext pc = (PageContext) this.getJspContext();
//获取请求对象
ServletRequest request = pc.getRequest();
//获取客户端IP
String clientIp = request.getRemoteAddr();
//获取标准输出流
JspWriter out = pc.getOut();
//输出
out.print(clientIp);
}
}
(3)、注册标签处理器
//customTags.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!--配置标签库信息-->
<tlib-version>1.0</tlib-version>
<short-name>customTags</short-name>
<uri>http://www.jstlproject.com/jsp/tags/custom</uri>
<!--注册标签-->
<tag>
<name>clientIp</name>
<tag-class>tags.ClientIpTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
(4)、使用自定义标签
<%@ taglib uri = "http://www.jstlproject.com/jsp/tags/custom" prefix = "customTags" %>
<body>
<%
String ip = request.getRemoteAddr();
out.println("ip = " + ip);
%>
<br/>
<customTags:clientIp />
</body>
2.5.2 定义带标签体的标签
//标签处理器 - 小写变大写
public class LowerToUpperTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//获取标签体对象
JspFragment jspbody = this.getJspBody();
//创建字符串输出流
StringWriter strWriter = new StringWriter();
//标签体对象写入字符串输出流
jspbody.invoke(strWriter);
//字符串输出流中的数据
String str = strWriter.toString();
//小写变大写
str = str.toUpperCase();
//写入标准输出流
this.getJspContext().getOut().print(str);
}
}
注册
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!--配置标签库信息-->
<tlib-version>1.0</tlib-version>
<short-name>customTags</short-name>
<uri>http://www.jstlproject.com/jsp/tags/custom</uri>
<!--注册标签-->
<tag>
<name>clientIp</name>
<tag-class>tags.ClientIpTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>lowerToUpper</name>
<tag-class>tags.LowerToUpperTag</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>
附:
- empty:表示当前标签没有标签体
- scriptless:表示当前标签具有标签体,对el表达式解析。
- jsp:原样输出,已过时
- tagdependent: 原样输出到浏览器,不解析el表达式
//index.jsp
<%@ taglib uri = "http://www.jstlproject.com/jsp/tags/custom" prefix = "customTags" %>
<body>
<%
String username = "aaa";
pageContext.setAttribute("username", username);
%>
<customTags:lowerToUpper>${username }</customTags:lowerToUpper>
</body>
2.5.3 定义带属性的标签
//注册标签
<tag>
<name>if</name>
<tag-class>tags.IfTag</tag-class>
<body-content>tagdependent</body-content>
<attribute>
<name>test</name>
<required>true</required>
<!-- runtime expression value
true:该属性的值支持el表达式与jsp表达式
-->
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
//定义标签处理器
public class IfTag extends SimpleTagSupport {
private boolean test;
//标签的属性反映到标签处理器中,就是一个set属性
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
if(test) {
/*
JspFragment jspbody = this.getJspBody();
jspbody.invoke(this.getJspContext().getOut());
*/
//以上代码等价于以下代码
this.getJspBody().invoke(null);
}
}
}
//index.jsp
<customTages:if test = ${gender} }} }>男</customTages:if>
<customTages:if test = not gender }>女</customTages:if>
2.5.4 定义forEach标签
//定义标签处理器,遍历collection集合和数组
public class ForEachTag extends SimpleTagSupport {
private Object items;
private String var;
public void setItems(Object items) {
this.items = items;
}
public void setVar(String var) {
this.var = var;
}
public Collection getcoll() {
if(items instanceof List) {
return (List) items;
}else if(items instanceof Set) {
return (Set) items;
}else if(items instanceof Map) {
return ((Map) items).entrySet();
}else if(items instanceof Object[]) {
return Arrays.asList((Object[])items);
}
return null;
}
@Override
public void doTag() throws JspException, IOException {
for (Object obj:getcoll()) {
this.getJspContext().setAttribute(var, obj);
this.getJspBody().invoke(null);
}
}
}
//注册
<tag>
<name>forEach</name>
<tag-class>tags.ForEachTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
//index.jsp
<customTags:forEach items="${citys}" var="city">
${city }<br>
</customTags:forEach>
2.5.5 将自定义标签库打包发行
1、右键export选择jar包,只打包源码。
2、把.tld注册文件,放到jar包里的META-INFO里面。
3、把jar包放到项目的WEB-INF的lib下。
4、jsp页面中导入标签库,就可以直接用了。
2.6 JSTL
jsp standard tag library,包含五个子库。
核心标签库、格式化标签库、EL函数标签库、SQL操作标签库(过时)、XML操作标签库(过时)。
导入jstl.jar包和standard.jar包
2.6.1 核心标签库
<%@ taglib uri=”http://java.sun.com/jsp/jstl/core“ prefix=”c” %>
(1)、c:set
//将变量存放到指定域中
<c:set var="name" value="zhangsan" scope="session">
name = ${sessionScope.name}
//为Bean的属性赋值
<%
Student student = new Student();
pageContext.setAttribute("student", student);
%>
<c:set value="lisi" property="name" target="${pageScope.student}"></c:set>
student = ${student}
//为map赋值
<%
Map<String, Object> map = new HashMap<>();
pageContext.setAttribute("map", map);
%>
<c:set value="abc" property="company" target="${pageScope.map}"></c:set>
map = ${map}
(2)、c:remove
//从域属性空间中删除变量
<c:remove var="school">
(3)、c:out
//输出指定的变量
<c:set var="city" value="<h1>beijing</h1>">
city1 = <c:out value="${city}"/>
<br />
city2 = <c:out value="${city}" escapeXml="false" />
city1对h1标签进行了解析。
city2对h1标签没有进行解析,直接输出。
(4)、c:catch
//获取异常信息
<c:catch var="ex">
<%
int i = 3/0;
%>
</c:catch>
(5)、c:if
<c:if test="${user == "zhangsan"}">
<a href="#">进入系统</a>
</c:if>
(6)、c:choose
<c:choose>
<c:when test="${pagenumber == 1}">
第一页
</c:when>
<c:when test="${pagenumber == 2}">
第二页
</c:when>
<c:otherwise>
第三页
</c:otherwise>
</c:choose>
(7)、c:forEach
//遍历集合
<c:forEach items="${citys}" var="city" begin="0" end="7" step="4">
${city} <br>
</c:forEach>
//输出行号
<c:forEach items="${students}" var="student" varStatus="vs">
<tr class="${vs.count/2 == 0 ? 'even' : 'odd'}">
<td>${vs.count}</td>
<td>${student.name}</td>
<td>${student.age}</td>
</tr>
</c:forEach>
2.6.1 格式化标签库
<%@ taglib uri=”http://java.sun.com/jsp/jstl/fmt“ prefix=”fmt” %>
<%
Date now = new Date();
pageContext.setAttribute("now", now);
%>
//格式化日期,输出到浏览器
now = <fmt:formatDate value="${now}" pattern="yyyy-MM-dd">
//格式化日期,将结果放到域中的变量里
<fmt:formatDate value="${now}" pattern="yyyy-MM-dd" var="birth">
生日:<input type="text" name="birthday" value="${birth}" />
2.6.2 jstl下载
apache.org –> Tomcat –> Taglibs –> Download