Java Code Generator [Beggars Edition]

1. Reverse engineering to obtain database meta objects

The current code generator obtains the table information of the specified Schema through reverse engineering, including table comments, field information in the table, and field comments. (In order to adapt to Oracle database, DM database, etc. later, the interface should be encapsulated, because only the Mysql database is implemented due to time constraints.)

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 {<!-- -->

    /**
     * Query table name, table comments
     * @param schema
     * @param table
     * @return
     */
    List<Table> selectTables(@Param("schema") String schema, @Param("table") String table);

    /**
     * Get column meta information of the specified table
     * @param schema
     * @param table
     * @return
     */
    List<Column> selectColumns(@Param("schema") String schema, @Param("table") String table);

    /**
     * Get the specified table
     * @param schema
     * @param table
     * @return
     */
    Table selectTable(@Param("schema") String schema, @Param("table") String table);
}

2. Data type processing

The data types of the Mysql database need to be mapped to the data types of the Java database. Commonly used data types are simply implemented through 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. Prepare to fill data into the Bean
Taking the Controller file as an example, each Controller needs to inherit the parent class, which contains the common attributes of the files that need to be generated.

package com.cll.jtool.template.bean.domain.base;
import lombok.Data;
@Data
public class FileMeta {<!-- -->
    /**
     * name
     */
    private String name;

    /**
     * Absolute path
     */

    private String absolutePath;


    /**
     * Big camel case naming style
     */
    private String upperCamelStyleName;

    /**
     * Little camel case naming style
     */
    private String lowerCamelStyleName;
}

4. Prepare Velocity template file
The template file draws on the VM file of MybatisPlus and changes it to its own code style.

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} interface
 *
 * @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();
     }

}

5. Generate code
Finally, the code can be generated to the specified directory through the generator. The following is the generated code. (For the sake of the mouse pad, no matter so much)

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;


/**
 * Interface
 *
 * @author ${author}
 * @since ${date}
 */
@RestController
@RequestMapping("/sUser")
@Api(value="${table.comment}")
public class SUserController {<!-- -->

     @Autowired
     private SUserService sUserService;

     @ApiOperation(value = "New")
     @PostMapping("/add")
     public Result addItem(){<!-- -->
          return Result.success();
     }

     @ApiOperation(value = "Delete based on ID")
     @PostMapping("/delete")
     public Result deleteItem(Long id){<!-- -->
          return Result.success();
     }

     @ApiOperation(value = "Get details based on ID")
     @PostMapping("/get")
     public Result getItem(Long id){<!-- -->
          return Result.success();
     }

     @ApiOperation(value = "Edit based on ID")
     @PostMapping("/edit")
     public Result editItem(){<!-- -->
           return Result.success();
     }

     @ApiOperation(value = "Conditional paging query")
     @PostMapping("/query")
     public Result queryItems(){<!-- -->
          return Result.success();
     }


     @ApiOperation(value = "Conditional Excel export")
     @PostMapping("/export")
     public Result exportItem(){<!-- -->
          return Result.success();
     }


     @ApiOperation(value = "Excel data import")
     @PostMapping("/import")
     public Result importItem(){<!-- -->
          return Result.success();
     }

}

Generate code

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 {<!-- -->
        //Read object meta information from the database
        Table table = mysqlObjectMapper.selectTable("jtool", "s_user");
        List<Column> columns = mysqlObjectMapper.selectColumns("jtool", "s_user");
        table.setFields(columns);
        MysqlColumnMapping.mapping(table);

        //Set basic data
        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") ;


        //Fill in context data
        Properties properties = new Properties();
        properties.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(properties);

        VelocityContext context = new VelocityContext();
        //Public properties
        context.put("package", pa);

        //Table related attributes
        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"));

        //load template
        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());

        //render template
        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. Summary
Later, I hope to complete the generation of various files on this basis, preferably in a visual form to avoid repeated configuration in the code. It is best to implement a one-click deletion function to delete the generated code files. All in all, it’s a bit thankless, haha, it feels like there’s too much to do.