Github:servlet_demo
一. 定义
servlet-api:https://tomcat.apache.org/tomcat-8.5-doc/servletapi/index.html
Servlet(Server Applet,运行在服务器端的小程序),是一个接口,定义了 Java 类被浏览器访问到(Tomcat 识别)的规则。我们需要自定义一个类实现 Servlet 接口并重写其方法。
二. 创建步骤
1.创建 JavaEE 项目
2.创建一个类并实现 Servlet 接口:public class ServletDemo1 implements Servlet
3.实现 Servlet 接口中的抽象方法
import javax.servlet.*;
import java.io.IOException;
/**
* ServletDemo1:Servlet 快速入门
*/
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 Servlet!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
4.在 web.xml 中配置 Servlet
<!-- 配置 Servlet -->
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>com.hjplz.web.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
三. 执行流程
1.当服务器接收到客户端浏览器的请求后,会解析请求 URL 路径,获取访问 Servlet 的资源路径。
2.服务器查找在 web.xml 中 <url-pattern>
是否有对应的路径。
3.如果有,通过映射找到 <servlet-class>
全类名。
4.Tomcat 将全类名对应的字节码文件加载进内存:Class.forName()
,并创建其对象:newInstance()
。
5.调用 service()
方法
6.将处理结果封装到 response
对象,服务器从此对象中获取信息,给客户端浏览器返回 HTTP 响应。
注意,多个请求创建多个线程来处理。
四. 生命周期
1.被创建:init()
,只执行一次。
- 默认情况:第一次被访问时创建 Servlet
- 可以通过在
<servlet>
标签下配置来指定 Servlet 的创建时机<!-- 指定 Servlet 的创建时机 1. 第一次被访问时创建:<load-on-startup> 的值为负数(默认为 -1) 2. 在服务器启动时创建:<load-on-startup> 的值为非负数 --> <load-on-startup>-1(default)</load-on-startup>
init()
只执行一次说明一个 Servlet 在内存中只存在一个对象,Servlet 是单例的。- 多个用户同时访问时,可能存在线程安全问题。
- 解决方法:尽量不要在 Servlet 中定义成员变量,即使定义了成员变量,也不要修改其值。
2.提供服务:service()
,可以执行多次。
- 每次访问 Servlet 时,
service()
都会被调用一次。
3.被销毁:destroy()
,只执行一次。
- 服务器关闭时,Servlet 被销毁。如果服务器不是正常关闭则不会执行此方法。
- 在 Servlet 被销毁之前执行,一般用于释放资源。
import javax.servlet.*;
import java.io.IOException;
/**
* ServletDemo2:Servlet 方法(生命周期)
*/
public class ServletDemo2 implements Servlet {
/**
* 初始化方法
* 在 Servlet 被创建时执行,只会执行一次。
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init...");
}
/**
* 获取 ServletConfig 对象(Servlet 配置对象)
* @return
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务方法
* 每一次 Servlet 被访问时执行,可以执行多次。
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service...");
}
/**
* 获取 Servlet 信息:version、author...
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 在服务器正常关闭时执行,只会执行一次。
*/
@Override
public void destroy() {
System.out.println("destroy...");
}
}
五. Servlet 继承体系结构
1.Servlet(接口)— GenericServlet(抽象类)— HttpServlet(抽象类)
2.GenericServlet:将 Servlet 接口中其他方法做了默认空实现,只把 service()
抽象。
- 定义 Servlet 类继承 GenericServlet,只要实现
service()
即可。import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; /** * 继承抽象类 GenericServlet */ @WebServlet("/demo4") public class ServletDemo4 extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("GenericServlet..."); } }
3.HttpServlet:对HTTP协议进行封装,简化操作。
- 定义 Servlet 类继承 HttpServlet,重写
doGet()
&doPost()
。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; /** * 继承抽象类 HttpServlet */ @WebServlet("/demo5") public class ServletDemo5 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost..."); } }
六. Servlet 3.0
1.优点:支持注解配置,不再需要 web.xml。
2.注解配置:在类上使用 @WebServlet("url-pattern")
,e.g. @WebServlet("/demo3")
- 虚拟目录
Application context
是项目的访问地址,资源路径url-pattern
是 Servlet 类的访问地址。 - 一个 Servlet 可以定义多个访问路径:
@WebServlet({"/path1", "/path2", ...})
- 路径定义规则
- 精准匹配:/foo.htm 只会匹配 foo.htm 这个 URL
- 路径匹配:/foo/* 会匹配以 foo 为前缀的 URL
- 后缀匹配:*.htm 会匹配所有以 .htm 为后缀的 URL
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;
/**
* Servlet 路径配置
*/
// @WebServlet({"/demo6", "/d6"})
// @WebServlet("/*")
// @WebServlet("/user/*")
// @WebServlet("/user/demo6")
// @WebServlet("*.do")
@WebServlet("/demo6")
public class ServletDemo6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo6...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo6...");
}
}
七. IDEA InteliJ & Tomcat 的相关配置
1.IDEA InteliJ 会为每一个 Tomcat 部署的项目单独创建一份配置文件
- 查看控制台log:
org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: /Users/mac/Library/Caches/IntelliJIdea2019.2/tomcat/Tomcat_8_5_45_servlet_demo
2.工作空间项目 & Tomcat 部署的 web 项目
- Tomcat 真正访问的是部署的 web 项目,其对应着工作空间项目 web 目录下的所有资源。
- WEB-INF 目录下的资源(classes 目录、lib 目录、web.xml)不能直接被浏览器访问。
3.断点调试:Debug