【JavaEE安全】Servlet与数据库操作(JDBC&MyBatis)

一、Servlet核心技术:路由、生命周期与请求响应处理

Servlet作为JavaEE的核心组件,是运行在Web服务器上的服务端程序,承担着客户端HTTP请求与服务端业务/数据库交互的中间层角色,能够实现请求接收、业务处理、动态网页生成等核心功能,是Web开发的基础核心。

1. Servlet的创建与路由配置

Servlet的使用核心在于类的实现路由映射 ,路由映射是客户端请求能找到对应Servlet的关键,主流有web.xml配置注解配置两种方式,以下是完整实现步骤:

  1. 自定义Servlet类,继承javax.servlet.http.HttpServlet,重写业务所需方法(doGet/doPost);
  2. 配置路由映射,实现客户端请求路径与Servlet的绑定;
  3. 部署项目,通过浏览器访问配置的路由路径触发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个核心阶段,其中初始化销毁 仅执行一次,服务阶段随每次请求执行,是性能优化的核心关注点:

  1. 构造方法执行(实例化):第一次请求Servlet或服务器启动时执行,仅创建一个实例(单例),保证资源复用;
  2. init()方法(初始化):实例创建后立即执行,用于初始化Servlet资源(如加载配置、创建连接池),仅执行一次;
  3. service()方法(服务):每次客户端请求都会执行,容器会根据请求方式(GET/POST)自动调用doGet()或doPost()方法,是业务处理的核心;
  4. 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 请求处理

HttpServletRequestServletRequest的HTTP协议专用子接口,用于获取客户端请求的所有信息,核心方法:

  • 获取请求参数
    • String getParameter(String name):获取单个参数值(如表单、URL传参);
    • String[] getParameterValues(String name):获取多值参数(如复选框);
  • 解决中文乱码req.setCharacterEncoding("UTF-8")
  • 其他常用getMethod()获取请求方式、getRemoteAddr()获取客户端IP。
(2)HttpServletResponse 响应处理

HttpServletResponseServletResponse的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)下载数据库驱动包

从Maven仓库(https://mvnrepository.com/)下载对应数据库的驱动包,如MySQL的`mysql-connector-java`,根据数据库版本选择适配版本(MySQL5.7对应5.1.x,MySQL8.0对应8.0.x)。

(2)导入驱动包

在Web项目中创建WEB-INF/lib目录,将驱动包复制到该目录,右键添加为库(Add as Library),使项目识别驱动包。

2. JDBC完整开发步骤

JDBC操作数据库遵循注册驱动→建立连接→执行SQL→处理结果→释放资源 的固定流程,核心使用DriverManagerConnectionStatement/PreparedStatementResultSet四大核心类/接口。

(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提供StatementPreparedStatement两种执行器,优先使用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核心优势

  1. 消除了JDBC几乎所有的样板代码,简化数据库操作;
  2. 支持自定义SQL,保留SQL的灵活性,适配复杂业务查询;
  3. 自动完成参数映射结果集封装,无需手动设置占位符和解析ResultSet;
  4. 支持缓存机制(一级缓存/二级缓存),提升查询效率;
  5. 支持动态SQL,通过标签实现SQL的动态拼接,适配多条件查询。

2. MyBatis核心设计思想

MyBatis的核心是ORM(对象关系映射) 的轻量实现,将数据库表的行与Java实体类对象进行映射,通过Mapper接口XML映射文件(或注解)实现SQL的执行,无需编写实现类,由MyBatis动态代理生成。

3. MyBatis基础开发流程

(1)项目环境搭建
  1. 创建JavaEE/Maven项目,引入MyBatis核心依赖、数据库驱动依赖;
  2. 编写MyBatis核心配置文件mybatis-config.xml,配置数据库连接、别名、Mapper映射路径;
  3. 编写数据库表对应的Java实体类(POJO),实现属性与表字段的一一映射;
  4. 编写Mapper接口,定义数据库操作方法;
  5. 编写Mapper.xml映射文件,配置SQL语句与Mapper接口方法的绑定。
(2)核心执行逻辑
  1. 通过MyBatis的SqlSessionFactory创建SqlSession(数据库会话);
  2. 通过SqlSession获取Mapper接口的代理对象;
  3. 调用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>

四、技术总结与应用场景

  1. Servlet :JavaEE Web开发的基础,负责处理HTTP请求、实现业务逻辑分发,是前后端交互的核心,其路由配置生命周期管理是Web开发的必备知识点,也是SpringMVC等Web框架的底层基础;
  2. JDBC :Java操作数据库的原生规范,是所有持久层框架的基础,掌握JDBC的核心流程和预编译防注入是数据库开发的基础,适用于简单项目或框架底层开发;
  3. MyBatis :企业级开发的主流持久层框架,基于JDBC封装,简化开发的同时保留SQL灵活性,ORM映射动态SQL缓存机制是其核心优势,适用于绝大多数JavaEE企业项目。

以上技术是JavaEE后端开发的核心基础,也是后续学习Spring、SpringBoot等主流框架的前提,掌握其底层原理和实际应用,能够实现从前端请求到数据库操作的全流程Web开发,适配企业级Web项目的开发需求。

相关推荐
xuansec6 小时前
【JavaEE安全】Spring Boot 安全实战:JWT 身份鉴权与打包部署
spring boot·安全·java-ee
DevSecOps选型指南7 小时前
直击AI全生命周期安全治理,悬镜正式发布原创多模态AIST新品
人工智能·安全·自然语言处理
乾元7 小时前
本地大模型:如何在内网部署 Llama/Qwen 等安全增强模型
运维·网络·人工智能·安全·机器学习·llama·安全架构
星幻元宇VR7 小时前
VR应急救护学习机|让急救教育更直观
学习·安全·vr·虚拟现实
落寞的魚丶7 小时前
第二届全国网络安全行业赛-电子取证师复赛R03(其他赛区)
安全·web安全
星幻元宇VR7 小时前
VR社区安全学习机:居民安全教育新选择
科技·学习·安全·vr·虚拟现实
dashizhi20158 小时前
服务器共享文件安全管理之如何禁止打印共享文件、禁止复制共享文件
运维·服务器·安全
xiangzhihong88 小时前
放生小龙虾,OpenClaw 安全卸载指南
服务器·安全·php
2501_915921438 小时前
只有 IPA 没有源码时,如何给 iOS 应用做安全处理
android·安全·ios·小程序·uni-app·iphone·webview
xuansec8 小时前
【JavaEE安全】Java第三方组件安全漏洞(Log4J JNDI/FastJson 反射)
java·安全·java-ee