模型库
This commit is contained in:
		
							
								
								
									
										334
									
								
								src/main/java/com/yj/earth/common/util/SQLiteUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								src/main/java/com/yj/earth/common/util/SQLiteUtil.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,334 @@ | ||||
| package com.yj.earth.common.util; | ||||
|  | ||||
| import java.sql.*; | ||||
| import java.util.*; | ||||
| import java.lang.reflect.*; | ||||
| import java.util.Date; | ||||
| import java.time.LocalDateTime; // 新增导入 | ||||
| import java.time.format.DateTimeFormatter; // 新增导入 | ||||
| import java.time.format.DateTimeParseException; // 新增导入 | ||||
|  | ||||
| public class SQLiteUtil { | ||||
|  | ||||
|     // 加载 SQLite JDBC 驱动 | ||||
|     static { | ||||
|         try { | ||||
|             Class.forName("org.sqlite.JDBC"); | ||||
|         } catch (ClassNotFoundException e) { | ||||
|             throw new RuntimeException("无法加载SQLite JDBC驱动", e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 统一日期格式(匹配数据库TEXT字段存储的格式:yyyy-MM-dd'T'HH:mm:ss.SSS) | ||||
|     private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; | ||||
|  | ||||
|     /** | ||||
|      * 根据数据库文件绝对路径获取连接 | ||||
|      */ | ||||
|     public static Connection getConnection(String dbFilePath) throws SQLException { | ||||
|         String url = "jdbc:sqlite:" + dbFilePath; | ||||
|         return DriverManager.getConnection(url); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行查询并返回单个对象 | ||||
|      */ | ||||
|     public static <T> T queryForObject(String dbFilePath, String sql, List<Object> params, Class<T> clazz) throws SQLException, IllegalAccessException, InstantiationException { | ||||
|         List<T> results = queryForList(dbFilePath, sql, params, clazz); | ||||
|         return results.isEmpty() ? null : results.get(0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行查询并返回对象列表 | ||||
|      */ | ||||
|     public static <T> List<T> queryForList(String dbFilePath, String sql, List<Object> params, Class<T> clazz) | ||||
|             throws SQLException, IllegalAccessException, InstantiationException { | ||||
|         List<T> resultList = new ArrayList<>(); | ||||
|  | ||||
|         // 使用try-with-resources确保资源自动关闭 | ||||
|         try (Connection conn = getConnection(dbFilePath); | ||||
|              PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) { | ||||
|  | ||||
|             // 执行查询 | ||||
|             try (ResultSet rs = pstmt.executeQuery()) { | ||||
|                 ResultSetMetaData metaData = rs.getMetaData(); | ||||
|                 int columnCount = metaData.getColumnCount(); | ||||
|  | ||||
|                 // 处理结果集 | ||||
|                 while (rs.next()) { | ||||
|                     T obj = clazz.newInstance(); | ||||
|                     for (int i = 1; i <= columnCount; i++) { | ||||
|                         String columnName = metaData.getColumnName(i); | ||||
|                         Object value = rs.getObject(i); | ||||
|  | ||||
|                         // 设置对象属性(自动处理类型转换) | ||||
|                         setFieldValue(obj, columnName, value); | ||||
|                     } | ||||
|                     resultList.add(obj); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return resultList; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行增删改SQL语句 | ||||
|      */ | ||||
|     public static int executeUpdate(String dbFilePath, String sql, List<Object> params) throws SQLException { | ||||
|         try (Connection conn = getConnection(dbFilePath); | ||||
|              PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) { | ||||
|             return pstmt.executeUpdate(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建并设置参数化的PreparedStatement(关键:处理LocalDateTime转String) | ||||
|      */ | ||||
|     private static PreparedStatement createPreparedStatement(Connection conn, String sql, List<Object> params) | ||||
|             throws SQLException { | ||||
|         PreparedStatement pstmt = conn.prepareStatement(sql); | ||||
|  | ||||
|         if (params != null && !params.isEmpty()) { | ||||
|             int index = 1; | ||||
|             for (Object value : params) { | ||||
|                 // 新增:LocalDateTime类型转为String、适配SQLite的TEXT字段 | ||||
|                 if (value instanceof LocalDateTime) { | ||||
|                     String dateStr = ((LocalDateTime) value).format(LOCAL_DATE_TIME_FORMATTER); | ||||
|                     pstmt.setObject(index++, dateStr); | ||||
|                 } | ||||
|                 // 新增:byte[]类型显式指定为BLOB(避免SQLite自动转换异常) | ||||
|                 else if (value instanceof byte[]) { | ||||
|                     pstmt.setBytes(index++, (byte[]) value); | ||||
|                 } else { | ||||
|                     pstmt.setObject(index++, value); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return pstmt; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 通过反射设置对象的字段值 | ||||
|      */ | ||||
|     private static void setFieldValue(Object obj, String columnName, Object value) { | ||||
|         try { | ||||
|             Field field = findField(obj.getClass(), columnName); | ||||
|             if (field != null) { | ||||
|                 field.setAccessible(true); | ||||
|                 Object convertedValue = convertValue(field.getType(), value); | ||||
|                 field.set(obj, convertedValue); | ||||
|             } | ||||
|         } catch (IllegalAccessException e) { | ||||
|             System.err.println("警告: 无法设置字段 " + columnName + " 的值 - " + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 查找字段、支持下划线命名转驼峰命名(如created_at → createdAt) | ||||
|      */ | ||||
|     private static Field findField(Class<?> clazz, String columnName) { | ||||
|         // 1. 直接匹配字段名(如数据库列名与字段名一致) | ||||
|         try { | ||||
|             return clazz.getDeclaredField(columnName); | ||||
|         } catch (NoSuchFieldException e) { | ||||
|             // 2. 下划线转驼峰后匹配(如created_at → createdAt) | ||||
|             String camelCaseName = underscoreToCamelCase(columnName); | ||||
|             try { | ||||
|                 return clazz.getDeclaredField(camelCaseName); | ||||
|             } catch (NoSuchFieldException e1) { | ||||
|                 // 3. 递归查找父类(支持继承场景) | ||||
|                 if (clazz.getSuperclass() != null) { | ||||
|                     return findField(clazz.getSuperclass(), columnName); | ||||
|                 } | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 下划线命名转驼峰命名(工具方法) | ||||
|      */ | ||||
|     private static String underscoreToCamelCase(String str) { | ||||
|         if (str == null || str.isEmpty()) { | ||||
|             return str; | ||||
|         } | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         boolean nextUpperCase = false; | ||||
|         for (char c : str.toCharArray()) { | ||||
|             if (c == '_') { | ||||
|                 nextUpperCase = true; | ||||
|             } else { | ||||
|                 if (nextUpperCase) { | ||||
|                     sb.append(Character.toUpperCase(c)); | ||||
|                     nextUpperCase = false; | ||||
|                 } else { | ||||
|                     // 修正:首字母小写(如CREATED_AT → createdAt、而非CreatedAt) | ||||
|                     sb.append(Character.toLowerCase(c)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 核心:类型转换(新增LocalDateTime解析、优化BLOB适配) | ||||
|      */ | ||||
|     private static Object convertValue(Class<?> targetType, Object value) { | ||||
|         if (value == null) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         // 类型已匹配、直接返回 | ||||
|         if (targetType.isInstance(value)) { | ||||
|             return value; | ||||
|         } | ||||
|  | ||||
|         // 1. 数字类型转换(int/long/double等) | ||||
|         if (targetType == Integer.class || targetType == int.class) { | ||||
|             return ((Number) value).intValue(); | ||||
|         } else if (targetType == Long.class || targetType == long.class) { | ||||
|             return ((Number) value).longValue(); | ||||
|         } else if (targetType == Double.class || targetType == double.class) { | ||||
|             return ((Number) value).doubleValue(); | ||||
|         } else if (targetType == Float.class || targetType == float.class) { | ||||
|             return ((Number) value).floatValue(); | ||||
|         } | ||||
|  | ||||
|         // 2. 布尔类型转换(支持数字/字符串转布尔) | ||||
|         else if (targetType == Boolean.class || targetType == boolean.class) { | ||||
|             if (value instanceof Number) { | ||||
|                 return ((Number) value).intValue() != 0; | ||||
|             } else if (value instanceof String) { | ||||
|                 return "true".equalsIgnoreCase((String) value); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 3. 字符串类型转换(所有类型转String) | ||||
|         else if (targetType == String.class) { | ||||
|             return value.toString(); | ||||
|         } | ||||
|  | ||||
|         // 4. 日期类型转换(java.util.Date) | ||||
|         else if (targetType == Date.class) { | ||||
|             if (value instanceof Timestamp) { | ||||
|                 return new Date(((Timestamp) value).getTime()); | ||||
|             } else if (value instanceof LocalDateTime) { | ||||
|                 // 支持LocalDateTime转Date(如需) | ||||
|                 return Date.from(((LocalDateTime) value).atZone(java.time.ZoneId.systemDefault()).toInstant()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 5. 新增:LocalDateTime类型转换(SQLite TEXT → Java LocalDateTime) | ||||
|         else if (targetType == LocalDateTime.class) { | ||||
|             if (value instanceof String) { | ||||
|                 try { | ||||
|                     // 解析数据库存储的ISO格式字符串(如"2025-09-18T17:30:27.143") | ||||
|                     return LocalDateTime.parse((String) value, LOCAL_DATE_TIME_FORMATTER); | ||||
|                 } catch (DateTimeParseException e) { | ||||
|                     System.err.println("警告: 日期解析失败、字符串=" + value + "、格式应为yyyy-MM-dd'T'HH:mm:ss.SSS - " + e.getMessage()); | ||||
|                     return null; | ||||
|                 } | ||||
|             } else if (value instanceof Timestamp) { | ||||
|                 // 兼容Timestamp类型(如其他数据库迁移场景) | ||||
|                 return ((Timestamp) value).toLocalDateTime(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 6. 新增:byte[]类型转换(SQLite BLOB → Java byte[]) | ||||
|         else if (targetType == byte[].class && value instanceof Blob) { | ||||
|             Blob blob = (Blob) value; | ||||
|             try { | ||||
|                 return blob.getBytes(1, (int) blob.length()); | ||||
|             } catch (SQLException e) { | ||||
|                 System.err.println("警告: BLOB转byte[]失败 - " + e.getMessage()); | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 无法转换时返回原始值(避免崩溃、打印警告) | ||||
|         System.err.println("警告: 不支持的类型转换、目标类型=" + targetType.getName() + "、原始值类型=" + value.getClass().getName()); | ||||
|         return value; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行DDL语句(CREATE, ALTER, DROP等) | ||||
|      */ | ||||
|     private static void executeDDL(String dbFilePath, String sql, List<Object> params) throws SQLException { | ||||
|         try (Connection conn = getConnection(dbFilePath); | ||||
|              PreparedStatement pstmt = createPreparedStatement(conn, sql, params)) { | ||||
|             pstmt.execute(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行无参数的DDL语句 | ||||
|      */ | ||||
|     public static void executeDDL(String dbFilePath, String sql) { | ||||
|         try { | ||||
|             executeDDL(dbFilePath, sql, null); | ||||
|         } catch (SQLException e) { | ||||
|             throw new RuntimeException("执行DDL语句失败、SQL=" + sql, e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行查询并返回count结果 | ||||
|      */ | ||||
|     public static int queryForCount(String dbFilePath, String sql, List<Object> params) throws SQLException { | ||||
|         try (Connection conn = getConnection(dbFilePath); | ||||
|              PreparedStatement pstmt = createPreparedStatement(conn, sql, params); | ||||
|              ResultSet rs = pstmt.executeQuery()) { | ||||
|  | ||||
|             if (rs.next()) { | ||||
|                 return rs.getInt(1); | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行无参数的查询并返回count结果 | ||||
|      */ | ||||
|     public static int queryForCount(String dbFilePath, String sql) throws SQLException { | ||||
|         return queryForCount(dbFilePath, sql, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 初始化数据库表(model_type + model) | ||||
|      */ | ||||
|     public static void initialization(String modelPath) { | ||||
|         // 创建模型类型表 | ||||
|         String sql = """ | ||||
|                     CREATE TABLE "model_type" ( | ||||
|                       "id" TEXT, | ||||
|                       "name" TEXT, | ||||
|                       "parent_id" TEXT, | ||||
|                       "created_at" TEXT, | ||||
|                       "updated_at" TEXT, | ||||
|                       PRIMARY KEY ("id") | ||||
|                     ); | ||||
|                 """; | ||||
|         executeDDL(modelPath, sql); | ||||
|  | ||||
|         // 创建模型表 | ||||
|         sql = """ | ||||
|                   CREATE TABLE "model" ( | ||||
|                     "id" TEXT, | ||||
|                     "model_type_id" TEXT, | ||||
|                     "model_name" TEXT, | ||||
|                     "model_type" TEXT, | ||||
|                     "poster_type" TEXT, | ||||
|                     "poster" TEXT, | ||||
|                     "data" TEXT, | ||||
|                     "view" TEXT, | ||||
|                     "created_at" TEXT, | ||||
|                     "updated_at" TEXT, | ||||
|                     PRIMARY KEY ("id") | ||||
|                   ); | ||||
|                 """; | ||||
|         executeDDL(modelPath, sql); | ||||
|     } | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 ZZX9599
					ZZX9599