Servlet
三大组件-Servlet
概念
Servlet和Tomcat的关系:Tomcat支持Servlet

Servlet 在开发动态 WEB 工程中,得到广泛的应用,掌握好 Servlet 非常重要了, Servlet(基石)是 SpringMVC 的基础
Servlet(java 服务器小程序),它的特点:
- 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
- 他是用java语言编写的, 本质就是Java类
- 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
- 功能强大,可以完成几乎所有的网站功能
手动开发Servlet
- 编写类HelloServlet去实现 Servlet 接口
- 实现 service 方法,处理请求,并响应数据
- 在 web.xml 中去配置 servlet 程序的访问地址
注意:要手动添加servlet-api.jar(在web/WEB-INF/lib下) 到工程。
package com.lzw.servlet;
import javax.servlet.*;
import java.io.IOException;
/**
* @author LiAng
* @time 2022/2/19 10:42
*/
public class HelloServlet implements Servlet {
/**
* 1.初始化 servlet
* 2.当创建HelloServlet 实例时,会调用init方法
* @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;
}
/**
* 1.service方法处理浏览器的请求(包括get/post)
* 2.当浏览器每次请求Servlet时,就会调用一次service方法
* 3.当tomcat调用该方法时,会把http请求的数据封装成实现了ServletRequest接口的request对象
* 4.通过servletRequest 对象,可以得到用户提交的数据
* 5. servletResponse 对象可以用于返回数据给Tomcat->浏览器
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet");
}
/**
* 返回servlet信息,使用较少
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 1.该方法是在servlet销毁时,被调用
* 2.只会调用一次
*/
@Override
public void destroy() {
System.out.println("destroy 调用");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- 注释小技巧-->
<!--注意
1.servlet-name:给Servlet取名,该名字唯一
2.servlet-class:Servlet的类的全路径:Tomcat在反射生成该Servlet需要使用
3.url-pattern:这个就是该servlet访问的url的配置(路径)
4.这时应该这样访问:http://localhost:8080/servlet/helloServlet
5.url-pattern 取名是程序员决定的,/不要丢
6.load-on-startup 表示在tomcat 启动时,会自动的加载servlet实例
-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.lzw.servlet.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
</web-app>
浏览器调用Servlet流程

Servlet生命周期

- init()初始化阶段
- service()处理浏览器请求阶段
- destroy()终止阶段
初始化阶段
Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init()方法,init()方法只会调用一次, Servlet 容器在下面的情况装载 Servlet:
- Servlet 容器(Tomcat)启动时自动装载某些 servlet,实现这个需要在 web.xml 文件中添加
<load-on-startup>1</load-on-startup>
1 表示装载的顺序 - 在 Servlet 容器启动后,浏览器首次向 Servlet 发送请求(这个前面说过)
- Servlet 重新装载时(比如 tomcat 进行 redeploy【redeploy 会销毁所有的 Servlet 实例】), 浏览器再向 Servlet 发送请求的第 1 次
处理浏览器请求阶段(service 方法)
- 每收到一个 http 请求,服务器就会产生一个新的线程去处理[线程]
- 创建一个用于封装 HTTP 请求消息的 ServletRequest 对象和一个代表 HTTP 响应消息的ServletResponse 对象
- 然后调用 Servlet 的 service()方法并将请求和响应对象作为参数传递进去
终止阶段 destory 方法(体现 Servlet 完整的生命周期)
当 web 应用被终止,或者 Servlet 容器终止运行,或者 Servlet 类重新装载时,会调用destroy()方法
HttpServlet

Servlet注意事项和细节
- Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行。
- 针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象, 也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至 web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁。

在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引 擎调用一次 servlet 的 service 方法。
对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个 新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet 的 service()方法,service 方法再根据请求方式分别调用 doXXX 方法。
如果在
<servlet>
元素中配置了一个<load-on-startup>
元素,那么 WEB 应用程序在启动时, 就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法。
Servlet注解方式
package com.lzw.servlet.annotation;
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;
/**
* @author LiAng
* @time 2022/2/21 8:25
* 注解方式来配置
*/
/**
* 1. @WebServlet 是一个注解
* 2. @WebServlet 源码
* @Target({ElementType.TYPE})
* @Retention(RetentionPolicy.RUNTIME)
* @Documented => 在javadoc工具生成文档有记录
* public @interface WebServlet {
* String name() default "";
*
* String[] value() default {};
*
* String[] urlPatterns() default {};
*
* int loadOnStartup() default -1;
*
* WebInitParam[] initParams() default {};
*
* boolean asyncSupported() default false;
*
* String smallIcon() default "";
*
* String largeIcon() default "";
*
* String description() default "";
*
* String displayName() default "";
* }
* 3. urlPatterns 对应web.xml 的 <url-pattern></url-pattern>
* 4. {"/ok1", "/ok2"} 可以给OkServlet配置多个 url-pattern
* 5. 相当于 @WebServlet(urlPatterns = {"/ok1", "/ok2"}) 代替了web.xml的配置
* 底层使用了 反射+注解+IO+集合 来完成一个支撑
* 6. 浏览器可以这样访问OkServlet时,http://localhost:8080/servlet/ok1
* 或 http://localhost:8080/servlet/ok2
* 7.
*/
@WebServlet(urlPatterns = {"/ok1", "/ok2"}, loadOnStartup = 1)
public class OkServlet extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("注解 init()");
}
@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 urlPattern 配置
1.精确匹配
配置路径 : @WebServlet("/ok/zs")
访问 servlet: localhost:8080/servlet/ok/zs
2.目录匹配
配置路径 : @WebServlet("/ok/*")
访问文件: localhost:8080/servlet/ok/aaa localhost:8080/servlet/ok/bbb
3.扩展名匹配
配置路径 : @WebServlet("**.action")*
访问文件: localhost:8080/hsp/zs.action localhost:8080/hsp/ls.action
提示: @WebServlet("/*.action") , 不能带 / , 否则 tomcat 报错
4.任意匹配
配置路径 : @WebServlet("/") @WebServlet("/*")
访问文件: localhost:8080/hsp/aaa localhost:8080/hsp/bbb localhost:8080/hsp/ccc
提示:/ 和 /*的配置,会匹配所有的请求,这个比较麻烦,要避免
注意
1、当 Servlet 配置了 "/", 会覆盖 tomcat 的 DefaultServlet, 当其他的 utl-pattern 都匹配不上时,都会走这个Servlet,这样可以拦截到其他静态资源。
2、当 Servelt 配置了 "/*", 表示可以匹配任意访问路径
3、提示: 建议不要使用 / 和 /*, 建议尽量使用精确匹配
4、优先级遵守:精确路径 > 目录路径 > 扩展名路径 > /* > /
ServletConfig
介绍
1.ServletConfig 类是为 Servlet 程序的配置信息的类
2.Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
3.Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig对象
作用
1.获取 Servlet 程序的 servlet-name 的值
2.获取初始化参数 init-param
3.获取 ServletContext 对象
<?xml version="1.0" encoding="UTF-8"?>
<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-name>DBServlet</servlet-name>
<servlet-class>com.lzw.servlet.DBServlet</servlet-class>
<!--配置信息,而不是硬编码到程序-->
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>pwd</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DBServlet</servlet-name>
<url-pattern>/db</url-pattern>
</servlet-mapping>
</web-app>
package com.lzw.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DBServlet extends HttpServlet {
/**
* 1. 当DBServlet对象初始化时,tomcat会同时创建一个 ServletConfig对象
* 2. 这是如果DBServlet init() 方法中你调用 super.init(config);
* 3. 调用父类
* public void init(ServletConfig config) throws ServletException {
* this.config = config;
* this.init();
* }
* 这时就会把 Tomcat创建的ServletConfig对象赋给GenericServlet的属性 config
* 4. 因此如果你重写init()方法,如果你想在其他方法通过 getServletConfig() 获取ServletConfig
* 有一定记住,要调用 super.init(config);
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init" + config);
super.init(config);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在 DBServlet 执行 doGet()/doPost() 时,可以获取到 web.xml 配置的用户名和密码
//DBServlet的父类GenericServlet有getServletConfig()
/**
* 1. getServletConfig() 方法是 GenericServlet
* 2. 返回的 servletConfig 对象是 private transient ServletConfig config
* 3. 当一个属性被 transient 修饰,表示该属性不会被串行化(有些重要信息,不希望保存到文件)
*/
ServletConfig servletConfig = getServletConfig();
System.out.println(servletConfig);
String username = servletConfig.getInitParameter("username");
String pwd = servletConfig.getInitParameter("pwd");
System.out.println("初始化参数username = " + username);
System.out.println("初始化参数pwd = " + pwd);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
ServletContext
介绍
1.ServletContext 是一个接口,它表示 Servlet 上下文对象
2.一个 web 工程,只有一个 ServletContext 对象实例
3.ServletContext 对象 是在 web 工程启动的时候创建,在 web 工程停止的时候销毁
4.ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。
5.由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext对象来实现多个 Servlet 间通讯。ServletContext 对象通常也被称之为域对象。

作用
1.获取 web.xml 中配置的上下文参数 context-param [信息和整个 web 应用相关,而不是属于某个 Servlet]
2.获取当前的工程路径,格式: /工程路径 =》 比如 /servlet
3.获 取 工 程 部 署 后 在 服 务 器 硬 盘 上 的 绝 对 路 径 ( 比如:D:\lzw_javaweb\servlet\out\artifacts\servlet_war_exploded)
4.像 Map 一样存取数据, 多个 Servlet 共享数据
<?xml version="1.0" encoding="UTF-8"?>
<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-name>ServletContext_</servlet-name>
<servlet-class>com.lzw.servlet.servletcontext.ServletContext_</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletContext_</servlet-name>
<url-pattern>/servletContext_</url-pattern>
</servlet-mapping>
<!--配置整个网站的信息-->
<context-param>
<param-name>website</param-name>
<param-value>http://www.lzw.net</param-value>
</context-param>
<context-param>
<param-name>company</param-name>
<param-value>巴拉巴拉</param-value>
</context-param>
</web-app>
package com.lzw.servlet.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletContext_ extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取web.xml的context-parameter
//1.获取到ServletContext对象
ServletContext servletContext = getServletContext();
//2.获取website
String website = servletContext.getInitParameter("website");
String company = servletContext.getInitParameter("company");
//3.获取项目的工程路径
String contextPath = servletContext.getContextPath();
//4.获取项目发布后 真正的工作路径
// "/" 表示我们的项目(发布后)的根路径 E:\VIP\JavaWeb\Demo\servlet\out\artifacts\servlet_war_exploded
String realPath = servletContext.getRealPath("/");
System.out.println("项目发布后的绝对路径 = " + realPath);
System.out.println("项目路径 = " + contextPath);
System.out.println("website = " + website);
System.out.println("company = " + company);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}