SpringBoot code generator, no need to manually roll code from now on

preface

Usually, when starting to develop a project, the database related tables will be established first, and then Controller, Service, DAO, Model and some front-end pages will be generated according to the table structure.

If there are no mandatory constraints before development, and every programmer has his own coding habits, it will eventually lead to a project showing a variety of coding styles. Then there are some CRUD list functions, which are basically not challenging, pure coolie work and waste of time.

Therefore, according to the company's existing framework, it is necessary to develop a unified style code generator.

Technology selection

Development framework: SpringBoot+JPA. Considering that various front and back end code files will be generated, we use freemarker template engine to make corresponding templates.

Realization ideas

Get table structure information

First, we define an entity class. For convenience, we put table and field information into one class:

/**
 * Table and related field information
 */
@Data
public class AppGen extends PageBean implements Serializable {

    /**
     * Table name
     */
    private String tableName;
    /**
     * Entity class name
     */
    private String entityName;
    /**
     * Entity class name initial lowercase
     */
    private String lowerEntityName;
    /**
     * fpt 
     */
    private String tableComment;
    /**
     * Table prefix
     */
    private String prefix;
    /**
     * Function description
     */
    private String function;

    /**
     * Column name
     */
    private String columnName;
    /**
     * Entity column name
     */
    private String entityColumnName;
    /**
     * Column description
     */
    private String columnComment;

    /**
     * type
     */
    private String dataType;

    /**
     * Self increasing
     */
    private Object columnExtra;
    /**
     * length
     */
    private Object columnLength;

    private List<AppGen> list;

}

Get table list:

@Override
@Transactional(readOnly = true)
public Result list(AppGen gen){
    String countSql = "SELECT COUNT(*) FROM information_schema.tables ";
    countSql +="WHERE table_schema='tools'";
    Long totalCount = dynamicQuery.nativeQueryCount(countSql);
    PageBean<AppGen> data = new PageBean<>();
    if(totalCount>0){
        String nativeSql = "SELECT table_name as tableName,table_comment as tableComment ";
        nativeSql+="FROM information_schema.tables WHERE table_schema='tools'";
        Pageable pageable = PageRequest.of(gen.getPageNo(),gen.getPageSize());
        List<AppGen> list = dynamicQuery.nativeQueryPagingListModel(AppGen.class,pageable, nativeSql);
        data = new PageBean<>(list, totalCount);
    }
    return Result.ok(data);
}

Make template

There are too many templates. Take the Controller template as an example and paste the implementation code. For more templates, see the source code:

package com.tools.module.${prefix}.web;

import com.tools.common.config.AbstractController;
import com.tools.common.model.Result;
import com.tools.module.${prefix}.entity.${entityName};
import com.tools.module.${prefix}.service.${entityName}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/${prefix}/${function}")
public class ${entityName}Controller extends AbstractController {

    @Autowired
    private ${entityName}Service ${function}Service;

    /**
     * list
     */
    @PostMapping("/list")
    public Result list(${entityName} ${function}){
        return ${function}Service.list(${function});
    }
    /**
     * query
     */
    @PostMapping("/get")
    public Result get(Long id){
        return ${function}Service.get(id);
    }
    /**
     * preservation
     */
    @PostMapping("/save")
    public Result save(@RequestBody ${entityName} ${function}){
        return ${function}Service.save(${function});
    }

    /**
     * delete
     */
    @PostMapping("/delete")
    public Result delete(Long id){
        return ${function}Service.delete(id);
    }
}

In fact, it is to pass parameters and write some variable code fragments in the form of ${name}.

code generation

It's a bit long. Look at it slowly, it's actually rendering various front and rear templates:

/**
 * Generate code
 * @param gen
 * @return
 * @throws IOException
 * @throws TemplateException
 */
@PostMapping("/create")
public Result create(@RequestBody AppGen gen) throws IOException, TemplateException {
    /**
     * Get table fields and comments
     */
    List<AppGen> list = genService.getByTable(gen);
    String name = gen.getTableName();
    String[] table =  StringUtils.split(name,"_");
    gen.setPrefix(table[0]);
    gen.setFunction(table[1]);
    gen.setEntityName(GenUtils.allInitialCapital(gen.getTableName()));
    list.stream().forEach(column-> {
       column.setEntityColumnName(GenUtils.secInitialCapital(column.getColumnName()));
    });
    gen.setList(list);
    String baseFile = filePath+ SystemConstant.SF_FILE_SEPARATOR+"com"+
            SystemConstant.SF_FILE_SEPARATOR+ "tools"+
            SystemConstant.SF_FILE_SEPARATOR+ "module"+
            SystemConstant.SF_FILE_SEPARATOR+ gen.getPrefix()+SystemConstant.SF_FILE_SEPARATOR;
    /**
     * Back end code
     */
    File entityFile = FileUtil.touch(baseFile+"entity"+
            SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+".java");
    File repositoryFile = FileUtil.touch(baseFile+"repository"+
            SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+"Repository.java");
    File serviceFile = FileUtil.touch(baseFile+"service"+
            SystemConstant.SF_FILE_SEPARATOR+gen.getEntityName()+"Service.java");
    File serviceImplFile = FileUtil.touch(baseFile+"service"+
            SystemConstant.SF_FILE_SEPARATOR+"impl"+SystemConstant.SF_FILE_SEPARATOR+
            gen.getEntityName()+"ServiceImpl.java");
    File controllerFile = FileUtil.touch(baseFile+"web"+
            SystemConstant.SF_FILE_SEPARATOR + gen.getEntityName() + "Controller.java");
    /**
     * Front end code
     */
    String htmlPath =  filePath+
            SystemConstant.SF_FILE_SEPARATOR + "templates"+
            SystemConstant.SF_FILE_SEPARATOR + gen.getPrefix()+
            SystemConstant.SF_FILE_SEPARATOR + gen.getFunction()+SystemConstant.SF_FILE_SEPARATOR;
    File listFile = FileUtil.touch(htmlPath + "list.html");
    File formFile = FileUtil.touch(htmlPath + "form.html");
    /**
     * Generate static page
     */
    Template template = configuration.getTemplate("html/list.ftl");
    String text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,listFile,"UTF-8");
    template = configuration.getTemplate("html/form.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,formFile,"UTF-8");
    /**
     * Generate backend code repository
     */
    template = configuration.getTemplate("java/repository.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,repositoryFile,"UTF-8");
    /**
     * Generate backend code entity
     */
    template = configuration.getTemplate("java/entity.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,entityFile,"UTF-8");
    /**
     * Generate backend code service
     */
    template = configuration.getTemplate("java/service.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,serviceFile,"UTF-8");
    /**
     * Generate backend code service implementation
     */
    template = configuration.getTemplate("java/serviceImpl.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,serviceImplFile,"UTF-8");
    /**
     * Generate backend code controller implementation
     */
    template = configuration.getTemplate("java/controller.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,controllerFile,"UTF-8");
    return Result.ok();
}

The generation logic is still stupid. It will be optimized later. For example, different forms can be generated according to the field type, and whether the field is displayed can be customized.

Summary

Generally speaking, it is relatively easy to use. Compared with some simple list functions, it can produce effect in minutes, develop for one minute and drink tea for a whole day. Of course, for some complex effects, it's better to achieve them one by one.

Source code

https://gitee.com/52itstyle/SPTools

Tags: Java Database SpringBoot FreeMarker

Posted on Fri, 22 May 2020 05:03:10 -0400 by mindevil