最近在做一个项目,需要新建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模型 *Createdby创建人on$current_time$. */ publicclass$table_name_hump_A$ModelextendsToString{ }
可以看到,模版里分别使用了$table_desc$(表中文名)、$current_time$(当前时间)、$table_name_hump_A$(表名转首字母大写驼峰) 这三个动态参数。
当我们设置 表名 = goods_order、表中文名 = 商品订单 时,代码生成的结果如下所示:
/** *商品订单Model模型 *Createdby创建人on2023-02-051732. */ publicclassGoodsOrderModelextendsToString{ }
动态参数部分,全部替换成了我们输入的表信息。
最后希望这个项目对大家有用,之后我会开发更多有意思的项目。
由于这个项目都是晚上加班肝出来的,可能会存在一些BUG,发现了我会尽快修复的,也请大家多多包涵。
代码模版参考
以下是当前工具里默认的代码模版,你可以通过参考这些模版,举一反三,配置出专属于你自己的代码模版。
工具提供了模版的导入和导出功能,如果你创建好了一份非常满意的模版,可以导出,然后发给你的同事直接使用,这样它就不用重复创建了,你也可以忽悠你的同事来创建,然后分享给你。
建表SQL模版
CREATETABLE`$table_name$`( $create_table_field_list$ PRIMARYKEY(`$primary_key$`) )ENGINE=$db_engine$DEFAULTCHARSET=$db_encoded$;
实体类模版
主体
/** *$table_desc$DTO模型 *Createdby创建人on$current_time$. */ publicclass$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$; } publicvoidset$field_name_hump_A$($field_type_java$$field_name_hump$){ this.$field_name_hump$=$field_name_hump$; }
接口类模版(DB层)
importorg.apache.ibatis.annotations.Mapper; importorg.apache.ibatis.annotations.Param; importjava.util.List; importjava.util.Map; /** *$table_desc$DB接口 *Createdby创建人on$current_time$ */ @Mapper publicinterface$table_name_hump_A$DAO{ /** *添加 *@paramdata *return影响行数 */ intinsert($table_name_hump_A$DOdata); /** *修改 *@paramdata *return影响行数 */ intupdate($table_name_hump_A$DOdata); /** *分页查询 *@paramparam *return结果列表 */ List<$table_name_hump_A$DO>pageQuery(Mapparam); /** *查询count *@paramparam *returncount条数 */ LongpageQueryCount(Mapparam); /** *根据ID查询 *@paramid *return结果DO对象 */ $table_name_hump_A$DOqueryById(@Param("$primary_key_hump$")$primary_key_type_java$$primary_key_hump$); /** *根据ID查询(带锁) *@paramid *return结果DO对象 */ $table_name_hump_A$DOqueryByIdLock(@Param("$primary_key_hump$")$primary_key_type_java$$primary_key_hump$); }
CRUD SQL模版
INSERTINTO$table_name$($insert_field_name_list$) VALUES($insert_field_value_list$); UPDATE$table_name$SET $update_field_list$ WHERE$primary_key$=#{$primary_key_hump$};
模型转换器模版
不同层级间,可能会有不同的实体类,那么它们相互之间的数据转换,也是一个重复且浪费时间的工作,所以也可以配置一个模版。
importorg.springframework.util.CollectionUtils; importjava.util.ArrayList; importjava.util.List; /** *$table_desc$模型转换器 *Createdby创建人on$current_time$ */ publicclass$table_name_hump_A$Converter{ /** *dto转do *@paramsource *returndo模型 */ publicstatic$table_name_hump_A$DOtoDo($table_name_hump_A$DTOsource){ $table_name_hump_A$DOtarget=new$table_name_hump_A$DO(); $converter_source_to_target_params_list$ returntarget; } /** *do转dto *@paramsource *returndto模型 */ publicstatic$table_name_hump_A$DTOtoDto($table_name_hump_A$DOsource){ $table_name_hump_A$DTOtarget=new$table_name_hump_A$DTO(); $converter_source_to_target_params_list$ returntarget; } /** *dolist转dto *@paramdata *returnlistdto模型 */ publicstaticList<$table_name_hump_A$DTO>toDtoList(List<$table_name_hump_A$DO>data){ if(CollectionUtils.isEmpty(data)){ returnnull; } List<$table_name_hump_A$DTO>list=newArrayList<>(); for($table_name_hump_A$DOitem:data){ list.add($table_name_hump_A$Converter.toDto(item)); } returnlist; } }
成员代码块 模型转换器参数列表(converter_source_to_target_params_list)
target.set$field_name_hump_A$(source.get$field_name_hump_A$());
业务接口实现类模版
importcom.alibaba.fastjson.JSONObject; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.stereotype.Service; /** *$table_desc$业务实现 *Createdby创建人on$current_time$ */ @Service publicclass$table_name_hump_A$ServiceImplimplements$table_name_hump_A$Service{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger($table_name_hump_A$ServiceImpl.class); @Resource private$table_name_hump_A$DAO$table_name_hump$DAO; @Override publicCommonResultcreate(JSONObjectrequest){ //入参转成对应类型 CommonAssert.isNoEmptyObj(request,"请求参数不可空"); $table_name_hump_A$DTOdto=JSON.toJavaObject(request,$table_name_hump_A$DTO.class); //参数校验 $biz_check_required_params$ //转成do模型 $table_name_hump_A$DOdataDo=$table_name_hump_A$Converter.toDo(dto); //落库 intcount=$table_name_hump$DAO.insert(dataDo); CommonAssert.isTrue(count>0,"创建失败,请重试"); //返回创建成功的ID数据 returnnewCommonResult(dataDo.get$primary_key_hump_A$()); } @Override publicCommonResultmodify(JSONObjectrequest){ //入参转成对应类型 CommonAssert.isNoEmptyObj(request,"请求参数不可空"); $table_name_hump_A$DTOdto=JSON.toJavaObject(request,$table_name_hump_A$DTO.class); //参数校验 $biz_check_required_params$ //转成do模型 $table_name_hump_A$DOdataDo=$table_name_hump_A$Converter.toDo(dto); //落库 intcount=$table_name_hump$DAO.update(dataDo); CommonAssert.greaterThanZero(count,"修改失败,请重试"); //返回修改成功的ID数据 returnnewCommonResult(dataDo.get$primary_key_hump_A$()); } @Override publicCommonResultpageQuery(JSONObjectrequest){ //入参基本校验 CommonAssert.isNoEmptyObj(request,"请求参数不可空"); //分页信息校验 PaginationDOpagination=PaginationDO.setRequestOffsetAndRows(request); CommonAssert.isNoEmptyObj(pagination,"分页参数$pageIndex、$pageSize不可空"); CommonAssert.isTrue(pagination.getPageSize()<= 100, "单次查询条数不可超过100条"); // 取分页列表数据 List<$table_name_hump_A$DO>dbResult=$table_name_hump$DAO.pageQuery(request); //取count数据 longcount=$table_name_hump$DAO.pageQueryCount(request); //空返回 if(CollectionUtils.isEmpty(dbResult)){ returnnewCommonResult(newPaginationResult(null,request,count)); } //模型转换 List<$table_name_hump_A$DTO>list=$table_name_hump_A$Converter.toDtoList(dbResult); //返回分页结果 returnnewCommonResult(newPaginationResult(list,request,count)); } @Override publicCommonResultqueryById(JSONObjectrequest){ //取入参 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$DOdbResult=$table_name_hump$DAO.queryById($primary_key_hump$); //未查询到结果,返回 if(null==dbResult){ returnnewCommonResult(); } //模型转换 $table_name_hump_A$DTOresult=$table_name_hump_A$Converter.toDto(dbResult); //返回结果对象 returnnewCommonResult(result); } }
成员代码块 必填项业务校验(biz_check_required_params)
CommonAssert.$java_type_adapter_assert_method$(dto.get$field_name_hump_A$(),"$field_comment$不可空");
Controller模版
importcom.alibaba.fastjson.JSONObject; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importorg.springframework.web.bind.annotation.*; importjavax.annotation.Resource; /** *$table_desc$HTTP请求控制器 *Createdby创建人on$current_time$. */ @CrossOrigin @RestController @RequestMapping(value="/$table_name_hump$/") publicclass$table_name_hump_A$Controller{ privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger($table_name_hump_A$Controller.class); @Resource private$table_name_hump_A$Service$table_name_hump$Service; /** *创建 *@paramrequest *@return */ @RequestMapping(value="create.json",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody publicObjectcreate(@RequestBodyJSONObjectrequest){ returnCommonTemplate.run(LOGGER,newCommonTemplate(){ @Override protectedObjectbusiness(){ return$table_name_hump$Service.create(request); } },request); } /** *修改 *@paramrequest *@return */ @RequestMapping(value="modify.json",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody publicObjectmodify(@RequestBodyJSONObjectrequest){ returnCommonTemplate.run(LOGGER,newCommonTemplate(){ @Override protectedObjectbusiness(){ return$table_name_hump$Service.modify(request); } },request); } /** *分页查询 *@paramrequest *@return */ @RequestMapping(value="pageQuery.json",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody publicObjectpageQuery(@RequestBodyJSONObjectrequest){ returnCommonTemplate.run(LOGGER,newCommonTemplate(){ @Override protectedObjectbusiness(){ return$table_name_hump$Service.pageQuery(request); } },request); } /** *通过主键查询 *@paramrequest *@return */ @RequestMapping(value="queryById.json",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody publicObjectqueryById(@RequestBodyJSONObjectrequest){ returnCommonTemplate.run(LOGGER,newCommonTemplate(){ @Override protectedObjectbusiness(){ 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, 输出(会自动换行,会携带以下缩进):
❞
ANDid=#{id} ANDgoods_name=#{goodsName} ANDprice=#{price}
创建表-表字段列表 $create_table_field_list$
❝
例如表中有三个字段:id(自增主键)、goods_name、price 输出(会自动换行,会携带以下缩进):
❞
`id`INT(11)NOTNULLAUTO_INCREMENT, `goods_name`VARCHAR(128)NOTNULLDEFAULT'NULL', `price`DECIMAL(10,2)NOTNULLDEFAULT'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*/ privateIntegerid; /**商品名称*/ privateStringgoodsName; /**商品价格*/ privateStringprice;
GetSet方法列表 $get_set_method_list$
例如表中有三个字段:id(主键)、goods_name、price
假设用户定义了如下代码块内容:
public$field_type_java$get$field_name_hump_A$(){ return$field_name_hump$; } publicvoidset$field_name_hump_A$($field_type_java$$field_name_hump$){ this.$field_name_hump$=$field_name_hump$; }
输出(会自动根据字段数量,累加输出自定义代码块内容):
publicIntegergetId(){ returnid; } publicvoidsetId(Integerid){ this.id=id; } publicStringgetGoodsName(){ returngoodsName; } publicvoidsetGoodsName(StringgoodsName){ this.goodsName=goodsName; } publicStringgetPrice(){ returnprice; } publicvoidsetPrice(Stringprice){ 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不可空");
审核编辑:刘清
-
转换器
+关注
关注
27文章
8645浏览量
146924 -
SQL
+关注
关注
1文章
760浏览量
44087 -
代码生成器
+关注
关注
0文章
25浏览量
9109
原文标题:非低代码,我写了一个比ChatGPT还牛的CRUD代码生成器
文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论