代码生成器:根据项目组织结构自定义代码生成规则生成代码,摆脱重复代码的编码工作。 通过二次开发和配置最终完成一个代码生成器,达到生成目标代码的目的。
首次启动时,设定好生成器模型数据的属性描述(一个属性描述对象相当于一列),设置后建议不能修改。
名称:
列的英文名称,生成代码需要用到,必输项。
注释(列标题):
列的标题,必输项。
显示宽度:
列的宽度,必输项。
输入类型:
列单元格输入类型,必输项。
Boolean:Java类型小boolean,编辑器类型CheckBox。如果参考值用,隔开,前表示true显示的文字,后表示false显示的文字,如:是,否。
Integer:Java类型Integer,编辑器类型TextField。
Double:Java类型Double,编辑器类型TextField。
String:Java类型String,编辑器类型TextField。如果参考值用,隔开,编辑器类型为可编辑的ComboBox。
Date:Java类型Date,编辑器类型DatePicker。
Enum:Java类型String,编辑器类型ChoiceBox。
Group:Java类型Group,编辑器类型TreeView。
默认值:
列单元格添加时默认值。
验证脚本(El表达式):
列单元格的保存提交时的验证规则,用El表达式自定义。
EL表达式取得列单元格的值用名称,如:如果列名称为name,EL表达式可以为fn:length(name)>5,表示这一列输入值长度必须大于5。
验证提示:
验证脚本验证失败时的提示信息。
参考值:
主要表示Enum类型时的值,多个值用,隔开。
生成路径:
代码生成的根路径。
生成分组:
生成代码时,临时选择的分组。未勾选,则不参与代码生成。
设置快捷属性后,可在添加模型数据时直接添加预先编辑的快捷属性。
同一份生成器的数据,可以选择不同的模板生成策略生成不同的代码。
同一份生成器的数据,可以选择不同的模板生成策略生成不同的代码。
模板生成策略文件的所有数据都来自生成器。
模板生成策略文件必须放入templates文件夹下,所有的模板文件必须templates文件夹或者子文件下,模板用velocity。
数据结构:
config = {<!-- 文件生成根路径 -->
generatePath<!-- 快捷属性,是Map结构,key根据启动设置来确定 -->
quickProperties:[]<!-- 启动设置对应对象 -->
propertyFeatures:[ {<!-- 名称 -->
name<!-- 注释(列标题) -->
comment<!-- 显示宽度 -->
viewWidth<!-- 输入类型 -->
type<!-- 默认值 -->
defaultValue<!-- 验证脚本(EL表达式) -->
checkStatement<!-- 验证提示 -->
checkMessage<!-- 参考值 -->
referenceValues } ],<!-- 生成策略配置文件 -->
templateConfig:{<!-- 是否被应用 -->
apply<!-- 文件名 -->
name<!-- 策略作用描述 -->
description } }project,module,model继承于group(项目、模块、模型,抽象成分组),组合模式。 group = {
<!-- 主键 -->
id<!-- 名称 -->
name<!-- 注释 -->
comment<!-- 描述 -->
description<!-- 父分组 -->
parent<!-- 子分组-->
children:[] }
<!-- 项目 -->
project = {<!-- 子分组:可以是module和model -->
children:[] }
<!-- 模块 -->
module = {<!-- 子分组:可以是module和model -->
children:[] }
<!-- 模型 -->
model = {<!-- 快捷属性,是Map结构,key根据启动设置来确定 -->
properties:[] }
模板生成策略文件:
顶级变量config和project
<?xml version="1.0" encoding="UTF-8"?><!-- global:取得配置数据的顶级key description:描述模板策略的作用 -->
<template-config description="架构代码模板"><!-- file:生成一个文件 name:文件名称 template:生成文件用的模板 -->
<file name="数据字典.html" template="framework/data-dictionary.vm"><!-- template-context:模板文件的生成文件所需的上下文 -->
<template-context var="config" value="${config}"/> <template-context var="date" value="${fn:newInstance('org.apache.velocity.tools.generic.DateTool')}"/> </file><!-- folder:生成一个文件夹 name:文件夹名称 -->
<folder name="com"> <folder name="lite"> <folder name="app"> <folder name="${fn:toLowerCase(project.name)}"> <folder name="service"><!-- foreach:for循环 item:迭代时变量名 items:迭代的集合,支持List,Map,Array -->
<!-- status:迭代状态对象,有属性first:是否第一次迭代 last:是否最后一次 index:索引,0开始 count:索引,1开始 current:当前迭代项 -->
<foreach item="model" items="${project.children}" status="status"> <file name="${fn:toUpperCaseFirst(model.name)}Service.java" template="framework/service.vm"> <template-context var="config" value="${config}"/> <template-context var="model" value="${model}"/> <template-context var="date" value="${fn:newInstance('org.apache.velocity.tools.generic.DateTool')}"/> </file><!-- if:条件判断 -->
<if test="${status.index % 2 == 0}"><!-- continue:结束本次循环,只能用于foreach里 -->
<continue/> </if> <if test="${status.index % 2 == 0}"><!-- break:跳出循环,只能用于foreach里 -->
<break/> </if> </foreach> </folder> </folder> </folder> </folder> </folder><!-- function:定义一个函数 name:函数名 argument[i]:形参参数名,i从1开始 -->
<function name="out" argument1="projectName" argument2="project" argument[i]...><!-- var:定义一个变量 name:变量名 value:变量值 -->
<var name="pn" value="${projectName}"/><!-- out:输出值到控制台 value:输出值 -->
<out value="${pn}"/><!-- call:调用一个函数 function:函数名 argument[i]:实参,i从1开始 -->
<call function="out" argument1="${project.name}" argument2="${project}" argument[i].../><!-- return:返回函数 -->
<return/> </function> </template-config>
因为都是JavaFx封装的可观察类型,所以数据结构中的Map取值都要用${对象名.key.value}
velocity模板文件:
<!DOCTYPE html> <html> <head> <title>Hello,World!</title> </head> <body> <h1>project.name - $project.comment</h1> <h4>生成日期:$date.get('yyyy-MM-dd HH:mm:ss')</h4> #foreach($module in $project.children) <div>$velocityCount.$!module.name</div> #end </body> </html>
编译代码目录:
plugins\classes
扩展EL表达式:类注解com.lite.generator.framework.el.Function。
package
com.lite.generator.framework.el;
import
java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited
public
@interface
Function {//表达式库前缀 String prefix();
}
--------------
package
......
import
......
......
@com.lite.generator.framework.el.Function(prefix = "fn")
public
class
Function {<code>public</code> <code>static</code> String trim(String input) { <code>if</code> (input == <code>null</code>) <code>return</code> ""; <code>return</code> input.trim(); } <code>......</code>
}
--------------
${fn:trim(string)}
依赖Jar包目录:
plugins\library
删除:
Ctrl + D
撤销:
Ctrl + Z
重做:
Ctrl + Shift + Z