12

SpringBoot代码生成器,从此不用手撸代码

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzA3OTUyNjkwMw%3D%3D&%3Bmid=2656653629&%3Bidx=1&%3Bsn=03dddf92ae2ad6a11d7ed16c1137248f
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

点击▲关注 “ 爪哇笔记 ”   给公众号标星置顶

更多精彩 第一时间直达

z6JBNfe.jpg!web

前言

通常在开始开发项目的时候,首先会建立好数据库相关表,然后根据表结构生成 Controller、Service、DAO、Model 以及一些前端页面。

如果开发前没有强制的约束,而每个程序员都有自己的编码习惯,最终会导致一个项目呈现出多种编码风格。再有就是一些 CRUD 的列表功能,基本是没啥挑战性的,纯粹苦力活,浪费时间。

所以,根据公司现有框架,开发一款统一风格的代码生成器还是很有必要的。

技术选型

开发框架: SpringBoot+JPA ,考虑到会生成各种前后端代码文件,这里我们选用 freemarker 模板引擎来制作相应的模板。

实现思路

获取表结构信息

首先我们定义一个实体类,为了使用方便,把表和字段信息放到了一个类中:

/**
 * 表以及相关字段信息
 */
@Data
public class AppGen extends PageBean implements Serializable {

    /**
     * 表名
     */
    private String tableName;
    /**
     * 实体类名
     */
    private String entityName;
    /**
     * 实体类名 首字母小写
     */
    private String lowerEntityName;
    /**
     * 表备注
     */
    private String tableComment;
    /**
     * 表前缀
     */
    private String prefix;
    /**
     * 功能描述
     */
    private String function;

    /**
     * 列名
     */
    private String columnName;
    /**
     * 实体列名
     */
    private String entityColumnName;
    /**
     * 列描述
     */
    private String columnComment;

    /**
     * 类型
     */
    private String dataType;

    /**
     * 自增
     */
    private Object columnExtra;
    /**
     * 长度
     */
    private Object columnLength;

    private List<AppGen> 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);
}

mUf6nub.png!web

制作模板

模板太多了,这里只以 Controller 模板为例,贴一下实现代码,更多模板见源码:

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;

    /**
     * 列表
     */
    @PostMapping("/list")
    public Result list(${entityName} ${function}){
        return ${function}Service.list(${function});
    }
    /**
     * 查询
     */
    @PostMapping("/get")
    public Result get(Long id){
        return ${function}Service.get(id);
    }
    /**
     * 保存
     */
    @PostMapping("/save")
    public Result save(@RequestBody ${entityName} ${function}){
        return ${function}Service.save(${function});
    }

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

说白了其实就是传递参数,把一些可变的代码片段使用 ${name} 形式编写。

代码生成

有点长,慢慢看,其实就是渲染各种前后端模板:

/**
 * 生成代码
 * @param gen
 * @return
 * @throws IOException
 * @throws TemplateException
 */
@PostMapping("/create")
public Result create(@RequestBody AppGen gen) throws IOException, TemplateException {
    /**
     * 获取表字段以及注释
     */
    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;
    /**
     * 后端代码
     */
    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");
    /**
     * 前端代码
     */
    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");
    /**
     * 生成静态页面
     */
    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");
    /**
     * 生成后端代码 repository
     */
    template = configuration.getTemplate("java/repository.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,repositoryFile,"UTF-8");
    /**
     * 生成后端代码 entity
     */
    template = configuration.getTemplate("java/entity.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,entityFile,"UTF-8");
    /**
     * 生成后端代码 service
     */
    template = configuration.getTemplate("java/service.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,serviceFile,"UTF-8");
    /**
     * 生成后端代码 service 实现
     */
    template = configuration.getTemplate("java/serviceImpl.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,serviceImplFile,"UTF-8");
    /**
     * 生成后端代码 controller 实现
     */
    template = configuration.getTemplate("java/controller.ftl");
    text = FreeMarkerTemplateUtils.processTemplateIntoString(
            template, gen);
    FileUtil.writeString(text,controllerFile,"UTF-8");
    return Result.ok();
}

生成逻辑还是很傻瓜的,后期会慢慢优化,比如根据字段类型生成不同的表单形式,可以自定义字段是否显示等的。

小结

总的来说,还是比较容易上手的,相对于一些简单的列表功能分分钟撸出效果,开发一分钟,喝茶一整天。当然对于一些复杂的效果,还是自己一一去实现,但这并不影响生成器的实用性。

源码

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

▲扫一扫进群交流,期待与你一起进步

有兴趣的小伙伴们可以阅读原文获取项目源码,如果觉得不错可以给个小星星,有什么好的意见和建议也都使劲扔过来吧。

你点的每个在看,我都认真当成了喜欢


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK