JSP的本质是Servlet,当用户向指定Servlet发送请求时,Servlet利用输出流动态生成HTML页面,包括每一个静态的HTML标签和所有在HTML页面中出现的内容。
由于包括大量的HTML标签、大量的静态文本及格式等,导致Servlet的开发效率极为低下。所有的表现逻辑,包括布局、色彩及图像等,都必须耦合在Java代码中,这的确让人不胜其烦。JSP的出现弥补了这种不足,JSP通过在标准的HTML页面中嵌入Java代码,其静态的部分无须Java程序控制,只有那些需要从数据库读取或需要动态生成的页面内容,才使用Java脚本控制。
从上面的介绍可以看出,JSP页面的内容由如下两部分组成。
静态部分:标准的HTML标签、静态的页面内容,这些内容与静态HTML页面相同。
动态部分:受Java程序控制的内容,这些内容由Java程序来动态生成。
下面是一个最简单的JSP页面代码。
程序清单:codes\02\2.2\jspPrinciple\first.jsp
- <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
- <html>
- <head>
- <title>欢迎</title>
- </head>
- <body>
欢迎学习Java Web知识,现在时间是:
- <%out.println(new java.util.Date());%>
- </body>
- </html>
上面的页面中粗体字代码放在<%和%>之间,表明这些是Java脚本,而不是静态内容,通过这种方式就可以把Java代码嵌入HTML页面中,这就变成了动态的JSP页面。在浏览器中浏览该页面,将看到如图2.2所示的页面。
图2.2 JSP页面的静态部分和动态部分 |
上面JSP页面必须放在Web应用中才有效,所以编写该JSP页面之前应该先构建一个Web应用。本章后面介绍的内容都必须运行在Web应用中,所以也必须先构建Web应用。
从表面上看,JSP页面已经不再需要Java类,似乎完全脱离了Java面向对象的特征。事实上,JSP的本质依然是Servlet(一个特殊的Java类),每个JSP页面就是一个Servlet实例--JSP页面由系统编译成Servlet,Servlet再负责响应用户请求。也就是说,JSP其实也是Servlet的一种简化,使用JSP时,其实还是使用Servlet,因为Web应用中的每个JSP页面都会由Servlet容器生成对应的Servlet。对于Tomcat而言,JSP页面生成的Servlet放在work路径对应的Web应用下。
再看如下一个简单的JSP页面。
程序清单:codes\02\2.2\jspPrinciple\test.jsp
- <!-- 表明这是一个JSP页面 -->
- <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %>
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title> 第二个JSP页面 </title>
- </head>
- <body>
- <!-- 下面是Java脚本 -->
- <%for(int i = 0 ; i < 7; i++)
- {
- out.println("<font size='" + i + "'>");
- %>
- 疯狂Java训练营(Wild Java Camp)</font>
- <br/>
- <%}%>
- </body>
- </html>
当启动Tomcat之后,可以在Tomcat的work\Catalina\localhost\jspPrinciple\org\apache\jsp目录下找到如下文件(本Web应用名为jspPrinciple,上面JSP页的名为test.jsp):test_jsp.java和test_jsp.class。这两个文件都是由Tomcat生成的,Tomcat根据JSP页面生成对应Servlet的Java文件和class文件。
下面是test1_jsp.java文件的源代码,这是一个特殊的Java类,是一个Servlet类。
程序清单:codes\02\2.2\test.java
- //JSP页面经过Tomcat编译后默认的包
- package org.apache.jsp;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import javax.servlet.jsp.*;
- //继承HttpJspBase类,该类其实是Servlet的子类
- public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
- implements org.apache.jasper.runtime.JspSourceDependent {
- private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
- private static java.util.List<String> _jspx_dependants;
- private javax.el.ExpressionFactory _el_expressionfactory;
- private org.apache.tomcat.InstanceManager _jsp_instancemanager;
- public java.util.List<String> getDependants() {
- return _jspx_dependants;
- }
- public void _jspInit() {
- _el_expressionfactory = _jspxFactory.getJspApplicationContext
- (getServletConfig().getServletContext()).getExpressionFactory();
- _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory
- .getInstanceManager(getServletConfig());
- }
- public void _jspDestroy() {
- }
- //用于响应用户请求的方法
- public void _jspService(HttpServletRequest request, HttpServletResponse response)
- throws java.io.IOException, ServletException {
- 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 {
- response.setContentType("text/html; charset=GBK");
- pageContext = _jspxFactory.getPageContext(this, request, response,
- "", 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("\r\n");
- out.write("\r\n");
- out.write("<!DOCTYPE html PUBLIC \"-// W3C//DTD XHTML 1.0 Transitional //EN\"\r\n");
- out.write("\t\"http://www.w3.org/TR/ xhtml1/DTD/xhtml1-transitional. dtd\"> \r\n");
- out.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
- out.write("<head>\r\n");
- out.write("\t<title> 第二个JSP页面 </title>\r\n");
- out.write("\t<meta name=\"website\" content=\http://www.crazyit.org\ />\ r\n");
- out.write("</head>\r\n");
- out.write("<body>\r\n");
- out.write("<!-- 下面是Java脚本 -->\r\n");
- for(int i = 0 ; i < 7; i++)
- {
- out.println("<font size='" + i + "'>");
- out.write("\r\n");
- out.write("疯狂Java训练营(Wild Java Camp)</font>\r\n");
- out.write("<br/>\r\n");
- }
- out.write("\r\n");
- out.write("</body>\r\n");
- out.write("</html>");
- } catch (Throwable t) {
- if (!(t instanceof SkipPageException)){
- out = _jspx_out;
- if (out != null && out.getBufferSize() != 0)
- try { out.clearBuffer(); } catch (java.io.IOException e) {}
- if (_jspx_page_context != null) _jspx_page_context.handlePage Exception(t);
- }
- } finally {
- _jspxFactory.releasePageContext(_jspx_page_context);
- }
- }
- }
初学者看到上面的Java类可能有点难以阅读,其实这就是一个Servlet类的源代码,该Java类主要包含如下三个方法(去除方法名中的_jsp前缀,再将首字母小写)。
init():初始化JSP/Servlet的方法。
destroy():销毁JSP/Servlet之前的方法。
service():对用户请求生成响应的方法。
即使读者暂时不了解上面提供的Java代码,也依然不会影响JSP页面的编写,因为这都是由Web容器负责生成的,后面介绍了编写Servlet的知识之后再来看这个Java类将十分清晰。浏览该页面可看到如图2.3所示的页面。
图2.3 使用Java代码控制静态内容 |
从图2.3中可以看出,JSP页面里的Java代码不仅仅可以输出动态内容,还可以动态控制页面里的静态内容,例如,从图2.3中看到将"疯狂Java训练营(Wild Java Camp)"重复输出了7次。
根据图2.3所示的执行效果,再次对比test1.jsp和test1_jsp.java文件,可得到一个结论:JSP页面中的所有内容都由test1_jsp.java文件的页面输出流来生成。图2.4显示了JSP页面的工作原理。
图2.4 JSP页面的工作原理 |
根据上面的JSP页面工作原理图,可以得到如下4个结论:
JSP文件必须在JSP服务器内运行。
JSP文件必须生成Servlet才能执行。
每个JSP页面的第一个访问者速度很慢,因为必须等待JSP编译成Servlet。
JSP页面的访问者无须安装任何客户端,甚至不需要可以运行Java的运行环境,因为JSP页面输送到客户端的是标准HTML页面。
JSP技术的出现,大大提高了Java动态网站的开发效率,所以得到了Java动态网站开发者的广泛支持。