第4讲 Servlet开发基础

第4讲 Servlet开发基础
·Servlet的有关概念与前置知识
·Servlet应用入门
·Servlet的特点及运行过程
·ServletConfig接口
·GenericServlet与HttpServlet类
·ServletContext接口

Servlet的有关概念与前置知识
·什么是动态网页
·动态网页程序与引擎
·Servlet技术简介
·B/S系统架构与C/S系统架构
·Servlet开发设计的相关技术

什么是动态网页
·如果浏览器在不同时刻或不同条件下访问WEB服务器上的某个页面,浏览器所获得的页面内容可以发生变化,那么这个页面就称之为动态网页。
·要想让浏览器访问某一WEB页面时,能够查询出一些动态变化的实时信息,例如,某日某次列车的车票剩余状况,浏览器在不同时刻所得的WEB页面的内容必须随着车票的剩余状况进行变化,这就必须采用动态网页来实现。
·浏览器只关心如何显示和处理WEB服务器所返回的内容,浏览器处理动态网页的方式与它处理静态网页的方式完全相同、并无差异。
·Web服务器发送的静态内容直接来自文本或数据文件,而动态内容需要依靠一个程序来临时产生。

指点迷津:区分动态网页与动态HTML页面的概念?
动态网页是指WEB服务器端所创建的内容动态变化的网页,而动态HTML网页是指使用客户端脚本程序所实现具有动态视觉效果的网页,虽然动态HTML页面也可以在浏览器中显示出视觉上的动态效果并能与用户进行交互,但是它这种动态视觉效果是浏览器程序执行的结果,它并不是网页源文件的内容改变后的结果。

动态网页程序与引擎(1)
·动态网页内容的创建过程包含两个步骤:
 -首先使用某种编程语言编写出相应的动态网页程序;
 -然后由一个专门的WEB服务器程序模块来解释执行该动态网页程序。
·在动态网页程序的代码中可以完成各种程序逻辑控制、获取客户端传递的数据、对数据库进行操作、创建输出内容等功能,WEB程序开发就是指使用某种编程语言来编写完成上述功能的动态网页程序。
·动态网页程序需要有一个专门的WEB服务器程序模块来解释执行,专门解释和执行某种动态网页程序的WEB服务器程序模块习惯上被称为引擎,譬如ASP引擎、Servlet引擎、JSP引擎等等。
·只有引擎会与浏览器直接进行信息交换,动态网页程序不直接与浏览器进行信息交换,动态网页程序只与引擎进行信息交换,由引擎将浏览器的信息传递给动态网页程序和将动态网页程序生成的结果回送给浏览器。
·引擎提供的API有两个基本的作用:一些API用于将访问请求的相关信息传递给动态网页程序;另外一些API将动态网页程序产生的结果传递给引擎。

浏览器、引擎、API和动态网页程序之间的关系

动态网页程序与引擎(2)
·客户端向WEB服务器请求的URL资源路径,不仅可以指向服务器端的一个静态HTML文件,还可以指向服务器端的某种可被解释运行的程序文件。
·如果客户端请求的URL后缀名符合某种引擎所处理的资源名的特征,WEB服务器将把请求转交给相应的引擎去处理,然后由引擎去调用某个程序文件,并将程序动态产生的内容返回给客户端。
·动态网页程序文件中的代码不仅可以创建出用于返回给浏览器的动态变化内容,还可以实现对数据库的插入、修改、删除和查询等操作、从而让网站可实现论坛交流、产品订购、问卷调查、甚至是企业的整个管理信息系统等功能。
·目前有不少公司提供了动态网页的解决方案,称之服务器端的WEB编程技术,常见的技术有CGI、ISAPI、ASP、ASP.NET、Servlet/JSP、PHP灯,这些技术分别使用不同的编程语言。

Servlet技术简介
·Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的WEB服务器端编程技术。
·Servlet技术也是JSP技术(另外一种动态网页开发技术)的基础。
·一个Servlet程序就是一个实现了特殊接口的Java类,它由支持Servlet(具有Servlet引擎)的WEB服务器调用和启动运行。一个Servlet程序负责处理它所对应的一个或一组URL地址的访问请求,并接收客户端发出的访问请求信息和产生响应内容。
·Applet是用于浏览器的Java小程序,Servlet是用于WEB服务器端的Java小程序。
·Servlet程序可以完成普通Java程序所能完成的大多数任务:
 -获取客户端通过HTML的FORM表单递交的数据和URL后面的参数信息
 -创建对客户端的响应消息内容
 -访问服务器端的文件系统
 -连接数据库并开发基于数据库的应用
 -调用其它的java类

B/S系统架构与C/S系统架构
·企业信息管理软件系统的一个重要特点就是:要使用多台计算机作为操作终端,而系统的数据信息集中存放在网络上的数据库服务器中。
·在开发企业信息管理软件时,人们通常需要在两种系统架构之间进行选择,即C/S架构和B/S架构。
·C/S架构是Client/Server的简写,也就是客户机/服务器架构,它是早期出现的一种分布式架构。
·B/S架构是Browser/Server的简写,也就是浏览器/服务器架构,它是随着Internet技术的兴起,对C/S架构的一种变化和改进的架构。
C/S系统架构
C/S系统架构的特点
·缺点:
 -数据库系统支持的并发连接数有限,限制了同时运行的客户端程序的数目。
 -业务逻辑处理和界面显示都是由客户端程序负责处理,一旦业务逻辑或者显示界面要发生变化,则需要对整个客户端程序进行修改 ,不利于软件的维护和功能扩展。
 -每个客户机上都需要安装客户端程序,对于大一点的企业来说,如果客户端程序发生了修改,则需要系统管理人员到几百甚至上千  台客户机上去重新安装客户端程序。
·有点:
 客户端程序就是计算机上的一个桌面程序,功能可以做得非常强大,例如,在数据库服务器不可用时仍可以独立运行,可以将事务记录保存在本地桌面数据库中后再集中向数据库服务器提交,很容易对数据库中的数据进行实时监控和实现报警功能。

B/S系统架构

B/S系统架构的优点
·B/S架构将程序中的界面显示和业务逻辑处理都移动到了WEB服务器中来实现,其应用全部集中到了WEB服务器端,客户端只需要具有浏览器就可以作为B/S架构的操作终端,而不用安装和部署任何程序。
·B/S架构中的用户操作界面是由WEB服务器创建的,当要修改系统提供的用户操作界面时,只需要在WEB服务器端修改相应的网页文档,整个系统的更新部署不需要在客户机上进行任何操作和设置,在用户的不知不觉中就迅速完成,可以做到快速服务相应。
·客户端不直接与数据库建立连接,而是只有WEB服务器端的程序需要与数据库建立连接,所以数据库并发连接数量有限制的问题也得到了解决。
·B/S架构应作为各类信息管理系统的首选体系架构,它基本上已全面取代了C/S架构。

Servlet开发涉及到的相关知识
·良好的Java编程基础
·熟悉XML、HTTP协议和WEB站点管理
·熟悉HTML语言、CSS和JavaScript
·一定的数据库理论和开发基础


Servlet开发入门
·Servlet API介绍
·编写与编译Servlet程序
·Servlet的注册于运行
·Servlet激活器
·缺省Servlet
·Servlet的类装载器
·编写一个自动编译工具


Servlet API介绍
·Servlet API(Servlet Application Programming Interface)是SUN公司定义的一套专门用于开发Servlet程序的Java类和接口。
·早期包装Servlet API的jar包被称之为JSDK(Java Servlet Development Kit,即Java Servlet开发工具包),最新版本的Java Servlet开发工具包已经被集成到了SUN公司的Java EE(J2EE升级后的名称,即Java企业级版本)开发工具包中,这些开发工具包都可以从http://java.sun.com站点上下载到。
·应结合Servlet API帮助文档来学习和应用Servlet API,边学边查、边用边查。必须了解HTTP协议和WEB服务器的内部运行方式、以及Servlet引擎的一些实现机制后,才能够在看懂帮助文档中的英文单词的基础上去了解和掌握一些Servlet API的用途与用法,才能够使用Servlet来实现一些特殊的WEB功能。

动手体验:查看Tomcat提供的Servlet API帮助文档

编写Servlet程序
·一个Servlet程序就是一个实现了javax.servlet.Servlet接口的Java类,Servlet接口定义了Servlet引擎与Servlet程序之间通信的协议约定。
·javax.servlet.GenericServlet类实现了Servlet接口,它实现了Servlet程序的基本特征和功能。
·javax.servlet.HttpServlet类是GenericServlet的子类,它在GenericServlet类的基础上进行了一些针对HTTP特点的扩充。
·客户端每次访问一个支持HTTP的Servlet程序时,Servlet引擎都将调用Servlet的service方法来进行处理。service方法接受两个参数,一个是用于封装HTTP请求消息的对象,其类型为HttpServletRequest,另一个是代表HTTP响应消息的对象,其类型为HttpServletResponse。

编写与编译Servlet程序
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class HelloServlet extends HttpServlet
{
 //从Httpservlet类的帮助文档中复制service方法的声明部分可避免书写错误
 public void service(HttpServletRequest request,
        HttpServletResponse response) throws ServletException,IOException
 {
  PrintWriter out = response.getWriter();
  out.println("<html>");
  out.println("<font size=30 color=red>www.it315.org</font><br>");
  out.println("<marquee>"+ new java.util.Date() +"</marquee>");
  out.println("</html>");
 }
}

编译doc窗口log:
E:/file>javac HelloServlet.java
HelloServlet.java:2: 软件包 javax.servlet 不存在
import javax.servlet.*;
^
HelloServlet.java:3: 软件包 javax.servlet.http 不存在
import javax.servlet.http.*;
^
HelloServlet.java:4: 找不到符号
符号: 类 HttpServlet
public class HelloServlet extends HttpServlet
                                  ^
HelloServlet.java:7: 找不到符号
符号: 类 HttpServletRequest
位置: 类 HelloServlet
        public void service(HttpServletRequest request,
                            ^
HelloServlet.java:8: 找不到符号
符号: 类 HttpServletResponse
位置: 类 HelloServlet
               HttpServletResponse response) throws ServletException,IOException

               ^
HelloServlet.java:8: 找不到符号
符号: 类 ServletException
位置: 类 HelloServlet
               HttpServletResponse response) throws ServletException,IOException

                                                    ^
6 错误

E:/file>set classpath=F:/apache-tomcat-5.5.26/common/lib/servlet-api.jar;%classp
ath%;

E:/file>javac HelloServlet.java


Servlet的注册与运行
·Servlet程序必须通过Servlet引擎来启动运行,并且储存目录有特殊要求,通常需要存储在<WEB应用程序目录>/WEB-INF/classes/目录中。
·Servlet程序必须在WEB应用程序 的web.xml文件中进行注册和映射其访问路径,才可以被Servlet引擎加载和被外界访问。
·一个<servlet>元素用于注册一个Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整路径。
·一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
<web-app>
   ......
 <servlet>
  <servlet-name>AnyName</servlet-name>
  <servlet-class>HelloServlet</servlet-class>
 </servlet>
   ......
 <servlet-mapping>
  <servlet-name>AnyName</servlet-name>
  <url-pattern>/demo/hello.html</url-pattern>
 </servlet-mapping>
   ......
</web-app>

Servlet映射的细节
·同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
·在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。
例1:
<servlet-mapping>
 <servlet-name>AnyName</servlet-name>
 <url-pattern>*.do</url-pattren>
</servlet-mapping>
例2:
<servlet-mapping>
 <servlet-name>AnyName</servlet-name>
 <url-pattern>/action/*</url-pattren>
</servlet-mapping>

对于如下的一些映射关系:
·/abc/*映射到 Servlet1
·/*   映射到 Servlet2
·/abc 映射到 Servlet3
·*.do 映射到 Servlet4
将发生如下一些行为:
·当请求URL为“/abc/a.html”,“/abc/*”和“/*”都可以匹配这个URL,Servlet引擎将调用Servlet1。
·当请求URL为“/abc”时,“/abc/*”和“/abc”都可以匹配这个URL,Servlet引擎将调用Servlet3。
·当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都可以匹配这个URL,Servlet引擎将调用Servlet1。
·当请求URL为“/a.do”时,“/*”和“*.do”都可以匹配这个URL,Servlet引擎将调用Servlet2。
·当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都可以匹配这个URL,Servlet引擎调用Servlet2。
总结:1.*.扩展名的形式的映射匹配优先级要比/xxx/*的形式要低。2.在都是同一种通配符格式的情况下Servlet是取最接近相似程度的匹配

注册和访问Servlet程序->实践


特别提醒:
1.映射URL不能设置为“/action/*.xx”。
2.Servlet程序不能被设置为Web应用程序的目录默认网页文档。

Servlet激活器
·Tomcat的examples应用程序中的例子Servlet的访问路径:
 http://localhost:8080/examples/servlet/<Servlet名称>
·应用程序的web.xml文件中的设置:
<servlet-mapping>
 <servlet-name>invoker</servlet-name>
 <url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
·conf/web.xml文件中的设置:
<servlet>
 <servlet-name>invoker</servlet-name>
 <servlet-class>
  org.apache.catalina.servlets.InvokerServlet
 </servlet-class>
 <load-on-startup>2</load-on-startup>
</servlet>

缺省Servlet
·如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应程序的缺省Servlet。
·凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
·在<tomcat的安装目录>/conf/web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置成为了缺省Servlet。
·当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。

类装载器(1)
·Java虚拟机使用每一个类的第一件事情就是将该类的字节码装载进来,装载类字节码的功能是由类装载器完成的,类装载器负责根据一个类的名称来定位和生产类的字节码数据后返回给Java虚拟机。
·类装载器本身也是一个Java类,Java虚拟机也允许开发人员编写自己的类装载器,以便通过其他各种特殊方式来产生类字节码。
·不管类装载器采用什么方式,只要能够在内存中制造出给Java虚拟机调用类字节码即可,所以,把类装载器描述为类字节码的制造器更容易让人理解。
·当一个类被加载后,Java虚拟机将其编译为可执行代码存储在内存中,并将索引信息存储进一个HashTable中,其索引关键字为与之相对应的类名。

类装载器(2)
·Java程序中的类本身也是一种事物,它也可以用一个Java类描述,这个特殊的类名就叫Class。类装载器装载某个类的字节码的过程实际上就是在创建Class类的一个实例对象,这个Class类的实例对象封装的内容正好是当前加载的类的字节码数据。
·要想在程序中获得代表某个类的字节码数据的Class实例对象,可以采用下面三种方式:
 -类名.class,例如,System.class
 -对象.getClass(),例如,new Date().getClass()
 -Class.forName("类名"),例如,Class.forName("java.util.Date");
·Java类库中提供了一个Java.lang.ClassLoader来作为类装载器的基类,Java虚拟机和程序都调用ClassLoader类的loadClass方法来加载类,ClassLoader是一个抽象类,真正的类装载器必须是ClassLoader的子类。
·Class类中定义了一个getClassLoader方法,用于返回它所描述的类的类加载器对象,这个返回对象的类型就是ClassLoader。

类装载器的基本策略
·一个类装载器本身也是一个Java类,所以,类装载器自身也需要被另外一个类装载器装载。
·Java虚拟机中内嵌了一个称为Bootstrap的类装载器,它属于Java虚拟机的内核,不用类装载器装载。Bootstrap类装载器负责加载Java核心包中的类(即rt.jar文件中的类),这些类的Class.getClassLoader方法返回值为null,即表示是Bootstrap类装载器。
·ExtClassLoader类装载器负责加载存放在<JAVA_HOME>/jre/lib/ext目录下的jar包中的类,AppClassLoader负责加载应用程序的启动执行类。

实例代码:
package cn.lqqheima.lqqheimaweb.web.servlets;

import javax.swing.Box;

import sun.net.spi.nameservice.dns.DNSNameService;

public class ClassLoaderTest {

 /**
  * @param args
  */
 public static void main(String[] args) {

  ClassLoader c1 = System.class.getClassLoader();
  System.out.println(c1==null ?"null":c1.getClass().getName());
  c1 = Box.class.getClassLoader();
  System.out.println(c1==null ?"null":c1.getClass().getName());
  c1 = DNSNameService.class.getClassLoader();
  System.out.println(c1==null ?"null":c1.getClass().getName());
  c1 = ClassLoaderTest.class.getClassLoader();
  System.out.println(c1==null ?"null":c1.getClass().getName());
 }

}


类装载器的委托模式
·一个Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象,如果没有指定的话,则以ClassLoader.getSystemClassLoader()方法返回的系统类装载器作为其父级类装载器对象。
·系统类装载器通常被设置为启动应用程序的AppClassLoader,可以通过Java.system.class.loader系统属性来将系统类装载器设置为其他类装载器。ExtClassLoader是AppClassLoader父级类装载器,ExtClassLoader没有父级类装载器。
·每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载。
·当要加载一个类时,ClassLoader的loadClass方法先查找这个类是否已被加载,如果没有加载则委托其父级类装载器去加载这个类,如果父级的类装载器无法装载这个类,子级类装载器才调用自己内部的findClass方法去进行真正的加载。委托过程会一直追溯到Bootstrap类装载器,如果委托过程中的所有类装载器都不能完成类的装载,最终就会报告ClassNotFoundException异常。
·一个类装载器只能创建某个类的一份字节码数据,即只能为某个类创建一个与之对应的Class实例对象。在一个Java虚拟机中可以存在多个类加载器,每个类加载器都拥有自己的名称空间,对于同一个类,每个加载器都可以创建出它的一个Class实例对象。
·采用委托模式避免一个Java虚拟机中的多个类装载器为同一个类创建多份字节码数据的情况。只要开发人员自定义的类装载器不覆盖ClassLoader的loadClass方法,而是覆盖其findClass方法,这样就可以继续采用委托模式。


线程中的类加载器
·如果在类A中使用new关键字创建类B,Java虚拟机将使用加载类A的类装载器来加载类B。如果在一个类中调用Class.forName方法来动态加载另外一个类,可以通过传递给Class.forName方法的一个参数来指定另外那个类的类装载器,如果没有指定该参数,则使用加载当前类的类装载器。

·依据一个类的存放位置,这个类最终只能由一个特定的类装载器装载。对于一个已被伏击类装载器装载的类来说,Java虚拟机默认也使用这个父级类装载器去装载它所调用的其他类,由于伏击类装载器不会委托子级类装载器去装载类,所以,在一般情况下,一个已被父级类装载器装载的类无法调用那些只能被子级类装载器发现和装载的其他类。
·每个运行中的线程都有一个关联的上下文类装载器,可以使用Thread.serContextClassLoader()方法设置线程的上下文类装载器。
·每个线程默认的上下文类装载器是其父线程的上下文类装载器,而主线程的类装载器初始被设置为ClassLoader.getSystemClassLoader()方法返回的系统类加载器。
·当线程中运行的代码需要使用某个类时,它使用上下文类装载器来装载这个类,上下文类装载器首先会委托它的父级类装载器来装载这个类,如果父级的类装载器无法装载时,上下文类装载器才自己进行装载。

Tomcat中的类装载器
Bootstrap
  |
System
  |
Common
|        /
catalina  shared
           /     /
 Webapp1 Webapp2
·Bootstrap为Java虚拟机内嵌的类装载器与ExtClassLoader的总称,负责加载Java核心包中的类和存放在<JAVA_HOME>/jre/lib/ext目录下的类。
·System即系统类装载器,通常情况下就是AppClassLoader,负责加载CLASSPATH环境变量设置的目录中的类。Tomcat不会继承操作系统上原来设置好的CLASSPATH环境变量的内容,而是将CLASSPATH环境变量重新设置为仅包含如下两个jar包:
 -<CATALINA_HOME>/bin/bootstrap.jar
 -<JAVA_HOME>/lib/tools.jar
·Common类装载器负责从<CATALINA_HOME>/common/classes中的.class类文件和<CATALINA_HOME>/common/lib中的jar包中加载类。
·Catalina类装载器负责从<CATALINA_HOME>/server/classes中的.class类文件和<CATALINA_HOME>/server/lib中的jar包中加载类。
·Shared类装载器负责从<CATALINA_HOME>/share/classes中的.class文件和<CATALINA_HOME>/share/lib中的jar包中加载类。
·WebappX类装载器负责从当前Web应用程序的/WEB-INF/classes中的.class类文件和/WEB-INF/lib中的jar包中加载类。


动手体验:体验Tomcat如何完成类的加载

提点迷津:区分Servlet的编译和运行环境
编译和运行Servlet的环境是完全不同的两个环境,解释执行Servlet的过程是在Tomcat服务器程序中进行的,Servlet的运行环境就是Tomcat服务器程序设置的环境,而编译Servlet程序是由编程人员使用JAVAC命令完成的,Servlet的编译环境是某个命令行窗口或者是开发工具所设置的环境,即使Servlet程序在运行时能够成功装载某个其他的类,但在编译的时候却不一定能找到这个类,例如Servlet在运行时可以找到那些Servlet API类,但是如果运行javac命令时classpath环境变量中没有包含Servlet api所在的jar文件,那么编译的时候就会出现找不到Servlet api的错误,另外即使Servlet程序的编译能够成功通过,但是这个Servlet程序在Tomcat中运行的时候也可能出现找不到其他类的情况。

编写一个自动编译工具

·编译Servlet源文件时的两个繁琐问题:
(1)必须将包含有 Servlet API的jar文件加入到CLASSPATH环境变量的路径列表中。
(2)编译生成的.class文件必须放置在Web应用程序的WEB-INF/classes目录中,并且要有与包名对应的子目录结构。
·解决方案:使用compile.bat批处理文件
set CLASSPATH=%CATALINA_HOME%/common/lib/servlet-api.jar;%CLASSPATH%

javac -d %CATALINA_HOME%/webapps/servlet/WEB-INF/classes %1

pause

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值