Aspose.words for java
一、邮件合并
-
接口编写,组装数据。
组装map,以及需要遍历的列表数据。
# invoice { "id": "1651783854850650113", "createBy": "admin", "createTime": "2023-04-28", "updateBy": null, "updateTime": null, "sysOrgCode": "A02A02A01", "invoiceNo": "INV-20230428-012", "invoiceType": "1", "parentContractNo": "000001", "customerName": "测试0426黄11", "customerId": "1651060982522449920", "billContact": "粉红色调", "billMail": "4949198@joifdc.com", "billTel": "5949189", "state": "2", "remark": "31321", "totalPrice": 1317.00, "orderDate": "2023-04-28", "mailAddress": "你好世界", "orderNo": "CM-20230428-001", "invoiceType_dictText": "维修" } #invoiceWorkList [ { "id": "1651783855219748866", "invoiceId": "1651783854850650113", "workContent": "31", "unitPrice": 654.00, "deposite": null, "isDeductionOfDeposit": null, "plateNo": "TET", "carId": null }, { "id": "1651783855219748867", "invoiceId": "1651783854850650113", "workContent": "2", "unitPrice": 6.00, "deposite": null, "isDeductionOfDeposit": null, "plateNo": "CAR-0426-01", "carId": null }, { "id": "1651783855219748868", "invoiceId": "1651783854850650113", "workContent": "32455", "unitPrice": 654.00, "deposite": null, "isDeductionOfDeposit": null, "plateNo": "Tio-001", "carId": null }, { "id": "1651783855219748869", "invoiceId": "1651783854850650113", "workContent": "456", "unitPrice": 3.00, "deposite": null, "isDeductionOfDeposit": null, "plateNo": "Tio-002", "carId": null } ]
@RequestMapping(value = "/printPdf", method = RequestMethod.GET)
public void printPdf(@RequestParam(name="id") String id, HttpServletResponse response) {
try {
Invoice invoice=invoiceService.getById(id);
Map<String, Object> objectMap = BeanUtil.beanToMap(invoice);
String invoiceType = sysDictService.queryDictTextByKey("InvoiceType", String.valueOf(invoice.getInvoiceType()));
// 处理字典
objectMap.put("invoiceType", invoiceType);
// 处理日期
String orderDate = DateUtil.formatDate(invoice.getOrderDate());
objectMap.put("orderDate", orderDate);
// 插入水印
objectMap.put("chapter", TemplatePathEnum.CHAPTER);
// 查子表
Map<String, Object> listMap = new HashMap<>();
List<InvoiceWork> invoiceWorkList = invoiceWorkService.selectByMainId(id);
listMap.put("invoiceWorkList", invoiceWorkList);
AsposeWordUtil.GenerateByTemplate(TemplatePathEnum.INVOICE, response, objectMap,listMap, SaveFormat.PDF, new InvoiceFieldMergingCallback());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- 生成模板方法。这里用了小胡子语法。
mailMerge.execute注入map数据,MailMergeDataSource需要自己继承实现
mailMerge.executeWithRegions注入列表数据,RegionsMailMergeDataSource需要自己继承实现
mailMerge.setFieldMergingCallback注入数据时的回调
public static void GenerateByTemplate(String path, HttpServletResponse response, Map<String,Object> data,Map<String,Object> listMap,int saveFormat,IFieldMergingCallback iFieldMergingCallback) {
if (!getlic()){throw new JeecgBootException("获取证书失败");}
response.addHeader("Content-Disposition", "attachment;filename="+"template."+SaveFormat.getName(saveFormat));
try{
InputStream resourceAsStream = AsposeWordUtil.class.getClassLoader().getResourceAsStream(path);
Document doc = new Document(resourceAsStream);
// 邮件合并
MailMerge mailMerge = doc.getMailMerge();
doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS);
// 字段合并回调
mailMerge.setFieldMergingCallback(iFieldMergingCallback);
// 使用小胡子语法{{$value}}
mailMerge.setUseNonMergeFields(true);
// 注入map映射数据
mailMerge.execute(new MailMergeDataSource(data));
if(listMap!=null){
// 注入列表数据
for (Map.Entry<String, Object> entry : listMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if(ObjectUtil.isNull(value)){continue;}
List<Map<String, Object>> list = Convert.convert(new TypeReference<List<Map<String, Object>>>() {
}, value);
// if(list.size()==0){continue;}
// 邮件列表字段合并,必须要添加合并字段,否则setCleanupOptions不生效
mailMerge.executeWithRegions(new RegionsMailMergeDataSource(key, list));
}
}
// 清除未使用的邮件合并字段
mailMerge.deleteFields();
doc.save(response.getOutputStream(), saveFormat);
response.getOutputStream().close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
MailMergeDataSource
package com.autotoll.aspose;
import cn.hutool.core.util.ObjectUtil;
import com.aspose.words.IMailMergeDataSource;
import com.aspose.words.ref.Ref;
import java.util.Map;
public class MailMergeDataSource implements IMailMergeDataSource {
private Map<String,Object> map;
// 只需要遍历一次
private boolean Once;
public MailMergeDataSource(Map<String, Object> map) {
this.map = map;
this.Once=true;
}
@Override
public String getTableName() throws Exception {
return null;
}
@Override
public boolean moveNext() throws Exception {
if (Once){
Once=false;
return true;
}else{
return false;
}
}
@Override
public boolean getValue(String s, Ref<Object> ref) throws Exception {
ref.set(map.get(s));
return ObjectUtil.isNotNull(map.get(s));
}
@Override
public IMailMergeDataSource getChildDataSource(String s) throws Exception {
return null;
}
}
RegionsMailMergeDataSource
package com.autotoll.aspose;
import cn.hutool.core.util.ObjectUtil;
import com.aspose.words.IMailMergeDataSource;
import com.aspose.words.ref.Ref;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class RegionsMailMergeDataSource implements IMailMergeDataSource {
private List<Map<String,Object>> list;
private Iterator<Map<String,Object>> iterator;
private String tableName;
private Map<String,Object> item;
public RegionsMailMergeDataSource(String tableName,List<Map<String, Object>> list) {
this.list = list;
this.iterator = this.list.iterator();
this.tableName = tableName;
}
@Override
public String getTableName() throws Exception {
return this.tableName;
}
@Override
public boolean moveNext() throws Exception {
if(iterator.hasNext()){
item = iterator.next();
return true;
}else{
return false;
}
}
@Override
public boolean getValue(String s, Ref<Object> ref) throws Exception {
ref.set(item.get(s));
return ObjectUtil.isNotNull(item.get(s));
}
@Override
public IMailMergeDataSource getChildDataSource(String s) throws Exception {
return null;
}
}
- 回调
package com.autotoll.aspose.merge;
import com.aspose.words.*;
import com.autotoll.aspose.FieldMergingCallback;
import java.io.InputStream;
public class InvoiceFieldMergingCallback implements IFieldMergingCallback {
private DocumentBuilder mBuilder;
@Override
public void fieldMerging(FieldMergingArgs e) throws Exception {
// if (mBuilder == null)
// mBuilder = new DocumentBuilder(e.getDocument());
Document doc = e.getDocument();
// 删除书签所在位置===>标题栏
// if("totalPrice".equals(e.getFieldName())){
// if(new BigDecimal(e.getFieldValue().toString()).compareTo(BigDecimal.ZERO)==0){
// BookmarkCollection bookmarks = doc.getRange().getBookmarks();
// Bookmark myBookmark = bookmarks.get("myBookmark");
// myBookmark.getBookmarkStart().getParentNode().getParentNode().getParentNode().remove();
// FieldStart start = e.getField().getStart();
// if (start.getParentNode().getParentNode().getParentNode() != null) {
// start.getParentNode().getParentNode().getParentNode().remove();
// }
// e.getField().remove();
// }
// }
}
@Override
public void imageFieldMerging(ImageFieldMergingArgs args) throws Exception {
InputStream resourceAsStream = FieldMergingCallback.class.getClassLoader().getResourceAsStream(args.getFieldValue().toString());
Shape shape = new Shape(args.getDocument(), ShapeType.IMAGE);
{
shape.setWidth(70.0); shape.setHeight(70.0);
shape.setWrapType(WrapType.NONE);
}
// 设置图片数据流
shape.getImageData().setImage(resourceAsStream);
// 形状在文字下面
shape.setBehindText(true);
shape.setHorizontalAlignment(HorizontalAlignment.CENTER);
shape.setTop(-20);
args.setShape(shape);
}
}
-
模板
其中小胡子语法
{{}}不需要加域,《》是加域后显示的效果。
7. 结果
2023.5.16小胡子语法中使用if,和官网相同,但是比较坑的是没有告知{}是用域创建的,word快捷键是ctrl+f9
二、 LINQ报告引擎
个人感觉不好用,可参考docs.aspose.com/words/java/…