Servlet小结
视频链接:黑马servlet视频全套视频教程,快速入门servlet原理+servlet实战
什么是Servlet?
菜鸟教程:Java Servlet
servlet: server applet
Servlet是一个运行在Web服务器(如Tomcat、Jetty)或应用服务器(如WebLogic、WildFly)中的Java类,用于扩展服务器功能,通过请求-响应模型与客户端交互(如浏览器)。
- 它实现了javax.servlet.Servlet接口或继承HttpServlet类,处理HTTP请求(GET、POST等)并生成动态响应(HTML、JSON、图片等)。
- 与JSP(JavaServer Pages)结合使用时,Servlet负责业务逻辑处理,JSP负责页面渲染。
Servlet其实就是一个接口,它定义了Java类被浏览器访问到(tomcat识别到)的规则,只要实现了这个接口的Java类就是一个Servlet
快速入门
1.创建项目

2.编写Servlet类
2.1 实现Servlet接口
1
| public class ServletDemo1 implements Servlet
|
2.2 继承HttpServlet类
1
| public class ServletDemo2 extends HttpServlet
|
其实这个底层也是实现Servlet接口

3.实现Servlet或重写HttpServlet里面的方法
servlet里面最重要的方法:service方法
HttpServlet里面最重要的方法: doGet doPost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface Servlet { void init(ServletConfig var1) throws ServletException; ServletConfig getServletConfig(); void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; String getServletInfo(); void destroy(); }
|

4.配置Servlet
4.1 基于web.xml配置
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>servlet的名字</servlet-name> <servlet-class>servlet的全类名</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet的名字</servlet-name> <url-pattern>servlet的请求路径</url-pattern> </servlet-mapping>
|
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" version="5.0"> <servlet> <servlet-name>servlet1</servlet-name> <servlet-class>com.itcast.servlet.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet1</servlet-name> <url-pattern>/servlet1</url-pattern> </servlet-mapping>
<servlet> <servlet-name>servlet2</servlet-name> <servlet-class>com.itcast.servlet.ServletDemo2</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet2</servlet-name> <url-pattern>/servlet2</url-pattern> </servlet-mapping>
</web-app>
|
4.2 基于@WebServlet注解配置
1 2 3 4 5 6 7 8 9 10 11 12
| @WebServlet("/servlet1") public class Servlet1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet1 doGet"); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet1 doPost"); } }
|
@WebServlet
注解会自动把当前类注册为Servlet并且请求路径为/servlet1
相当于
1 2 3 4 5 6 7 8 9
| <servlet> <servlet-name>servlet1</servlet-name> <servlet-class>com.itcast.servlet.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet1</servlet-name> <url-pattern>/servlet1</url-pattern> </servlet-mapping>
|
执行流程
1.客户端请求
浏览器输入URL http://localhost:8080/servlet1,发送HTTP请求。
2.Tomcat接收请求
Connector组件(如 Coyote)监听端口 8080,接收请求。
解析请求:提取URL路径 /servlet1,并封装为HttpServletRequest对象。
3.URL到Servlet的映射
Tomcat在启动时已加载所有Servlet配置(包括web.xml和@WebServlet注解),建立URL到Servlet类的映射表。
匹配路径:Tomcat检查请求的URL /servlet1
是否与已注册的Servlet路径匹配。
如果匹配,找到对应的Servlet类(如 ServletDemo1)。
4.Servlet类加载与实例化(单次行为)
4.1 类加载:
Tomcat使用Web应用类加载器加载Servlet类的字节码(如 ServletDemo1.class)。
类路径通常为 WEB-INF/classes 或 WEB-INF/lib 中的JAR包。
4.2 实例化:
Tomcat通过反射机制创建Servlet类的实例(ServletDemo1 instance = new ServletDemo1())。
4.3 初始化:
调用Servlet的init()方法,完成初始化(如加载配置、数据库连接等)。
5.处理请求
调用service()方法:
Tomcat根据请求方法(如GET/POST),调用Servlet的service()方法。
service()方法会进一步分发到doGet()或doPost()等具体方法。
6.响应客户端
构建响应:Servlet通过HttpServletResponse对象生成响应内容(如HTML、JSON等)。
返回结果:Tomcat通过Connector将响应结果返回给浏览器。
Http协议
特点
- 无状态(Stateless)
定义:协议本身不保存请求与响应之间的通信状态,每次请求都是独立的。
意义:简化了服务器的实现,提高了可扩展性,但需要客户端在每次请求中携带必要的状态信息(如通过Cookie、Session等)。
- 无连接(Connectionless)
定义:客户端与服务器在每次请求完成后断开连接(HTTP/1.0默认),但HTTP/1.1引入了持久连接(Keep-Alive)。
早期版本:HTTP/0.9和HTTP/1.0每次请求均建立新连接,效率低;HTTP/1.1通过持久连接复用TCP连接,减少开销。
- 面向对象(Object-Oriented)
定义:通过统一资源标识符(URI)定位互联网上的资源(如HTML、图片、视频等),支持对资源的增删改查操作。
方法:GET(获取资源)、POST(提交数据)、PUT(更新资源)、DELETE(删除资源)等。
- 短连接(Short-lived)
早期行为:HTTP/0.9和1.0采用短连接,请求完成后立即断开,导致频繁的TCP握手开销。
改进:HTTP/1.1引入持久连接(Keep-Alive),允许复用TCP连接,提升性能。
- 可缓存(Cachable)
机制:通过Cache-Control、ETag、Last-Modified等头部字段,客户端或代理服务器可缓存响应内容,减少重复请求。
优势:降低服务器负载,加快响应速度。
- 灵活扩展
头部信息:通过请求头和响应头(如Content-Type、User-Agent)传递元数据,支持功能扩展。
方法扩展:HTTP/1.1新增PUT、DELETE等方法,HTTP/2支持服务器推送(Server Push)。
请求消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| POST /login HTTP/1.1 Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept-Encoding: gzip, deflate, br, zstd Accept-Language: zh-CN,zh;q=0.9 Cache-Control: max-age=0 Connection: keep-alive Content-Length: 27 Content-Type: application/x-www-form-urlencoded Cookie: JSESSIONID=ED583FB162E9D2E951D951B649C4DEBA Host: localhost:8080 Origin: http://localhost:8080 Referer: http://localhost:8080/ Sec-Fetch-Dest: document Sec-Fetch-Mode: navigate Sec-Fetch-Site: same-origin Sec-Fetch-User: ?1 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 sec-ch-ua: "Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows"
username=admin&password=123
|
1.请求行
- 方法(Method):POST(向服务器提交数据,通常用于表单提交)。
- 路径(URI):
/login
(请求的目标资源路径)。
- 协议版本(Protocol):HTTP/1.1(使用的HTTP协议版本)。
2.请求头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*
|
1.User-Agent: 浏览器的版本信息
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
2.Refer: 告诉服务器,请求来源页面
Referer: http://localhost:8080/
3.Cookie:客户端携带的Cookie
Cookie: JSESSIONID=ED583FB162E9D2E951D951B649C4DEBA
4.Origin:请求的来源域
Origin: http://localhost:8080
5.Accept:浏览器可接受的响应内容
1
| Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*
|
3.请求空行
请求头结束后必须有一个空行(即两个换行符 \r\n\r\n),表示请求头结束,请求体开始。
4.请求体
1
| username=admin&password=123
|
ServletRequest 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public interface ServletRequest { Object getAttribute(String var1); Enumeration<String> getAttributeNames(); String getCharacterEncoding(); void setCharacterEncoding(String var1) throws UnsupportedEncodingException; int getContentLength(); long getContentLengthLong(); String getContentType(); ServletInputStream getInputStream() throws IOException; String getParameter(String var1); Enumeration<String> getParameterNames(); String[] getParameterValues(String var1); Map<String, String[]> getParameterMap(); String getProtocol(); String getScheme(); String getServerName(); int getServerPort(); BufferedReader getReader() throws IOException; String getRemoteAddr(); String getRemoteHost(); void setAttribute(String var1, Object var2); void removeAttribute(String var1); Locale getLocale(); Enumeration<Locale> getLocales(); boolean isSecure(); RequestDispatcher getRequestDispatcher(String var1);
}
|
ServletResponse 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public interface ServletResponse {
String getCharacterEncoding();
String getContentType();
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setBufferSize(int var1);
int getBufferSize();
void flushBuffer() throws IOException;
void resetBuffer();
boolean isCommitted();
void reset();
void setLocale(Locale var1);
Locale getLocale(); }
|
HttpRequest 的核心方法
1. 请求参数获取
getParameter(String name)
获取指定名称的请求参数的第一个值(如表单提交或 URL 参数)。
示例:String username = request.getParameter("username");
getParameterValues(String name)
获取指定名称的请求参数的所有值(如多选框的多个值)。
示例:String[] hobbies = request.getParameterValues("hobby");
getParameterMap()
返回所有请求参数的 Map
(键为参数名,值为参数值数组)。
示例:Map<String, String[]> paramMap = request.getParameterMap();
2. 请求头与元数据
getMethod()
获取请求方法(如 GET
、POST
)。
示例:String method = request.getMethod();
getHeader(String name)
获取指定名称的请求头值(如 User-Agent
、Content-Type
)。
示例:String userAgent = request.getHeader("User-Agent");
getHeaders(String name)
获取指定名称的所有请求头值(若存在多个值)。
示例:Enumeration<String> acceptTypes = request.getHeaders("Accept");
3. 请求路径与来源
getRequestURI()
获取请求的资源路径(不包含主机名和端口)。
示例:/api/user
(返回路径部分)。
getRequestURL()
获取完整的请求 URL(包含协议、主机和端口)。
示例:http://localhost:8080/api/user
。
getRemoteAddr()
获取客户端的 IP 地址。
示例:String clientIP = request.getRemoteAddr();
4. 会话与 Cookie
5. 其他重要方法
HttpResponse 的核心方法
1. 响应头与状态码设置
setStatus(int sc)
或 sendError(int sc)
设置 HTTP 状态码(如 200
成功、404
未找到、500
服务器错误)。
示例:response.setStatus(HttpServletResponse.SC_OK);
setHeader(String name, String value)
设置指定名称的响应头(如 Content-Type
、Cache-Control
)。
示例:response.setHeader("Content-Type", "application/json");
2. 响应内容输出
3. 重定向与会话管理
4. 缓冲区与提交控制
5. 其他重要方法
setContentType(String type)
设置响应的 MIME 类型(如 text/html
、application/json
)。
示例:response.setContentType("application/json");
setCharacterEncoding(String charset)
设置响应的字符编码(如 UTF-8
)。
示例:response.setCharacterEncoding("UTF-8");
关键注意事项
getInputStream()
和 getWriter()
的冲突
- 在
HttpServletRequest
中,二者不能同时使用,否则抛出 IllegalStateException
。
响应提交后的限制
- 一旦响应提交(通过
flushBuffer()
或客户端接收),无法修改响应头或状态码。
字符编码设置时机
- 应在调用
getWriter()
或 getOutputStream()
之前设置字符编码。
会话与 Cookie 的安全性
- 敏感数据(如密码)应避免通过 Cookie 传输,需使用
HttpOnly
和 Secure
标志。
登录案例
项目结构:

index.jsp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <%-- Created by IntelliJ IDEA. User: xuan Date: 2025/4/24 Time: 20:05 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="/login" method="post"> 用户名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"/> </form> </body> </html>
|
pom.xml文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId> <artifactId>login-test</artifactId> <version>1.0-SNAPSHOT</version> <name>login-test</name> <packaging>war</packaging>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <junit.version>5.9.2</junit.version> </properties>
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency>
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.6</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency>
</dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.2</version> </plugin> </plugins> </build> </project>
|

1.创建数据库,创建user表
1 2 3 4 5 6 7 8 9
| create database servlet;
create table user ( id int auto_increment primary key, username varchar(50) not null comment '用户名', password varchar(12) not null );
|
2.编写数据库配置文件
1 2 3 4 5 6 7
| driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/servlet username=root password=root initialSize=5 maxActive=20 maxWait=60000
|
3.编写数据库工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.itcast.utils;
import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.util.Properties;
public class JDBCUtils { private static DataSource dataSource;
static { try { Properties properties = new Properties(); InputStream resource = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); properties.load(resource); dataSource = DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); System.err.println("数据库加载出错"); } } public static DataSource getDataSource(){ return dataSource; } public Connection getConnection() throws Exception{ return dataSource.getConnection(); } }
|
4.编写User实体类,封装用户数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.itcast.dao;
public class User { private String username; private String password;
public User() { }
public User(String username, String password) { this.username = username; this.password = password; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; } }
|
5.编写LoginDao.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.itcast.domain;
import com.itcast.dao.User; import com.itcast.utils.JDBCUtils; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate;
public class UserDao { private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource());
public User login(User loginUser) { try { String sql = "select * from user where username = ? and password = ?"; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), loginUser.getUsername(), loginUser.getPassword()); return user; } catch (DataAccessException e) { System.out.println("用户"+loginUser.getUsername()+"登录失败"); return null; } } }
|
6.编写servlet
LoginServlet.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.itcast.servlet;
import com.itcast.dao.User; import com.itcast.domain.UserDao; import org.apache.commons.beanutils.BeanUtils;
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; import java.lang.reflect.InvocationTargetException; import java.util.Map;
@WebServlet("/login") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); Map<String, String[]> map = req.getParameterMap(); User userDTO = new User(); try { BeanUtils.populate(userDTO, map); } catch (Exception e) { e.printStackTrace(); System.out.println("复制失败"); } UserDao userDao = new UserDao(); User user = userDao.login(userDTO); if (user == null) { req.setAttribute("msg", "用户名或密码错误"); req.getRequestDispatcher("/fail").forward(req, resp); }else { req.getRequestDispatcher("/success").forward(req, resp); } } }
|
FailServlet.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com.itcast.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("/fail") public class FailServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write("登录失败"); } }
|
SuccessServlet.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.itcast.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("/success") public class SuccessServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); String username = req.getParameter("username"); resp.getWriter().write(username + "登录成功"); } }
|