1.逆向工程获取数据库元对象

目前的代码生成器是通过逆向工程获取指定Schema的表信息,包括表的注释,表中字段信息,字段注释。(为了后面适配Oracle数据库,DM数据库等,应该封装接口,因为时间关系只实现了Mysql数据库。)

package com.cll.jtool.template.mapper;


import com.cll.jtool.template.bean.domain.Column;
import com.cll.jtool.template.bean.domain.Schema;
import com.cll.jtool.template.bean.domain.Table;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface MysqlObjectMapper {

    /**
     * 查询表名,表注释
     * @param schema
     * @param table
     * @return
     */
    List<Table> selectTables(@Param("schema") String schema, @Param("table") String table);

    /**
     * 获取指定表的列 元信息
     * @param schema
     * @param table
     * @return
     */
    List<Column> selectColumns(@Param("schema") String schema, @Param("table") String table);

    /**
     * 获取指定表
     * @param schema
     * @param table
     * @return
     */
    Table selectTable(@Param("schema") String schema, @Param("table") String table);
}

2.数据类型处理

需要将Mysql数据库的数据类型映射成Java数据库的数据类型,这里通过Regex简单实现了常用的数据类型。

package com.cll.jtool.template.mapping;

import com.cll.jtool.template.bean.domain.Column;
import com.cll.jtool.template.bean.domain.Table;

import java.util.Locale;

public class MysqlColumnMapping {

    public static final String integerRegex = "TINYINT|SMALLINT|MEDIUMINT|INT";
    public static final String stringRegex = "CHAR|VARCHAR|TEXT|MEDIUMTEXT|LONGTEXT";

    public static final String timeRegex = "DATE|TIME|DATETIME|TIMESTAMP";

    public static final String longRegex = "BIGINT";


    public static void mapping(Table table) {
        for (Column field : table.getFields()) {
            String dataType = field.getDataType().toUpperCase(Locale.ROOT);
            if (dataType.matches(stringRegex)) {
                field.setJavaDataType("String");
            } else if (dataType.matches(longRegex)) {
                field.setJavaDataType("Long");
            } else if (dataType.matches(integerRegex)) {
                field.setJavaDataType("Integer");
            } else if (dataType.matches(timeRegex)) {
                field.setJavaDataType("Date");
            }
        }
    }
}

3.准备给Bean填充数据

以Contoller文件为例,每个Controller需要继承父类,父类包含这些需要生成的文件的共有属性。

package com.cll.jtool.template.bean.domain.base;

import lombok.Data;


@Data
public class FileMeta {
    /**
     * 名称
     */
    private String name;
2
    /**
     * 绝对路径
     */

    private String absolutePath;


    /**
     * 大驼峰命名风格
     */
    private String upperCamelStyleName;

    /**
     * 小驼峰命名风格
     */
    private String lowerCamelStyleName;
}


4.准备Velocity模板文件

模板文件借鉴了MybatisPlus的VM文件,改成了自己的代码风格。

package ${package.Controller};
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import com.cll.jtool.common.bean.Result;
import com.cll.jtool.service.${service.name};




/**
 * $!{table.comment} 接口
 *
 * @author ${author}
 * @since ${date}
 */
@RestController
@RequestMapping("/${name.lowerCamelStyleName}")
@Api(value="${table.comment}")
public class ${controller.name} {

     @Autowired
     private ${service.name}  ${service.lowerCamelStyleName};

     @ApiOperation(value = "${description.ADD}")
     @PostMapping("/add")
     public Result ${method.ADD}(){
          return Result.success();
     }

     @ApiOperation(value = "${description.DELETE}")
     @PostMapping("/delete")
     public Result ${method.DELETE}(Long id){
          return Result.success();
     }

     @ApiOperation(value = "${description.GET}")
     @PostMapping("/get")
     public Result ${method.GET}(Long id){
          return Result.success();
     }

     @ApiOperation(value = "${description.EDIT}")
     @PostMapping("/edit")
     public Result ${method.EDIT}(){
           return Result.success();
     }

     @ApiOperation(value = "${description.QUERY}")
     @PostMapping("/query")
     public Result ${method.QUERY}(){
          return Result.success();
     }


     @ApiOperation(value = "${description.EXPORT}")
     @PostMapping("/export")
     public Result ${method.EXPORT}(){
          return Result.success();
     }


     @ApiOperation(value = "${description.IMPORT}")
     @PostMapping("/import")
     public Result ${method.IMPORT}(){
          return Result.success();
     }

}

Java代码生成器(丐版)_spring

5.生成代码

最后通过生成器就可以将代码生成到指定的目录了,下面是生成的代码。(为了鼠标垫,不管这么多了)

package com.cll.jtool.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import com.cll.jtool.common.bean.Result;
import com.cll.jtool.service.SUserService;


/**
 *  接口
 *
 * @author ${author}
 * @since ${date}
 */
@RestController
@RequestMapping("/sUser")
@Api(value="${table.comment}")
public class SUserController {

     @Autowired
     private SUserService  sUserService;

     @ApiOperation(value = "新增")
     @PostMapping("/add")
     public Result addItem(){
          return Result.success();
     }

     @ApiOperation(value = "根据ID删除")
     @PostMapping("/delete")
     public Result deleteItem(Long id){
          return Result.success();
     }

     @ApiOperation(value = "根据ID获取详情")
     @PostMapping("/get")
     public Result getItem(Long id){
          return Result.success();
     }

     @ApiOperation(value = "根据ID编辑")
     @PostMapping("/edit")
     public Result editItem(){
           return Result.success();
     }

     @ApiOperation(value = "条件分页查询")
     @PostMapping("/query")
     public Result queryItems(){
          return Result.success();
     }


     @ApiOperation(value = "条件Excel导出")
     @PostMapping("/export")
     public Result exportItem(){
          return Result.success();
     }


     @ApiOperation(value = "Excel数据导入")
     @PostMapping("/import")
     public Result importItem(){
          return Result.success();
     }

}

生成代码

package com.cll.jtool.template.generator;

import com.cll.jtool.common.util.NamingUtil;
import com.cll.jtool.template.bean.domain.*;
import com.cll.jtool.template.bean.domain.Package;
import com.cll.jtool.template.mapper.MysqlObjectMapper;

import com.cll.jtool.template.mapping.MysqlColumnMapping;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.FieldMethodizer;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.List;
import java.util.Properties;

@Component
public class Generator {

    @Autowired
    private MysqlObjectMapper mysqlObjectMapper;


    public void generate() throws IOException {
        //从数据库读取对象元信息
        Table table = mysqlObjectMapper.selectTable("jtool", "s_user");
        List<Column> columns = mysqlObjectMapper.selectColumns("jtool", "s_user");
        table.setFields(columns);
        MysqlColumnMapping.mapping(table);

        //设置基本数据
        Package pa = new Package();
        pa.setEntity("com.cll.jtool.bean.domain");
        pa.setMapper("com.cll.jtool.mapper");
        pa.setService("com.cll.jtool.service");
        pa.setServiceImpl("com.cll.jtool.service.impl");
        pa.setController("com.cll.jtool.controller");

        Name name = new Name();
        name.setUpperCamelStyleName(NamingUtil.getUpperCamelCase(table.getTableName()));
        name.setLowerCamelStyleName(NamingUtil.getLowerCamelCase(table.getTableName()));

        Entity entity = new Entity();
        entity.setName(name.getUpperCamelStyleName());
        entity.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\bean\\" + entity.getName() + ".java");

        Controller controller = new Controller();
        controller.setName(name.getUpperCamelStyleName()+"Controller");
        controller.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\controller\\" + controller.getName() + ".java");

        Mapper mapper = new Mapper();
        mapper.setName(name.getUpperCamelStyleName()+"Mapper");
        mapper.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\mapper\\" + mapper.getName() + ".java");


        Service service = new Service();
        service.setName(name.getUpperCamelStyleName()+"Service");
        service.setLowerCamelStyleName(name.getLowerCamelStyleName()+"Service");
        service.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\service\\" + service.getName() + ".java");

        ServiceImpl serviceImpl = new ServiceImpl();
        serviceImpl.setName(name.getUpperCamelStyleName()+"ServiceImpl");
        serviceImpl.setLowerCamelStyleName(name.getLowerCamelStyleName()+"ServiceImpl");
        serviceImpl.setAbsolutePath("C:\\Users\\Desktop\\Java\\Java1\\jtool\\jtool-security\\src\\main\\java\\com\\cll\\jtool\\service\\impl\\" + serviceImpl.getName() + ".java");


        //填充上下文数据
        Properties properties = new Properties();
        properties.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(properties);

        VelocityContext context = new VelocityContext();
        //公共属性
        context.put("package", pa);

        //表相关属性
        context.put("table", table);
        context.put("entity", entity);
        context.put("mapper", mapper);
        context.put("service", service);
        context.put("serviceImpl", serviceImpl);
        context.put("controller", controller);
        context.put("name", name);
        context.put("description",new FieldMethodizer( "com.cll.jtool.template.bean.domain.Description"));
        context.put("method",new FieldMethodizer( "com.cll.jtool.template.bean.domain.Method"));

        //加载模板
        Template template = Velocity.getTemplate("/template/entity.java.vm", "utf-8");
        Template template2 = Velocity.getTemplate("/template/controller.java.vm", "utf-8");
        Template template3 = Velocity.getTemplate("/template/service.java.vm", "utf-8");
        Template template4 = Velocity.getTemplate("/template/serviceImpl.java.vm", "utf-8");
        Template template5 = Velocity.getTemplate("/template/mapper.java.vm", "utf-8");






        FileWriter fileWriter = new FileWriter(entity.getAbsolutePath());
        FileWriter fileWriter2 = new FileWriter(controller.getAbsolutePath());
        FileWriter fileWriter3 = new FileWriter(service.getAbsolutePath());
        FileWriter fileWriter4 = new FileWriter(serviceImpl.getAbsolutePath());
        FileWriter fileWriter5 = new FileWriter(mapper.getAbsolutePath());

        //渲染模板
        template.merge(context, fileWriter);
        template2.merge(context, fileWriter2);
        template3.merge(context, fileWriter3);
        template4.merge(context, fileWriter4);
        template5.merge(context, fileWriter5);

        fileWriter.close();
        fileWriter2.close();
        fileWriter3.close();
        fileWriter4.close();
        fileWriter5.close();

    }
}


6.总结

后面希望能在此基础上完成各种文件的生成,最好能做成可视化的形式,避免在代码里反复配置。最好能实现一键删除功能,删除生成的代码文件。总之有些吃力不讨好,哈哈,感觉需要做的太多了。