了解

第一个 JSP 程序

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<title>第一个 JSP 程序</title>
</head>
<body>
<%
out.println("Hello World!");
%>
</body>
</html>

JSP 生命周期

JSP编译

当浏览器请求JSP页面时,JSP引擎会首先去检查是否需要编译这个文件。如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个JSP文件。

编译的过程包括三个步骤:

  • 解析JSP文件。
  • 将JSP文件转为servlet。
  • 编译servlet。

JSP初始化

容器载入JSP文件后,它会在为请求提供任何服务前调用jspInit()方法。如果您需要执行自定义的JSP初始化任务,复写jspInit()方法就行了,就像下面这样:

1
2
3
public void jspInit(){
// 初始化代码
}

一般来讲程序只初始化一次,servlet也是如此。通常情况下您可以在jspInit()方法中初始化数据库连接、打开文件和创建查询表。


JSP执行

这一阶段描述了JSP生命周期中一切与请求相关的交互行为,直到被销毁。

当JSP网页完成初始化后,JSP引擎将会调用_jspService()方法。

_jspService()方法需要一个HttpServletRequest对象和一个HttpServletResponse对象作为它的参数,就像下面这样:

1
2
3
4
5
void _jspService(HttpServletRequest request,
HttpServletResponse response)
{
// 服务端处理代码
}

_jspService()方法在每个request中被调用一次并且负责产生与之相对应的response,并且它还负责产生所有7个HTTP方法的回应,比如GET、POST、DELETE等等。


JSP清理

JSP生命周期的销毁阶段描述了当一个JSP网页从容器中被移除时所发生的一切。

jspDestroy()方法在JSP中等价于servlet中的销毁方法。当您需要执行任何清理工作时复写jspDestroy()方法,比如释放数据库连接或者关闭文件夹等等。

jspDestroy()方法的格式如下:

1
2
3
4
public void jspDestroy()
{
// 清理代码
}

JSP 语法

##基础语法

1
<% 代码片段 %>

效果等同于

1
2
3
<jsp:scriptlet>
代码片段
</jsp:scriptlet>

输出

1
2
3
<%
out.println("Your IP address is " + request.getRemoteAddr());
%>

中文编码

1
2
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

声明变量

1
2
3
<%! int i = 0; %> 
<%! int a, b, c; %>
<%! Circle a = new Circle(2.0); %>
1
2
3
<jsp:declaration>
代码片段
</jsp:declaration>

JSP 表达式

先被转化成String,然后插入到表达式出现的地方。

表达式元素中可以包含任何符合Java语言规范的表达式,但是不能使用分号来结束表达式。

1
<%= 表达式 %>
1
2
3
<jsp:expression>
表达式
</jsp:expression>

JSP 注释

1
<%-- 该部分注释在网页中不会被显示--%>

HTML 注释

1
2
> <!-- 注释 -->
>

JSP 指令

JSP指令用来设置与整个JSP页面相关的属性。

1
<%@ directive attribute="value" %>

这里有三种指令标签:

指令 描述
<%@ page … %> 定义页面的依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include … %> 包含其他文件
<%@ taglib … %> 引入标签库的定义,可以是自定义标签

JSP 行为

JSP行为标签使用XML语法结构来控制servlet引擎。它能够动态插入一个文件,重用JavaBean组件,引导用户去另一个页面,为Java插件产生相关的HTML等等。

1
<jsp:action_name attribute="value" />
语法 描述
jsp:include 用于在当前页面中包含静态或动态资源
jsp:useBean 寻找和初始化一个JavaBean组件
jsp:setProperty 设置 JavaBean组件的值
jsp:getProperty 将 JavaBean组件的值插入到 output中
jsp:forward 从一个JSP文件向另一个文件传递一个包含用户请求的request对象
jsp:plugin 用于在生成的HTML页面中包含Applet和JavaBean对象
jsp:element 动态创建一个XML元素
jsp:attribute 定义动态创建的XML元素的属性
jsp:body 定义动态创建的XML元素的主体
jsp:text 用于封装模板数据

JSP 对象

对象 描述
request HttpServletRequest类的实例
response HttpServletResponse类的实例
out PrintWriter类的实例,用于把结果输出至网页上
session HttpSession类的实例
application ServletContext类的实例,与应用上下文有关
config ServletConfig类的实例
pageContext PageContext类的实例,提供对JSP页面所有对象以及命名空间的访问
page 类似于Java类中的this关键字
Exception Exception类的对象,代表发生错误的JSP页面中对应的异常对象

控制流语句

同 Java

判断语句

if…else…

1
2
3
4
5
6
7
<%! int day = 3; %> 
<h3>IF...ELSE 实例</h3>
<% if (day == 1 | day == 7) { %>
<p>今天是周末</p>
<% } else { %>
<p>今天不是周末</p>
<% } %>

switch

1
2
3
4
5
6
7
8
9
10
11
12
<%! int day = 3; %> 
<%
switch(day) {
case 0:
out.println("星期天");
break;
case 1:
...
default:
out.println("星期六");
}
%>

循环语句

可以使用Java的三个基本循环类型:for,while,和 do…while

1
2
3
4
5
6
7
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%! int fontSize; %>
<h3>For 循环实例</h3>
<% for ( fontSize = 1; fontSize <= 3; fontSize++){ %>
<font color="green" size="<%= fontSize %>">菜鸟教程</font><br />
<% } %>
运行结果
运行结果

JSP 运算符

JSP支持所有Java逻辑和算术运算符。

JSP 字面量

  • 布尔值(boolean):true 和 false;
  • 整型(int):与 Java 中的一样;
  • 浮点型(float):与 Java 中的一样;
  • 字符串(string):以单引号或双引号开始和结束;
  • Null:null。

JSP 指令

JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言。

1
<%@ directive attribute="value" %>

Page 指令

Page指令为容器提供当前页面的使用说明。一个JSP页面可以包含多个page指令。

1
<%@ page attribute="value" %>

等价的XML格式:

1
<jsp:directive.page attribute="value" />

下表列出与Page指令相关的属性:

属性 描述
buffer 指定out对象使用缓冲区的大小
autoFlush 控制out对象的 缓存区
contentType 指定当前JSP页面的MIME类型和字符编码
errorPage 指定当JSP页面发生异常时需要转向的错误处理页面
isErrorPage 指定当前页面是否可以作为另一个JSP页面的错误处理页面
extends 指定servlet从哪一个类继承
import 导入要使用的Java类
info 定义JSP页面的描述信息
isThreadSafe 指定对JSP页面的访问是否为线程安全
language 定义JSP页面所用的脚本语言,默认是Java
session 指定JSP页面是否使用session
isELIgnored 指定是否执行EL表达式
isScriptingEnabled 确定脚本元素能否被使用

Include指令

JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。

1
<%@ include file="文件相对 url 地址" %>
1
<jsp:directive.include file="文件相对 url 地址" />

Taglib指令

JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合。

Taglib指令引入一个自定义标签集合的定义,包括库路径、自定义标签。

1
<%@ taglib uri="uri" prefix="prefixOfTag" %>

uri属性确定标签库的位置,prefix属性指定标签库的前缀。

1
<jsp:directive.taglib uri="uri" prefix="prefixOfTag" />

JSP 动作元素

与JSP指令元素不同的是,JSP动作元素在请求处理阶段起作用。JSP动作元素是用XML语法写成的。

利用JSP动作可以动态地插入文件、重用JavaBean组件、把用户重定向到另外的页面、为Java插件生成HTML代码。

动作元素只有一种语法,它符合XML标准:

1
<jsp:action_name attribute="value" />

<jsp:include>动作元素

<jsp:include>动作元素用来包含静态和动态的文件。该动作把指定文件插入正在生成的页面。语法格式如下:

1
<jsp:include page="相对 URL 地址" flush="true" />

flush:布尔属性,定义在包含资源前是否刷新缓存区。

前面已经介绍过include指令,它是在JSP文件被转换成Servlet的时候引入文件,而这里的jsp:include动作不同,插入文件的时间是在页面被请求的时候。

实例

date.jsp文件代码:

1
2
3
4
5
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<p>
今天的日期是: <%= (new java.util.Date()).toLocaleString()%>
</p>

main.jsp文件代码:

1
2
3
4
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h2>include 动作实例</h2>
<jsp:include page="date.jsp" flush="true" />

运行结果

1
今天的日期是: 2016-6-25 14:08:17

<jsp:useBean>动作元素

jsp:useBean 动作用来加载一个将在JSP页面中使用的JavaBean,使得我们可以发挥 Java 组件复用的优势。

1
<jsp:useBean id="name" class="package.class" />

在类载入后,我们既可以通过 jsp:setProperty 和 jsp:getProperty 动作来修改和检索bean的属性。

属性 描述
class 指定Bean的完整包名。
type 指定将引用该对象变量的类型。
beanName 通过 java.beans.Beans 的 instantiate() 方法指定Bean的名字。

<jsp:setProperty>动作元素

jsp:setProperty用来设置已经实例化的Bean对象的属性,有两种用法。

首先,你可以在jsp:useBean元素的外面(后面)使用jsp:setProperty,如下所示:

1
2
3
<jsp:useBean id="myName" ... />
...
<jsp:setProperty name="myName" property="someProperty" .../>

此时,不管jsp:useBean是找到了一个现有的Bean,还是新创建了一个Bean实例,jsp:setProperty都会执行。


第二种用法是把jsp:setProperty放入jsp:useBean元素的内部,如下所示:

1
2
3
4
<jsp:useBean id="myName" ... >
...
<jsp:setProperty name="myName" property="someProperty" .../>
</jsp:useBean>

此时,jsp:setProperty只有在新建Bean实例时才会执行,如果是使用现有实例则不执行jsp:setProperty。

jsp:setProperty动作有下面四个属性,如下表:

属性 描述
name 必需。它表示要设置属性的是哪个Bean。
property 必需。它表示要设置哪个属性。有一个特殊用法:如果property的值是”*”,表示所有名字和Bean属性名字匹配的请求参数都将被传递给相应的属性set方法。
value 可选。该属性用来指定Bean属性的值。value和param不能同时使用,但可以使用其中任意一个。
param 可选。它指定用哪个请求参数作为Bean属性的值。如果当前请求没有参数,则什么事情也不做,系统不会把null传递给Bean属性的set方法。因此,你可以让Bean自己提供默认属性值,只有当请求参数明确指定了新值时才修改默认属性值。

<jsp:getProperty>动作元素

jsp:getProperty动作提取指定Bean属性的值,转换成字符串,然后输出。语法格式如下:

1
2
3
<jsp:useBean id="myName" ... />
...
<jsp:getProperty name="myName" property="someProperty" .../>
实例

使用 Bean

1
2
3
4
5
6
7
8
9
10
11
12
package com.runoob.main;

public class TestBean {
private String message = "菜鸟教程";

public String getMessage() {
return(message);
}
public void setMessage(String message) {
this.message = message;
}
}

编译以上实例文件 TestBean.java :

1
$ javac TestBean.java

在main.jsp文件中调用该Bean:

1
2
3
4
5
6
7
8
9
10
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h2>Jsp 使用 JavaBean 实例</h2>
<jsp:useBean id="test" class="com.runoob.main.TestBean" />

<jsp:setProperty name="test" property="message" value="菜鸟教程..." />

<p>输出信息....</p>

<jsp:getProperty name="test" property="message" />

运行结果

1
2
输出信息...
菜鸟教程...

<jsp:forward> 动作元素

jsp:forward动作把请求转到另外的页面。

1
<jsp:forward page="相对 URL 地址" />

page属性包含的是一个相对URL。page的值既可以直接给出,也可以在请求的时候动态计算,可以是一个JSP页面或者一个 Java Servlet.

<jsp:plugin>动作元素

jsp:plugin动作用来根据浏览器的类型,插入通过Java插件 运行Java Applet所必需的OBJECT或EMBED元素。

如果需要的插件不存在,它会下载插件,然后执行Java组件。 Java组件可以是一个applet或一个JavaBean。

plugin动作有多个对应HTML元素的属性用于格式化Java 组件。param元素可用于向Applet 或 Bean 传递参数。

1
2
3
4
5
6
7
8
9
10
<jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
width="60" height="80">
<jsp:param name="fontcolor" value="red" />
<jsp:param name="background" value="black" />

<jsp:fallback>
Unable to initialize Java Plugin
</jsp:fallback>

</jsp:plugin>

如果你有兴趣可以尝试使用applet来测试jsp:plugin动作元素,<fallback>元素是一个新元素,在组件出现故障的错误时发送给用户错误信息。

<jsp:element><jsp:attribute><jsp:body>动作元素

<jsp:element><jsp:attribute><jsp:body>动作元素动态定义XML元素。动态是非常重要的,这就意味着XML元素在编译时是动态生成的而非静态。

实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<jsp:element name="xmlElement">
<jsp:attribute name="xmlElementAttr">
属性值
</jsp:attribute>
<jsp:body>
XML 元素的主体
</jsp:body>
</jsp:element>
</body>
</html>

运行结果

运行结果
运行结果

<jsp:text>动作元素

<jsp:text>动作元素允许在JSP页面和文档中使用写入文本的模板,语法格式如下:

1
<jsp:text>模板数据</jsp:text>

以上文本模板不能包含其他元素,只能只能包含文本和EL表达式(注:EL表达式将在后续章节中介绍)。请注意,在XML文件中,您不能使用表达式如 ${whatever > 0},因为>符号是非法的。 你可以使用 ${whatever gt 0}表达式或者嵌入在一个CDATA部分的值。

1
<jsp:text><![CDATA[<br>]]></jsp:text>

如果你需要在 XHTML 中声明 DOCTYPE,必须使用到<jsp:text>动作元素,实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<jsp:text><![CDATA[<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">]]>
</jsp:text>
<head><title>jsp:text action</title></head>
<body>

<books><book><jsp:text>
Welcome to JSP Programming
</jsp:text></book></books>

</body>
</html>

你可以对以上实例尝试使用<jsp:text>及不使用该动作元素执行结果的区别。

JSP 隐式对象

JSP隐式对象是JSP容器为每个页面提供的Java对象,开发者可以直接使用它们而不用显式声明。JSP隐式对象也被称为预定义变量。

request对象

request对象是javax.servlet.http.HttpServletRequest 类的实例。每当客户端请求一个JSP页面时,JSP引擎就会制造一个新的request对象来代表这个请求。

request对象提供了一系列方法来获取HTTP头信息,cookies,HTTP方法等等。

response对象

response对象是javax.servlet.http.HttpServletResponse类的实例。当服务器创建request对象时会同时创建用于响应这个客户端的response对象。

response对象也定义了处理HTTP头模块的接口。通过这个对象,开发者们可以添加新的cookies,时间戳,HTTP状态码等等。

out对象

out对象是 javax.servlet.jsp.JspWriter 类的实例,用来在response对象中写入内容。

最初的JspWriter类对象根据页面是否有缓存来进行不同的实例化操作。可以在page指令中使用buffered=’false’属性来轻松关闭缓存。

JspWriter类包含了大部分java.io.PrintWriter类中的方法。不过,JspWriter新增了一些专为处理缓存而设计的方法。还有就是,JspWriter类会抛出IOExceptions异常,而PrintWriter不会。

下表列出了我们将会用来输出boolean,char,int,double,String,object等类型数据的重要方法:

方法 描述
out.print(dataType dt) 输出Type类型的值
out.println(dataType dt) 输出Type类型的值然后换行
out.flush() 刷新输出流

session对象

session对象是 javax.servlet.http.HttpSession 类的实例。和Java Servlets中的session对象有一样的行为。

session对象用来跟踪在各个客户端请求间的会话。

application对象

application对象直接包装了servlet的ServletContext类的对象,是javax.servlet.ServletContext 类的实例。

这个对象在JSP页面的整个生命周期中都代表着这个JSP页面。这个对象在JSP页面初始化时被创建,随着jspDestroy()方法的调用而被移除。

通过向application中添加属性,则所有组成您web应用的JSP文件都能访问到这些属性。

config对象

config对象是 javax.servlet.ServletConfig 类的实例,直接包装了servlet的ServletConfig类的对象。

这个对象允许开发者访问Servlet或者JSP引擎的初始化参数,比如文件路径等。

以下是config对象的使用方法,不是很重要,所以不常用:

1
config.getServletName();

它返回包含在<servlet-name>元素中的servlet名字,注意,<servlet-name>元素在 WEB-INF\web.xml 文件中定义。

pageContext 对象

pageContext对象是javax.servlet.jsp.PageContext 类的实例,用来代表整个JSP页面。

这个对象主要用来访问页面信息,同时过滤掉大部分实现细节。

这个对象存储了request对象和response对象的引用。application对象,config对象,session对象,out对象可以通过访问这个对象的属性来导出。

pageContext对象也包含了传给JSP页面的指令信息,包括缓存信息,ErrorPage URL,页面scope等。

PageContext类定义了一些字段,包括PAGE_SCOPE,REQUEST_SCOPE,SESSION_SCOPE, APPLICATION_SCOPE。它也提供了40余种方法,有一半继承自javax.servlet.jsp.JspContext 类。

其中一个重要的方法就是removeArribute(),它可接受一个或两个参数。比如,pageContext.removeArribute(“attrName”)移除四个scope中相关属性,但是下面这种方法只移除特定scope中的相关属性:

1
pageContext.removeAttribute("attrName", PAGE_SCOPE);

page 对象

这个对象就是页面实例的引用。它可以被看做是整个JSP页面的代表。

page 对象就是this对象的同义词。

exception 对象

exception 对象包装了从先前页面中抛出的异常信息。它通常被用来产生对出错条件的适当响应。

JSP 响应

JSP 客户端请求

下表列出了浏览器端信息头的一些重要内容:

信息 描述
Accept 指定浏览器或其他客户端可以处理的MIME类型。它的值通常为 image/pngimage/jpeg
Accept-Charset 指定浏览器要使用的字符集。比如 ISO-8859-1
Accept-Encoding 指定编码类型。它的值通常为 gzipcompress
Accept-Language 指定客户端首选语言,servlet会优先返回以当前语言构成的结果集,如果servlet支持这种语言的话。比如 en,en-us,ru等等
Authorization 在访问受密码保护的网页时识别不同的用户
Connection 表明客户端是否可以处理HTTP持久连接。持久连接允许客户端或浏览器在一个请求中获取多个文件。Keep-Alive 表示启用持久连接
Content-Length 仅适用于POST请求,表示 POST 数据的字节数
Cookie 返回先前发送给浏览器的cookies至服务器
Host 指出原始URL中的主机名和端口号
If-Modified-Since 表明只有当网页在指定的日期被修改后客户端才需要这个网页。 服务器发送304码给客户端,表示没有更新的资源
If-Unmodified-Since 与If-Modified-Since相反, 只有文档在指定日期后仍未被修改过,操作才会成功
Referer 标志着所引用页面的URL。比如,如果你在页面1,然后点了个链接至页面2,那么页面1的URL就会包含在浏览器请求页面2的信息头中
User-Agent 用来区分不同浏览器或客户端发送的请求,并对不同类型的浏览器返回不同的内容

HttpServletRequest类

request对象是javax.servlet.http.HttpServletRequest类的实例。每当客户端请求一个页面时,JSP引擎就会产生一个新的对象来代表这个请求。

request对象提供了一系列方法来获取HTTP信息头,包括表单数据,cookies,HTTP方法等等。

一些在JSP编程中常用的获取HTTP信息头的方法:

序号 方法 & 描述
1 Cookie[] getCookies()
返回客户端所有的Cookie的数组
2 Enumeration getAttributeNames()
返回request对象的所有属性名称的集合
3 Enumeration getHeaderNames()
返回所有HTTP头的名称集合
4 Enumeration getParameterNames()
返回请求中所有参数的集合
5 HttpSession getSession()
返回request对应的session对象,如果没有,则创建一个
6 HttpSession getSession(boolean create)
返回request对应的session对象,如果没有并且参数create为true,则返回一个新的session对象
7 Locale getLocale()
返回当前页的Locale对象,可以在response中设置
8 Object getAttribute(String name)
返回名称为name的属性值,如果不存在则返回null。
9 ServletInputStream getInputStream()
返回请求的输入流
10 String getAuthType()
返回认证方案的名称,用来保护servlet,比如 “BASIC” 或者 “SSL” 或 null 如果 JSP没设置保护措施
11 String getCharacterEncoding()
返回request的字符编码集名称
12 String getContentType()
返回request主体的MIME类型,若未知则返回null
13 String getContextPath()
返回request URI中指明的上下文路径
14 String getHeader(String name)
返回name指定的信息头
15 String getMethod()
返回此request中的HTTP方法,比如 GET,,POST,或PUT
16 String getParameter(String name)
返回此request中name指定的参数,若不存在则返回null
17 String getPathInfo()
返回任何额外的与此request URL相关的路径
18 String getProtocol()
返回此request所使用的协议名和版本
19 String getQueryString()
返回此 request URL包含的查询字符串
20 String getRemoteAddr()
返回客户端的IP地址
21 String getRemoteHost()
返回客户端的完整名称
22 String getRemoteUser()
返回客户端通过登录认证的用户,若用户未认证则返回null
23 String getRequestURI()
返回request的URI
24 String getRequestedSessionId()
返回request指定的session ID
25 String getServletPath()
返回所请求的servlet路径
26 String[] getParameterValues(String name)
返回指定名称的参数的所有值,若不存在则返回null
27 boolean isSecure()
返回request是否使用了加密通道,比如HTTPS
28 int getContentLength()
返回request主体所包含的字节数,若未知的返回-1
29 int getIntHeader(String name)
返回指定名称的request信息头的值
30 int getServerPort()
返回服务器端口号

HTTP信息头示例

在这个例子中,我们会使用HttpServletRequest类的getHeaderNames()方法来读取HTTP信息头。这个方法以枚举的形式返回当前HTTP请求的头信息。

获取Enumeration对象后,用标准的方式来遍历Enumeration对象,用hasMoreElements()方法来确定什么时候停止,用nextElement()方法来获得每个参数的名字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>

<h2>HTTP 头部请求实例</h2>

<table width="100%" border="1" align="center">
<tr bgcolor="#949494">
<th>Header Name</th><th>Header Value(s)</th>
</tr>
<%
Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String paramName = (String)headerNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");
String paramValue = request.getHeader(paramName);
out.println("<td> " + paramValue + "</td></tr>\n");
}
%>
</table>

访问main.jsp,将会得到以下结果:

img
img

JSP 服务器响应

Response响应对象主要将JSP容器处理后的结果传回到客户端。可以通过response变量设置HTTP的状态和向客户端发送数据,如Cookie、HTTP文件头信息等。

一个典型的响应看起来就像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Content-Type: text/html
Header2: ...
...
HeaderN: ...
(空行)
<!doctype ...>
<html>
<head>...</head>
<body>
...
</body>
</html>

状态行包含HTTP版本信息,比如HTTP/1.1,一个状态码,比如200,还有一个非常短的信息对应着状态码,比如OK。

下表摘要出了HTTP1.1响应头中最有用的部分:

响应头 描述
Allow 指定服务器支持的request方法(GET,POST等等)
Cache-Control 指定响应文档能够被安全缓存的情况。通常取值为 public****privateno-cache 等等。 Public意味着文档可缓存,Private意味着文档只为单用户服务并且只能使用私有缓存。No-cache 意味着文档不被缓存。
Connection 命令浏览器是否要使用持久的HTTP连接。close**值** 命令浏览器不使用持久HTTP连接,而keep-alive 意味着使用持久化连接。
Content-Disposition 让浏览器要求用户将响应以给定的名称存储在磁盘中
Content-Encoding 指定传输时页面的编码规则
Content-Language 表述文档所使用的语言,比如en, en-us,,ru等等
Content-Length 表明响应的字节数。只有在浏览器使用持久化 (keep-alive) HTTP 连接时才有用
Content-Type 表明文档使用的MIME类型
Expires 指明啥时候过期并从缓存中移除
Last-Modified 指明文档最后修改时间。客户端可以 缓存文档并且在后续的请求中提供一个 If-Modified-Since请求头
Location 在300秒内,包含所有的有一个状态码的响应地址,浏览器会自动重连然后检索新文档
Refresh 指明浏览器每隔多久请求更新一次页面。
Retry-After 与503 (Service Unavailable)一起使用来告诉用户多久后请求将会得到响应
Set-Cookie 指明当前页面对应的cookie

HttpServletResponse类

response 对象是 javax.servlet.http.HttpServletResponse 类的一个实例。就像服务器会创建request对象一样,它也会创建一个客户端响应。

response对象定义了处理创建HTTP信息头的接口。通过使用这个对象,开发者们可以添加新的cookie或时间戳,还有HTTP状态码等等。

下表列出了用来设置HTTP响应头的方法,这些方法由HttpServletResponse 类提供:

S.N. 方法 & 描述
1 String encodeRedirectURL(String url)
对sendRedirect()方法使用的URL进行编码
2 String encodeURL(String url)
将URL编码,回传包含Session ID的URL
3 boolean containsHeader(String name)
返回指定的响应头是否存在
4 boolean isCommitted()
返回响应是否已经提交到客户端
5 void addCookie(Cookie cookie)
添加指定的cookie至响应中
6 void addDateHeader(String name, long date)
添加指定名称的响应头和日期值
7 void addHeader(String name, String value)
添加指定名称的响应头和值
8 void addIntHeader(String name, int value)
添加指定名称的响应头和int值
9 void flushBuffer()
将任何缓存中的内容写入客户端
10 void reset()
清除任何缓存中的任何数据,包括状态码和各种响应头
11 void resetBuffer()
清除基本的缓存数据,不包括响应头和状态码
12 void sendError(int sc)
使用指定的状态码向客户端发送一个出错响应,然后清除缓存
13 void sendError(int sc, String msg)
使用指定的状态码和消息向客户端发送一个出错响应
14 void sendRedirect(String location)
使用指定的URL向客户端发送一个临时的间接响应
15 void setBufferSize(int size)
设置响应体的缓存区大小
16 void setCharacterEncoding(String charset)
指定响应的编码集(MIME字符集),例如UTF-8
17 void setContentLength(int len)
指定HTTP servlets中响应的内容的长度,此方法用来设置 HTTP Content-Length 信息头
18 void setContentType(String type)
设置响应的内容的类型,如果响应还未被提交的话
19 void setDateHeader(String name, long date)
使用指定名称和值设置响应头的名称和内容
20 void setHeader(String name, String value)
使用指定名称和值设置响应头的名称和内容
21 void setIntHeader(String name, int value)
使用指定名称和值设置响应头的名称和内容
22 void setLocale(Locale loc)
设置响应的语言环境,如果响应尚未被提交的话
23 void setStatus(int sc)
设置响应的状态码

HTTP响应头程序示例

自动刷新实例

接下来的例子使用setIntHeader()方法和setRefreshHeader()方法来模拟一个数字时钟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>

<!DOCTYPE html>
<html>
<body>
<h2>自动刷新实例</h2>
<%
// 设置每隔5秒自动刷新
response.setIntHeader("Refresh", 5);
// 获取当前时间
Calendar calendar = new GregorianCalendar();
String am_pm;
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
if(calendar.get(Calendar.AM_PM) == 0)
am_pm = "AM";
else
am_pm = "PM";
String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
out.println("当前时间: " + CT + "\n");
%>
</body>
</html>

它将会每隔5秒显示一下系统当前时间。

img
img

JSP HTTP 状态码

HTTP请求与HTTP响应的格式相近,都有着如下结构:

  • 以状态行+CRLF(回车换行)开始
  • 零行或多行头模块+CRLF
  • 一个空行,比如CRLF
  • 可选的消息体比如文件,查询数据,查询输出

一个服务器响应头看起来就像下面这样:

1
2
3
HTTP/1.1 200 OK
......
......

状态行包含HTTP版本,一个状态码,和状态码相对应的短消息。

状态码 消息 描述
100 Continue 只有一部分请求被服务器接收,但只要没被服务器拒绝,客户端就会延续这个请求
101 Switching Protocols 服务器交换机协议
200 OK 请求被确认
201 Created 请求时完整的,新的资源被创建
202 Accepted 请求被接受,但未处理完
203 Non-authoritative Information
204 No Content
205 Reset Content
206 Partial Content
300 Multiple Choices 一个超链接表,用户可以选择一个超链接并访问,最大支持5个超链接
301 Moved Permanently 被请求的页面已经移动到了新的URL下
302 Found 被请求的页面暂时性地移动到了新的URL下
303 See Other 被请求的页面可以在一个不同的URL下找到
304 Not Modified
305 Use Proxy
306 Unused 已经不再使用此状态码,但状态码被保留
307 Temporary Redirect 被请求的页面暂时性地移动到了新的URL下
400 Bad Request 服务器无法识别请求
401 Unauthorized 被请求的页面需要用户名和密码
402 Payment Required 目前还不能使用此状态码
403 Forbidden 禁止访问所请求的页面
404 Not Found 服务器无法找到所请求的页面
405 Method Not Allowed 请求中所指定的方法不被允许
406 Not Acceptable 服务器只能创建一个客户端无法接受的响应
407 Proxy Authentication Required 在请求被服务前必须认证一个代理服务器
408 Request Timeout 请求时间超过了服务器所能等待的时间,连接被断开
409 Conflict 请求有矛盾的地方
410 Gone 被请求的页面不再可用
411 Length Required “Content-Length”没有被定义,服务器拒绝接受请求
412 Precondition Failed 请求的前提条件被服务器评估为false
413 Request Entity Too Large 因为请求的实体太大,服务器拒绝接受请求
414 Request-url Too Long 服务器拒绝接受请求,因为URL太长。多出现在把”POST”请求转换为”GET”请求时所附带的大量查询信息
415 Unsupported Media Type 服务器拒绝接受请求,因为媒体类型不被支持
417 Expectation Failed
500 Internal Server Error 请求不完整,服务器遇见了出乎意料的状况
501 Not Implemented 请求不完整,服务器不提供所需要的功能
502 Bad Gateway 请求不完整,服务器从上游服务器接受了一个无效的响应
503 Service Unavailable 请求不完整,服务器暂时重启或关闭
504 Gateway Timeout 网关超时
505 HTTP Version Not Supported 服务器不支持所指定的HTTP版本

设置HTTP状态码的方法

下表列出了HttpServletResponse 类中用来设置状态码的方法:

S.N. 方法 & 描述
1 public void setStatus ( int statusCode )
此方法可以设置任意的状态码。如果您的响应包含一个特殊的状态码和一个文档,请确保在用PrintWriter返回任何内容前调用setStatus方法
2 public void sendRedirect(String url)
此方法产生302响应,同时产生一个 Location 头告诉URL 一个新的文档
3 public void sendError(int code, String message)
此方法将一个状态码(通常为 404)和一个短消息,自动插入HTML文档中并发回给客户端

HTTP状态码程序示例

本例将会发送407错误码给浏览器,然后浏览器将会告诉您”Need authentication!!!”。

1
2
3
4
5
6
7
8
9
10
11
<html>
<head>
<title>Setting HTTP Status Code</title>
</head>
<body>
<%
// 设置错误代码,并说明原因
response.sendError(407, "Need authentication!!!" );
%>
</body>
</html>

访问以上JSP页面,将会得到以下结果:

js_http_status_codes
js_http_status_codes

JSP 表单

JSP 表单处理

浏览器中使用 GET 和 POST 方法向服务器提交数据。

GET 方法

GET方法将请求的编码信息添加在网址后面,网址与编码信息通过”?”号分隔。如下所示:

1
http://www.runoob.com/hello?key1=value1&key2=value2

GET方法是浏览器默认传递参数的方法,一些敏感信息,如密码等建议不使用GET方法。

用get时,传输数据的大小有限制 (注意不是参数的个数有限制),最大为1024字节。

POST 方法

一些敏感信息,如密码等我们可以通过POST方法传递,POST提交数据是隐式的。

POST提交数据是不可见的,GET是通过在url里面传递的(可以看一下你浏览器的地址栏)。

JSP使用getParameter()来获得传递的参数,getInputStream()方法用来处理客户端的二进制数据流的请求。


JSP 读取表单数据

  • getParameter(): 使用 request.getParameter() 方法来获取表单参数的值。
  • getParameterValues(): 获得如checkbox类(名字相同,但值有多个)的数据。 接收数组变量 ,如checkbox类型
  • getParameterNames():该方法可以取得所有变量的名称,该方法返回一个Emumeration。
  • getInputStream():调用此方法来读取来自客户端的二进制数据流。

GET 实例

URL:http://localhost:8080/testjsp/main.jsp?name=小白&url=http://www.baidu.com

读取 name 表单:

1
2
名字:<%= request.getParameter("name")%> <br />
网址:<%= request.getParameter("url")%>

运行结果:

1
2
名字:小白
网址:http://www.baidu.com

POST 实例

1
2
3
4
5
6
<%  // 解决中文乱码的问题
String name = new String((request.getParameter("name")).getBytes("ISO-8859-1"),"UTF-8");
%>
名字:<%=name%>

网址:<%= request.getParameter("url")%>

使用 new String((request.getParameter(“name”)).getBytes(“ISO-8859-1”),”UTF-8”)来转换编码,防止中文乱码的发生。

传递 CHeckbox 实例

HTML 代码:

1
<input type="checkbox" name="cb" checked="checked" />

JSP代码:

1
2
<b>是否选中:</b>
<%= request.getParameter("cb")%>

运行结果:

1
on

读取所有表单参数

使用 HttpServletRequestgetParameterNames() 来读取所有表单参数,该方法可以取得所有变量的名称,该方法返回一个枚举。

有了一个 Enumeration(枚举),就可以调用 hasMoreElements() 方法来确定是否还有元素,以及使用nextElement()方法来获得每个参数的名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<table width="100%" border="1" align="center">
<tr bgcolor="#949494">
<th>参数名</th><th>参数值</th>
</tr>
<%
Enumeration paramNames = request.getParameterNames();

while(paramNames.hasMoreElements()) {
String paramName = (String)paramNames.nextElement();
out.print("<tr><td>" + paramName + "</td>\n");
String paramValue = request.getParameter(paramName);
out.println("<td> " + paramValue + "</td></tr>\n");
}
%>
</table>
运行结果
运行结果

JSP 过滤器

过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。

Servlet 过滤器方法

过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:

序号 方法 & 描述
1 public void doFilter (ServletRequest, ServletResponse, FilterChain)
该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
2 public void init(FilterConfig filterConfig)
web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
3 public void destroy()
Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

FilterConfig 使用

Filter 的 init 方法中提供了一个 FilterConfig 对象。

如 web.xml 文件配置如下:

1
2
3
4
5
6
7
8
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>菜鸟教程</param-value>
</init-param>
</filter>

在 init 方法使用 FilterConfig 对象获取参数:

1
2
3
4
5
6
public void  init(FilterConfig config) throws ServletException {
// 获取初始化参数
String site = config.getInitParameter("Site");
// 输出初始化参数
System.out.println("网站名称: " + site);
}

JSP 过滤器实例

https://www.runoob.com/jsp/jsp-writing-filters.html

使用多个过滤器

网址同上

JSP Cookie 处理需要对中文进行编码与解码,方法如下:

1
2
String str = java.net.URLEncoder.encode("中文""UTF-8"); //编码
String str = java.net.URLDecoder.decode("编码后的字符串","UTF-8"); // 解码

HTTP 信息头

1
2
3
4
5
6
7
HTTP/1.1 200 OK
Date: Fri, 04 Feb 2015 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=runoob; expires=Friday, 04-Feb-07 22:03:38 GMT;
path=/; domain=runoob.com
Connection: close
Content-Type: text/html
序号 方法 & 描述
1 public void setDomain(String pattern)
设置cookie的域名,比如 runoob.com
2 public String getDomain()
获取cookie的域名,比如 runoob.com
3 public void setMaxAge(int expiry)
设置cookie有效期,以秒为单位,默认有效期为当前session的存活时间
4 public int getMaxAge()
获取cookie有效期,以秒为单位,默认为-1 ,表明cookie会活到浏览器关闭为止
5 public String getName()
返回 cookie的名称,名称创建后将不能被修改
6 public void setValue(String newValue)
设置 cookie的值
7 public String getValue()
获取cookie的值
8 public void setPath(String uri)
设置cookie 的路径,默认为当前页面目录下的所有URL,还有此目录下的所有子目录
9 public String getPath()
获取cookie 的路径
10 public void setSecure(boolean flag)
指明cookie是否要加密传输
11 public void setComment(String purpose)
设置注释描述 cookie的目的。当浏览器将cookie展现给用户时,注释将会变得非常有用
12 public String getComment()
返回描述cookie目的的注释,若没有则返回null

使用JSP设置cookie包含三个步骤:

*(1)创建一个Cookie对象: *调用Cookie的构造函数,使用一个cookie名称和值做参数,它们都是字符串。

1
Cookie cookie = new Cookie("key","value");

请务必牢记,名称和值中都不能包含空格或者如下的字符:

1
[ ] ( ) = , " / ? @ : ;

(2) 设置有效期:调用setMaxAge()函数表明cookie在多长时间(以秒为单位)内有效。下面的操作将有效期设为了24小时。

1
cookie.setMaxAge(60*60*24);

(3) 将cookie发送至HTTP响应头中:调用response.addCookie()函数来向HTTP响应头中添加cookie。

1
response.addCookie(cookie);

Cookie 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
// 读取表单提交的 name 内容,并解决中文乱码
String str = URLEncoder.encode(request.getParameter("name"),"utf-8");
// 设置 name cookie
Cookie name = new Cookie("name", str);、

// 设置cookie过期时间为24小时。
name.setMaxAge(60*60*24);

// 在响应头部添加cookie
response.addCookie( name );
%>
<p>名字: <%= request.getParameter("name")%></p>

调用request.getCookies()方法来获得一个javax.servlet.http.Cookie对象的数组,然后遍历这个数组,使用getName()方法和getValue()方法来获取每一个cookie的名称和值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.net.*" %>
<%
Cookie cookie = null;
Cookie[] cookies = null;
// 获取cookies的数据,是一个数组
cookies = request.getCookies();
if( cookies != null ){
for (int i = 0; i < cookies.length; i++)
{
cookie = cookies[i];

out.print("参数名 : " + cookie.getName() + "<br>");
out.print("参数值: " + URLDecoder.decode(cookie.getValue(), "utf-8") +" <br>");
}
}
%>

将cookie的有效期设置为0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%
Cookie cookie = null;
Cookie[] cookies = null;
// 获取当前域名下的cookies,是一个数组
cookies = request.getCookies();
if( cookies != null )
{
for (int i = 0; i < cookies.length; i++)
{
cookie = cookies[i];
// 确保存在 Cookie
if((cookie.getName()).compareTo("name") == 0 )
{
cookie.setMaxAge(0);
response.addCookie(cookie);
break;
}
}
}
%>

JSP Session

有三种方法来维持客户端与服务器的会话:

Cookies

网络服务器可以指定一个唯一的session ID作为cookie来代表每个客户端,用来识别这个客户端接下来的请求。(很多时候浏览器并不一定支持cookie,所以不建议)

隐藏表单域

一个网络服务器可以发送一个隐藏的HTML表单域和一个唯一的session ID

1
<input type="hidden" name="sessionid" value="12345">

当表单被提交时,指定的名称和值将会自动包含在GET或POST数据中。每当浏览器发送一个请求,session_id的值就可以用来保存不同浏览器的轨迹。

可能比较有效,但是点击<A HREF>标签中的超链接时不会产生表单提交事件,因此隐藏表单域也不支持通用会话跟踪。

重写URL

在每个URL后面添加一些额外的数据来区分会话,服务器能够根据这些数据来关联session标识符。

举例来说,http://w3cschool.cc/file.htm;sessionid=12345, session标识符为sessionid=12345,服务器可以用这个数据来识别客户端。

相比而言,重写URL是更好的方式,就算浏览器不支持cookies也能工作,但缺点是您必须为每个URL动态指定session ID,就算这是个简单的HTML页面。

session对象

默认情况下,JSP允许会话跟踪,一个新的HttpSession对象将会自动地为新的客户端实例化。禁止会话跟踪需要显式地关掉它,通过将page指令中session属性值设为false来实现,就像下面这样:

1
<%@ page session="false" %>

JSP引擎将隐含的session对象暴露给开发者。由于提供了session对象,开发者就可以方便地存储或检索数据。

ession对象的一些重要方法:

S.N. 方法 & 描述
1 public Object getAttribute(String name)
返回session对象中与指定名称绑定的对象,如果不存在则返回null
2 public Enumeration getAttributeNames()
返回session对象中所有的对象名称
3 public long getCreationTime()
返回session对象被创建的时间, 以毫秒为单位,从1970年1月1号凌晨开始算起
4 public String getId()
返回session对象的ID
5 public long getLastAccessedTime()
返回客户端最后访问的时间,以毫秒为单位,从1970年1月1号凌晨开始算起
6 public int getMaxInactiveInterval()
返回最大时间间隔,以秒为单位,servlet 容器将会在这段时间内保持会话打开
7 public void invalidate()
将session无效化,解绑任何与该session绑定的对象
8 public boolean isNew()
返回是否为一个新的客户端,或者客户端是否拒绝加入session
9 public void removeAttribute(String name)
移除session中指定名称的对象
10 public void setAttribute(String name, Object value)
使用指定的名称和值来产生一个对象并绑定到session中
11 public void setMaxInactiveInterval(int interval)
用来指定时间,以秒为单位,servlet容器将会在这段时间内保持会话有效

Session 实例

如何使用HttpSession对象来获取创建时间和最后一次访问时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<%
// 获取session创建时间
Date createTime = new Date(session.getCreationTime());
// 获取最后访问页面的时间
Date lastAccessTime = new Date(session.getLastAccessedTime());

String title = "再次访问";
Integer visitCount = new Integer(0);
String visitCountKey = new String("visitCount");
String userIDKey = new String("userID");
String userID = new String("ABCD");

// 检测网页是否由新的访问用户
if (session.isNew()){
title = "访问";
session.setAttribute(userIDKey, userID);
session.setAttribute(visitCountKey, visitCount);
} else {
visitCount = (Integer)session.getAttribute(visitCountKey);
if (visitCount == null) visitCount = 0; // 实测可能会是 null
visitCount++;
userID = (String)session.getAttribute(userIDKey);
session.setAttribute(visitCountKey, visitCount);
}
%>
  id   :<% out.print( session.getId()); %> <br />
 创建时间 :<% out.print(createTime); %> <br />
最后访问时间:<% out.print(lastAccessTime); %> <br />
 用户 ID  :<% out.print(userID); %> <br />
 访问次数 :<% out.print(visitCount); %>

删除 Session 数据

当处理完一个用户的会话数据后,您可以有如下选择:

  • 移除一个特定的属性:

    调用public void removeAttribute(String name) 方法来移除指定的属性。

  • 删除整个会话:

    调用public void invalidate() 方法来使整个session无效。

  • 设置会话有效期:

    调用 public void setMaxInactiveInterval(int interval) 方法来设置session超时。

  • 登出用户:

    支持servlet2.4版本的服务器,可以调用 logout()方法来登出用户,并且使所有相关的session无效。

  • 配置web.xml文件:

    如果使用的是Tomcat,可以向下面这样配置web.xml文件:

1
2
3
<session-config>
<session-timeout>15</session-timeout>
</session-config>

超时以分钟为单位,Tomcat中的默认的超时时间是30分钟。

Servlet中的getMaxInactiveInterval( ) 方法以秒为单位返回超时时间。如果在web.xml中配置的是15分钟,则getMaxInactiveInterval( ) 方法将会返回900。

JSP 文件上传

https://www.runoob.com/jsp/jsp-file-uploading.html

HTML 代码创建一个文件上传表单。以下几点需要注意:

  • 表单 method 属性应该设置为 POST 方法,不能使用 GET 方法。
  • 表单 enctype 属性应该设置为 multipart/form-data.
  • 表单 action 属性应该设置为在后端服务器上处理文件上传的 Servlet 文件。下面的实例使用了 UploadServlet Servlet 来上传文件。
  • 上传单个文件,您应该使用单个带有属性 type=”file” 的 <input …/> 标签。为了允许多个文件上传,请包含多个 name 属性值不同的 input 标签。输入标签具有不同的名称属性的值。浏览器会为每个 input 标签关联一个浏览按钮。

upload.jsp 文件代码如下:

1
2
3
4
5
6
7
8
9
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<form method="post" action="/TomcatTest/UploadServlet" enctype="multipart/form-data">
选择一个文件:<input type="file" name="uploadFile" />
<br/><br/>
<input type="submit" value="上传" />
</form>

编写后台 Servlet

见上方网址

message.jsp 文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传结果</title>
</head>
<body>
<center>
<h2>${message}</h2>
</center>
</body>
</html>

编译和运行 Servlet

编译上面的 Servlet UploadServlet,并在 web.xml 文件中创建所需的条目,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<servlet>
<display-name>UploadServlet</display-name>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.runoob.test.UploadServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/TomcatTest/UploadServlet</url-pattern>
</servlet-mapping>
</web-app>

JSP 功能

JSP 日期

第一个构造函数使用当前日期和时间来初始化对象。

1
Date()

第二个构造函数接受一个参数,这个参数表示从1970年1月1日凌晨至所要表示时间的毫秒数。

1
Date(long millisec)

获取Date对象后,您就能够使用下表列出的所有方法:

序号 方法 & 描述
1 boolean after(Date date)
如果比给定的日期晚,则返回true,否则返回false
2 boolean before(Date date)
如果比给定的日期早,则返回true,否则返回false
3 Object clone( )
获取当前对象的一个副本
4 int compareTo(Date date)
如果与给定日期相等,则返回0,如果比给定日期早,则返回一个负数,如果比给定日期晚,则返回一个正数
5 int compareTo(Object obj)
与 compareTo(Date) 方法相同,如果 obj 不是Date类或其子类的对象,抛出ClassCastException异常
6 boolean equals(Object date)
如果与给定日期相同,则返回true,否则返回false
7 long getTime( )
返回从1970年1月1日凌晨至此对象所表示时间的毫秒数
8 int hashCode( )
返回此对象的哈希码
9 void setTime(long time)
使用给定参数设置时间和日期,参数time表示从1970年1月1日凌晨至time所经过的毫秒数
10 String toString( )
将此对象转换为字符串并返回这个字符串

获取当前日期和时间

使用JSP编程可以很容易的获取当前日期和时间,使用Date对象的toString()方法

1
2
3
4
5
<%@ page import="java.util.*" %>
<%
Date date = new Date();
out.print( "<h2 align=\"center\">" +date.toString()+"</h2>");
%>

运行结果:

1
Sat Jun 25 17:54:34 CST 2016

日期比较

比较两个日期

  • 使用getTime()方法得到毫秒数,然后比较毫秒数就行了。
  • 使用before(),after(),equals()方法。比如,new Date(99,2,12).before(new Date(99,2,18))返回true。
  • 使用compareTo()方法,这个方法在Comparable接口中定义,在Date中实现。

使用SimpleDateFormat格式化日期

SimpleDateFormat使用一种地区敏感的方式来格式化和解析日期,它允许您使用自定义的模式来格式化日期和时间。

1
2
3
4
5
6
7
<%@ page import="java.io.*,java.util.*,javax.servlet.*,java.text.*" %>
<%
Date dNow = new Date( );
SimpleDateFormat ft =
new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
out.print( "<h2 align=\"center\">" + ft.format(dNow) + "</h2>");
%>

运行结果:

1
2016-06-25 17:57:53

SimpleDateFormat格式码

要指定模式字符串,需要使用下表列出的格式码:

字符 描述 示例
G 时代标识符 AD
y 4位数年份 2001
M July or 07
d 10
h 12小时制, A.M./P.M. (1~12) 12
H 24小时制 22
m 分钟 30
s 55
S 毫秒 234
E 星期 Tuesday
D 一年中的某天 360
F 一个月中某星期的某天 2 (second Wed. in July)
w 一年中的某星期 40
W 一个月中的某星期 1
a A.M./P.M. 标记 PM
k 一天中的某个小时 (1~24) 24
K 一天中的某个小时,A.M./P.M. (0~11) 10
z 时区 Eastern Standard Time
文本分隔 Delimiter
单引号 `

JSP 页面重定向

1
2
3
4
5
6
<%@ page import="java.io.*,java.util.*" %>
<%
String site = new String("http://www.runoob.com");
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", site);
%>

JSP 点击量统计

利用应用程序隐式对象和相关方法getAttribute()和setAttribute()来实现

在应用中创建变量的语法:

1
application.setAttribute(String Key, Object Value);

读取变量的方法如下:

1
application.getAttribute(String Key);

点击量统计实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>
<%
Integer hitsCount = (Integer)application.getAttribute("hitCounter");
if( hitsCount ==null || hitsCount == 0 )
{
/* 第一次访问 */
out.println("欢迎访问!");
hitsCount = 1;
}
else
{
/* 返回访问值 */
out.println("欢迎再次访问!");
hitsCount += 1;
}
application.setAttribute("hitCounter", hitsCount);
%>

<p>页面访问量为: <%= hitsCount%></p>

复位计数器

使用以上方法,在 web 服务器重启后,计数器会被复位为 0,即前面保留的数据都会消失。可以使用数据库或者文件来保存。

JSP 自动刷新

方法的签名如下:

1
public void setIntHeader(String header, int headerValue)

自动刷新实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*" %>

<%
// 设置每隔5秒刷新一次
response.setIntHeader("Refresh", 5);
// 获取当前时间
Calendar calendar = new GregorianCalendar();
String am_pm;
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
if(calendar.get(Calendar.AM_PM) == 0)
am_pm = "AM";
else
am_pm = "PM";
String CT = hour+":"+ minute +":"+ second +" "+ am_pm;
out.println("当前时间为: " + CT + "\n");
%>

运行结果:

1
当前时间为: 6:5:36 PM

JSP 发送邮件

https://www.runoob.com/jsp/jsp-sending-email.html

发送简单的邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<%@ page import="java.io.*,java.util.*,javax.mail.*"%>
<%@ page import="javax.mail.internet.*,javax.activation.*"%>
<%@ page import="javax.servlet.http.*,javax.servlet.*" %>

<%
String result;
// 收件人的电子邮件
String to = "abcd@gmail.com";

// 发件人的电子邮件
String from = "mcmohd@gmail.com";

// 假设你是从本地主机发送电子邮件
String host = "localhost";

// 获取系统属性对象
Properties properties = System.getProperties();

// 设置邮件服务器
properties.setProperty("mail.smtp.host", host);

// 获取默认的Session对象。
Session mailSession = Session.getDefaultInstance(properties);

try{
// 创建一个默认的MimeMessage对象。
MimeMessage message = new MimeMessage(mailSession);
// 设置 From: 头部的header字段
message.setFrom(new InternetAddress(from));
// 设置 To: 头部的header字段
message.addRecipient(Message.RecipientType.TO,
new InternetAddress(to));
// 设置 Subject: header字段
message.setSubject("This is the Subject Line!");
// 现在设置的实际消息
message.setText("This is actual message");
// 发送消息
Transport.send(message);
result = "Sent message successfully....";
}catch (MessagingException mex) {
mex.printStackTrace();
result = "Error: unable to send message....";
}
%>
<%
out.println("Result: " + result + "\n");
%>

发送给多人:

1
2
3
void addRecipients(Message.RecipientType type, 
Address[] addresses)
throws MessagingException

HTML 邮件、附件

见上方网址

JSP 高级教程

JSP 标准标签库(JSTL)

JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。

JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。

根据JSTL标签所提供的功能,可以将其分为5个类别。

  • 核心标签
  • 格式化标签
  • SQL 标签
  • XML 标签
  • JSTL 函数

JSTL 库安装

官方下载地址:http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/

标签库安装方法:https://www.runoob.com/jsp/jsp-jstl.html

核心标签

核心标签是最常用的JSTL标签。

1
2
<%@ taglib prefix="c" 
uri="http://java.sun.com/jsp/jstl/core" %>

所有标签库请访问上方的标签库网址。

格式化标签

用来格式化并输出文本、日期、时间、数字。

1
2
<%@ taglib prefix="fmt" 
uri="http://java.sun.com/jsp/jstl/fmt" %>

格式化标签

用来格式化并输出文本、日期、时间、数字。

1
2
<%@ taglib prefix="fmt" 
uri="http://java.sun.com/jsp/jstl/fmt" %>

SQL标签

提供了与关系型数据库(Oracle,MySQL,SQL Server等等)进行交互的标签。

1
2
<%@ taglib prefix="sql" 
uri="http://java.sun.com/jsp/jstl/sql" %>

XML 标签

提供了创建和操作XML文档的标签。

1
2
<%@ taglib prefix="x" 
uri="http://java.sun.com/jsp/jstl/xml" %>

JSTL函数

JSTL包含一系列标准函数,大部分是通用的字符串处理函数

1
2
<%@ taglib prefix="fn" 
uri="http://java.sun.com/jsp/jstl/functions" %>

JSP 数据库

jar 包下载地址:http://static.runoob.com/download/mysql-connector-java-5.1.39-bin.jar

下载后把 mysql-connector-java-5.1.39-bin.jar 拷贝到 tomcat 下 lib 目录。

创建测试数据

在 MySQL 中创建 RUNOOB 数据库,并创建 websites 数据表,表结构如下:

1
2
3
4
5
6
7
8
CREATE TABLE `websites` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(20) NOT NULL DEFAULT '' COMMENT '站点名称',
`url` varchar(255) NOT NULL DEFAULT '',
`alexa` int(11) NOT NULL DEFAULT '0' COMMENT 'Alexa 排名',
`country` char(10) NOT NULL DEFAULT '' COMMENT '国家',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

插入一些数据:

1
INSERT INTO `websites` VALUES ('1', 'Google', 'https://www.google.cm/', '1', 'USA'), ('2', '淘宝', 'https://www.taobao.com/', '13', 'CN'), ('3', '菜鸟教程', 'http://www.runoob.com', '5892', ''), ('4', '微博', 'http://weibo.com/', '20', 'CN'), ('5', 'Facebook', 'https://www.facebook.com/', '3', 'USA');

SELECT 操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.*,java.util.*,java.sql.*"%>
<%@ page import="javax.servlet.http.*,javax.servlet.*" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql"%>

<!--
JDBC 驱动名及数据库 URL
数据库的用户名与密码,需要根据自己的设置
useUnicode=true&characterEncoding=utf-8 防止中文乱码
-->
<sql:setDataSource var="snapshot" driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/RUNOOB?useUnicode=true&characterEncoding=utf-8"
user="root" password="123456"/>

<!-- 查询操作到 result -->
<sql:query dataSource="${snapshot}" var="result">
SELECT * from websites;
</sql:query>

<!-- 展示查询结果 -->
<c:forEach var="row" items="${result.rows}">
ID:<c:out value="${row.id}"/> <br />
站点名:<c:out value="${row.name}"/> <br />
站点地址:<c:out value="${row.url}"/> <br />
</c:forEach>

INSERT 操作

1
2
3
4
<!-- 插入数据 -->
<sql:update dataSource="${snapshot}" var="result">
INSERT INTO websites (name,url,alexa,country) VALUES ('昂昂', 'http://m.baidu.com', 5093, 'CN');
</sql:update>

DELETE 操作

1
2
3
4
5
<!-- 删除 ID 为 11 的数据 -->
<sql:update dataSource="${snapshot}" var="count">
DELETE FROM websites WHERE Id = ?
<sql:param value="${11}" />
</sql:update>

UPDATE 操作

1
2
3
4
5
6
7
<!-- 修改 ID 为 3 的名字为 RUNOOB -->
<c:set var="SiteId" value="3"/>

<sql:update dataSource="${snapshot}" var="count">
UPDATE websites SET name = 'RUNOOB' WHERE Id = ?
<sql:param value="${SiteId}" />
</sql:update>

JSP XML 数据处理

发送 XML

和发送 HTML 一样,但是需要把页面的context属性设置为text/xml

1
<%@ page contentType="text/xml" %>

处理 XML

需要将与XML 和XPath相关的两个库文件放在<Tomcat Installation Directory>\lib目录下:

books.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
<books>
<book>
<name>Padam History</name>
<author>ZARA</author>
<price>100</price>
</book>
<book>
<name>Great Mistry</name>
<author>NUHA</author>
<price>2000</price>
</book>
</books>

main.jsp文件:

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

<c:import var="bookInfo" url="http://localhost:8080/books.xml"/>
<x:parse xml="${bookInfo}" var="output"/>

<b>The title of the first book is</b>:
<x:out select="$output/books/book[1]/name" /> <br>
<b>The price of the second book</b>:
<x:out select="$output/books/book[2]/price" />

格式化 XML

这个是XSLT样式表style.xsl文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>

<xsl:template match="books">
<table border="1" width="100%">
<xsl:for-each select="book">
<tr>
<td>
<i><xsl:value-of select="name"/></i>
</td>
<td>
<xsl:value-of select="author"/>
</td>
<td>
<xsl:value-of select="price"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

这个是main.jsp文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>

<h3>Books Info:</h3>
<c:set var="xmltext">
<books>
<book>
<name>Padam History</name>
<author>ZARA</author>
<price>100</price>
</book>
<book>
<name>Great Mistry</name>
<author>NUHA</author>
<price>2000</price>
</book>
</books>
</c:set>

<c:import url="http://localhost:8080/style.xsl" var="xslt"/>
<x:transform xml="${xmltext}" xslt="${xslt}"/>

运行结果如下:

img
img

JavaBean

JavaBean是特殊的Java类,使用J ava语言书写,并且遵守JavaBean API规范。

JavaBean与其它Java类相比而言独一无二的特征:

  • 提供一个默认的无参构造函数。
  • 需要被序列化并且实现了Serializable接口。
  • 可能有一系列可读写属性。
  • 可能有一系列的”getter”或”setter”方法。

一个只读的属性只提供getPropertyName()方法,一个只写的属性只提供setPropertyName()方法。

访问 JavaBean

<jsp:useBean> 标签可以在JSP中声明一个JavaBean,然后使用。声明后,JavaBean对象就成了脚本变量,可以通过脚本元素或其他自定义标签来访问。

1
<jsp:useBean id="bean 的名字" scope="bean 的作用域" typeSpec/>

其中,根据具体情况,scope的值可以是page,request,session或application。id值可任意只要不和同一JSP文件中其它<jsp:useBean>中id值一样就行了。

1
2
3
4
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="date" class="java.util.Date" />
<p>日期为:<%= date %>

它将会产生如下结果:

1
日期为:Tue Jun 28 15:22:24 CST 2016

访问 JavaBean 对象的属性

<jsp:useBean> 标签主体中使用 <jsp:getProperty /> 标签来调用 getter 方法,使用 <jsp:setProperty /> 标签来调用 setter 方法,语法格式如下:

1
2
3
4
5
6
<jsp:useBean id="id" class="bean 编译的类" scope="bean 作用域">
<jsp:setProperty name="bean 的 id" property="属性名"
value="value"/>
<jsp:getProperty name="bean 的 id" property="属性名"/>
...........
</jsp:useBean>

name属性指的是Bean的id属性。property属性指的是想要调用的getter或setter方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>

<jsp:useBean id="students"
class="com.runoob.StudentsBean">
<jsp:setProperty name="students" property="firstName"
value="小强"/>
<jsp:setProperty name="students" property="lastName"
value="王"/>
<jsp:setProperty name="students" property="age"
value="10"/>
</jsp:useBean>

<p>名字:<jsp:getProperty name="students" property="firstName"/> </p>
<p>姓氏: <jsp:getProperty name="students" property="lastName"/></p>
<p>年龄: <jsp:getProperty name="students" property="age"/></p>

访问以上 JSP,运行结果如下:

1
2
3
名字: 小强
姓氏: 王
年龄: 10

自定义标签

创建 HELLO 标签

创建一个自定义标签叫作ex:Hello,标签格式为:

1
<ex:Hello />

要创建自定义的JSP标签,你首先必须创建处理标签的Java类。所以,让我们创建一个HelloTag类,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("Hello Custom Tag!");
}
}

以下代码重写了doTag()方法,方法中使用了getJspContext()方法来获取当前的JspContext对象,并将”Hello Custom Tag!”传递给JspWriter对象。

编译以上类,并将其复制到环境变量CLASSPATH目录中。最后创建如下标签库:<Tomcat安装目录>webapps\ROOT\WEB-INF\custom.tld

1
2
3
4
5
6
7
8
9
10
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>Example TLD</short-name>
<tag>
<name>Hello</name>
<tag-class>com.runoob.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>

接下来,可以在JSP文件中使用Hello标签:

1
2
<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<ex:Hello/>

以上程序输出结果为:

1
Hello Custom Tag!

访问标签体

1
2
3
<ex:Hello>
This is message body
</ex:Hello>

修改标签处理类文件,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

StringWriter sw = new StringWriter();
public void doTag() throws JspException, IOException {
getJspBody().invoke(sw);
getJspContext().getOut().println(sw.toString());
}

}

接下来我们需要修改TLD文件,如下所示:

1
2
3
4
5
6
7
8
9
10
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>Example TLD with Body</short-name>
<tag>
<name>Hello</name>
<tag-class>com.runoob.HelloTag</tag-class>
<body-content>scriptless</body-content>
</tag>
</taglib>

现在我们可以在JSP使用修改后的标签,如下所示:

1
2
3
4
<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<ex:Hello>
This is message body
</ex:Hello>

以上程序输出结果如下所示:

1
This is message body

自定义标签属性

自定义标签类必须实现setter方法, JavaBean 中的setter方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.runoob;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

private String message;

public void setMessage(String msg) {
this.message = msg;
}

StringWriter sw = new StringWriter();

public void doTag()
throws JspException, IOException
{
if (message != null) {
/* 从属性中使用消息 */
JspWriter out = getJspContext().getOut();
out.println( message );
}
else {
/* 从内容体中使用消息 */
getJspBody().invoke(sw);
getJspContext().getOut().println(sw.toString());
}
}

}

属性的名称是”message”,所以setter方法是的setMessage()。现在让我们在TLD文件中使用的<attribute>元素添加此属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>Example TLD with Body</short-name>
<tag>
<name>Hello</name>
<tag-class>com.runoob.HelloTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>message</name>
</attribute>
</tag>
</taglib>

现在我们就可以在JSP文件中使用message属性了,如下所示:

1
2
<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<ex:Hello message="This is custom tag" />

以上实例数据输出结果为:

1
This is custom tag

还可以包含以下属性:

属性 描述
name 定义属性的名称。每个标签的是属性名称必须是唯一的。
required 指定属性是否是必须的或者可选的,如果设置为false为可选。
rtexprvalue 声明在运行表达式时,标签属性是否有效。
type 定义该属性的Java类类型 。默认指定为 String
description 描述信息
fragment 如果声明了该属性,属性值将被视为一个 JspFragment

以下是指定相关的属性实例:

1
2
3
4
5
6
7
8
.....
<attribute>
<name>attribute_name</name>
<required>false</required>
<type>java.util.Date</type>
<fragment>false</fragment>
</attribute>
.....

如果你使用了两个属性,修改TLD文件,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
.....
<attribute>
<name>attribute_name1</name>
<required>false</required>
<type>java.util.Boolean</type>
<fragment>false</fragment>
</attribute>
<attribute>
<name>attribute_name2</name>
<required>true</required>
<type>java.util.Date</type>
</attribute>
.....

JSP 表达式语言

JSP表达式语言(EL)使得访问存储在JavaBean中的数据变得非常简单。JSP EL既可以用来创建算术表达式也可以用来创建逻辑表达式。在JSP EL表达式内可以使用整型数,浮点数,字符串,常量true、false,还有null。

一个简单的语法

典型的,在JSP标签中指定一个属性值,只需要简单地使用字符串即可:

1
<jsp:setProperty name="box" property="perimeter" value="${2*box.width+2*box.height}"/>

JSP EL允许指定一个表达式来表示属性值:

1
${expr}

其中,expr指的是表达式。在JSP EL中通用的操作符是 . 和 {} 。

当JSP编译器在属性中见到”${}”格式后,它会产生代码来计算这个表达式,并且产生一个替代品来代替表达式的值。

也可以在标签的模板文本中使用表达式语言。比如<jsp:text>标签简单地将其主体中的文本插入到JSP输出中:

1
2
3
<jsp:text>
Box Perimeter is: ${2*box.width + (1+2)*box.height}
</jsp:text>

想要停用对EL表达式的评估的话,需要使用page指令将isELIgnored属性值设为true:

1
<%@ page isELIgnored ="true|false" %>

这样,EL表达式就会被忽略。若设为false,则容器将会计算EL表达式。

EL中的基础操作符

EL表达式支持大部分Java所提供的算术和逻辑操作符:

操作符 描述
. 访问一个Bean属性或者一个映射条目
[] 访问一个数组或者链表的元素
( ) 组织一个子表达式以改变优先级
+
- 减或负
*
/ or div
% or mod 取模
== or eq 测试是否相等
!= or ne 测试是否不等
< or lt 测试是否小于
> or gt 测试是否大于
<= or le 测试是否小于等于
>= or ge 测试是否大于等于
&& or and 测试逻辑与
|| or or 测试逻辑或
! or not 测试取反
empty 测试是否空值

JSP EL中的函数

JSP EL允许您在表达式中使用函数。这些函数必须被定义在自定义标签库中。函数的使用语法如下:

1
${ns:func(param1, param2, ...)}

ns指的是命名空间(namespace),func指的是函数的名称,param1指的是第一个参数,param2指的是第二个参数,以此类推。比如,有函数fn:length,在JSTL库中定义,可以像下面这样来获取一个字符串的长度:

1
${fn:length("Get my length")}

要使用任何标签库中的函数,您需要将这些库安装在服务器中,然后使用<taglib>标签在JSP文件中包含这些库。

JSP EL隐含对象

JSP EL支持下表列出的隐含对象:

隐含对象 描述
pageScope page 作用域
requestScope request 作用域
sessionScope session 作用域
applicationScope application 作用域
param Request 对象的参数,字符串
paramValues Request对象的参数,字符串集合
header HTTP 信息头,字符串
headerValues HTTP 信息头,字符串集合
initParam 上下文初始化参数
cookie Cookie值
pageContext 当前页面的pageContext

可以在表达式中使用这些对象,就像使用变量一样。

pageContext对象

pageContext对象是JSP中pageContext对象的引用。通过pageContext对象,可以访问request对象。比如,访问request对象传入的查询字符串,就像这样:

1
${pageContext.request.queryString}

Scope对象

pageScope,requestScope,sessionScope,applicationScope变量用来访问存储在各个作用域层次的变量。

举例来说,如果需要显式访问在applicationScope层的box变量,可以这样来访问:applicationScope.box。

param和paramValues对象

param和paramValues 对象用来访问参数值,通过使用 request.getParameter 方法和 request.getParameterValues 方法。

举例来说,访问一个名为 order 的参数,可以这样使用表达式:${param.order},或者${param[“order”]}。

如何访问 request 中的 username 参数:

1
2
<%@ page import="java.io.*,java.util.*" %>
${param["username"]}

param 对象返回单一的字符串,而 paramValues 对象则返回一个字符串数组。

header和headerValues对象

header和headerValues对象用来访问信息头,通过使用 request.getHeader方法和request.getHeaders方法。

举例来说,要访问一个名为 user-agent 的信息头,可以这样使用表达式:${header.user-agent},或者 ${header[“user-agent”]}。

如何访问 user-agent 信息头:

1
2
<%@ page import="java.io.*,java.util.*" %>
${header["user-agent"]}

header对象返回单一值,而headerValues则返回一个字符串数组。

JSP 异常处理

JSP代码中通常有以下几类异常:

  • 检查型异常:检查型异常就是一个典型的用户错误或者一个程序员无法预见的错误。举例来说,如果一个文件将要被打开,但是无法找到这个文件,则一个异常被抛出。这些异常不能再编译期被简单地忽略。
  • 运行时异常:一个运行时异常可能已经被程序员避免,这种异常在编译期将会被忽略。
  • 错误:错误不是异常,但问题是它超出了用户或者程序员的控制范围。错误通常会在代码中被忽略,您几乎不能拿它怎么样。举例来说,栈溢出错误。这些错误都会在编译期被忽略。

使用 Exception 对象

exception对象是Throwable子类的一个实例,只在错误页面中可用。下表列出了Throwable类中一些重要的方法:

序号 方法 & 描述
1 public String getMessage()
返回异常的信息。这个信息在Throwable构造函数中被初始化
2 public ThrowablegetCause()
返回引起异常的原因,类型为Throwable对象
3 public String toString()
返回类名
4 public void printStackTrace()
将异常栈轨迹输出至System.err
5 public StackTraceElement [] getStackTrace()
以栈轨迹元素数组的形式返回异常栈轨迹
6 public ThrowablefillInStackTrace()
使用当前栈轨迹填充Throwable对象

JSP提供了可选项来为每个JSP页面指定错误页面。无论何时页面抛出了异常,JSP容器都会自动地调用错误页面。

接下来的例子为main.jsp指定了一个错误页面。使用<%@page errorPage=”XXXXX”%>指令指定一个错误页面。

1
2
3
4
5
6
7
8
9
<%@ page errorPage="ShowError.jsp" %>

<%
// Throw an exception to invoke the error page
if (1 == 1)
{
throw new RuntimeException("Error condition!!!");
}
%>

现在,编写ShowError.jsp文件如下:

1
2
3
4
5
6
7
8
9
10
11
<%@ page isErrorPage="true" %>
<html>
<head>
<title>Show Error Page</title>
</head>
<body>
<h1>Opps...</h1>
<p>Sorry, an error occurred.</p>
<p>Here is the exception stack trace: </p>
<pre>
<% exception.printStackTrace(response.getWriter()); %>

注意到,ShowError.jsp文件使用了<%@page isErrorPage=”true”%>指令,这个指令告诉JSP编译器需要产生一个异常实例变量。

现在试着访问main.jsp页面,它将会产生如下结果:

1
2
3
4
5
6
7
java.lang.RuntimeException: Error condition!!!
......

Opps...
Sorry, an error occurred.

Here is the exception stack trace:

在错误页面使用 JSTL 标签

可以利用JSTL标签来编写错误页面ShowError.jsp。这个例子中的代码与上例代码的逻辑几乎一样,但是本例的代码有更好的结构,并且能够提供更多信息:

1
2
3
4
5
6
7
8
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page isErrorPage="true" %>
Error: ${pageContext.exception} <br />
URI: ${pageContext.errorData.requestURI} <br />
Status code: ${pageContext.errorData.statusCode} <br />
<c:forEach var="trace" items="${pageContext.exception.stackTrace}">
${trace} <br />
</c:forEach>

运行结果如下:

jsp-exeception-1
jsp-exeception-1

使用 try … catch 块

如果您想要将异常处理放在一个页面中,并且对不同的异常进行不同的处理,那么您就需要使用try…catch块了。

1
2
3
4
5
6
7
8
9
10
<%
try{
int i = 1;
i = i / 0;
out.println("The answer is " + i);
}
catch (Exception e){
out.println("An exception occurred: " + e.getMessage());
}
%>

运行结果:

1
An exception occurred: / by zero

JSP 调试

System.out.println()

JDB Logger

J2SE日志框架可为任何运行在JVM中的类提供日志记录服务。因此我们可以利用这个框架来记录任何信息。

使用JDK中的 logger API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page import="java.util.logging.Logger" %>

<% Logger logger=Logger.getLogger(this.getClass().getName());%>

<c:forEach var="counter" begin="1" end="10" step="1" >
<c:set var="myCount" value="${counter-5}" />
<c:out value="${myCount}"/></br>
<% String message = "counter="
+ pageContext.findAttribute("counter")
+ " myCount="
+ pageContext.findAttribute("myCount");
logger.info( message );
%>
</c:forEach>

给出stdout.log文件中的一个快照:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=1 myCount=-4
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=2 myCount=-3
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=3 myCount=-2
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=4 myCount=-1
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=5 myCount=0
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=6 myCount=1
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=7 myCount=2
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=8 myCount=3
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=9 myCount=4
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService
INFO: counter=10 myCount=5

消息可以使用各种优先级发送,通过使用sever(),warning(),info(),config(),fine(),finer(),finest()方法。finest()方法用来记录最好的信息,而sever()方法用来记录最严重的信息。

使用Log4J 框架来将消息记录在不同的文件中,这些消息基于严重程度和重要性来进行分类。

调试工具

NetBeans是树形结构,是开源的Java综合开发环境,支持开发独立的Java应用程序和网络应用程序,同时也支持JSP调试。

NetBeans支持如下几个基本的调试功能:

  • 断点
  • 单步跟踪
  • 观察点

详细的信息可以查看NetBeans使用手册。

使用JDB Debugger

使用注释

浏览器开发者模式

JSP 国际化

https://www.runoob.com/jsp/jsp-internationalization.html

解释几个重要的概念:

  • 国际化(i18n):表明一个页面根据访问者的语言或国家来呈现不同的翻译版本。
  • 本地化(l10n):向网站添加资源,以使它适应不同的地区和文化。比如网站的印度语版本。
  • 区域:这是一个特定的区域或文化,通常认为是一个语言标志和国家标志通过下划线连接起来。比如”en_US”代表美国英语地区。

JSP容器能够根据request的locale属性来提供正确地页面版本。接下来给出了如何通过request对象来获得Locale对象的语法:

1
java.util.Locale request.getLocale()