关于Spring JDBC RowMapper的一点改进思路

【注】通常我们使用RowMapper(比如ParameterizedRowMapper),都需要定义好查询字段,如果使用别名就没办法了。还要比如加入group,或者联合查询,也不能够使用,除非不想要非主体Bean之外的字段,那么只能用Map接收返回结果了,或者直接实现RowMapper。基于这一点,提出一个稍微通用的解决思路:所有的Bean都继承一个基类Bean,里面放一个Map(就是存放那些Bean没有指定的字段了,比如sum、count、avg … 各种查询字段或者别名),参考BeanPropertyRowMapper,在mapRow方法里面做些小调整,找不到的column就放到map里面,这样子的话,Bean有的字段就采用getxxx(),没有就从map里面取,好像会有点用。

#具体方法如下#

public abstract class BaseEntity {

    private Map<String, Object> aliasFields = new HashMap<String, Object>();

    public void setAliasField(String field, Object value) {
        aliasFields.put(field, value);
    }

    public Object getAliasFields(String field) {
        return aliasFields.get(field);
    }
}  

该类中只放一个map,存储Bean里面没有的字段,剩下的就是改造RowMapper实现类,可以拷贝BeanPropertyRowMapper,换个类名,直接修改mapRow方法,具体如下(改动量非常小,看注释):

public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
    Assert.state(this.mappedClass != null, "Mapped class was not specified");
    T mappedObject = BeanUtils.instantiate(this.mappedClass);
    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
    initBeanWrapper(bw);

    ResultSetMetaData rsmd = rs.getMetaData();
    int columnCount = rsmd.getColumnCount();
    Set<String> populatedProperties = (isCheckFullyPopulated() ? new HashSet<String>() : null);

    for (int index = 1; index <= columnCount; index++) {
        String column = JdbcUtils.lookupColumnName(rsmd, index);
        PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase());
        if (pd != null) {
            try {
                Object value = getColumnValue(rs, index, pd);
                if (logger.isDebugEnabled() && rowNumber == 0) {
                    logger.debug("Mapping column ‘" + column + "‘ to property ‘" +
                            pd.getName() + "‘ of type " + pd.getPropertyType());
                }
                try {
                    bw.setPropertyValue(pd.getName(), value);
                }
                catch (TypeMismatchException e) {
                    if (value == null && primitivesDefaultedForNullValue) {
                        logger.debug("Intercepted TypeMismatchException for row " + rowNumber +
                                " and column ‘" + column + "‘ with value " + value +
                                " when setting property ‘" + pd.getName() + "‘ of type " + pd.getPropertyType() +
                                " on object: " + mappedObject);
                    }
                    else {
                        throw e;
                    }
                }
                if (populatedProperties != null) {
                    populatedProperties.add(pd.getName());
                }
            }
            catch (NotWritablePropertyException ex) {
                throw new DataRetrievalFailureException(
                        "Unable to map column " + column + " to property " + pd.getName(), ex);
            }
        } else {/// *****就是修改这个地方了!!!!
            Object value = JdbcUtils.getResultSetValue(rs, index);
            ((BaseEntity)mappedObject).setAliasField(column, value);
        }
    }

    if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) {
        throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " +
                "necessary to populate object of class [" + this.mappedClass + "]: " + this.mappedProperties);
    }

    return mappedObject;
}

剩下的就是具体的Bean,继承BaseEntity,比如:

public class Demo extends BaseEntity implements Serializable {

    public static final long serialVersionUID = 2233912281609962999L;

    private Integer id;
    private String name;
    private String password;
    private Date createTime;
    private Integer type;

    public Demo() {
        super.queryBuilder = new QueryBuilder(this);
    }

    public void setId (Integer id) {
        this.id = id;
    }
    public Integer getId () {
        return this.id;
    }
    public void setName (String name) {
        this.name = name;
    }
    public String getName () {
        return this.name;
    }
    public void setPassword (String password) {
        this.password = password;
    }
    public String getPassword () {
        return this.password;
    }
    public void setCreateTime (Date createTime) {
        this.createTime = createTime;
    }
    public Date getCreateTime () {
        return this.createTime;
    }
    public void setType (Integer type) {
        this.type = type;
    }
    public Integer getType () {
        return this.type;
    }
}

查询的时候,就可以通过Demo Bean取出非表字段的数据,通过getAliasFields(String field)方法。个人感觉能够提高一定的便捷性,后续会加入sbrom中,关于sbrom可以查看http://blog.csdn.net/yefeng_918/article/details/44747033,欢迎吐槽!

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。