2007-09
14

介绍完工具和基本概念,现在终于开始介绍Servlet的编写方法了。 为了便于理解,我们将采用eclipse+Lomboz作为开发环境, 一切的操作都可以在eclipse中完成。 如果你还没有安装好Lomboz,请参考前几篇文章配置好环境。

我们将建立一个名为 com.idv2.learnjsp 的包,用于容纳所有的示例程序。 下面我们就看看最基本的Servlet的创建方法。

创建项目

启动eclipse,然后选择菜单File->New->Project...,在新建项目向导中选择 Web->Dynamic Web Project。该项目即为使用Servlet、JSP等技术开发动态网站的项目。 (如果你找不到这一项,说明Lomboz没有配置好,请参阅文章开头的链接进行配置。)

新建一个Dynamic Web Project

下一步,输入项目名 LearnJSP。下面的Target Runtime指定运行这个项目的服务器, 如果你已经在配置Lomboz 的一节中配置好了Tomcat服务器,那么在这里你可以看到相应的服务器配置,选择它即可。 如果选择框中只有<none>,说明你还没有配置服务器,可以单击右侧的New...按钮新建。

Configurations项选择<none>即可。

项目名和配置

下一步选择项目所需的特性,默认的Dynamic Web ModuleJava就足够了。

选择项目特性

下一步是输入相关的目录,这里也直接使用默认值即可。图略。

最后单击 Finish,完成项目创建。创建途中可能会有一个用户使用协议需要你同意, 单击I Agree即可。创建完成后会询问是否要切换到J2EE视图(下图),选择Yes, 完成项目创建。

是否要切换到J2EE视图

项目建立完成后,请在左侧的 Project Explorer 中打开 LearnJSP 项目, 看看它各个部分的构成。

项目视图的各个组成部分

基础知识一节中 我们知道,应用程序由三部分组成,即Servlet、JSP及静态内容、配置文件web.xml。 项目视图中的 src 目录用来保存 Servlet 源代码,WebContent 目录用来保存JSP及静态内容, web.xml则位于 WebContent/WEB-INF/web.xml。但手工编辑 web.xml 比较麻烦, 因此 Lomboz 提供了一套可视化工具用于编辑 web.xml,即最上方的Depolyment Descriptor, 里面包含的内容以后会陆续讲解。

理解Servlet

在Project Explorer中打开Java Resources: src -> Libraries -> Apache Tomcat 5.5 -> servlet-api.jar 文件,可以看到其中包含两个包:javax.servletjavax.servlet.http, 与Servlet有关的类和接口都位于这两个包里面。

Servlet API所在的包

Servlet是一个接口,位于 javax.servlet.Servlet,它规定了每个Servlet所必须实现的方法。 实际应用时我们需要从 javax.servlet.GenericServlet 和 javax.servlet.http.HttpServlet 两个抽象类 继承出自己的Servlet类,并实现所需的功能。这几个类的关系如下(绿色斜体字为抽象类):

Servlet相关类的关系

上图中,Servlet依赖于ServletRequest和ServletResponse接口,这两个接口负责为Servlet接受和发送信息。 HttpServlet也类似。

Servlet接口

javax.servlet.Servlet接口包含以下的方法:

init()
void init(ServletConfig config) throws ServletException
init方法用于初始化,在Servlet启动时调用。
service()
void service(ServletRequest req, ServiceResponse res) throws ServletException, IOException
Servlet通过这个方法,从req获得客户端请求,处理并生成结果,再通过res发送给客户端。
destroy()
void destroy()
Servlet销毁时执行的方法。
getServletInfo()
String getServletInfo()
将Servlet的信息通过字符串返回。
getServletConfig()
ServletConfig getServletConfig()
获取包含Servlet各种信息的ServletConfig对象。

当某个Servlet第一次被请求时,服务器(Servlet容器)会生成该Servlet并调用它的init()方法, 再调用其service()方法处理请求。处理结束后该Servlet会常驻于容器中,下一个请求则不再 重新生成Servlet,而是直接调用常驻的Servlet对象的service()方法。 服务器停止时,会调用该Servlet的destroy()方法。

因此,在Servlet的一个生命周期中,init()和destroy()仅会被调用一次, 而service()则会被调用多次。

GenericServlet抽象类

javax.servlet.GenericServlet为我们实现了Servlet接口的大部分方法,除了service()方法之外。 因此,我们在制作自己的Servlet时,只需要继承GenericServlet并重载service()方法即可。

典型的Servlet示例

下面我们来做一个典型的Servlet。

在eclipse左侧的Project Explorer中,右键单击Java Resources: src目录(以后简称src目录), 选择New->Class,建立如下所示的类。

建立Servlet类

包名输入我们要建立的 com.idv2.learnjsp,类名为 HelloServlet,父类为 javax.servlet.http.GenericServlet。 在输入父类名时,你会看到输入框左侧有个小灯泡的图标,这说明可以通过 Alt-/键自动补齐, 因此你只需输入 GenericSer 几个字母,然后按 Alt-/ 组合键,系统会自动查找开头为 GenericSer 的类 并补齐剩余部分。

Finish之后eclipse会为我们生成代码框架,我们只需填入实际的处理代码即可。 代码可以从这里下载。

上述代码是UTF-8编码,如果你直接放到src目录中有可能出现乱码, 这时请选择Windows->Preferences...菜单,选择左侧的General->Workspace, 然后将Text file encoding设置为UTF-8即可。

代码写好后,从Project Explorer中打开项目的 build 目录,可以看到eclipse自动编译了 HelloServlet.java并生成了 com/idv2/learnjsp/HelloServlet.class 文件。

那么如何在服务器上运行它呢?首先必须要做的就是在配置文件 web.xml 中登记这个Servlet。 刚才我们在建立 HelloServlet 类时,并没有声明它是一个Servlet,这样服务器就无法将它 作为Servlet执行,因此必须先登记,并为它指定一个URL(即Servlet Mapping)。

右键单击Depolyment Descriptor中的Servlets,选择New->Servlet,出现下面的画面。

登记Servlet

因为我们已经写好了HelloServlet类,因此选中Use existing Servlet class, 然后单击右侧的Browse...按钮,选择HelloServlet类。下一步。

设置Servlet名称和URL映射

URL映射是指,浏览器通过哪个URL能访问到这个Servlet。 默认与Servlet名称相同,为了演示,我们这里将他修改为小写的 /helloservlet 。 实际的URL格式为 http://主机名/应用程序名/Servlet的URL映射, 我们这个Servlet的URL就应当是 http://localhost:8080/LearnJSP/helloservlet

单击Finish完成添加Servlet。如果你有兴趣可以打开 WebContent/WEB-INF/web.xml, 可以看到刚才的修改在web.xml中是怎样的结果。

下一步我们需要将它部署到服务器上。打开eclipse下方的Servet栏, 可以看到系统中的服务器列表。

Server栏

如果你找不到Server栏,请通过主菜单Window->Show View->Others添加Server栏; 如果你的Server栏中什么都没有,请在Server栏中单击右键然后 New->Server

右键单击服务器,选择Add and Remove Projects...,将 LearnJSP项目添加到服务器上。 添加之后的结果如下:

Server栏

最后右键单击服务器,选择Start,片刻即可看到在Console栏中输出大量的信息,服务器启动了。 打开浏览器,访问 http://localhost:8080/LearnJSP/helloservlet。 如果能看到“Hello Servlet”的输出,则恭喜你,第一个Servlet成功运行了!

刷新浏览器页面几次,然后回到eclipse下侧的Console栏,可以看到下面的字样:

init() was called.
service() was called.
service() was called.
service() was called.

这是我们加入的调试信息。这些信息说明了Servlet的一个生命周期中 init、service和destroy函数的执行过程。 如果在Server栏中停止服务器,那么你可以在Console栏中的信息中找到 destroy() 函数的执行。

结语

这一节重点结合Lomboz的用法,讲述了Servlet的基本原理和最简单的Servlet的编写方法。 以后的内容可能就不会这么详细地说明Lomboz的用法了。




这篇文章有 26 条评论了,快来一起讨论讨论吧!
#1
Alopa
2008-04-19 15:33

配置一切都正常,但结果是:
HTTP Status 404 - /LearnJSP/helloservlet

——————————————————————————–

type Status report

message /LearnJSP/helloservlet

description The requested resource (/LearnJSP/helloservlet) is not available.
弄了一天了,都搞不定~~哎

#2
bille_chen
2008-06-22 16:27

上面的朋友你出的错估计是使用了Tomcat插件启动的服务器,建议你按照这篇教程来操作,在“server视图”中新建Tomcat服务器,加进项目后再启动。我已经调通了。

#3
zny
2008-07-16 17:27

为什么我照着做到最后右键单击服务器,选择Start,启动LearnJSP
的时候弹出一个对话框,里面的内容是Several ports (8005, 8080, 8009) required by Tomcat v5.5 Server at localhost are already in use. The server may already be running in another process, or a system process may be using the port. To start this server you will need to stop the other process or change the port number(s).

#4
zny
2008-07-16 17:29

楼主有电话或其他联系方式,我想求助一下
呵呵

#5
charlee
2008-07-16 17:52

@zny 你是否安装了其他的Web服务器,如Apache等?或者,迅雷、Skype等程序也有可能会影响Tomcat的运行。请将其他的程序停止试试看。

#6
zny
2008-07-16 20:29

谢谢了,是TOMCAT的过

#7
cay
2008-08-01 23:37

楼主你写的很好,但是为什么我的结果跟一楼的一样呢?我都按照你的来了阿?可以帮我解决这个问题吗?

#8
bjw
2008-08-28 15:48

2008-8-28 14:17:56 org.apache.tomcat.util.digester.SetPropertiesRule begin
警告: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ’source’ to ‘org.eclipse.jst.jee.server:LearnJSP’ did not find a matching property.

启动tomcat有一个警告,是什么问题?怎么消除?

#9
匿名
2008-09-05 18:39

大哥 按你的要求做的啊 没有Depolyment Descriptor
?是不是要在哪打开啊 刚学这个 有点小白。。。

#10
charlee
2008-09-05 18:54

没有Depolyment Descriptor会不会是版本的原因?换成这篇文章内指定的版本试试看?

#11
匿名
2008-09-05 19:17

eclipse用的是3.3.2的 lomboz用的是你文中讲的额。。
自己配的web.xml,居然成功了。。。

#12
donalliang
2008-09-07 01:10

手上有一个作业要求用JSP/Servlet开发,所以就冒冒失失一路找到这里学习来了。
发现了跟三楼zny一样的问题,然后解决了,写在这里。我使用的是tomcat6和eclipse3.4

安装完Tomcat后,默认部署了一个应用(application),位置在:\webapps\ROOT下。

当然,也有可能同时部署了一些例子应用(如果在安装过程中选择安装这些例子的话)和另外两个应用(host-

manager和manager)。要查询具体部署了哪些应用的话,在http://localhost:8080/manager/html可以看到(要

求用户名及口令,安装时定义好的)。这几个应用都运行在这个Server上面,这个Server是默认存在的,监听端口

是8080。这个Server存在于一个叫tomcat6.exe(注意不是tomcat6w.exe)的进程中,相当于java.exe或

javaw.exe的虚拟机进程环境。所有部署在\webapps的应用,都要依赖于这个tomcat6.exe

进程才能运行。

安装完eclipse及其他插件后,根据楼主的说明“如果你的Server栏中什么都没有,请在Server栏中单击右键然后

New->Server”,建立一个新的Server,于是出现了两个Server同时监听8080端口的情况,这个Server是以

eclipse内置的Java 运行环境为环境,进程名称叫做javaw.exe(javaw.exe,是无控制台信息的java.exe虚拟机进程

)。如果你还看到另一个javaw.exe进程的话,那么它是由JavaSDK启动的,但其中并不运行Server。

总结以上,即:
由tomcat启动的server,运行在tomcat6.exe进程中。
由eclipse启动的server,运行在一个javaw.exe进程中。
另外还可能有一个javaw.exe进程。

这两个server都在监听8080端口。这里的规则是:谁先启动,谁先拥有8080端口的监听权,同时排挤另一个server


如果先启动tomcat的server,再在eclipse中启动server,那么就会得到三楼zny得到的错误报告。
如果先启动eclipse的server,再启动tomcat的server,tomcat并不给出报告,并且该server无法启动。

解决办法,可以将LearnJSP以.war导出到\webapps\下面,Tomcat会检测并自动部署这个

项目(应用);或者更改端口。

#13
匿名
2008-11-16 14:42

好,解决!

#14
cj
2008-11-25 01:06

朋友,感谢你的文章!

#15
cx
2009-01-06 02:29

老师您好,我不知道怎么回事,前面一直按您文章中写的操作,也一直都没问题,写好HelloServlet了,部署也部署了,运行之后也都是正常的,但我百思不得其解的是为什么在浏览器里不能打开呢,甚至TOMCAT主页也上不了。而我直接用TOMCAT运行文件打开就可以用浏览器打开TOMCAT主页请老师帮忙分析一下可能存在的问题好么?
TOMCAT运行情况如下:
2009-1-6 2:11:14 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jre1.5.0_11\bin;.;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Java\jre1.5.0_11\bin\client;C:\Program Files\Java\jre1.5.0_11\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;%JAVA_HOME%\bin
2009-1-6 2:11:15 org.apache.coyote.http11.Http11BaseProtocol init
信息: Initializing Coyote HTTP/1.1 on http-8080
2009-1-6 2:11:15 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 2203 ms
2009-1-6 2:11:15 org.apache.catalina.core.StandardService start
信息: Starting service Catalina
2009-1-6 2:11:15 org.apache.catalina.core.StandardEngine start
信息: Starting Servlet Engine: Apache Tomcat/5.5.27
2009-1-6 2:11:15 org.apache.catalina.core.StandardHost start
信息: XML validation disabled
2009-1-6 2:11:16 org.apache.coyote.http11.Http11BaseProtocol start
信息: Starting Coyote HTTP/1.1 on http-8080
2009-1-6 2:11:17 org.apache.jk.common.ChannelSocket init
信息: JK: ajp13 listening on /0.0.0.0:8009
2009-1-6 2:11:17 org.apache.jk.server.JkMain start
信息: Jk running ID=0 time=0/359 config=null
2009-1-6 2:11:17 org.apache.catalina.storeconfig.StoreLoader load
信息: Find registry server-registry.xml at classpath resource
2009-1-6 2:11:17 org.apache.catalina.startup.Catalina start
信息: Server startup in 2812 ms

#16
charlee
2009-01-06 11:43

@cx 看你的情况,tomcat应该正常启动了。首先按照下面的步骤检查一下tomcat的主页能不能连上(http://localhost:8080/):

1. 启动命令行,输入 netstat -ano | find “LISTEN”,看看结果中有没有 127.0.0.1:8080 的字样:

2. 如果有的话,查看127.0.0.1:8080那一行的最后一列,那是进程的PID,然后打开任务管理器,查看进程,看看这个PID是不是tomcat.exe或java.exe?(需要在任务管理器的视图->选择列中勾选PID才能看到)

3. 如果2的结果不是tomcat.exe,那么关掉它对应的软件,重启tomcat试试。

4. 如果2的结果是tomcat,看看windows的防火墙有没有打开?关掉试试

#17
cx
2009-01-06 20:52

老师您好!非常感谢您百忙中抽出时间帮助我。我照您说的操作了,情况如下:
首先我在ECLIPSE中运行TOMCAT,通过CMD中运行NETSTAT -ANO找到了端口为8080的PID,结果在任务管理器中找到的进程是JAVAW.EXE,而不是TOMCAT.EXE。我终止进程后ECLIPSE的运行状态也停止了。再START运行还依然是JAVAW.EXE,依然不能用浏览器查看网页。
然后我停止在ECLIPSE中运行,直接双击运行TOMCAT安装目录下的tomcat5.exe,再通过CMD运行NETSTAT -ANO找到端口为8080的PID,在任务管理器中找到的进程是tomcat5.exe,也能够用浏览器查看网页。
有一个现象如下:两种情况下,CMD里都有0.0.0.0:8080的行,而不是127.0.0.1:8080,前面是127.0.0.1的行有很多,但端口都很奇怪各不相同(没有8080的)。第一种情况下我在浏览器里输入http://127.0.0.1:8080或是http://localhost:8080/都不能查看网页;第二种情况下则输入http://127.0.0.1:8080或是http://localhost:8080/都能查看网页。
老师您能否帮我分析一下如何才能让ECLIPSE里运行的时候是TOMCAT.EXE而不是JAVAW.EXE?另外还有一点疑问:为什么CMD里不是127.0.0.1:8080而是0.0.0.0:8080,既然如此,为什么我在第二种情况下浏览器里输入http://127.0.0.1:8080也能查看网页,而输入http://0.0.0.0:8080却反而不能查看网页呢?

#18
charlee
2009-01-06 23:11

@cx 您好。我明白您的情况了。

javaw.exe的情况,估计是eclipse通过javaw.exe(java虚拟机)调用了Tomcat的核心(.jar文件)来启动服务器,这样才能在eclipse中运行程序。这时在eclipse中应该是可以看到页面,并可以调试的。可能是eclipse不允许通过浏览器访问?

tomcat5.exe的情况,才是真正的Tomcat在独立运行,此时通过浏览器是可以访问的。

总之,第一种情况不能用浏览器访问应该是正常的,只要能在eclipse中运行、调试就行了。程序开发完成后,真正需要部署时,关掉eclipse再启动Tomcat,就可以用浏览器访问了。

另外,127.0.0.1:8080那个是咱们的服务器设置不一样,0.0.0.0:8080也是同样的意思,不用在意。

#19
charlee
2009-01-06 23:16

关于IP地址再说点题外话:

一台能正常上网的电脑一般有两个IP地址,其中一个如63.2.3.4这样的是真实的IP(用ipconfig命令可以看到),另一个IP为127.0.0.1,是表示本机的虚拟地址(这个IP就是所谓的localhost)。

0.0.0.0:8080中的0.0.0.0表示“任意IP地址”,就是说,不论是63.2.3.4:8080还是127.0.0.1:8080,都可以访问。而127.0.0.1:8080表示这个8080端口只在127.0.0.1这个IP上有效,所以127.0.0.1:8080能访问,但63.2.3.4:8080不能访问。同理,如果显示的是63.2.3.4:8080,那么用127.0.0.1:8080就不能访问。

0.0.0.0只是一个表示“任意IP地址”的符号,不是IP地址,所以http://0.0.0.0:8080当然不行了。

#20
cx
2009-01-07 00:16

嗯,看了老师的解释我明白了许多。但是我要如何做才能真正地在浏览器上看到真正是自己写的网页呢?我在webapps文件下建议了一个myweb文件夹,里面建立了个WEB-INF文件夹,然后把ECLIPSE 的workspace里面的WEB-INF文件夹拷到myweb文件夹下,把classes文件夹拷到WEB-INF文件夹内。也就是说:myweb文件夹下只有一个WEB-INF文件夹,WEB-INF文件夹中有web.xml部署文件,classes文件夹,lib文件夹;classes文件夹里头则是编译的HelloServlet.class文件。lib里面为空。
启动tomcat,打开主页,进入管理员帐号,能看到myweb,但点击却又是无法打开,这又是为什么呢?
最好是能够ECLIPSE里面运行后直接就能在浏览器里访问网页,这样的效果能达到吗?老师能帮我分析一下吗?

#21
cx
2009-01-07 00:21

还有一点,TOMCAT启动的时候有这样一段话,说什么什么的没找到,这样的是正常情况的吗?还是说明我什么地方没配置好呢?
信息: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jre1.5.0_11\bin;.;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Java\jre1.5.0_11\bin\client;C:\Program Files\Java\jre1.5.0_11\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;%JAVA_HOME%\bin

#22
cx
2009-01-07 00:29

我因为是自学的,所以学起来很吃力,这个问题卡了我好多天了,弄了好几个通宵也没解决,老师您帮我分析一下好吗?

#23
charlee
2009-01-07 23:11

@cx 关于第一个问题,我想你的方法是正确的,直接访问localhost/myweb应该能够打开吧?不好意思我这里已经没有Tomcat的执行环境了,没办法验证。

第二个问题,是说tomcat找不到native library(原生函数库),这个库可以用于提高tomcat的性能。没有也没关系,性能差一些,但开发足够用了。在需要将程序部署到生产环境时,再去考虑它吧。

#24
cx
2009-01-08 11:57

老师,谢谢您。我可能是自己电脑的问题,点myweb不行,点localhost/myweb/heloservlet又是可以的。一直以为点myweb都不行,直接访问它下面的路径肯定是不可以的。可是谁知道这东西就是这么奇怪出乎我的想像。

最后,谢谢老师,您的耐心指导我不胜感激!祝老师新年快乐!

#25
dlwdgl
2009-02-05 03:12

charlee你好,我是个jsp初学者,根据您的步骤试的时候,发现eclipse里无法正常导入tomcat里的所有包,但是工程里面这些包的路径显示却是正确的,应该排除了classpath设置出错的可能。不知道我哪里搞错了。
ps:您要是比较忙,就别理我这小问题呵呵。小弟谢过了先~

#26
dlwdgl
2009-02-06 14:56

原来直接new->servelet就不会这样了-_-||

添加评论