其实我一点都不想用mybatis,好多地方得自己写,比如这里。

使用mybatis要写大量的xml,烦的一批。最烦人的莫过于写各种resultmap,就是数据库字段和实体属性做映射。我认为这里应该是mybatis自动支持的,但是,它没有。为了轻量化(caocaocoa)???。

很少用mybatis,不知道有没有相关插件。只有自己写方法实现了。

先整理一下大体思路:

1.扫描项目代码下的所有类

2.选出所有类中的含有Table注解的类

3.根据column注解找出类下的属性映射关系

4.创建mybatis配置类,在mybatis配置完成后根据2.3两步的信息创建新的resultmap添加到mybatis的SqlSessionFactory中

代码:

这个是mybatis配置类,

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. import java.util.List;
  5. import java.util.Map;
  6. import java.util.Set;
  7.  
  8. import javax.persistence.Table;
  9.  
  10. import org.apache.ibatis.binding.MapperRegistry;
  11. import org.apache.ibatis.mapping.ResultMap;
  12. import org.apache.ibatis.mapping.ResultMapping;
  13. import org.apache.ibatis.session.SqlSessionFactory;
  14. import org.apache.log4j.Logger;
  15. import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.boot.autoconfigure.AutoConfigureAfter;
  18. import org.springframework.context.ApplicationContext;
  19. import org.springframework.context.annotation.Configuration;
  20.  
  21. import com.esri.rest.util.ClassUtil;
  22. import com.esri.rest.util.SpringUtil;
  23.  
  24. @Configuration
  25. @AutoConfigureAfter(MybatisAutoConfiguration.class)
  26. public class MyBatisTypeMapScannerConfig {
  27.  
  28. private Logger log = Logger.getLogger(MyBatisTypeMapScannerConfig.class);
  29.  
  30. public MyBatisTypeMapScannerConfig(ApplicationContext applicationContext, SqlSessionFactory sqlSessionFactory) {
  31. log.debug("自动添加resultMap");
  32. org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
  33.  
  34. //ResultMap rm = new ResultMap.Builder(configuration, id, type, null).build();
  35. //configuration.addResultMap(rm);
  36. // 选出所有类中的含有Table注解的类
  37. List<Class<?>> list = ClassUtil.getClassesWithAnnotation(Table.class);
  38.  
  39. for (Class<?> clas : list) {
  40. System.out.println(clas);
    //创建新的resultmap添加到mybatis的SqlSessionFactory中
  41. ResultMap rm = new ResultMap.Builder(configuration, clas.getName(), clas, getResultMapping(configuration, clas)).build();
  42. configuration.addResultMap(rm);
  43. }
  44.  
  45. log.debug("自动添加resultMap");
  46. }
  47.  
  48. private List<ResultMapping> getResultMapping(org.apache.ibatis.session.Configuration configuration, Class<?> type) {
  49. List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
          // 根据column注解找出类下的属性映射关系
  50. Map<String, Map<String, Object>> cols = ClassUtil.getColumnRelation(type);
  51. System.out.println(cols);
  52. Set<String> keys = cols.keySet();
  53. String[] keyArr = new String[keys.size()];
  54. keys.toArray(keyArr);
  55.  
  56. for(String key:keyArr){
  57. String property;
  58. String column;
  59. Object javaType;
  60. Map<String, Object> map = cols.get(key);
  61. property = key;
  62. column = (String) map.get("dbname");
  63. javaType = map.get("type");
  64. ResultMapping mapping = new ResultMapping.Builder(configuration, property, column,(Class<?> )javaType).build();
  65. resultMappings.add(mapping);
  66. }
  67.  
  68. return resultMappings;
  69. }
  70.  
  71. }
  1. ClassUtil
  1. import java.io.File;
  2. import java.io.FileFilter;
  3. import java.io.IOException;
  4. import java.lang.annotation.Annotation;
  5. import java.lang.reflect.Field;
  6. import java.lang.reflect.Method;
  7. import java.net.JarURLConnection;
  8. import java.net.URL;
  9. import java.net.URLDecoder;
  10. import java.util.ArrayList;
  11. import java.util.Enumeration;
  12. import java.util.HashMap;
  13. import java.util.LinkedHashSet;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import java.util.jar.JarEntry;
  18. import java.util.jar.JarFile;
  19.  
  20. import javax.persistence.Column;
  21. import javax.persistence.Table;
  22.  
  23. /**
  24. * 扫描esri包下的所有类
  25. * <p>
  26. * Title: ClassUtil.java
  27. * </p>
  28. * <p>
  29. * Description:
  30. * </p>
  31. *
  32. * @author lichao1
  33. * @date 2018年12月3日
  34. * @version 1.0
  35. */
  36. public class ClassUtil {
  37.  
  38. private static Set<Class<?>> classList;
  39. static {
  40. classList = getClasses("com.esri.rest");
  41. }
  42.  
  43. /**
  44. * 从包package中获取所有的Class
  45. *
  46. * @param pack
  47. * @return
  48. */
  49. public static Set<Class<?>> getClasses(String pack) {
  50.  
  51. // 第一个class类的集合
  52. Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
  53. // 是否循环迭代
  54. boolean recursive = true;
  55. // 获取包的名字 并进行替换
  56. String packageName = pack;
  57. String packageDirName = packageName.replace('.', '/');
  58. // 定义一个枚举的集合 并进行循环来处理这个目录下的things
  59. Enumeration<URL> dirs;
  60. try {
  61. dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
  62. // 循环迭代下去
  63. while (dirs.hasMoreElements()) {
  64. // 获取下一个元素
  65. URL url = dirs.nextElement();
  66. // 得到协议的名称
  67. String protocol = url.getProtocol();
  68. // 如果是以文件的形式保存在服务器上
  69. if ("file".equals(protocol)) {
  70. // System.err.println("file类型的扫描");
  71. // 获取包的物理路径
  72. String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
  73. // 以文件的方式扫描整个包下的文件 并添加到集合中
  74. findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
  75. } else if ("jar".equals(protocol)) {
  76. // 如果是jar包文件
  77. // 定义一个JarFile
  78. // System.err.println("jar类型的扫描");
  79. JarFile jar;
  80. try {
  81. // 获取jar
  82. jar = ((JarURLConnection) url.openConnection()).getJarFile();
  83. // 从此jar包 得到一个枚举类
  84. Enumeration<JarEntry> entries = jar.entries();
  85. // 同样的进行循环迭代
  86. while (entries.hasMoreElements()) {
  87. // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
  88. JarEntry entry = entries.nextElement();
  89. String name = entry.getName();
  90. // 如果是以/开头的
  91. if (name.charAt(0) == '/') {
  92. // 获取后面的字符串
  93. name = name.substring(1);
  94. }
  95. // 如果前半部分和定义的包名相同
  96. if (name.startsWith(packageDirName)) {
  97. int idx = name.lastIndexOf('/');
  98. // 如果以"/"结尾 是一个包
  99. if (idx != -1) {
  100. // 获取包名 把"/"替换成"."
  101. packageName = name.substring(0, idx).replace('/', '.');
  102. }
  103. // 如果可以迭代下去 并且是一个包
  104. if ((idx != -1) || recursive) {
  105. // 如果是一个.class文件 而且不是目录
  106. if (name.endsWith(".class") && !entry.isDirectory()) {
  107. // 去掉后面的".class" 获取真正的类名
  108. String className = name.substring(packageName.length() + 1, name.length() - 6);
  109. try {
  110. // 添加到classes
  111. classes.add(Class.forName(packageName + '.' + className));
  112. } catch (ClassNotFoundException e) {
  113. // log
  114. // .error("添加用户自定义视图类错误
  115. // 找不到此类的.class文件");
  116. e.printStackTrace();
  117. }
  118. }
  119. }
  120. }
  121. }
  122. } catch (IOException e) {
  123. // log.error("在扫描用户定义视图时从jar包获取文件出错");
  124. e.printStackTrace();
  125. }
  126. }
  127. }
  128. } catch (IOException e) {
  129. e.printStackTrace();
  130. }
  131.  
  132. return classes;
  133. }
  134.  
  135. /**
  136. * 以文件的形式来获取包下的所有Class
  137. *
  138. * @param packageName
  139. * @param packagePath
  140. * @param recursive
  141. * @param classes
  142. */
  143. private static void findAndAddClassesInPackageByFile(String packageName, String packagePath,
  144. final boolean recursive, Set<Class<?>> classes) {
  145. // 获取此包的目录 建立一个File
  146. File dir = new File(packagePath);
  147. // 如果不存在或者 也不是目录就直接返回
  148. if (!dir.exists() || !dir.isDirectory()) {
  149. // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
  150. return;
  151. }
  152. // 如果存在 就获取包下的所有文件 包括目录
  153. File[] dirfiles = dir.listFiles(new FileFilter() {
  154. // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
  155. public boolean accept(File file) {
  156. return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
  157. }
  158. });
  159. // 循环所有文件
  160. for (File file : dirfiles) {
  161. // 如果是目录 则继续扫描
  162. if (file.isDirectory()) {
  163. findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,
  164. classes);
  165. } else {
  166. // 如果是java类文件 去掉后面的.class 只留下类名
  167. String className = file.getName().substring(0, file.getName().length() - 6);
  168. try {
  169. // 添加到集合中去
  170. // classes.add(Class.forName(packageName + '.' +
  171. // className));
  172. // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
  173. classes.add(
  174. Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
  175. } catch (ClassNotFoundException e) {
  176. // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
  177. e.printStackTrace();
  178. }
  179. }
  180. }
  181. }
  182.  
  183. /**
  184. * 根据注解查找类
  185. *
  186. * @param annotationType
  187. * @return
  188. */
  189. public static List<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotationType) {
  190. List<Class<?>> list = new ArrayList<Class<?>>();
  191. Object[] ts = classList.toArray();
  192. for (Object t : ts) {
  193. Class<?> ty = (Class<?>) t;
  194. Object aclass = ty.getAnnotation(annotationType);
  195. if (aclass != null) {
  196. list.add(ty);
  197. }
  198. }
  199. return list;
  200. }
  201.  
  202. /**
  203. * 获取类中标记Column注解的字段
  204. * @param clas
  205. * @return
  206. */
  207. public static Map<String, Map<String, Object>> getColumnRelation(Class<?> clas){
  208. Map<String, Map<String, Object>> cols = new HashMap<String, Map<String, Object>>();
  209. // 直接标注属性
  210. Field field;
  211. Field[] fields = clas.getDeclaredFields();
  212. for (int i = 0; i < fields.length; i++) {
  213. fields[i].setAccessible(true);
  214. }
  215. for (int i = 0; i < fields.length; i++) {
  216. Map<String, Object> map= new HashMap<String, Object>();
  217. try {
  218. field = clas.getDeclaredField(fields[i].getName());
  219. Column column = field.getAnnotation(Column.class);
  220. if (column != null) {
  221. map.put("dbname", column.name());
  222. map.put("length", column.length());
  223. map.put("type", field.getType());
  224. //System.out.println(column.name());
  225. //System.out.println(column.length());
  226. cols.put(field.getName(), map);
  227. }
  228. } catch (Exception e) {
  229. }
  230. }
  231.  
  232. // 标注方法
  233. Method method;
  234. Method[] methods = clas.getDeclaredMethods();
  235. for (int i = 0; i < methods.length; i++) {
  236. Map<String, Object> map= new HashMap<String, Object>();
  237. try {
  238. method = methods[i];
  239. Column column = method.getAnnotation(Column.class);
  240. if (column != null) {
  241. String filedName = method.getName();
  242. boolean isGet = filedName.indexOf("get")>=0;
  243. if(isGet){
  244. map.put("type", method.getReturnType());
  245. }else{
  246. map.put("type", method.getParameterTypes()[0]);
  247. }
  248. filedName = filedName.replaceAll("set", "");
  249. filedName = filedName.replaceAll("get", "");
  250. filedName = filedName.substring(0, 1).toLowerCase() + filedName.substring(1);
  251. map.put("dbname", column.name());
  252. map.put("length", column.length());
  253. cols.put(filedName, map);
  254. }
  255. } catch (SecurityException e) {
  256. e.printStackTrace();
  257. }
  258. }
  259.  
  260. return cols;
  261. }
  262.  
  263. public static void main(String[] args) {
  264. System.out.println(classList);
  265. // Object[] ts = classList.toArray();
  266. // for(Object t:ts){
  267. // Class<?> tt = (Class<?>) t;
  268. // System.out.println(tt);
  269. // }
  270.  
  271. List<Class<?>> list = getClassesWithAnnotation(Table.class);
  272. for (Class<?> clas : list) {
  273. System.out.println(clas);
  274. Map<String, Map<String, Object>> cols = getColumnRelation(clas);
  275. System.out.println(cols);
  276. }
  277. }
  278. }

经测试可行,细节方面自己调整

SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成ResultMap的更多相关文章

  1. SpringBoot+MyBatis中自动根据@Table注解和@Column注解生成增删改查逻辑

    习惯使用jpa操作对象的方式,现在用mybatis有点不习惯. 其实是懒得写SQL,增删改查那么简单的事情你帮我做了呗,mybatis:NO. 没办法,自己搞喽! 这里主要是实现了通过代码自动生成my ...

  2. JPA中自动使用@Table(name = "userTab")后自动将表名、列名添加了下划线的问题

    一.问题 JPA中自动使用@Table(name = "userTab")后自动将表名.列名添加了下划线的问题,如下图: 二.解决 在application.properties文 ...

  3. Springboot mybatis generate 自动生成实体类和Mapper

    https://github.com/JasmineQian/SpringDemo_2019/tree/master/mybatis Springboot让java开发变得方便,Springboot中 ...

  4. 关于springboot项目中自动注入,但是用的时候值为空的BUG

    最近想做一些web项目来填充下业余时间,首先想到了使用springboot框架,毕竟方便 快捷 首先:去这里 http://start.spring.io/ 直接构建了一个springboot初始化的 ...

  5. SpringBoot+Mybatis+MySql 自动生成代码 自动分页

    一.配置文件 <!-- 通用mapper --> <dependency> <groupId>tk.mybatis</groupId> <arti ...

  6. Springboot+mybatis中整合过程访问Mysql数据库时报错

    报错原因如下:com.mysql.cj.core.exceptions.InvalidConnectionAttributeException: The server time zone.. 产生这个 ...

  7. tk.mybatis 中一直报...table doesn't exists

    首先检查你在实体类中可有加上@Table(name="数据库中的表名") 第二:如果你加了@Table注解, 那么只有一种可能就是.xml中定义了与通用mapper中的相同的方法名 ...

  8. springboot+mybatis项目自动生成

    springboot_data_access_demo基于rapid,根据自定义模版生成的基于mybatis+mysql的数据库访问示例项目.简单配置数据库信息,配置不同的生成策略生成可以直接运行访问 ...

  9. springboot拦截中自动注入的组件为null问题解决方法

    一.写SpringUtil类来获取Springh管理的类实例,判断是否注入成功,如果没有注入成功重新获取注入 package com.util; import org.springframework. ...

随机推荐

  1. sql: MySQL and Microsoft SQL Server Stored Procedures IN, OUT using csharp code

    MySQL存储过程: #插入一条返回值涂聚文注 DELIMITER $$ DROP PROCEDURE IF EXISTS `geovindu`.`proc_Insert_BookKindOut` $ ...

  2. git杂记-查看历史提交

    普通查看:git log.输入q退出比较. $ git log commit ca82a6dff817ec66f44342007202690a93763949 Author: Scott Chacon ...

  3. Visual Studio Code 保存时自动格式化的问题

    烦人的说,保存的时候自动格式化, 格式话后,代码就失效了 纳尼!!!! 网上其他人都说     JS-CSS-HTML Formatter这个插件在捣蛋!   试了,的确如此. 找到他,给禁用,就不会 ...

  4. LintCode2016年8月22日算法比赛----平面列表

    平面列表 题目描述 给定一个列表,该列表中的每个要素要么是个列表,要么是整数.将其变成一个只包含整数的简单列表. 注意事项 如果给定的列表中的要素本身也是一个列表,那么它也可以包含列表. 样例 给定 ...

  5. ArcGIS 地类净面积计算工具

    地类净面积计算工具可以自己定义图层.字段.地类代码计算任意图层的椭球面积.线状地物扣除.零星扣除和其他扣除,计算地类净面积计算:可以用于二调数据图斑地类.规划地块和基本农田等等需要计算净面积的都可以. ...

  6. 在 Azure 虚拟机中配置 Always On 可用性组(经典)

    在开始之前,请先假设现在可以在 Azure Resource Manager 模型中完成此任务. 我们建议使用 Azure Resource Manager 模型来进行新的部署. 请参阅 Azure ...

  7. Sqlserver新建随机测试数据

    USE Test --使用数据库Test(如果没有则需要新建一个) ----1.新建一个users表 create table users( uId int primary key identity( ...

  8. faf

    1.Nginx的简单说明 a.  Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器,期初开发的目的就是为了代理电子邮件服务器室友:Igor Sysoev开发 ...

  9. Python学习---Django下的Sql性能的测试

    安装django-debug-tools Python学习---django-debug-tools安装 性能测试: settings.py INSTALLED_APPS = [ ... 'app01 ...

  10. 3D旋转相册的实现

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...