优化word文档的导出
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
package com.zyplayer.doc.data.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class HtmlUtils {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(HtmlUtils.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从Content-Disposition头部提取文件名
|
||||||
|
*
|
||||||
|
* @param contentDisposition Content-Disposition头部字符串
|
||||||
|
* @return 文件名,如果未找到则返回null
|
||||||
|
*/
|
||||||
|
public static String extractFilename(String contentDisposition, String defaultName) {
|
||||||
|
if (StringUtils.isBlank(contentDisposition)) {
|
||||||
|
return defaultName;
|
||||||
|
}
|
||||||
|
for (String name : contentDisposition.split(";")) {
|
||||||
|
String[] nameArr = name.trim().split("=");
|
||||||
|
if (nameArr.length >= 2 && StringUtils.startsWith(nameArr[0], "filename")) {
|
||||||
|
return StringUtils.removeEnd(StringUtils.removeStart(nameArr[1].trim(), "\""), "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import com.zyplayer.doc.wiki.controller.vo.WikiPageContentVo;
|
|||||||
import com.zyplayer.doc.wiki.controller.vo.WikiPageVo;
|
import com.zyplayer.doc.wiki.controller.vo.WikiPageVo;
|
||||||
import com.zyplayer.doc.wiki.framework.consts.SpaceType;
|
import com.zyplayer.doc.wiki.framework.consts.SpaceType;
|
||||||
import com.zyplayer.doc.wiki.service.WikiPageUploadService;
|
import com.zyplayer.doc.wiki.service.WikiPageUploadService;
|
||||||
|
import com.zyplayer.doc.wiki.service.WikiPageWebService;
|
||||||
import com.zyplayer.doc.wiki.service.common.WikiPageAuthService;
|
import com.zyplayer.doc.wiki.service.common.WikiPageAuthService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -84,7 +85,7 @@ public class WikiPageController {
|
|||||||
private final WikiPageMapper wikiPageMapper;
|
private final WikiPageMapper wikiPageMapper;
|
||||||
private final WikiPageCommentService wikiPageCommentService;
|
private final WikiPageCommentService wikiPageCommentService;
|
||||||
private final WikiPageTemplateService wikiPageTemplateService;
|
private final WikiPageTemplateService wikiPageTemplateService;
|
||||||
|
private final WikiPageWebService wikiPageWebService;
|
||||||
|
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public ResponseJson<List<WikiPageVo>> list(WikiPage wikiPage) {
|
public ResponseJson<List<WikiPageVo>> list(WikiPage wikiPage) {
|
||||||
@@ -429,60 +430,7 @@ public class WikiPageController {
|
|||||||
|
|
||||||
@PostMapping("/download")
|
@PostMapping("/download")
|
||||||
public ResponseJson<Object> download(Long pageId, String content, HttpServletRequest request, HttpServletResponse response) {
|
public ResponseJson<Object> download(Long pageId, String content, HttpServletRequest request, HttpServletResponse response) {
|
||||||
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
|
return wikiPageWebService.download(pageId, content, request, response);
|
||||||
String requestURI = request.getRequestURL().toString();
|
|
||||||
WikiPage wikiPageSel = wikiPageService.getById(pageId);
|
|
||||||
// 页面已删除
|
|
||||||
if (wikiPageSel == null || Objects.equals(wikiPageSel.getDelFlag(), 1)) {
|
|
||||||
return DocResponseJson.warn("该页面不存在或已删除!");
|
|
||||||
}
|
|
||||||
WikiSpace wikiSpaceSel = wikiSpaceService.getById(wikiPageSel.getSpaceId());
|
|
||||||
// 空间已删除
|
|
||||||
if (wikiSpaceSel == null || Objects.equals(wikiSpaceSel.getDelFlag(), 1)) {
|
|
||||||
return DocResponseJson.warn("该页面不存在或已删除!");
|
|
||||||
}
|
|
||||||
// 私人空间
|
|
||||||
if (SpaceType.isOthersPrivate(wikiSpaceSel.getType(), currentUser.getUserId(), wikiSpaceSel.getCreateUserId())) {
|
|
||||||
return DocResponseJson.warn("您没有权限查看该空间的文章详情!");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String fileName = URLEncoder.encode(wikiPageSel.getName(), "UTF-8").replaceAll("\\+", "%20");
|
|
||||||
String domainUri = requestURI.substring(0, requestURI.indexOf("/zyplayer-doc-wiki") + 1);
|
|
||||||
// 解析内容,并替换图片URL
|
|
||||||
Document document = Jsoup.parse(content);
|
|
||||||
document.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);
|
|
||||||
Elements images = document.select("img");
|
|
||||||
for (Element image : images) {
|
|
||||||
image.attr("src", domainUri + image.attr("src"));
|
|
||||||
}
|
|
||||||
content = document.html();
|
|
||||||
content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Strict//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" +
|
|
||||||
"<html lang=\"zh\">\n" +
|
|
||||||
"<head>\n" +
|
|
||||||
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" +
|
|
||||||
"<title>" + fileName + "</title>\n" +
|
|
||||||
"</head>\n" +
|
|
||||||
"<body>" +
|
|
||||||
content +
|
|
||||||
"</body>\n" +
|
|
||||||
"</html>";
|
|
||||||
// 写入流
|
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
response.setContentType("application/vnd.ms-excel");
|
|
||||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
|
|
||||||
ServletOutputStream outputStream = response.getOutputStream();
|
|
||||||
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
|
|
||||||
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
|
|
||||||
mdp.addAltChunk(AltChunkType.Xhtml, content.getBytes(StandardCharsets.UTF_8));
|
|
||||||
mdp.convertAltChunks();
|
|
||||||
XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true);
|
|
||||||
wordMLPackage.save(outputStream);
|
|
||||||
outputStream.close();
|
|
||||||
return DocResponseJson.ok();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return DocResponseJson.warn("导出失败");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/news")
|
@PostMapping("/news")
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package com.zyplayer.doc.wiki.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.io.file.FileNameUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import cn.hutool.system.SystemUtil;
|
||||||
|
import com.zyplayer.doc.core.json.DocResponseJson;
|
||||||
|
import com.zyplayer.doc.core.json.ResponseJson;
|
||||||
|
import com.zyplayer.doc.data.config.security.DocUserDetails;
|
||||||
|
import com.zyplayer.doc.data.config.security.DocUserUtil;
|
||||||
|
import com.zyplayer.doc.data.repository.manage.entity.WikiPage;
|
||||||
|
import com.zyplayer.doc.data.repository.manage.entity.WikiSpace;
|
||||||
|
import com.zyplayer.doc.data.service.manage.WikiPageService;
|
||||||
|
import com.zyplayer.doc.data.service.manage.WikiSpaceService;
|
||||||
|
import com.zyplayer.doc.data.utils.HtmlUtils;
|
||||||
|
import com.zyplayer.doc.wiki.framework.consts.SpaceType;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.docx4j.XmlUtils;
|
||||||
|
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||||
|
import org.docx4j.openpackaging.parts.WordprocessingML.AltChunkType;
|
||||||
|
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.nodes.Entities;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class WikiPageWebService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(WikiPageWebService.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
WikiPageService wikiPageService;
|
||||||
|
@Resource
|
||||||
|
WikiSpaceService wikiSpaceService;
|
||||||
|
|
||||||
|
public ResponseJson<Object> download(Long pageId, String content, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
DocUserDetails currentUser = DocUserUtil.getCurrentUser();
|
||||||
|
String requestURI = request.getRequestURL().toString();
|
||||||
|
WikiPage wikiPageSel = wikiPageService.getById(pageId);
|
||||||
|
// 页面已删除
|
||||||
|
if (wikiPageSel == null || Objects.equals(wikiPageSel.getDelFlag(), 1)) {
|
||||||
|
return DocResponseJson.warn("该页面不存在或已删除!");
|
||||||
|
}
|
||||||
|
WikiSpace wikiSpaceSel = wikiSpaceService.getById(wikiPageSel.getSpaceId());
|
||||||
|
// 空间已删除
|
||||||
|
if (wikiSpaceSel == null || Objects.equals(wikiSpaceSel.getDelFlag(), 1)) {
|
||||||
|
return DocResponseJson.warn("该页面不存在或已删除!");
|
||||||
|
}
|
||||||
|
// 私人空间
|
||||||
|
if (SpaceType.isOthersPrivate(wikiSpaceSel.getType(), currentUser.getUserId(), wikiSpaceSel.getCreateUserId())) {
|
||||||
|
return DocResponseJson.warn("您没有权限查看该空间的文章详情!");
|
||||||
|
}
|
||||||
|
String srcFilePath = new File(SystemUtil.get("java.io.tmpdir"), IdUtil.objectId()).getPath();
|
||||||
|
try {
|
||||||
|
String fileName = URLEncoder.encode(wikiPageSel.getName(), "UTF-8").replaceAll("\\+", "%20");
|
||||||
|
String domainUri = requestURI.substring(0, requestURI.indexOf("/zyplayer-doc-wiki") + 1);
|
||||||
|
// 解析内容,并替换图片URL
|
||||||
|
Document document = Jsoup.parse(content);
|
||||||
|
document.outputSettings().syntax(Document.OutputSettings.Syntax.xml).escapeMode(Entities.EscapeMode.xhtml);
|
||||||
|
Elements images = document.select("img");
|
||||||
|
for (Element image : images) {
|
||||||
|
String src = image.attr("src");
|
||||||
|
if (StringUtils.startsWith(src, "zyplayer-doc-wiki/common/file?uuid=")) {
|
||||||
|
src = domainUri + src;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
HttpResponse execute = HttpUtil.createGet(src).timeout(5000).execute();
|
||||||
|
String originFileName = HtmlUtils.extractFilename(execute.header("Content-Disposition"), "image.png");
|
||||||
|
String extName = FileNameUtil.extName(originFileName);
|
||||||
|
File srcFile = new File(srcFilePath, IdUtil.objectId() + "." + extName);
|
||||||
|
FileUtil.writeFromStream(execute.bodyStream(), srcFile);
|
||||||
|
image.attr("src", URLUtil.getURL(srcFile).toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
image.attr("src", "");
|
||||||
|
logger.error("下载图片失败,忽略异常:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Strict//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" +
|
||||||
|
"<html lang=\"zh\">\n" +
|
||||||
|
"<head>\n" +
|
||||||
|
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" +
|
||||||
|
"</head>\n" +
|
||||||
|
"<body>" + document.body().html() + "</body>\n" +
|
||||||
|
"</html>";
|
||||||
|
// 写入流
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
|
||||||
|
MainDocumentPart mdp = wordMLPackage.getMainDocumentPart();
|
||||||
|
mdp.addAltChunk(AltChunkType.Xhtml, content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
mdp.convertAltChunks();
|
||||||
|
XmlUtils.marshaltoString(wordMLPackage.getMainDocumentPart().getJaxbElement(), true, true);
|
||||||
|
wordMLPackage.save(outputStream);
|
||||||
|
outputStream.close();
|
||||||
|
return DocResponseJson.ok();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("下载文件失败", e);
|
||||||
|
} finally {
|
||||||
|
FileUtil.del(srcFilePath);
|
||||||
|
}
|
||||||
|
return DocResponseJson.warn("导出失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user