@Service
public class MultiDocxServiceImpl implements MultiDocxService {
private final Logger log = LoggerFactory.getLogger(MultiDocxServiceImpl.class);
@Resource
private FileServerUtil fileServerUtil;
@Resource
private PropertiesUtils propertiesUtils;
public final String DOCX_NAME = "_default.docx";
@Value("${cache.expire:86400}")
private Long expire;
@Value("${word.title.fontFamily:宋体}")
private String fontFamily;
@Value("${word.title.fontSize:10}")
private Integer fontSize;
@Override
public String merge(MultiDocxParams multiDocxParams) {
log.info("入参:{}", JSON.toJSONString(multiDocxParams));
String fileName = multiDocxParams.getFileName();
if(StringUtils.isBlank(fileName)){
fileName = UUIDGenerator.getUUID() + DOCX_NAME;
}else{
fileName = multiDocxParams.getFileName();
}
String localPath = propertiesUtils.getCommonYml("upload.path") + fileName;
NiceXWPFDocument mergeDocument = null;
FileOutputStream out = null;
try {
FileUtil.mkParentDirs(localPath);
out = new FileOutputStream(localPath);
mergeDocument = mergeDocument(multiDocxParams);
mergeDocument.write(out);
return fileServerUtil.restTemplateUploadFile(new File(localPath));
} catch (Exception e) {
log.error("合并异常了",e);
throw new CustomException(ResponseCode.FAILED.getCode(),e.getMessage());
} finally {
try {
if(mergeDocument!=null) {
mergeDocument.close();
}
if(out!=null) {
out.close();
}
} catch (IOException e) {
log.error("关闭文件异常",e);
log.error("关闭文件失败,文件位置:{}",localPath);
}
try {
// 删除临时docx文件
File file = new File(localPath);
file.delete();
} catch (Exception e) {
log.error("删除临时文件异常",e);
log.error("删除临时文件失败,文件位置:{}",localPath);
}
}
}
private NiceXWPFDocument mergeDocument(MultiDocxParams multiDocxParams) throws Exception {
List<DocxFileParam> docxFileParamList = multiDocxParams.getDocxFileParamList();
NiceXWPFDocument newDoc = null;
for (DocxFileParam docxFileParam : docxFileParamList) {
NiceXWPFDocument document = getDocument(docxFileParam.getFileId());
NiceXWPFDocument niceXWPFDocument = word2007ParamReplace(document, changeMap(docxFileParam.getParams()));
if (newDoc == null) {
newDoc = niceXWPFDocument;
} else {
//添加段落
XWPFParagraph p = newDoc.createParagraph();
p.setPageBreak(true);
if(StringUtils.isNotBlank(docxFileParam.getTitle())) {
XWPFRun run = p.createRun();
run.setFontFamily(fontFamily);
run.setFontSize(fontSize);
run.setText(docxFileParam.getTitle());
}
newDoc = newDoc.merge(niceXWPFDocument);
}
}
return newDoc;
}
private NiceXWPFDocument getDocument(Long fileId) throws Exception {
String name = String.valueOf(fileId);
Object cache = Cache.get(name);
NiceXWPFDocument document = null;
if (cache != null) {
byte[] b = (byte[]) cache;
document = new NiceXWPFDocument(toInputStream(b));
} else {
byte[] buf = fileServerUtil.restTemplateDownloadFile(fileId);
Cache.put(name, buf, expire*1000);
document = new NiceXWPFDocument(toInputStream(buf));
}
return document;
}
public InputStream toInputStream(byte[] b) {
return new ByteArrayInputStream(b);
}
private Map<String, String> changeMap(Map<String, String> paramsMap) {
if (paramsMap == null || paramsMap.isEmpty()) {
return paramsMap;
}
Map<String, String> changeMap = new HashMap<>();
Set<String> keys = paramsMap.keySet();
for (String key : keys) {
changeMap.put("${" + key + "}", StringUtils.defaultIfEmpty(paramsMap.get(key),""));
}
return changeMap;
}
private NiceXWPFDocument word2007ParamReplace(NiceXWPFDocument document, Map<String, String> paramsMap) {
if (paramsMap == null || paramsMap.isEmpty()) {
return document;
}
// 替换段落中的指定文字
Iterator<XWPFParagraph> itPara = document.getParagraphsIterator();
while (itPara.hasNext()) {
XWPFParagraph paragraph = (XWPFParagraph) itPara.next();
List<XWPFRun> runs = paragraph.getRuns();
for (int i = 0; i < runs.size(); i++) {
String oneparaString = runs.get(i).getText(0);
if (oneparaString != null && !"".equals(oneparaString)) {
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
oneparaString = oneparaString.replace(entry.getKey(), entry.getValue());
runs.get(i).setText(oneparaString, 0);
}
}
}
}
// 替换表格中的指定文字
Iterator<XWPFTable> itTable = document.getTablesIterator();
while (itTable.hasNext()) {
XWPFTable table = (XWPFTable) itTable.next();
int rcount = table.getNumberOfRows();
for (int i = 0; i < rcount; i++) {
XWPFTableRow row = table.getRow(i);
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> paragraphs = cell.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String oneparaString = run.getText(0);
if (oneparaString != null && !"".equals(oneparaString.trim())) {
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
oneparaString = oneparaString.replace(entry.getKey(), entry.getValue());
run.setText(oneparaString, 0);
}
}
}
}
}
}
}
return document;
}
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.9.1</version>
</dependency>
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "DocxFileParam对象", description = "DocxFileParam对象")
public class DocxFileParam {
@ApiModelProperty(value = "word文件ID")
@NotNull(message = "word文件ID不能为空")
private Long fileId;
@ApiModelProperty(value = "word文件中参数列表")
private Map<String, String> params;
@ApiModelProperty(value = "抬头title,可以为空")
private String title;
}
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "MultiDocxParams对象", description = "MultiDocxParams对象")
public class MultiDocxParams {
@ApiModelProperty(value = "上传到文件服务器的名称,不填则自动生成")
private String fileName;
@ApiModelProperty(value = "word列表")
@Size(min = 1,message = "word文件列表至少1个")
private List<DocxFileParam> docxFileParamList;
}