目录
1. 官方文档
2. Servlet概述
3. Servlet基本使用
3.1. 浏览器调用Servlet的流程
3.2. Servlet生命周期
3.3. Get/Post请求的分发处理
4. Servlet继承结构
5. 继承HttpServlet开发Servlet
5.1. HttpServlet介绍
5.2. 使用相关代码测试
5.3. HttpServletRequest
5.4. HttpServletResponse
6. Servlet注意事项
7. ServletConfig和ServletContext
7.1. ServletConfig的使用
7.2. ServletContext的使用
8. Servlet注解方式
8.1. 定义
8.2. 代码演示
8.3. @WebServlet注解
8.4. WebServlet注解原理
9. 请求转发和响应重定位
9.1. 概述
9.2. 请求转发
9.3. 响应重定向
官方文档地址:Overview (Servlet 4.0 API Documentation - Apache Tomcat 9.0.83)
servlet 与 Tomcat 的关系:Tomcat 支持 Servlet
Tomcat 是一个开源的 Java 服务器,它主要用来提供 Web 服务,包括 HTTP 请求和响应的处理。Servlet 是 Java 的一种技术,用于创建动态 Web 应用程序。
Tomcat 支持 Servlet,这意味着你可以在 Tomcat 服务器上运行 Servlet 程序。Tomcat 为 Servlet 提供了一个运行环境,使得你可以使用 Servlet 技术来开发并部署 Web 应用程序。
简单来说,如果你想使用 Servlet 技术来开发 Web 应用程序,你需要一个支持 Servlet 的服务器,而 Tomcat 就是一个很好的选择。
Servlet 是 Java 的一种技术,就是用Java编写的,本质就是Java类,用于创建动态 Web 应用程序。它是
一个运行在服务器端的 Java 小程序,可以响应客户端的请求,处理数据,并返回响应结果。Servlet 由
Sun Microsystems 公司提供一套规范,定义了动态资源如何在 Web 服务器上运行。
从代码层面上讲,Servlet 是一个接口,这意味着它定义了一组方法,这些方法可以由 Web 服务器调用。
在 Tomcat 中,Servlet 运行在一个称为“容器”的环境中。Tomcat 为 Servlet 提供了一个运行环境,这
个容器负责加载和运行 Servlet。Tomcat 会将来自客户端的 HTTP 请求转发给 Servlet 处理,并将
Servlet 的响应返回给客户端。
因此,Servlet 和 Tomcat 是相互依存的。如果你想使用 Servlet 技术来开发 Web 应用程序,你需要一个
支持 Servlet 的服务器,而 Tomcat 就是一个很好的选择。
简单总结就是:
Servlet是一种用于接收、处理客户端请求、响应给浏览器的动态资源的Java类。它必须满足特定的接口规范,并需要被部署在支持Servlet的Web服务器或应用服务器上才能正常运行。
需求:
开发一个 HelloServlet
当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "Hi HelloServelt"
具体步骤:
这里用两种方法:一个是自己导入实体Tomcatlib文件夹下的servlet的jar包
二是在pom文件配置联网下载Servlet的jar包
package com.example;
import javax.servlet.*;
//创建一个Servlet类,要实现Servlet接口
//实现接口的5个方法,但常用的是3个
public class HelloServlet implements Servlet {
/*
* 该方法常用
* init初始化方法,在服务器启动时调用该方法
* 该方法只执行一次
* */
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("init方法被调用~");
}
/*
* getServletConfig方法
* 返回ServletConfig 也就是返回ServLet的配置
* */
@Override
public ServletConfig getServletConfig() {
return null;
}
/*
* 该方法使用的非常多
* service方法,在服务器接收到请求时(含get/post方法)调用该方法
* 该方法每次请求都会被调用
* 该方法会把http请求转为Java对象,进行一系列操作
* 处理请求之后会把Java对象转为http响应,返回给客户端
* */
@Override
public void service(ServletRequest req, ServletResponse res) {
System.out.println("Hello Servlet!");
}
/*
* getServletInfo方法
* 返回Servlet的描述信息*/
@Override
public String getServletInfo() {
return null;
}
/*
* 该方法常用
* destroy销毁方法,
* 在服务器关闭时调用该方法
* 该方法只执行一次
* */
@Override
public void destroy() {
}
}
记住,虽然这五个方法都是可选的,但init()、service()和destroy()是最常用的
为什么要怎么做,不进行这步,刚才写的Servlet是没办法调用实现功能的。
因为Servlet容器不知道如何将客户端的请求分发到该Servlet,因此无法将其用于处理客户端的请求。
HelloServlet
com.example.HelloServlet
HelloServlet
/hello
在浏览器输入对应的地址并回车
IDEA控制台显示刚才在Servlet方法中的输出信息
如果此时多次刷新该页面,控制台会多次输出 “Hello Servlet”
第一次HTTP请求:(也就是在浏览器地址栏输入回车对应的地址)
先在web.xml文件上找url-pattern是否有对应的,也就是“/hello”。如果有就会得到对应的servlet-name:HelloServlet。
同时,Tomcat维护了一个很大的HashMap
查询有这个servlet-name:HelloServlet的话,就会根据相应的servlet-class找到该类的全路径,找这个类在这个项目的哪里。
最后使用反射技术,将servlet实例化 -> init( )
并放到Tomcat维护的HashMap
在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。
第二次及以后的相同HTTP请求,Tomcat会执行以下步骤:
对于第二次及以后的相同HTTP请求,Tomcat会有以下的不同:
Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程。这个过程包括三个阶段:初始化(init)、服务(service)和销毁(destroy)。
总之,Servlet的生命周期是指从创建Servlet对象到销毁Servlet对象的过程,包括初始化、服务和销毁三个阶段。
Servlet容器是一个运行环境,它负责创建Servlet对象,并调用Servlet的生命周期方法。Servlet容器负责管理Servlet的生命周期,包括初始化、服务和销毁阶段。
在Servlet的生命周期中,Servlet容器会调用Servlet的init()方法进行初始化,然后根据客户端的请求调用service()方法来处理请求。当Servlet不再需要时,Servlet容器会调用destroy()方法来销毁Servlet对象。
生命周期 |
对应方法 |
执行时机 |
执行次数 |
构造对象 |
构造器 |
第一次请求或者容器启动 |
1 |
初始化 |
init() |
构造完毕后 |
1 |
处理服务 |
service(HttpServletRequest req,HttpServletResponse resp) |
每次请求 |
多次 |
销毁 |
destory() |
容器关闭 |
1 |
简单讲,Servlet的生命周期就是从创建Servlet对象开始,经过初始化、处理服务,最后到销毁Servlet对象的过程。在这个过程中,开发人员可以关注和实现业务逻辑,而Servlet容器会负责调用相应的生命周期方法。
当我们在开发Web应用程序时,通常需要处理两种主要的HTTP请求方法:Get和Post。
在Servlet开发中,我们通常会为这两种请求方法编写不同的处理逻辑。这是通过在Servlet中重写doGet和doPost方法来完成的。这两个方法是Java Servlet API定义的一部分,用于处理HTTP请求。
代码演示:
注册
用户注册
后端的Servlet就用刚刚的HelloServlet,方便,web.xml也不用配置
注意:前端页面提交的数据是请求对象,但在service方法中的ServletRequest中并没有对应的方法去获取这个请求对象,怎么办,查看ServletRequest的子类是否有
但是ServletRequest类的实现类中的HttpServletRequest含有这个方法
显示下面这个界面是在IDEA中同时按下Ctrl+Alt再鼠标指向ServletRequest
该操作可以查看该接口的子接口和实现子类
所以就有了如下代码:
控制台输出了这些
原因如下:
同理,如果前端中method的方法写成get,控制台也会有相应的输出
下面两个是抽象类,上面仨是接口,具体源码可以自己在IDEA中Ctrl+鼠标键详情查看
这里稍微“简单”介绍一下:
Servlet接口
源码及功能解释
接口及方法说明
GenericServlet 抽象类
源码
源码解释
HttpServlet 抽象类
源码
解释
实际开发中,在Servlet的继承体系下,很少直接实现Servlet接口去写代码,更多的是使用HttpServlet
自己写一个自定义的Servlet接口去继承HttpServlet抽象类
HelloServlet
快捷生成doget、dopost的方法
右键选择生成或则Alt+insert键
找到重写方法
在选择对应的doget、dopost方法即可
对应的web.xml文件配置
register.html
注意,这里是post方法
启动服务器,并输入相关地址
HttpServletRequest是Java Servlet API中的一个核心接口,它代表了来自客户端的HTTP请求。这个接口提供了许多方法,用于获取请求的各种属性和参数,如请求的URI、请求方法、请求头信息、请求参数等。
当一个HTTP请求到达Servlet容器(如Tomcat)时,容器会将请求报文转换成一个HttpServletRequest对象,并将这个对象作为参数传递给Servlet的service方法。这样,Servlet就可以通过HttpServletRequest对象获取到所有关于该请求的信息,从而进行处理。
API |
功能解释 |
StringBuffer getRequestURL(); |
获取客户端请求的url |
String getRequestURI(); |
获取客户端请求项目中的具体资源 |
int getServerPort(); |
获取客户端发送请求时的端口 |
int getLocalPort(); |
获取本应用在所在容器的端口 |
int getRemotePort(); |
获取客户端程序的端口 |
String getScheme(); |
获取请求协议 |
String getProtocol(); |
获取请求协议及版本号 |
String getMethod(); |
获取请求方式 |
API |
功能解释 |
String getHeader(String headerName); |
根据头名称获取请求头 |
Enumeration getHeaderNames(); |
获取所有的请求头名字 |
String getContentType(); |
获取content-type请求头 |
API |
功能解释 |
String getParameter(String parameterName); |
根据请求参数名获取请求单个参数值 |
String[] getParameterValues(String parameterName); |
根据请求参数名获取请求多个参数值数组 |
Enumeration getParameterNames(); |
获取所有请求参数名 |
Map |
获取所有请求参数的键值对集合 |
BufferedReader getReader() throws IOException; |
获取读取请求体的字符输入流 |
ServletInputStream getInputStream() throws IOException; |
获取读取请求体的字节输入流 |
int getContentLength(); |
获得请求体长度的字节数 |
API |
功能解释 |
String getServletPath(); |
获取请求的Servlet的映射路径 |
ServletContext getServletContext(); |
获取ServletContext对象 |
Cookie[] getCookies(); |
获取请求中的所有cookie |
HttpSession getSession(); |
获取Session对象 |
void setCharacterEncoding(String encoding) ; |
设置请求体字符集 |
HttpServletResponse是Java Servlet API中的另一个核心接口,它代表了服务器对客户端的响应。这个接口提供了一些方法,用于设置响应头信息、输出响应内容、设置响应状态等。
当Servlet的service方法处理完请求后,它可以通过HttpServletResponse对象将响应内容写入到响应报文中,并将响应报文发送给客户端。通过HttpServletResponse对象,Servlet可以设置响应的状态码、响应头信息、响应内容等。
API |
功能解释 |
void setStatus(int code); |
设置响应状态码 |
API |
功能解释 |
void setHeader(String headerName, String headerValue); |
设置/修改响应头键值对 |
void setContentType(String contentType); |
设置content-type响应头及响应字符集(设置MIME类型) |
API |
功能解释 |
PrintWriter getWriter() throws IOException; |
获得向响应体放入信息的字符输出流 |
ServletOutputStream getOutputStream() throws IOException; |
获得向响应体放入信息的字节输出流 |
void setContentLength(int length); |
设置响应体的字节长度,其实就是在设置content-length响应头 |
API |
功能解释 |
void sendError(int code, String message) throws IOException; |
向客户端响应错误信息的方法,需要指定响应码和响应信息 |
void addCookie(Cookie cookie); |
向响应体中增加cookie |
void setCharacterEncoding(String encoding); |
设置响应体字符集 |
MIME类型
文件拓展名 |
MIME类型 |
.html |
text/html |
.css |
text/css |
.js |
application/javascript |
.png /.jpeg/.jpg/... ... |
image/jpeg |
.mp3/.mpe/.mpeg/ ... ... |
audio/mpeg |
.mp4 |
video/mp4 |
.m1v/.m1v/.m2v/.mpe/... ... |
video/mpeg |
Servlet 容器提供了一个环境,让 Servlet 能够与 HTTP 请求和响应进行交互,并提供了诸如生命周期管理、安全性和并发处理等重要功能。
Servlet 实现了一个叫做 javax.servlet.Servlet 的接口,这个接口定义了一些方法,比如 init(), service(), doGet(), doPost(), 和 destroy()。这些方法使得 Servlet 能够处理 HTTP 请求,生成响应,以及在 Servlet 的生命周期中进行必要的操作。
为了运行 Servlet,你需要一个 Servlet 容器,比如 Tomcat 或者 Jetty。这些容器会加载 Servlet 类,管理它们的生命周期,并提供一个环境让它们能够与 HTTP 请求和响应进行交互。
ServletConfig是Java Servlet API中的一个接口,它提供了Servlet的初始化配置参数。每个Servlet实例都有一个自己独立且唯一的ServletConfig对象。
当Web应用程序被部署并启动时,Servlet容器会实例化每个Servlet,并为每个Servlet实例创建一个ServletConfig对象。这个ServletConfig对象包含了在Web应用程序的部署描述符(web.xml文件)中为该Servlet指定的初始化参数。
这些初始化参数可以在Servlet的初始化方法(init())中被访问和利用。在Servlet的生命周期中,ServletConfig对象作为属性被传递给Servlet的init方法。这样,Servlet就可以在初始化时获取到它所需要的配置信息,从而进行相应的初始化操作。
举个简单的例子就是:
ServletConfig可以类比为一家餐厅的菜单。当顾客进入餐厅时,他们会看到菜单,并根据菜单选择他们想吃的菜品。菜单提供了关于菜品的信息,如菜名、价格、食材等。同样地,ServletConfig提供了关于Servlet的信息,如Servlet的名称、初始化参数等。
在Web应用程序中,Servlet扮演着处理请求的角色,就像餐厅中的服务员一样。当一个请求到达Servlet时,Servlet会根据ServletConfig中的信息来处理请求。就像服务员根据菜单上的信息为顾客提供服务一样。
ServletConfig 类能干什么
ServletConfig是一个接口,定义了如下API:
package jakarta.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration getInitParameterNames();
}
方法名 |
作用 |
getServletName() |
获取 |
getServletContext() |
获取ServletContext对象 |
getInitParameter() |
获取配置Servlet时设置的『初始化参数』,根据名字获取值 |
getInitParameterNames() |
获取所有初始化参数名组成的Enumeration对象 |
ServletConfig怎么用,测试代码如下
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
// 根据参数名获取单个参数
String value = servletConfig.getInitParameter("param1");
System.out.println("param1:"+value);
// 获取所有参数名
Enumeration parameterNames = servletConfig.getInitParameterNames();
// 迭代并获取参数名
while (parameterNames.hasMoreElements()) {
String paramaterName = parameterNames.nextElement();
System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));
}
}
}
public class ServletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
// 根据参数名获取单个参数
String value = servletConfig.getInitParameter("param1");
System.out.println("param1:"+value);
// 获取所有参数名
Enumeration parameterNames = servletConfig.getInitParameterNames();
// 迭代并获取参数名
while (parameterNames.hasMoreElements()) {
String paramaterName = parameterNames.nextElement();
System.out.println(paramaterName+":"+servletConfig.getInitParameter(paramaterName));
}
}
}
ServletA
com.atguigu.servlet.ServletA
param1
value1
param2
value2
ServletB
com.atguigu.servlet.ServletB
param3
value3
param4
value4
ServletA
/servletA
ServletB
/servletB
ServletContext是Java Servlet API中的一个接口,它代表了Web应用程序的上下文,也称为应用域对象。在Web应用程序中,每个应用程序都会有一个唯一的ServletContext对象。这个对象由Servlet容器在应用程序启动时创建,并在整个应用程序的生命周期内保持存在。
ServletContext对象是所有Servlet共享的,这意味着在同一个Web应用程序中,所有的Servlet都可以访问和修改同一个ServletContext对象。这为Servlet之间的数据共享和协作提供了方便的机制。
ServletContext可以为所有的Servlet提供初始配置参数。这些参数可以在Web应用程序的部署描述符(web.xml文件)中定义。当Web应用程序启动时,容器会将这些参数传递给每个Servlet,作为它们的初始化参数。这样,Servlet就可以在初始化时获取到它们所需要的配置信息。
简单来说,ServletContext就像是一个大的共享容器,它存储了Web应用程序的配置信息,并且可以被所有的Servlet访问和修改。
ServletContext怎么用
paramA
valueA
paramB
valueB
package com.atguigu.servlet;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
public class ServletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从ServletContext中获取为所有的Servlet准备的参数
ServletContext servletContext = this.getServletContext();
String valueA = servletContext.getInitParameter("paramA");
System.out.println("paramA:"+valueA);
// 获取所有参数名
Enumeration initParameterNames = servletContext.getInitParameterNames();
// 迭代并获取参数名
while (initParameterNames.hasMoreElements()) {
String paramaterName = initParameterNames.nextElement();
System.out.println(paramaterName+":"+servletContext.getInitParameter(paramaterName));
}
}
}
@WebServlet注解是Java Servlet API的一部分,用于在Java Servlet应用程序中定义Servlet。它允许开发人员将Servlet类映射到特定的URL路径或Servlet名称,以便处理来自客户端的请求。
通过使用@WebServlet注解,开发人员可以将Servlet类与特定的URL模式关联起来,以便当客户端发出请求时,Servlet可以拦截和处理这些请求。这个注解可以用于将Servlet映射到根路径或特定的子路径,以及指定Servlet的初始化参数和其他配置选项。
MyServlet.java
不在web.xml进行配置
前端测试代码,action设置为注解的urlPatterns
启动服务器
从上面也看出来了,@WebServlet注解确实可以简化Servlet的映射设置过程。通过使用@WebServlet注解,开发人员可以更快速地将Servlet类与特定的URL路径进行关联,而无需在Web.xml文件中手动配置。这有助于减少开发时间和代码复杂度,特别是在小型项目中。然而,需要注意的是,@WebServlet注解是Java Servlet API的一部分,需要在支持Servlet规范的容器中运行。
annotation就是注解的意思
package javax.servlet.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Documented;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
/**
* The name of the servlet
*
* @return the name of the servlet
*/
String name() default "";
/**
* The URL patterns of the servlet
*
* @return the URL patterns of the servlet
*/
String[] value() default {};
/**
* The URL patterns of the servlet
*
* @return the URL patterns of the servlet
*/
String[] urlPatterns() default {};
/**
* The load-on-startup order of the servlet
*
* @return the load-on-startup order of the servlet
*/
int loadOnStartup() default -1;
/**
* The init parameters of the servlet
*
* @return the init parameters of the servlet
*/
WebInitParam [] initParams() default {};
/**
* Declares whether the servlet supports asynchronous operation mode.
*
* @return {@code true} if the servlet supports asynchronous operation mode
* @see javax.servlet.ServletRequest#startAsync
* @see javax.servlet.ServletRequest#startAsync(ServletRequest,
* ServletResponse)
*/
boolean asyncSupported() default false;
/**
* The small-icon of the servlet
*
* @return the small-icon of the servlet
*/
String smallIcon() default "";
/**
* The large-icon of the servlet
*
* @return the large-icon of the servlet
*/
String largeIcon() default "";
/**
* The description of the servlet
*
* @return the description of the servlet
*/
String description() default "";
/**
* The display name of the servlet
*
* @return the display name of the servlet
*/
String displayName() default "";
}
上面是从IDEA上面扒下来的WebServlet.java的源码,简单概括就是
它是用来定义一个servlet的配置信息的:
name()
:返回servlet的名字,默认为空字符串。value()
和urlPatterns()
:这两个方法是等价的,都是用来设置URL模式的。当请求匹配这些模式时,该servlet将被调用。loadOnStartup()
:设置servlet在应用启动时加载的顺序。默认值为-1,表示容器可自由选择加载时机。initParams()
:设置servlet的初始化参数。asyncSupported()
:声明servlet是否支持异步操作模式。如果为true,那么servlet可以使用startAsync()
方法进行异步处理。smallIcon()
和largeIcon()
:分别设置servlet的小图标和大图标。默认都为空字符串。description()
:设置servlet的描述信息。默认为空字符串。displayName()
:设置servlet的显示名。默认为空字符串。上面的例子就用到了name和urlPatterns,设定servlet的名字和它的URL地址
先在web.xml文件上找url-pattern是否有对应的,也就是“/hello”。如果有就会得到对应的servlet-name:HelloServlet。
同时,Tomcat维护了一个很大的HashMap
查询有这个servlet-name:HelloServlet的话,就会根据相应的servlet-class找到该类的全路径,找这个类在这个项目的哪里。
最后使用反射技术,将servlet实例化 -> init( )
并放到Tomcat维护的HashMap
在service()方法中,可以根据请求的类型(GET、POST等)和URL路径来确定 具体要执行的方法。
当Tomcat找到匹配的URL Pattern时,它会查看Servlet类上是否有@WebServlet注解。注解中通常包含一个urlPatterns属性,该属性指定了该Servlet类应该映射到的URL路径。例如,@WebServlet(urlPatterns = "/hello")。
如果存在@WebServlet注解,Tomcat会根据注解中的urlPatterns属性将该Servlet类映射到相应的URL路径。然后,Tomcat会使用反射技术实例化该Servlet类,并调用它的init()方法进行初始化。
此时,web.xml文件不进行配置也是可以的
与之前不同的是,Tomcat不再维护一个HashMap
总之,使用@WebServlet注解简化了Servlet的配置过程,并且允许动态地创建和销毁Servlet实例。然而,需要注意的是,使用注解可能会增加每次请求的处理开销,因为每次都需要动态地创建和销毁Servlet实例。在需要高性能或高并发的场景下,可能需要权衡使用注解和预创建Servlet实例的利弊。
请求转发和响应重定向是Web应用程序中常用的两种页面跳转方法。以下是关于这两种方法的详细解释:
请求转发(Request Forwarding):
请求转发是一种由Servlet实现的请求转发机制。当一个Servlet接收到一个HTTP请求后,它可以通过调用RequestDispatcher接口的forward()方法将请求转发给另一个Servlet或JSP页面。这个过程是服务器内部的操作,客户端并不知道。请求转发的优点是实现简单,性能较好。
举个例子,张三向李四借钱,但李四没有钱。于是李四向王五借钱,并告诉王五将钱借给张三。这个过程中,张三只向李四请求借钱,但实际上钱是从王五那里借来的。
响应重定向(Response Redirection):
响应重定向是另一种页面跳转方法,它通过在客户端进行操作来实现。当一个Servlet接收到一个HTTP请求后,它可以通过调用HttpServletResponse对象的sendRedirect()方法将客户端重定向到另一个页面。重定向是通过HTTP协议的3xx响应码实现的,客户端会收到一个新的URL,并重新向这个URL发送请求。
在举个例子,张三向李四借钱,但李四没有钱。李四告诉张三去找王五借钱。于是张三自己去找王五借钱,这个过程中,张三的请求被重定向到了王五那里。
总结一下,请求转发和响应重定向的区别:
代码演示:
代码演示: