写一个比ChatGPT还牛的CRUD代码生成器

最近在做一个项目,需要新建20多张表
相信大多数同学应该和我一样,都是比较讨厌创建新表这个工作的,因为每创建一张表,都要去创建实体类、创建增删改查的接口、编写增删改查的sql代码等等,把这些事情做完,2个小时也就过去了
我就在思考啊,每一张表,就要耗费两个小时,20多张表,那就是40多个小时,一周的时间就这样过去了。
思考
这谁受得了呀,所以我打算写一个工具,把这些代码都自动生成出来!
代码都自动生成出来
在连续爆肝了5个晚上之后,我做出了这款自动生成业务代码的工具!
自动生成业务代码
我把它放在了我的工具站上,大家可以访问这个域名直接使用https://utilsbox.cn/?app=bizcode
使用演示
下面给大家演示一下
假设我们现在创建一个商品表
首先填写表名和表的中文名称
然后我们添加商品表对应的字段,这些操作和我们日常使用的数据库工具差不多
把字段填写好了之后,点击“一键生成代码”
完成表信息编辑
高潮的地方来了
db层、业务层、甚至是controller层的代码,工具都帮我们自动生成了!
来看下代码,建表sql、增删改查sql、表对应的实体类、db层的接口类、业务层的实体类、业务层的接口类、业务接口的实现类、业务层实体类和db层实体类的转换器,最后是controller层,这些代码全都帮我们生成好了。
代码全都帮我们生成好了
这是什么概念呢
现在我们只需要把这些代码拷贝到项目里,简单设置一下类的引用,增删改查这些基本功能,就已经可以直接给前端去调用了。
crud
很多同学可能会问,如果是现有的数据表,再来这里添加一次感觉太麻烦了
这个问题我也遇到了,所以我做了一个识别建表sql的功能,常见的数据库工具对于已经创建好的表,都提供建表语句的复制功能,只需要把建表sql粘贴到这个文本框里。
点击“识别”按钮,这个sql的信息会自动识别过来,这时候只需要把表的中文名称填写上去,点击“一键生成代码”,就可以马上得到这个表的业务代码。
业务代码生成器
通用性的思考
不知道大家觉得怎么样哈,如果只是我自己用,我觉着已经非常好了,但既然是开放出来给大家用,通用性肯定还是不够的。
因为现在看到的这一套自动生成的代码,可能只是适合我,但不同的人、不同的公司,它们项目结构的分层、代码的细节,都是不一样的
所以,我还开发了代码模版配置的功能
点击“代码模版配置”按钮,在这个弹窗里,我们可以新增、删除代码的分类。同样的,也可以新增、删除和编辑具体的代码模版。
代码模版
代码生成的原理
在说代码模版具体怎么配置之前,先给大家讲一下代码自动生成的原理
它由代码模版和动态参数组成,核心就是匹配 - 替换
首先,工具提供了很多动态参数,这些动态参数,对应的是我们填写的表名、字段名等等这些信息的原始值,或者处理过后的值。
然后,代码模版由用户自行定义,在代码的关键位置,插入动态参数,即可形成一份代码模版。
最后,工具通过匹配和替换动态参数,最终生成了代码。
理论上,不论什么语言,你都可以配置专属于你自己的代码模版。
举个简单的栗子:
我们配置了一份这样的代码模版,如下:
/** * $table_desc$model模型 * created by 创建人 on $current_time$. */public class $table_name_hump_a$model extends tostring{}  
可以看到,模版里分别使用了$table_desc$(表中文名)、$current_time$(当前时间)、$table_name_hump_a$(表名转首字母大写驼峰) 这三个动态参数。
当我们设置 表名 = goods_order、表中文名 = 商品订单 时,代码生成的结果如下所示:
/** * 商品订单model模型 * created by 创建人 on 2023-02-05 1732. */public class goodsordermodel extends tostring{}  
动态参数部分,全部替换成了我们输入的表信息。
最后希望这个项目对大家有用,之后我会开发更多有意思的项目。
由于这个项目都是晚上加班肝出来的,可能会存在一些bug,发现了我会尽快修复的,也请大家多多包涵。
代码模版参考
以下是当前工具里默认的代码模版,你可以通过参考这些模版,举一反三,配置出专属于你自己的代码模版。
工具提供了模版的导入和导出功能,如果你创建好了一份非常满意的模版,可以导出,然后发给你的同事直接使用,这样它就不用重复创建了,你也可以忽悠你的同事来创建,然后分享给你。
建表sql模版
create table `$table_name$` (  $create_table_field_list$  primary key (`$primary_key$`)) engine=$db_engine$ default charset=$db_encoded$;  
实体类模版
主体
/** * $table_desc$dto模型 * created by 创建人 on $current_time$. */public class $table_name_hump_a$do {    $member_param_list$    $get_set_method_list$}  
成员代码块 成员变量列表(member_param_list)
/** $field_comment$ */private $field_type_java$ $field_name_hump$;  
成员代码块 getset方法列表(get_set_method_list)
public $field_type_java$ get$field_name_hump_a$() {    return $field_name_hump$;}public void set$field_name_hump_a$($field_type_java$ $field_name_hump$) {    this.$field_name_hump$ = $field_name_hump$;}  
接口类模版(db层)
import org.apache.ibatis.annotations.mapper;import org.apache.ibatis.annotations.param;import java.util.list;import java.util.map;/** * $table_desc$db接口 * created by 创建人 on $current_time$ */@mapperpublic interface $table_name_hump_a$dao {    /**     * 添加     * @param data     * return 影响行数     */    int insert($table_name_hump_a$do data);    /**     * 修改     * @param data     * return 影响行数     */    int update($table_name_hump_a$do data);    /**     * 分页查询     * @param param     * return 结果列表     */    list pagequery(map param);    /**     * 查询count     * @param param     * return count条数     */    long pagequerycount(map param);    /**     * 根据id查询     * @param id     * return 结果do对象     */    $table_name_hump_a$do querybyid(@param($primary_key_hump$) $primary_key_type_java$ $primary_key_hump$);    /**     * 根据id查询(带锁)     * @param id     * return 结果do对象     */    $table_name_hump_a$do querybyidlock(@param($primary_key_hump$) $primary_key_type_java$ $primary_key_hump$);}  
crud sql模版
insert into $table_name$($insert_field_name_list$)        values ($insert_field_value_list$);                update $table_name$ set            $update_field_list$        where $primary_key$ = #{$primary_key_hump$};                select $select_field_list$ from $table_name$        where 1=1        $while_field_list$        order by $primary_key$ desc                    limit #{offset},#{rows}                        select count(1) as total from $table_name$        where 1=1        $while_field_list$                select $select_field_list$ from $table_name$        where $primary_key$ = #{$primary_key_hump$};                select $select_field_list$ from $table_name$        where $primary_key$ = #{$primary_key_hump$} for update;      
模型转换器模版
不同层级间,可能会有不同的实体类,那么它们相互之间的数据转换,也是一个重复且浪费时间的工作,所以也可以配置一个模版。
import org.springframework.util.collectionutils;import java.util.arraylist;import java.util.list;/** * $table_desc$模型转换器 * created by 创建人 on $current_time$ */public class $table_name_hump_a$converter {    /**     * dto转do     * @param source     * return do模型     */    public static $table_name_hump_a$do todo($table_name_hump_a$dto source){        $table_name_hump_a$do target = new $table_name_hump_a$do();        $converter_source_to_target_params_list$        return target;    }    /**     * do转dto     * @param source     * return dto模型     */    public static $table_name_hump_a$dto todto($table_name_hump_a$do source){        $table_name_hump_a$dto target = new $table_name_hump_a$dto();        $converter_source_to_target_params_list$        return target;    }    /**     * do list 转 dto     * @param data     * return list dto模型     */    public static list todtolist(list data){        if (collectionutils.isempty(data)){            return null;        }        list list = new arraylist();        for ($table_name_hump_a$do item : data){            list.add($table_name_hump_a$converter.todto(item));        }        return list;    }}  
成员代码块 模型转换器参数列表(converter_source_to_target_params_list)
target.set$field_name_hump_a$(source.get$field_name_hump_a$());  
业务接口实现类模版
import com.alibaba.fastjson.jsonobject;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.stereotype.service;/** * $table_desc$业务实现 * created by 创建人 on $current_time$ */@servicepublic class $table_name_hump_a$serviceimpl implements $table_name_hump_a$service {    private static final logger logger = loggerfactory.getlogger($table_name_hump_a$serviceimpl.class);    @resource    private $table_name_hump_a$dao $table_name_hump$dao;    @override    public commonresult create(jsonobject request) {                // 入参转成对应类型        commonassert.isnoemptyobj(request, 请求参数不可空);        $table_name_hump_a$dto dto = json.tojavaobject(request, $table_name_hump_a$dto.class);          // 参数校验     $biz_check_required_params$                // 转成do模型        $table_name_hump_a$do datado = $table_name_hump_a$converter.todo(dto);        // 落库        int count = $table_name_hump$dao.insert(datado);        commonassert.istrue(count > 0, 创建失败,请重试);        // 返回创建成功的id数据        return new commonresult(datado.get$primary_key_hump_a$());    }    @override    public commonresult modify(jsonobject request) {                // 入参转成对应类型        commonassert.isnoemptyobj(request, 请求参数不可空);        $table_name_hump_a$dto dto = json.tojavaobject(request, $table_name_hump_a$dto.class);          // 参数校验     $biz_check_required_params$                // 转成do模型        $table_name_hump_a$do datado = $table_name_hump_a$converter.todo(dto);        // 落库        int count = $table_name_hump$dao.update(datado);        commonassert.greaterthanzero(count, 修改失败,请重试);        // 返回修改成功的id数据        return new commonresult(datado.get$primary_key_hump_a$());    }    @override    public commonresult pagequery(jsonobject request) {                // 入参基本校验        commonassert.isnoemptyobj(request, 请求参数不可空);                // 分页信息校验        paginationdo pagination = paginationdo.setrequestoffsetandrows(request);        commonassert.isnoemptyobj(pagination, 分页参数 $pageindex、$pagesize 不可空);        commonassert.istrue(pagination.getpagesize() <= 100, 单次查询条数不可超过100条);        // 取分页列表数据        list dbresult = $table_name_hump$dao.pagequery(request);        // 取count数据        long count = $table_name_hump$dao.pagequerycount(request);        // 空返回        if (collectionutils.isempty(dbresult)){            return new commonresult(new paginationresult(null, request, count));        }        // 模型转换        list list = $table_name_hump_a$converter.todtolist(dbresult);        // 返回分页结果        return new commonresult(new paginationresult(list, request, count));    }    @override    public commonresult querybyid(jsonobject request) {                // 取入参        commonassert.isnoemptyobj(request, 请求参数不可空);        // 根据id获取数据        $primary_key_type_java$ $primary_key_hump$ = request.get$primary_key_type_java$($primary_key_hump$);        commonassert.isnoemptyobj($primary_key_hump$, 参数错误,无法执行查询);        $table_name_hump_a$do dbresult = $table_name_hump$dao.querybyid($primary_key_hump$);                // 未查询到结果,返回        if (null == dbresult){            return new commonresult();        }        // 模型转换        $table_name_hump_a$dto result = $table_name_hump_a$converter.todto(dbresult);        // 返回结果对象        return new commonresult(result);    }}  
成员代码块 必填项业务校验(biz_check_required_params)
commonassert.$java_type_adapter_assert_method$(dto.get$field_name_hump_a$(), $field_comment$不可空);  
controller模版
import com.alibaba.fastjson.jsonobject;import org.slf4j.logger;import org.slf4j.loggerfactory;import org.springframework.web.bind.annotation.*;import javax.annotation.resource;/** * $table_desc$http请求控制器 * created by 创建人 on $current_time$. */@crossorigin@restcontroller@requestmapping(value = /$table_name_hump$/)public class $table_name_hump_a$controller {    private static final logger logger = loggerfactory.getlogger($table_name_hump_a$controller.class);    @resource    private $table_name_hump_a$service $table_name_hump$service;    /**     * 创建     * @param request     * @return     */    @requestmapping(value = create.json, method = {requestmethod.get, requestmethod.post})    @responsebody    public object create(@requestbody jsonobject request){        return commontemplate.run(logger, new commontemplate() {            @override            protected object business() {                return $table_name_hump$service.create(request);            }        }, request);    }    /**     * 修改     * @param request     * @return     */    @requestmapping(value = modify.json, method = {requestmethod.get, requestmethod.post})    @responsebody    public object modify(@requestbody jsonobject request){        return commontemplate.run(logger, new commontemplate() {            @override            protected object business() {                return $table_name_hump$service.modify(request);            }        }, request);    }    /**     * 分页查询     * @param request     * @return     */    @requestmapping(value = pagequery.json, method = {requestmethod.get, requestmethod.post})    @responsebody    public object pagequery(@requestbody jsonobject request){        return commontemplate.run(logger, new commontemplate() {            @override            protected object business() {                return $table_name_hump$service.pagequery(request);            }        }, request);    }    /**     * 通过主键查询     * @param request     * @return     */    @requestmapping(value = querybyid.json, method = {requestmethod.get, requestmethod.post})    @responsebody    public object querybyid(@requestbody jsonobject request){        return commontemplate.run(logger, new commontemplate() {            @override            protected object business() {                return $table_name_hump$service.querybyid(request);            }        }, request);    }}  
动态参数
原始表名 $table_name$

用户输入的表名,不做任何处理。

表名驼峰首字母小写 $table_name_hump$

用户输入的表名,经过驼峰处理。例如输入:goods_order ,输出:goodsorder

表名驼峰首字母大写 $table_name_hump_a$

用户输入的表名,经过驼峰处理。例如输入:goods_order ,输出:goodsorder

原始字段名 $field_name$

用户输入的表字段名,不做任何处理。

字段名驼峰首字母小写 $field_name_hump$

用户输入的表字段名,经过驼峰处理。例如输入:order_number ,输出:ordernumber

字段名驼峰首字母大写 $field_name_hump_a$

用户输入的表字段名,经过驼峰处理。例如输入:order_number ,输出:ordernumber

字段说明 $field_comment$

用户输入的表字段说明,不做任何处理。

字段数据类型(对应db)$field_type_db$

用户选择的表字段类型,不做任何处理。

字段数据类型(对应java)$field_type_java$

用户选择的表字段类型,会自动匹配对应的java类型。例如输入:varchar(),输出:string

主键字段名 $primary_key$

用户选择的主键字段,不做任何处理。例如用户定义的主键是id,那么输出就是:id

主键字段名驼峰首字母小写 $primary_key_hump$

用户选择的主键字段,经过驼峰处理。例如输入:order_number ,输出:ordernumber

主键字段名驼峰首字母大写 $primary_key_hump_a$

用户选择的主键字段,经过驼峰处理。例如输入:order_number ,输出:ordernumber

主键字段数据类型(对应java)$primary_key_type_java$

用户选择的主键字段类型,会自动匹配对应的java类型。例如输入:varchar(),输出:string

插入数据sql,字段名列表 $insert_field_name_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:goods_name,price 。会自动排除主键 不仅插入数据时可用,任何需要排除id,然后使用英文逗号拼接表所有字段信息的地方,都可以使用它

插入数据sql,字段值列表 $insert_field_value_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:#{goodsname},#{price} 。会自动排除主键 不仅插入数据时可用,任何需要排除id,然后使用英文逗号拼接表所有字段信息的地方,都可以使用它

修改数据sql,字段名列表 $update_field_list$

例如表中有三个字段:id(主键)、goods_name、price 输出(会自动换行,会携带以下缩进,会自动排除主键):

goods_name = #{goodsname},price = #{price}  
查询数据sql,字段名列表 $select_field_list$

例如表中有三个字段:id(主键)、goods_name、price,输出:id,goods_name,price 。带主键

whele字段条件sql,字段名列表 $whele_field_list$

例如表中有三个字段:id(主键)、goods_name、price, 输出(会自动换行,会携带以下缩进):

and id = #{id}    and goods_name = #{goodsname}    and price = #{price}  
创建表-表字段列表 $create_table_field_list$

例如表中有三个字段:id(自增主键)、goods_name、price 输出(会自动换行,会携带以下缩进):

`id` int(11) not null auto_increment,  `goods_name` varchar(128) not null default 'null',  `price` decimal(10,2) not null default 'null'  
当前时间 $current_time$

自动获取当前时间,格式:yyyy-mm-dd hhss,示例值:2023-02-05 1718

自动根据数据类型,匹配断言方法 $java_type_adapter_assert_method$

对于java数据类型等于string的字段,使用isnoblankstr方法,其他的类型都使用isnoemptyobj方法 这是一个定制化很高的动态参数,可忽略它。

动态代码块
动态代码块由用户自行定义,代码块中也可以设置动态参数,目前仅提供4种明确的动态代码块
成员变量列表 $member_param_list$
例如表中有三个字段:id(主键)、goods_name、price
假设用户定义了如下代码块内容:
/** $field_comment$ */private $field_type_java$ $field_name_hump$;  
输出(会自动根据字段数量,累加输出自定义代码块内容):
/** id */private integer id;/** 商品名称 */private string goodsname;/** 商品价格 */private string price;  
getset方法列表 $get_set_method_list$
例如表中有三个字段:id(主键)、goods_name、price
假设用户定义了如下代码块内容:
public $field_type_java$ get$field_name_hump_a$() {    return $field_name_hump$;}public void set$field_name_hump_a$($field_type_java$ $field_name_hump$) {    this.$field_name_hump$ = $field_name_hump$;}  
输出(会自动根据字段数量,累加输出自定义代码块内容):
public integer getid() {    return id;}public void setid(integer id) {    this.id = id;}public string getgoodsname() {    return goodsname;}public void setgoodsname(string goodsname) {    this.goodsname = goodsname;}public string getprice() {    return price;}public void setprice(string price) {    this.price = price;}  
模型转换器参数列表 $converter_source_to_target_params_list$
例如表中有三个字段:id(主键)、goods_name、price
假设用户定义了如下代码块内容:
target.set$field_name_hump_a$(source.get$field_name_hump_a$());  
输出(会自动根据字段数量,累加输出自定义代码块内容):
target.setid(source.getid());target.setgoodsname(source.getgoodsname());target.setprice(source.getprice());  
必填项业务校验 $biz_check_required_params$
例如表中有三个字段:id(主键)、goods_name、price
假设用户定义了如下代码块内容:
commonassert.$java_type_adapter_assert_method$(dto.get$field_name_hump_a$(), $field_comment$不可空);  
输出(会自动根据字段数量,累加输出自定义代码块内容):
commonassert.isnoblankstr(dto.getgoodsname(), goodsname不可空);        commonassert.isnoblankstr(dto.getprice(), price不可空);


开关电源的主要测试点
小米MIX2、华为Mate10、一加5T最新消息汇总:最强全面屏小米MIX2、华为Mate10、一加5T你选谁?
CES 2020上英特尔揭示了DG1显卡的更多真实细节
多用途滤波器网络结合了抗混叠和sinc补偿
正确使用焊锡丝需要一些技巧和注意事项
写一个比ChatGPT还牛的CRUD代码生成器
PCB制造中叠层之间的铜分布不均匀会有什么影响
卡巴斯基发布报告声称,“加密货币”在网络罪犯中越来越受欢迎
冶金钢铁行业:钢包秤称重传感器的应用
无线通信在自由空间传播时的距离计算方法
‍‍‍‍‍‍‍‍意法半导体推出TSB582双路高输出放大器
随着科技水平的不断进步 智能家居的春天已经到来
浅谈Sonoma的隔离式能量测量子系统
智能安防2.0:海康威视将亮相2015安博会
中软国际为先进云数字化转型打造ERP与数据服务,成就企业卓越与创新
创基Type-C转换器为我们带来不言而喻的帮助
爱立信:北美和东北亚引领5G兴起 2024年5G用户将达15亿人
百度启动国内首家百度大脑创新体验中心
什么是电池热管理 电池预加热技术的应用
LED驱动电源设计需要考虑的五大关键点