JSP
1. JSP简介
JSP(Java Server Pages),即Java服务器端页面。可以理解为一个特殊的页面,其中既可以定义HTML的标签,又可以定义Java代码,故而可以简化书写。
JSP可以概括地理解为“嵌入了Java代码的HTML”,其由静态HTML、专用的JSP标签、Java代码组成。
index.jsp示例:
JSP适宜在web页面中置入动态元素:
2. JSP的原理
JSP是服务器端的技术,在后台被自动转换成Servlet。
JSP本质上就是一个Servlet。

如果修改了某个JSP,该JSP仅在修改后被第一次被访问时才会被转换成Servlet并进行编译,创建JSP唯一的一个实例,并调用_jspInit
完成初始化。之后每个用户请求都会创建一个调用JSP实例的_jspService
方法的线程,因而多个并发请求会导致多个线程同时调用_jspService
。
Tomcat中,默认目录下的JSP文件被转换生成的Servlet文件及编译后的.class文件被放在install_dir/work/Catalina/localhost/_/org/apache/jsp目录下。
3. JSP语法
除了标准的HTML以外,JSP主要包括三类组件:
- 脚本元素(scripting elements):可以向JSP文件产生的servlet文件中插入代码。
- 指令标签(directives):影响由JSP生成的Servlet的总体结构。
- 动作标签(actions):影响JSP运行时的功能。
3.1 脚本元素
JSP脚本——JSP定义Java代码的方式,其语法如下:
语法 | 作用 |
---|---|
<% 代码 %> | 定义的Java代码会置于service方法中 |
<%! 代码 %> | 定义的Java代码是Servlet类的成员(用的少) |
<%= 输出语句 %> | 定义的Java代码会直接输出到页面上(编译后位于Servlet的service方法中) |
<!-- 注释内容 --> | html注释:只能注释html代码片段 |
<%-- 注释内容 --%> | jsp注释:可以注释所有代码片段(推荐) |
示例index.jsp:
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<%--以下代码将置于Servlet的service()方法中--%>
<%
System.out.println("hello jsp");
int i = 1;
System.out.println(i);
%>
<%--以下代码将置于Servlet类的定义成员的位置--%>
<%!
private int i = 2;
%>
<%--以下代码将直接输出到页面上--%>
<%= "i = " + i %>
</body>
</html>
3.2 指令标签与动作标签
指令标签<%@ include file="filename" %>
和动作标签<jsp:include page="someFile.html" />
都可以嵌入代码,前者实际上是将代码插入行内,后者是将另一个页面的输出插入原来的页面。
3.3 JavaBean动作标签
JavaBean解决了这个问题,它将一系列相关的属性和方法组合在一个Java类中,构成了一个组件。在JSP程序中,只要使用JavaBean动作标签调用该组件就可以了。
- JavaBean其实就是Java类,但其必须使用一组相当简单而又标准的设计和命名约定,因而调用它们的程序无须理解其内部工作原理,就可以很容易地使用JavaBean的方法。
- JavaBean类的一个实例叫做一个bean。
- 通常我们将JavaBean的文件名取作XxxBean。
- JavaBean必须拥有一个默认(无参数)的构造方法,JSP元素创建bean时,会调用默认构造方法。
- JavaBean不应该有公开的属性,且类内的属性通常应该提供get/set方法。
- 可以使用JSP脚本元素访问类的任意方法,访问bean的标准JSP动作只能使用那些遵循getXxx/setXxx或isXxx/setXxx命名约定的方法。
package com.chuan;
/**
* 设计一个描述员工信息的JavaBean,包括编号、姓名、性别、工资。
*/
public class EmployeeBean {
private int id = 0;
private int salary = 0;
private String name = "none";
private boolean male = true;
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMale() {
return this.male;
}
public void setMale(boolean male) {
this.male = male;
}
public int getSalary() {
return this.salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
如果Java类的某个属性只有getXxx或isXxx方法,叫做只读属性。
JavaBean在Web应用中的部署(不同的JSP引擎部署方法不同):
不能放在含有JSP文件的目录中,而应该放在安装Servlet的目录中,且一定要使用包。
单个JavaBean的字节码文件的正确位置是:webAppDir/WEB-INF/classes/packageName。
含有JavaBean的JAR文件应该放在webAppDir/WEB-INF/lib/目录中。
在JSP页面中,可以使用三种JavaBean动作标签构建和操作JavaBean组件:
useBean:
<jsp:useBean id="beanName" class="package.class" scope="someScope" />
表示建立一个bean类的对象参数 含义 scope 有效范围 Page 当前请求访问的JSP页面 Request 当前的请求 Session 客户的会话期间 Application 表示要将bean实例存储在ServletContext中,ServletContext由Web应用中多个Servlet和JSP页面共享 getProperty:
<jsp:getProperty name="beanName" property="propertyName" />
表示读取bean属性的值。setProperty:
<jsp:setProperty name="beanName" property="propertyName" value="propertyValue"|param="parameterName" />
表示设置bean的属性值,该属性必须有set方法。- 也可以用JSP脚本元素
<%= beanName.setXxx("propertyValue") %>
得到相同的结果。
- 也可以用JSP脚本元素
3.4 标签库
除了使用JavaBean,JSP还可以使用定制的标记,便于Web开发人员实现内容和功能的分离;
相对于使用JavaBean,用户自定义的标签库有如下优点:
- beans不可以操作JSP的内容,但标签库可以;
- 使用标签比bean可以用更加简单的形式完成复杂的功能。
JSP通过指令标签中的taglib指令使用标签库。
使用自定义标签比使用bean要复杂一些,它需要3个部分:
- 实现标签行为的标签处理类;
- 将XML元素名称映射到标签实现上的标签库描述文件(后缀名为tld);
- 使用标签的JSP程序。
标签处理类是一具Java类,用来告诉系统在JSP程序中遇到标签后应该做些什么。
标签处理类必须实现javax.servlet.jsp.tagext.Tag接口,通常通过扩展如下两类来实现:
javax.servlet.jsp.tagext.TagSupport
javax.servlet.jsp.tagext.BodyTagSupport
示例:
package com.chuan;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
/**
* 实现一个标签处理类,当JSP程序遇到相应标签,可以插入一个100以内的随机整数和一行文本。
*/
public class ExampleTag extends TagSupport {
public int doStartTag() {
try {
JspWriter out = pageContext.getOut();
out.print((int) (Math.random() * 100));
out.print("My first tag test!");
} catch (IOException ioe) {
System.out.println("Error in ExampleTag: " + ioe);
}
return (SKIP_BODY);
}
}
标签库描述文件:
定义了标签处理类后,接下来就是在服务器上为这个类命名,并将其和一个专门的XML标签名关联起来,通过标签库描述文件可以完成这个任务。
标签库描述文件包括一个XML版本声明、一个DOCTYPE声明、一个taglib容器元素。
重点是taglib容器元素中的tag元素,对于没有属性的标签,tag元素又应该包括以下四个子元素:
子元素 说明 name 定义将在JSP文件中使用的tagname tag-class 给出标签处理类的完整类名,包括包名 body-content 对于没有体的标签应该取值为EMPTY description 一个简单的说明
示例
<?xml version="1.0" encoding="UTF-8"?>
<!-- 建立一个标签库描述文件,将上例建立的标签处理类和example名关联。 -->
<!-- 将其存储在WEB-INF/tlds/example.tld -->
<taglib version="2.0"
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 web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>example</short-name>
<uri>/WEB-INF/tlds/example</uri>
<tag>
<name>example</name>
<tag-class>com.chuan.ExampleTag</tag-class>
<body-content>empty</body-content>
<description>Insert a random integer.</description>
</tag>
</taglib>
至此,可以在JSP中使用自定义的标签了:
- 在首次使用标签前,需要使用taglib指令标签:
<%@ tablib uri="someuri" prefix="somename" %>
- 接下来使用
<prefix:tagname />
引用标签。
示例:
<%@ page contentType="text/html;charset=gb2312" %>
<html>
<head>
<%@ taglib uri="/WEB-INF/tlds/example" prefix="testTag" %>
<title>使用标签<testTag:example/></title>
</head>
<body>
<h1><testTag:example /></h1>
</body>
</html>
3.5 指定某标签的一些属性
有时我们需要在JSP文件中指定标签的一些属性,例如我们希望输出1000以内而不是100以内的随机整数,这时的引用形式应该是:<prefix:tagname attribute1="value1" attribute2="value2" />
。
相应地需要修改标签处理类和标签库描述文件:
package com.chuan;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.*;
/**
* 实现一个标签处理类,当JSP程序遇到相应标签,可以插入一个100以内的随机整数和一行文本。
*/
public class ExampleTag extends TagSupport {
protected int range = 100;
public int doStartTag() {
try {
JspWriter out = pageContext.getOut();
out.print((int) (Math.random() * range));
out.print("Tag test with attriubte!");
} catch (IOException ioe) {
System.out.println("Error in ExampleTag: " + ioe);
}
return (SKIP_BODY);
}
public void setRange(String range) {
try {
this.range = Integer.parseInt(range);
} catch (NumberFormatException nfe) {
this.range = 100;
}
}
}
// 未完待续。。。。。。。
4. JSP的内置对象
JSP的内置对象即在JSP页面中不需要获取和创建,可以直接使用的对象。
JSP一共有9个内置对象(pageContext、request、session、application对象是域对象):
request
:是javax.servlet.http.HttpServletRequest的实例,封装了用户请求的信息response
:是javax.servlet.http.HttpServletResponse的实例out
:字符输出流对象,可以将数据输出到页面上pageContext
session
application
比session对象的生存期更长。
- 服务器启动后就产生,直到服务器关闭该对象才被销毁。
- 所有客户共享这个内置的application对象,因而任何客户改变该对象中存储的数据都会影响到其他客户,所以在某些情况下,对该对象的操作需要同步处理。
applicaton对象的常用方法:
方法 作用 void setAttribute(String key, Object obj)
将obj对象添加到application对象中,并为obj指定一个索引关键字key Object getAttribute(String key)
获取application对象中指定关键字的对象 Enumeration getAttributeNames()
返回application对象的所有索引关键字 void removeAttribute(String key)
删除指定索引的对象
page
config
exception
5. 从JSP中发送请求到别处
使用动作标签<jsp:forward page="URL" />
,配合<jsp:param name="someName" value="someValue" />
,可将控制权转交给别处,并提供额外的参数。其中page属性可以包含JSP表达式,使目的地可以在请求时被计算出来。
6. JSP与Servlet
Servlet擅长数据处理,如读取并检查数据、与数据库通信
JSP擅长表示,即构建HTML来表示请求的结果。