package org.jeecg.modules.system.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.docx4j.TraversalUtil;
import org.docx4j.XmlUtils;
import org.docx4j.finders.ClassFinder;
import org.docx4j.jaxb.Context;
import org.docx4j.model.fields.FieldUpdater;
import org.docx4j.openpackaging.io3.Save;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Document;
import org.docx4j.wml.Tbl;
import org.docx4j.wml.Tr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Component
public class VariableReplace {
private static final Logger LOGGER = LoggerFactory.getLogger(VariableReplace.class);
static {
preLoadWordTemptal();
}
private static void preLoadWordTemptal () {
try {
String wordTemplateFilePath = CreditWordTemplateUtils.getCreditWordTemplateResourcePath("wordTemplateDir", 1);
LOGGER.info("wordTemplateFilePath:{}", wordTemplateFilePath);
ClassPathResource resource = new ClassPathResource(wordTemplateFilePath);
try(InputStream rs = resource.getInputStream()) {
//获取word模板文件的路径
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
.load(rs);
}
}catch (Exception e){
LOGGER.error("preLoadWordTemplate load fail");
}
}
public static String getNewWord(String flag, Map<String, String> mappings , List<Map<String, String>> getDataList1
, HttpServletResponse response, String wordTemplateDir) throws Exception {
//获取word模板文件的路径
String wordTemplateFilePath = CreditWordTemplateUtils.getCreditWordTemplateResourcePath(wordTemplateDir, Integer.valueOf(flag));
LOGGER.info("wordTemplateFilePath:{}", wordTemplateFilePath);
ClassPathResource resource = new ClassPathResource(wordTemplateFilePath);
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
.load(resource.getInputStream());
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
cleanDocumentPart(documentPart);
int startIndex = 11;
//单一
if ("1".equals(flag)) {
//替换表格1
startIndex = 11;
} else if ("2".equals(flag)) {
startIndex = 12;
}else if ("3".equals(flag)){
startIndex = 7;
}
//替换表格1
ClassFinder find = new ClassFinder(Tbl.class);
new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(), find);
Tbl table = (Tbl) find.results.get(0);
if (ObjectUtils.isNotEmpty(getDataList1)) {
Tr dynamicTr = (Tr) table.getContent().get(startIndex);
String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);
for (Map<String, String> dataMap : getDataList1) {
// cleanDocumentPart(documentPart);
Tr newTr = (Tr) XmlUtils.unmarshallFromTemplate(dynamicTrXml, dataMap);
table.getContent().add(startIndex, newTr);
startIndex++;
}
table.getContent().remove(startIndex);
}
//替换内容
long start = System.currentTimeMillis();
documentPart.variableReplace(mappings);
long end = System.currentTimeMillis();
long total = end - start;
LOGGER.info("Time-------: {}", total);
FieldUpdater fieldUpdater = new FieldUpdater(wordMLPackage);
fieldUpdater.update(false);
Save save1 = new Save(wordMLPackage);
save1.save(response.getOutputStream());
LOGGER.info("刷新输出流.....");
response.getOutputStream().flush();
return "";
}
public static boolean cleanDocumentPart(MainDocumentPart documentPart) throws Exception {
if (documentPart == null) {
return false;
}
Document document = documentPart.getContents();
String wmlTemplate =
XmlUtils.marshaltoString(document, true, false, Context.jc);
document = (Document) XmlUtils.unwrap(DocxVariableClearUtils.doCleanDocumentPart(wmlTemplate, Context.jc));
documentPart.setContents(document);
return true;
}
/**
* 将金额格式转为三位一逗
*
* @return
*/
public static String convertAccountFormat(String str) {
if (StringUtils.isBlank(str)) {
return "0.00";
}
//判断是否为数值型
boolean matches = str.matches("-?[0-9]+.?[0-9]*");
if (matches) {
DecimalFormat df = new DecimalFormat("#,##0.00");
String data = df.format(new BigDecimal(str));
return data;
}
return str;
}
/**
* 将日期中的“/”转化为“-”
* 和yyyyMMdd格式的转换为yyyy-MM-dd
*
* @param dateStr
* @return
*/
public static String converDateFormat(String dateStr) {
if (StringUtils.isNotBlank(dateStr)) {
String str = null;
if (dateStr.matches("^[0-9]{8}$")) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
Date date = null;
try {
date = format.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
str = dateFormat.format(date);
return str;
} else if (dateStr.length() > 8) {
str = dateStr.replaceAll("/", "-");
return str;
} else {
return dateStr;
}
}
return "";
}
public static String extractFinanceNumber(String str) {
try {
double number = Double.parseDouble(str);
return str;
} catch (Exception e) {
log.info("尽责报告表头获取金额为脏数据,用正则表达式提取");
String regex = "[\\d|,|, ]+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
return matcher.find() ? matcher.group(0).replaceAll(",|,", "") : "";
}
}
/**
* 日期处理:
"20211001",
"2021-10-01",
"2021/10/01",
"2021-10-01/12:23:00",
"2021/10/01 12:23:00",
"2021/10/01 12:23:00"
* */
public static String converDateString(String str){
String date;
Pattern pattern1 = Pattern.compile("^\\d{4}-\\d{1,2}-\\d{1,2}");
Matcher matcher1 = pattern1.matcher(str);
if (matcher1.find()){
date=matcher1.group();
String[] dateStrs=date.split("-");
return dateStrs[0]+
(dateStrs[1].length()==1?"-0"+dateStrs[1]:"-"+dateStrs[1])+
(dateStrs[2].length()==1?"-0"+dateStrs[2]:"-"+dateStrs[2]);
}
Pattern pattern2 = Pattern.compile("^\\d{8}");
Matcher matcher2 = pattern2.matcher(str);
if (matcher2.find()){
date=matcher2.group();
return date.replaceAll("(?<=^\\d{4})|(?<=^\\d{6})","-");
}
Pattern pattern3 = Pattern.compile("^\\d{4}/\\d{1,2}/\\d{1,2}");
Matcher matcher3 = pattern3.matcher(str);
if (matcher3.find()){
date=matcher3.group();
String[] dateStrs=date.split("/");
return dateStrs[0]+
(dateStrs[1].length()==1?"-0"+dateStrs[1]:"-"+dateStrs[1])+
(dateStrs[2].length()==1?"-0"+dateStrs[2]:"-"+dateStrs[2]);
}
return str;
}
}
扫清${variable}格式
package com.amarsoft.app.afrs.core.utils;
import org.docx4j.XmlUtils;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.util.regex.Pattern;
/**
* 清扫 docx4j 模板变量字符,通常以${variable}形式
*
* XXX: 主要在上传模板时处理一下, 后续
*
* @author liliang
* @since 2018-11-07
*/
public class DocxVariableClearUtils {
/**
* 去任意XML标签
*/
private static final Pattern XML_PATTERN = Pattern.compile("<[^>]*>");
private DocxVariableClearUtils() {
}
/**
* start符号
*/
private static final char PREFIX = '$';
/**
* 中包含
*/
private static final char LEFT_BRACE = '{';
/**
* 结尾
*/
private static final char RIGHT_BRACE = '}';
/**
* 未开始
*/
private static final int NONE_START = -1;
/**
* 未开始
*/
private static final int NONE_START_INDEX = -1;
/**
* 开始
*/
private static final int PREFIX_STATUS = 1;
/**
* 左括号
*/
private static final int LEFT_BRACE_STATUS = 2;
/**
* 右括号
*/
private static final int RIGHT_BRACE_STATUS = 3;
/**
* doCleanDocumentPart
*
* @param wmlTemplate
* @param jc
* @return
* @throws JAXBException
*/
public static Object doCleanDocumentPart(String wmlTemplate, JAXBContext jc) throws JAXBException {
// 进入变量块位置
int curStatus = NONE_START;
// 开始位置
int keyStartIndex = NONE_START_INDEX;
// 当前位置
int curIndex = 0;
char[] textCharacters = wmlTemplate.toCharArray();
StringBuilder documentBuilder = new StringBuilder(textCharacters.length);
documentBuilder.append(textCharacters);
// 新文档
StringBuilder newDocumentBuilder = new StringBuilder(textCharacters.length);
// 最后一次写位置
int lastWriteIndex = 0;
for (char c : textCharacters) {
switch (c) {
case PREFIX:
// TODO 不管其何状态直接修改指针,这也意味着变量名称里面不能有PREFIX
keyStartIndex = curIndex;
curStatus = PREFIX_STATUS;
break;
case LEFT_BRACE:
if (curStatus == PREFIX_STATUS) {
curStatus = LEFT_BRACE_STATUS;
}
break;
case RIGHT_BRACE:
if (curStatus == LEFT_BRACE_STATUS) {
// 接上之前的字符
newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex, keyStartIndex));
// 结束位置
int keyEndIndex = curIndex + 1;
// 替换
String rawKey = documentBuilder.substring(keyStartIndex, keyEndIndex);
// 干掉多余标签
String mappingKey = XML_PATTERN.matcher(rawKey).replaceAll("");
if (!mappingKey.equals(rawKey)) {
char[] rawKeyChars = rawKey.toCharArray();
// 保留原格式
StringBuilder rawStringBuilder = new StringBuilder(rawKey.length());
// 去掉变量引用字符
for (char rawChar : rawKeyChars) {
if (rawChar == PREFIX || rawChar == LEFT_BRACE || rawChar == RIGHT_BRACE) {
continue;
}
rawStringBuilder.append(rawChar);
}
// FIXME 要求变量连在一起
String variable = mappingKey.substring(2, mappingKey.length() - 1);
int variableStart = rawStringBuilder.indexOf(variable);
if (variableStart > 0) {
rawStringBuilder = rawStringBuilder.replace(variableStart, variableStart + variable.length(), mappingKey);
}
newDocumentBuilder.append(rawStringBuilder.toString());
} else {
newDocumentBuilder.append(mappingKey);
}
lastWriteIndex = keyEndIndex;
curStatus = NONE_START;
keyStartIndex = NONE_START_INDEX;
}
default:
break;
}
curIndex++;
}
// 余部
if (lastWriteIndex < documentBuilder.length()) {
newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex));
}
return XmlUtils.unmarshalString(newDocumentBuilder.toString(), jc);
}
}
合并单元格子
package com.amarsoft.app;
import org.docx4j.wml.*;
import javax.xml.bind.JAXBElement;
import java.util.ArrayList;
import java.util.List;
public class MergeCell {
public static void main(String[] args) {
//替换表格
ClassFinder find = new ClassFinder(Tbl.class);
new TraversalUtil(wordMLPackage.getMainDocumentPart().getContent(),find);
Tbl table = (Tbl) find.results.get(0);
Tr dynamicTr = (Tr) table.getContent().get(11);
String dynamicTrXml = XmlUtils.marshaltoString(dynamicTr);
int startIndex = 11;
List<Map<String, Object>> dataList = getDataList();
for(Map<String, Object> dataMap : dataList){
// cleanDocumentPart(documentPart);
Tr newTr = (Tr) XmlUtils.unmarshallFromTemplate(dynamicTrXml,dataMap);
table.getContent().add(startIndex,newTr);
startIndex++;
}
table.getContent().remove(startIndex);
new MergeCell().mergeCellsVertically(table,0,11,20);
}
/**
* @Description: 跨列合并
*/
public void mergeCellsHorizontal(Tbl tbl, int row, int fromCell, int toCell) {
if (row < 0 || fromCell < 0 || toCell < 0) {
return;
}
List<Tr> trList = getTblAllTr(tbl);
if (row > trList.size()) {
return;
}
Tr tr = trList.get(row);
List<Tc> tcList = getTrAllCell(tr);
for (int cellIndex = fromCell, len = Math
.min(tcList.size() - 1, toCell); cellIndex <= len; cellIndex++) {
Tc tc = tcList.get(cellIndex);
TcPr tcPr = getTcPr(tc);
TcPrInner.HMerge hMerge = tcPr.getHMerge();
if (hMerge == null) {
hMerge = new TcPrInner.HMerge();
tcPr.setHMerge(hMerge);
}
if (cellIndex == fromCell) {
hMerge.setVal("restart");
} else {
hMerge.setVal("continue");
}
}
}
/**
* @Description: 跨行合并
*/
public void mergeCellsVertically(Tbl tbl, int col, int fromRow, int toRow) {
if (col < 0 || fromRow < 0 || toRow < 0) {
return;
}
for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
Tc tc = getTc(tbl, rowIndex, col);
if (tc == null) {
break;
}
TcPr tcPr = getTcPr(tc);
TcPrInner.VMerge vMerge = tcPr.getVMerge();
if (vMerge == null) {
vMerge = new TcPrInner.VMerge();
tcPr.setVMerge(vMerge);
}
if (rowIndex == fromRow) {
vMerge.setVal("restart");
} else {
vMerge.setVal("continue");
}
}
}
/**
* @Description:得到指定位置的表格
*/
public Tc getTc(Tbl tbl, int row, int cell) {
if (row < 0 || cell < 0) {
return null;
}
List<Tr> trList = getTblAllTr(tbl);
if (row >= trList.size()) {
return null;
}
List<Tc> tcList = getTrAllCell(trList.get(row));
if (cell >= tcList.size()) {
return null;
}
return tcList.get(cell);
}
/**
* @Description: 获取所有的单元格
*/
public List<Tc> getTrAllCell(Tr tr) {
List<Object> objList = getAllElementFromObject(tr, Tc.class);
List<Tc> tcList = new ArrayList<Tc>();
if (objList == null) {
return tcList;
}
for (Object tcObj : objList) {
if (tcObj instanceof Tc) {
Tc objTc = (Tc) tcObj;
tcList.add(objTc);
}
}
return tcList;
}
public TcPr getTcPr(Tc tc) {
TcPr tcPr = tc.getTcPr();
if (tcPr == null) {
tcPr = new TcPr();
tc.setTcPr(tcPr);
}
return tcPr;
}
/**
* @Description: 得到表格所有的行
*/
public List<Tr> getTblAllTr(Tbl tbl) {
List<Object> objList = getAllElementFromObject(tbl, Tr.class);
List<Tr> trList = new ArrayList<Tr>();
if (objList == null) {
return trList;
}
for (Object obj : objList) {
if (obj instanceof Tr) {
Tr tr = (Tr) obj;
trList.add(tr);
}
}
return trList;
}
/**
* @Description:得到指定类型的元素
*/
public static List<Object> getAllElementFromObject(Object obj,
Class<?> toSearch) {
List<Object> result = new ArrayList<Object>();
if (obj instanceof JAXBElement)
obj = ((JAXBElement<?>) obj).getValue();
if (obj.getClass().equals(toSearch))
result.add(obj);
else if (obj instanceof ContentAccessor) {
List<?> children = ((ContentAccessor) obj).getContent();
for (Object child : children) {
result.addAll(getAllElementFromObject(child, toSearch));
}
}
return result;
}
}
添加响应头信息
/**
* 添加响应头信息
*
* @param response
* @param fileName
* @throws Exception
*/
private void setResponseHeader(HttpServletResponse response, String fileName) throws Exception {
try {
try {
fileName = new String(fileName.getBytes(), "ISO8859-1");
} catch (UnsupportedEncodingException e) {
log.error("尽责报告导出失败", e);
throw e;
}
response.setContentType("application/octet-stream;charset=ISO8859-1");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
} catch (Exception e) {
log.error("尽责报告导出失败", e);
throw e;
}
}