Mybatis自动代码生成器的实现

原博地址https://laboo.top/2018/11/26/a-db/#more

本文介绍如何用Java编写高度自定义的代码生成器

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息。

上面这一段话来自Mybatis官网的介绍, 初用Mybatis时感觉这个框架相比于JDBC优雅多了, 用起来也如官网说的非常简单。但是用了一段时间之后, 弊端就慢慢凸显出来了

使用Mybatis时不得不为每个表创建一个Entity.javaMapper.xml(Mapper可以融合入Dao中)Dao.java,Service.java 层次很清晰, 但是太多重复性的工作了, 费时间且易于出错

并且当数据库发生一点改动的时候... 苦不堪言

后来出现了自动生成代码的插件, 但是总是不尽人意, 不能随心所欲地控制, 毕竟每个人的需求都不一样

本文就来介绍如何简单的编写一个自己的代码生成器

项目源码

mybatis-generator

代码实现

实现的思路很简单, 首先查询数据库的表结构, 得到列名, 列类型...等信息

创建文件模版, 将这些信息插入模版中, 最后打包模版进压缩包导出

代码实现 一共五个Java类

  • TableDO
  • ColumnDO
  • GeneratorMapper
  • GeneratorUtils
  • GeneratorService

首先来看两个实体类

TableDO 和 ColumnDO

TableDO 存放表名, 对于的类名, 以及列信息

完整类代码 TableDO.java

public class TableDO {

    private String tableName;
    private List<ColumnDO> columns;
    private String className;
    private String suffix;

    // get()... set()...
}

ColumnDO 存放列名, 数据库字段类型, 以及对应Java中的属性名和类型

完整类代码 ColumnDO.java

public class ColumnDO {

    private String columnName;
    private String dataType;
    private String attrName;
    private String attrLowerName;
    private String attrType;

    // get()... set()...
}

GeneratorMapper

在GeneratorMapper 中, 我们通过表名查询表自动的信息

完整类代码 GeneratorMapper.java

@Mapper
public interface GeneratorMapper {

    @Select("select column_name columnName, data_type dataType from information_schema.columns where table_name = #{tableName} and table_schema = (select database()) order by ordinal_position")
    List<ColumnDO> listColumns(String tableName);
}

GeneratorUtils

在GeneratorUtils 中进行类信息与模版之间的转换

完整类代码 GeneratorUtils.java

将表信息放入Velocity模版的上下文中

Map<String, Object> map = new HashMap<>();
map.put("tableName", table.getTableName());
map.put("className", table.getClassName());
map.put("pathName", getPackageName().substring(getPackageName().lastIndexOf(".") + 1));
map.put("columns", table.getColumns());
map.put("package", getPackageName());
map.put("suffix", table.getSuffix());

Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
VelocityContext context = new VelocityContext(map);

添加模版

List<String> templates = new ArrayList<>();
templates.add("mybatis/Model.java.vm");
templates.add("mybatis/Query.java.vm");
templates.add("mybatis/Dao.java.vm");
templates.add("mybatis/Mapper.xml.vm");
templates.add("mybatis/Service.java.vm");

编译模版

StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);

Utils类完成了生成代码的主要工作, 但是代码也是比较简单的

GeneratorService

在Service 中注入Mapper 查询列信息, 并用Utils生成代码, 然后导出压缩包

完整类代码 GeneratorService.java

@Service
public class GeneratorService {

    @Resource
    private GeneratorMapper generatorMapper;

    @Resource
    private Environment environment;

    public void generateZip(String[] tableNames, String zipPath) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        for (String tableName : tableNames) {
            TableDO table = new TableDO();
            table.setTableName(tableName);
            table.setColumns(generatorMapper.listColumns(tableName));
            GeneratorUtils.generatorCode(table, zip,getConfig());
        }
        IOUtils.closeQuietly(zip);
        FileOutputStream file = new FileOutputStream(zipPath);
        file.write(outputStream.toByteArray());
        file.close();
    }

    // getConfig ...
}

VM模版

自己写代码生成器的好处就是, 可以根据需求定制自己的模版, 下面是我的几个模版可以供参考

  • Mapper.xml.vm
  • Dao.java.vm
  • Service.java.vm
  • Model.java.vm
  • Query.java.vm

生成的代码是在commons-mybatis架构下使用的

Dao.java.vm

package ${package}.database.dao;

import ${package}.database.model.${className}${suffix};

import org.apache.ibatis.annotations.Mapper;
import org.laziji.commons.mybatis.dao.${suffix}Dao;

@Mapper
public interface ${className}Dao extends ${suffix}Dao<${className}${suffix}> {

}

...

其余模版

使用

配置文件

resources下创建application-${name}.yml文件, ${name}随意, 例如: application-example.yml, 可创建多个

配置文件内容如下, 填入数据库配置, 以及生成代码的包名, 源文件路径

spring:
  datasource:
    url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxxx?characterEncoding=utf-8
    username: xxxxxx
    password: xxxxxx

generator:
  package: com.xxx.xxx
  resources: mapper

Test

在test文件下创建测试类

  • @ActiveProfiles("example")中填入刚才配置文件名的namepackage pg.laziji.generator; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; import pg.laziji.generator.mybatis.GeneratorService; import javax.annotation.Resource; import java.io.IOException; @ActiveProfiles("example") @RunWith(SpringRunner.class) @SpringBootTest public class ExampleTest { @Resource private GeneratorService generatorService; @Test public void test() throws IOException { String[] tableNames = new String[]{"example_table1", "example_table2"}; String zipPath = "/home/code.zip"; generatorService.generateZip(tableNames,zipPath); } }
  • tableNames需要生成的表, 可以多个
  • zipPath 代码导出路径 运行测试方法即可

欢迎关注我的博客公众号

2018_11_16_0048241709.png

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

辣子鸡的技术分享

1 篇文章1 人订阅

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

写在学习golang一个月后

连接池。由于PHP没有连接池,当高并发时就会有大量的数据库连接直接冲击到MySQL上,最终导致数据库挂掉。虽然Swoole有连接池,但是Swoole只是PHP的...

2552
来自专栏比原链

Derek解读Bytom源码-P2P网络 地址簿

Gitee地址:https://gitee.com/BytomBlockchain/bytom

841
来自专栏杨建荣的学习笔记

一天内碰到的3个rac节点问题 (r6笔记第36天)

说到问题,真是层出不穷,自己也算搭建了也不少的rac环境的,但是在本地试验的时候总是会碰到一些问题,昨晚铲掉旧环境,搭建了两遍rac环境,终于在凌晨搭建好了环境...

3457
来自专栏xingoo, 一个梦想做发明家的程序员

开启服务和停止服务

Start函数用于开启服务 1 初始化状态变量 2 创建监听套接字 3 加载使用扩展API函数 4 创建完成端口对象 5 建立监听套接字和完成端口对象间的关联 ...

2808
来自专栏大内老A

Windows安全认证是如何进行的?[Kerberos篇]

最近一段时间都在折腾安全(Security)方面的东西,比如Windows认证、非对称加密、数字证书、数字签名、TLS/SSL、WS-Security等。如果时...

2307
来自专栏SDNLAB

Ryu:如何在LLDP中添加自定义LLDPDU

在许多实验场景中,都需要使用链路发现协议(LLDP)来发现链路,从而构建网络拓扑。然而LLDP协议不仅仅可以用来发现拓扑,也可以用于时延检测等业务。LLDP通过...

4046
来自专栏程序员的SOD蜜

PDF.NET SOD 开源框架红包派送活动 && 新手快速入门指引

一、框架的由来  快速入门 有关框架的更多信息,请看框架官方主页! 本套框架的思想是借鉴Java平台的Hibernate 和 iBatis 而来,兼有...

2909
来自专栏安恒网络空间安全讲武堂

XCTF-赛博地球杯工业互联网安全大赛web部分题解

0x01工控云管理系统项目管理页面解析漏洞 题目首先给出了源码: `http://47.104.156.32:20007/view-source.php` 关键...

6598
来自专栏大魏分享(微信公众号:david-share)

通过Swagger管理API:API Management学习第一篇

3 Scale有个很好的功能,它提供ActiveDocs实时文档。它基于Swagger框架,提供了一种记录API的方法,并包含在Developer Portal...

1283
来自专栏黑泽君的专栏

day54_BOS项目_06

第一步:根据提供的 业务受理.pdm 文件生成建表文件 bos_qp.sql 第二步:由于业务受理.pdm 文件中有伪表,所以我们需要修改生成的建表文件,修改如...

942

扫码关注云+社区

领取腾讯云代金券