上一篇讲了用EZDML生成vue-element-admin前端,这回来试下折腾下后端接口的生成。还是分两步走,先人工做单个表的模板工程,再转成批量自动生成。
本文图多内容枯燥,仅适合想自己用EZDML生成框架的后端java程序员参考,其他人员请慎入。
运行环境:JDK8,idea64,EZDML for win64 v3.27。
还是从零开始吧,新建项目,从start.spring.io创建,打开浏览器:
选择了Lombok、JPA、H2作为附加依赖,生成项目文件下载解压:
用idea打开,等待初始化构建完成:
这时已经是可以运行的了:
可以从浏览器访问,只不过没有内容:
在src/main的com.ezdml.codegen.ezdmlcodegendemo下新建子目录包ezmodel.eztable,并创建EzEntity实体对象类,以及对应的Repository类和Controller,内容都是超级简单的:
现在流行yml,删除application.properties,创建application.yml,编辑内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| server: port: 8080 spring: datasource: url: jdbc:h2:~/eztest driver-class-name: org.h2.Driver username: sa password: 1234
jpa: database: h2 hibernate: ddl-auto: update show-sql: true h2: console: path: /h2-console enabled: true
|
再次运行,在浏览器输入/ez_table的地址,可以看到有响应了,虽然是空的:
接下来创建Service接口和实现类:
并在Controller上添加相应接口(删除之前那个helloc测试函数):
再次运行,这时可以用add方法添加记录了:
添加两条后,可以用list看到结果:
日志可以看到执行了相关SQL:
打开http://localhost:8080/h2-console,输入yml中配置的信息登录:
可以看到数据确实保存了:
接下来添加swagger支持(在pom.xml中添加内容,在右侧Maven栏中点刷新按钮):
1 2 3 4 5 6 7 8 9 10
| <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency>
|
修改application.yml,在EzdmlCodeGenDemoApplication上添加@EnableSwagger2注解,并创建SwaggerConfig类:
修改Controller添加swagger api注解:
运行,报空指针NullPointerException错误,按网上说明,在yml中添加以下内容:
1 2 3 4
| spring: mvc: pathmatch: matching-strategy: ant_path_matcher
|
再次运行成功 :
打开http://localhost:8080/api-docs:
打开http://localhost:8080/swagger-ui.html:
一切正常,至此人肉基础模板工程准备完毕。
接下来开始批量自动生成的转换。打开EZDML的脚本目录(我机上是D:\EZDML\Templates),创建springJpaSwaggerDemo目录:
将模板工程的src目录复制过来:
只保留\src\main\java\com\ezdml\codegen\ezdmlcodegendemo下的ezmodel子目录及其文件,其它的全部删除,因为我们只需要生成这个目录:
在根目录src旁边创建_dml_config.INI文件,内容如下:
[dml_settings]
create_root_folder=0
意思生成时不要创建“springJpaSwaggerDemo”这个根文件夹。
然后转到src\main\java\com\ezdml\codegen\ezdmlcodegendemo下,在ezmodel旁边创建_dml_config.INI文件:
内容如下:
[ezmodel]
rename=#curmodel_name:ChnToPY:CamelCaseToUnderline#
意思就是将这个目录改为模型名:
再进入ezmodel目录,在eztable旁边创建_dml_config.INI文件,内容如下:
[eztable]
rename=#curtable_name:ChnToPY:CamelCaseToUnderline#
loop_each_table=1
意思是为模型中的每个表复制eztable这个目录,并改名为表名(汉字转拼音,下划线命名)。
我们先运行一下:
嗯,确实生成了需要的目录,只剩下最后的类文件了。
进入eztable子目录,创建_dml_config.INI文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| [EzEntity.java] rename=#curtable_name:ClassName#.java run_as_script=js
[EzEntityController.java] rename=#curtable_name:ClassName#Controller.java run_as_script=js
[EzEntityRepository.java] rename=#curtable_name:ClassName#Repository.java run_as_script=js
[EzEntityService.java] rename=#curtable_name:ClassName#Service.java run_as_script=js
[EzEntityServiceImpl.java] rename=#curtable_name:ClassName#ServiceImpl.java run_as_script=js
|
把5个java文件转成JS模板,以EzEntity.java为例:
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| <% var parentPkgName=GetGParamValue('EZGEN_ROOT_PKGNAME'); if(!parentPkgName)parentPkgName='com.ezdml.codegen.ezdmlcodegendemo';
var tb=curTable; var ClsName=AutoCapProc(tb.name,'ClassName'); var dispName=tb.UIDisplayName;
%>package ${parentPkgName}.${AutoCapProc(curModel.name,'JavaPackageName')}.${AutoCapProc(tb.name,'JavaPackageName')};
import lombok.Data; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import javax.persistence.*; import java.util.Date;
@Entity @Data @ApiModel("${dispName}") @AllArgsConstructor @NoArgsConstructor public class ${ClsName} {
<% var fds=tb.metaFields;
for(var k=0; k<fds.count; k++) { var fd = fds.getItem(k); if(!fd.isPhysicalField()) continue; var tp=getFieldJavaType(fd); fout('@ApiModelProperty("'+fd.getLabelText()+'")'); if(fd.keyFieldType=='cfktId'){ fout('@Id'); if(tp=='int'){ fout('@GeneratedValue'); tp='long'; } else { fout('@GeneratedValue(generator="sys_uuid")'); fout('@GenericGenerator(name="sys_uuid",strategy="uuid")'); } } var cs=''; if(tp=='String' && fd.dataLength>0) cs+=(cs==''?'':', ')+'length='+fd.dataLength; if(!fd.nullable) cs+=(cs==''?'':', ')+'nullable=false'; if(fd.indexType=='cfitUnique') cs+=(cs==''?'':', ')+'unique=true'; if(cs){ fout('@Column('+cs+')'); } fout('private '+tp+' '+AutoCapProc(fd.name,'FieldName')+';'); fout(''); }
function getFieldJavaType(fd) { var cfType=fd.dataType; if(cfType.indexOf("cfdt")==0){ var res= cfType.substr(4); if(res=="Integer") return "int"; if(res=="Float") return "double"; if(res=="Bool") return "boolean"; if(res=="Enum") return "int"; if(res=="Blob") return "byte[]"; if(res=="List") return "List"; if(res=="Event") return "EventClass"; if(res=="Other") return "class"; return res; } else return cfType; }
function fout(s){ curOut.add(' '+s); }
%>
}
|
其它几个文件类似的,不细述了。
接下来,重新执行生成,将输出文件夹指定为之前的ezdml-code-gen-demo目录:
生成结果示例:
尝试编译OK,不过,运行时提示,AdminRole这个对象没有主键:
嗯,这个是多对多的纯关联表,把它移除,下次生成时不要勾选它,或者直接在这个表的生成选项里禁止生成代码:
再次运行,一切正常,swagger接口出来了:
至此一个简单后端接口的批量生成模板就做好了。新版本EZDML已经带了这个示例工程,同样也加了个生成后的启动菜单SHELL脚本:
安装后的文件位于EZDML下的\Templates\SpringJpaSwagger目录,同时也上传到了gitee:
https://gitee.com/huzgd/spring-jpa-swagger-demo (请选择ezdml_demo分支)
大家可以在此基础上继续修改实现的自定义模板内容。
我把上期生成的前端跟这个生成的后端接口对比了一下,两者的接口格式有点不一样,由于时间精力有限,我暂时没有做合并对接处理,呵呵,真的是“前后端分离”了。
对于后端来说,如何设计表结构是首要的问题,解决业务问题不能只依靠代码生成,复杂的软件开发没有银蛋。不过反正表都设计好了再生成一下也是顺便,现在生成代码工具满天飞,咱们就当凑个热闹。
我平时开发用iBatis/myBatis较多,基本上不用swagger和JPA,所以估计会有一些错漏问题,有任何问题可加Q群沟通(见软件的帮助、关于),谢谢!