美文网首页
SpringBoot代码生成器,从此不用手撸代码

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

作者: 小柒2012 | 来源:发表于2020-05-24 20:47 被阅读0次
    image

    前言

    通常在开始开发项目的时候,首先会建立好数据库相关表,然后根据表结构生成 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);
    }
    
    image

    制作模板

    模板太多了,这里只以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

    相关文章

      网友评论

          本文标题:SpringBoot代码生成器,从此不用手撸代码

          本文链接:https://www.haomeiwen.com/subject/acfsahtx.html