我想使用Apache DBUtils
库从DB填充POJO(State.java)。但是,由于Bean属性的名称与DB列名称不完全匹配,因此某些属性未填充。
现在,我通过谷歌搜索做了一些研究,发现这可以通过以下方式实现:
有人能提供一个很好的例子来说明如何使用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,
)
State.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
}
Main.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);
}
}
}
答案 0 :(得分:3)
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);
答案 1 :(得分: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
答案 2 :(得分:1)
如果你看一下BeanProcessor的Java文档:
protected int [] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor []道具) 抛出SQLException
返回数组中的位置代表列号。每个存储的值 position表示bean的PropertyDescriptor []中的索引 与列名匹配的属性。如果没有找到bean属性 对于列,位置设置为PROPERTY_NOT_FOUND。参数: rsmd - 包含列信息的ResultSetMetaData。道具 - 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())));
免责声明:我尚未测试此代码。它旨在向您展示您可以组合在一起以获得自定义字段映射的各个部分。如果您发现它有问题,可以告诉我,以便我可以查看。
答案 3 :(得分:1)
我已经回答了类似的so question here。
您可以使用GenerousBeanProcessor
这是BeanProcessor
的子类,它会忽略下划线和&amp;列名称的区分大小写。您不必为此特定情况实施自己的自定义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());
}
答案 4 :(得分:0)
这可以使用 MapListHandler 和 Jackson 轻松完成,无需定义自定义 bean 处理器或提供列映射。
将您的 POJO 更改为
public class State implements Serializable {
@JsonProperty("state_id")//db column name
private int stateId;
@JsonProperty("state_cd")
private String stateCode;
//and so on ....
}
使用 MapListHandler 和 Jackson 获取响应并将其映射到 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
这种方法可以让您更好地控制将 DB 列映射到 POJO 字段。