第3章〓JSP语法 学习目的与要求 本章主要介绍JSP脚本元素、JSP指令标记和JSP动作标记。通过本章的学习,要求读者理解JSP页面的组成部分,掌握JSP语法,并能够使用JSP开发Web页面。 本章主要内容 JSP页面的基本构成 JSP脚本元素 JSP指令标记 JSP动作标记 一个JSP页面通常由HTML标记、JSP注释、Java脚本元素以及JSP标记4种基本元素组成。这4种基本元素在JSP页面中是如何被使用的为本章介绍的重点。 本章涉及的JSP页面保存在ch3项目的src/main/webapp目录中。 扫一扫 视频讲解 3.1JSP页面的基本构成 3.1.1一个JSP页面 在HTML静态页面文件中加入和Java相关的动态元素,就构成了一个JSP页面。一个JSP页面通常由以下4种基本元素组成: (1) 普通的HTML标记。 (2) JSP注释。 (3) Java脚本元素,包括声明、Java程序片和Java表达式。 (4) JSP标记,例如指令标记、动作标记和自定义标记等。 【例31】根据example3_1.jsp代码中的注释识别JSP页面的基本元素。 example3_1.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html jsp:include page="a.jsp"/ !-- JSP动作标记-- %! int i = 0;//数据声明 int add(int x, int y) { //方法声明 return x + y; } % html!-- HTML标记-- head meta charset="UTF-8" titleInsert title here/title /head body % i ++;//Java程序片 int result = add(1, 2); % i的值为%=i%%--Java表达式--% br 1+2的和为%=result% /body /html a.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleInsert title here/title /head body 被example3_1.jsp动态引用。 /body /html 3.1.2JSP页面注释 在example3_1.jsp的代码中有许多JSP注释,添加注释能够增强JSP文件的可读性,便于Web项目的更新和维护。JSP页面中常见的注释有以下两种: HTML注释 格式: <!HTML注释> 在标记符“<!”和“>”之间加入注释内容,就构成了HTML注释。 JSP引擎对于HTML注释也要进行处理,即不将它看作注释,如果其中有JSP代码,也将被JSP引擎处理。JSP引擎将处理之后的HTML注释交给客户端,在通过浏览器查看JSP源文件时能够看到HTML注释。 JSP注释 格式: <%JSP注释%> 在标记符“<%”和“%>”之间加入注释内容,就构成了JSP注释。 JSP引擎将JSP注释当作真正的注释,在编译JSP页面时忽略这部分代码,因此在通过浏览器查看JSP源文件时无法看到JSP注释。 3.1.3实践环节——识别JSP页面元素 识别出以下JSP页面的基本元素: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html !--学习JSP页面的基本构成-- %! String content = "JSP页面的基本构成: "; % html head meta charset="UTF-8" titleshijian3_1.jsp/title /head body % content = content + "HTML标记、JSP注释、JSP标记以及Java脚本元素"; % %=content% /body /html 扫一扫 视频讲解 3.2JSP脚本元素 JSP中的Java脚本元素包括声明、Java程序片以及Java表达式。 3.2.1Java程序片 在标记符“<%”和“%>”之间插入的Java代码被称为JSP页面的Java程序片。Java程序片的格式如下: % Java代码% 一个JSP页面中可以有任意段Java程序片,这些程序片将被JSP引擎(本书中指Tomcat服务器)按顺序执行。在一个程序片中声明的变量称为JSP页面的局部变量,它们在JSP页面中后继的所有程序片以及表达式内都有效。 当多个用户请求一个JSP页面时,JSP引擎为每个用户启动一个线程,不同的线程会分别执行该JSP页面中的Java程序片,程序片中的局部变量会在不同的线程中被分配不同的内存空间,因此一个用户对JSP页面中局部变量操作的结果不会影响其他用户。Java程序片的执行原理如图3.1所示。 图3.1Java程序片的执行原理 【例32】编写一个JSP页面example3_2.jsp,在页面中存在一段Java程序片,该程序片内声明了一个整型的局部变量n,初始值为0。 example3_2.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_2.jsp/title /head body % int n = 0; n++; out.print("n = " + n); % /body /html 如果有5个用户请求example3_2.jsp页面,JSP引擎会启动5个线程,页面中的Java程序片在每个线程中都会被执行一次,共执行5次; 在内存中,局部变量n对应5处不同的存储空间,初始值都为0,且都仅执行了一次自加运算,所以5个用户看到的页面效果是相同的。 3.2.2成员变量与方法的声明 成员变量和方法的声明格式如下: %! 变量或方法的定义 % 在标记符“<%!”和“%>”之间声明的变量被称为JSP页面的成员变量,它们可以是Java 语言允许的任何数据类型。例如: %! int n = 0; Date date; % 成员变量在整个JSP页面内都有效(与书写位置无关),因为JSP引擎在将JSP页面转译成Java 文件时将这些变量作为类的成员变量,这些变量的内存空间直到服务器关闭才释放,因此多个用户共享JSP页面的成员变量,任何用户对JSP页面成员变量操作的结果都会影响到其他用户。 在标记符“<%!”和“%>”之间声明的方法被称为JSP页面的成员方法,该方法在整个JSP页面内有效,但是在该方法内定义的变量仅在该方法内有效。 【例33】编写一个JSP页面example3_3.jsp,在该页面中声明一个成员变量n(初始值为0)和方法add()(求两个整数的和),另外该页面中还有一段Java程序片,在程序片中声明一个局部变量m,并且对成员变量n和局部变量m分别进行自加运算。 example3_3.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_3.jsp/title /head %! int n=0; int add(int x,int y){ return x+y; } % body % int m=0; n++; m++; int result=add(1,2); out.print("成员变量n的值为: "+n+"br"); out.print("局部变量m的值为: "+m+"br"); out.print("1+2="+result+"br"+"br"); out.print("第"+n+"个用户"); % /body /html 在example3_3.jsp中,变量n是成员变量,被所有用户共享; 变量m是局部变量,被每个用户独享。如果有3个用户请求这个JSP页面,则看到的效果如图3.2所示。 图3.23个用户请求example3_3.jsp页面的效果 从example3_3.jsp中可知Java程序片具有以下特点: (1) 调用JSP页面声明的方法。 (2) 操作JSP页面声明的成员变量。 (3) 声明局部变量。 (4) 操作局部变量。 3.2.3Java表达式 在标记符“<%=”和“%>”之间可以插入一个表达式,这个表达式必须能求值。表达式的值由Web服务器负责计算,并将计算结果用字符串形式发送到客户端,作为HTML页面的内容显示。 在Java表达式中可以有算术表达式、逻辑表达式、条件表达式等,但在使用Java表达式时需要注意以下两点: (1) 不可以在“<%=”和“%>”之间插入语句,即输入的内容不能以分号结束。 (2) “<%=”是一个完整的符号,在“<%”和“=”之间不能有空格。 3.2.4实践环节——在JSP页面中输出英文字母表 编写一个JSP页面,在JSP页面中使用Java程序片输出小写的英文字母表。 3.2.5实践环节——网站访问量的统计 利用成员变量被所有用户共享这一性质实现一个简单的计数器,页面效果如图3.3所示。 图3.3简单的计数器 3.2.6实践环节——打印表格 在浏览器中输出15×10的表格,页面效果如图3.4所示。 图3.415×10的表格 扫一扫 视频讲解 3.3JSP指令标记 常用的JSP指令标记有page指令标记和include指令标记。 3.3.1page指令标记 page指令标记用来定义整个JSP页面中的一些属性和这些属性的值,可以用一个page指令标记指定多个属性的值,也可以使用多个page指令标记分别为每个属性指定值。page指令标记的语法格式如下: %@ page属性1="属性1的值" 属性2="属性2的值" …% 或 %@ page属性1="属性1的值" % %@ page属性2="属性2的值" % %@ page属性3="属性3的值" % … %@ page属性n="属性n的值" % page指令标记的属性主要有contentType、import、language和pageEncoding等。 contentType属性 JSP页面使用page指令标记只能为contentType属性指定一个值,用来确定响应的MIME类型(MIME类型就是设定某种文件用相应的一种应用程序来打开的方式类型)。当用户请求一个JSP页面时,服务器会告诉浏览器使用contentType属性指定的MIME类型来解释执行所接收到的服务器为之响应的信息。例如,当浏览器使用Word应用程序打开用户的请求时,可以将contentType属性值设置为: %@page contentType="application/msword;charset=UTF-8"% 常见的MIME类型有text/html(HTML解析器,所谓的网页形式)、text/plain(普通文本)、application/pdf(PDF文档)、application/msword(Word应用程序)、image/jpeg(JPEG图像)、image/png(PNG图像)、image/gif(GIF图形)以及application/vnd.mspowerpoint(PowerPoint应用程序)。 import属性 在JSP页面中使用page指令标记可以为import属性指定多个值,import属性的作用是为JSP页面引入包中的类,以便在JSP页面的程序片、变量及方法声明或表达式中使用包中的类。 language属性 language属性用来指定JSP页面中使用的脚本语言,目前该属性的值只能取"java"。 pageEncoding属性 contentType中的charset是指服务器发送给浏览器时用户所见到的网页内容的编码; pageEncoding是指JSP文件存储时所用的编码。 在JSP规范中,如果pageEncoding属性存在,那么JSP页面的字符编码方式就由pageEncoding决定,否则由contentType属性中的charset决定,如果charset也不存在,JSP页面的字符编码方式采用默认的ISO88591。 【例34】编写一个JSP页面example3_4.jsp,当用户请求该页面时,在Eclipse内嵌的浏览器中启动本地的PowerPoint应用程序打开该页面。 example3_4.jsp的代码如下: %@ page language="java" contentType="application/vnd.ms-powerpoint; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_4.jsp/title /head body 在学习page指令标记时,请记住只能为JSP页面设置一个contentType属性值,可以为import属性设置多个值。 /body /html 3.3.2include指令标记 一个网站中的多个JSP页面有时需要显示同样的信息,例如该网站的Logo、导航条等,为了便于维护网站程序,通常在这些JSP页面的适当位置嵌入一个相同的文件。include指令标记的作用就是将JSP文件、HTML网页文件或其他文本文件等静态嵌入当前的JSP网页中,该指令标记的语法格式如下: %@include file="文件的URL"% 所谓静态嵌入就是“先包含后处理”,在编译阶段完成对文件的嵌入,即先将当前JSP页面与要嵌入的文件合并成一个新的JSP页面,然后由JSP引擎将新页面转化为Java文件处理并运行。 图3.5include指令标记的使用 【例35】编写两个JSP页面example3_5.jsp和example3_5_1.jsp,在example3_5.jsp页面中使用include指令标记静态嵌入example3_5_1.jsp页面,访问example3_5.jsp页面,运行效果如图3.5所示。 example3_5.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_5.jsp/title /head body 静态嵌入example3_5_1.jsp之前 br %@include file="example3_5_1.jsp"% br 静态嵌入example3_5_1.jsp之后 /body /html example3_5_1.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_5_1.jsp/title /head body font color="red" size=4example3_5_1.jsp文件的内容/font /body /html example3_5.jsp页面静态嵌入example3_5_1.jsp页面,需要先将example3_5_1.jsp中的所有代码嵌入example3_5.jsp的指定位置,形成一个新的JSP文件,然后将新文件提交给JSP引擎处理,如图3.6所示。 图3.6静态嵌入的原理 在使用include指令标记时,需要注意嵌入文件后必须保证新合成的JSP页面符合JSP的语法规则,比如例35的example3_5.jsp和example3_5_1.jsp两个页面的page指令标记就不能指定不同的contentType值,否则合并后的JSP页面就使用两次page指令标记为contentType属性设置了不同的属性值,导致语法错误。 图3.7导航栏的运行效果 3.3.3实践环节——制作导航栏 编写3个JSP页面index.jsp、main.jsp和head.jsp,在index.jsp和main.jsp页面中分别使用include指令标记静态嵌入head.jsp(导航栏)。导航栏的运行效果如图3.7所示。 扫一扫 视频讲解 3.4JSP动作标记 常用的JSP动作标记有include、forward、param、useBean、getProperty和setProperty,其中useBean、getProperty和setProperty将在本书的第5章中介绍。 3.4.1include动作标记 动作标记include的作用是将JSP文件、HTML网页文件或其他文本文件等动态嵌入当前的JSP网页中。该动作标记的语法格式如下: jsp:include page="文件的URL"/ 或 jsp:include page="文件的URL" 子标记 jsp:include/ 当动作标记include不需要子标记时使用上述第一种形式。 所谓动态嵌入就是“先处理后包含”,在运行阶段完成对文件的嵌入,即在将JSP页面转译成Java文件时并不合并两个页面,而是在Java文件的字节码文件被加载并执行时才去处理include动作标记中引入的文件。与静态嵌入相比,动态嵌入的执行速度稍慢,但是灵活性较高。 【例36】编写两个JSP页面example3_6.jsp和example3_6_1.jsp,在example3_6.jsp页面中使用include动作标记动态嵌入example3_6_1.jsp页面,运行example3_6.jsp页面。 example3_6.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_6.jsp/title /head body 动态嵌入example3_6_1.jsp之前 br jsp:include page="example3_6_1.jsp"/ br 动态嵌入example3_6_1.jsp之后 /body /html example3_6_1.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_6_1.jsp/title /head body font color="red" size=4example3_6_1.jsp文件的内容/font /body /html 页面文件example3_6.jsp通过动作标记include动态嵌入了example3_6_1.jsp,此时JSP引擎不会将两个文件合并成一个JSP页面,而是分别将文件example3_6.jsp和example3_6_1.jsp转化成对应的Java文件和字节码文件。当JSP解释器解释执行example3_6.jsp页面时会遇到动作指令<jsp:include page="example3_6_1.jsp"/>对应的代码,此时才会执行example3_6_1.jsp页面对应的字节码文件,然后将执行的结果发送到客户端,并由客户端负责显示这些结果,所以example3_6.jsp和example3_6_1.jsp页面中page指令标记的contentType属性值可以不同。 3.4.2forward动作标记 动作标记forward的作用是从该标记出现处停止当前JSP页面的继续执行,转而执行forward动作标记中page属性值指定的JSP页面。该动作标记的语法格式如下: jsp: forward page="文件的URL"/ 或 jsp: forward page="文件的URL" 子标记 /jsp: forward 当动作标记forward不需要子标记时使用上述第一种形式。 【例37】编写3个JSP页面example3_7.jsp、oddNumber.jsp和evenNumbers.jsp,在example3_7.jsp页面中随机获取0~10的整数,当该整数为偶数时转向页面evenNumbers.jsp,否则转向页面oddNumber.jsp。首先访问example3_7.jsp页面。 example3_7.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_7.jsp/title /head body % long i = Math.round(Math.random() * 10); if(i%2 == 0){ System.out.println("获得的整数是偶数,即将跳转到偶数页面evenNumbers.jsp。"); % jsp:forward page="evenNumbers.jsp"/ % System.out.println("我是偶数,尝试一下能看到我吗?"); }else{ System.out.println("获得的整数是奇数,即将跳转到奇数页面oddNumber.jsp。"); % jsp:forward page="oddNumber.jsp"/ % System.out.println("我是奇数,尝试一下能看到我吗?"); } % /body /html evenNumbers.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleevenNumbers.jsp/title /head body 我是偶数页。 /body /html oddNumber.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleoddNumber.jsp/title /head body 我是奇数页。 /body /html 3.4.3param动作标记 动作标记param不能单独使用,但可以作为include、forward动作标记的子标记来使用,该动作标记以“名字值”对的形式为对应页面传递参数。该动作标记的语法格式如下: jsp:父标记page="接收参数页面的URL" jsp:param name="参数名" value="参数值"/ /jsp:父标记 接收参数的页面可以使用内置对象request调用getParameter("参数名")方法获取动作标记param传递过来的参数值。内置对象将在本书的第4章中介绍。 用户可以使用param子标记向页面传递多个参数,格式如下: jsp:父标记 page="接收参数页面的URL" jsp:param name="参数名1" value="参数值1"/ jsp:param name="参数名2" value="参数值2"/ jsp:param name="参数名3" value="参数值3"/ … /jsp:父标记 【例38】编写两个页面example3_8.jsp和computer.jsp,在页面example3_8.jsp中使用include动作标记动态包含文件computer.jsp,并向它传递一个矩形的长和宽; computer.jsp接收到参数后计算矩形的面积,并显示结果。 example3_8.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titleexample3_8.jsp/title /head body 加载computer.jsp页面计算矩形的面积brbr jsp:include page="computer.jsp" jsp:param value="10" name="length"/ jsp:param value="6" name="width"/ /jsp:include /body /html computer.jsp的代码如下: %@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"% !DOCTYPE html html head meta charset="UTF-8" titlecomputer.jsp/title /head body % String m = request.getParameter("length"); String n = request.getParameter("width"); double a = Double.parseDouble(m); double b = Double.parseDouble(n); out.print("我是被加载的页面,负责计算矩形的面积" + "br"); out.print("给我传递的矩形的长度是:"+a+",宽度是:" + b + "br"); out.print("矩形的面积是:" + a * b); % /body /html 3.4.4实践环节——include和param动作标记的应用 编写3个JSP页面input.jsp、first.jsp和second.jsp,将3个JSP文件保存在同一个Web服务目录中,input.jsp使用include动作标记加载first.jsp和second.jsp页面。first.jsp页面可以画出一个表格,second.jsp页面可以计算出两个正整数的最大公约数。当first.jsp被加载时获取input.jsp页面中include动作标记的param子标记提供的表格的行数和列数,当second.jsp被加载时获取input.jsp页面中include动作标记的param子标记提供的两个正整数的值。 3.4.5实践环节——登录验证 编写3个JSP页面login.jsp、validate.jsp和success.jsp,login.jsp输入用户名和密码信息,提交给validate.jsp进行用户验证,如果验证为合法用户(用户名为tom,密码为jenny),则转到(forward动作标记)success.jsp页面,否则转到login.jsp页面重新登录。 本章小结 本章主要介绍了JSP页面的组成、JSP脚本元素和JSP标记。一个JSP页面通常由HTML标记、JSP注释、Java脚本元素以及JSP标记组成。JSP脚本元素包括Java程序片、JSP页面成员变量与方法的声明、Java表达式。JSP标记包括指令标记和动作标记。 习 题 3