Servlet 和 JSP 要同时学习和使用。JSP 是编写 servlet 的另一种不同的方式。如果你不了解 servlet 编程,那么即使存在比JSP更好的选择,你也不能使用 MVC 构架来集成 servlet 和 JSP, 不能理解复杂的 JSP 构造,不能理解 JSP 脚本(scripting)元素如何工作;如果你不了解 JSP 开发,当 JSP 比 servlet 更适用时,你就不能使用 JSP、 MVC框架,同时,即使几乎完全是 静态 HTML 的页面,你也要借助 Print 语句。
1、Servlet 和 JSP技术概述
- **定义**servlet 是运行在 Web 服务器或应用服务器上的 Java 程序,它是一个中间层,负责连接来自其他 HTTP 客户程序的请求和 HTTP 服务器上的数据库或应用程序。
-
servlet 的工作
- 读取客户发送的显式数据(如何读取 第4章)
- 读取由浏览器发送的隐式请求数据(第5章)
- 生成结果:这个过程可能需要访问数据库、执行 RMI 或 EJB 调用、调用 Web 服务,或者直接计算得出对应的响应。实际的数据可能存储在关系型数据库中。该数据库可能不理解 HTTP,或者不能返回 HTML 形式的结果,所以 Web 浏览器不能直接与数据库进行会话。即使它能够做到这一点,为了安全上的考虑,我们也不这样做。对于大多数其他应用程序,也存在类似的问题。因此,我们需要 Web 中间层从 HTTP 流中提取输入数据,与应用程序会话,并将结果嵌入到文档中。
- 向客户发送显式数据(即文档):这个文档可以用各种格式发送,包括文本(HTML或XML),二进制(GIF图),甚至可以是建立在其他底层格式之上的压缩格式,如gzip。但是,到目前为止,HTML是最常用的格式,故而servlet和JSP的重要任务之一就是将结果包装到HTML中。
- 发送隐式的 HTTP 响应数据:HTTP响应数据的发送过程涉及告知浏览器或其他客户程序所返回文档的类型(例如HTML),设置cookie和缓存参数,以及其他类似的任务。(第6章和第7章)
-
动态生成网页的理由
- 网页基于客户发送的数据:例如,搜索引擎生成的页面。用户提交的两种类型的数据:显式(HTML表单数据)和隐式(HTTP请求的报头),两种数据都可用来构建输出界面。基于 cookie 值针对具体用户构建页面的情况尤其普遍。
- 网页由频繁改变的数据导出:如果页面需要根据每个具体的请求做出相应的更改当然需要在请求发生时构建响应。但是如果页面周期性地改变,我们可以用两种方式来处理它。周期性地在服务器上构建新的网页(和客户请求无关),或者仅仅在用户请求该页面时再构建。具体应该采用哪种方式要依具体情况而定,但后一种方式常常更为方便,因为它只需简单地等待用户的请求。例如,天气预报或新闻网站可能会动态地构建页面,也有可能会返回之前构建的页面(如果它还是最新的话)。
- 网页中使用了来自公共数据库或其他服务器端数据源的信息:如果数据存储在数据库中,那么,即使客户端使用动态Web内容,比如applet,我们依旧需要执行服务器端处理。我们需要与数据库进行会话。从客户端到Web层再到数据库(三层结构),要比从applet直接到数据库(二层结构)主灵活,也更安全,而性能上的损失很少甚至没有。毕竟数据库调用通常是对速度影响最大的步骤,因而,经过Web服务器不会带来性能上的明显降低。实际上,三层结构常常更快,因为中间层(middle tieq)可以执行高速缓存(caching)和连接共享(connection pooling)。
- 服务器:理论上讲,servlet并非只用于处理HTTP请求的Web服务器或应用服务器,它同样可以用于其他类型的服务器。例如,servlet能够嵌入到FTP或邮件服务器中,扩展它们的功能。而且,用于会话启动协议(Session Initiation Protocol,SIP)服务器的servlet API最近己经被标准化。但在实践中,servlet的这种用法尚不流行。
-
优点:
- 效率:实例化更少的对象;能直接存储客户请求之间的任意复杂数据
- 便利:能自动分析和解码HTML的表单数据,读取和设置HTTP报头,处理cookie,跟踪会话
- 强大:直接Web服务器对话;多个servlet共享数据,实现数据库连接共享;servlet维护请求之间的信息,更容易实现会话跟踪和计算结果缓存
- 可移植性
- 廉价:能从免费的服务器开始(如Apache Tomcat),移到性能更高的付费服务器(如Caucho Resin),servlet 和 JSP 不需要更改
- 安全:数组边界的检查、内存保护特性
- 主流
- 简化地看,servlet 是含有HTML的Java程序;JSP是含有Java代码的HTML页面。JSP文档只不过是编写servlet的另一种方式,JSP页面会被翻译成servlet,servlet会被编译,在请求期间运行的就是servlet。
- servlet和JSP的区别:JSP注重简化HTML的创建和维护;servlet最适合于调用商业逻辑,执行复杂操作。一个规则,对于面向处理(processing)的任务用servlet,面向表示(presentation)的任务用JSP。需要将二者结合起来使用。
第一部分:servlet技术(第2章-第9章)
2、服务器的安装和配置
- 在桌面上部署服务器的原因:
- 测试快速
- 易于调式:简单的System.out.println语句成为跟踪和调试的有效工具
- 易于重启
- 基准更为可靠
- 完全控制
- 易于安装
- 用于桌面开发的最为流行的免费服务器
- Apache Tomcat:免费;完整的源代码;对最新servlet和JSP规范的支持最好
- Macromedia Jrun:既能够以独立的模式用于开发过程中,也可以在部署过程中插入到大多数商业Web服务器中
- Caucho Resin:对XML提供广泛支持
- New Atlanta 的 ServletExec
- Jetty
- 启用servlet重新载入功能:默认关闭,对于那些已载入到服务器内存的servlet,每次重新编译后都得重新启动服务器或重新载入web应用。修改Tomcat安装目录下/conf/server.xml,向主 Service元素加入DefaultContext子元素
<DefaultContext reloadable="true"/>
-
测试服务器的基本设置:双击/bin/startup.bat,在浏览器里输入localhost:8080/,如果出现“If you’re seeing this, you’ve successfully installed Tomcat. Congratulations!”表示成功。如果Tomcat不能允许,到/bin目录中输入
catalina run;
,这样可以阻止Tomcat启动另外的单独窗口,从而看到诸如端口被占用等错误消息。 -
建立开发环境
- 创建开发目录:不要在服务器的部署目录作为开发场所,应该在单独的目录中进行开发
-
设置CLASSPATH:告诉编译器servlet类的位置 将 /lib/servlet.jar 添加到CLASSPATH中;一定要将开发目录加入CLASSPATH中,否则如果包中的servlet使用了同一包中其他的类,编译出错“Unresolved symbol”;还应包括“.”当前目录,否则只能编译那些开发目录顶层的无包装的类
set CLASSPATH=.;开发目录;install_tomcat\lib\servlet.jar
警告:CLASSPATH必须包括开发的顶层目录,否则,当试图编译的servlet属于包,且使用包中用户定义的类时,会产生“unresolved symbol”错误信息。 - 创建启动和停止服务器的快捷方式: 对lib中的startup.bat和shutdown.bat进行复制,然后在开发目录中选择 粘贴快捷方式,而非粘贴。你可以设置快捷方式属性的键盘快捷方式,就可以通过Ctrl+alt+somekey启动和停止服务器。
- 标记或安装servlet和JSP的API文档:你将频繁地参考这份文档
- 测试系统的设置
- 检验SDK的安装:
java -version
,javac -help
- 检查服务器的基本配置:启动服务器,访问http://localhost:8080/;能够成功访问HTML页面(你了解哪个目录保存HTML和JSP页面);能够成功访问新建的JSP页面说明Java编译器配置正确。
- 编译并部署一些简单的servlet
- 检验SDK的安装:
- 实现简单的部署方法
- 复制成快捷方式或符号连接:初学者
- 使用javac的 -d 选项:只适用于Java类文件,不能部署HTML和JSP页面
- 由IDE完成部署:IDE专有技术,不能跨系统移植
- 使用ant或类似工具:灵活,从编译Java源代码,复制文件到生成war文件;学习曲线比较陡峭
- Web应用:初学时使用默认web应用和默认的servlet URL;对于正式应用,使用定制的(在web.xml中指定)
为编写的 servlet分配定制的URL:- 部署描述文件的位置:web.xml总是放置在 WEB-INF目录中
- 基本格式:开头是XML表头和DOCTYPE声明,并且含有一个web-app元素
- servlet的命名:使用servlet元素的servlet-name(选取任意名称)和serv-class(完全限定类名)子元素
- URL的指定:使用servlet-mapping的servlet-name和url-pattern(URL前缀,由斜杠/开始)子元素
- 部署描述文件的读取:修改web.xml文件要重启服务器
3、servlet基础
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ServletTemplate extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Use "request" to read incoming HTTP headers
// (e.g., cookies) and query data from HTML forms.
// Use "response" to specify the HTTP response status
// code and headers (e.g., the content type, cookies).
PrintWriter out = response.getWriter();
// Use "out" to send content to browser
}
}
- servlet 一般扩展HttpServlet,并依数据发送方式的不同(GET或POST),覆盖doGet或doPost方法。如果希望对GET和POST请求采用同样的行动,只需要让doGet调用doPost,反之亦然。
通过HttpDervletRequest提供的方法可以得到表单数据、HTTP请求报头和客户的主机名等信息;通过HttpServletResponse可以指定输出信息,比如HTTP状态码和响应报头。通过HttpServletResponse可以获得PrintWriter,用它可以将文档内容发送给客户。 - servlet要生成HTML,需要:告知浏览器,即将向它发送HTML:指明HTML的方式是使用text/html类型(
response.setContentType("text/html");
放在任何使用PrintWriter的行之前);用println语句输出HTML;核实生成的HTML - Java页面使用的定制类一定要放在包中,包是Java中用以避免命名冲突的标准解决方案
- 标准servlet中,Web页面的两部分内容(DOCTYPE和HEAD)一般不变,可以归结到一个简单的实用工具文件中
-
service方法
- 服务器每次接收到对servlet的请求,都会产生一个新的线程,调用service方法。service方法检查HTTP请求的类型并相应地调用doGet、doPost等方法。service提供对HEAD、OPTION和TRACE请求的自动支持。
- Get请求起因于正常的URL请求,或没有指定METHOD的HTML表单;POST请求起因于特别将POST列为METHOD的HTML表单。如果你的servlet需要等同地处理GET和POST,可以让doPost方法调用doGet
- init方法:在servlet初次创建时被调用,主要用于一次性的初始化。 常规初始化,以及由初始化参数控制的初始化
- destroy方法:使得servlet在服务器移除servlet的实例之前有机会关闭数据库连接、停止后台运行的线程、将cookie列表和点击计数写入到磁盘、并执行其他清理活动。
- 使用
synchronized(this){代码块}
来同步对代码的访问,一旦一个线程进入代码块,则直到该线程退出为止,不允许任何其他线程进入 - 调试servlet的10种通用策略
- 使用打印语句:如果产生NullPointerException,可以插入几个打印语句,找出哪一行代码生成这个错误,该行哪个对象为null
- 使用IDE中的调试器:断点、跟踪方法调用
- 使用日志文件log
- Log4J
- 编写独立的类
- 预先做好数据缺失或异常的准备
- 检查HTML源代码
- 单独检查请求数据EchoServer类
- 单独检查响应数据
- 停止和重启服务器