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为值。