poi-tl(poi template language)是Word模板引擎,使用Word模板和数据创建很棒的Word文档。 poi-tl官方网址
项目中有需求需要动态填充交易合同,因此想到了使用poi-tl技术来实现
com.deepoove
poi-tl
1.5.0
org.apache.poi
poi-ooxml
4.1.2
org.apache.poi
poi-ooxml-schemas
4.1.2
org.apache.poi
poi
4.1.2
com.deepoove
poi-tl
1.9.1
public class MoneyUtils {
private static final String UNIT = "万千佰拾亿千佰拾万千佰拾元角分";
private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
private static final double MAX_VALUE = 9999999999999.99D;
public static String change(double v) {
if (v < 0 || v > MAX_VALUE){
return "参数非法!";
}
long l = Math.round(v * 100);
if (l == 0){
return "零元整";
}
String strValue = l + "";
// i用来控制数
int i = 0;
// j用来控制单位
int j = UNIT.length() - strValue.length();
String rs = "";
boolean isZero = false;
for (; i < strValue.length(); i++, j++) {
char ch = strValue.charAt(i);
if (ch == '0') {
isZero = true;
if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
rs = rs + UNIT.charAt(j);
isZero = false;
}
} else {
if (isZero) {
rs = rs + "零";
isZero = false;
}
rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
}
}
if (!rs.endsWith("分")) {
rs = rs + "整";
}
rs = rs.replaceAll("亿万", "亿");
return rs;
}
public static void main(String[] args){
System.out.println(MoneyUtils.change(12356789.9845));
}
}
# 电子合同生成相关配置
contract:
#生产环境合同模板存放路径
prodTemplateUrl: https://xxxxxx-cn-beijing.aliyuncs.com/templets/64042201/20221116/cd9aeb196edd46aeacc607c18d1c481d/xxxxxx活牛交易市场肉牛买卖合同模板.docx
#生产环境合同临时存放路径(应用服务器路径)
prodContractPath: /ekode/offlineFile/
#测试环境合同模板存放路径
devTemplateUrl: https://xxxxxx-cn-beijing.aliyuncs.com/templets/64042201/20221116/cd9aeb196edd46aeacc607c18d1c481d/xxxxxx活牛交易市场肉牛买卖合同模板.docx
#测试环境合同临时存放路径(应用服务器路径)
devContractPath: C://Users//xxxxxx//Desktop//临时文件//
#合同名后缀
fileNameSuffix: 肉牛买卖合同
@Component
@ConfigurationProperties(prefix = "contract")
public class ContractConfig {
private String prodTemplateUrl;
private String prodContractPath;
private String devTemplateUrl;
private String devContractPath;
private String fileNameSuffix;
public String getProdTemplateUrl() {
return prodTemplateUrl;
}
public void setProdTemplateUrl(String prodTemplateUrl) {
this.prodTemplateUrl = prodTemplateUrl;
}
public String getProdContractPath() {
return prodContractPath;
}
public void setProdContractPath(String prodContractPath) {
this.prodContractPath = prodContractPath;
}
public String getDevTemplateUrl() {
return devTemplateUrl;
}
public void setDevTemplateUrl(String devTemplateUrl) {
this.devTemplateUrl = devTemplateUrl;
}
public String getDevContractPath() {
return devContractPath;
}
public void setDevContractPath(String devContractPath) {
this.devContractPath = devContractPath;
}
public String getFileNameSuffix() {
return fileNameSuffix;
}
public void setFileNameSuffix(String fileNameSuffix) {
this.fileNameSuffix = fileNameSuffix;
}
}
public class WordUtils {
private static Logger logger = LoggerFactory.getLogger(WordUtils.class);
/**
* @param templatePath 文档模板存放路径
* @param createFileDir 生成的文档存档地址
* @param createFileName 生成的文件名(不带格式后缀)
* @param paramsMap 需要填充的内容
* @return
*/
public static String createWord(String templatePath, String createFileDir, String createFileName, Map paramsMap) throws IOException {
logger.info("【动态填充文档公共方法】被操作文档:{},填充后新文档存放地址:{},填充后新文档名称:{}," +
"填充字段内容:{}", JSON.toJSONString(templatePath),JSON.toJSONString(createFileDir),
JSON.toJSONString(createFileName),JSON.toJSONString(paramsMap));
Assert.notNull(templatePath,"文档模板存放路径不能为空");
Assert.notNull(createFileDir,"生成的文档存档地址不能为空");
Assert.notNull(createFileName,"生成的文件名不能为空");
Assert.notNull(paramsMap,"需要填充的内容不能为空");
//生成的文件格式
String formatSuffix = ".docx";
//拼接后的文件名
String fileName = createFileName + formatSuffix;
logger.info("生成合同的文件名(带后缀)为:{}",JSON.toJSONString(fileName));
//生成文件存放路径
if(!createFileDir.endsWith("/")){
createFileDir = createFileDir + File.separator;
}
File dir = new File(createFileDir);
if(!dir.exists()){
dir.mkdirs();
logger.info("生成合同时存储文件的路径{}不存在,已自动创建文件夹",createFileDir);
}
//生成的文件全路径
String filePath = createFileDir + fileName;
logger.info("生成合同的存放路径(绝对路径):{}",JSON.toJSONString(filePath));
XWPFTemplate template = null;
//poi-tl使用网络文件作为合同模板,需要转换为文件流动态填写
if(templatePath.contains("https://xxxxxx-cn-beijing.aliyuncs.com")){
URL url = new URL(templatePath);
InputStream in = url.openStream();
//渲染表格
HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy();
//此list是步骤四中动态传入的数据列表
Configure config = Configure.newBuilder().bind("list", policy).build();
template = XWPFTemplate.compile(in,config).render(paramsMap);
}else {
//hetong muban wei bendi wenjian
template = XWPFTemplate.compile(templatePath).render(paramsMap);
}
//将填写后的内容写入生成的合同中
template.writeToFile(filePath);
template.close();
logger.info("【生成的电子合同本地存放路径为】:{}",JSON.toJSONString(filePath));
return filePath;
}
}
Map paramsMap = new HashMap<>();
paramsMap.put("bianHao",bianHao);
paramsMap.put("jfName",contractDTO.getJfName());
paramsMap.put("yfName",contractDTO.getYfName());
paramsMap.put("zongJia",contractDTO.getPrice());
paramsMap.put("dingJin",contractDTO.getDingJin());
paramsMap.put("yuKuan",contractDTO.getWeiKuan());
paramsMap.put("yuKuanJieQingDate",contractDTO.getJiaoFuDateEnd()+"日");
paramsMap.put("jiaoFuDateStart",contractDTO.getJiaoFuDateStart()+"日");
paramsMap.put("jiaoFuDateEnd",contractDTO.getJiaoFuDateEnd()+"日");
paramsMap.put("gaoZhiDay",contractDTO.getGaoZhiDay());
paramsMap.put("jiaoFuDiDian",contractDTO.getJiaoFuDiDian());
paramsMap.put("yunShuFangShi",contractDTO.getYunShuFangShi());
paramsMap.put("jfwyJin",contractDTO.getJfwyJin());
paramsMap.put("jfwyDay",contractDTO.getJfwyDay());
//牛只列表
List