自定义基于maven插件的代码生成器

前言

最近研究了一下maven的自定义插件,之前用过maven中的mybatis-generator插件,此插件是基于tk-mybatis根据表生成实体类及dao层和mapper文件。于是便有了自己写一个类似的插件用于生成controller层,service层及service的实现类的想法。

由于篇幅问题,此处只列出生成controller层的代码。

具体实现

1. pom.xml

pom文件中列出了一些插件所要使用的依赖,这里需要注意的是我并没有加上mysql的依赖,一点是因为不知道要使用插件的项目中mysql的版本,所以选择在使用插件的时候添加依赖的方式,另一点就是加上mysql8的依赖,项目install会报错。具体错误及错误的排查与解决下面会提到。

这些需要使用的依赖在项目install之后,在另一个新项目中使用此插件的时候就不需要再次添加了。具体使用插件的方式下面也会介绍。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>plugindemo</artifactId>
  <packaging>maven-plugin</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>plugindemo Maven Mojo</name>
  <url>http://maven.apache.org</url>

  <dependencies>

    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>2.0</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <!--此依赖提供@mojo和@parameter注解-->
    <dependency>
      <groupId>org.apache.maven.plugin-tools</groupId>
      <artifactId>maven-plugin-annotations</artifactId>
      <version>3.4</version>
    </dependency>

    <!--maven提供的获取资源文件的依赖-->
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-model</artifactId>
      <version>2.2.1</version>
    </dependency>

    <!-- Apache Commons -->
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.4</version>
    </dependency>

    <dependency>
      <groupId>commons-dbutils</groupId>
      <artifactId>commons-dbutils</artifactId>
      <version>1.6</version>
    </dependency>

    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>

    <dependency>
      <groupId>org.apache.velocity</groupId>
      <artifactId>velocity</artifactId>
      <version>1.7</version>
    </dependency>

  </dependencies>


</project>

2. MoJo的代码

package com.example.plugin;

import com.example.core.entity.ColumnDefinition;
import com.example.core.entity.ConfigContext;
import com.example.core.helper.ColumnHelper;
import com.example.core.helper.DBHelper;
import com.example.core.service.Callback;
import com.example.core.util.FileUtil;
import com.example.core.util.VelocityUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @Description TODO
 * @Author LiuYue
 * @Date 2019/1/2
 * @Version 1.0
 */

@Mojo(name = "generator")
public class GeneratorMojo extends AbstractMojo {

    //项目构建根目录
    @Parameter(property = "project.build.directory", required = true)
    private File outputDirectory;

    //项目构建资源文件根目录
    @Parameter(property = "project.build.sourceDirectory", required = true, readonly = true)
    private File sourcedir;

    //项目根目录 如:E:\Research\maven_plugin
    @Parameter(property = "project.basedir", required = true, readonly = true)
    private File basedir;

    private String getSourcePath(){
        return String.format("%s/src/main/resources/",basedir.getAbsolutePath());
    }

    private String getOutputPath(){
        return String.format("%s/src/main/java/",basedir.getAbsolutePath());
    }


    public void execute() throws MojoExecutionException, MojoFailureException {

        try {
            //得到配置文件对象 将指定输出路径与读取资源文件路径
            ConfigContext configContext = new ConfigContext(getSourcePath(),getOutputPath());

            //初始化DB工具类
            DBHelper dbHelper = new DBHelper(configContext);

            //得到数据库表的元数据
            List<Map<String,Object>> resultList= dbHelper.descTable();

            //元数据处理
            List<ColumnDefinition> columnDefinitionList = ColumnHelper.covertColumnDefinition(resultList);

            String rootPath = configContext.getOutputPath() + getPackagePath(configContext.getTargetPackage());

            String serviceImplPath = configContext.getOutputPath() + configContext.getTargetPackage() + "/" + configContext.getTargetServiceImpl();

            doGenerator(configContext, columnDefinitionList, new Callback() {
                public void write(ConfigContext configContext, VelocityContext context) {


                    FileUtil.writeFile(rootPath+configContext.getTargetEntity(),                   //输出目录
                            String.format("%s.java",configContext.getTargetName()),    //文件名
                            VelocityUtil.render("entity.vm", context));                 //模板生成内容

                    FileUtil.writeFile(rootPath+configContext.getTargetService(),
                            String.format("I%sService.java", configContext.getTargetName()),
                            VelocityUtil.render("contract.vm", context));

                    FileUtil.writeFile(rootPath+configContext.getTargetDao(),
                            String.format("%sDao.java", configContext.getTargetName()),
                            VelocityUtil.render("dao.vm", context));

                    FileUtil.writeFile(getPackagePath(serviceImplPath),
                            String.format("%sServiceImpl.java", configContext.getTargetName()),
                            VelocityUtil.render("service.vm", context));

                    FileUtil.writeFile(rootPath+configContext.getTargetController(),
                            String.format("%sController.java", configContext.getTargetName()),
                            VelocityUtil.render("controller.vm", context));
                }
            });
        } catch (Exception e){
            throw new MojoExecutionException("unable to generator codes of table.",e);
        }

    }

    private static void doGenerator(ConfigContext configContext, Object data, Callback callback) {
        //配置velocity的资源加载路径
        Properties velocityPros = new Properties();
        velocityPros.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, configContext.getSourcePath());
        Velocity.init(velocityPros);

        //封装velocity数据
        VelocityContext context = new VelocityContext();
        context.put("table", configContext.getTargetTable());
        context.put("name", configContext.getTargetName());
        context.put("package", configContext.getTargetPackage());
        context.put("columns", data);
        context.put("entity", configContext.getTargetEntity());
        context.put("service", configContext.getTargetService());
        context.put("serviceImpl", configContext.getTargetServiceImpl());
        context.put("controller", configContext.getTargetController());
        context.put("dao", configContext.getTargetDao());

        callback.write(configContext, context);

    }

    private static String getPackagePath(String targetPackage){
        return StringUtils.replace(targetPackage,".","/")+"/";
    }
}

ConfigContext对象中的属性,存放了数据库连接信息,生成的各个文件要存放的路径。这些信息都是通过proputil(此工具类代码就不列出来了)读取generator.properties文件获取的,所以在使用插件的时候需要根据在配置文件中配置好数据库连接下信息、表名及对应的文件所要生成的路径。

package com.example.core.entity;

import com.example.core.util.PropsUtil;
import lombok.Getter;
import lombok.Setter;

import java.util.Properties;

@Setter
@Getter
public class ConfigContext {

    private String sourcePath;
    private String outputPath;

    private String driver;
    private String url;
    private String userName;
    private String password;
    private String targetTable;
    private String targetName;
    private String targetPackage;
    private String targetEntity;
    private String targetService;
    private String targetServiceImpl;

    private String targetController;
    private String targetDao;

    public ConfigContext(String sourcePath, String outputPath) {

        Properties properties = PropsUtil.loadProps(sourcePath+Constant.CONFIG_PROPS);
        setSourcePath(sourcePath);
        setOutputPath(outputPath);

        setDriver(PropsUtil.getString(properties, Constant.JDBC_DRIVER));
        setUrl(PropsUtil.getString(properties, Constant.JDBC_URL));
        setUserName(PropsUtil.getString(properties, Constant.JDBC_USERNAME));
        setPassword(PropsUtil.getString(properties, Constant.JDBC_PASSWORD));

        setTargetTable(PropsUtil.getString(properties, Constant.TARGET_TABLE));
        setTargetName(PropsUtil.getString(properties, Constant.TARGET_NAME));
        setTargetPackage(PropsUtil.getString(properties, Constant.TARGET_PACKAGE));
        setTargetEntity(PropsUtil.getString(properties, Constant.TARGET_ENTITY));
        setTargetService(PropsUtil.getString(properties, Constant.TARGET_SERVICE));
        setTargetServiceImpl(PropsUtil.getString(properties, Constant.TARGET_SERVICEIMPL));
        setTargetController(PropsUtil.getString(properties, Constant.TARGET_CONTROLLER));
        setTargetDao(PropsUtil.getString(properties, Constant.TARGET_DAO));
    }

    

}

dbHelper中使用dbutil连接数据库,构造函数传入ConfigContext,根据ConfigContext属性进行初始化连接。

dbHelper中的descTable会获取指定表的详细信息,如字段名、字段数据类型等元数据信息。然后利用工具类ColumnHelper将这些元数据信息转换成ColumnDefinition对象。后面会使用此对象生成实体类。

package com.example.core.helper;

import com.example.core.entity.ConfigContext;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class DBHelper {

    private DataSource dataSource;
    private QueryRunner queryRunner;
    private ConfigContext context;

    private DataSource initDataSource(ConfigContext context){
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(context.getDriver());
        dataSource.setUrl(context.getUrl());
        dataSource.setUsername(context.getUserName());
        dataSource.setPassword(context.getPassword());
        return dataSource;
    }

    public DBHelper(ConfigContext context){
        this.context = context;
        dataSource = initDataSource(this.context);
        queryRunner = new QueryRunner(dataSource);
    }

    public List<Map<String, Object>> descTable(){

        String DESC_TABLE = String.format("desc %s",context.getTargetTable());

        return queryMapList(DESC_TABLE,null);
    }

    public List<Map<String, Object>> queryMapList(String sql, Object... params) {
        List<Map<String, Object>> fieldMapList;
        try {
            fieldMapList = queryRunner.query(sql, new MapListHandler(), params);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return fieldMapList;
    }

}


可以发现后面调用了doGenerator方法,方法需要传入三个参数,一个是configContext,一个是data(刚才的ColumnDefinition),还有一个callback对象。会在此方法中将configContext中的内容与data传入到模板中,在模板中可以使用${}的方式获取这些信息。模板配置完毕后会调用callback接口中的write方法在指定路径生成文件。

callback是一个接口,此接口没有定义实现类,所以采用上述的方式调用doGenerator方法时候配置callback的参数:

package com.example.core.service;

import com.example.core.entity.ConfigContext;
import org.apache.velocity.VelocityContext;

public interface Callback {
    public void write(ConfigContext configContext, VelocityContext context);
}


通过fileUtil生成对应的.java文件,通过VelocityUtil模板工具类获取指定内容的模板,并将configContext中的值塞到里面。

3. controller模板

可以很明显的看出来,这些使用${}表达式的参数都是在Mojo中给模板中添加的属性。

package ${package}.${controller};

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMethod;

import ${package}.${service}.I${name}Service;

import ${package}.${entity}.${name};

@RestController
public class ${name}Controller {

    @Autowired
    private I${name}Service ${name}Service;

    @RequestMapping(value = "/get${name}ById",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ${name} get${name}ById(){

        long id = 1;

        return ${name}Service.loadById(id);
    }
}

遇到的问题

1. install出错

代码编写完毕执行install命令,控制台报错,使用-e打印错误信息出现如下内容:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.2:descriptor (default-descriptor) on project plugindemo: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.2:descriptor failed: 35368 -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-plugin-plugin:3.2:descriptor (default-descriptor) on project plugindemo: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.2:descriptor failed: 35368
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.PluginExecutionException: Execution default-descriptor of goal org.apache.maven.plugins:maven-plugin-plugin:3.2:descriptor failed: 35368
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:145)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
        ... 20 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 35368
        at org.objectweb.asm.ClassReader.readClass(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.apache.maven.tools.plugin.annotations.scanner.DefaultMojoAnnotationsScanner.scanFile(DefaultMojoAnnotationsScanner.java:139)
        at org.apache.maven.tools.plugin.annotations.scanner.DefaultMojoAnnotationsScanner.scan(DefaultMojoAnnotationsScanner.java:85)
        at org.apache.maven.tools.plugin.annotations.JavaAnnotationsMojoDescriptorExtractor.scanAnnotations(JavaAnnotationsMojoDescriptorExtractor.java:125)
        at org.apache.maven.tools.plugin.annotations.JavaAnnotationsMojoDescriptorExtractor.execute(JavaAnnotationsMojoDescriptorExtractor.java:104)
        at org.apache.maven.tools.plugin.scanner.DefaultMojoScanner.populatePluginDescriptor(DefaultMojoScanner.java:108)
        at org.apache.maven.plugin.plugin.AbstractGeneratorMojo.execute(AbstractGeneratorMojo.java:233)
        at org.apache.maven.plugin.plugin.DescriptorGeneratorMojo.execute(DescriptorGeneratorMojo.java:92)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
        ... 21 more

尝试了很多方法都没有解决掉此错误,最后怀疑是某个依赖导致的,然后逐个排查项目中的依赖(还好项目中所添加的依赖不多,要不然可麻烦了)。最后发现是mysql的依赖所造成的影响,关键的是我将mysql依赖改为5.1.38版本,插件install完全没有问题,但是由于我的mysql是8版本,当我将mysql改为8.0.11时安装就会报错。不知道是什么原因。

最终解决办法是插件install的时候不添加mysql依赖,因为在install的时候并不需要连接mysql数据库,而在使用插件的时候会根据需要去查询数据库中的指定表,然后根据表结构生成代码,这时候才会需要mysql的依赖,这时候根据mysql的版本添加对应版本的依赖文件。

2. 执行插件目标generator命令报错

[ERROR] Failed to execute goal com.example:plugindemo:1.0-SNAPSHOT:generator (default-cli) on project plugindemo: unable to generator codes of table. org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'com.mysql.jdbc.Driver' -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal com.example:plugindemo:1.0-SNAPSHOT:generator (default-cli) on project plugindemo: unable to generator codes of table.
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
Caused by: org.apache.maven.plugin.MojoExecutionException: unable to generator codes of table.
    at com.example.plugin.GeneratorMojo.execute(GeneratorMojo.java:95)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
    ... 21 more
Caused by: java.lang.RuntimeException: org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'com.mysql.jdbc.Driver'
    at com.example.core.helper.DBHelper.queryMapList(DBHelper.java:51)
    at com.example.core.helper.DBHelper.descTable(DBHelper.java:43)
    at com.example.plugin.GeneratorMojo.execute(GeneratorMojo.java:64)
    ... 23 more
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'com.mysql.jdbc.Driver'
    at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1429)
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    at org.apache.commons.dbutils.AbstractQueryRunner.prepareConnection(AbstractQueryRunner.java:204)
    at org.apache.commons.dbutils.QueryRunner.query(QueryRunner.java:287)
    at com.example.core.helper.DBHelper.queryMapList(DBHelper.java:49)
    ... 25 more
Caused by: java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1420)
    ... 30 more

在使用插件的时候添加mysql依赖:

<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    <plugin>
        <groupId>com.example</groupId>
        <artifactId>plugindemo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <configuration>
            <includes>
                <include>java</include>
                <include>sql</include>
            </includes>
        </configuration>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.11</version>
            </dependency>
        </dependencies>
    </plugin>
</plugins>

3. 生成的dao层文件执行insert语句报错

package com.example.demo;

import com.example.demo.entity.Student;
import com.example.demo.service.IStudentService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import tk.mybatis.spring.annotation.MapperScan;

@RunWith(SpringRunner.class)
@MapperScan("com.example.demo.dao")
@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    private IStudentService studentService;

    @Test
    public void contextLoads() {

        Student student = new Student();

        student.setAddress("shanghai");
        student.setUid(2);
        student.setSname("张三");
        student.setSage(24);

        studentService.insert(student);
    }

}

本代码生成器是基于tk-mybatis的,但是在测试生成的代码功能的时候,明明已经set了实体类的值,但是在调用tkmybatis中的insert的时候还是会报错。

Field 'id' doesn't have a default value

错误内容很明显,id没有一个默认值,id在数据库中我设置了主键且不为null,但是最后tkmybatis执行的sql却只插入了两个varchar类型的属性,其他两个int类型的属性并没有插入。再看看之前通过tk-mybatis+mybatis-generator生成的实体类代码,实体类的属性上都加了@column注解。而我配置的模板中的实体类并没有加注解,由此看来问题大概就是出在这个地方了。

在实体类的模板中加上注解的配置,最终解决此问题。(也可以将数据库中int类型的字段改为varchar的方式解决,但是设计数据库的时候总会有int类型的需要,所以还是从改模板的方向出发)

使用插件

1. pom.xml文件

在使用插件的时候只需要在pom文件中添加此插件即可,因为安装在本地环境,所以可以直接使用,后面可以考虑安装到指定站点。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency>

        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.example</groupId>
                <artifactId>plugindemo</artifactId>
                <version>1.0-SNAPSHOT</version>
                <configuration>
                    <includes>
                        <include>java</include>
                        <include>sql</include>
                    </includes>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.11</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>

2. generator.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/plugin_test?serverTimezone=UTC
jdbc.username=root
jdbc.password=root


target.table=student
target.name=Student
target.package=com.example.demo
# 实体类包名
target.entity=entity
# service接口包名
target.service=service
# service实现类包名
target.serviceImpl=service.impl
# controller包名
target.controller=controller
# dao层包名
target.dao=dao

3. 执行命令

最后执行generator命令即可,最后会在配置文件中的指定包名中生成指定的文件。

自定义基于maven插件的代码生成器

自定义基于maven插件的代码生成器