273 lines
10 KiB
Java
273 lines
10 KiB
Java
package cn.keking.service;
|
||
|
||
import cn.afterturn.easypoi.word.WordExportUtil;
|
||
import cn.keking.config.ConfigConstants;
|
||
import cn.keking.config.KkfileConfig;
|
||
import cn.keking.exception.KkFileException;
|
||
import cn.keking.service.impl.OtherFilePreviewImpl;
|
||
import cn.keking.utils.Consts;
|
||
import cn.keking.utils.WebUtils;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.apache.commons.codec.binary.Base64;
|
||
import org.apache.commons.collections4.MapUtils;
|
||
import org.apache.commons.io.FilenameUtils;
|
||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||
import org.apache.poi.xwpf.usermodel.XWPFTable;
|
||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
|
||
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
|
||
import org.springframework.core.io.ClassPathResource;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.util.StreamUtils;
|
||
import org.springframework.web.multipart.MultipartFile;
|
||
import org.springframework.web.util.HtmlUtils;
|
||
|
||
import javax.annotation.Resource;
|
||
import java.io.*;
|
||
import java.net.URLEncoder;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.util.Arrays;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import java.util.UUID;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* @author Hikaru
|
||
*/
|
||
@Service
|
||
@Slf4j
|
||
public class ContractService {
|
||
|
||
|
||
/**
|
||
* 配置常量
|
||
*/
|
||
@Resource
|
||
private ConfigConstants configConstants;
|
||
|
||
|
||
/**
|
||
* kkfile配置
|
||
*/
|
||
@Resource
|
||
private KkfileConfig kkfileConfig;
|
||
|
||
|
||
private final OfficeToPdfService officeToPdfService;
|
||
|
||
|
||
public ContractService(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
|
||
this.officeToPdfService = officeToPdfService;
|
||
|
||
}
|
||
|
||
/**
|
||
* 上传
|
||
*
|
||
* @param templateName 模板名
|
||
* @param multipartFile 模板文件
|
||
* @return 路径
|
||
* @throws IOException 异常
|
||
*/
|
||
public String upload(String templateName, MultipartFile multipartFile) {
|
||
if (multipartFile == null) {
|
||
throw new KkFileException("上传文件不能为空");
|
||
}
|
||
// 获取文件名
|
||
String fileName = multipartFile.getOriginalFilename();
|
||
fileName = HtmlUtils.htmlEscape(fileName, StandardCharsets.UTF_8.name());
|
||
|
||
//获取文件大小 ,文件大小不超过10m
|
||
long size = multipartFile.getSize();
|
||
if (size > kkfileConfig.getTemplateMaxSize()) {
|
||
long currentSizeM = kkfileConfig.getTemplateMaxSize() / 1024 / 1024;
|
||
throw new KkFileException("上传的文件限制大小为" + currentSizeM + "m");
|
||
}
|
||
//获取文件扩展名,目前模板只支持docx
|
||
String extensionName = getExtension(fileName);
|
||
if (!kkfileConfig.getAllowUploadType().contains(extensionName)) {
|
||
throw new KkFileException("不支持的文件类型【" + extensionName + "】");
|
||
}
|
||
//目录不存在重新生成目录
|
||
File outFile = new File(Consts.getTemplatePath());
|
||
|
||
if (!outFile.exists() && !outFile.mkdirs()) {
|
||
log.error("创建文件夹【{}】失败,请检查目录权限!", Consts.getTemplatePath());
|
||
}
|
||
String newFileName = templateName + "." + extensionName;
|
||
String url = this.configConstants.getBaseUrl() + "/" + Consts.TEMPLATE_PATH_NAME + "/" + templateName + "." + extensionName;
|
||
String filePath = Consts.getTemplatePath() + File.separator + newFileName;
|
||
log.info("上传文件:{}", filePath);
|
||
try (InputStream in = multipartFile.getInputStream(); OutputStream out = new FileOutputStream(filePath)) {
|
||
StreamUtils.copy(in, out);
|
||
} catch (Exception e) {
|
||
log.error("文件拷贝失败:", e);
|
||
throw new KkFileException("文件拷贝失败");
|
||
}
|
||
return url;
|
||
}
|
||
|
||
/**
|
||
* 查询所有模板url
|
||
*
|
||
* @param templateNames 模板名称
|
||
* @return 模板url
|
||
*/
|
||
public List<String> listTemplate(List<String> templateNames) {
|
||
return templateNames.stream().map(s -> downUrl(s, "docx")).collect(Collectors.toList());
|
||
}
|
||
|
||
private String downUrl(String templateName, String extensionName) {
|
||
return this.configConstants.getBaseUrl() + "/" + Consts.TEMPLATE_PATH_NAME + "/" + templateName + "." + extensionName;
|
||
}
|
||
|
||
/**
|
||
* 根据模板生成内容
|
||
*
|
||
* @param templateName 模板名称
|
||
* @param dataMap 数据
|
||
* @return 生成得预览路径
|
||
* @throws Exception 异常
|
||
*/
|
||
public String gen(String templateName, Map<String, Object> dataMap) throws Exception {
|
||
OutputStream os = null;
|
||
try {
|
||
File outFile = new File(Consts.uploadAbsDir());
|
||
if (!outFile.exists()) {
|
||
outFile.mkdirs();
|
||
}
|
||
String templatePath = Consts.getTemplatePath();
|
||
String abTemplatePath = templatePath + File.separator + templateName + ".docx";
|
||
//判断模板是否存在
|
||
File file = new File(abTemplatePath);
|
||
if (!file.exists()) {
|
||
throw new KkFileException("请先上传模板!");
|
||
}
|
||
XWPFDocument xwpfDocument = WordExportUtil.exportWord07(abTemplatePath, dataMap);
|
||
//如果是签收单,则需要合并单元格
|
||
if (Consts.RECEIPT_FORM.equals(templateName)){
|
||
List<Object> invoiceResList = (List<Object>) MapUtils.getObject(dataMap, "invoiceResList");
|
||
mergeCell(xwpfDocument,0,7,7+invoiceResList.size()-1,Arrays.asList(5,6));
|
||
}
|
||
if (Consts.RECEIPT_INVOICE.equals(templateName)){
|
||
List<Object> invoiceResList = (List<Object>) MapUtils.getObject(dataMap, "invoiceResList");
|
||
mergeCell(xwpfDocument,0,7,7+invoiceResList.size()-1,Arrays.asList(5,6));
|
||
}
|
||
|
||
String docxFile = "/"+ UUID.randomUUID().toString().replace("-", "") + ".docx";
|
||
//通过填参 生产文件 并放到 upload 文件夹中
|
||
String path = Consts.uploadAbsDir();
|
||
String pathFile = path + docxFile;
|
||
os = new FileOutputStream(pathFile);
|
||
xwpfDocument.write(os);
|
||
log.info("文件路径:{}", kkfileConfig.getLocalfileUrl() + File.separator + Consts.UPLOAD_PATH_NAME + docxFile);
|
||
String previewUrl = WebUtils.getBaseUrl() + "onlinePreview?url=" +
|
||
URLEncoder.encode(Base64.encodeBase64String((kkfileConfig.getLocalfileUrl() + File.separator + Consts.UPLOAD_PATH_NAME + docxFile).getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8.name());
|
||
return previewUrl;
|
||
} finally {
|
||
if (os != null) {
|
||
os.close();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 合并单元格
|
||
* @param xwpfDocument 文档对象
|
||
* @param tableIndex 表格索引
|
||
* @param beginRowIndex 开始行索引
|
||
* @param endRowIndex 结束行索引
|
||
* @param collIndexs 合并列索引
|
||
*/
|
||
public static void mergeCell(XWPFDocument xwpfDocument,int tableIndex,int beginRowIndex,int endRowIndex,List<Integer> collIndexs){
|
||
//获取文档中指定的表格对象
|
||
XWPFTable table = xwpfDocument.getTableArray(tableIndex);
|
||
if (beginRowIndex == endRowIndex || beginRowIndex > endRowIndex){
|
||
return;
|
||
}
|
||
//合并单元格的第一个单元格
|
||
CTVMerge startMerge = CTVMerge.Factory.newInstance();
|
||
startMerge.setVal(STMerge.RESTART);
|
||
//合并行单元格之后的单元格
|
||
CTVMerge endMerge = CTVMerge.Factory.newInstance();
|
||
endMerge.setVal(STMerge.CONTINUE);
|
||
|
||
for (Integer collIndex : collIndexs){
|
||
table.getRow(beginRowIndex).getCell(collIndex).getCTTc().getTcPr().setVMerge(startMerge);
|
||
for (int i = beginRowIndex + 1; i <= endRowIndex; i++){
|
||
table.getRow(i).getCell(collIndex).getCTTc().getTcPr().setVMerge(endMerge);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取扩展名
|
||
*
|
||
* @param fileName 文件名
|
||
* @return 扩展名
|
||
*/
|
||
public static final String getExtension(String fileName) {
|
||
return FilenameUtils.getExtension(fileName);
|
||
}
|
||
|
||
/**
|
||
* 获取绝对路径
|
||
*
|
||
* @param uploadDir 上传得目录
|
||
* @param fileName 文件
|
||
* @return 获取文件绝对路径
|
||
* @throws IOException 异常
|
||
*/
|
||
public File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
|
||
File desc = new File(uploadDir + File.separator + fileName);
|
||
|
||
if (!desc.exists()) {
|
||
if (!desc.getParentFile().exists()) {
|
||
desc.getParentFile().mkdirs();
|
||
}
|
||
}
|
||
return desc;
|
||
}
|
||
|
||
|
||
public File download(String templateName, Map<String, Object> dataMap) throws Exception {
|
||
OutputStream os = null;
|
||
try {
|
||
File outFile = new File(Consts.uploadAbsDir());
|
||
if (!outFile.exists()) {
|
||
outFile.mkdirs();
|
||
}
|
||
String templatePath = Consts.getTemplatePath();
|
||
String abTemplatePath = templatePath + File.separator + templateName + ".docx";
|
||
//判断模板是否存在
|
||
File file = new File(abTemplatePath);
|
||
if(!file.exists()){
|
||
throw new KkFileException("请先上传模板!");
|
||
}
|
||
XWPFDocument xwpfDocument = WordExportUtil.exportWord07(abTemplatePath, dataMap);
|
||
//如果是签收单,则需要合并单元格
|
||
if (Consts.RECEIPT_FORM.equals(templateName)){
|
||
List<Object> invoiceResList = (List<Object>) MapUtils.getObject(dataMap, "invoiceResList");
|
||
mergeCell(xwpfDocument,0,6,6+invoiceResList.size()-1,Arrays.asList(4,5));
|
||
}
|
||
String docxFile = "/"+ UUID.randomUUID().toString().replace("-", "") + ".docx";
|
||
String pdfName = "/"+ UUID.randomUUID().toString().replace("-", "") + ".pdf";
|
||
//通过填参 生产文件 并放到 upload 文件夹中
|
||
String path = Consts.uploadAbsDir();
|
||
String pathFile = path + docxFile;
|
||
os = new FileOutputStream(pathFile);
|
||
xwpfDocument.write(os);
|
||
String outFilePath = Consts.uploadAbsDir()+ File.separator+ pdfName;
|
||
officeToPdfService.openOfficeToPDF(pathFile, outFilePath);
|
||
//返回pdf
|
||
return new File(outFilePath);
|
||
//返回word
|
||
//return new File(pathFile);
|
||
} finally {
|
||
if (os != null) {
|
||
os.close();
|
||
}
|
||
}
|
||
}
|
||
}
|