1、1,第十一章 Servlet程序设计,JAVA语言程序设计,2,Java 2平台有3个版本, 适用于桌面系统的Java 2平台标准版(Java 2 Platform Standard Edition,J2SE) 适用于创建服务器应用程序和服务的Java 2平台企业版(Java 2 Platform Enterprise Edition,J2EE)。 适用于小型设备和智能卡的Java 2平台Micro版(Java 2 Platform Micro Edition,J2ME),3,J2EE,J2EE (Java 2 Platform Enterprise Edition,J2EE)是一种利用Jav
2、a 2平台来简化企业解决方案的开发、部署和管理相关的复杂问题的体系结构。目的是成为一个能够使企业开发者大幅缩短投放市场时间的体系结构。 J2EE技术的基础是核心Java平台或Java 2平台的标准版,J2EE不仅巩固了标准版中的许多优点,例如“编写一次、随处运行”的特性、方便存取数据库的JDBC API、CORBA技术以及能够在Internet应用中保护数据的安全模式等 提供了对 EJB(Enterprise JavaBeans)、Java Servlets API、JSP(Java Server Pages)以及XML技术的全面支持,4,J2EE说明书中定义了以下的J2EE组件: 应用客户端
3、程序和applets是客户层组件. Java Servlet和JavaServer Pages(JSP)是web层组件. Enterprise JavaBeans(EJB)是业务层组件.,5,参考资料The Java Tutorial continued Java Web 开发,电子工业出版社,方振宇 Java网络编程与分布式计算,沈凤译,6,Servlet基础,本节内容包括 web服务器 Servlet基础 Servlet容器、应用服务器 Web应用程序 Servlet API Servlet的基本结构 Servlet编译和安装,7,进行Servlet开发所需要的基本环境 JSDK(Java
4、 Servlet Development Kit) 。Java 1.2或以上版本进行开发,不必安装JSDK 支持Servlet的Web服务器,8,11.1 构建Java web环境,web服务器 能够处理Http请求的服务器 可以提供静态页面、图像等 有的web服务器也支持动态页面的生成,支持JSP、Servlet等,具有JVM 浏览器统一资源定位器(URL) 常用的web服务器 Microsoft的Web服务器产品为Internet Information Server (IIS), IBM WebSphere (以电子商务开发为核心) BEA WebLogic (基于 Internet 的
5、企业都选择它来开发、部署最佳的应用 ) Apache Tomcat仍然是世界上用的最多的Web服务器,市场占有率达60%左右,9,Tomcat的安装和配置 下载web服务器http:/jakarta.apache.org/tomcat/ 下载最新版本 运行:http:/localhost:8080/,10,11.2 Servlet基础,Servlet 是用java技术来实现CGI(Common Gateway Interface, 通用网关接口)功能的编程(使用Java Servlet 应用程序设计接口(API)及相关类和方法的 Java 程序 ) 介于浏览器(或其他HTTP客户端)与服务器之
6、间,起到桥梁的作用。具体作用为: 读取客户端发送的数据 获取客户请求(request)中所包含的信息 产生响应结果,并将结果包含到一个文件中,比如HTML文件中 设置HTTP响应参数,比如告诉浏览器,文件类型为HTML 将文件返回给客户端 与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。,11,Servlet容器 也称为Servlet引擎 是一个编译好的可执行程序,它是web服务器与servlet间的媒介。负责将用户请求翻译成Servlet能够理解的形式传递给servlet,同时传给servlet一个对
7、象使之可以送回响应 负责管理servlet的生命周期(通过五个接口,见后) Servlet不能独立运行,必须部署到Servlet容器中,由容器来实例化和调用Servlet方法 一些Servlet容器,如:Apache Tomcat,可以作为独立的Web服务器运行,12,Servlet工作原理 Servlet容器负责把请求传递给Servlet,并把结果返回结客户。在使用Servlet的过程中,并发访问的问题由Servlet容器处理,当多个用户请求同一个Servlet的时候,Servlet容器负责为每个用户启动一个线程,这些线程的运行和销毁由Servlet容器负责,而在传统的CGI程序中,是为每一
8、个用户启动一个进程,因此Servlet的运行效率就要比CGI的高出很多。,13,Servlet运行模式Servlet生命周期 Servlet类加载、Servlet实例化、调用init方法、调用service()方法、调用destroy()方法(servlet容器服务终止),14,Servlet的生命周期,首先服务器仅创建servlet的一个实例(初始化) 创建servlet实例时,它的init方法都会被调用 针对每个客户端的每个请求,都会创建一个线程(提供服务) 该线程调用servlet实例的service方法 Service方法根据收到HTTP请求的类型,调用doGet,doPost或者其他
9、方法 多个并发请求,一般会导致多个线程同时调用service方法,通过单线程模式(SingleThreadModel)也可以规定任何时间仅允许一个线程运行 卸载servlet(销毁) 服务器调用servlet的destroy方法,15,Servlet的生命周期(续) Servlet生命周期示意图,服务器,服务器,Servlet代码,服务器,客户端,客户端,装载,Servlet代码,卸载,Servlet代码,处理 客户端请求,Servlet 的生命周期,16,11.3 Servlet API,Servlet API 包含javax.servlet.*和javax.servlet.http.*两个
10、软件包 Javax.servlet 包含所有Servlet实现和扩展到通用接口和类(与HTTP协议无关的Servlet类) Javax.servlet.http包含与HTTP协议相关的功能 所有servlet须实现javax.servlet.Servlet接口。可以通过直接或继承方式实现 GenericServlet 和HttpServlet两个类实现了Servlet的所有接口。,Servlet 接口包括五个方法,18,11.3.1 创建servlet的三种方法,通过实现Servlet接口创建Servlet 通过继承GenericServlet类实现Servlet 通过继承HttpServle
11、t实现Servlet,19,11.3.1 创建servlet的三种方法,1、通过实现Servlet接口创建Servlet import java.io.IOException; import java.io.PrintWriter; import javax.servlet.*;public class Hello1 implements Servlet /实现Servlet接口 public Hello1() public static void main(String args)public void init(ServletConfig config)throws /初始化sevlet
12、ServletExceptionpublic ServletConfig getServletConfig() /实现getServletConfig()return null;,20,public void service(ServletRequest req, ServletResponse resp)throws ServletException, IOExceptionresp.setContentType(“text/html;charset=utf-8“);PrintWriter printwriter=resp.getWriter(); /实例化PrintWriterprintw
13、riter.println(“实现Servlet接口”); /处理业务逻辑public String getServletInfo() /实现getServletInfo()return null;public void destroy() /实现destory() ,21,配置web.xml,Servlet容器根据XML文件的配置信息来找到要运行的Servlet类,并加载、执行 标签用于注册servlet程序,包括两个子标签: : 设置注册名称,不可冲突 :指定当前注册的servlet的完整类名,包括类的包名 Servlet中wet.xml中映射其访问路径,包括两个子标签: :用于指定已经注
14、册过的servlet名称 :用于设置servlet的对外访问路径,22,import java.io.IOException; import java.io.PrintWriter;import javax.servlet.*; import javax.servlet.GenericServlet;public class Hello1 extends GenericServlet public void service(ServletRequest req, ServletResponse rep) try PrintWriter out=rep.getWriter(); rep.setC
15、ontentType(“text/html;charset=utf-8“); out.println(“通过继承GenericServlet实现“); catch(Exception e) e.printStackTrace(); ,2、通过继承GenericServlet类实现Servlet,23,3、通过继承HttpServlet实现Servlet,Servlet 基础,两个常见的HTTP请求类型 GET:从server获得信息。通常为HTML document或图象 POST:将数据发送至server。通常为HTML表单形式。,24,Server端响应方法:doGet(), doPost
16、() 复写doGet或者doPost方法 doGet或doPost都接收两个类型的参数:HttpServletRequest和HttpServletResponse 通过HttpServletRequest,可以得到所有的输入数据,比如表单数据、HTTP请求报头等客户信息 通过HttpServletResponse可以指定输出信息 由于doGet和doPost方法可能生成异常,必须在方法名称后声明抛出异常或者用try-catch语句处理异常,25,HttpServletRequest接口 由Web服务器创建该接口的一个对象,并将其传递给servlet的 service 方法 该类对象含有来自于
17、客户端的请求(方法见后) HttpServletResponse接口 由Web服务器创建该接口的一个 对象,并将其传送给servlet的 service 方法 通过该类对象服务器端可以对客户端发出响应信息(方法见后),26,HttpServletRequest接口,Servlet 基础,27,HttpServletResponse接口,Servlet 基础,28,11.4 建立Web站点,Web站点的建立 在webapps中定义站点名 创建WEB-INF文件 在WEB-INF下创建web.xml文件 在WEB-INF下创建classes文件夹,存放编译好的类文件 如果采用MyEclipse创建
18、web项目,这些文件夹和配置文件会自动生成。(具体见后),29,MyEclipse中进行,FileNewWeb Project创建工程 Src右键New-Servlet创建Servlet程序 给出包名 给出servlet类名 在Tomcat webapps中自动生相关配置文件(WEB-INF, web.xml, classes), /xml版本信息/web.xml文件配置开始/注释信息/servlet配置信息开始This is the description of my J2EE componentThis is the display name of my J2EE componentHel
19、lo1 /servlet注册名Hello1 /servlet完整的类名(可包含包名)/servlet映射信息开始Hello1 /servlet注册名/servlet/Hello1 /servlet的对外访问路径index.jsp/web.xml文件结束,配置web.xml文件,This is the description of my J2EE componentThis is the display name of my J2EE componentmyServletmyServletThis is the description of my J2EE componentThis is th
20、e display name of my J2EE componentHello1Hello1,标签用来注册Servlet程序。包括两个子标签: 用来设置Servlet的注册名称,不能与其他servlet同名 用来指定当前注册的Servlet程序的完整类名。 注意:完整类名要包含类的包名。,理解Web.xml文件,myServlet/servlet/myServletHello1/servlet/Hello1,标签用来映射一个已注册的Servlet的对外访问路径。 用户通过该Servlet所映射到对外访问路径才能访问Servlet。该标签有 两个子标签: 用来指定已经注册过的servlet名称
21、 用来设置servlet的对外访问路径,33,Servlet编译和安装,编译在设置好path和classpath的前提下,servlet的编译和普通的java程序完全相同( 可以通过javac.exe编译,比如可以在Dos环境下输入: javac MyServlet.java 也可以通过集成开发环境(IDE)编译 建立web站点编译成功之后,将生成的类文件复制到相应的目录下即可。在Tomcat服务器上,此目录可能是install_dirwebappsROOTWEB-INFclasses 运行启动Tomcat服务器,在地址栏输入http:/localhost:8080/servlet/MySer
22、vlet,Servlet 基础,34,Eclipse 中创建servlet,创建Web Project-在project的src下创建servlet 注意 Servlet文件的访问路径要根据你创建servlet时的路径来确定(见图),35,访问路径为: http:/localhost:8080/ServletDemo/servlet/myServlet,36,访问路径为: http:/localhost:8080/ServletDemo/otherServlet,37,Servlet HTTP GET ExampleClick the button to have the servlet se
23、ndan HTML document,Action访问路径应与前面创建servlet的两种情况匹配,38,11.5 Servlet应用举例,1、处理HTTP GET 请求 在通过提交表单调用Servlet的时候,只需要把表单的action指向对应的Servlet 例:HTTPGetServlet.java HTTPGetServlet.html,39,11.5 Servlet应用举例,2、处理HTTP POSt 请求及文件操作 例:HTTPPostServlet.javaHTTPPostServlet.html,40,11.5 Servlet应用举例,3、Servlet读写数据库 例:Gues
24、tBookServlet.javaGuestBookForm.html,41,11.5 客户端跟踪,客户端跟踪 HTTP是无状态协议,服务器不能自动维护客户连接的上下文信息 许多情况下,Web服务器必须要能够跟踪用户的状态 比如购物网站和电子邮件网站,当用户登录以后,其身份和一系列的操作状态都需要被跟踪并保持 servlet API提供了两种可以跟踪客户端状态的方法 Cookie Session,42,11.5.1 使用Cookie,Cookie Cookie是Web服务器保存在用户硬盘上的一段文本(不太准确) 。cookie机制采用的是在客户端保持状态的方案。 cookie的内容主要包括:名
25、字、值、过期时间。以名/值对(name-value pairs)的形式储存。(见cookies文件) cookie一般不存储在硬盘上而是保存在内存(如果设置了过期时间,则保存在硬盘) ,cookie中保存的是字符串。 其用途可以体现在如下几点: 在电子商务中标识用户,实现短期跟踪用户 记录用户名和用户密码,允许用户下次自动登陆 定制站点,记录用户的偏好, 提供个人化服务的网站 定向广告,记录用户感兴趣的主题,并显示与之相关的广告,客户端跟踪,43,调用Cookie的构造函数可创建一个cookie 构造方法接收两个字符串参数 cookie名称 cookie的值 例如创建一个名为CookieNam
26、e,值为John的cookie,可以使用下面的语句 Cookie login = new Cookie(“CookieName”, ”John”);,客户端跟踪,11.5.1 使用Cookie(续) 创建Cookie对象,44,创建了一个名为login的cookie之后,可通过很多现有的方法设置cookie的值和属性 可通过如下语句设置cookie的注释: login.setComent(“You can get UserName from this cookie”); 创建cookie并将它发送到浏览器后,默认情况下,它是会话级的cookie,仅仅存储在浏览器内存中,用户退出浏览器后,coo
27、kie将被删除;如果希望将cookie存储在磁盘上,则需要设定MaxAge,给出一个以秒为单位的生命周期,如下可以将生命设置为一天 login.setMaxAge(60*60*24) / one day setPath(),setValue(),setVersion(),setDomain(),setSecure()等,相关的具体用法请查看servlet API,11.5.1 使用Cookie(续) 设置Cookie属性,客户端跟踪,45,刚创建的cookie存在于服务器内存中。必须将它发送到客户端,cookie才能真正的发挥作用。发送cookie需要使用HttpServletResponse
28、的addCookie方法,将cookie插入到一个HTTP响应报头。发送的语句如下 public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException Cookie login = new Cookie(“UserName”, ”John”);login.setComent(“You can get UserName form this cookie”);res.addCookie(login);/. ,客户端跟踪,11.5.1 使用Cookie(续)
29、发送Cookie到客户端,46,从客户端读取你感兴趣的cookie,需要两个步骤 首先调用request.getCookies得到一个Cookie对象的数组 然后调用每个cookie的getName方法,从数组中寻找所需的cookie String nameString = “UserName” Cookie cookies = request.getCookies(); for ( int i=0; icookies.length; i+) Cookie cookie = cookiesi;if (nameString.equals( cookie.getName() )/ do somet
30、hing / cookies.setMaxAge(0); 找到感兴趣的cookie之后,便可以操作此cookie, 如通过getValue方法得到相关cookie的值,设置MaxAge等,客户端跟踪,11.5.1 使用Cookie(续) 从客户读取Cookie,47,11.5.2 使用Session,Session session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。session中保存的是对象 在一个Session中客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源,其间用户的状态需要跟踪并保持 当每个用户首次与这台
31、WWW服务器建立连接时,他就与这个服务器建立了一个Session,同时服务器会自动为其分配一个SessionID,用以标识这个用户的唯一身份 访问者从到达某个特定主页到离开为止的那段时间内单个客户与web服务器的一连串的交互过程 存在于服务器端,不在网络上传送 它的好处是可以用来记录客户端私有的信息,并且在时间范围内不会消失,客户端跟踪,48,Session ID Servlet容器为HttpSession分配的一个唯一标识符 作为Cookie保存在客户的浏览器中 session cookie 每次客户发出HTTP请求时,Servlet容器可以从HttpRequest对象中读取Session
32、ID,然后根据Session ID在服务器端找到相应的HttpSession对象,从而获取客户的状态信息,这样的cookie叫做session cookie 存储于浏览器内存中的,并不写到硬盘上的 针对某一次会话而言,会话结束也就随着消失了,客户端跟踪,11.5.2 使用Session(续) 存储或读取数据,49,11.5.2 使用Session(续),Session的使用可以分为三个步骤 获得一个session 存储数据到session或从session读取数据 销毁session,客户端跟踪,50,通过调用httpServletRequest的getSession方法可以得到一个sessi
33、on HttpSession session = request.getSession(); 为了保持正确的会话,必须在发送任何文档到客户程序之前获得一个session public class SessionServlet extends HttpServlet public void doGet( HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException/ Get the users sessionHttpSession session = request.ge
34、tSession(true);/.out = response.getWriter();/ . ,客户端跟踪,11.5.2 使用Session(续) 获得一个Session,51,URL 重写 浏览器不支持 Cookie,或者将浏览器设置为不接受 Cookie的情况,可通过 URL 重写来实现会话管理 向 URL 连接添加参数,并把 session ID 作为值包含在连接中。为 servlet 响应部分的每个连接添加 session ID ,可以使用一对方法 response.encodeURL() :使 URL 包含session ID response.encodeRedirectURL(
35、):使用重定向,客户端跟踪,11.5.2 使用Session(续) 存储或读取数据,52,从Session中读取数据 session.getAttribute(“name”) 查找以前存储的值 如果不存在则返回null 在调用此方法返回的对象前,一定要检查它是否为null 向session中设置相关信息 setAttribute 替换掉此前设定的任何值 removeAttribute 移除而不是替换某个值,客户端跟踪,11.5.2 使用Session(续) 存储或读取数据,53,public class SessionServlet extends HttpServlet public voi
36、d doGet (HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException/ Get the users sessionHttpSession session = request.getSession(true);SomeClass scl = (SomeClass)session.getAttribute( “name1“ );/ If the user has no SomeClass object, create a new oneif (scl = null
37、) scl = new SomeClass();session.putAttribute( “name1“, scl );/. ,11.5.2 使用Session(续) SessionServlet.java,客户端跟踪,54,销毁Session 意味着从系统删除session对象及其值 自动销毁 在一段时间(时间长短依赖与Web服务器的设定)没有request的情况下,Web服务器会自动销毁session 手动销毁 通过调用session的invalidate方法可以手动的销毁session logout 在支持servlet2.4的服务器中,可调用logout将客户从Web服务器中注销,同
38、时废弃所有与该用户相关联的会话 需要注意的是,这个动作会影响到此servlet之外的其他servlet,因此一定要与网站的其他开发人员协调使用,11.5.2 使用Session(续) 销毁Session,客户端跟踪,55,Cookies 和Session例题,Cookies CookieExample.java SelectLanguage.html Session TrackSession.java AccessCount.java,56,11.6 与客户端交互,HTTP servlet与客户端的交互 通过service方法处理客户端的请求 service方法根据请求(request)类型的
39、不同,调用不同的方法 对于GET请求,调用doGet( )方法进行处理 对于POST请求,调用doPost( )方法进行处理,57,11.6.1 提取Servlet信息,注册的servlet都有相关的很多初始化参数 这些初始化参数写在web.xml中,具体语法格式请参阅Tomcat文档 getInitParameter()方法 可以得到servlet初始化的一些参数 返回一个指定参数的值(String类型) 如果指定参数不存在,则返回null getInitParameterNames()方法 可以得到初始化参数名称 返回String类型的Enumeration类型数据 如果不存在初始化参数,
40、则返回一个null的Enumeration,与客户端交互,58,通过servlet初始化参数建立一个数据库连接的程序段如下 java.sql.Connection con = null; public void init(ServletConfig config) throws ServletException super.init(config);String host = getInitParameter(“host“);int port = Integer.parseInt(getInitParameter(“port“);String db = getInitParameter(“db
41、“);String user = getInitParameter(“user“);String password = getInitParameter(“password“);String proxy = getInitParameter(“proxy“);con = establishConnection(host, port, db, user, password, proxy); ,11.6.1 提取Servlet信息(续) 通过初始化建立数据库连接,与客户端交互,59,输出全部初始化参数名称 import java.io.*; import java.util.*; import j
42、avax.servlet.*; public class PrintInitParaNames extends GenericServlet public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException res.setContentType(“text/plain“);PrintWriter out = res.getWriter();out.println(“Init Parameters As Following:“);Enumeration enum = g
43、etInitParameterNames();while (enum.hasMoreElements() String name = (String) enum.nextElement();out.println(name “: “ + getInitParameter(name); ,11.6.1 提取Servlet信息(续) PrintInitParaNames.java,与客户端交互,60,11.6.2 提取服务器信息,servlet可以得到很多服务器相关的信息,同时可以将这些信息发送到客户端 getServerName()返回服务器名称 getServerPort()返回服务器监听端口
44、 getServerInfo()输出服务器程序和版本,之间用“/”分开 getAttribute()返回服务程序的属性 得到路径相关的信息 public String HttpServletRequest.getPathInfo() public String HttpServletRequest.getPathTranslated(),与客户端交互,61,提取服务器信息举例 import java.io.*; import java.util.*; import javax.servlet.*; public class ServerSnoop extends GenericServlet
45、public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException res.setContentType(“text/plain“);PrintWriter out = res.getWriter();out.println(“req.getServerName() output: “ + req.getServerName();out.println(“req.getServerPort() output: “ + req.getServerPort();out.p
46、rintln(“getServletContext().getServerInfo() output: “ + getServletContext().getServerInfo() );out.println(“getServletContext().getAttribute(“attribute“) output: “ + getServletContext().getAttribute(“attribute“) ); ,11.6.2 提取服务器信息(续) 例11_3,与客户端交互,62,11.6.3 提取客户端信息,服务器可以从request得到很多客户端的信息 getRemoteAdd
47、r():得到IP地址 getRemoteHost():得到客户端机器的名称 利用InetAddress.getByName()方法可以将IP地址或客户端机器名称转换成一个.InetAddress类型的对象 InetAddress remoteInetAddress = InetAddress.getByName(req.getRemoteAddr(); 通过获取客户端的地址,并判断是否隶属某个范围,可以限制某个地区的用户访问你的网站,与客户端交互,63,11.6.3 提取客户端信息(续),服务器可以得到客户想做的事情 客户请求表现为表单数据,由“名/值”对组成。当提交某一个网页的时候常常在浏览
48、器地址栏中看到类似格式的数据格式 name/value,每对之间用&隔开,表达式为 param1=value1¶m2=value2¶m3=value3 request.getParameter:得到表单参数的值 request.getParameterValues:得到多次出现的参数值 reques.getParameterNames:得到当前请求中所有参数的完整列表,调用形式如下 public String ServletRequest.getParameter(String name) public String ServletRequest.getParameterVal
49、ues(String name),与客户端交互,64,书本查询的一个HTML网页 !DOCTYPE HTML PUBLIC “-/W3C/DTD HTML 4.01 Transitional/EN“A Sample Form for Query a Book Book to look up: ,11.6.3 提取客户端信息(续) Query.html,与客户端交互,65,获取客户端信息的servlet import java.io.*; import .*; import javax.servlet.*; import javax.servlet.http.*; public class Qu
50、eryServlet extends HttpServlet public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException res.setContentType(“text/html;charset=UTF-8“);String queryBookValue=req.getParameter(“Book“);PrintWriter out = res.getWriter();out.println(“The book you wanted is:“+queryBookValue);out.close(); ,