Servlet&HTTP&Request
# Servlet
# 1. 概念
Servlet 是运行在服务器端的小程序(Java 编写),主要用于接收客户端的请求、处理请求并返回响应,是 Java Web 的核心技术之一。它运行在 Web 容器(如 Tomcat)中。
# 2. 步骤
- 创建一个类实现 javax.servlet.Servlet 接口(或继承 HttpServlet)。
- 重写核心方法(如 doGet、doPost)。
- 在 web.xml 中配置 Servlet,或使用注解 @WebServlet。
- 部署到 Servlet 容器中(如 Tomcat)。
- 浏览器访问对应的 URL,触发 Servlet 处理请求。
# 3. 执行原理
简要流程如下:
启动时加载 Servlet(可通过配置或注解控制是否懒加载)。
当客户端发送请求:
- Web 容器接收到请求。
- 容器根据 URL 映射找到对应的 Servlet。
- 若是第一次访问,容器先创建 Servlet 实例并调用 init() 方法进行初始化。
- 接着调用 service() 方法处理请求。
- 对于 HttpServlet,会进一步分发到 doGet() 或 doPost()。
- 最终生成响应,返回客户端。
# 4. 生命周期
Servlet 的完整生命周期包括以下三个阶段:
- 初始化(init)
- 容器创建 Servlet 实例后,调用 init() 方法,仅调用一次。
- 可做资源初始化等操作。
- 服务(service)
- 每次请求都会调用一次 service() 方法。
- HttpServlet 会根据请求类型调用 doGet()、doPost() 等。
- 销毁(destroy)
- 当容器关闭或 Servlet 被卸载时调用 destroy() 方法,只调用一次。
- 用于资源释放,如关闭数据库连接、线程池等。
# 5. Servlet 3.0 注解配置
使用 @WebServlet 注解可以代替 web.xml 配置。
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "HelloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
resp.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = resp.getWriter()) {
out.println("\<h1\>Hello Servlet\</h1\>");
} catch (IOException e) {
e.printStackTrace();
}
}
}
# 6. Servlet 的体系结构
Servlet 接口和相关类的继承结构如下:
javax.servlet.Servlet (接口)
├── javax.servlet.GenericServlet (抽象类)
│ └── javax.servlet.http.HttpServlet (抽象类)
│ └── 自定义 Servlet(通常继承 HttpServlet)
- 说明:
- Servlet(接口):定义了所有 Servlet 必须实现的方法,包括 init()、service()、destroy()、getServletConfig()、getServletInfo()。
- GenericServlet(抽象类):简化了开发,只需实现 service() 方法,适用于协议无关的 Servlet。
- HttpServlet(抽象类):是最常用的 Servlet 基类,已经实现了 service() 方法并根据请求类型调用 doGet()、doPost() 等。
开发时我们一般直接继承 HttpServlet,重写 doGet() 或 doPost() 方法即可。
# 7. Servlet 相关配置
- urlPattern:Servlet 访问路径
- 一个 Servlet 可以定义多个访问路径:
@WebServlet({"/d4","/dd4","/ddd4"})
- 路径定义规则:
- /xxx:路径匹配
- /xxx/xxx:多层路径,目录结构
- *.do:扩展名匹配
# HTTP 协议
# 概念
HTTP(Hyper Text Transfer Protocol 超文本传输协议)
- 定义了客户端与服务器通信时的数据格式
- 特点:
- 基于 TCP/IP 的高级协议
- 默认端口号:80
- 基于请求/响应模型:一次请求对应一次响应
- 无状态:每次请求之间相互独立,不能交互数据
- 历史版本:
- 1.0:每次请求响应都会建立新的连接
- 1.1:复用连接
# 请求消息数据格式
- 请求行
GET /login.html HTTP/1.1
- 请求方式:
- HTTP 协议有 7 种请求方式,常用:GET 和 POST
- GET:
- 参数在请求行 url 后
- URL 长度有限制
- 安全性较低
- POST:
- 参数在请求体中
- URL 长度无限制
- 安全性较高
- GET:
- HTTP 协议有 7 种请求方式,常用:GET 和 POST
- 请求头
请求头名称: 请求头值
- 常见请求头:
- User-Agent:浏览器告诉服务器当前的浏览器版本信息
- Referer:请求来源地址(如:http://localhost/login.html (opens new window))
- 作用:
- 防盗链
- 统计来源
- 作用:
- 请求空行
- 分割请求头和请求体
- 请求体(POST 数据)
username=zhangsan
完整请求样例如下:
POST /login.html HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
username=zhangsan
# Request
# 1. request 和 response 对象原理
- 由服务器创建,开发者使用
- request 获取请求数据,response 设置响应数据
# 2. request 对象继承结构
ServletRequest -- 接口
└── HttpServletRequest -- 接口
└── RequestFacade -- 实现类(Tomcat)
# 3. request 功能
# 获取请求消息数据
- 请求行:
String getMethod(); // GET
String getContextPath(); // /day14
String getServletPath(); // /demo1
String getQueryString(); // name=zhangsan
String getRequestURI(); // /day14/demo1
StringBuffer getRequestURL(); // http://localhost/day14/demo1
String getProtocol(); // HTTP/1.1
String getRemoteAddr(); // 客户端 IP 地址
- 请求头:
String getHeader(String name);
Enumeration<String> getHeaderNames();
- 请求体(POST):
BufferedReader getReader(); // 字符输入流
ServletInputStream getInputStream();// 字节输入流
# 获取请求参数通用方法
适用于 GET 和 POST:
String getParameter(String name);
String[] getParameterValues(String name);
Enumeration<String> getParameterNames();
Map<String,String[]> getParameterMap();
- POST 中文乱码解决:
request.setCharacterEncoding("utf-8");
# 请求转发
- 步骤:
RequestDispatcher rd = request.getRequestDispatcher("/xxx");
rd.forward(request, response);
特点:
- 地址栏不变
- 只能转发服务器内部资源
- 属于一次请求
# request 域对象(共享数据)
request.setAttribute("name", obj);
Object obj = request.getAttribute("name");
request.removeAttribute("name");
# 获取 ServletContext
ServletContext context = request.getServletContext();
# 案例:用户登录
# 需求
- 编写 login.html 页面,包含 username 和 password 输入框
- 使用 Druid 连接池,操作 day14 数据库中的 user 表
- 使用 JdbcTemplate 封装 JDBC
- 登录成功跳转到 SuccessServlet,展示欢迎信息
- 登录失败跳转到 FailServlet,提示错误信息
# 数据库建表语句
CREATE DATABASE day14;
USE day14;
CREATE TABLE USER (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32) UNIQUE NOT NULL,
PASSWORD VARCHAR(32) NOT NULL
);
# 实体类 User
public class User {
private int id;
private String username;
private String password;
// Getters / Setters / toString()
}
# JDBC 工具类 JDBCUtils
public class JDBCUtils {
private static DataSource ds;
static {
try {
Properties pro = new Properties();
InputStream is = JDBCUtils.class.getClassLoader()
.getResourceAsStream("druid.properties");
pro.load(is);
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource() {
return ds;
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
}
# DAO 类:UserDao
public class UserDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
public User login(User loginUser) {
try {
String sql = "select * from user where username = ? and password = ?";
return template.queryForObject(sql,
new BeanPropertyRowMapper<>(User.class),
loginUser.getUsername(), loginUser.getPassword());
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}
}
# LoginServlet
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
UserDao dao = new UserDao();
User user = dao.login(loginUser);
if (user == null) {
req.getRequestDispatcher("/failServlet").forward(req, resp);
} else {
req.setAttribute("user", user);
req.getRequestDispatcher("/successServlet").forward(req, resp);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req, resp);
}
}
# 成功与失败页面 Servlet
SuccessServlet
@WebServlet("/successServlet")
public class SuccessServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User user = (User) request.getAttribute("user");
if (user != null) {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("登录成功!" + user.getUsername() + ",欢迎您");
}
}
}
FailServlet
@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("登录失败,用户名或密码错误");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
# login.html 表单提交路径
- 表单 action:
action="${pageContext.request.contextPath}/loginServlet"
# BeanUtils 工具类
用于简化 JavaBean 数据封装
- JavaBean 要求:
- public 修饰类
- 空参构造器
- 成员变量为 private
- 提供 getter / setter
- 方法:
BeanUtils.setProperty(obj, "name", value);
BeanUtils.getProperty(obj, "name");
BeanUtils.populate(obj, map); // map 的键值封装进 JavaBean
上次更新: 2025/07/23, 01:37:33