工单模块

This commit is contained in:
2025-12-19 11:11:51 +08:00
parent 41cbe2bd54
commit 409e33abb6
49 changed files with 1934 additions and 323 deletions

View File

@@ -0,0 +1,44 @@
<?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>
<parent>
<groupId>org.xyzh</groupId>
<artifactId>common</artifactId>
<version>1.0.0</version>
</parent>
<groupId>org.xyzh.common</groupId>
<artifactId>common-jdbc</artifactId>
<version>${urban-lifeline.version}</version>
<packaging>jar</packaging>
<description>JDBC相关工具MyBatis类型处理器</description>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<scope>provided</scope>
</dependency>
<!-- FastJson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
</dependency>
<!-- common-utils (用于 AesEncryptUtil) -->
<dependency>
<groupId>org.xyzh.common</groupId>
<artifactId>common-utils</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,39 @@
package org.xyzh.common.jdbc.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.xyzh.common.jdbc.handler.EncryptedStringTypeHandler;
import org.xyzh.common.utils.crypto.AesEncryptUtil;
import jakarta.annotation.PostConstruct;
/**
* TypeHandler 配置类
* 用于初始化 EncryptedStringTypeHandler 中的 AesEncryptUtil
*
* @author yslg
* @since 2025-12-11
*/
@Configuration
@ConditionalOnClass(AesEncryptUtil.class)
public class TypeHandlerConfig {
private final AesEncryptUtil aesEncryptUtil;
@Autowired(required = false)
public TypeHandlerConfig(AesEncryptUtil aesEncryptUtil) {
this.aesEncryptUtil = aesEncryptUtil;
}
@PostConstruct
public void init() {
// 初始化 TypeHandler 中的静态 AesEncryptUtil 实例
if (aesEncryptUtil != null) {
EncryptedStringTypeHandler.setAesEncryptUtil(aesEncryptUtil);
System.out.println("✓ TypeHandler 已初始化 AES 加密工具");
} else {
System.err.println("警告: AesEncryptUtil 未能注入,加密功能可能无法正常工作");
}
}
}

View File

@@ -0,0 +1,77 @@
package org.xyzh.common.jdbc.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.xyzh.common.utils.crypto.AesEncryptUtil;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* MyBatis 加密字段类型处理器
* 自动对数据库字段进行加密/解密
*
* 使用方式:
* 在实体类字段上添加注解:
* @TableField(typeHandler = EncryptedStringTypeHandler.class)
* private String phone;
*
* @author yslg
* @since 2025-12-05
*/
@MappedTypes({String.class})
public class EncryptedStringTypeHandler extends BaseTypeHandler<String> {
private static AesEncryptUtil aesEncryptUtil;
/**
* 设置加密工具(由 Spring 注入)
*/
public static void setAesEncryptUtil(AesEncryptUtil util) {
aesEncryptUtil = util;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
// 写入数据库时加密
if (aesEncryptUtil != null && parameter != null) {
ps.setString(i, aesEncryptUtil.encrypt(parameter));
} else {
ps.setString(i, parameter);
}
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
// 从数据库读取时解密
String encrypted = rs.getString(columnName);
return decrypt(encrypted);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String encrypted = rs.getString(columnIndex);
return decrypt(encrypted);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String encrypted = cs.getString(columnIndex);
return decrypt(encrypted);
}
private String decrypt(String encrypted) {
if (aesEncryptUtil != null && encrypted != null && !encrypted.isEmpty()) {
try {
return aesEncryptUtil.decrypt(encrypted);
} catch (Exception e) {
// 如果解密失败,可能是旧数据,返回原值
return encrypted;
}
}
return encrypted;
}
}

View File

@@ -0,0 +1,103 @@
package org.xyzh.common.jdbc.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @description 通用枚举类型处理器,支持枚举类中定义 getName() 方法
* 将枚举的 name 属性(自定义字符串)存储到数据库
* @filename EnumNameTypeHandler.java
* @author yslg
* @copyright xyzh
* @since 2025-12-18
*/
public class EnumNameTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
private final Class<E> type;
public EnumNameTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
String value = getEnumName(parameter);
ps.setString(i, value);
}
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
String name = rs.getString(columnName);
return fromName(name);
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String name = rs.getString(columnIndex);
return fromName(name);
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String name = cs.getString(columnIndex);
return fromName(name);
}
/**
* 获取枚举的 name 属性值
* 优先调用 getName() 方法,如果不存在则使用 name()
*/
private String getEnumName(E enumValue) {
try {
java.lang.reflect.Method getNameMethod = type.getMethod("getName");
return (String) getNameMethod.invoke(enumValue);
} catch (NoSuchMethodException e) {
return enumValue.name();
} catch (Exception e) {
return enumValue.name();
}
}
/**
* 根据 name 属性值查找枚举
* 优先匹配 getName(),如果不存在则匹配 name()
*/
private E fromName(String name) {
if (name == null) {
return null;
}
E[] enumConstants = type.getEnumConstants();
// 先尝试匹配 getName()
try {
java.lang.reflect.Method getNameMethod = type.getMethod("getName");
for (E enumConstant : enumConstants) {
String enumName = (String) getNameMethod.invoke(enumConstant);
if (name.equals(enumName)) {
return enumConstant;
}
}
} catch (NoSuchMethodException e) {
// 没有 getName 方法,使用 name()
} catch (Exception e) {
// 其他异常,使用 name()
}
// 回退到 name() 匹配
for (E enumConstant : enumConstants) {
if (name.equals(enumConstant.name())) {
return enumConstant;
}
}
return null;
}
}

View File

@@ -0,0 +1,57 @@
package org.xyzh.common.jdbc.handler;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @description FastJSON2 JSONObject 类型处理器
* @filename FastJson2TypeHandler.java
* @author yslg
* @copyright xyzh
* @since 2025-12-09
*/
@MappedTypes({JSONObject.class})
public class FastJson2TypeHandler extends BaseTypeHandler<JSONObject> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.toJSONString());
}
@Override
public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException {
String jsonString = rs.getString(columnName);
return parseToJSONObject(jsonString);
}
@Override
public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String jsonString = rs.getString(columnIndex);
return parseToJSONObject(jsonString);
}
@Override
public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String jsonString = cs.getString(columnIndex);
return parseToJSONObject(jsonString);
}
private JSONObject parseToJSONObject(String jsonString) {
if (jsonString == null || jsonString.trim().isEmpty()) {
return null;
}
try {
return JSON.parseObject(jsonString);
} catch (Exception e) {
return new JSONObject();
}
}
}

View File

@@ -0,0 +1,59 @@
package org.xyzh.common.jdbc.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @description PostgreSQL VARCHAR数组类型处理器
* @filename StringArrayTypeHandler.java
* @author yslg
* @copyright xyzh
* @since 2025-12-15
*/
@MappedTypes({List.class})
public class StringArrayTypeHandler extends BaseTypeHandler<List<String>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null || parameter.isEmpty()) {
ps.setArray(i, null);
} else {
ps.setArray(i, ps.getConnection().createArrayOf("varchar", parameter.toArray()));
}
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
java.sql.Array array = rs.getArray(columnName);
return parseArray(array);
}
@Override
public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
java.sql.Array array = rs.getArray(columnIndex);
return parseArray(array);
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
java.sql.Array array = cs.getArray(columnIndex);
return parseArray(array);
}
private List<String> parseArray(java.sql.Array array) throws SQLException {
if (array == null) {
return null;
}
Object[] objects = (Object[]) array.getArray();
return new ArrayList<>(Arrays.asList((String[]) objects));
}
}