SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成ResultMap
其实我一点都不想用mybatis,好多地方得自己写,比如这里。
使用mybatis要写大量的xml,烦的一批。最烦人的莫过于写各种resultmap,就是数据库字段和实体属性做映射。我认为这里应该是mybatis自动支持的,但是,它没有。为了轻量化(caocaocoa)???。
很少用mybatis,不知道有没有相关插件。只有自己写方法实现了。
先整理一下大体思路:
1.扫描项目代码下的所有类
2.选出所有类中的含有Table注解的类
3.根据column注解找出类下的属性映射关系
4.创建mybatis配置类,在mybatis配置完成后根据2.3两步的信息创建新的resultmap添加到mybatis的SqlSessionFactory中
代码:
这个是mybatis配置类,
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import javax.persistence.Table;
- import org.apache.ibatis.binding.MapperRegistry;
- import org.apache.ibatis.mapping.ResultMap;
- import org.apache.ibatis.mapping.ResultMapping;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.log4j.Logger;
- import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.AutoConfigureAfter;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.annotation.Configuration;
- import com.esri.rest.util.ClassUtil;
- import com.esri.rest.util.SpringUtil;
- @Configuration
- @AutoConfigureAfter(MybatisAutoConfiguration.class)
- public class MyBatisTypeMapScannerConfig {
- private Logger log = Logger.getLogger(MyBatisTypeMapScannerConfig.class);
- public MyBatisTypeMapScannerConfig(ApplicationContext applicationContext, SqlSessionFactory sqlSessionFactory) {
- log.debug("自动添加resultMap");
- org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
- //ResultMap rm = new ResultMap.Builder(configuration, id, type, null).build();
- //configuration.addResultMap(rm);
- // 选出所有类中的含有Table注解的类
- List<Class<?>> list = ClassUtil.getClassesWithAnnotation(Table.class);
- for (Class<?> clas : list) {
- System.out.println(clas);
//创建新的resultmap添加到mybatis的SqlSessionFactory中- ResultMap rm = new ResultMap.Builder(configuration, clas.getName(), clas, getResultMapping(configuration, clas)).build();
- configuration.addResultMap(rm);
- }
- log.debug("自动添加resultMap");
- }
- private List<ResultMapping> getResultMapping(org.apache.ibatis.session.Configuration configuration, Class<?> type) {
- List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
// 根据column注解找出类下的属性映射关系- Map<String, Map<String, Object>> cols = ClassUtil.getColumnRelation(type);
- System.out.println(cols);
- Set<String> keys = cols.keySet();
- String[] keyArr = new String[keys.size()];
- keys.toArray(keyArr);
- for(String key:keyArr){
- String property;
- String column;
- Object javaType;
- Map<String, Object> map = cols.get(key);
- property = key;
- column = (String) map.get("dbname");
- javaType = map.get("type");
- ResultMapping mapping = new ResultMapping.Builder(configuration, property, column,(Class<?> )javaType).build();
- resultMappings.add(mapping);
- }
- return resultMappings;
- }
- }
- ClassUtil 类
- import java.io.File;
- import java.io.FileFilter;
- import java.io.IOException;
- import java.lang.annotation.Annotation;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.net.JarURLConnection;
- import java.net.URL;
- import java.net.URLDecoder;
- import java.util.ArrayList;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.LinkedHashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.jar.JarEntry;
- import java.util.jar.JarFile;
- import javax.persistence.Column;
- import javax.persistence.Table;
- /**
- * 扫描esri包下的所有类
- * <p>
- * Title: ClassUtil.java
- * </p>
- * <p>
- * Description:
- * </p>
- *
- * @author lichao1
- * @date 2018年12月3日
- * @version 1.0
- */
- public class ClassUtil {
- private static Set<Class<?>> classList;
- static {
- classList = getClasses("com.esri.rest");
- }
- /**
- * 从包package中获取所有的Class
- *
- * @param pack
- * @return
- */
- public static Set<Class<?>> getClasses(String pack) {
- // 第一个class类的集合
- Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
- // 是否循环迭代
- boolean recursive = true;
- // 获取包的名字 并进行替换
- String packageName = pack;
- String packageDirName = packageName.replace('.', '/');
- // 定义一个枚举的集合 并进行循环来处理这个目录下的things
- Enumeration<URL> dirs;
- try {
- dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
- // 循环迭代下去
- while (dirs.hasMoreElements()) {
- // 获取下一个元素
- URL url = dirs.nextElement();
- // 得到协议的名称
- String protocol = url.getProtocol();
- // 如果是以文件的形式保存在服务器上
- if ("file".equals(protocol)) {
- // System.err.println("file类型的扫描");
- // 获取包的物理路径
- String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
- // 以文件的方式扫描整个包下的文件 并添加到集合中
- findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
- } else if ("jar".equals(protocol)) {
- // 如果是jar包文件
- // 定义一个JarFile
- // System.err.println("jar类型的扫描");
- JarFile jar;
- try {
- // 获取jar
- jar = ((JarURLConnection) url.openConnection()).getJarFile();
- // 从此jar包 得到一个枚举类
- Enumeration<JarEntry> entries = jar.entries();
- // 同样的进行循环迭代
- while (entries.hasMoreElements()) {
- // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
- JarEntry entry = entries.nextElement();
- String name = entry.getName();
- // 如果是以/开头的
- if (name.charAt(0) == '/') {
- // 获取后面的字符串
- name = name.substring(1);
- }
- // 如果前半部分和定义的包名相同
- if (name.startsWith(packageDirName)) {
- int idx = name.lastIndexOf('/');
- // 如果以"/"结尾 是一个包
- if (idx != -1) {
- // 获取包名 把"/"替换成"."
- packageName = name.substring(0, idx).replace('/', '.');
- }
- // 如果可以迭代下去 并且是一个包
- if ((idx != -1) || recursive) {
- // 如果是一个.class文件 而且不是目录
- if (name.endsWith(".class") && !entry.isDirectory()) {
- // 去掉后面的".class" 获取真正的类名
- String className = name.substring(packageName.length() + 1, name.length() - 6);
- try {
- // 添加到classes
- classes.add(Class.forName(packageName + '.' + className));
- } catch (ClassNotFoundException e) {
- // log
- // .error("添加用户自定义视图类错误
- // 找不到此类的.class文件");
- e.printStackTrace();
- }
- }
- }
- }
- }
- } catch (IOException e) {
- // log.error("在扫描用户定义视图时从jar包获取文件出错");
- e.printStackTrace();
- }
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return classes;
- }
- /**
- * 以文件的形式来获取包下的所有Class
- *
- * @param packageName
- * @param packagePath
- * @param recursive
- * @param classes
- */
- private static void findAndAddClassesInPackageByFile(String packageName, String packagePath,
- final boolean recursive, Set<Class<?>> classes) {
- // 获取此包的目录 建立一个File
- File dir = new File(packagePath);
- // 如果不存在或者 也不是目录就直接返回
- if (!dir.exists() || !dir.isDirectory()) {
- // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
- return;
- }
- // 如果存在 就获取包下的所有文件 包括目录
- File[] dirfiles = dir.listFiles(new FileFilter() {
- // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
- public boolean accept(File file) {
- return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
- }
- });
- // 循环所有文件
- for (File file : dirfiles) {
- // 如果是目录 则继续扫描
- if (file.isDirectory()) {
- findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
- classes);
- } else {
- // 如果是java类文件 去掉后面的.class 只留下类名
- String className = file.getName().substring(0, file.getName().length() - 6);
- try {
- // 添加到集合中去
- // classes.add(Class.forName(packageName + '.' +
- // className));
- // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
- classes.add(
- Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
- } catch (ClassNotFoundException e) {
- // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
- e.printStackTrace();
- }
- }
- }
- }
- /**
- * 根据注解查找类
- *
- * @param annotationType
- * @return
- */
- public static List<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotationType) {
- List<Class<?>> list = new ArrayList<Class<?>>();
- Object[] ts = classList.toArray();
- for (Object t : ts) {
- Class<?> ty = (Class<?>) t;
- Object aclass = ty.getAnnotation(annotationType);
- if (aclass != null) {
- list.add(ty);
- }
- }
- return list;
- }
- /**
- * 获取类中标记Column注解的字段
- * @param clas
- * @return
- */
- public static Map<String, Map<String, Object>> getColumnRelation(Class<?> clas){
- Map<String, Map<String, Object>> cols = new HashMap<String, Map<String, Object>>();
- // 直接标注属性
- Field field;
- Field[] fields = clas.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- fields[i].setAccessible(true);
- }
- for (int i = 0; i < fields.length; i++) {
- Map<String, Object> map= new HashMap<String, Object>();
- try {
- field = clas.getDeclaredField(fields[i].getName());
- Column column = field.getAnnotation(Column.class);
- if (column != null) {
- map.put("dbname", column.name());
- map.put("length", column.length());
- map.put("type", field.getType());
- //System.out.println(column.name());
- //System.out.println(column.length());
- cols.put(field.getName(), map);
- }
- } catch (Exception e) {
- }
- }
- // 标注方法
- Method method;
- Method[] methods = clas.getDeclaredMethods();
- for (int i = 0; i < methods.length; i++) {
- Map<String, Object> map= new HashMap<String, Object>();
- try {
- method = methods[i];
- Column column = method.getAnnotation(Column.class);
- if (column != null) {
- String filedName = method.getName();
- boolean isGet = filedName.indexOf("get")>=0;
- if(isGet){
- map.put("type", method.getReturnType());
- }else{
- map.put("type", method.getParameterTypes()[0]);
- }
- filedName = filedName.replaceAll("set", "");
- filedName = filedName.replaceAll("get", "");
- filedName = filedName.substring(0, 1).toLowerCase() + filedName.substring(1);
- map.put("dbname", column.name());
- map.put("length", column.length());
- cols.put(filedName, map);
- }
- } catch (SecurityException e) {
- e.printStackTrace();
- }
- }
- return cols;
- }
- public static void main(String[] args) {
- System.out.println(classList);
- // Object[] ts = classList.toArray();
- // for(Object t:ts){
- // Class<?> tt = (Class<?>) t;
- // System.out.println(tt);
- // }
- List<Class<?>> list = getClassesWithAnnotation(Table.class);
- for (Class<?> clas : list) {
- System.out.println(clas);
- Map<String, Map<String, Object>> cols = getColumnRelation(clas);
- System.out.println(cols);
- }
- }
- }
经测试可行,细节方面自己调整
SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成ResultMap的更多相关文章
- SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成增删改查逻辑
习惯使用jpa操作对象的方式,现在用mybatis有点不习惯. 其实是懒得写SQL,增删改查那么简单的事情你帮我做了呗,mybatis:NO. 没办法,自己搞喽! 这里主要是实现了通过代码自动生成my ...
- JPA中自动使用@Table(name = "userTab")后自动将表名、列名添加了下划线的问题
一.问题 JPA中自动使用@Table(name = "userTab")后自动将表名.列名添加了下划线的问题,如下图: 二.解决 在application.properties文 ...
- Springboot mybatis generate 自动生成实体类和Mapper
https://github.com/JasmineQian/SpringDemo_2019/tree/master/mybatis Springboot让java开发变得方便,Springboot中 ...
- 关于springboot项目中自动注入,但是用的时候值为空的BUG
最近想做一些web项目来填充下业余时间,首先想到了使用springboot框架,毕竟方便 快捷 首先:去这里 http://start.spring.io/ 直接构建了一个springboot初始化的 ...
- SpringBoot+Mybatis+MySql 自动生成代码 自动分页
一.配置文件 <!-- 通用mapper --> <dependency> <groupId>tk.mybatis</groupId> <arti ...
- Springboot+mybatis中整合过程访问Mysql数据库时报错
报错原因如下:com.mysql.cj.core.exceptions.InvalidConnectionAttributeException: The server time zone.. 产生这个 ...
- tk.mybatis 中一直报...table doesn't exists
首先检查你在实体类中可有加上@Table(name="数据库中的表名") 第二:如果你加了@Table注解, 那么只有一种可能就是.xml中定义了与通用mapper中的相同的方法名 ...
- springboot+mybatis项目自动生成
springboot_data_access_demo基于rapid,根据自定义模版生成的基于mybatis+mysql的数据库访问示例项目.简单配置数据库信息,配置不同的生成策略生成可以直接运行访问 ...
- springboot拦截中自动注入的组件为null问题解决方法
一.写SpringUtil类来获取Springh管理的类实例,判断是否注入成功,如果没有注入成功重新获取注入 package com.util; import org.springframework. ...
随机推荐
- sql: MySQL and Microsoft SQL Server Stored Procedures IN, OUT using csharp code
MySQL存储过程: #插入一条返回值涂聚文注 DELIMITER $$ DROP PROCEDURE IF EXISTS `geovindu`.`proc_Insert_BookKindOut` $ ...
- git杂记-查看历史提交
普通查看:git log.输入q退出比较. $ git log commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon ...
- Visual Studio Code 保存时自动格式化的问题
烦人的说,保存的时候自动格式化, 格式话后,代码就失效了 纳尼!!!! 网上其他人都说 JS-CSS-HTML Formatter这个插件在捣蛋! 试了,的确如此. 找到他,给禁用,就不会 ...
- LintCode2016年8月22日算法比赛----平面列表
平面列表 题目描述 给定一个列表,该列表中的每个要素要么是个列表,要么是整数.将其变成一个只包含整数的简单列表. 注意事项 如果给定的列表中的要素本身也是一个列表,那么它也可以包含列表. 样例 给定 ...
- ArcGIS 地类净面积计算工具
地类净面积计算工具可以自己定义图层.字段.地类代码计算任意图层的椭球面积.线状地物扣除.零星扣除和其他扣除,计算地类净面积计算:可以用于二调数据图斑地类.规划地块和基本农田等等需要计算净面积的都可以. ...
- 在 Azure 虚拟机中配置 Always On 可用性组(经典)
在开始之前,请先假设现在可以在 Azure Resource Manager 模型中完成此任务. 我们建议使用 Azure Resource Manager 模型来进行新的部署. 请参阅 Azure ...
- Sqlserver新建随机测试数据
USE Test --使用数据库Test(如果没有则需要新建一个) ----1.新建一个users表 create table users( uId int primary key identity( ...
- faf
1.Nginx的简单说明 a. Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器,期初开发的目的就是为了代理电子邮件服务器室友:Igor Sysoev开发 ...
- Python学习---Django下的Sql性能的测试
安装django-debug-tools Python学习---django-debug-tools安装 性能测试: settings.py INSTALLED_APPS = [ ... 'app01 ...
- 3D旋转相册的实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...