第3 章 JSP语法 本章介绍JSP的基本语法,包括指令元素、脚本元素、动作元素、注释。指令元素告 诉JSP容器如何编译JSP文件,脚本元素是JSP文件中的Java代码,动作元素是用来协 助处理客户请求的。 3.1 JSP文件的组成 JSP是HTML和Java脚本混合的文本文件,可以处理用户的HTTP请求,并返回 动态的页面。JSP由指令元素、脚本元素、动作元素、注释和HTML标签构成。 3.1.1 一个典型的JSP 文件 一个典型的JSP文件如下,文件名为typical.jsp。文件中包含page指令、声明、表达 式、小脚本,以及HTML标签。 <%@ page contentType="text/html; charset=GB18030"%> <html><head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>一个典型的JSP 文件</title></head> <%! int count = 10; String getDate(){ return new java.util.Date().toString(); } %> <body> <h2>当前时间是: <%=getDate()%></h2> <table width="400" border="1" > <tr> <td width="100">学号</td> <td width="300">姓名</td> </tr> <% for(int i=1;i<=count;i++){ %> 52 JSP 程序设计(第2 版) <tr><td><%=i%></td><td><%="Name"+i%></td></tr> <% }% > </table></body></html> 3.1.2 分析JSP 文件中的元素 typical.jsp文件的内容简单分析如下: . < %@ pagecontentType="text/html;charset=GB18030" %> ,page指令用来 说明如何编译JSP文件。 . < %! %> 声明,用来定义类的成员变量和成员方法。 . < % %>Scriptlet(小脚本),即Java代码。 . < %= %> 表达式,计算并输出Java表达式的值。 . <html> </html> ,HTML文档的标识符。 . <head> </head> ,文档头部。 . <title> </title> ,文档标题。 . <body> </body> ,文档正文。 . <h3> </h3> ,标题3。 . <table> </table> ,表格。 . <tr> </tr> ,表格的一行。 . <td> </td> ,表格的一个单元格。 3.1.3 JSP 文件的运行结果 在Eclipse中新建动态网站项目(DynamicWebProject),项目名为ch03。在项目的 src/main/webapp目录中新建JSP文件,文件名为typical.jsp。在Eclipse中启动服务器 Tomcat,然后打开浏览器并在地址栏输入下面URL,就可以看到JSP文件的运行结果, 如图3-1所示。 http://localhost:8080/ch03/typical.jsp 上面给出的是浏览器把HTML解释后展现给用户的效果,实际的HTML文件的内 容如下: <html><head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>第一个JSP 文件</title></head> <body> <h3>当前时间是: Web Aug 04 16:40:58 CST 2021</h3> <table width="400" border="1" > <tr> <td width="100">学号</td> 第3 章 JSP 语法 53 图3-1 JSP文件的运行结果 <td width="300">姓名</td> </tr> <tr><td>1</td><td>Name1</td></tr> <tr><td>2</td><td>Name2</td></tr> <tr><td>3</td><td>Name3</td></tr> <tr><td>4</td><td>Name4</td></tr> <tr><td>5</td><td>Name5</td></tr> <tr><td>6</td><td>Name6</td></tr> <tr><td>7</td><td>Name7</td></tr> <tr><td>8</td><td>Name8</td></tr> <tr><td>9</td><td>Name9</td></tr> <tr><td>10</td><td>Name10</td></tr> </table></body></html> 3.1.4 JSP 转译的Java 源文件 当服务器上的一个JSP页面第一次被请求执行时,服务器上的JSP引擎首先将JSP 页面文件转译成一个Java文件,再将Java文件编译生成字节码文件,然后通过访问字节 码文件实例化的Java对象响应客户端的请求。当多个客户请求同一个JSP页面时,JSP 引擎为每个客户分配一个线程池里已有的线程,该线程负责访问已经驻留在内存中的 Java对象来响应客户的请求。 注意:多个线程并发访问同一个Java对象,会存在线程安全问题。 typical.jsp被Tomcat转译成Java源文件typical_jsp.java。由于该源文件是Tomcat 自动转译的,格式比较不规范,下面的源文件经过作者手工排版,并加入了注释。 54 JSP 程序设计(第2 版) package org.apache.jsp; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import java.io.*; import org.apache.jasper.runtime.*; public final class typical_jsp extends HttpJspBase implements JspSourceDependent { //变量声明转译成类的成员变量 int count = 10; //方法声明转译成类的方法 String getDate(){ return new java.util.Date().toString(); } private static java.util.List _jspx_dependants; public Object getDependants() { return _jspx_dependants; } public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { JspFactory _jspxFactory = null; PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; try { _jspxFactory = JspFactory.getDefaultFactory(); response.setContentType("text/html; charset=GB18030"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write("\r\n"); out.write("<html>\r\n"); out.write("<head>\r\n"); 第3 章 JSP 语法 55 out.write("<meta http-equiv=\"Content-Type\" "); out.write("content=\"text/html; charset=GB18030\" />\r\n"); out.write("<title>一个典型的JSP 文件</title>\r\n"); out.write("</head>\r\n"); out.write("<body>\r\n"); out.write("<h2>当前时间是: "); out.print(getDate()); out.write("</h2>\r\n"); out.write("<table width=\"400\" border=\"1\" >\r\n"); out.write("<tr>\r\n"); out.write(" <td width=\"100\">学号</td>\r\n"); out.write(" <td width=\"300\">姓名</td>\r\n"); out.write("</tr>\r\n"); //for 循环 for(int i=1;i<=count;i++){ out.write("<tr><td>"); out.print(i); //表达式 out.write("</td><td>"); out.print("Name"+i); //表达式 out.write("</td></tr>\r\n"); } out.write("</table>\r\n"); out.write("</body>\r\n"); out.write("</html>\r\n"); } catch (Throwable t) { if(!(t instanceof SkipPageException)){ out = _jspx_out; if (out != null && out.getBufferSize() != 0) out.clearBuffer(); if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); } }finally{ if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context); } } } 3.2 JSP中的注释 注释可以增强JSP页面的可读性,并易于JSP页面的维护。JSP页面中的注释可分 为以下3种: 56 JSP 程序设计(第2 版) (1)HTML注释:在标记符号“< %--”和“--%>”之间加入注释内容。例如: <!-- 注释内容 --> JSP引擎会计算注释中的JSP表达式,并把HTML注释交给用户,因此用户通过浏 览器查看JSP页面的源文件时,能够看到HTML注释。 (2)JSP注释:在标记符号“< %--”和“--%>”之间加入注释内容。例如: <%-- 注释内容--%> JSP引擎忽略JSP注释,即在编译JSP页面时忽略JSP注释,因此浏览器用户是无法 通过查看源文件看到JSP注释的。 (3)Java注释:在“/*”和“*/”之间可以加入单行或多行注释,在“//”后可以加入 单行注释。例如: /* 注释行1 注释行2 注释行3 */ //单行注释内容 1.comment.jsp:演示JSP中的注释 <%@ page contentType="text/html; charset=GB18030" %> <html><head><title>comment</title></head><body> <h2>HTML 注释举例</h2> <!-- HTML 注释 --> <!-- 含表达式的HTML 注释<%= new java.util.Date()%> --> <h2>JSP 注释举例</h2> <%-- JSP 注释 --%> <h2>Java 注释举例</h2> <% /* 多行注释 */ //单行注释 String developer = "佟强"; %> </body> </html> 2.comment.jsp:输出的HTML内容 <html><head><title>comment</title></head><body> <h2>HTML 注释举例</h2> <!-- HTML 注释 --> <!-- 含表达式的HTML 注释Web Aug 04 16:50:58 CST 2021 --> 第3 章 JSP 语法 57 <h2>JSP 注释举例</h2> <h2>Java 注释举例</h2> </body> </html> 3.3 指令元素 JSP指令元素用来告诉JSP容器如何编译JSP文件,JSP指令元素有三个:页面指令 page、包含指令include、标签库指令taglib。 3.3.1 page 指令 page指令用来定义JSP文件中的全局属性。一个JSP页面可以包含多个page指 令,除了import属性外,其他属性只能出现一次。page指令的作用对整个JSP页面有 效,与其书写的位置无关,但习惯把page指令写在JSP页面的最前面。 <%@ page [language="java"] [import="{package.clazz|package.*},..."] [contentType="TYPE;charset=CHARSET"] [session="true|false"] [buffer="none|8kb|sizekb"] [autoFlash="true|false"] [isThreadSafe="true|false"] [info="text"] [errorPage="relativeURL] [isErrorPage="true|false"] [extends="package.class"] [isELIgnored="true|false"] [pageEncoding="CHARSET"] %> 例如: <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030" session="true" import="java.io.*,java.sql.*,javax.sql.*,java.util.*" %> 在对浏览器的响应中,应用服务器负责通知浏览器使用什么样的方法来处理接收到 的信息,这就要求JSP页面必须设置响应的MIME 类型和字符集,即设置contentType 属性。MIME是MultipurposeInternetMailExtensions的缩写,是一个互联网标准,扩 展了电子邮件标准。在万维网中使用的HTTP协议也使用了MIME的框架,标准被扩 展为互联网媒体类型。JSP页面输出HTML的MIME类型是text/html,而其他类型通 常使用Servlet输出。如果用户的浏览器不支持某种MIME类型,那么用户的浏览器就 58 JSP 程序设计(第2 版) 无法用相应的应用程序处理接收到的信息。除text/html,常见的MIME类型还有: .image/jpeg,JPEG图像。 .image/png,PNG图像。 .image/gif,GIF图形。 .text/plain,普通文本。 .application/zip,ZIP压缩文件。 .application/pdf,PDF文件。 .application/octet-stream,任意的二进制数据。 .application/vnd.ms-excel,.xls格式的Excel工作簿。 .xlsx格式的Excel工作簿文件的MIME类型是: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet page指令的属性描述、默认值和示例,如表3-1所示。 表3-1 page指令的属性描述、默认值和示例 属 性描 述默认值示 例 language 定义要使用的脚本语言,目前只能是"java" "java" language="java" import 和一般的Javaimport意义一样,用于引入要使 用的类,用逗号","隔开包和类的列表 默认省略import="java.io.*, java.util.HashMap" session 指定所在页面是否参与HTTP会话"true" session="true" buffer 指定客户端输出流的缓冲模式。如果为none, 则不缓冲;可指定具体大小,与autoFlash一起 使用 默认8KB buffer="64kb" autoFlush 为true则缓冲区满时,输出缓冲区被刷新;为 false则缓冲区满时,出现运行异常,表示缓冲区 溢出 "true" autoFlush="true" info 关于JSP页面的信息,定义一个字符串,可以使 用servlet.getServletInfo()获得 默认省略info="测试页面" isErrorPage 表明当前页是否为其他页的errorPage目标。 如果被设置为true,则可以使用exception对象。 相反,如果被设置为false,则不可以使用 exception对象 "false" isErrorPage="true" errorPage 定义此页面出现异常时调用的页面默认省略errorPage="err.jsp" isThreadSafe 用来设置JSP文件是否能多线程使用。如果设 置为true,那么一个JSP能够同时处理多个用 户的请求;如果设置为false,一个JSP只能一次 处理一个请求 "true" isThreadSafe="true" contentType 定义JSP页面响应的MIME类型和响应内容的 字符编码 text/html; charset= ISO-8859-1 "text/html; charset=GB18030" 续表 第3 章 JSP 语法 59 属 性描 述默认值示 例 pageEncoding JSP页面的字符编码ISO-8859-1 pageEncoding= "GB18030" isELIgnored 指定EL(表达式语言)是否被忽略。如果为 true,则容器忽略"${}"表达式的计算"false" isELIgnored="true" 3.3.2 include 指令 include指令通知容器在当前JSP页面中指定的位置嵌入其他文件。被包含的文件 内容可以被JSP解析,这种解析发生在编译期间。 <%@ include file="filename" %> 其中filename为要包含的文件名。需要注意的是,一经编译,内容就不可变,如果要 图3-2 include指令举例 改变内容,必须重新编译JSP文件。相比运行时包含,编译 时包含的JSP执行效率更高。而且,Tomcat会检测文件的 改动,并自动重新编译文件。 如果filename以“/”开头,那么路径是参照Web应用 所在的根路径;如果filename是文件名,或者是以目录名开 头,那么路径是以JSP文件所在路径为参照的相对路径。 例如,设计网站时,为了让网站具有统一的风格,可以 将页面头部和页面底部做成公共的页面,如图3-2所示。 然后在其他页面中使用include指令将页面头部和页面底 部包含进来。需要注意的是,头部和底部的页面应是 HTML片段,而不是完整的HTML文档。 1.页面文件home.jsp <%@ page contentType="text/html; charset=GB18030" %> <html><head> <style type="text/css"> /*body 标签的样式*/ body{ text-align: center; margin:0; padding:0; } /*标题1 去掉margin 和padding*/ h1{ margin:0; padding:0; } 60 JSP 程序设计(第2 版) /*段落去掉margin 和padding*/ p{ margin:0; padding:0; } /*定义一个放所有页面内容的容器*/ #container{ width: 800px; height: auto; margin: 0 auto; text-align:left; } /*定义页面头部*/ #header{ width: 800px; height: 60px; line-height: 60px; background-color: red; } /*定义页面中部*/ #content{ width: 800px; height:680px; background-color: green; } /*定义页面底部*/ #footer{ width: 800px; height: 40px; line-height: 40px; background-color: blue; }< /style> <title>使用include 指令包含页面头部和页面底部</title> </head> <body> <div id="container"> <div id="header"> <%@ include file="header.jsp" %> </div> <div id="content"> <h1>文档的标题</h1> <p>文档内容</p> </div> <div id="footer"> 第3 章 JSP 语法 61 <%@ include file="footer.jsp" %> </div> </div> </body> </html> 2.页面头部文件header.jsp <%@ page contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <h1>页面的头部</h1> 3.页面底部文件footer.jsp <%@ page contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <p>页面的底部</p> 3.3.3 taglib 指令 taglib指令允许页面使用自定义标签。用户可以开发标签库,为标签库编写.tld配置 文件,然后在JSP页面中使用taglib指令引入标签库。在JSP2.0规范中引入了标准标 签库JSTL。如何使用表达式语言EL和标准标签库JSTL请分别参考第11章表达式语 言EL和第12章标准标签库JSTL,可提前阅读。JSP中使用taglib指令引入标签库的语 法如下: <%@ taglib uri="taglibURI" prefix="tagPrefix"%> uri用来告诉JSP引擎怎么找到标签描述文件和标签库。prefix定义在JSP页面中 引用标签使用的前缀,前缀不可以是:jsp、jspx、java、javax、sun、servlet和sunw。 例如,引入JSTL核心标签库的taglib指令是: <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 引入核心标签库之后,就可以使用JSTL核心标签库中定义的标签,例如使用迭代标 签<c:forEach> 输出表格数据行的代码如下: <table width="600" border="1"> <thead> <tr><th>学号</th> <th>姓名</th></tr> </thead> <tbody> <c:forEach var="student" items="${students}"> <td>${student.id}</td> <td>${student.name}</td> </c:forEach> </tbody> </table> 62 JSP 程序设计(第2 版) 3.4 脚本元素 JSP脚本元素是JSP最烦琐的元素,特别是Scriptlet,在早期的JSP代码中占主导地 位。脚本元素通常是Java编写的脚本代码,可以声明变量和方法,可以包含任意的Java 代码和表达式计算。 3.4.1 声明<% !与% > 在JSP中,声明(Declaration)是一段Java代码,它用来定义在产生的类文件中类的 属性和方法。声明后面的变量和方法可以在JSP的任意地方使用。可以声明方法,也可 以声明变量。声明的格式如下: <%! variable declaration method declaration(paramType param,...) %> 1.变量声明 <%! int m, n=100, k; String message=”Hello World!”; Date date; %> 由“< %!”和“%>”之间定义的变量是类的成员变量,这些变量在整个JSP页面内都 有效,与“< %!”和“%>”标记符在页面中所在的位置无关,但习惯上通常把“< %!”和 “%>”标记符写在JSP页面的前面。当多个客户端请求同一个JSP页面时,JSP引擎会 为每个客户端分配一个线程,这些线程共享类的成员变量,任何一个客户端对成员变量的 修改都将影响其他客户端。因此,声明的成员变量存在线程的安全问题,应该尽量避免 使用。在 小脚本中使用上面所声明变量的代码如下: <% m = 20; k = m+n; date = new Date(); out.println(message); %> 2.方法声明 <%! /*将两个整数相加,返回相加的结果*/ 第3 章 JSP 语法 63 int add(int x, int y) { return x+y; } /*计算n 的阶乘*/ long factorial(long n) { long fact = 1; for(long i=2; i<=n; i++) { fact*=i; } return fact; } %> 在“< %!”和“%>”之间定义的方法是类的成员方法,在整个JSP页面内有效。但方 法内部定义的变量是局部变量,方法被调用时才分配局部变量的存储空间,调用完毕即释 放所占的内存。 在小脚本中使用上面定义的add()方法: <% int a = 100; int b = 23; int c = add(a,b); out.println("a="+a+" "+"b="+b+" "+"c="+c); %> 在表达式中使用factorial()方法: <h3>10 的阶乘是<%=factorial(10)%></h3> 将以上变量声明和方法声明的代码应用到一个JSP文件中(declaration.jsp),运行结 果如图3-3所示。 图3-3 declaration.jsp的运行结果 3.页面计数器page_counter.jsp 变量声明为类的成员变量,多个线程同时访问的是一个对象中的同一个变量。我们 利用一个成员变量“counter”实现一个页面计数器,可以验证多次访问对应同一个Java 对象。 <%! int counter = 0; %> 64 JSP 程序设计(第2 版) 如果在页面的小脚本部分直接修改counter,可能导致线程安全问题。比如第一个线 程读取了counter的值为10,还没来得及给counter加1,这时第二个线程读到counter的 值仍为10。然后,第一个线程执行加1写回操作,counter的值被更新为11;第二个线程 也执行加1 写回操作,也把counter的值更新为11。两个线程都执行加1 操作之后 counter的取值应该是12,但是这里却得到了错误结果11。 为了解决针对一个对象的互斥访问,Java语言提供了synchoronized关键字。Java 虚拟机确保同时只能有一个线程进入有synchoronized关键字修饰的方法。定义一个有 synchoronized关键字修饰的方法来执行counter加1的操作。 <%! synchronized int incrementCounter( ) { return ++counter; } %> 在JSP页面中显示页面被访问次数的代码如下: <h2>当前页面被访问计数: <%=incrementCounter()%></h2> 将以上代码应用到page_counter.jsp,每次刷新计数加1,运行结果如图3-4所示。 图3-4 page_counter.jsp的运行结果 3.4.2 表达式<% =与% > 表达式(Expression)是在JSP请求处理阶段计算它的值,所得的结果转换为字符串 并输出。表达式所在页面的位置,也就是该表达式计算结果显示的位置。表达式的语 法是: <%= Java Expression %> 表达式必须能求值,且不能以“;”(英文分号)结束,因为表达式不是Java的语句。 表达式的示例:expression.jsp <%@ page contentType="text/html; charset=GB18030" %> <html><head><title>表达式</title></head> <body> <% //局部变量的定义 double a=9, b=5, c=16; int x=12, y=10; 第3 章 JSP 语法 65 %> <p>ax+y^2-by+c 的值: <%=a*x+y*y-b*y+c%></p> <p>x>y&&a==b 的值: <%=x>y&&a==b%></p> <p>sin(x)+cos(y)的值: <%=Math.sin(x)+Math.cos(y)%></p> <p>16 的平方根: <%=Math.sqrt(16)%></p> </body> </html> expression.jsp的运行结果如图3-5所示。 图3-5 expression.jsp的运行结果 3.4.3 小脚本<% 与% > 小脚本(Scriptlet)是JSP页面处理请求时执行的Java代码,Scriptlet包括在“< %”和 “%>”之间。它可以产生输出,可以是一些流程控制语句,也可以包含Java 注释。 Scriptlet的语法是: <% Java Statements %> 在“< %”和“%>”之间定义的变量是函数的局部变量。局部变量的有效范围和其定 义的位置有关,即局部变量在定义的位置之后才有效。JSP引擎将JSP文件转译成Java 文件时,将各个小脚本中的局部变量都转化为Java类的“_jspService()”方法的局部 变量。 1.Java小脚本(Scriptlet)示例:name.jsp <%@ page contentType="text/html; charset=GB18030" %> <html> <head> <title>小脚本(Scriptlet)</title> </head> <body> <% String[] names = {"施耐庵","曹雪芹","佟强","罗贯中"}; for(int i=0; i<names.length; i++){ out.print(names[i]); 66 JSP 程序设计(第2 版) if(names[i].equals("佟强")){ out.print("是本书的作者。"); } out.println("<br/>"); } %> </body> </html> name.jsp的运行结果如图3-6所示。 图3-6 name.jsp的运行结果 下面再来分析一个复杂一点的小脚本示例,静态和动态都可以在循环时切换。 2.score.jsp <%@ page contentType="text/html; charset=GB18030" import="java.util.*" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>小脚本(Scriptlet)</title> </head> <body> <% //Map 里面存储的是多组关键字和与其对应的值 Map<String,Float> students = new HashMap<String,Float>(); students.put("张三", 78.5F); //张三,78.5 分 students.put("李四", 87.0F); //李四,87 分 students.put("赵五", 92.5F); //赵五,92.5 分 %> <h1 align="center">学生成绩表</h1> <table width="600" border="1" align="center"> <thead> <tr align="center"> <th>姓名</th><th>成绩</th> </tr> </thead> <tbody> <% //获得学生姓名的集合 Set<String> studentNames = students.keySet(); 第3 章 JSP 语法 67 //获得姓名集合的迭代器 Iterator<String> it = studentNames.iterator(); //迭代姓名集合 while(it.hasNext()){ //取出一个姓名 String name = it.next(); //get()方法根据关键字得到对应的值 Float score = students.get(name); %> <tr align="center"><td><%=name%></td><td><%=score%></td></tr> <% } %> </tbody> </table> </body> </html> score.jsp的运行结果如图3-7所示。 图3-7 score.jsp的运行结果 3.4.4 表达式语言$ { } 表达式语言(ExpressionLanguage,EL)是JSP2.0增加的技术,通过表达式语言,可 以简化JSP的开发,使代码整洁。EL 表达式使用“${}”表示,用于读取pageContext、 request、session、application对象上绑定的属性(Attribute)。 表达式语言可以读取request对象上的属性,下面代码在request对象上绑定一个属 性message,属性的取值是String对象。 <% request.setAttribute("message","Hello Expression Language!"); %> 在JSP页面中静态的HTML部分使用EL读取属性值并输出,可使用${message}。 <h3>${message}</h3> 68 JSP 程序设计(第2 版) 使用EL也可以很方便地读取JavaBean(绑定在request等对象上的自定义Java对 象)的属性,以下代码创建了一个Student对象,并将这个对象绑定到request对象上,属 性名是“student”。这样,student就成为了一个request范围内的一个JavaBean,其自身 具有属性学号(stuNo)、姓名(name)和成绩(score)。 <% Student student = new Student("201501001","王小花",96.5F); //将Student 对象绑定到request 上,属性名是student request.setAttribute("student", student); %> 在JSP页面的静态HTML部分,可以使用如下EL表达式读取student对象的属性。 但是需要强调的是,EL表达式并不直接读取student对象的数据成员,而是通过调用对 应的Getter方法来读取数据成员,比如,表达式${student.name}将调用student. getName()方法。 <p>${student.stuNo} ${student.name} ${student.score}</p> 将以上程序段和EL表达式应用到el.jsp中,运行结果如图3-8所示。另外需要的 Student类的定义如下: package cn.edu.uibe.domain; public class Student { private String stuNo; //学号 private String name; //姓名 private float score; //成绩 public Student(String stuNo,String name,float score){ this.stuNo = stuNo; this.name = name; this.score = score; } public String getStuNo() { return stuNo; } public void setStuNo(String stuNo) { this.stuNo = stuNo; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getScore() { return score; } public void setScore(float score) { this.score = score; } } 图3-8 el.jsp的运行结果 第3 章 JSP 语法 69 3.5 动作元素 JSP动作元素是在请求处理阶段按照其在页面中出现的顺序执行的,该类元素只有 在被执行时才实现其所具有的功能,这与指令元素不同。JSP指令元素是在编译时发生 作用,指导JSP引擎将JSP页面转译成Servlet。JSP动作元素使用XML语法,有以下两 种格式: <prefix:tag attribute=value attribute-list .../> 或者: <prefix:tag attribute=value attribute-list ...> ...... </prefix:tag> 在JSP页面中,常用的动作元素包括<jsp:include> 、<jsp:forward> 、<jsp:useBean> 、 <jsp:setProperty> 、<jsp:getProperty> 、<jsp:param> 。 3.5.1 <jsp:param> 提供参数 <jsp:param> 操作是以“名称-值”对的形式为其他标签提供额外参数。它可与<jsp: include> 和<jsp:forward> 一起使用,在动态包含和转发时为目标JSP页面提供参数。它 的使用形式如下: <jsp:param name="paramName" value="paramValue"/> 其中name为参数名,value为参数值。例如: <jsp:param name="productId" value="1048485790"/> 3.5.2 <jsp:include> 包含页面 <jsp:include> 操作在处理用户请求时动态地引入其他资源(JSP、HTML)。被包含 的对象只有对JSP Writer对象的访问权,不能设置Header或者Cookie。与include指令 相比,<jsp:include> 操作发生在处理用户请求时,是动态的;而include指令发生在JSP 文件编译时,是静态的。<jsp:include> 是运行时调用另外一个JSP页面,并将另外一个 页面的运行结果输出到当前页面中include动作元素所在的位置;而< %@include> 是在 编译时将被包含的文件复制到include指令所在位置,然后作为一个整体编译。<jsp: include> 语法如下: <jsp:include page="url" flush="true"/> 或者: <jsp:include page="url" flush="true"> <jsp:param name="paramName" value="paramValue"/> 70 JSP 程序设计(第2 版) ...... </jsp:include> 其中,page属性给出被包含页面的URL,flush属性标识当输出缓冲区满时,是否清 空缓冲区。page属性的url如果以“/”开头,则从当前应用所在路径开始查找页面文件, 如果以文件名或目录名开头,则以当前路径为基础查找被包含的页面文件。flush属性的 默认值是false,通常情况下设置为true。<jsp:param> 子元素可以向被包含的JSP页面 传递参数。 以下<jsp:include> 的示例由2个页面构成,jspinclude1.jsp页面中使用include动作 元素动态地包含jspinclude2.jsp,并使用<jsp:param> 传递了参数message。 1.动态包含另外一个文件:jspinclude1.jsp <%@ page contentType="text/html; charset=GB18030" %> <html><head> <title>jsp:include demo</title> </head><body> <h3>包含前</h3> <jsp:include page="jspinclude2.jsp"> <jsp:param name="message" value="Hello Include!"/> </jsp:include> <h3>包含后</h3> </body></html> 2.被包含的文件:jspinclude2.jsp <%@ page contentType="text/html; charset=GB18030" %> <% String message = request.getParameter("message"); out.println("<h3>被包含页面: "+message+"</h3>"); %> 3.分析运行结果 在浏览器中访问第一个JSP文件jspinclude1.jsp,运行结果如图3-9所示。 图3-9 jspinclude1.jsp的运行结果 需要注意的是,被包含的JSP文件只能输出HTML片段,而不能是完整的HTML 文件,否则将导致输出的结果包含重复的<html> 、<head> 、<title> 、<body> 等标签。通