一个加速产生 Spring JDBC RowMapper 的工具类

在使用Spring JdbcTemplate 时,编写 RowMapper 实在是一件累人的工作。于是我写了一个根据实体类产生 RowMapper 的工厂类 RowMapperFactory,来避免直接编写 RowMapper。RowMapperFactory 暂不支持枚举。

下面就是 RowMapperFactory:

import org.springframework.jdbc.core.RowMapper;

import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

public class RowMapperFactory {

    public static <K> RowMapper<K> getInstance(Class<K> clazz) {
        return getRowMapper(clazz);
    }

    public static <K> RowMapper<K> getRowMapper(Class<K> clazz) {

        return new RowMapper<K>() {

            private AutoRowMapper<K> rm = new AutoRowMapper(clazz);

            @Override
            public K mapRow(ResultSet rs, int rowNum) throws SQLException {
                try {
                    return rm.mapRow(rs, rowNum, clazz.newInstance());
                }
                catch (InstantiationException | IllegalAccessException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        };
    }

    /**
     * 这是一个用于简化 rowMapper 的编写辅助类。
     * <p/>
     * 本类会自动跳过 entity 中存在,但是在查询语句中不存在的列。
     *
     * @param <T> entity type
     */
    private static class AutoRowMapper<T> {

        private Map<String, String> colName2SetterMap = new HashMap<>(); // 数据列名到 setter 名称的映射
        private Map<String, Method> setterMap = new HashMap<>();         // setter 名称到 setter 方法的映射
        private Map<String, String> setterParamMap = new HashMap<>();    // setter 名称到 setter 参数类型的映射

        /**
         * 初始化
         *
         * @param t 实体类的类对象
         */
        protected <T> AutoRowMapper(Class<T> t) {
            Method[] ms = t.getMethods();
            for (int i = 0; i < ms.length; i++) {
                String name = ms[i].getName();
                if (name.startsWith("set") && ms[i].getParameterCount() == 1) {
                    setterMap.put(name, ms[i]);
                    setterParamMap.put(name, ms[i].getGenericParameterTypes()[0].getTypeName());
                    colName2SetterMap.put(setterToColName(name), name);
                }
            }
        }

        /**
         * 在子类中,要实现的 RowMapper.mapRow 中掉用此方法。
         *
         * @param rs     结果集
         * @param rowNum 结果集行号
         * @param t      entity 对象,用于装填查询结果行数据
         * @return 传入的 entity 对象
         */
        public T mapRow(ResultSet rs, int rowNum, T t) {

            for (String col : colName2SetterMap.keySet()) {
                try {
                    int index = rs.findColumn(col); // 如果找不到列,就会抛出异常
                    String setterName = colName2SetterMap.get(col);
                    inject(setterMap.get(setterName), setterParamMap.get(setterName), rs, index, t);
                } catch (SQLException ex) {
                    continue;
                }
            }
            return t;
        }

        /**
         * 把 setter 名称转换为列名。如 setCreatedOn --> created_on
         */
        private static String setterToColName(String setterName) {
            String property = setterName.substring(3, setterName.length());
            StringBuilder sb = new StringBuilder().append(property.charAt(0));
            for(int i = 1; i < property.length(); i++) {
                char c = property.charAt(i);
                if(Character.isUpperCase(c)) {
                    sb.append(‘_‘);
                }
                sb.append(c);
            }
            return sb.toString().toLowerCase();
        }

        /**
         * 把指定列按类型注入 entity.
         * <p/>
         * 目前支持的类字段类型有:
         * <pre>
         * java.lang.Boolean    boolean
         * java.lang.Byte       byte
         * java.lang.Long       long
         * java.lang.Integer    int
         * java.lang.Short      short
         * java.lang.Float      float
         * java.lang.Double     double
         * java.lang.Date
         * java.lang.String
         * java.sql.Blob
         * java.math.BigDecimal
         * </pre>
         */
        private void inject(Method getter, String fieldType, ResultSet rs, int index, T t) {
            try {

                switch (fieldType) {
                    case "java.lang.Boolean":  // 布尔值
                    case "boolean":
                        getter.invoke(t, rs.getBoolean(index));
                        break;
                    case "java.lang.Byte":     // 字节
                    case "byte":
                        getter.invoke(t, rs.getByte(index));
                        break;
                    case "java.lang.Long":     // Long
                    case "long":
                        getter.invoke(t, rs.getLong(index));
                        break;
                    case "java.lang.Integer":  // Int
                    case "int":
                        getter.invoke(t, rs.getInt(index));
                        break;
                    case "java.lang.Short":    // Short
                    case "short":
                        getter.invoke(t, rs.getShort(index));
                        break;
                    case "java.lang.Float":    // Float
                    case "float":
                        getter.invoke(t, rs.getFloat(index));
                        break;
                    case "java.lang.Double":   // Double
                    case "double":
                        getter.invoke(t, rs.getDouble(index));
                        break;
                    case "java.lang.Date":
                        getter.invoke(t, rs.getDate(index));
                        break;
                    case "java.lang.String":
                        getter.invoke(t, rs.getString(index));
                        break;
                    case "java.sql.Blob":
                        getter.invoke(t, rs.getBlob(index));
                        break;
                    case "java.math.BigDecimal":
                        getter.invoke(t, rs.getBigDecimal(index));
                        break;
                    default:
                        getter.invoke(t, rs.getObject(index));
                        break;
                }
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
}

使用方式如下:

RowMapper<User> userRowMapper = RowMapperFactory.getRowMapper(User.class);
时间: 2025-01-03 18:39:47

一个加速产生 Spring JDBC RowMapper 的工具类的相关文章

获取Spring容器Bean对象工具类

在开发中,总是能碰到用注解注入不了Spring容器里面bean对象的问题.为了解决这个问题,我们需要一个工具类来直接获取Spring容器中的bean.因此就写了这个工具类,在此记录一下,方便后续查阅.废话不多说,直接上代码. 一.代码 package com.zxy.demo.spring; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext;

Spring 常用的一些工具类

学习Java的人,或者开发很多项目,都需要使用到Spring 这个框架,这个框架对于java程序员来说.学好spring 就不怕找不到工作.我们时常会写一些工具类,但是有些时候 我们不清楚,我们些的工具类,是否稳定,可靠.对于有看spring 源码习惯的人,其实,spring框架本身自带了很多工具类,其实,我有一个想法,就是想把一些常用的方法,从spring 整理整理出来,然后编译成jar包,因为有些时候,项目并不需要引用所有jar包进入的.这边整理了一些spring 常用的类,共大家参照: s

JDBC : 使用DBUtils 工具类

所需jar包 : commons-dbutils-1.6.jar DbUtils类  1.DbUtils :提供如关闭连接.装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的.主要方法如下: -public static void close(-) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法.这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection.Statement和ResultSet. -pu

Spring boot中普通工具类不能使用@Value注入yml文件中的自定义参数的问题

在写一个工具类的时候,因为要用到yml中的自定义参数,使用@Value发现值不能正常注入,都显示为null: yml文件中的自定义格式 调用工具类的时候不能new的方式 要使用@Autowired的方式注入进来, new会导致部分环境未加载,尽可能舍弃new的方式,交付spring管理 而工具类也是需要交给spring管理.需要在工具类上加上 @Component注解然后注意一下的是 在springframework下不能@Autowired静态变量 所以在变量上不能有 static 怎么扫描注

Spring便携开发之工具类专题(一)

Java作为高级程序语言中的老将,自然拥有很多技术工具,其中Spring框架为人所熟知,里面也有很多utils提供给开发者,随我一起来看看吧! 前言 Spring的工具类都是以Utils结尾,所以要查看这些工具类,只需要在API文档中查询所有*Utils即可,可以看到有多达几十个.其中有我们非常熟悉的org.springframework.util.StringUtils,有用到过的org.springframework.aop.support.AopUtils,还有可能没有听过的org.spr

结合AnyChart做报表:一个生成AnyChart图形XML数据的工具类

今天头有点痛,所以不能详细地写了,先把代码贴上来,等身体状况稍微好一点,再继续完善. 1.(主角)一个使用XML模板生成Anychart XML数据的工具类 /** * */ package com.common.anychart; import java.io.InputStream; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.l

浅析Android Camera开发中的三个尺寸和三种变形 (贡献一个自适配Picturesize和Previewsize的工具类)

转至 (http://blog.csdn.net/yanzi1225627/article/details/17652643) 经常听人问Camera开发中,各种变形问题,今天有空就在此梳理总结下. 三个尺寸: 1.Surfaceview的尺寸 Surfaceview是用来预览Camera的,当它全屏时就是Screen的大小. 2.Picturesize的尺寸 这是拍照后的PictureSize尺寸. 3.Previewsize的尺寸 这是预览时帧数据的尺寸. 三种变形: 1.预览画面的物体长宽

jdbc连接用工具类

封装的是链接部分和关流部分 mysql8.0.13 public class JDBCUtils { private JDBCUtils(){} private static Connection con; static{ try { Class.forName("com.mysql.jdbc.Driver"); //2获得连接 对象 String url ="jdbc:mysql://localhost:3306/rwx?useSSl=false&serverTim

JDBC连接Oracle工具类

import java.sql.*;import java.util.ResourceBundle; /** * jdbc工具类,负责: * 1. 加载/注册数据库驱动程序 * 2. 获取数据库连接 * 3. 释放数据库资源(Connection, Statement, ResultSet) */public class JdbcUtil { private static final String DRIVER = getValue("jdbc.driver"); private st