我们可以通过三种方式来开发servlet:
A:实现Servlet接口
B:继承GenericServlet类
C:继承HttpServlet类
首先我们来说第一种方式:
实现Servlet接口
详细步骤:
1.在Tomcat目录下的webapps下面,新建自命名一个文件夹 myServlet。然后在该目录下新建WEB-INF文件夹,该文件夹下面再建classes、lib文件夹,还有web.xml文件。
在classes下面新建Hello.java文件
2.首先对环境进行配置,将Servlet-api.jar(此包默认包含在Tomcat安装目录的common\lib文件夹下)包加入classpath环境变量
接着完成Hello.java的代码编写,并编译。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package com.lpq; import javax.servlet.*; import java.io.*; public class Hello implements Servlet{ public void init(ServletConfig config) throws ServletException{ System.out.println("init it"); } public ServletConfig getServletConfig(){ return null; } public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException{ System.out.println("service it"); PrintWriter pw = resp.getWriter(); pw.print("Hello,World!"); } public String getServletInfo(){ return ""; } public void destroy(){ System.out.println("destroy"); } } |
3.在web.xml文件中部署你的servlet。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <servlet> <!--servlet-name 给该Servlet取名, 该名字可以自己定义:默认就使用该Servlet的名字--> <servlet-name>Hello</servlet-name> <!--servlet-class要指明该Servlet 放在哪个包下的,形式是包/包/../类--> <servlet-class>com.lpq.Hello</servlet-class>注意:后面不要带.java </servlet> <!--Servlet的映射--> <servlet-mapping> <!--这个Servlet-name要和上面的servlet-name名字一样--> <servlet-name>Hello</servlet-name> <!--url-pattern这里就是将来访问该Servlet的资源名部分--> <url-pattern>/hello</url-pattern> </servlet-mapping> |
4.启动tomcat访问servlet,在浏览器地址栏输入http://localhost:8080/myServlet/hello
即可看到浏览器显示的Hello,World!
我们可以发现,当我们刷新页面的时候,控制台只输出一次init it,而会每次访问都会输入service it。
这里我们来说说Servlet的生命周期:
Servlet部署在容器里,这里我们使用的是tomcat,也可以是其它的容器如:weblogic 它的生命周期由容器来管理。
Servlet的生命周期分为以下几个阶段:
1、加载阶段
当Web服务器启动时,Servlet容器加载一个Java Servlet类,这个过程也有可能推迟到Web客户请求Servlet服务时发生。通常情况下,Servlet容器使用Java类加载器加载一个Servlet,可以加载本地的Servlet,也可以加载远程的Servlet。注意,Servlet只需要被加载一次,然后将会实例化该类的一个实例或者多个实例。
2.创建一个servlet实例。
Servlet容器调用Servlet的初始化方法HttpServlet.init()进行Servlet初始化。因此,我们可以通过重写init()方法进行初始化某些工作。
例如:通过重写init()方法,读取配置信息,完成数据连接等工作。
如果init()方法调用失败,则会发生ServletException,Servlet将不能正常工作。在这种情况下,该Serlvet将会被容器清除掉,清除该Servlet后,容器将重新初始化这个Servlet。
3.Servlet运行阶段
当Web服务器接受到浏览器的访问请求后,将把该请求传送给Servlet容器。Servlet容器将请求包装成HttpServletRequest和HttpServletResponse对象,封装从Web客户接收到的HTTP请求和由Servlet生成的响应。并使用这两个对象作为参数,调用service()方法。
在service()方法中,可以从HttpServletRequest类中提取来自HttpSession、reqeust或cookie等对象的状态信息,进行特定应用的处理,并且用HttpServletResponse对象生成HTTP响应数据。
4.Servlet结束时期
Servlet将一直运行到被服务器卸载,或者当Web服务器和容器关闭时。这种情况下将回收init()方法中使用的资源,如关闭数据库连接等。这些都是通过调用destrory()方法来实现的。
容器在调用destroy()方法前,它必须等待那些正在service()方法中执行的线程执行完毕或者在服务器定义的一段时间内执行(这个时间段在容器调用destroy()方法之前)。一旦destroy()方法被调用,容器就不会再向该实例发送任何请求。如果容器需要再使用该Servlet,它必须创建新的实例。destroy()方法完成后,容器必须释放Servlet实例以便它能够被垃圾回收。
A:tomcat重启 B:reload该webapps空间 C:重启电脑
继承GeneriServlet
通过继承GenericServlet去开发servlet,只需要重写service方法,相对来说简单一点。
1.同样新建一个HelloGen文件,继承GenericServlet,重写service方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package com.lpq; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class HelloGen extends GenericServlet{ @Override public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter pw = resp.getWriter(); pw.print("Hello,wrold!Generic"); } } |
2.在web.xml文件中部署该servlet
1 2 3 4 5 6 7 8 9 | <servlet> <servlet-name>HelloGen</servlet-name> <servlet-class>com.lpq.HelloGen</servlet-class>注意:后面不要带.java④ </servlet> <servlet-mapping> <servlet-name>HelloGen</servlet-name> <url-pattern>/hellogen</url-pattern> </servlet-mapping> |
3.启动tomcat,输入http://localhost:8080/myServlet/hellogen 即可显示Hello,World!Generic
继承HttpServlet
通过继承HttpServlet去开发Servlet,需要重写doGet() doPost()方法。这是目前使用的最多的一种方法。
我们先来说说get和post提交的区别:
1.从安全性来看post的安全性要高于get,get提交的数据会在浏览器地址栏显示。
2.从提交的内容大小来看,get提交的数据不能大于2K,而post提交的数据理论上不受限制,但是实际编程中不要大于64K
3.从请求响应速度来看,get的响应速度要快,get要求服务器立即处理请求,而post骑牛可能形成一个队列请求。
1.我们仍然写一个HelloHttp.java文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package com.lpq; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloHttp extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub PrintWriter pw = resp.getWriter(); pw.print("Hello,wrold!HttpServlet"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doGet(req, resp); } } |
2.在web.xml文件中部署该servlet
1 2 3 4 5 6 7 8 9 | <servlet> <servlet-name>HelloHttp</servlet-name> <servlet-class>com.lpq.HelloHttp</servlet-class>注意:后面不要带.java④ </servlet> <servlet-mapping> <servlet-name>HelloHttp</servlet-name> <url-pattern>/hellohttp</url-pattern> </servlet-mapping> |
3.启动tomcat,输入http://localhost:8080/myServlet/hellohttp 即可显示Hello,World!HttpServlet
Servlet细节问题:
① 一个已经注册的Servlet可以被多次映射。
② 当映射一个servlet时候,可以多层 比如
<url-pattern>/servlet/index.html</url-pattern> ok
从这里还可以看出,后缀名是 html 不一定就是 html,可能是假象.
③ 使用通配符在servlet映射到URL中
有两种格式:
第一种格式 *.扩展名 比如 *.do *.ss
第二种格式 以 / 开头 同时以 /* 结尾 比如 /* /news/*
通配符练习题:
l Servlet1映射到 /abc/*
l Servlet2映射到 /*
l Servlet3映射到 /abc
l Servlet4映射到 *.do
问题(面试题):
l 当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
l 当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
l 当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
l 当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
l 当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
在匹配的时候,要参考的标准:
(1) 看谁的匹配度高,谁就被选择
(2) *.do 的优先级最低
④ Servlet单例问题
当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务.即在使用中是单例.
因为 Servlet是单例,因此会出现线程安全问题: 比如:
售票系统. 如果不加同步机制,则会出现问题:
这里我给大家一个原则:
(1) 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制
synchronized(对象){
//同步代码
}
(2)如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题
⑤ servlet中的 <load-on-startup> 配置
需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表), 在比如:
我们的网站有一些要求定时完成的任务[ 定时写日志,定时备份数据.. 定时发送邮件..]
解决方法: 可以通过<load-on-startup> 配合 线程知识搞定.
先说明<load-on-startup>: 通过配置<load-on-startup> 我们可以指定某个Servlet 自动创建.
除非注明,饮水思源博客文章均为原创,转载请以链接形式标明本文地址