From f5d32c6114aebf3fc88b57980e0eaa5b190b53d4 Mon Sep 17 00:00:00 2001 From: sswiki <1773266885@qq.com> Date: Tue, 25 Jun 2024 19:29:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96word=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E7=9A=84=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zyplayer/doc/data/utils/HtmlUtils.java | 28 ++++ .../wiki/controller/WikiPageController.java | 58 +-------- .../doc/wiki/service/WikiPageWebService.java | 121 ++++++++++++++++++ 3 files changed, 152 insertions(+), 55 deletions(-) create mode 100644 zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/HtmlUtils.java create mode 100644 zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/service/WikiPageWebService.java diff --git a/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/HtmlUtils.java b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/HtmlUtils.java new file mode 100644 index 00000000..71a6d8a7 --- /dev/null +++ b/zyplayer-doc-data/src/main/java/com/zyplayer/doc/data/utils/HtmlUtils.java @@ -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; + } +} diff --git a/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/controller/WikiPageController.java b/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/controller/WikiPageController.java index 1146978d..12e7011a 100644 --- a/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/controller/WikiPageController.java +++ b/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/controller/WikiPageController.java @@ -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.framework.consts.SpaceType; import com.zyplayer.doc.wiki.service.WikiPageUploadService; +import com.zyplayer.doc.wiki.service.WikiPageWebService; import com.zyplayer.doc.wiki.service.common.WikiPageAuthService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -84,7 +85,7 @@ public class WikiPageController { private final WikiPageMapper wikiPageMapper; private final WikiPageCommentService wikiPageCommentService; private final WikiPageTemplateService wikiPageTemplateService; - + private final WikiPageWebService wikiPageWebService; @PostMapping("/list") public ResponseJson> list(WikiPage wikiPage) { @@ -429,60 +430,7 @@ public class WikiPageController { @PostMapping("/download") public ResponseJson 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("您没有权限查看该空间的文章详情!"); - } - 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 = "\n" + - "\n" + - "\n" + - "\n" + - "" + fileName + "\n" + - "\n" + - "" + - content + - "\n" + - ""; - // 写入流 - 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("导出失败"); + return wikiPageWebService.download(pageId, content, request, response); } @PostMapping("/news") diff --git a/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/service/WikiPageWebService.java b/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/service/WikiPageWebService.java new file mode 100644 index 00000000..e2ec3c65 --- /dev/null +++ b/zyplayer-doc-wiki/src/main/java/com/zyplayer/doc/wiki/service/WikiPageWebService.java @@ -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 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 = "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "" + document.body().html() + "\n" + + ""; + // 写入流 + 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("导出失败"); + } +}