1. Servlet 的概念
Servlet(Server Applet),它是运行在服务器端的小程序。
实际上 Servlet 就是一个接口,定义了 Java 类能被 Tomcat 识别的规则。(也就是说我们自定义一个 java 类,它实现了 Servlet 接口,它就能被 Tomcat 识别了)
2. Servlet 快速入门
-
创建一个 JavaEE 项目
-
定义一个 Java 类,并且实现 Servlet 接口
-
实现 Servlet 接口中的方法
package com.zt.web.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } // 提供服务的方法 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("hello"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
-
配置 Servlet
在web.xml中配置:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--配置 Servlet--> <servlet> <!--给 Servlet 起一个名字,一般和类名一致--> <servlet-name>ServletDemo1</servlet-name> <!--配置这个 Servlet 的全类名--> <servlet-class>com.zt.web.servlet.ServletDemo1</servlet-class> </servlet> <!--配置 Servlet 的映射路径--> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <!--外界能访问到 Servlet 的资源路径--> <url-pattern>/ServletDemo1</url-pattern> </servlet-mapping> </web-app>
-
访问项目
-
启动服务器
-
打开浏览器,在地址栏输入
http://localhost:8080/ServletDemo1
-
此时控制台会输出
hello
-
3. Servlet 的执行原理
疑问:
在上面的实例中,我们创建了 ServletDemo1 这个类,并且实现了 Servlet 接口,但我们并没有创建 ServletDemo1 的对象,那 service 方法(不是静态方法)是怎么就被执行了呢?
Servlet 的执行原理如下:
- 当服务器接受到客户端浏览器的请求后,会解析请求 URL 路径,获取访问的 Servlet 的资源路径
- 然后查找 web.xml 文件,是否有与资源路径对应的
<url-pattern>
标签体内容。 - 如果有,则在找到对应的
<servlet-class>
全类名 - Tomcat 会将全类名对应的字节码文件加载进内存,并且创建其对象,调用 service 方法
4. Servlet 的生命周期
-
被创建
Servlet 被创建时,执行 init 方法,只执行一次(一般用于加载资源)
-
Servlet 什么时候被创建?
默认情况下,第一次被访问时,Servlet 被创建
-
配置执行 Servlet 的创建时机
在
<servlet>
标签中配置-
第一次被访问时,Servlet 被创建
<load-on-startup>负数</load-on-startup>
-
在服务器启动时,Servlet 被创建
<load-on-startup>0或正整数</load-on-startup>
-
-
Servlet 的 init 方法,只执行一次,说明一个 Servlet 在内存中只存在一个对象,Servlet 是单例的
问题:多个用户同时访问时,可能存在线程安全问题
解决办法:尽量不要在 Servlet 中定义成员变量。即使定义了成员变量,也不要对修改值
-
-
提供服务
每一次 Servlet 被访问时,执行 service 方法,执行多次
-
被销毁
在服务器正常关闭时,执行 destroy 方法,只执行一次(一般用于释放资源。)
5. Servlet 3.0
-
功能
支持注解配置,可以不用 web.xml 配置了。
-
使用步骤
-
点击 Create New Project
-
选择 Java Enterprise
-
Java EE version 修改为 Java EE 7 及以上
-
勾选 Web Application,选择 Servlet 的版本 3.0 及以上,可以不勾选创建 web.xml,点击 Next
-
输入 Project Name,点击 Finish
-
定义一个 Java 类,并且实现 Servlet 接口
-
实现 Servlet 接口中的方法
-
在类上使用 @WebServlet 注解,进行配置
// 定义一个访问路径 @WebServlet("资源路径") // 定义多个访问路径 @WebServlet({"资源路径1","资源路径2","资源路径3"})
-
访问项目
-
启动服务器
-
打开浏览器,在地址栏输入
http://localhost:8080/资源路径
-
-
6. Servlet 的体系结构
我们使用 Servlet 类时,往往只需要使用 service 方法,但我们却不得不实现 Servlet 接口中的所有方法,这样会出现很多冗余代码。Java EE 中 Servlet 接口有两个实现类,可以解决这一问题。
Servlet 的体系结构:
Servlet -- 接口
|
GenericServlet -- 实现 Servlet 接口的抽象类
|
HttpServlet -- 实现 Servlet 接口的抽象类
-
GenericServlet
GenericServlet 类将 Servlet 接口中其他的方法做了默认空实现,只将 service() 方法作为抽象方法。将来定义 Servlet 类时,可以继承 GenericServlet,只需实现 service() 方法。
package com.zt.web.servlet; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/ServletDemo2") public class ServletDemo2 extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("GenericServlet..."); } }
-
HttpServlet
在 service 方法中,获取数据之前,先要判断请求方式
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取请求方式 String method = req.getMethod(); // 判断请求方式 if(method.equals("GET")){ // Get 方式获取数据 } if(method.equals("POST")){ // Post 方式获取数据 } }
上面这个过程十分麻烦,但也是不能省略的,所以 Java EE 中提供了 HttpServlet 。在 service 方法中,它帮我们判断请求方式是 GET 还是 POST,并做了一个方法的分发,如果是 GET 就调用 doGet 方法,如果是 POST 就调用 doPost 方法。
将来定义 Servlet 类时,可以继承 HttpServlet,就只用重写 doGet 和 doPost 方法即可,不用再去重写 service 了。
package com.zt.web.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/ServletDemo3") public class ServletDemo3 extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost..."); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet..."); } }
补充:浏览器直接访问 Servlet 是 Get 方式