1.JSP语句的生明
JSP的声明语句格式<%! %>,,要注意,凡是用JSP声明的变量或函数,在servlet容器翻译成servlet类时,都将其翻译为servlet类的成员变量或函数;当JSP文件被翻译成servlet类后进行实例化时,所有的客户端访问的实例化servlet对象都是同一个对象,这意味着,如果试图对成员变量进行操作,那么其影响可谓是全局性的。来看下下面实例:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<%!
private int count = 0;
public int getCount()
{
count ++ ;
return count;
}
%>
<body>
<%
out.println("the value of count is: " + getCount());
%>
</body>
</html>
这是一个简单的JSP程序,在第一次运行后,页面结果显示为:the value of count is: 1
而进行刷新页面时,每刷新一次,其count值都加1,显示结果也会改变:the value of count is: 2等等。
再从浏览器中看下HTLM源代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="http://jxpc-001:8080/MyTest/">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
the value of count is: 1
</body>
</html>
可以看到,凡是有关jsp声明相关的部分全部没有了,只剩下纯HTML代码。正好印证了前面一篇文章中所说过的话:
“容器会再加载service,这部分就是真正相应客户端请求的实现逻辑,它实现客户端的请求响应,然后动态生成HTML页面显示到客户端”
2.JSP的编译指令:include 和 page
至于上面的JSP文章中开头部分还有一行代码:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
这是一条编译指令,在JSP翻译成servlet类时,用来通知servlet容器的消息,以让其在翻译成servlet类时按照指定的额外要求进行翻译。
说到这,再来探讨下编译指令。常见的编译指令有3条:page(对当前页面的编译要求),include(包含其它页面),和tablib(自定义和访问),其声明方式为<%@ (指令) [属性 ="..." ] %>, 对于page指令,通常放在JSP文件开头处,一个JSP页面可出现多个page指令,如可将上面的page指令改为:
<%@ page language="java" import="java.util.*"% >
<%@ page pageEncoding="ISO-8859-1"%>
两行语句来代替,其效果相同。
而对于include指令,<%@ include %>,这是个静态包含语句,servlet容器在包含时对其内容不进行任何检测就将其包含,若其文件内容有误,也在包含进来后进行翻译的时候才检测其内容的正误,这一点与C++中的预编译指令#define有些像,#define只是进行简单的替换,至于其正误,在代码编译时才能检测出来,而在这里<% @ include %>也只是先进行简单的包含,对于其内容要一直等到编译为servlet类时进行检测。
另外编写一个JSP文件,其内容如下:
<%@page import = "java.util.*" %>
<%=new Date() %>
在之前代码的<body>部分再加一行代码:
<%@include file="includeByIndex.jsp" %>
执行程序后,结果如下:
this is a new JSP page
Tue Aug 09 09:56:23 CST 2011
3.JSP的几种动作指令
在这里,我们再把之前的include语句替换成如下语句:
<jsp:forward page="includeByIndex.jsp"></jsp:forward>
includeByIndex.jsp的内容不变,则显示结果又如下:
Tue Aug 09 10:11:30 CST 2011
没有了之前的“this is a new JSP page”,这是因为这里的jsp:forword是个跳转语句,其可跳转到指定的静态或动态页面,或跳转到容器中的servlet。
在进行跳转时,还可以进行参数传递,如下:
<jsp:forward page="includeByIndex.jsp">
<jsp:param value="James" name="username"/>
</jsp:forward>
将includeByIndex.jsp的内容再改写如下:
<%@ page import="java.util.*"%>
<body>
<%out.println("the param of username is : "); %>
<%=request.getParameter("username") %>
<%out.println("now the time is: "); %>
<%=new Date() %>
</body>
最终页面上的结果为:
the param of username is : James now the time is: Tue Aug 09 10:19:40 CST 2011
至于接收参数的对象request,再这里先不介绍,以后再进行详细阐述。
我们继续将之前的讲解include源代码基础上再将include语句替换成如下语句:
<jsp:include page="includeByIndex.jsp"></jsp:include>
其页面显示结果为:
this is a new JSP page
Tue Aug 09 10:29:14 CST 2011
可以看到与没替换之前编译指令include执行效果差不多,那么它们的区别到底在哪呢?区别就在于:编译指令<%@include>只是简单的将源文件包含进来,然后进行执行,而<jsp:include>是个动作指令,它是在将源文件代码进行执行后,再将其结果包含进来进行显示(如果要包含的文件为静态文件,则直接进行显示),简单的说:<%@include>指令先包含,再执行,而<jsp:include>指令先执行,再包含。从servlet容器层面上来看,动态导入时,servlet类中会将<jsp:include>翻译为一条简单的包含语句:
org.apache.jasper.runtime.JspRuntimeLibrary.include(request , response ,"includeByIndex.jsp" , out);
而<%@include>会被容器翻译为JAVA源代码,然后与servlet类一起构成整个文件。
到这里,JSP单文件处理内容已经差不多了,接下来就是JSP与JAVA类的混合编码,开始步入将业务逻辑与页面实现分离的阶段。
首先来看下3种动作指令:useBean,setProperty,getProperty,其中useBean是进行类的对象的声明语句,setProperty和getProperty是对页类的属性进行操作的语句。
我们先来声明一个自己的JAVA类,代码如下所示:
package com.user;
public class userInformation {
private String userName;
private String userPassword;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
在页面中的<body>部分代码如下:
<body>
<jsp:useBean id="user" class="com.user.userInformation" scope="page"></jsp:useBean>
<jsp:setProperty property="userName" name="user" value="James"/>
<jsp:setProperty property="userPassword" name="user" value="123456"/>
<jsp:getProperty property="userName" name="user"/>
<jsp:getProperty property="userPassword" name="user"/>
</body>
该JSP文件的执行结果为:
James 123456
其中<jsp:useBean>的属性id为对象名,class为类名,scope为对象的生存周期,有如下四个可选项:
page:仅在当前页面有效;
request::在一次请求范围内有效,即:如果页面从一个页面转到另一个页面,那么当前对象失效;
session:在一次连接范围内有效,如果和服务器断开连接,则当前对象失效;
application:从服务器启动到结束一直有效。
(至于这几个声明周期,其具体内容较多,在此先不进行详细阐述,会在下一篇文章中介绍。)
<jsp:setProperty>属性property为类的属性名,name为对象名,value为值。