public static <T> void getDocx(String fileName, List<Map<String, Object>> List) throws Exception {
//模板路径
String testPath = "docx/导出.docx";
//输出路径1
String outPath = "D:/1/"+fileName+".docx";
//书签名称
String bookmarkName = "bookmark";
// 图片路径
String imagePath = "C:\\Users\\Administrator\\Desktop\\1.jpg";
WordprocessingMLPackage wordMlPackage = WordprocessingMLPackage.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(testPath));;
org.docx4j.finders.ClassFinder find = new ClassFinder(Tbl.class);
new TraversalUtil(wordMlPackage.getMainDocumentPart().getContent(),find);
// 提取正文
MainDocumentPart mainDocumentPart = wordMlPackage.getMainDocumentPart();
Document wmlDoc = (Document) mainDocumentPart.getJaxbElement();
Body body = wmlDoc.getBody();
// 提取正文中所有段落
List<Object> paragraphs = body.getContent();
// 提取书签并创建书签的游标
RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
new TraversalUtil(paragraphs, rt);
//构造循环列表的数据
Map<String, String> mappings = null;
List wordInformationDataList = null;
for (Map<String,Object> data:List
) {
String type = (String) data.get("type");
//如果type为1,,则设置为全局变量
if ("1".equals(type)) {
List datalist = (List) data.get("datalist");
mappings = (HashMap<String, String>) datalist.get(0);
mappings = mapSetNullToBlankString(mappings);
} else {
wordInformationDataList = (List) data.get("datalist");
//读取第几个表格
Tbl table = (Tbl) find.results.get(Integer.valueOf(type)-1);
// 获取模板行的XML数据
Tr dynamicTr = (Tr) table.getContent().get(1);
String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);
List<Map<String,Object>> dataList= new ArrayList<Map<String, Object>>() ;
dataList = wordInformationDataList;
for (Map<String,Object> dataMap :dataList){
Map map = mapSetNullToBlankString(dataMap);
Tr newTr = (Tr)XmlUtils.unmarshallFromTemplate(dynamicTrXml,map);
table.getContent().add(newTr);
}
//删除模板行的站位行
table.getContent().remove(1);
}
}
// 遍历书签
for (CTBookmark bm:rt.getStarts()) {
// 这儿可以对单个书签进行操作,也可以用一个map对所有的书签进行处理
if (bm.getName().equals(bookmarkName)){
// 读入图片并转化为字节数组,因为docx4j只能字节数组的方式插入图片
InputStream is = new FileInputStream(imagePath);
byte[] bytes = IOUtils.toByteArray(is);
// 穿件一个行内图片
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMlPackage, bytes);
// createImageInline函数的前四个参数我都没有找到具体啥意思,,,,
// 最有一个是限制图片的宽度,缩放的依据
Inline inline = imagePart.createImageInline(null, null, 0,1, false, 1800);
// 获取该书签的父级段落
P p = (P)(bm.getParent());
ObjectFactory factory = new ObjectFactory();
// R对象是匿名的复杂类型,然而我并不知道具体啥意思,估计这个要好好去看看ooxml才知道
R run = factory.createR();
// drawing理解为画布?
Drawing drawing = factory.createDrawing();
drawing.getAnchorOrInline().add(inline);
run.getContent().add(drawing);
p.getContent().add(run);
}
}
//替换全局变量
wordMlPackage.getMainDocumentPart().variableReplace(mappings);
//输出文件
Docx4J.save(wordMlPackage,new File(outPath));
}
mapSetNullToBlankString(Map map) 是将map中的null替换为空字符串的方法,docx4j使用模板导出时,如果值为null会在表格内留下字段名。