You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:48:10