1.pom.xml三方依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ordinary</groupId>
<artifactId>ordinary</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysql.version>8.0.30</mysql.version>
<protobuf-java.version>3.25.3</protobuf-java.version>
<guava.version>32.1.3-jre</guava.version>
<hutool.version>5.8.25</hutool.version>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<exclusions>
<!-- mysql驱动依赖的protobuf-java的版本是3.19.4,该版本容易被攻击。 -->
<exclusion>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf-java.version}</version>
</dependency>
<!-- 工具 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
</project>
2.JDBC查询
package cn.ordinary.util.jdbc;
import com.mysql.cj.jdbc.Driver;
import java.sql.*;
import java.util.function.Function;
/**
* @Classname JdbcOptionUtils
* @Date 2024/3/14
* @Author sh
**/
public class JdbcOptionUtils {
private static final String LOAD_WAY_1 = "1";
private static final String LOAD_WAY_2 = "2";
public static <R> R query(JdbcProperties jdbcProperties, String querySql,
Function<ResultSet, R> function)
throws SQLException {
// 1- 加载并注册 JDBC 驱动
//registerJdbcDriver(LOAD_WAY_1);
/**
* JDBC4.0 之后引入了一个重要特性:自动加载JDBC驱动。这意味着,只要JDBC4.0兼容的驱动位于 应用程序的类路径上,它就会被自动加载,
* 不需要通过代码显示的加载驱动类(例如,使用 Class.forName("com.mysql.cj.jdbc.Driver");)。该特性利用了
* Java 服务提供者接口(SPI)机制 和 线程上下文类加载器 实现。
*
* // 设置 线程上下文类加载器 为 应用程序/系统 类加载器
* Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
*
* 自动发现和加载JDBC驱动的过程如下:
* ① 服务提供者配置文件
* JDBC驱动jar包中包含了一个服务提供者配置文件,位于 META-INF/services 目录下。对于JDBC驱动来说,这个配置文件
* 的名称是 java.sql.Driver。文件内容是实现了 java.sql.Driver 接口的具体驱动类的全限定名(如,com.mysql.cj.jdbc.Driver)。
* ② 使用ServiceLoader加载服务
* JDBC API 使用 java.util.ServiceLoader 类来加载 java.sql.Driver 服务。
* ServiceLoader 会读取上面的配置文件,找到并加载列出的驱动类。
* ③ 线程上下文类加载器
* ServiceLoader.load() 方法默认使用 线程上下文类加载器 去查找和加载 服务提供者。这意味着,
* 即使【JDBC API是由 启动类加载器 加载的,它仍然能够通过 线程上下文类加载器 加载并访问 应用程序类路径上的JDBC驱动】。
*/
// 2- 操作 数据库
try (
// 连接数据库
Connection conn = DriverManager.getConnection(
jdbcProperties.getUrl(), jdbcProperties.getUser(), jdbcProperties.getPassword());
// 创建 ps对象
PreparedStatement ps = conn.prepareStatement(querySql);
// 执行查询
ResultSet rs = ps.executeQuery();
) {
// 返回查询结果集
return function.apply(rs);
} catch (SQLException e) {
throw new SQLException("查询失败", e);
} catch (Exception e) {
// 捕获并处理 非SQL异常(function.apply(rs)回调可能会出现异常)
throw new SQLException("处理查询结果集时出现异常", e);
}
}
/**
* 加载并注册 JDBC 驱动
*/
private static void registerJdbcDriver(String loadWay) {
switch (loadWay) {
// 方式一
case LOAD_WAY_1:
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("JDBC驱动加载失败");
e.printStackTrace();
}
break;
// 方式二/默认方式
case LOAD_WAY_2:
default:
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
3.JDBC查询测试
3.1加解密算法
package cn.ordinary.util.security;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
/**
* 加密/解密 工具
*
* @author shihao
*/
public class SecureUtils {
/**
* 对密文进行解密,解密算法:DES
*
* @param ciphertext 密文
* @param key 密钥
* @return 明文
*/
public static String getPlaintextByDes(String ciphertext, String key) {
byte[] secretKey = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(),
key.getBytes()).getEncoded();
return SecureUtil.des(secretKey).decryptStr(ciphertext);
}
public static void des(String plaintext, String key) {
// %s: 字符串,%n: 换行符
System.out.printf("plaintext : %s%n", plaintext);
// 密钥
byte[] secretKey = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(),
key.getBytes()).getEncoded();
// 1- 加密
String ciphertextByDes = SecureUtil.des(secretKey).encryptHex(plaintext);
System.out.printf("ciphertext by des : %s%n", ciphertextByDes);
// 2- 解密
String plaintextByDes = SecureUtil.des(secretKey).decryptStr(ciphertextByDes);
System.out.printf("plaintext by des : %s%n", plaintextByDes);
}
/**
* 默认密钥
*/
public static final String KEY = "1234567890*";
}
3.2JDBC基本属性JavaBean
package cn.ordinary.util.jdbc;
import cn.ordinary.util.security.SecureUtils;
/**
* @Description TODO
* @Classname JdbcProperties
* @Date 2024/3/14
* @Author sh
**/
public class JdbcProperties {
private String url;
private String user;
private String password;
public JdbcProperties() {
}
public JdbcProperties(String url, String user, String password) {
this.url = url;
this.user = user;
this.password = password;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return this.url;
}
public void setUser(String user) {
this.user = user;
}
public String getUser() {
return this.user;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return SecureUtils.getPlaintextByDes(this.password, SecureUtils.KEY);
}
}
3.3查询测试
package cn.ordinary.test.jdbc;
import cn.ordinary.domain.TbAddress;
import cn.ordinary.util.jdbc.JdbcOptionUtils;
import cn.ordinary.util.jdbc.JdbcProperties;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @Description TODO
* @Classname JDBCTest
* @Date 2024/3/12
* @Author sh
**/
public class JDBCTest {
public static void main(String[] args) {
JdbcProperties jdbcProperties = new JdbcProperties("jdbc:mysql://localhost:3306/zt",
"root", "172640dd50807625");
List<TbAddress> addressList;
try {
addressList = JdbcOptionUtils.query(jdbcProperties, "select * from tb_address", rs -> {
// 处理结果集
List<TbAddress> rsList = new ArrayList<>();
TbAddress tbAddress;
try {
while (rs.next()) {
String id = rs.getString("id");
String parentId = rs.getString("parent_id");
String addressName = rs.getString("address_name");
tbAddress = new TbAddress(id, parentId, addressName);
rsList.add(tbAddress);
}
} catch (SQLException e) {
throw new RuntimeException("结果集转换异常", e);
}
return rsList;
});
} catch (SQLException e) {
throw new RuntimeException("数据库操作失败", e);
}
// 输出各个省的名称
addressList.stream()
.filter(innerTbAddress -> innerTbAddress.getId().length() == 2)
.map(TbAddress::getAddressName)
.forEach(System.out::println);
}
}