最智能listMap转bean方法

本文介绍如何利用阿里FastJSON库将List<Map>转换为List<DnsResolution>对象列表,实现数据类型转换并保持大小写不敏感。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

List<Map> listMap = mapper.getListMapData(query);

 List<DnsResolution> listDnsKpiGridData = JSON.parseArray(JSON.toJSONString(listMap), DnsResolution.class);


这个需要用到阿里的jar包(fastjson)


转换方便,大小写不敏感。

<think>我们之前已经讨论了根据Bean生成SQL的几种方法,包括使用JPA、MyBatis以及自定义反射生成器。现在用户希望基于Bean对象实现自定义SQL生成器,并支持生成update和count语句。根据引用[1]和[4]中提到的动态SQL生成思想,以及引用[2]中MyBatis-Plus的@SelectProvider方式,我们可以设计一个基于反射的自定义SQL生成器,支持生成INSERT、UPDATE、COUNT等语句。###设计思路1.**注解定义**:定义用于标记表名和字段名的注解(如`@Table`,`@Column`)。2.**反射处理**:通过反射读取Bean的字段和注解信息,动态构建SQL语句。3.**空值处理**:对于UPDATE语句,只更新非空字段;对于COUNT语句,只生成简单的计数查询。4.**防止SQL注入**:生成参数化SQL(使用占位符?)而不是直接拼接值。###实现步骤####1.定义注解```javaimportjava.lang.annotation.*;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceTable{Stringname();}@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceColumn{Stringname();//是否为主键booleanisPrimaryKey()defaultfalse;//是否在更新时忽略空值booleanignoreNull()defaulttrue;}```####2.实现SQL生成器```javaimportjava.lang.reflect.Field;importjava.util.ArrayList;importjava.util.List;publicclassSQLGenerator{//生成INSERT语句(带占位符?)publicstaticStringgenerateInsert(Objectentity){Class<?>clazz=entity.getClass();Tabletable=clazz.getAnnotation(Table.class);if(table==null){thrownewRuntimeException("Missing@Tableannotation");}List<String>columns=newArrayList<>();List<String>placeholders=newArrayList<>();for(Fieldfield:clazz.getDeclaredFields()){field.setAccessible(true);Columncolumn=field.getAnnotation(Column.class);if(column!=null){try{Objectvalue=field.get(entity);//如果字段值为空且设置了ignoreNull,则跳过if(value==null&&column.ignoreNull()){continue;}columns.add(column.name());placeholders.add("?");}catch(IllegalAccessExceptione){thrownewRuntimeException(e);}}}returnString.format("INSERTINTO%s(%s)VALUES(%s)",table.name(),String.join(",",columns),String.join(",",placeholders));}//生成UPDATE语句(带占位符?)publicstaticStringgenerateUpdate(Objectentity){Class<?>clazz=entity.getClass();Tabletable=clazz.getAnnotation(Table.class);if(table==null){thrownewRuntimeException("Missing@Tableannotation");}List<String>setClauses=newArrayList<>();StringwhereClause=null;for(Fieldfield:clazz.getDeclaredFields()){field.setAccessible(true);Columncolumn=field.getAnnotation(Column.class);if(column!=null){try{Objectvalue=field.get(entity);//主键用于WHERE条件if(column.isPrimaryKey()){if(value==null){thrownewRuntimeException("Primarykeycannotbenullforupdate");}whereClause=column.name()+"=?";continue;}//非主键字段,如果值为空且忽略空值,则不更新if(value==null&&column.ignoreNull()){continue;}setClauses.add(column.name()+"=?");}catch(IllegalAccessExceptione){thrownewRuntimeException(e);}}}if(setClauses.isEmpty()){thrownewRuntimeException("Nofieldstoupdate");}if(whereClause==null){thrownewRuntimeException("Noprimarykeyfoundforupdatecondition");}returnString.format("UPDATE%sSET%sWHERE%s",table.name(),String.join(",",setClauses),whereClause);}//生成COUNT语句(无条件)publicstaticStringgenerateCount(Class<?>clazz){Tabletable=clazz.getAnnotation(Table.class);if(table==null){thrownewRuntimeException("Missing@Tableannotation");}return"SELECTCOUNT(*)FROM"+table.name();}//生成带条件的COUNT语句(动态条件,参考引用[1]和[4]的动态条件思想)//这里简单示例,实际可扩展动态条件publicstaticStringgenerateCountByCondition(Class<?>clazz,Stringcondition){StringbaseSql=generateCount(clazz);if(condition!=null&&!condition.trim().isEmpty()){returnbaseSql+"WHERE"+condition;}returnbaseSql;}}```####3.使用示例```java@Table(name="users")publicclassUser{@Column(name="id",isPrimaryKey=true)privateLongid;@Column(name="user_name")privateStringname;@Column(name="age")privateIntegerage;//gettersandsetters}publicclassMain{publicstaticvoidmain(String[]args){Useruser=newUser();user.setId(1L);user.setName("Alice");//age为null//生成INSERT语句(忽略空值age)StringinsertSQL=SQLGenerator.generateInsert(user);System.out.println(insertSQL);//输出:INSERTINTOusers(id,user_name)VALUES(?,?)//生成UPDATE语句(忽略空值age,使用id作为条件)StringupdateSQL=SQLGenerator.generateUpdate(user);System.out.println(updateSQL);//输出:UPDATEusersSETuser_name=?WHEREid=?//生成COUNT语句StringcountSQL=SQLGenerator.generateCount(User.class);System.out.println(countSQL);//输出:SELECTCOUNT(*)FROMusers//生成带条件的COUNT语句StringcountConditionSQL=SQLGenerator.generateCountByCondition(User.class,"age>18");System.out.println(countConditionSQL);//输出:SELECTCOUNT(*)FROMusersWHEREage>18}}```###关键点说明1.**空值处理**:通过`@Column(ignoreNull=true)`控制是否忽略空值字段(在INSERT和UPDATE中)。2.**主键识别**:使用`@Column(isPrimaryKey=true)`标记主键,UPDATE语句中自动作为WHERE条件。3.**动态条件**:COUNT语句的条件可以动态传入,更复杂的条件可参考引用[1]中的WhereHelper思想或引用[2]的Provider方式。4.**防注入处理**:生成的SQL使用占位符`?`,实际执行时通过PreparedStatement设置参数。###扩展建议1.**复杂条件生成**:参考引用[1]的`IfElseWhereHelper`注解实现条件分支,或引用[4]的默认值语法(如`{{andtype=[type,default,1]}}`)。2.**性能优化**:缓存类的元数据(如字段列表、注解信息)避免重复反射。3.**类型转换**:处理日期、枚举等特殊类型(可扩展为每个字段的类型转换器)。###相关问题1.如何实现动态WHERE条件(如根据Bean中的非空字段自动生成条件)?2.如何扩展SQL生成器以支持JOIN操作?3.怎样处理数据库字段和Java字段的命名转换(如驼峰下划线)?4.如何保证生成的SQL语句在不同数据库中的兼容性?5.怎样实现分页查询的SQL生成?[^1]:sql2java:WhereHelper基于Beanshell(bsh)动态生成SQL语句[^2]:MyBatis-Plus通过@SelectProvider动态生成SQL[^4]:Mybatis自定义Sql模板语法</think>### 基于 Bean 的自定义 SQL 生成器实现(支持 UPDATE/COUNT) 根据您的需求,结合引用[1][2][4]的动态 SQL 思想,我设计了一个基于反射的自定义 SQL 生成器,支持生成 UPDATE 和 COUNT 语句。以下是完整实现: #### 1. 注解定义(核心元数据) ```java // 表注解 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String name(); } // 字段注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String name(); // 数据库字段名 boolean isPrimaryKey() default false; // 是否主键 boolean ignoreNull() default true; // UPDATE 时是否忽略 null 值 } // 动态条件注解(引用[1]思想) @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Condition { String operator() default "="; // 操作符:=, >, <, LIKE String defaultValue() default ""; // 引用[4]的默认值机制 } ``` #### 2. SQL 生成器核心类 ```java import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class SQLGenerator { // 生成 UPDATE 语句 public static <T> String generateUpdate(T entity) { Class<?> clazz = entity.getClass(); Table table = clazz.getAnnotation(Table.class); if (table == null) throw new SQLGenerationException("Missing @Table annotation"); StringBuilder setClause = new StringBuilder(); StringBuilder whereClause = new StringBuilder(" WHERE "); List<Object> values = new ArrayList<>(); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); Column column = field.getAnnotation(Column.class); if (column == null) continue; try { Object value = field.get(entity); Condition condition = field.getAnnotation(Condition.class); // 主键处理(WHERE 条件) if (column.isPrimaryKey()) { if (value == null) throw new SQLGenerationException("Primary key cannot be null"); whereClause.append(column.name()).append(" = ?"); values.add(value); continue; } // 空值处理(引用[4]默认值机制) if (value == null && condition != null && !condition.defaultValue().isEmpty()) { value = condition.defaultValue(); } // SET 子句生成 if (value != null || !column.ignoreNull()) { setClause.append(column.name()).append(" = ?, "); values.add(value); } } catch (IllegalAccessException e) { throw new SQLGenerationException("Field access error", e); } } // 移除末尾逗号 if (setClause.length() > 0) { setClause.setLength(setClause.length() - 2); } return "UPDATE " + table.name() + " SET " + setClause + whereClause; } // 生成 COUNT 语句(引用[1]条件表达式思想) public static <T> String generateCount(Class<T> clazz, T conditionBean) { Table table = clazz.getAnnotation(Table.class); if (table == null) throw new SQLGenerationException("Missing @Table annotation"); StringBuilder whereClause = new StringBuilder(); List<Object> params = new ArrayList<>(); if (conditionBean != null) { for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); Column column = field.getAnnotation(Column.class); Condition condition = field.getAnnotation(Condition.class); if (column == null || condition == null) continue; try { Object value = field.get(conditionBean); if (value == null && !condition.defaultValue().isEmpty()) { value = condition.defaultValue(); // 应用默认值 } if (value != null) { whereClause.append(" AND ") .append(column.name()) .append(" ") .append(condition.operator()) .append(" ?"); params.add(value); } } catch (IllegalAccessException e) { throw new SQLGenerationException("Field access error", e); } } } String baseSQL = "SELECT COUNT(*) FROM " + table.name(); return whereClause.length() > 0 ? baseSQL + " WHERE 1=1" + whereClause : baseSQL; } } // 自定义异常 class SQLGenerationException extends RuntimeException { public SQLGenerationException(String message) { super(message); } public SQLGenerationException(String message, Throwable cause) { super(message, cause); } } ``` #### 3. 使用示例 ```java // 实体定义 @Table(name = "users") public class User { @Column(name = "id", isPrimaryKey = true) private Long id; @Column(name = "username") @Condition(operator = "LIKE", defaultValue = "%admin%") private String name; @Column(name = "age", ignoreNull = false) @Condition(operator = ">") private Integer age; // getters/setters } // 更新操作 User updateUser = new User(); updateUser.setId(1L); updateUser.setName("Alice"); // age 保持为 null String updateSQL = SQLGenerator.generateUpdate(updateUser); // 生成: UPDATE users SET username = ? WHERE id = ? // 参数: ["Alice", 1] // 计数查询 User query = new User(); query.setName("Bob"); // 显式设置值 // age 未设置,将使用注解默认值 String countSQL = SQLGenerator.generateCount(User.class, query); // 生成: SELECT COUNT(*) FROM users WHERE 1=1 // AND username LIKE ? // AND age > ? // 参数: ["Bob", "%admin%"] ``` ### 关键特性说明 1. **动态条件生成**(引用[1][4]): - 通过 `@Condition` 注解支持运算符和默认值 - 空值自动处理:当字段为 null 时使用默认值或跳过 - 示例:`@Condition(operator = ">", defaultValue = "18")` 2. **UPDATE 智能处理**: - 主键自动作为 WHERE 条件 - `ignoreNull` 控制是否更新 null 值 - 示例:`@Column(ignoreNull = true)` 跳过 null 字段更新 3. **COUNT 动态条件**: - 基于条件 Bean 生成 WHERE 子句 - 自动添加 `1=1` 简化条件拼接 - 支持混合条件(显式值 + 默认值) 4. **防 SQL 注入**: - 全参数化查询(使用 `?` 占位符) - 值与应用层分离 ### 进阶优化建议 1. **类型转换器**: ```java public interface TypeHandler { Object convert(Object fieldValue); } // 注册处理器处理 Date/Enum 等特殊类型 ``` 2. **条件表达式扩展**(引用[1]): ```java @Condition(test = "age != null", doStatement = "AND age > #{age}", elseStatement = "AND age > 18") ``` 3. **缓存优化**: ```java // 缓存类元数据避免重复反射 private static final Map<Class<?>, TableMetadata> METADATA_CACHE = new ConcurrentHashMap<>(); ``` 4. **分页支持**: ```java public String generatePageQuery(Class<?> clazz, int page, int size) { return generateSelect(clazz) + " LIMIT " + size + " OFFSET " + (page-1)*size; } ``` ### 相关问题 1. 如何实现嵌套对象的 SQL 条件生成(如 `user.address.city`)? 2. 怎样处理数据库字段和 Java 字段的命名转换(驼峰/下划线)? 3. 如何实现动态排序(`ORDER BY`)子句的生成? 4. 怎样扩展支持 `BETWEEN`、`IN` 等复杂条件运算符? 5. 如何与 Spring JDBC 或 MyBatis 集成使用? > 本实现结合了引用[1]的条件表达式思想、引用[2]的 Provider 动态生成模式和引用[4]的默认值机制,实现了基于 Bean 的安全 SQL 生成方案[^1][^2][^4]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值