package com.product.print.service;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.net.URLEncodeUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
import com.alibaba.fastjson.JSONArray;
|
import com.deepoove.poi.XWPFTemplate;
|
import com.deepoove.poi.config.Configure;
|
import com.deepoove.poi.config.ConfigureBuilder;
|
import com.deepoove.poi.data.TextRenderData;
|
import com.deepoove.poi.data.style.Style;
|
import com.deepoove.poi.render.RenderContext;
|
import com.deepoove.poi.util.RegexUtils;
|
import com.product.common.lang.StringUtils;
|
import com.product.core.cache.DataPoolCacheImpl;
|
import com.product.core.config.Global;
|
import com.product.core.entity.DataTableEntity;
|
import com.product.core.entity.FieldSetEntity;
|
import com.product.core.exception.BaseException;
|
import com.product.core.service.support.AbstractBaseService;
|
import com.product.file.service.FileManagerService;
|
import com.product.file.util.PdfConcurrenceUtil;
|
import com.product.print.config.CmnCode;
|
import com.product.print.config.CmnConst;
|
import com.product.print.service.ide.IPrintRealizeService;
|
import com.product.print.util.DynamicTableRenderPolicy;
|
import com.product.print.util.FlowOpinionRenderPolicy;
|
import com.product.print.util.TableEmptyHandler;
|
import com.product.tool.flow.service.FlowDetailService;
|
import com.product.util.BaseUtil;
|
|
import com.product.util.SystemParamReplace;
|
import org.apache.poi.xwpf.usermodel.XWPFTable;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import javax.servlet.http.HttpServletResponse;
|
import java.io.*;
|
import java.util.*;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
import java.util.stream.Collectors;
|
|
|
/**
|
* @ClassName PrintRealizeService
|
* @Description 打印实现 业务层
|
* @Author cheng
|
* @Date 2021/12/1 9:50
|
*/
|
@Service
|
public class PrintRealizeService extends AbstractBaseService implements IPrintRealizeService {
|
|
|
@Autowired
|
FileManagerService fileManagerService;
|
|
/**
|
* word打印复选框处理
|
*
|
* @param fse
|
*/
|
public static void dataConvertCheckedData(FieldSetEntity fse) {
|
|
TextRenderData selSymbol = new TextRenderData(CmnConst.PRINT_CHECKED_CHAR, new Style(CmnConst.PRINT_FONT, 14));
|
TextRenderData unselSymbol = new TextRenderData(CmnConst.PRINT_UNCHECKED_CHAR, new Style(CmnConst.PRINT_FONT, 18));
|
|
//获取表单字段
|
Object[] fields = fse.getMeta().getFields();
|
if (fields == null) {
|
return;
|
}
|
for (int i = 0; i < fields.length; ++i) {
|
//获取保存的数据值
|
String dataSaveValue = fse.getString(fields[i] + CmnConst._SAVE_VALUE);
|
if (BaseUtil.strIsNull(dataSaveValue)) {
|
continue;
|
}
|
//获取每个字段的meta信息
|
FieldSetEntity meta = fse.getMeta().getFieldMeta(fields[i].toString());
|
if (meta == null || meta.getString(CmnConst.FIELD_REFERECE) == null || meta.getString(CmnConst.FIELD_REFERECE).indexOf("《") == -1) {
|
continue;
|
}
|
//数据对应参照信息
|
DataTableEntity dictInfos = getMetaAndCacheDictInfo(meta);
|
if (BaseUtil.dataTableIsEmpty(dictInfos)) {
|
continue;
|
}
|
for (int j = 0; j < dictInfos.getRows(); j++) {
|
//获取每个参照对应值
|
String dict_value = dictInfos.getFieldSetEntity(j).getString(CmnConst.DICT_VALUE);
|
if (dataSaveValue.indexOf(dict_value) > -1) {
|
fse.setValue(fields[i] + "_" + dict_value, selSymbol);
|
continue;
|
}
|
fse.setValue(fields[i] + "_" + dict_value, unselSymbol);
|
}
|
}
|
}
|
|
/**
|
* 获取字段对应数据字典信息
|
*
|
* @param fieldMate
|
* @return
|
*/
|
public static DataTableEntity getMetaAndCacheDictInfo(FieldSetEntity fieldMate) {
|
if (fieldMate != null && fieldMate.getString(CmnConst.FIELD_REFERECE) != null) {
|
int a = fieldMate.getString(CmnConst.FIELD_REFERECE).indexOf("《");
|
int b = fieldMate.getString(CmnConst.FIELD_REFERECE).indexOf("》");
|
if (b > 1 && a == 0) {
|
return DataPoolCacheImpl.getInstance().getCacheData("数据字典配置信息", new String[]{fieldMate.getString(CmnConst.FIELD_REFERECE).substring(a + 1, b)});
|
}
|
}
|
return null;
|
}
|
|
|
/**
|
* 打印传输pdf流到前端
|
*
|
* @param fse 打印数据
|
* @param response 响应
|
* @param isConvertPdf 是否转换为pdf
|
* @throws BaseException
|
*/
|
@Override
|
public void print(FieldSetEntity fse, HttpServletResponse response, boolean isConvertPdf) throws BaseException {
|
//打印配置
|
FieldSetEntity printConfig = getPrintConfig(fse.getString("~" + CmnConst.PRINT_TEMP + "~"));
|
//获取到替换后的文件路径 (pdf文件或者word文件)
|
String tempPdfFilePath = replaceTemplateFileOut(printConfig, fse, isConvertPdf);
|
//获取文件名
|
String fileName = BaseUtil.ifNull(printConfig.getString(CmnConst.PRINT_FILE_NAME), printConfig.getString(CmnConst.PRINT_NAME));
|
if (isConvertPdf) {
|
fileName = fileName + ".pdf";
|
} else {
|
fileName = fileName + ".docx";
|
}
|
//设置响应
|
response.setContentType("application/octet-stream;charset=UTF-8");
|
// 将响应头中的Content-Disposition暴露出来,不然前端获取不到
|
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
// 设置自定义头Content-Disposition
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncodeUtil.encode(fileName));
|
|
try (
|
OutputStream out = response.getOutputStream();
|
) {
|
FileUtil.writeToStream(new File(tempPdfFilePath), out);
|
} catch (Exception e) {
|
e.printStackTrace();
|
throw new BaseException(CmnCode.PRINT_CONTENT_FAIL, e);
|
} finally {
|
File file = new File(tempPdfFilePath);
|
String absolutePath = file.getAbsolutePath();
|
System.out.println(absolutePath);
|
file.delete();
|
}
|
|
}
|
|
/**
|
* 获取打印配置
|
*
|
* @param uuid 打印配置uuid
|
* @return
|
* @throws BaseException
|
*/
|
public FieldSetEntity getPrintConfig(String uuid) throws BaseException {
|
//查询打印配置
|
FieldSetEntity fieldSetEntity = getBaseDao().getFieldSetEntity(CmnConst.TABLE_PRINT_CONFIG, uuid, false);
|
if (fieldSetEntity == null || StringUtils.isEmpty(fieldSetEntity.getString(CmnConst.PRINT_TEMPLATE))) {
|
throw new BaseException(CmnCode.PRINT_CONFIG_NOT_EXIST.getValue(), CmnCode.PRINT_CONFIG_NOT_EXIST.getText());
|
}
|
|
return fieldSetEntity;
|
}
|
|
/**
|
* 替换模板文件并输出
|
*
|
* @param printConf 打印配置
|
* @param fse 替换数据
|
* @param isConvertPdf 是否转换为pdf
|
* @return 替换后的文件路径
|
* @throws BaseException 异常
|
*/
|
private String replaceTemplateFileOut(FieldSetEntity printConf, FieldSetEntity fse, boolean isConvertPdf) throws BaseException {
|
|
Object[] fields = fse.getFields();
|
for (int i = 0; i < fields.length; i++) {
|
String field = fields[i].toString();
|
FieldSetEntity metaEntity = fse.getMeta().getFieldMeta(field);
|
if (metaEntity == null) {
|
continue;
|
}
|
String fieldType = metaEntity.getString("field_type");
|
//判断是否拥有流程标识
|
if ("flowsign".equals(fieldType)) {
|
if (StringUtils.equalsAny(fse.getString(field), "1", "2")) {
|
//流程办理中或办结 获取流程意见
|
FieldSetEntity flowTask = getBaseDao().getFieldSetByFilter("product_sys_flow_task", "table_name=? and record_uuid=?", new Object[]{fse.getTableName(), fse.getUUID()}, false);
|
if (flowTask != null) {
|
String taskUuid = flowTask.getString(CmnConst.UUID);
|
//获取流程意见
|
FlowDetailService flowDetailService = SpringUtil.getBean(FlowDetailService.class);
|
JSONArray opinion = flowDetailService.getHistoryInfo(taskUuid);
|
fse.setValue("~flow_opinion~", opinion);
|
}
|
}
|
break;
|
}
|
}
|
|
// 打印模板附件uuid
|
String template_uuid = printConf.getString(CmnConst.PRINT_TEMPLATE);
|
// 获取打印模板
|
File file = getTemplateFile(template_uuid);
|
// 加载参照 打印时使用显示值 而不是实际值
|
getBaseDao().loadPromptData(fse);
|
// 文件名前缀部分
|
Object tempKey = UUID.randomUUID();
|
// 替换后的word临时路径
|
String localTempPathWord = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".docx";
|
replaceWord(localTempPathWord, file.getPath(), fse);
|
file.delete();
|
|
String replaceParams = SystemParamReplace.replaceParams(Optional.ofNullable(printConf.getString(CmnConst.PRINT_FILE_NAME)).orElse(printConf.getString(CmnConst.PRINT_NAME)), fse);
|
printConf.setValue(CmnConst.PRINT_FILE_NAME, replaceParams);
|
if (isConvertPdf) {
|
try {
|
// 替换后的pdf临时路径
|
String localTempPathPdf = Global.getSystemConfig("temp.dir", "") + File.separator + "temp_print_" + tempKey + ".pdf";
|
//检查文件是否存在不存则创建
|
FileUtil.touch(localTempPathPdf);
|
// 转换pdf
|
PdfConcurrenceUtil.convertToPdf(localTempPathWord, localTempPathPdf, "docx");
|
// 删除word临时文件
|
File wordTemp = new File(localTempPathWord);
|
if (wordTemp.exists()) {
|
wordTemp.delete();
|
}
|
return localTempPathPdf;
|
} catch (Exception e) {
|
throw new BaseException(CmnCode.CONVERT_PDF_ERROR, e);
|
} finally {
|
FileUtil.del(localTempPathWord);
|
}
|
}
|
return localTempPathWord;
|
}
|
|
/**
|
* 替换word模板
|
*
|
* @param outPath 输出路径
|
* @param templatePath 模板路径
|
* @param dataFse 替换数据
|
*/
|
public static void replaceWord(String outPath, String templatePath, FieldSetEntity dataFse) {
|
JSONArray flowOpinion = (JSONArray) dataFse.getObject("~flow_opinion~");
|
if (flowOpinion != null) {
|
dataFse.remove("~flow_opinion~");
|
}
|
//转换数据为复选框
|
dataConvertCheckedData(dataFse);
|
//克隆一份values
|
Map<String, Object> cloneValues = new HashMap(dataFse.getValues());
|
//获取子表数据
|
Map<String, DataTableEntity> subDataMap = dataFse.getSubData();
|
ConfigureBuilder config = Configure.createDefault().builder();
|
config.addPlugin('@', new FlowOpinionRenderPolicy(flowOpinion));
|
config.addPlugin('$', new com.deepoove.poi.policy.DynamicTableRenderPolicy() {
|
@Override
|
public void doRender(RenderContext<Object> context) throws Exception {
|
return;
|
}
|
|
@Override
|
public void render(XWPFTable table, Object data) throws Exception {
|
return;
|
}
|
});
|
config.buildGrammerRegex("(#)?([\\w\\u4e00-\\u9fa5]+)(\\.?[\\w\\u4e00-\\u9fa5\\|]*)*(#)?");
|
TableEmptyHandler tableEmptyHandler = new TableEmptyHandler();
|
if (!CollectionUtil.isEmpty(subDataMap)) {
|
for (Map.Entry<String, DataTableEntity> entry : subDataMap.entrySet()) {
|
cloneValues.put(entry.getKey(), entry.getValue().getData().stream().map(item -> (Map<String, Object>) ((Map) item.getValues())).collect(Collectors.toList()));
|
config.bind(entry.getKey(), new DynamicTableRenderPolicy(entry.getKey()));
|
tableEmptyHandler.addTag(entry.getKey());
|
}
|
}
|
if (flowOpinion != null) {
|
if (!CollectionUtil.isEmpty(flowOpinion)) {
|
cloneValues.put("lx_flow_opinion", flowOpinion);
|
config.bind("lx_flow_opinion", new DynamicTableRenderPolicy("lx_flow_opinion"));
|
}
|
tableEmptyHandler.addTag("lx_flow_opinion");
|
}
|
config.setValidErrorHandler(tableEmptyHandler);
|
|
try {
|
//检查输出文件是否存在,不存在则创建
|
FileUtil.touch(outPath);
|
System.out.println(cloneValues);
|
XWPFTemplate.compile(templatePath, config.build()).render(cloneValues).writeToFile(outPath);
|
} catch (Exception e) {
|
e.printStackTrace();
|
FileUtil.del(outPath);
|
throw new BaseException(CmnCode.REPLACE_TEMPLATE_CONTENT_ERROR, e);
|
}
|
}
|
|
/**
|
* 获取模板附件
|
*
|
* @param templateUid 模板附件uuid
|
* @return
|
* @throws BaseException
|
*/
|
private File getTemplateFile(String templateUid) throws BaseException {
|
try {
|
return fileManagerService.getFile(templateUid);
|
} catch (BaseException e) {
|
e.printStackTrace();
|
//获取打印模板错误
|
throw new BaseException(CmnCode.GET_PRINT_TEMPLATE_FILE_FAIL.getValue(), CmnCode.GET_PRINT_TEMPLATE_FILE_FAIL.getText());
|
}
|
}
|
}
|