一、Servlet核心技术:路由、生命周期与请求响应处理
Servlet作为JavaEE的核心组件,是运行在Web服务器上的服务端程序,承担着客户端HTTP请求与服务端业务/数据库交互的中间层角色,能够实现请求接收、业务处理、动态网页生成等核心功能,是Web开发的基础核心。
1. Servlet的创建与路由配置
Servlet的使用核心在于类的实现 与路由映射 ,路由映射是客户端请求能找到对应Servlet的关键,主流有web.xml配置 和注解配置两种方式,以下是完整实现步骤:
- 自定义Servlet类,继承
javax.servlet.http.HttpServlet,重写业务所需方法(doGet/doPost); - 配置路由映射,实现客户端请求路径与Servlet的绑定;
- 部署项目,通过浏览器访问配置的路由路径触发Servlet执行。
(1)web.xml 传统路由配置
通过配置文件实现路由解耦,适用于多路由统一管理场景,核心是<servlet>注册类、<servlet-mapping>映射路径:
xml
<!-- 注册Servlet -->
<servlet>
<servlet-name>demoServlet</servlet-name>
<servlet-class>com.demo.servlet.DemoServlet</servlet-class>
</servlet>
<!-- 映射访问路由 -->
<servlet-mapping>
<servlet-name>demoServlet</servlet-name>
<url-pattern>/demo</url-pattern>
</servlet-mapping>
url-pattern配置规则:
/:代表当前Web应用根目录;- 精确匹配:如
/demo,仅匹配该路径请求; - 通配匹配:如
/*,匹配当前应用下所有请求。
(2)@WebServlet 注解路由配置
注解方式简化配置,直接在Servlet类上标注,无需修改web.xml,开发效率更高,是主流开发方式:
java
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
// 路由路径直接通过注解指定,支持多个路径映射
@WebServlet("/demo/*")
public class DemoServlet extends HttpServlet {
// 重写doGet/doPost处理业务
}
2. Servlet完整生命周期
Servlet的生命周期由Web容器(如Tomcat)全程管理,从实例化 到销毁 共4个核心阶段,其中初始化 和销毁 仅执行一次,服务阶段随每次请求执行,是性能优化的核心关注点:
- 构造方法执行(实例化):第一次请求Servlet或服务器启动时执行,仅创建一个实例(单例),保证资源复用;
- init()方法(初始化):实例创建后立即执行,用于初始化Servlet资源(如加载配置、创建连接池),仅执行一次;
- service()方法(服务):每次客户端请求都会执行,容器会根据请求方式(GET/POST)自动调用doGet()或doPost()方法,是业务处理的核心;
- destroy()方法(销毁):服务器关闭或Servlet被移除时执行,用于释放资源(如关闭数据库连接、销毁线程),仅执行一次。
核心方法重写示例:
java
public class DemoServlet extends HttpServlet {
// 构造方法
public DemoServlet() {
System.out.println("Servlet实例化");
}
// 初始化方法
@Override
public void init() {
System.out.println("Servlet初始化");
}
// 处理GET请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("处理GET请求");
}
// 处理POST请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
doGet(req, resp); // 统一GET/POST处理逻辑
}
// 销毁方法
@Override
public void destroy() {
System.out.println("Servlet销毁");
}
}
3. HTTP请求与响应的处理
Web容器会为每次HTTP请求创建HttpServletRequest(请求对象)和HttpServletResponse(响应对象),分别封装请求信息和响应数据,是Servlet与客户端交互的核心API。
(1)HttpServletRequest 请求处理
HttpServletRequest是ServletRequest的HTTP协议专用子接口,用于获取客户端请求的所有信息,核心方法:
- 获取请求参数 :
String getParameter(String name):获取单个参数值(如表单、URL传参);String[] getParameterValues(String name):获取多值参数(如复选框);
- 解决中文乱码 :
req.setCharacterEncoding("UTF-8"); - 其他常用 :
getMethod()获取请求方式、getRemoteAddr()获取客户端IP。
(2)HttpServletResponse 响应处理
HttpServletResponse是ServletResponse的HTTP协议专用子接口,用于向客户端返回响应数据,核心方法:
- 解决响应乱码 :
resp.setContentType("text/html;charset=UTF-8")(同时设置服务端编码和浏览器解析编码,推荐); - 获取输出流 :
PrintWriter out = resp.getWriter(),通过out.println()向浏览器输出文本/HTML数据; - 状态码与重定向 :
resp.sendRedirect("/index")(重定向,状态码302)、resp.setStatus(200)(设置响应状态码)。
请求响应完整示例:
java
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 解决请求乱码
req.setCharacterEncoding("UTF-8");
// 解决响应乱码
resp.setContentType("text/html;charset=UTF-8");
// 获取请求参数
String username = req.getParameter("username");
String[] hobbies = req.getParameterValues("hobby");
// 获取输出流,向浏览器回显数据
PrintWriter out = resp.getWriter();
out.println("用户名:" + username);
out.println("爱好:" + Arrays.toString(hobbies));
}
二、数据库操作核心:JDBC原生开发
JDBC(Java Database Connectivity)是Java提供的数据库访问统一API规范,定义了连接数据库、执行SQL、处理结果的标准接口,由各数据库厂商提供对应的驱动包(JDBC接口的具体实现),是Java操作数据库的基础。
1. JDBC开发前置准备
(1)下载数据库驱动包
(2)导入驱动包
在Web项目中创建WEB-INF/lib目录,将驱动包复制到该目录,右键添加为库(Add as Library),使项目识别驱动包。
2. JDBC完整开发步骤
JDBC操作数据库遵循注册驱动→建立连接→执行SQL→处理结果→释放资源 的固定流程,核心使用DriverManager、Connection、Statement/PreparedStatement、ResultSet四大核心类/接口。
(1)注册数据库驱动
推荐使用反射方式加载驱动,避免与具体驱动类硬绑定,便于后续数据库切换:
java
// MySQL5.7驱动类
Class.forName("com.mysql.jdbc.Driver");
// MySQL8.0驱动类(需添加时区参数)
// Class.forName("com.mysql.cj.jdbc.Driver");
(2)建立数据库连接
通过DriverManager.getConnection()获取Connection对象,封装数据库连接信息,URL格式为jdbc:数据库类型://ip:端口/库名?参数:
java
// 数据库连接信息
String url = "jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=UTF-8";
String user = "root";
String password = "123456";
// 获取连接
Connection conn = DriverManager.getConnection(url, user, password);
(3)执行SQL语句
JDBC提供Statement和PreparedStatement两种执行器,优先使用PreparedStatement ,通过预编译机制解决SQL注入问题,提升安全性和执行效率。
① 防SQL注入:PreparedStatement预编译
原理:提前编译SQL执行逻辑,将参数作为占位符?传入,参数不会被解析为SQL语句,彻底避免SQL注入攻击:
java
// 预编译SQL,占位符?接收参数
String sql = "select * from user where username = ? and password = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
// 为占位符赋值(索引从1开始)
pstmt.setString(1, username);
pstmt.setString(2, password);
// 执行SQL:查询用executeQuery(),增删改用executeUpdate()
ResultSet rs = pstmt.executeQuery();
② 原生Statement(不推荐,存在SQL注入风险)
java
Statement stmt = conn.createStatement();
// 执行查询,返回结果集
ResultSet rs = stmt.executeQuery("select * from user");
// 执行增删改,返回影响行数
int row = stmt.executeUpdate("delete from user where id=1");
(4)处理结果集ResultSet
ResultSet封装SQL查询的结果,通过游标移动遍历数据,核心方法:
boolean next():游标下移一行,有数据返回true,无数据返回false;getXxx(String columnName/int index):获取指定列的数据,Xxx为数据类型(如getInt、getString)。
结果集处理示例:
java
while (rs.next()) {
// 根据列名获取数据
int id = rs.getInt("id");
String username = rs.getString("username");
String phone = rs.getString("phone");
// 业务处理
System.out.println("id:" + id + ",用户名:" + username + ",手机号:" + phone);
}
(5)释放资源
数据库连接、执行器、结果集均为稀缺资源,使用后必须及时关闭,释放顺序:后创建先释放 (ResultSet→PreparedStatement/Statement→Connection),建议在finally代码块中释放,保证无论是否异常都会执行:
java
finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
3. JDBC批处理操作
针对大量相同结构的增删改操作,使用JDBC批处理减少与数据库的交互次数,提升执行效率,核心使用addBatch()添加SQL、executeBatch()执行批处理:
java
String sql = "insert into user (username) values (?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
// 批量添加参数
for (int i = 0; i < 100; i++) {
pstmt.setString(1, "user" + i);
pstmt.addBatch();
// 每100条执行一次,避免内存溢出
if (i % 100 == 0) {
pstmt.executeBatch();
pstmt.clearBatch();
}
}
// 执行剩余批处理
pstmt.executeBatch();
三、数据库框架优化:MyBatis开发
MyBatis是一款优秀的持久层框架 ,基于JDBC进行封装,彻底避免了JDBC原生的繁琐代码(如手动注册驱动、设置参数、处理结果集),实现了SQL与Java代码解耦,同时保留了SQL的灵活性,是JavaEE中主流的数据库操作框架。
1. MyBatis核心优势
- 消除了JDBC几乎所有的样板代码,简化数据库操作;
- 支持自定义SQL,保留SQL的灵活性,适配复杂业务查询;
- 自动完成参数映射 和结果集封装,无需手动设置占位符和解析ResultSet;
- 支持缓存机制(一级缓存/二级缓存),提升查询效率;
- 支持动态SQL,通过标签实现SQL的动态拼接,适配多条件查询。
2. MyBatis核心设计思想
MyBatis的核心是ORM(对象关系映射) 的轻量实现,将数据库表的行与Java实体类对象进行映射,通过Mapper接口 和XML映射文件(或注解)实现SQL的执行,无需编写实现类,由MyBatis动态代理生成。
3. MyBatis基础开发流程
(1)项目环境搭建
- 创建JavaEE/Maven项目,引入MyBatis核心依赖、数据库驱动依赖;
- 编写MyBatis核心配置文件
mybatis-config.xml,配置数据库连接、别名、Mapper映射路径; - 编写数据库表对应的Java实体类(POJO),实现属性与表字段的一一映射;
- 编写Mapper接口,定义数据库操作方法;
- 编写Mapper.xml映射文件,配置SQL语句与Mapper接口方法的绑定。
(2)核心执行逻辑
- 通过MyBatis的
SqlSessionFactory创建SqlSession(数据库会话); - 通过
SqlSession获取Mapper接口的代理对象; - 调用Mapper接口方法,MyBatis自动执行对应的SQL并返回封装后的结果集。
4. MyBatis核心特性:防SQL注入
MyBatis的SQL参数绑定默认使用预编译机制 ,通过#{}占位符接收参数,底层封装了JDBC的PreparedStatement,彻底避免SQL注入攻击;若使用${}拼接参数,会存在注入风险,仅适用于表名/列名等动态拼接场景。
Mapper.xml中SQL编写示例:
xml
<!-- 根据用户名和密码查询用户,#{}(预编译)防注入 -->
<select id="selectUserByUsernameAndPwd" resultType="com.demo.pojo.User">
select id, username, password, phone from user
where username = #{username} and password = #{password}
</select>
四、技术总结与应用场景
- Servlet :JavaEE Web开发的基础,负责处理HTTP请求、实现业务逻辑分发,是前后端交互的核心,其路由配置 和生命周期管理是Web开发的必备知识点,也是SpringMVC等Web框架的底层基础;
- JDBC :Java操作数据库的原生规范,是所有持久层框架的基础,掌握JDBC的核心流程和预编译防注入是数据库开发的基础,适用于简单项目或框架底层开发;
- MyBatis :企业级开发的主流持久层框架,基于JDBC封装,简化开发的同时保留SQL灵活性,ORM映射 、动态SQL 、缓存机制是其核心优势,适用于绝大多数JavaEE企业项目。
以上技术是JavaEE后端开发的核心基础,也是后续学习Spring、SpringBoot等主流框架的前提,掌握其底层原理和实际应用,能够实现从前端请求到数据库操作的全流程Web开发,适配企业级Web项目的开发需求。