SpringBoot + Jfinal Enjoy + JdbcTemplate 整合

SpringBoot + Jfinal Enjoy + JdbcTemplate 整合

发布时间
Aug 11, 2022
标签
java
最近发现了 Jfinal 的 ORM 非常好用,于是想着将其抽出来,因为公司目前基于 JdbcTemplate 简单做了封装,将 SQL 语句写在 SQL 文件中,然后读取出来用 JdbcTemplate 执行,跟 Jfinal 是类似的,所以想将其抽出来扩展公司当前的框架
 

代码

核心代码讲解

 
项目所用到的依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>com.jfinal</groupId> <artifactId>enjoy</artifactId> <version>5.0.0</version> </dependency>
 
自建2个注解,用于表示实体类字段名
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) public @interface DbEntity { }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE}) public @interface DbColumn { String value() default ""; boolean exist() default true; }
 
DbMapper:用于保存 java 属性与数据库字段的映射关系
public class DbMapper { private static final Map<Class<?>, Map<String, String>> classColMap = new HashMap<>(); private static final Map<Class<?>, Map<String, Method>> classSetterMap = new HashMap<>(); private static final Map<Class<?>, Map<String, Class<?>>> classFieldTypeMap = new HashMap<>(); public static Map<String, String> columnMap(Class<?> clazz) { return classColMap.get(clazz); } public static String toSetterName(String fieldName) { String firstLetter = fieldName.substring(0, 1); return "set" + fieldName.replaceFirst(firstLetter, firstLetter.toUpperCase()); } public static Method setter(Class<?> entityClass, String field) { return classSetterMap.get(entityClass).get(field); } public static void classColMap(Class<?> clazz, Map<String, String> colMap) { classColMap.put(clazz, colMap); } public static void classSetterMap(Class<?> clazz, Map<String, Method> setterMap) { classSetterMap.put(clazz, setterMap); } public static void classFieldTypeMap(Class<?> clazz, Map<String, Class<?>> fieldTypeMap) { classFieldTypeMap.put(clazz, fieldTypeMap); } public static Class<?> getClassFieldType(Class<?> clazz, String fieldName) { return classFieldTypeMap.get(clazz).get(fieldName); }
 
读取实体类并将其属性与字段的映射保存
/** * 扫描包下全部类 * * @author vital */ public void scanner() { String basePackage = "net.vitalblog.edb.entity"; ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + "/**/*.class"; org.springframework.core.io.Resource[] resources = resourcePatternResolver.getResources(pattern); MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver); for (org.springframework.core.io.Resource resource : resources) { // 用于读取类信息 MetadataReader reader = readerFactory.getMetadataReader(resource); // 扫描到的class String classname = reader.getClassMetadata().getClassName(); Class<?> clazz = Class.forName(classname); // 判断是否有指定注解 if (clazz.getAnnotation(DbEntity.class) != null) { register(clazz); } } } catch (IOException | ClassNotFoundException e) { log.error("error", e); } } /** * 将类信息保存 * * @param clazz 实体类 * @author vital */ private <T> void register(Class<T> clazz) { List<Field> fieldList = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())); Class<? super T> superclass = clazz; // 判断是否有父类 for (int i = 0; i < 5; i++) { superclass = superclass.getSuperclass(); if (superclass == null) { break; } fieldList.addAll(Arrays.asList(superclass.getDeclaredFields())); } Map<String, Class<?>> fieldTypeMap = new HashMap<>(fieldList.size() + 1); Map<String, String> colMap = new HashMap<>(fieldList.size() + 1); Map<String, Method> setterMap = new HashMap<>(fieldList.size() + 1); for (Field field : fieldList) { String fieldName = field.getName(); DbColumn column = field.getAnnotation(DbColumn.class); if (column != null && !column.exist()) { continue; } String colName = column != null ? column.value() : camelCase2UnderScoreCase(fieldName); fieldTypeMap.put(fieldName, field.getType()); colMap.put(colName, fieldName); try { Method setter = clazz.getMethod(DbMapper.toSetterName(fieldName), field.getType()); setterMap.put(fieldName, setter); } catch (Exception e) { log.error("error", e); } } DbMapper.classFieldTypeMap(clazz, fieldTypeMap); DbMapper.classColMap(clazz, colMap); DbMapper.classSetterMap(clazz, setterMap); } /** * 驼峰命名转下划线命名 * * @param str 驼峰字段名 * @return java.lang.String * @author vital */ public static String camelCase2UnderScoreCase(String str) { Pattern compile = Pattern.compile("[A-Z]"); Matcher matcher = compile.matcher(str); StringBuffer sb = new StringBuffer(); while(matcher.find()) { matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); } matcher.appendTail(sb); return sb.toString(); }
 
RowMapper映射
public class CommonRowMapper<T> implements RowMapper<T> { private final Class<T> entityClass; public CommonRowMapper(Class<T> entityClass) { this.entityClass = entityClass; } @Override public T mapRow(ResultSet rs, int rowNum) throws SQLException { ResultSetMetaData metaData = rs.getMetaData(); int colAmount = metaData.getColumnCount(); Map<String, String> columnMap = DbMapper.columnMap(this.entityClass); T result = null; try { result = this.entityClass.newInstance(); for (int index = 1; index <= colAmount; index++) { String column = JdbcUtils.lookupColumnName(metaData, index); String fieldName = columnMap.get(column); if (StringUtils.isBlank(fieldName)) { continue; } Class<?> fieldType = DbMapper.getClassFieldType(this.entityClass, fieldName); Object value = JdbcUtils.getResultSetValue(rs, index, fieldType); if (value == null) { continue; } Method setter = DbMapper.setter(this.entityClass, fieldName); setter.invoke(result, value); } } catch (Exception e) { e.printStackTrace(); } return result; } }
 
使用
public <T> T findOne(String sql, Class<T> entityClass, Object... paras) { return jdbcTemplate.queryForObject(sql, new CommonRowMapper<>(entityClass), paras); }
 

测试效果:

notion image