2

我想使用Apache DBUtils库从 DB 填充 POJO(State.java)。但是,由于 Bean 属性的名称与 DB 列名称不完全匹配,因此某些属性未填写。

现在,我通过谷歌搜索对此进行了一些研究,发现可以通过以下方式实现:

  1. 编写 SQL 查询时的列别名(我不喜欢这样做,因为我在一些较大的表中有多个连接,因此需要大量的别名)
  2. 使用 BeanProcessor(在任何地方都找不到一个很好的例子)

谁能提供一个很好的例子来说明如何使用BeanProcessor将列名映射到属性?调整提供给我的示例会更好。

数据库表

CREATE TABLE public.states (
  state_id INTEGER DEFAULT nextval('states_seq'::regclass) NOT NULL,
  state_cd VARCHAR(2) NOT NULL,
  name VARCHAR(100) NOT NULL,
  tax_pct NUMERIC(10,2) DEFAULT 0.00 NOT NULL,
  active CHAR(1) DEFAULT 'Y'::bpchar NOT NULL,
) 

状态.java

  public class State implements Serializable {

    private int stateId;
    private String stateCode;
    private String name;
    private BigDecimal taxPct = new BigDecimal(0);
    private Date expiryDate;
    private String createdBy;
    private Date createdOn;
    private String active;

    //getters and setters here
}

主.java

    public class Main {

    public static void main(String[] args) {
        String url = "jdbc:postgresql://gsi-547576.gsiccorp.net:5432/istore-db";
        String driver = "org.postgresql.Driver";
        String user = "postgres";
        String pwd = "postgres";
        Connection conn = null;
        List<State> states = null;

        try {
            DbUtils.loadDriver(driver);
            conn = DriverManager.getConnection(url, user, pwd);

            states = (List<State>) new QueryRunner().query(conn, "select * from states a where a.active='Y'", new BeanListHandler(State.class);

            System.out.println("states::  " + states);

        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            DbUtils.closeQuietly(conn);
        }
    }

}
4

5 回答 5

7
Map<String,String> mapColumnsToProperties = new HashMap<>();
//mapping you database to entity here;
mapColumnsToProperties.put("database_column","entity_property");
BeanProcessor beanProcessor = new BeanProcessor(mapColumnsToProperties);
RowProcessor rowProcessor = new BasicRowProcessor( beanProcessor); 
ResultSetHandler<List<Entity>> resultSetHandler = new BeanListHandler<Entity>(Entity.class,rowProcessor);
List<Entity> entityLists = queryRunner.query(findListSQL, resultSetHandler);    
于 2016-12-21T07:32:04.750 回答
2

我来自中国,我的英语不是很好;但是这个问题,这是我的解决方法:因为dbutils是开源的,你可以修改源代码,使用maven为你制作一个jar,我只是修改了BeanProcessor类,你可以添加一个这样的方法changeColumnName

public  String changeColumnName(String columnName){
        if(columnName == null){
            return null;
        }
        if(columnName.contains("_")){
            char[] cs = columnName.toCharArray();
            int flag = -1;
            for(int index=0;index<columnName.toCharArray().length;index++){
                if(cs[index] == '_'){
                    flag = index;
                    break;
                }
            }
            columnName = columnName.substring(0, flag) + columnName.substring(flag+1,flag+2).toUpperCase() + columnName.substring(flag+2);
            return changeColumnName(columnName);
        }else{
            return columnName;
        }
    }

并且在方法中

protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
        PropertyDescriptor[] props) throws SQLException {

    int cols = rsmd.getColumnCount();
    int[] columnToProperty = new int[cols + 1];
    Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);

    for (int col = 1; col <= cols; col++) {
        String columnName = rsmd.getColumnLabel(col);
        if (null == columnName || 0 == columnName.length()) {
          columnName = rsmd.getColumnName(col);
        }
        String propertyName = columnToPropertyOverrides.get(columnName);
        if (propertyName == null) {
            propertyName = changeColumnName(columnName);//add here
        }
        for (int i = 0; i < props.length; i++) {

            if (propertyName.equalsIgnoreCase(props[i].getName())) {
                columnToProperty[col] = i;
                break;
            }
        }
    }

    return columnToProperty;
}

它可以解决问题。欢迎与我讨论。我的谷歌电子邮件是guomin.bai@gmail.com

于 2016-08-26T06:41:39.313 回答
2

我已经在这里回答了类似的问题

您可以使用GenerousBeanProcessor它的子类,BeanProcessor它会忽略列名中的下划线和区分大小写。BeanProcessor对于这种特殊情况,您不必实现自己的自定义。

GenerousBeanProcessor从commons-dbutils 1.6 版开始可用。

用法:

// TODO initialize
QueryRunner queryRunner = null;

ResultSetHandler<List<State>> resultSetHandler =
                new BeanListHandler<State>(State.class, new BasicRowProcessor(new GenerousBeanProcessor()));

// best practice is mentioning only required columns in the query
final List<State> states = queryRunner.query("select * from states a where a.active='Y'", resultSetHandler);

for (State state : states) {
    System.out.println(state.getStateId());
}
于 2017-11-09T06:36:10.103 回答
1

如果您查看 BeanProcessor 的 Java 文档:

protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) 抛出 SQLException

返回数组中的位置表示列号。存储在每个位置的值表示与列名匹配的 bean 属性的 PropertyDescriptor[] 中的索引。如果没有找到某个列的 bean 属性,则将位置设置为 PROPERTY_NOT_FOUND。参数: rsmd - 包含列信息的 ResultSetMetaData。props - bean 属性描述符。返回:具有列索引到属性索引映射的 int[]。第 0 个元素没有意义,因为 JDBC 列索引从 1 开始。

看起来您需要创建一个扩展BeanProcessor并覆盖该mapColumnsToProperties方法的类,如下所示:

public class StateBeanProcessor extends BeanProcessor {

    @Override
    protected  int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException {
          int[] mapping = super.mapColumnsToProperties(rsmd, props);
          /*Map database columns to fields in the order in which they appear
            1st column in the DB will be mapped to 1st field in the Java
            class and so on.. */
          for(int i=0;i<mapping.length;++i) {
             mapping[i]=i;
          }
      }
  }

然后,您可以将上述 StateBeanProcessor 插入到您的代码中,如下所示:

states = (List<State>) new QueryRunner().query(conn, "select * from states", new BeanListHandler(State.class,new BasicRowProcessor(new StateBeanProcessor())));

免责声明:我没有测试过这段代码。它旨在向您展示可以组合在一起以进行自定义字段映射的点点滴滴。如果您发现它有问题,可以让我知道,以便我进行调查。

于 2015-04-24T14:24:27.163 回答
0

这可以使用 MapListHandler 和 Jackson 轻松完成,无需定义自定义 bean 处理器或提供列映射。

  1. 将您的 POJO 更改为

     public class State implements Serializable {
    
     @JsonProperty("state_id")//db column name
     private int stateId;
    
     @JsonProperty("state_cd")
     private String stateCode;
    
     //and so on ....
    

    }

  2. 使用带有 Jackson 的 MapListHandler 来获取和映射到 POJO 的响应。

ObjectMapper objectMapper = new ObjectMapper();
List<State> stateList = new QueryRunner().query(connection, query, new MapListHandler())
.stream().map(response -> objectMapper.convertValue(response, State.class))
.collect(Collectors.toList());

在这种方法中,您首先获取 List<Map<String, Object>> 这是一个记录列表,每条记录都来自列名和值的映射,可以使用 Jackson 的 convertValue 方法映射到 POJO(将使用@JsonProperty 注解将该列映射到 POJO 字段)。

这种方法将使您更好地控制将 DB 列映射到 POJO 字段。

于 2021-02-23T19:42:08.587 回答