概述
Velocity是一个基于java的模板引擎(template engine)。它允许任何人仅仅简单的使用模板语言(template language)来引用由java代码定义的对象。
当Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只 关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提 供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。
Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当 作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。
本文将介绍他作为模板生成文件的具体实现。
实现
依赖
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
模板
package ${packagePath};
import java.lang.String;
## 类名处理
public class $!{targetFileName} {
## 方法处理
#if( $!testProductArr )
#foreach( $product in $productArr )
<li>value=$product</li>
#end
#end
#if( $!testMap )
#foreach( $key in $kvMap.keySet() )
<li>Key: $key ->Value: $kvMap.get($key)</li>
#end
#end
}
代码
目标文件的相关配置
package com.example.demo.test.velocity;
import lombok.Getter;
import org.springframework.util.StringUtils;
/**
* TargetFileConfig
*
* @author yuntian
* @since 2020/10/30
*/
@Getter
public class TargetFileConfig {
private static final String JAVA_FILE_PATH = "src/main/java/";
private static final String PACKAGE_DOT = ".";
private static final String PATH_SLASH = "/";
private static final String JAVA_FILE_SUFFIX = ".java";
private static final String CUR_FILE_NAME_PATTERN = "%sServiceImpl";
/**
* com.example.demo
*/
private String basePackagePath = "com.example.demo";
/**
* service.impl
*/
private String subPackagePath = "service.impl";
private String domainName;
/**
* DomainNameService
*/
private String fileName;
/**
* DomainNameService.java
*/
private String fileNameWithSuffix;
private String packagePath;
/**
* /Users/yuntian/try/demo/src/main/java/com/example/demo/service/impl/DomainNameService.java
*/
private String filePathWithFileName;
public TargetFileConfig(String basePackagePath, String subPackagePath, String domainName, String userDir) {
this.basePackagePath = basePackagePath;
this.subPackagePath = subPackagePath;
this.domainName = domainName;
this.fileName = String.format(CUR_FILE_NAME_PATTERN,domainName);
this.fileNameWithSuffix =fileName+JAVA_FILE_SUFFIX;
// concat package + path
this.packagePath = concatPackage(basePackagePath, subPackagePath);
String subPath = packagePath.replaceAll("\\.", PATH_SLASH);
this.filePathWithFileName = concatPath(userDir, JAVA_FILE_PATH, subPath)+fileNameWithSuffix;
}
/**
* concatPath
*
* @param basePath
* @param subPath
* @return
*/
private String concatPath(String basePath, String... subPath) {
StringBuilder stringBuilder = new StringBuilder(formatPath(basePath));
for (String s : subPath) {
String formatPath = formatPath(s);
if (StringUtils.isEmpty(formatPath)) {
continue;
}
stringBuilder.append(formatPath);
}
// 结尾加/
stringBuilder.append(PATH_SLASH);
return stringBuilder.toString();
}
/**
* concatPackage
*
* @param basePackage
* @param subPackage
* @return
*/
private String concatPackage(String basePackage, String... subPackage) {
StringBuilder stringBuilder = new StringBuilder(formatPackage(basePackage));
for (String s : subPackage) {
String formatPackage = formatPackage(s);
if (StringUtils.isEmpty(formatPackage)) {
continue;
}
stringBuilder.append(PACKAGE_DOT).append(formatPackage);
}
return stringBuilder.toString();
}
/**
* /Users/yuntian/try 前有 后无/
*
* @param curPath
* @return
*/
private String formatPath(String curPath) {
if (!curPath.startsWith(PATH_SLASH)) {
curPath = PATH_SLASH + curPath;
}
while (curPath.endsWith(PATH_SLASH)) {
curPath = curPath.substring(0, curPath.length() - 1);
}
return curPath;
}
/**
* 前后无.
*
* @param curPackage
* @return
*/
private String formatPackage(String curPackage) {
while (curPackage.startsWith(PACKAGE_DOT)) {
curPackage = curPackage.substring(1);
}
while (curPackage.endsWith(PACKAGE_DOT)) {
curPackage = curPackage.substring(0, curPackage.length() - 1);
}
return curPackage;
}
}
生成文件的主流程
package com.example.demo.test.velocity;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* VelocityDemo
*
* @author YunTian
* @since 2020/10/29
*/
public class VelocityDemo {
//类名
static String domainName = "YunTian";
//类包
static String basePackageName = "com.example.demo";
// /Users/yuntian/try/demo;
static String userDir = System.getProperty("user.dir");
static String templateDir = "/src/main/resources/templates/";
static String templateFileName = "Service.java.vm";
public static void main(String[] args) throws Exception {
TargetFileConfig fileConfig = new TargetFileConfig(basePackageName,"service.impl",domainName,userDir);
Map<String, TargetFileConfig> map = new HashMap<>();
map.put(templateFileName, fileConfig);
for (Map.Entry<String, TargetFileConfig> entry : map.entrySet()) {
String templateFileName=entry.getKey();
TargetFileConfig targetFileConfig = entry.getValue();
// 模板变量
VelocityContext context = buildVelocityContext(targetFileConfig);
// 获取模板
Template template = genTemplate(templateFileName);
// 生成文件
generatorTargetFile(context,template);
}
}
// 生成文件
private static void generatorTargetFile(VelocityContext context, Template template) throws Exception {
// 目的路径
String filePathWithFileName = (String) context.get("fileFullPath");
File file = new File(filePathWithFileName);
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream outStream = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(outStream,
StandardCharsets.UTF_8);
BufferedWriter sw = new BufferedWriter(writer);
template.merge(context, sw);
sw.flush();
sw.close();
outStream.close();
System.out.println("成功生成文件:" + filePathWithFileName);
}
/**
* 获取模板
* @param templateFileName 模板文件名
* @return
*/
private static Template genTemplate(String templateFileName){
VelocityEngine ve = buildVelocityEngine(userDir + templateDir);
return ve.getTemplate(templateFileName, StandardCharsets.UTF_8.name());
}
/**
* buildVelocityEngine
* @param absoluteTemplateDir 模板的绝对路径
* @return
*/
private static VelocityEngine buildVelocityEngine(String absoluteTemplateDir){
Properties pro = new Properties();
pro.setProperty(Velocity.OUTPUT_ENCODING, StandardCharsets.UTF_8.name());
pro.setProperty(Velocity.INPUT_ENCODING, StandardCharsets.UTF_8.name());
pro.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, absoluteTemplateDir);
return new VelocityEngine(pro);
}
/**
* 构造模板变量
* @return
*/
private static VelocityContext buildVelocityContext(TargetFileConfig fileConfig){
VelocityContext context = new VelocityContext();
context.put("packagePath", fileConfig.getPackagePath());
context.put("targetFileName", fileConfig.getFileName());
context.put("fileFullPath", fileConfig.getFilePathWithFileName());
String[] list= new String[]{"1","3"};
context.put("productArr", list);
// 执行add
context.put("testProductArr", "1");
context.put("testMap", "1");
Map<String, String> kvMap = new HashMap<>();
kvMap.put("k1","v1");
kvMap.put("k2","v2");
context.put("kvMap", kvMap);
return context;
}
}
结果
package com.example.demo.service.impl;
import java.lang.String;
public class YunTianServiceImpl {
<li>value=1</li>
<li>value=3</li>
<li>Key: k1 ->Value: v1</li>
<li>Key: k2 ->Value: v2</li>
}
推而广之,可以利用velocity生成任意模板化的项目文件。
Reference
- https://www.cnblogs.com/codingsilence/archive/2011/03/29/2146580.html
- https://www.cnblogs.com/niehaikuo/p/8873279.html