目录
静态成员变量(tokenExpiration 和 tokenSignKey)
readJson(HttpServletRequest request, Class clazz)
writeJson(HttpServletResponse response, Result result)
JDBCUtil(数据库连接池管理)
主要用于管理数据库连接。使用了 Druid 数据源 和 ThreadLocal 来确保多线程环境下数据库连接的安全性与高效性,减少频繁创建与销毁数据库连接的开销。该类提供了获取连接池、获取数据库连接以及释放连接的方法。
主要功能解释
1. ThreadLocal<Connection> threadLocal
:
- 使用
ThreadLocal
来存储每个线程的数据库连接。这保证了每个线程都有自己独立的数据库连接,避免了线程间的连接共享问题。
2. DataSource dataSource
:
DataSource
用于管理数据库连接池,允许获取和释放数据库连接。这里使用的是 Druid 数据源,它是一种高效、稳定的数据库连接池管理工具。
静态代码块
Properties properties = new Properties();
InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(resourceAsStream);
dataSource = DruidDataSourceFactory.createDataSource(properties);
在类加载时进行,用于初始化数据库连接池(dataSource
)。首先通过 Properties
类加载 jdbc.properties
文件中的配置,然后通过 DruidDataSourceFactory
创建连接池。
类方法
getDataSource()
public static DataSource getDataSource() {
return dataSource;
}
用于向外界提供 DataSource
对象,使得其他类能够直接访问连接池,获取数据库连接。
getConnection()
public static Connection getConnection() {
Connection connection = threadLocal.get();
if (null == connection) {
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
threadLocal.set(connection);
}
return connection;
}
该方法用于获取数据库连接:
- 先从
ThreadLocal
获取当前线程是否已有连接(如果有,则直接返回)。 - 如果当前线程没有连接,则从连接池中获取新的连接,并将其存储到
ThreadLocal
中,确保该线程后续操作会使用相同的连接。
releaseConnection()
public static void releaseConnection() {
Connection connection = threadLocal.get();
if (null != connection) {
threadLocal.remove();
try {
connection.setAutoCommit(true);
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
该方法用于释放数据库连接:
- 先从
ThreadLocal
中获取当前线程的连接。 - 如果连接存在,解除连接与
ThreadLocal
的关联(调用threadLocal.remove()
),并将连接的自动提交模式恢复为true
。 - 最后,调用
connection.close()
将连接归还到连接池中,而不是直接关闭它,从而可以重复使用该连接。
代码示例
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtil {
private static ThreadLocal<Connection> threadLocal =new ThreadLocal<>();
private static DataSource dataSource;
// 初始化连接池
static{
// 可以帮助我们读取.properties配置文件
Properties properties =new Properties();
InputStream resourceAsStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(resourceAsStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/*1 向外提供连接池的方法*/
public static DataSource getDataSource(){
return dataSource;
}
/*2 向外提供连接的方法*/
public static Connection getConnection(){
Connection connection = threadLocal.get();
if (null == connection) {
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
threadLocal.set(connection);
}
return connection;
}
/*定义一个归还连接的方法 (解除和ThreadLocal之间的关联关系) */
public static void releaseConnection(){
Connection connection = threadLocal.get();
if (null != connection) {
threadLocal.remove();
// 把连接设置回自动提交的连接
try {
connection.setAutoCommit(true);
// 自动归还到连接池
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
使用示例
要先配置jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/mydb
jdbc.username=root
jdbc.password=root
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//查询用户信息
public class JdbcExample {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 获取数据库连接
conn = JDBCUtil.getConnection();
// SQL查询语句
String sql = "SELECT id, name, email FROM users";
// 创建PreparedStatement对象
pstmt = conn.prepareStatement(sql);
// 执行查询并获取结果集
rs = pstmt.executeQuery();
// 遍历结果集并打印用户信息
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
System.out.println("ID: " + id + ", Name: " + name + ", Email: " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 释放连接资源
JDBCUtil.releaseConnection();
}
}
}
//新增数据
public class JdbcInsertExample {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
// 获取数据库连接
conn = JDBCUtil.getConnection();
// SQL插入语句
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
// 创建PreparedStatement对象
pstmt = conn.prepareStatement(sql);
// 设置参数值
pstmt.setString(1, "Alice");
pstmt.setString(2, "alice@example.com");
// 执行插入操作
int rowsAffected = pstmt.executeUpdate();
System.out.println("插入了 " + rowsAffected + " 行数据");
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 释放连接资源
JDBCUtil.releaseConnection();
}
}
}
JwtHelper(Token管理)
这个类是一个用于生成、解析和验证 JSON Web Token (JWT) 的工具类,通常用于用户身份验证或授权。在这个类中,JWT 用于将用户的 userId
编码到一个安全的令牌中,令牌在一定的时间段内有效。
静态成员变量(tokenExpiration
和 tokenSignKey
)
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "123456";
tokenExpiration
:令牌的有效期(以毫秒为单位,如24 * 60 * 60 * 1000为24小时
)。
tokenSignKey
:用于签名和验证 JWT 的密钥,确保生成的令牌在传输过程中没有被篡改。这个密钥应设置为复杂的字符串来提高安全性。
类方法
createToken(Long userId)
public static String createToken(Long userId) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
功能:生成一个 JWT 令牌。
Jwts.builder()
:创建一个 JWT 构造器,构建令牌。setSubject("YYGH-USER")
:设置令牌的主题(这里是 "YYGH-USER",可以表示用户身份或应用标识)。setExpiration(...)
:设置令牌的过期时间,这里是当前时间加上tokenExpiration
(24小时)。claim("userId", userId)
:在令牌中加入自定义声明,这里是用户的userId
,可以通过解析该令牌获取用户身份。signWith(SignatureAlgorithm.HS512, tokenSignKey)
:使用 HS512 算法和密钥tokenSignKey
对令牌进行签名,以保证令牌的安全性。compressWith(CompressionCodecs.GZIP)
:对生成的令牌使用 GZIP 压缩,减少令牌的长度。compact()
:生成最终的令牌字符串。
返回值:生成的 JWT 令牌是一个字符串,客户端可以使用该令牌在后续请求中进行身份验证。
getUserId(String token)
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
功能:从 JWT 令牌中解析出用户的 userId
。
Jwts.parser().setSigningKey(tokenSignKey)
:创建一个解析器,并使用签名密钥tokenSignKey
来验证令牌的签名。parseClaimsJws(token)
:解析传入的令牌,获取其中的声明(Claims
),包括自定义的userId
。claims.get("userId")
:从声明中获取userId
,并将其转换为Long
类型返回。
返回值:用户的 userId
,如果令牌无效或者为空,则返回 null
。
isExpiration(String token)
public static boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
return isExpire;
}catch(Exception e) {
return true;
}
}
功能:判断 JWT 令牌是否过期。
getExpiration().before(new Date())
:从令牌中获取到过期时间,并与当前时间进行比较。如果过期时间在当前时间之前,则表示令牌已过期。- 如果令牌已过期,或者在解析过程中抛出了异常(例如令牌格式错误或签名无效),则返回
true
,表示令牌已失效。
返回值:true
表示令牌无效或已过期,false
表示令牌有效。
代码示例
import com.alibaba.druid.util.StringUtils;
import io.jsonwebtoken.*;
import java.util.Date;
public class JwtHelper {
private static long tokenExpiration = 24*60*60*1000;
private static String tokenSignKey = "123456";
//生成token字符串
public static String createToken(Long userId) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
.claim("userId", userId)
.signWith(SignatureAlgorithm.HS512, tokenSignKey)
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//从token字符串获取userid
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//判断token是否有效
public static boolean isExpiration(String token){
try {
boolean isExpire = Jwts.parser()
.setSigningKey(tokenSignKey)
.parseClaimsJws(token)
.getBody()
.getExpiration().before(new Date());
//没有过期,有效,返回false
return isExpire;
}catch(Exception e) {
//过期出现异常,返回true
return true;
}
}
}
使用示例
public class JwtExample {
public static void main(String[] args) {
// 模拟用户ID
Long userId = 123L;
// 1. 生成 JWT token
String token = JwtHelper.createToken(userId);
System.out.println("生成的 JWT Token: " + token);
// 2. 从 token 中解析用户ID
Long extractedUserId = JwtHelper.getUserId(token);
System.out.println("从 JWT Token 中解析出的用户ID: " + extractedUserId);
// 3. 验证 token 是否过期
boolean isExpired = JwtHelper.isExpiration(token);
System.out.println("JWT Token 是否过期: " + isExpired);
}
}
MD5Util(MD5加密)
这个类是一个用于对字符串进行 MD5 哈希加密的工具类。MD5 是一种广泛使用的散列函数,可以将任意长度的数据映射到一个固定长度的哈希值(通常是 128 位)。该类提供了一个静态的 encrypt
方法,用于将输入字符串加密为 MD5 哈希值,并将其结果以 16 进制格式输出。
类方法
encrypt(String strSrc)
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
hexChars[]
数组:这个数组用于将 MD5 生成的字节结果转换为 16 进制字符。MD5 的结果是一个二进制数组,通过该数组,生成的字节可以被映射成0-9
和a-f
的 16 进制形式。strSrc.getBytes()
:将输入的字符串转换为字节数组,因为 MD5 加密是基于字节数组进行的。MessageDigest.getInstance("MD5")
:MessageDigest
是 Java 提供的加密 API,用于生成散列值。这里通过getInstance("MD5")
来创建一个 MD5 加密算法的实例。md.update(bytes)
:将字节数组传入 MD5 算法进行处理。bytes = md.digest()
:通过调用digest()
方法,完成对数据的 MD5 哈希运算,并返回一个字节数组。这个字节数组长度是 16(128 位),表示 MD5 的加密结果。- 将字节转换为 16 进制字符:MD5 的结果是一个字节数组,每个字节是 8 位(二进制)。为了将其表示为 16 进制的字符串,需要将每个字节分为高 4 位和低 4 位,分别映射到
hexChars[]
数组中的字符。通过这个过程,最终会生成一个长度为 32 的字符数组(每个字节对应 2 个 16 进制字符),然后将其转换为字符串返回。
使用示例
String encrypted = MD5Util.encrypt("password123");
System.out.println("加密后的字符串: " + encrypted);
代码示例
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5Util {
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
}
WebUtil(处理Web请求与响应)
这个类是一个用于处理 Web 请求和响应的工具类,主要用于将请求中的 JSON 数据转换为 Java 对象,以及将 Java 对象转换为 JSON 字符串并写入 HTTP 响应中。它通过 Jackson 库的 ObjectMapper
来实现 JSON 与 Java 对象之间的相互转换,并且处理了 HTTP 请求与响应的常见操作。
静态成员变量及静态代码块
private static ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
// 设置JSON和Object转换时的时间日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
ObjectMapper
:这是 Jackson 提供的核心类,用于处理 JSON 数据与 Java 对象之间的转换。它支持将 JSON 字符串转换为 Java 对象,也支持将 Java 对象序列化为 JSON 字符串。- 静态初始化:在类加载时,静态代码块会被执行,初始化
ObjectMapper
对象,并设置 JSON 与对象转换时的日期格式为"yyyy-MM-dd HH:mm:ss"
。这样,在处理日期类型字段时,统一使用该格式。
类方法
readJson(HttpServletRequest request, Class<T> clazz)
public static <T> T readJson(HttpServletRequest request, Class<T> clazz) {
T t = null;
BufferedReader reader = null;
try {
reader = request.getReader();
StringBuffer buffer = new StringBuffer();
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
t = objectMapper.readValue(buffer.toString(), clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
return t;
}
功能:从 HttpServletRequest
中读取 JSON 字符串并将其转换为指定类型的 Java 对象。
- 泛型支持:该方法是泛型方法,支持将 JSON 数据转换为任何类型的 Java 对象,类型由传入的
Class<T>
参数指定。 - 步骤:
- 使用
request.getReader()
获取请求体中的数据,这个方法返回BufferedReader
,可以按行读取请求的内容。 - 将读取到的内容逐行拼接到
StringBuffer
中。 - 通过
objectMapper.readValue(buffer.toString(), clazz)
将 JSON 字符串转换为指定的 Java 对象。
- 使用
- 异常处理:如果在读取或转换过程中发生
IOException
异常,则捕获该异常并抛出运行时异常。
用途:该方法适用于从客户端的 POST 请求体中读取 JSON 数据,并将其转换为对应的 Java 对象(如一个 DTO 类),以便在服务端处理。
writeJson(HttpServletResponse response, Result result)
public static void writeJson(HttpServletResponse response, Result result) {
response.setContentType("application/json;charset=UTF-8");
try {
String json = objectMapper.writeValueAsString(result);
response.getWriter().write(json);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
功能:将 Result
对象转换为 JSON 字符串并写入到 HTTP 响应中。
- 步骤:
- 设置响应的内容类型为
application/json
,并指定字符编码为 UTF-8,确保返回给客户端的 JSON 字符串能够被正确解析。 - 通过
objectMapper.writeValueAsString(result)
将 Java 对象(这里是Result
对象)转换为 JSON 字符串。 - 使用
response.getWriter().write(json)
将生成的 JSON 写入到 HTTP 响应中,发送给客户端。
- 设置响应的内容类型为
- 异常处理:捕获可能的
IOException
异常并抛出运行时异常。
用途:该方法适用于将服务器处理结果(如业务处理的响应信息)转换为 JSON 格式并返回给客户端。例如,在 RESTful 接口中,服务器通常以 JSON 格式返回数据给前端或移动端应用。
使用示例
从请求中读取 JSON:
User user = WebUtil.readJson(request, User.class);
// 现在 user 对象包含了请求体中的 JSON 数据
将对象返回为 JSON 响应:
Result result = new Result(200, "Success", data);
WebUtil.writeJson(response, result);
代码示例
import com.atguigu.headline.common.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.SimpleDateFormat;
public class WebUtil {
private static ObjectMapper objectMapper;
// 初始化objectMapper
static{
objectMapper=new ObjectMapper();
// 设置JSON和Object转换时的时间日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
// 从请求中获取JSON串并转换为Object
public static <T> T readJson(HttpServletRequest request,Class<T> clazz){
T t =null;
BufferedReader reader = null;
try {
reader = request.getReader();
StringBuffer buffer =new StringBuffer();
String line =null;
while((line = reader.readLine())!= null){
buffer.append(line);
}
t= objectMapper.readValue(buffer.toString(),clazz);
} catch (IOException e) {
throw new RuntimeException(e);
}
return t;
}
// 将Result对象转换成JSON串并放入响应对象
public static void writeJson(HttpServletResponse response, Result result){
response.setContentType("application/json;charset=UTF-8");
try {
String json = objectMapper.writeValueAsString(result);
response.getWriter().write(json);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}