JSP页面基本结构:
组成元素
普通的HTML标记符
JSP标记(指令标记 动作标记)
变量和方法的声明
java程序片
java表达式
常用的HTML语句
<HTML> </HTML> 表示html文件的开始和结束
<BODY> </BODY> 表示文件的主体部分,该标记可以有BGCOLOR属性设置背景颜色。
<Hn> </Hn> 表示标题
<P> 表示分段
<BR> </BR> 表示换行
<FONT> </FONT> 表示设置字体,该标记可以有SIZE和COLOR属性
<A href=“连接的地址”> 连接提示信息 </A>
我们先举个例子
example2_1.jsp
<%@ page contentType="text/html;charset=GB2312" %> <!-- jsp指令标记 --> <%@ page import="java.util.Date" %> <!-- jsp指令标记 --> <%! Date date; // 数据声明 int start,end,sum; public int continueSum(int start,int end) // 方法声明 { for(int i=start;i<=end;i++) sum=sum+i; return sum; } %> <HTML><BODY bgcolor=cyan> <!—html标记 --> <FONT size=4><P>程序片创建Date对象: <% date=new Date(); //java程序片 out.println("<BR>"+date); start=1; end=100; sum=continueSum(start,end); %> <BR>从 <%= start %> <!-- Java表达式 --> 至 <%= end %> 的连续和是 <%= sum %> </FONT></BODY></HTML>
程序的运行结果是:
这里我们可以看到,第3行和第13行,是一对标记符号<%! 和 %>,在这对标记符号中间存放 了java程序,但是我们同样发现, 13行和18行,还有一对标记符号<% 和 %> 中间同样有java程序,他们的区别是什么呢?
回想一下java中的静态(static)变量和成员变量的区别,一个类的所有对象访问的都是同一个静态变量,即其中一个变量对静态变量的改变,都会导致所有对象访问该静态变量值的变化;但是成员变量则不一样,当其中一个对象对其成员变量进行改变时,其他对象访问该成员变量的值不发生变化。简单来说,所有对象共同访问一个静态变量,但是他们各自拥有自己的成员变量。
这个就类似于静态变量和实例变量的区别,<%! 和 %> 这一对中声明的类似于static变量,访问这个JSP页面的所有用户都访问的同一个变量或方法,而<% 和 %> 就像普通的变量,每一个用户,Tomcat都会为其分配一个全新的线程和执行这部分代码。我们把在<%! 和 %>中定义的变量称为成员变量,把在<% 和 %>中的java代码成为java程序片,声明的变量称为局部变量。
为了更好的说明这部分,我们继续刷新这个页面,或者再开启一页,我们会发现,数字会一直增大。
这就说明所有用户共享的是一个sum变量,第一个用户计算之后sum变成5050并返回,第二个用户在5050的基础上继续计算,即变成10100,如果sum是<% 和 %> 中定义的,则不会出现这种问题。
example2_2.jsp就是对<%! 和 %> 和<% 和 %> 的应用。
example2_2.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY BGCOLOR=cyan><FONT size=3> <%! int i=0; %> <% i++; %> <P>您是第 <%= i %> 个访问本站的客户。 </BODY></HTML>
程序的运行结果:
但是这个方法会产生一个潜在的风险,就是当两个或者多个用户同时访问这个网页,多个线程同时对成员变量进行访问或者更改,往往会发生意料之外的事情,比如多个用户同时访问例2_2中的 i,那么多个用户将收到同样的 i,怎么防止这个问题的发生呢?我们使用同步代码块(synchronized)来解决这个问题,同步代码块,顾名思义,这个代码块是同步的,也就是这部分代码具有原子性(不可再分),当一个线程在同步代码块中,其他线程不允许进入同步代码块,只有当前线程离开,其他线程才可以进入。
synchronized关键字可以在方法前进行声明(如例example2_4),也可以直接使用{}来进行声明。
synchronized{ count++; }
example2_4.jsp
<%@ page contentType="text/html;Charset=GB2312" %> <HTML><BODY> <%! int count=0; //被客户共享的count synchronized void setCount() //synchronized修饰的方法 { count++; } %> <% setCount(); out.println("您是第"+count+"个访问本站的客户"); %> </BODY></HTML>
程序的运行结果:
这个方法就是线程安全的,即在多线程的情况下,运行这个程序不会因为多线程产生一些未知bug。
Java表达式:
example2_6.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY bgcolor=cyan><FONT size=3> <% double a=12.89; int x=12,y=10; %> 计算表达式a+x*y-100/x+x%5的值: <%= a+x*y-100/x+x%5 %> <BR>计算表达式x>y&&a>0的值: <%=x>y&&a>0%> <BR>计算表达式sin(x)+cos(y): <%=Math.sin(x)+Math.cos(y)%> <BR> 求8的平方根: <%=Math.sqrt(8)%> </FONT></BODY></HTML>
我们发现,JSP代码中我们使用<%= 和 %> 中插入表达式(<%= 是一个完整的符号,他们中间不可以有空格)
我们看这个栗子的结果并思考,就可以理解<%= 和 %> 的用途了。
JSP中的注释:
html注释 <!- -注释内容- -> 发送到客户端,由游览器执行。
jsp注释 <%- -注释内容- -%> 引擎忽略,不发送到客户端。
(两个“-”中间没有空格,但是不加空格在这里会自动解析成一个杠,实际上是像下面代码中一样,没有空格)
example2_7.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY> <!-- 以下字体的颜色为蓝色 --> <FONT size=3 color=blue>抽取字符串"C:\myfile\jspfile\example.jsp"中的"example.jsp" </FONT> <%-- 下面是成员变量的声明 --%> <%! String s="C:\\myfile\\jspfile\\example.jsp"; %> <%-- 下面是Java程序片 --%> <% int index=s.lastIndexOf("\\"); String str=s.substring(index+1); %> <BR><%-- 下面是Java表达式 --%> <%= str %> </BODY></HTML>
我们看代码中,有两种注释,分别是橙色的HTML注释部分和红色部分的JSP注释。
在运行时,JSP引擎在处理JSP页面时,会忽略JSP注释,但是会保留HTML注释,一并发送到客户端,由客户端浏览器来解析。
为了验证这种说法,我们来访问这个页面并查看页面源码。
我们可以发现,代码中的java代码已经被执行,并只发送结果“example.jsp”到客户端,JSP注释部分也不像客户端发送,只发送了HTML注释部分。
JSP指令标记:
page指令标记:
page指令用来定义整个JSP页面的一些属性和这些属性的值,属性值用单引号或双引号括起来。可以用一个page指令指定多个属性的值,例如:
<%@ page 属性1 = "属性1的值" 属性2 = "属性2的值" ·····%>
或者
<%@ page 属性1 = "属性1的值"%> <%@ page 属性2 = "属性2的值"%> ··· ··· ···
page指令的作用对整个JSP页面有效,与其书写的位置无关。习惯上把page指令写在JSP页面的最前面。
page指令标记可以指定如下属性值:
contentType、import、language、session、buffer、auotFlush、isThreadSafe。
1.contentType 属性
contentType属性值确定JSP页面响应的MIME类型和JSP页面字符的编码。
<%@ page contentType="text/html;charset=GB2312" %>
这里MIME类型是text/html,JSP页面字符编码是GB2312。
MIME的作用是告诉用户浏览器以什么形式来解析服务器发过来的信息,编码则指定信息的编码方式。
这里比如我们将example2_7.jsp的contentType属性的MIME值改成application/msword,我们再次访问这个页面。
浏览器以word形式解析,我们打开之后发现依然是网页显示的那些东西,只不过是以word形式解析。
page属性还有:text/html, text/plain, image/gif, image/x-xbitmap, image/jpeg, application/msword 等。
2.language 属性
该属性定义JSP页面使用的语言,该属性值目前只能取java。
3.import 属性
该属性的作用是为JSP页面因为Java运行环境提供包中的类;可以为该属性制定多个值,该属性的值可以使某包中的所有类或者一个具体的类。有两种声明方式。
<%@ page import = "java.io.*","java.util.Date" %>
或者
<%@ page import = "java.io.*" %> <%@ page import = "java.util.Date" %>
4.session 属性
该属性用于设置是否需要使用内置的session对象。默认是true。
5.buffer 属性
该属性用来指定out设置的缓冲区的大小或者不使用缓冲区。例如
<%@ page buffer = "24KB" %>
buffer的默认值是8KB,还可以设置为“none”,即不设置缓冲区。
6.autoFlush 属性
该属性指定out缓冲区被填满时,是否自动刷新,默认值true。
当autoFlush为flase时,当缓冲区被填满,会产生内存溢出。
当buffer设置为“none”时,不允许设置autoFlush为flase。
7.isThreadSafe 属性
该属性用来设置JSP页面是否可以多线程访问,默认值为true。
当isThreadSafe为true时,允许多个用户同时访问该页面,当isThreadSafe为flase时,同一时刻只允许一个用户访问JSP页面,其他用户必须排队等待。
8.info 属性
该属性的属性值是一个字符串,其目的是为了JSP页面准备一个常用但可能要经常修改的字符串。例如,
<%@ page info = "we are students" %>
可以在JSP页面中使用方法:
getServletInfo();
来获取info属性的属性值。
example2_9.jsp
<%@ page contentType="text/html;charset=GB2312" %> <%@ page info="清华大学" %> <% String s=getServletInfo(); %> <head> <%= s %></head> <HTML><BODY bgcolor=white><FONT Size=4> <BR><%=s %>出版社是中国著名出版社 <BR><%=s %>是全国著名的高等学府 </BODY><HTML>
运行之后是这样的
我们看到info属性后面是“清华大学”,我们使用String s=getServletInfo();就可以获取到Info属性里面的字符串,这个方法一般用来准备一个常用但可能要经常修改的字符串。
include指令标记
如果需要在JSP页面内某处整体嵌入一个文件,就可以考虑使用include指令标记,其语法格式如下:
<%@ include file="文件的URL"%>
它的作用就是在该指令出现的地方,静态的插入一个文件,被插入的文件必须是可以访问或者可以使用的,并且文件插入后不会导致JSP语法错误(比如新插入的文件的contentType属性为application/msword,而原页面的属性为text/html,这样就会产生两个contentType属性,导致语法错误。)有点类似于方法的调用,该标记目的是提高代码的复用性,比如多个页面都需要同一个功能,那么在多个页面中只要include功能文件即可。比如下面这个栗子。
假如我们需要一个网站导航,点击可以跳转到相应的页面,导航部分代码如下:
在根目录下新建文件夹myfile,并新建ok.jsp。
ok.jsp
<%@ page contentType="text/html;charset=GB2312" %> <center> <A href = "example2_10_a.jsp">北京大学</A> <A href = "example2_10_b.jsp">清华大学</A> <p>
实际上,这个文件可以是任何可以访问的类型,只要是jsp语法即可,ok.txt 甚至ok.xml都行。
<A href = “example2_10_b.jsp”>清华大学</A> 这句话我们之前也提过,是专门用来跳转的语句(<A href=“连接的地址”> 连接提示信息 </A>)
我们再写include这个页面的jsp页面。
example2_10_a.jsp
<%@ page contentType="text/html;charset=GB2312" %> <%@ include file="myfile/ok.jsp" %> <HTMLl><BODY bgcolor=white> <P>我是北京大学的jsp页面 </BODY></HTML>
example2_10_b.jsp
<%@ page contentType="text/html;charset=GB2312" %> <%@ include file="myfile/ok.jsp" %> <HTML><BODY bgcolor=yellow> <P>我是清华大学的jsp页面 </BODY></HTML>
现在我们访问这两个页面任意一个。
我们发现上面有两个链接“北京大学”,和“清华大学”,和我们在后面加的文字“实际上这里可以直接打上你需要的文字”,我们点击清华大学,跳转到如下页面,我们发现导航栏依然在。
这种插入方式成为静态插入,即JSP引擎在编译原页面时,会将两个页面组合成一个新页面最终转移成字节码文件。也就是实际上example2_10_a.jsp这个页面的字节码文件已经包括了导航部分,JSP引擎在编译example2_10_a.jsp页面时,就将ok.jsp与example2_10_a.jsp合二为一并保存。
JSP动作标记
include、param动作标记
他们的语法格式是:
<jsp:include page="文件的URL"> <jsp:param name="名字" value="指定给param的值"/> ··· ··· </jsp:include>
该标记可以将param中的值传递到include动作要加载的文件中去,被加载的JSP页面可以使用内置方法request获取param的值。
example2_11.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY bgcolor=white > <% double a=3,b=4,c=5; %> <BR>加载triangle.jsp计算三边为<%=a%>,<%=b%>,<%=c%>的三角形面积: <jsp:include page="myfile/triangle.jsp"> <jsp:param name="sideA" value="<%=a%>"/> <jsp:param name="sideB" value="<%=b%>"/> <jsp:param name="sideC" value="<%=c%>"/> </jsp:include> </BODY></HTML>
我们在根目录下的myfile中新建triangle.jsp
triangle.jsp
<%@ page contentType="text/html;charset=GB2312" %> <%! public String getArea(double a,double b,double c) { if(a+b>c&&a+c>b&&c+b>a) { double p=(a+b+c)/2.0; double area=Math.sqrt(p*(p-a)*(p-b)*(p-c)) ; return ""+area; } else { return(""+a+","+b+","+c+"不能构成一个三角形,无法计算面积"); } } %> <% String sideA=request.getParameter("sideA"); String sideB=request.getParameter("sideB"); String sideC=request.getParameter("sideC"); double a=Double.parseDouble(sideA); double b=Double.parseDouble(sideB); double c=Double.parseDouble(sideC); %> <Font color=blue size=4> <P>我是被加载的文件,负责计算三角形的面积<BR> 给我传递的三边是:<%=sideA%>,<%=sideB%>,<%=sideC%> <BR>三角形的面积:<%= getArea(a,b,c)%> </Font>
我们访问example2_11.jsp页面,发现已经显示了跳转页面中的结果。
动作标记是动态的,不是在编译过程中加入的,而是在执行过程中,由引擎根据文件格式的不同(如果是文本文件直接发送到客户端,如果是JSP文件则本地执行发送结果),动态的执行。
所以这里的triangle.jsp文件就必须是.jsp文件,如果是其他格式的文件,会直接发送到客户端而不执行(浏览器显示代码),上个栗子中ok.jsp之所以可以是很多格式是因为静态插入时,JSP引擎在编译时将ok.jsp合并入了那两个页面变成一个页面了。
静态插入和动态插入的区别:
尽管他们的作用都是处理所需要的文件,但是处理方式和处理时间是不同的。include指令标记(静态)是在编译阶段就处理所需要的文件,被处理的文件在逻辑和语法上依赖于当前的JSP文件,其优点是页面的执行速度快。include动作标记(动态)是在JSP页面运行时再处理文件,被处理的文件在逻辑和语法上独立于当前的JSP页面,其优点是可以使用param子标记更灵活地处理所需要的文件,缺点是执行速度慢一些。
forward 动作标记
语法格式:
<jsp:forward page:"要转向的页面"/> 或者 <jsp:forward page:"要转向的页面"> <jsp:param name="名字" value="值"> ··· ··· </jsp:forward>
当没有param子标记时必须使用第一种格式。
该指令的作用是:从该指令处停止当前页面的执行,而转向执行page属性指定的JSP页面。
example2_12.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY> <% double i=Math.random(); if(i>0.5) { %> <jsp:forward page="/myfile/frontSide.jsp" > <jsp:param name="number" value="<%= i %>" /> </jsp:forward> <% } else { %> <jsp:forward page="/myfile/reverseSide.jsp" > <jsp:param name="number" value="<%= i %>" /> </jsp:forward> <% } %> </BODY></HTML>
在myfile中新建
frontSide.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY bgcolor=white><Font size=3> <% String s=request.getParameter("number"); out.println("<BR>传递过来的值是"+s); %> <BR>这是另一个页面 </FONT></BODY></HTML>
receiveSide.jsp
<%@ page contentType="text/html;charset=GB2312" %> <HTML><BODY bgcolor=white><Font size=3> <% String s=request.getParameter("number"); out.println("传递过来的值是"+s); %> <BR>这是一个页面 </FONT></BODY></HTML>
我们访问127.0.0.1:8080/example2_12.jsp
或者
需要注意的是,当前页面使用forward动作标记转向后,尽管用户看到了转向后的页面的效果,但是浏览器的地址栏依然是转向前的JSP页面,因此,如果刷新当前页面,会回到转向前的页面。
useBean 动作标记
见JSP与javaBean。
课后题:
1.”<%!”和”%>”之间声明的变量与.”<%”和”%>”之间声明的变量有何不同?
· <%! %>之间声明的变量和方法在整个jsp页面内都有效,也就是说可以理解为<%! %>之间声明的是全局的变量和方法,方法可以被公有使用,变量则可以被所有方法调用改变。当有运行多个线程时,任何一个线程对jsp页面成员变量操作的结果,都会影响其他线程。
在<% %>之间声明的变量则为“局部变量”,当运行多个线程时,不同线程中的java程序片的局部变量互不干扰,也就是说一个用户改变java程序片中的局部变量的值不会影响下一个用户java程序片中的局部变量。
2.如果有两个用户访问一个JSP页面,该页面中的java程序片将被执行几次?
· 两次。(java程序片特指<% %>中的java语句)
3.是否允许JSP页面同时含有如下两条page指令:<%@ page contentType=”text/html;charset=gb2312″ %>、<%@ page contentType=”application/msword” %>
· 不允许。
4.是否允许JSP页面同时含有如下两条page指令:<%@ page import=”java.util.*” %>、<%@ page import=”java.sql.*” %>
· 允许。
5.假设有两个用户访问下列JSP页面hello.jsp,请问第一个访问和第二个访问hello.jsp页面的用户看到的页面的效果有何不同?
hello.jsp
<%@ page contentType="text/html;charset=gb2312" %> <%@ page isThreadSafe="flase" %> <HTML><BODY> <%! int sum = 1; void add(int m){ sum = sum+m; } %> <% int n = 100; add(n); %> <%=sum%> </BODY></HTML>
· 第一个用户看到的是101,第二个用户看到的是201。
6.请编写一个简单的JSP页面,显示英文字母表。
<%@ page contentType="text/html;charset=gb2312" %> <% char letter = 'a'; for(int i=0;i<26;i++){ out.println((char)(letter+i)); } %> <BR> <% letter = (char)(letter-32); for(int i=0;i<26;i++){ out.println((char)(letter+i)); } %>
7.请简单叙述include指令标记和include动作标记的不同。
· include指令标记是在编译阶段就处理所需要的文件,被处理的文件在逻辑和语法上依赖于当前的JSP文件,其优点是页面的执行速度快。include动作标记是在JSP页面运行时再处理文件,被处理的文件在逻辑和语法上独立于当前的JSP页面,其优点是可以使用param子标记更灵活地处理所需要的文件,缺点是执行速度慢一些。
8.编写三个JSP页面:main.jsp、circle.jsp和ladder.jsp,将三个JSP页面保存在Web服务器目录中。main使用include动作标记加载circle和ladder页面。circle页面可以计算并显示圆的面积,ladder页面可以计算并显示梯形的面积。当circle和ladder被加载时获取main页面include动作标记的param子标记提供的圆的半径以及提醒的上底、下底和高的值。
main.jsp
<%@ page contentType="text/html;charset=gb2312" %> <% int r = 3; int upper = 1,lower = 2,high = 1; %> <jsp:include page="/myfile/circle.jsp"> <jsp:param name="r" value="<%=r%>"/> </jsp:include> <jsp:include page="myfile/ladder.jsp"> <jsp:param name="upper" value="<%= upper%>"/> <jsp:param name="lower" value="<%= lower%>"/> <jsp:param name="high" value="<%= high%>"/> </jsp:include>
circle.jsp
<%@ page contentType="text/html;charset=gb2312" %> <%! public double compute(int r){ return r*r*3.14159265; } %> <% String r = request.getParameter("r"); int a = Integer.parseInt(r); double area = compute(a); %> <frot color=blue size=2> <br> 圆的面积是<%=area%>
ladder.jsp
<%@ page contentType="text/html;charset=gb2312" %> <%! double compute(int upper,int lower,int high){ return (upper+lower)*high/2; } %> <% String upper = request.getParameter("upper"); String lower = request.getParameter("lower"); String high = request.getParameter("high"); double area = compute(Integer.parseInt(upper),Integer.parseInt(lower),Integer.parseInt(high)); %> <frot color=blue size=2> <br> 梯形的面积是<%=area%>
0 条评论