在开发 Java
浏览器和服务器的 B/S
架构程序中,最开始用来接收浏览器发给服务器端请求的就是 Servlet
了,它最主要的作用就是用来接收用户请求,然后处理完相关的业务逻辑之后,再返回相应的信息给浏览器端。
1.Servlet是什么?
首先先看一下 API
文档中对它的定义:
`A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol. `
Servlet
是一种必须运行在 Web
服务器中的 Java
小程序,通常通过 HTTP(超文本传输协议)
来接受并响应来自 Web
客户端的请求。
2.新建一个Servlet
如何才能新建一个 Servlet
呢?首先想到的就是实现 javax.servlet.Servlet
接口,然后再对实现接口的类进行配置。当然在实现 Servlet
这个接口的时候,也会需要重写它的很多方法。
首先声明一个类来实现 Servlet
接口:
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class ServletUrl implements Servlet{
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
System.out.println("ServletUrl被访问了...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
然后再到 web.xml
文件中对这个 Servlet
进行配置
<servlet>
<servlet-name>ServletUrl</servlet-name>
<servlet-class>party.laucloud.ServletUrl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletUrl</servlet-name>
<url-pattern>/servletUrl</url-pattern>
</servlet-mapping>
这样配置好了之后,当用户请求 /servletUrl
路径的时候就可以访问的到我们刚才编写的这个 Servlet
类了,而响应用户请求的则是 Service()
方法,因此可以在这个方法中添加打印语句进行测试。 `
3.Servlet的执行流程
对于 Servlet
的执行流程,当用户在浏览器中输入地址对服务器进行访问的时候,首先就会根据访问路径到 web.xml
中 Servlet
配置中查找对应的 <url-pattern>
,找到 <url-pattern>
之后就可以确定对应的 <servlet-name>
,然后也就能确定到对应的 <servlet-class>
了,也就是具体的 Servlet
类了,而这个类中就会运行 service()
方法来响应用户的请求。这也就是 Servlet
的运行流程。
4.Servlet的实现关系
首先先看一段官方 API
中对于如何创建 Servlet
的描述:
`To implement this interface, you can write a generic servlet that extends javax.servlet.GenericServlet or an HTTP servlet that extends javax.servlet.http.HttpServlet.`
上面的说法是说要想创建一个 Servlet
有三种方式:
1、实现javax.servlet.Servlet这个接口
2、继承javax.servlet.GenericServlet这个类
3、继承javax.servlet.http.HttpServlet这个类
而 Servlet
的实现关系也就是上面三者之间的关系,也就是 GenericServlet
这个类实现了 Servlet
这个接口,而 HttpServlet
又继承了 GenericServlet
这个类。HttpServlet
是一个与协议有关的类,即它是用来处理 HTTP
协议的请求的,而我们浏览器与服务器之间通信就是基于 HTTP
请求啊,为什么还需要 GenericServlet
这个类呢?这样设计完全就是为了应对以后的发展,虽然现在都是基于 HTTP
协议的,但是不代表以后也一直是基于这个协议,事物总是会有发展的嘛,所以就设定了 GenericServlet
这个与任何协议都无关的类,以应对以后的发展。
我们开发的时候一般都是继承 HttpServlet
这个类,然后再重写它的 service()
方法来处理用户的请求,在查看 HttpServlet
类中的 service()
方法的源码时发现,在处理用户发送过来的请求时,它是根据用户的请求方式分类来进行处理的,如果用户使用的是 GET
请求方式,那么就会运行 doGet()
方法来处理用户的请求,如果是 POST
方式的话,那就调用 doPost()
方法来处理用户的请求,当然还有很多其它的请求方式,也都预定了它们对应的处理方法,因为 GET
方式和 POST
方式是使用的最多的两种方式,因此我们在重写 HttpServlet
中方法的时候,就可以不重写 service()
方法,而是重写 doGet()
和 doPost()
方法。由于这两个方法要处理的业务逻辑往往是一样的,因此可以让其中一个方法调用另一个方法。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().print("hello servlet ...");
}
5.在Eclipse中使用Servlet的模板
也许你会觉得上面创建 Servlet
的方式太过繁琐了,想用简单一点的方式,但是最好还是在完全掌握上面这种方式之后再使用其它的方法,也就是下面要介绍的,基于 Eclipse
模板生成的这种,这种方式在创建 Servlet
的过程中,完全是可视化图形界面的方式,创建好类之后还会自动在 web.xml
文件中加入 Servlet
的配置,但是可能使用这种方式多了以后,就会忘记最原始怎么创建 Servlet
了。
其实方式也十分简单,就是在一个包中创建 Servlet
类的时候,单击右键,选择 new
,然后再选择 Servlet
,输入要创建的名称和实现的父类,点击下一步就可以修改 URL mapping
,也就是我们之前手动设置时设置的 <url-pattern>
,最后点击下一步选择需要重写的父类方法,点击完成 Eclipse
就会自动为我们生成一个 Servlet
了,而且还会在 web.xml
中跟我们配置好。
采用这种自动生成的方式的话,最好在生成之后都检查一下,生成的类和 web.xml
配置文件都应该检查一下。
6.Servlet的生命周期
关于 Servlet
的生命周期,API
中也给出了非常详细的介绍:
`This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:
1.The servlet is constructed, then initialized with the init method.
2.Any calls from clients to the service method are handled.
3.The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized. `
上面就是说关于 Servlet
的生命周期,其实和三个方法有关,那就是 init()
、service()
以及 destroy()
方法,当一个 Servlet
第一次被访问的时候,这时 Servlet
对象就会被创建,被调用 init()
方法来进行一些初始化操作,而且 init()
只会执行一次,然后当有用户请求访问这个 Servlet
的时候,就会调用其中的 service()
方法进行响应,最后在将服务器关闭的时候,就会调用 destroy()
方法将这个 Servlet
进行销毁。这就是 Servlet
的生命周期了,要是想测试的话也可以分别在一个 Servlet
的 init()
、service()
以及 destroy()
方法中加上打印语句进行测试。
7.Servlet启动时加载配置
Servlet
是什么时候被创建呢?是被第一次访问的时候,那么这样说来,在 Servlet
第一次被访问的时候响应速度应该是最慢的,因为需要做很多初始化的操作,那如何解决这个问题呢?就是可以将 Servlet
创建的时间从第一次被访问移到服务器启动的时候,这样虽然服务器启动时间会偏长一点,但是以后使用 Servlet
响应用户请求的时候,每次的响应时间就都是一样的了。
要想实现让 Servlet
在服务器启动时创建,就需要在 Servlet
的配置文件中加入 load-on-startup
属性,该属性对应的属性值就是启动优先级,值越小说明优先级越高,Tomcat
中有一个默认的 Servlet
设置的优先级为 1
,所以我们一般将自己创建的 Servlet
优先级设置为 2
,可以如下设置:
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>party.laucloud.ServletDemo1</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>
Tomcat
中一个默认的 Servlet
的配置是在 conf/web.xml
中
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
8.Servlet访问路径的配置
Servlet
访问路径的设置,其实就是在 web.xml
中配置 Servlet
时其中的 url-pattern
属性,访问路径可以分为三种情况:全路径匹配、目录匹配和扩展名匹配。
全路径匹配:以/开头,例如:/ServletDemo、/abc/ServletDemo
目录匹配:以/开头,*结尾。例如:/*、/aaa/*(*代表任意字符)
扩展名匹配:以*开头,.xxx结尾。例如:*.action、*.do
有一种情况就是有一个路径请求匹配了多种路径设置,比如 /abc/servlet.action
可能既会满足全路径匹配 (/abc/servlet.action)
,又满足扩展名匹配 (*.action)
,那这样情况应该如何匹配呢?
上面就是要涉及到优先级了,其中的规则就是越精确优先级越高,也就是全路径匹配>目录匹配>扩展名匹配,也就是如果一个 Servlet
在在进行全路径匹配之后,就不会再匹配目录匹配和扩展名匹配了。
9.总结
关于 Servlet
的掌握的话重点还是应该在多使用上面,使用的多了也就会非常熟练了,最好是能做一些小案例,这样解决一些问题之后就会理解的更透彻,至于一些相关理论知识,可以通过查询文档来学习得知。