- 你写的JSP最终会变成一个servlet在Web应用中运行。它与其他servlet非常相似,只不过这个servlet类会由容器为你编写。
- 容器拿到你在JSP中写的代码,把这些代码转换为一个servlet类源文件,然后再把这个源文件编译为Java Servlet类。
- 学习JSP就是要搞清楚一点:你的JSP代码在最后的servlet类中扮演什么角色(换句话说,JSP中的元素最后会放在所生成servlet相应源代码中的什么位置)
下面代码是一个Web应用,写了一个计数器普通类,一个JSP页面。你可以建立一个JavaWeb应用,布署到服务器,访问看看效果。
Counter.java
package foo;
public class Counter{
private static int count;
public static synchronized int getCount(){
count++;
return count;
}
}
- BasicCounter.jsp
<html>
<body>
The page count is:
<%
out.println(Counter.getCount());
%>
</body>
</html>
- 你实验一下,上面代码运行,页面会出现500错误
- 原因:Counter类在foo包中,但是JSP无法了解这一点。
- 解决方法:要么导入包,要么在代码中使用完全限定类名。把上面的out语句改成下面这样,就不会出错了,这是完全限定类名:
out.println(foo.Counter.getCount());
使用page指令导入包
JSP有很多指令,指令为你提供了一条途径,可以在页面转换时向容器提供特殊的指示。指令有3种:page、include和taglib。现在我们先学习page指令。
BasicCounter.jsp
<%@ page import="foo.*" %>
<html>
<body>
The page count is:
<%
out.println(Counter.getCount());
%>
</body>
</html>
- 上面相关代码的区别:
- Java代码放在带百分号的尖括号中间:<%和%>
- 指令会为元素开始记号再增加一个字符:@
- 以后只要看到以<%@开始的JSP代码,我们应该知道这是一个JSP指令。
表达式元素
- 上面的JSP代码还是有out.println()语句。引入JSP,部分原因就是为了避免大量的println()语句出现。
有JSP表达式元素,表达式元素会自动打印放在标记之间的内容。
BasicCounter.jsp
<%@ page import="foo.*" %>
<html>
<body>
The page count is:
<%= Counter.getCount()%>
</body>
</html>
- 注意到Java代码的标记与表达式的标记有什么不同
- Java代码介于带百分号的尖括号中间<% %>
- 而表达式会为元素的开始记号再增加一个字符:一个等号(=)<%= %>
- 小总结:到目前为止,我们已经看到了3种不同类型的JSP元素:
- Java: <% %>
- 指令: <%@ %>
- 表达式: <%= %>
表达式容易出现的错误:
不要在表达式的最后加上分号
这样写是正确的:
<%= Counter.getCount()%>
- 这样写是错误的:
<%= Counter.getCount();%>
- 因为:容器拿到你在<%=和%>之间键入的所有内容,会把它作为参数传递给打印语句。上面的表达式会转换成下面这行代码:
out.println(Counter.getCount());
- 你如果放上分号,就成为下面这样,就是错误的:
out.println(Counter.getCount(););
上面计数器不写Counter类,直接在JSP定义一个变量,这样可以吗?
- BasicCounter.jsp
<html>
<body>
<%int count=0;%>
The page count is now:
<%= ++count %>
</body>
</html>
- 你写的是JSP,但它会变成一个servlet,要想知道到底发生了什么,唯一的办法是查看容器对你的JSP代码做了什么。
- 实际生成的servlet源代码读起来会稍微困难一点,略读即可,关键看我们写的相关代码出现在servlet哪个位置。
- 看Tomcat把JSP转换生成的servlet代码,可以查看tomcat/work/Catalina/localhost/yourWebAppName/org/apache/jsp,里面的源文件。
- 你会发现,所有scriptlet和表达式代码都放在服务方法中,这说明scriptlet中声明的变量总是局部变量。
需要另一个JSP元素:JSP声明
在scriptlet中声明count,意味着,每次运行服务方法时这个变量都会重新初始化。这说明对于每个请求它都会重置为0。我们需要以某种方式让count成为一个实例变量。
声明的JSP元素。
<%! int count=0; %>
- 百分号后面要放一个感叹号。
- JSP 声明用于声明所生成servlet类的成员。这说明变量和方法都可以声明。换句话说,<%!和%>标记之间的所有内容都会增加到类中,而且置于服务方法之外。
- 这意味着完全可以声明静态变量和方法。
上例的count总是计数为1。有了这个声明元素,你想一下,怎么通过声明元素,能让它有效计数。
BasicCounter.jsp,包含变量声明。
<html> <body> <%! int count=0; %> The page count is now: <%= ++count %> </body> </html>
- BasicCounter.jsp,增加了方法声明。
<html> <body> <%! int doubleCount(){ count = count*2; return count;} %> <%! int count=1; %> The page count is now: <%= doubleCount() %> </body> </html>
实验:
- 以下三个JSP页面的代码,这样写对不对?如果不对,你对它进行修改。
- 代码1
<html> <body> Test scriptlets... <% int y=5+x; %> <% int x=2; %> </body> </html>
- 代码2
<%@ page import="java.util.*" %> <html> <body> Test scriptlets... <% ArrayList list = new ArrayLIst(); list.add(new String("foo")); %> <%= list.get(0) %> </body> </html>
- 代码3
<html> <body> Test scriptlets... <%! int x = 42; %> <% int x = 22; %> <%= x %> </body> </html>