本文采用velocity模板来生成基于spring mvc ,spring data jpa, spring 的后台架构
和前端用的Metronic 的crud代码。大大的提升了开发速度。
在现今的软件开发过程中,软件开发人员将更多的精力投入在了重复的相似劳动中。特别是在如今特别流行的 MVC 架构模式中,软件各个层次的功能更加独立,同时代码的相似度也更加高。所以我们需要寻找一种来减少软件开发人员重复劳动的方法,让程序员将更多的精力放在业务逻辑以及其他更加具有创造力的工作上。Velocity 这个模板引擎就可以在一定程度上解决这个问题。
Velocity 是一个基于 Java 的模板引擎框架,提供的模板语言可以使用在 Java 中定义的对象和变量上。Velocity 是 Apache 基金会的项目,开发的目标是分离 MVC 模式中的持久化层和业务层。但是在实际应用过程中,Velocity 不仅仅被用在了 MVC 的架构中,还可以被用在以下一些场景中。
1.Web 应用:开发者在不使用 JSP 的情况下,可以用 Velocity 让 HTML 具有动态内容的特性。
源代码生成:Velocity 可以被用来生成 Java 代码、SQL 或者 PostScript。有很多开源和商业开发的软件是使用 Velocity 来开发的。
自动 Email:很多软件的用户注册、密码提醒或者报表都是使用 Velocity 来自动生成的。使用 Velocity 可以在文本文件里面生成邮件内容,而不是在 Java 代码中拼接字符串。
转换 xml:Velocity 提供一个叫 Anakia 的 ant 任务,可以读取 XML 文件并让它能够被 Velocity 模板读取。一个比较普遍的应用是将 xdoc 文档转换成带样式的 HTML 文件。
一、变量
和我们所熟知的其他编程语言一样,Velocity 也可以在模板文件中有变量的概念。
#set($name =“velocity”)
等号后面的字符串 Velocity 引擎将重新解析,例如出现以$开始的字符串时,将做变量的替换。
#set($hello =“hello $name”)
上面的这个等式将会给$hello 赋值为“hello velocity”
在模板文件中使用$name
或者${name}
来使用定义的变量。推荐使用${name}
这种格式,因为在模板中同时可能定义了类似$name
和$names
的两个变量,如果不选用大括号的话,引擎就没有办法正确识别$names
这个变量。
对于一个复杂对象类型的变量,例如$person
,可以使用${person.name}
来访问 person
的 name
属性。值得注意的是,这里的${person.name}
并不是直接访问 person
的 name
属性,而是访问 person
的 getName()
方法,所以${person.name}
和${person.getName()}
是一样的。
在第一小点中,定义了一个变量,同时给这个变量赋了值。对于 Velocity 来说,变量是弱数据类型的,可以在赋了一个 String 给变量之后再赋一个数字或者数组给它。可以将以下六种数据类型赋给一个 Velocity 变量:变量引用, 字面字符串, 属性引用, 方法引用, 字面数字, 数组列表。
#set($foo = $bar)
#set($foo =“hello”)
#set($foo.name = $bar.name)
#set($foo.name = $bar.getName($arg))
#set($foo = 123)
#set($foo = [“foo”,$bar])
二、循环
在 Velocity 中循环语句的语法结构如下:
#foreach($element in $list)
This is element velocityCount
#end
Velocity 引擎会将 list 中的值循环赋给 element 变量,同时会创建一个$velocityCount 的变量作为计数,从 1 开始,每次循环都会加 1.
三、条件语句
条件语句的语法如下
#if(condition)
...
#elseif(condition)
…
#else
…
#end
四、关系操作符
Velocity 引擎提供了 AND、OR 和 NOT 操作符,分别对应&&、||和! 例如:
#if($foo && $bar)
#end
以上内容包含了部分 Velocity 的语法,详细的语法内容可以参考 Velocity 的官方文档。
velocity-1.7.jar
velocity-tools-2.0.jar
commons-collections-3.2.jar
commons-pool-1.3.jar
这里我把我写的代码列一下。每一行都有注释。看一下就懂了。也可以根据这个来稍加修改就可以写出你自定义的代码生成器了。
package cn.Sirius_MK.admk.test;
import java.io.File;
import java.io.FileWriter;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.junit.Test;
/**
* 不要先使用真实默认,用一个临时模型Addr,如果运行页面ok,改为Address
* Title:CreateCode
* @author Sirius_KP
* @date 2016-12-23下午3:27:08
*/
public class CreateCode {
// 定义一个开关flag=false,不覆盖
private final static boolean flag = !true;
// 1.那些domain需要生成代码
private String[] domains = { "Address" };
// 2.定义固定的目录路径:都是使用相对路径,规范:路径前面都不加/,路径的后面都加/
private final static String SRC = "src/";
private final static String PACKAGE = "cn/Sirius_MK/admk/";
private final static String WEBAPP = "webapp/";
//获取首字母小写的实体用于创建包
private String lowerEntity = domains[0].substring(0, 1).toLowerCase() + domains[0].substring(1);
// 3.有那些模板需要生成
private String[] templates = { "ServiceImpl.java", "Service.java", "Controller.java", "entity.jsp", "input.js", "input.jsp",
"Repository.java"};
// 4.模板文件对应的生成文件路径
private String[] files = { SRC + PACKAGE + "service/impl/",SRC + PACKAGE + "service/", SRC + PACKAGE + "controller/",
WEBAPP + "WEB-INF/views/pages/"+lowerEntity+"/",WEBAPP + "static/js/"+lowerEntity+"/",WEBAPP + "WEB-INF/views/pages/"+lowerEntity+"/",
SRC + PACKAGE + "repository/"};
@Test
public void create() throws Exception {
if (templates.length != files.length) {
throw new RuntimeException("templates.length != files.length");
}
// 实例化Velocity上下文
VelocityContext context = new VelocityContext();
// 5.外循环:domains
for (int i = 0; i < domains.length; i++) {
context.put("entity", domains[i]);
// 定义domain的首字母小写
// 6.处理domain首字母小写
String lowerCaseEntity = domains[i].substring(0, 1).toLowerCase() + domains[i].substring(1);
context.put("lowerCaseEntity", lowerCaseEntity);
// 7.内循环:templates和files
for (int j = 0; j < templates.length; j++) {
// 8.实例化文件存放的路径
File file = new File(files[j] + domains[i] + templates[j]);
// 9.处理特殊的文件名称
if ("Service.java".equals(templates[j])) {
file = new File(files[j] + "I" + domains[i] + templates[j]);
}else if ("entity.jsp".equals(templates[j])) {
file = new File(files[j] + lowerCaseEntity + ".jsp");
}else if ("input.js".equals(templates[j])) {
file = new File(files[j] + lowerCaseEntity+ "_"+templates[j]);
}else if ("input.jsp".equals(templates[j])) {
file = new File(files[j] + lowerCaseEntity+ "_"+templates[j]);
}
// 12.开关:默认情况下已经存在的文件不需要生成代码 true:覆盖所有代码
// 如果flag==false并且当前生存文件是存在的
if (!flag && file.exists()) {
// return;
// break;
continue;// 本次跳过,继续下一次循环,
}
// 10.判断父目录是否存在
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
System.out.println(file.getAbsolutePath());
// 获取模版
Template template = Velocity.getTemplate("webapp/template/" + templates[j], "UTF-8");
// 流
FileWriter writer = new FileWriter(file);
// 合并
template.merge(context, writer);
// 11.必须关闭流,写入内容
writer.close();
}
}
System.out.println("先刷新工程,修改对应表需要展示的字段,修改需要编辑保存的字段,运行测试");
System.out.println("最后注意修改主菜单的地址运行测试");
}
}