时间:2023-03-15来源:系统城装机大师作者:佚名
假如某个新开发的功能,要新增10张表,按照这个时间计算,至少要100分钟,仔细想想,其实你会发现大部分的时间都浪费在这些简单而又重复的编程圈子中去了。
那有没有一个办法,将这些简单的CURD
代码,全部都标准化、公共化呢?这样我们的可以省下很多时间来投入业务场景的开发。
答案是肯定的,有!
我记得早期我最先接触的是MybatisGenertor
工具包,通过这个工具包,我们可以省去大部分的mybaits
中xml
文件的curd
编写工作。
还有我们所熟悉的JPA
,里面有一套公共的持久层动态代理类,它可以自动根据名称生成SQL
语句,能为开发省下不少的事情。
但是我这个人比较懒,我想搞一个工具,从controller
、service
、entity
、dao
层,全部的crud
代码,包括单元测试类,通过工具自动生成好。
像这样的工具,现在网上也有不少,例如我们所熟悉的Mybatis-plus
插件,它就可以做到这一点,也是非常好用。
但是有的公司就不喜欢它,原因也很简单,里面的很多公共方法封装的过于深入,而且很多crud
的sql
全部都是动态生成,你根本看不到。
总之啊就是一句,不在自己掌控之内的,很多程序员总是带着各种疑虑~~
当然,还有一个明显的疑虑,就是对微服务的开发,不能全面支持,比如你项目采用的是SpringBoot +Dubbo
组合来开发,这个时候生成的controller
,完全没啥用处,而且还很鸡肋。
因此在这种情况下,你得基于当前的项目软件开发规则,自己开发一套代码生成器,以满足快速开发的需要。
下面我就简单的介绍一下,如何自行开发一套代码生成器,过程如下!
其实开发一套代码生成器,真没大家想象中的那么复杂,其中用的最重要一项技术,就是利用模板来生成代码,例如我们经常使用的模板引擎freemarker
,它就可以帮助我们实现这一点。
1 2 3 4 5 |
< dependency > < groupId >org.freemarker</ groupId > < artifactId >freemarker</ artifactId > < version >2.3.23</ version > </ dependency > |
下面我们以动态创建实体类为例,编写一个实体类的模板entity.java.ftl
,其中${}
里面定义的是动态变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
package ${ package }; import java.io.Serializable; /** * <p> * ${tableComment} * </p> * * @author ${author} * @since ${date} */ public class ${entityClass} implements Serializable { private static final long serialVersionUID = 1L; <#--属性遍历--> <#list columns as pro> /** * ${pro.comment} */ private ${pro.propertyType} ${pro.propertyName}; </#list> <#--属性get||set方法--> <#list columns as pro> public ${pro.propertyType} get${pro.propertyName?cap_first}() { return this .${pro.propertyName}; } public ${entityClass} set${pro.propertyName?cap_first}(${pro.propertyType} ${pro.propertyName}) { this .${pro.propertyName} = ${pro.propertyName}; return this ; } </#list> } |
最后我们基于freemarker
编写一个测试类!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
public class CodeGeneratorDemo { public static void main(String[] args) throws IOException, TemplateException { Map<String, Object> objectMap = new HashMap<>(); //定义包路径 objectMap.put( "package" , "com.example.test" ); //定义实体类 objectMap.put( "entityClass" , "Student" ); //定义实体类属性 List<Map<String, Object>> columns = new ArrayList<>(); //姓名字段 Map<String, Object> column1 = new HashMap<>(); column1.put( "propertyType" , "String" ); column1.put( "propertyName" , "name" ); column1.put( "comment" , "姓名" ); columns.add(column1); //年龄字段 Map<String, Object> column2 = new HashMap<>(); column2.put( "propertyType" , "Integer" ); column2.put( "propertyName" , "age" ); column2.put( "comment" , "年龄" ); columns.add(column2); //定义类的属性 objectMap.put( "columns" , columns); //定义作者 objectMap.put( "author" , "张三" ); //定义创建时间 objectMap.put( "date" , new SimpleDateFormat( "yyyy-MM-dd" ).format( new Date())); //定义类描述 objectMap.put( "tableComment" , "学生信息" ); //生产目标代码 Configuration configuration = new Configuration(Configuration.VERSION_2_3_23); configuration.setDefaultEncoding(Charset.forName( "UTF-8" ).name()); configuration.setClassForTemplateLoading(CodeGeneratorDemo. class , "/" ); Template template = configuration.getTemplate( "/templates/entity.java.ftl" ); FileOutputStream fileOutputStream = new FileOutputStream( new File( "../src/main/java/com/example/generator/Student.java" )); template.process(objectMap, new OutputStreamWriter(fileOutputStream, Charset.forName( "UTF-8" ).name())); fileOutputStream.close(); System.out.println( "文件创建成功" ); } } |
运行程序,输出的文件结果如下!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
package com.example.test; import java.io.Serializable; /** * <p> * 学生信息 * </p> * * @author 张三 * @since 2021-08-22 */ public class Student implements Serializable { private static final long serialVersionUID = 1L; /** * 姓名 */ private String name; /** * 年龄 */ private Integer age; public String getName() { return this .name; } public Student setName(String name) { this .name = name; return this ; } public Integer getAge() { return this .age; } public Student setAge(Integer age) { this .age = age; return this ; } } |
与预期的效果一致,成功生成!
以上就是生成代码最核心的部分,首先编写一套模板,把需要填充的信息全部定义成动态变量,然后在代码中,通过map数据格式,使用freemarker
进行填充!
例如小编我就是采用这种方式,首先把要通过工具生成的代码,全部通过模板方式定义好。
然后通过连接数据库的方式,把需要自动生成的表结构查询出来,封装成数据渲染参数,最后传入到freemarker
中去,非常简单、快速的生成与自己预期想要的代码,所有单表的crud
全部一步到位!
下面这个就是小编,基于当前项目定制开发的一款代码生成器,项目采用SpringBoot + Dubbo
框架开发,没有Controller
层,截图中所有的代码全部都是采用代码生成器生成的,直接通过单元测试就可以运行,开发的时候非常快!
由于开发的代码生成器工具,代码有点过多,因此不便于通过文章分享给大家,有需要的朋友,可以访问如下链接获取:https://github.com/justdojava/springboot-example-generator
代码生成器,对于擅长以业务开发为主的程序员来说,绝对是一个巨大的福利,它能很明显的减轻开发人员的工作量,并且提升开发效率,能腾出更多的时间专注业务开发。
实际上,目前网上已经有很多的成熟、稳定的代码生成器,mybatis-plus
就是其中一个使用非常广泛的代码生成器,对于以单体web
开发为主的项目,它完全满足要求。
当然,如果当下你没有合适的代码生成器,不妨自己试试开发一款属于自己的代码生成器,同样也可以加倍提升开发效率。
2023-03-18
如何使用正则表达式保留部分内容的替换功能2023-03-18
gulp-font-spider实现中文字体包压缩实践2023-03-18
ChatGPT在前端领域的初步探索最近闲来无事,在自己的小程序里面集成了一个小视频的接口,但是由于小程序对于播放视频的限制,只能用来做一个demo刷视频了,没办法上线体验。小程序播放视频限制最多10个,超出可能...
2023-03-18
Vue.js、React和Angular对比 以下是Vue.js的代码示例: 以下是React的代码示例: 以下是Angular的代码示例:...
2023-03-18