Spring Boot中基于RowCallBackHandler动态设置DTO属性
动态设置Response属性的解决方案
首先修正你代码里的几处笔误:@Cloumn应为@Column,RowCallBackHandler的方法名是processRow而非processRows,SqlException应为SQLException。
以下是两种实用的动态属性赋值方案:
方案1:反射 + ResultSetMetaData
通过ResultSet元数据获取返回列名,转换为实体驼峰属性名后,用反射完成赋值。
List<String> userSelectionList = getUserSelectionList(); String sql = generateSqlBasedOnUserSelection(); List<Response> responseList = new ArrayList<>(); jdbcTemplate.query(sql, new RowCallbackHandler() { @Override public void processRow(ResultSet resultSet) throws SQLException { Response response = new Response(); ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { // 获取数据库列名(如NAME) String columnName = metaData.getColumnName(i); // 转换为驼峰属性名(如name) String propertyName = toCamelCase(columnName); Object value = resultSet.getObject(i); try { Field field = Response.class.getDeclaredField(propertyName); field.setAccessible(true); field.set(response, value); } catch (NoSuchFieldException | IllegalAccessException e) { // 实际项目建议用日志记录异常,而非直接打印 e.printStackTrace(); } } responseList.add(response); } }); // 辅助方法:数据库列名转驼峰属性名 private String toCamelCase(String columnName) { if (columnName == null || columnName.isEmpty()) { return columnName; } columnName = columnName.toLowerCase(); StringBuilder sb = new StringBuilder(); boolean nextUpperCase = false; for (char c : columnName.toCharArray()) { if (c == '_') { nextUpperCase = true; } else { sb.append(nextUpperCase ? Character.toUpperCase(c) : c); nextUpperCase = false; } } return sb.toString(); }
方案2:Spring BeanWrapper(更简洁)
利用Spring自带的BeanWrapper工具,自动处理类型转换和属性赋值,无需手动编写反射逻辑。
List<String> userSelectionList = getUserSelectionList(); String sql = generateSqlBasedOnUserSelection(); List<Response> responseList = new ArrayList<>(); jdbcTemplate.query(sql, new RowCallbackHandler() { @Override public void processRow(ResultSet resultSet) throws SQLException { Response response = new Response(); BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(response); ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { String columnName = metaData.getColumnName(i); String propertyName = toCamelCase(columnName); // 先检查属性是否可写,避免无效赋值报错 if (wrapper.isWritableProperty(propertyName)) { Object value = resultSet.getObject(i); wrapper.setPropertyValue(propertyName, value); } } responseList.add(response); } }); // 复用上面的toCamelCase方法 private String toCamelCase(String columnName) { if (columnName == null || columnName.isEmpty()) { return columnName; } columnName = columnName.toLowerCase(); StringBuilder sb = new StringBuilder(); boolean nextUpperCase = false; for (char c : columnName.toCharArray()) { if (c == '_') { nextUpperCase = true; } else { sb.append(nextUpperCase ? Character.toUpperCase(c) : c); nextUpperCase = false; } } return sb.toString(); }
注意事项
- 属性访问:使用BeanWrapper时,Response类需为属性提供setter方法;反射方案则需通过
field.setAccessible(true)绕过私有属性访问限制。 - 映射规则:如果列名与属性名的映射不是简单驼峰转换,可维护一个
Map<String, String>映射表来对应。 - 异常处理:实际项目中建议用日志框架记录异常,避免直接打印堆栈信息。
内容的提问来源于stack exchange,提问作者sushant shekhar
相关产品推荐
相关产品推荐

