{"id":6595,"date":"2025-09-29T11:41:27","date_gmt":"2025-09-29T03:41:27","guid":{"rendered":"https:\/\/xinchewhd.com.cn\/?p=6595"},"modified":"2025-09-29T11:41:42","modified_gmt":"2025-09-29T03:41:42","slug":"springboot-%e5%ae%9e%e7%8e%b0%e5%a4%9a%e7%a7%8d%e6%9d%a5%e6%ba%90%e7%9a%84-zip-%e5%a4%9a%e5%b1%82%e7%9b%ae%e5%bd%95%e6%89%93%e5%8c%85%e4%b8%8b%e8%bd%bd%ef%bc%88%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6amp","status":"publish","type":"post","link":"https:\/\/xinchewhd.com.cn\/index.php\/spring-boot\/springboot-%e5%ae%9e%e7%8e%b0%e5%a4%9a%e7%a7%8d%e6%9d%a5%e6%ba%90%e7%9a%84-zip-%e5%a4%9a%e5%b1%82%e7%9b%ae%e5%bd%95%e6%89%93%e5%8c%85%e4%b8%8b%e8%bd%bd%ef%bc%88%e6%9c%ac%e5%9c%b0%e6%96%87%e4%bb%b6amp\/","title":{"rendered":"SpringBoot \u5b9e\u73b0\u591a\u79cd\u6765\u6e90\u7684 Zip \u591a\u5c42\u76ee\u5f55\u6253\u5305\u4e0b\u8f7d\uff08\u672c\u5730\u6587\u4ef6&amp;HTTP\u6df7\u5408\uff09"},"content":{"rendered":"\n<p>\u9700\u8981\u5c06\u4e00\u6279\u6587\u4ef6\uff08\u53ef\u80fd\u5206\u5e03\u5728\u4e0d\u540c\u76ee\u5f55\u3001\u4e0d\u540c\u6765\u6e90\uff09\u6253\u5305\u6210Zip\u683c\u5f0f\uff0c\u6309\u76ee\u5f55\u7ed3\u6784\u5bfc\u51fa\u7ed9\u7528\u6237\u4e0b\u8f7d\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. \u6838\u5fc3\u601d\u8def<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2022 \u652f\u6301\u5c06\u672c\u5730\u670d\u52a1\u5668\u4e0a\u7684\u6587\u4ef6\uff08\u5982<code>\/data\/upload\/xxx.jpg<\/code>\uff09\u6253\u5305\u8fdbZip\uff0c\u4fdd\u6301\u539f\u6709\u76ee\u5f55\u7ed3\u6784\u3002<\/li>\n\n\n\n<li>\u2022 \u652f\u6301\u901a\u8fc7HTTP\u4e0b\u8f7d\u8fdc\u7a0b\u6587\u4ef6\u5199\u5165Zip\u3002<\/li>\n\n\n\n<li>\u2022 \u6240\u6709\u5199\u5165Zip\u7684\u76ee\u5f55\u540d\u3001\u6587\u4ef6\u540d\u5747\u9700\u5b89\u5168\u5904\u7406\u3002<\/li>\n\n\n\n<li>\u2022 \u7edf\u4e00\u4f7f\u7528\u6d41\u5f0fIO\uff0c\u9002\u5408\u5927\u6587\u4ef6\/\u5927\u91cf\u6587\u4ef6\u5bfc\u51fa\uff0c\u9632\u6b62\u5185\u5b58\u6ea2\u51fa\u3002<\/li>\n\n\n\n<li>\u2022 \u76ee\u5f55\u4e0b\u65e0\u6587\u4ef6\u65f6\u5199\u5165<code>empty.txt<\/code>\u6807\u8bc6\u3002<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. \u4ee3\u7801\u5b9e\u73b0<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">2.1 \u5de5\u5177\u7c7b\uff1a\u672c\u5730&amp;HTTP\u4e24\u79cd\u65b9\u5f0f\u5199\u5165Zip<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>package&nbsp;com.example.xiaoshitou.utils;<br><br>import&nbsp;org.apache.commons.compress.archivers.zip.ZipArchiveEntry;<br>import&nbsp;org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;<br>import&nbsp;org.springframework.util.StreamUtils;<br>import&nbsp;org.springframework.util.StringUtils;<br><br>import&nbsp;javax.servlet.http.HttpServletRequest;<br>import&nbsp;javax.servlet.http.HttpServletResponse;<br>import&nbsp;java.io.*;<br>import&nbsp;java.net.URL;<br>import&nbsp;java.net.URLConnection;<br>import&nbsp;java.net.URLEncoder;<br>import&nbsp;java.nio.charset.StandardCharsets;<br>import&nbsp;java.time.LocalDate;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:34<br>&nbsp;**\/<br>public&nbsp;class&nbsp;ZipDownloadUtils&nbsp;{<br><br><br>&nbsp; &nbsp; private&nbsp;static&nbsp;final<em>&nbsp;String<\/em>&nbsp;SUFFIX_ZIP&nbsp;=&nbsp;\".zip\";<br>&nbsp; &nbsp; private&nbsp;static&nbsp;final<em>&nbsp;String<\/em>&nbsp;UNNAMED&nbsp;=&nbsp;\"\u672a\u547d\u540d\";<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u5b89\u5168\u5904\u7406\u6587\u4ef6\u540d\/\u76ee\u5f55\u540d<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;name<br>&nbsp; &nbsp; &nbsp;*&nbsp;@return<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;String&nbsp;safeName(String name)&nbsp;{<br>&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(name ==&nbsp;null)&nbsp;return&nbsp;\"null\";<br>&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;name.replaceAll(\"&#91;\\\\\\\\\/:*?\\\"&lt;&gt;|]\",&nbsp;\"_\");<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* HTTP\u4e0b\u8f7d\u5199\u5165Zip<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipOut<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;fileUrl<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipEntryName<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;IOException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;void&nbsp;writeHttpFileToZip(ZipArchiveOutputStream zipOut, String fileUrl, String zipEntryName)&nbsp;throws&nbsp;IOException {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; ZipArchiveEntry<\/em>&nbsp;entry&nbsp;=&nbsp;new&nbsp;ZipArchiveEntry(zipEntryName);<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.putArchiveEntry(entry);<br>&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp;(<em>InputStream<\/em>&nbsp;in&nbsp;=&nbsp;openHttpStream(fileUrl,&nbsp;8000,&nbsp;20000)) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte<\/em>&#91;] buffer =&nbsp;new&nbsp;byte&#91;4096];<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int<\/em>&nbsp;len;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while&nbsp;((len = in.read(buffer)) != -1) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.write(buffer,&nbsp;0, len);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exception e) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.write((\"\u4e0b\u8f7d\u5931\u8d25: \"&nbsp;+ fileUrl).getBytes(StandardCharsets.UTF_8));<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.closeArchiveEntry();<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u672c\u5730\u6587\u4ef6\u5199\u5165Zip<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipOut<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;localFilePath<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipEntryName<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;IOException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;void&nbsp;writeLocalFileToZip(ZipArchiveOutputStream zipOut, String localFilePath, String zipEntryName)&nbsp;throws&nbsp;IOException {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; File<\/em>&nbsp;file&nbsp;=&nbsp;new&nbsp;File(localFilePath);<br>&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(!file.exists() || file.isDirectory()) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; writeTextToZip(zipOut, zipEntryName +&nbsp;\"_empty.txt\",&nbsp;\"\u6587\u4ef6\u4e0d\u5b58\u5728\u6216\u662f\u76ee\u5f55: \"&nbsp;+ localFilePath);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<em><br><br>&nbsp; &nbsp; &nbsp; &nbsp; ZipArchiveEntry<\/em>&nbsp;entry&nbsp;=&nbsp;new&nbsp;ZipArchiveEntry(zipEntryName);<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.putArchiveEntry(entry);<br>&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp;(<em>InputStream<\/em>&nbsp;fis&nbsp;=&nbsp;new&nbsp;FileInputStream(file)) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; byte<\/em>&#91;] buffer =&nbsp;new&nbsp;byte&#91;4096];<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int<\/em>&nbsp;len;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while&nbsp;((len = fis.read(buffer)) != -1) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.write(buffer,&nbsp;0, len);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.closeArchiveEntry();<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u5199\u5165\u6587\u672c\u6587\u4ef6\u5230Zip\uff08\u5982empty.txt\uff09<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipOut<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;zipEntryName<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;content<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;IOException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;void&nbsp;writeTextToZip(ZipArchiveOutputStream zipOut, String zipEntryName, String content)&nbsp;throws&nbsp;IOException {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; ZipArchiveEntry<\/em>&nbsp;entry&nbsp;=&nbsp;new&nbsp;ZipArchiveEntry(zipEntryName);<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.putArchiveEntry(entry);<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.write(content.getBytes(StandardCharsets.UTF_8));<br>&nbsp; &nbsp; &nbsp; &nbsp; zipOut.closeArchiveEntry();<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u6253\u5f00HTTP\u6587\u4ef6\u6d41<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;url<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;connectTimeout<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;readTimeout<br>&nbsp; &nbsp; &nbsp;*&nbsp;@return<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;IOException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;InputStream&nbsp;openHttpStream(String url,<em>&nbsp;int<\/em>&nbsp;connectTimeout,<em>&nbsp;int<\/em>&nbsp;readTimeout)&nbsp;throws&nbsp;IOException {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; URLConnection<\/em>&nbsp;conn&nbsp;=&nbsp;new&nbsp;URL(url).openConnection();<br>&nbsp; &nbsp; &nbsp; &nbsp; conn.setConnectTimeout(connectTimeout);<br>&nbsp; &nbsp; &nbsp; &nbsp; conn.setReadTimeout(readTimeout);<br>&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;conn.getInputStream();<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u4eceurl\u83b7\u53d6\u6587\u4ef6\u540d<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;url<br>&nbsp; &nbsp; &nbsp;*&nbsp;@return<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;IOException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;String&nbsp;getFileName(String url)&nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;url.substring(url.lastIndexOf('\/')+1);<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u8bbe\u7f6eresponse<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;request<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;response<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;fileName<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;UnsupportedEncodingException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;void&nbsp;setResponse(HttpServletRequest request, HttpServletResponse response, String fileName)&nbsp;throws&nbsp;UnsupportedEncodingException {<br>&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(!StringUtils.hasText(fileName)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileName = LocalDate.now() + UNNAMED;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(!fileName.endsWith(SUFFIX_ZIP)) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileName = fileName + SUFFIX_ZIP;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; response.setHeader(\"Connection\",&nbsp;\"close\");<br>&nbsp; &nbsp; &nbsp; &nbsp; response.setHeader(\"Content-Type\",&nbsp;\"application\/octet-stream;charset=UTF-8\");<em><br>&nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;filename&nbsp;=&nbsp;encodeFileName(request, fileName);<br>&nbsp; &nbsp; &nbsp; &nbsp; response.setHeader(\"Content-Disposition\",&nbsp;\"attachment;filename=\"&nbsp;+ filename);<br>&nbsp; &nbsp; }<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u6587\u4ef6\u540d\u5728\u4e0d\u540c\u6d4f\u89c8\u5668\u517c\u5bb9\u5904\u7406<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;request \u8bf7\u6c42\u4fe1\u606f<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;fileName \u6587\u4ef6\u540d<br>&nbsp; &nbsp; &nbsp;*&nbsp;@return<br>&nbsp; &nbsp; &nbsp;*&nbsp;@throws&nbsp;UnsupportedEncodingException<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; public&nbsp;static&nbsp;String&nbsp;encodeFileName(HttpServletRequest request, String fileName)&nbsp;throws&nbsp;UnsupportedEncodingException {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;userAgent&nbsp;=&nbsp;request.getHeader(\"USER-AGENT\");<br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ \u706b\u72d0\u6d4f\u89c8\u5668<br>&nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(userAgent.contains(\"Firefox\") || userAgent.contains(\"firefox\")) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileName =&nbsp;new&nbsp;String(fileName.getBytes(),&nbsp;\"ISO8859-1\");<br>&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;{<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ \u5176\u4ed6\u6d4f\u89c8\u5668<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileName = URLEncoder.encode(fileName,&nbsp;\"UTF-8\");<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp;fileName;<br>&nbsp; &nbsp; }<br>}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">2.2 Controller \u793a\u4f8b\uff1a\u6309\u672c\u5730\u76ee\u5f55\u7ed3\u6784\u6279\u91cf\u5bfc\u51fa<\/h4>\n\n\n\n<p>\u5047\u8bbe\u6709\u5982\u4e0b\u5bfc\u51fa\u7ed3\u6784\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u7528\u6237A\/<br>&nbsp; &nbsp; \u8eab\u4efd\u8bc1\/<br>&nbsp; &nbsp; &nbsp; &nbsp; xxx.jpg (\u672c\u5730)<br>&nbsp; &nbsp; &nbsp; &nbsp; xxx.png (\u672c\u5730)<br>&nbsp; &nbsp; \u5934\u50cf\/<br>&nbsp; &nbsp; &nbsp; &nbsp; xxx.jpg (HTTP)<br>\u7528\u6237B\/<br>&nbsp; &nbsp; empty.txt<\/code><\/pre>\n\n\n\n<p>\u6a21\u62df\u6570\u636e\u7ed3\u6784\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2022 zipGroup:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>import&nbsp;lombok.AllArgsConstructor;<br>import&nbsp;lombok.Data;<br><br>import&nbsp;java.util.List;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:36<br>&nbsp;**\/<br>@Data<br>@AllArgsConstructor<br>public&nbsp;class&nbsp;ZipGroup&nbsp;{<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u7528\u6237\u540d\u3001\u6587\u4ef6\u540d<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; private&nbsp;String dirName;<br>&nbsp; &nbsp; private&nbsp;List&lt;ZipSubDir&gt; subDirs;<br>}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2022 zipGroupDir:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>import&nbsp;lombok.AllArgsConstructor;<br>import&nbsp;lombok.Data;<br>import&nbsp;lombok.NoArgsConstructor;<br><br>import&nbsp;java.util.List;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:37<br>&nbsp;**\/<br>@Data<br>@AllArgsConstructor<br>@NoArgsConstructor<br>public&nbsp;class&nbsp;ZipSubDir&nbsp;{<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u5b50\u76ee\u5f55<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; private&nbsp;String subDirName;<br>&nbsp; &nbsp; private&nbsp;List&lt;ZipFileRef&gt; fileRefs;<br>}<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2022 ZipFileRef:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>import&nbsp;lombok.AllArgsConstructor;<br>import&nbsp;lombok.Data;<br>import&nbsp;lombok.NoArgsConstructor;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:38<br>&nbsp;**\/<br>@Data<br>@AllArgsConstructor<br>@NoArgsConstructor<br>public&nbsp;class&nbsp;ZipFileRef&nbsp;{<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u6587\u4ef6\u540d<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; private&nbsp;String name;<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* \u672c\u5730\u8def\u5f84<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; private&nbsp;String localPath;<br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* http\u8def\u5f84<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; private&nbsp;String httpUrl;<br>}<\/code><\/pre>\n\n\n\n<p>Controller\u901a\u7528\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package&nbsp;com.example.xiaoshitou.controller;<br><br>import&nbsp;com.example.xiaoshitou.service.ZipService;<br>import&nbsp;lombok.AllArgsConstructor;<br>import&nbsp;org.springframework.web.bind.annotation.GetMapping;<br>import&nbsp;org.springframework.web.bind.annotation.RequestMapping;<br>import&nbsp;org.springframework.web.bind.annotation.RestController;<br><br>import&nbsp;javax.servlet.http.HttpServletRequest;<br>import&nbsp;javax.servlet.http.HttpServletResponse;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:50<br>&nbsp;**\/<br>@RestController<br>@RequestMapping(\"\/zip\")<br>@AllArgsConstructor<br>public&nbsp;class&nbsp;ZipController&nbsp;{<br><br>&nbsp; &nbsp; private&nbsp;final&nbsp;ZipService zipService;<br><br>&nbsp; &nbsp; \/**<br>&nbsp; &nbsp; &nbsp;* &nbsp;\u6253\u5305\u4e0b\u8f7d<br>&nbsp; &nbsp; &nbsp;*&nbsp;@param&nbsp;response<br>&nbsp; &nbsp; &nbsp;*\/<br>&nbsp; &nbsp; @GetMapping(\"\/download\")<br>&nbsp; &nbsp; public&nbsp;void&nbsp;downloadZip(HttpServletRequest request, HttpServletResponse response)&nbsp;{<br>&nbsp; &nbsp; &nbsp; &nbsp; zipService.downloadZip(request,response);<br>&nbsp; &nbsp; }<br>}<\/code><\/pre>\n\n\n\n<p>Service \u5c42\u4ee3\u7801\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package&nbsp;com.example.xiaoshitou.service.impl;<br><br>import&nbsp;com.example.xiaoshitou.entity.ZipFileRef;<br>import&nbsp;com.example.xiaoshitou.entity.ZipGroup;<br>import&nbsp;com.example.xiaoshitou.entity.ZipSubDir;<br>import&nbsp;com.example.xiaoshitou.service.ZipService;<br>import&nbsp;com.example.xiaoshitou.utils.ZipDownloadUtils;<br>import&nbsp;lombok.extern.slf4j.Slf4j;<br>import&nbsp;org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;<br>import&nbsp;org.springframework.stereotype.Service;<br><br>import&nbsp;javax.servlet.http.HttpServletRequest;<br>import&nbsp;javax.servlet.http.HttpServletResponse;<br>import&nbsp;java.io.BufferedOutputStream;<br>import&nbsp;java.util.Arrays;<br>import&nbsp;java.util.Collections;<br>import&nbsp;java.util.List;<br>import&nbsp;java.util.zip.Deflater;<br><br>\/***<br>&nbsp;*&nbsp;@title<br>&nbsp;*&nbsp;@author&nbsp;shijiangyong<br>&nbsp;*&nbsp;@date&nbsp;2025\/4\/28 16:43<br>&nbsp;**\/<br>@Slf4j<br>@Service<br>public&nbsp;class&nbsp;ZipServiceImpl&nbsp;implements&nbsp;ZipService&nbsp;{<br>&nbsp; &nbsp; @Override<br>&nbsp; &nbsp; public&nbsp;void&nbsp;downloadZip(HttpServletRequest request, HttpServletResponse response)&nbsp;{<br>&nbsp; &nbsp; &nbsp; &nbsp; \/\/ ==== \u793a\u4f8b\u6570\u636e ====<br>&nbsp; &nbsp; &nbsp; &nbsp; List&lt;ZipGroup&gt; data = Arrays.asList(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipGroup(\"\u5c0f\u660e\", Arrays.asList(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipSubDir(\"\u8eab\u4efd\u8bc1(\u672c\u5730)\", Arrays.asList(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipFileRef(\"\",\"E:\/software\/test\/1.png\",\"\"),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipFileRef(\"\",\"E:\/software\/test\/2.png\",\"\")<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipSubDir(\"\u5934\u50cf(http)\", Arrays.asList(<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ \u767e\u5ea6\u968f\u4fbf\u627e\u7684<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipFileRef(\"\",\"\",\"https:\/\/pic4.zhimg.com\/v2-4d9e9f936b9968f53be22b594aafa74f_r.jpg\")<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ))<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new&nbsp;ZipGroup(\"\u5c0f\u654f\", Collections.emptyList())<br>&nbsp; &nbsp; &nbsp; &nbsp; );<br><br>&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp;(<em>BufferedOutputStream<\/em>&nbsp;bos&nbsp;=&nbsp;new&nbsp;BufferedOutputStream(response.getOutputStream());<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ZipArchiveOutputStream<\/em>&nbsp;zipOut&nbsp;=&nbsp;new&nbsp;ZipArchiveOutputStream(bos)) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;fileName&nbsp;=&nbsp;\"\u8d44\u6599\u6253\u5305_\"&nbsp;+ System.currentTimeMillis() +&nbsp;\".zip\";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ZipDownloadUtils.setResponse(request,response, fileName);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ \u5feb\u901f\u538b\u7f29<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.setLevel(Deflater.BEST_SPEED);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for&nbsp;(ZipGroup group : data) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;groupDir&nbsp;=&nbsp;ZipDownloadUtils.safeName(group.getDirName()) +&nbsp;\"\/\";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;ZipSubDir&gt; subDirs = group.getSubDirs();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(subDirs ==&nbsp;null&nbsp;|| subDirs.isEmpty()) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupDir = ZipDownloadUtils.safeName(group.getDirName()) +&nbsp;\"(\u65e0\u8d44\u6599)\/\";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ZipDownloadUtils.writeTextToZip(zipOut, groupDir +&nbsp;\"empty.txt\",&nbsp;\"\u8be5\u76ee\u5f55\u65e0\u4efb\u4f55\u8d44\u6599\");<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for&nbsp;(ZipSubDir subDir : subDirs) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;subDirPath&nbsp;=&nbsp;groupDir + ZipDownloadUtils.safeName(subDir.getSubDirName()) +&nbsp;\"\/\";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List&lt;ZipFileRef&gt; fileRefs = subDir.getFileRefs();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(fileRefs ==&nbsp;null&nbsp;|| fileRefs.isEmpty()) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subDirPath = groupDir + ZipDownloadUtils.safeName(subDir.getSubDirName()) +&nbsp;\"(empty)\/\";<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ZipDownloadUtils.writeTextToZip(zipOut, subDirPath +&nbsp;\"empty.txt\",&nbsp;\"\u8be5\u7c7b\u578b\u65e0\u8d44\u6599\");<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for&nbsp;(ZipFileRef fileRef : fileRefs) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if&nbsp;(fileRef.getLocalPath() !=&nbsp;null&nbsp;&amp;&amp; !fileRef.getLocalPath().isEmpty()) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;name&nbsp;=&nbsp;ZipDownloadUtils.getFileName(fileRef.getLocalPath());<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileRef.setName(name);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ZipDownloadUtils.writeLocalFileToZip(zipOut, fileRef.getLocalPath(), subDirPath + ZipDownloadUtils.safeName(fileRef.getName()));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;else&nbsp;if&nbsp;(fileRef.getHttpUrl() !=&nbsp;null&nbsp;&amp;&amp; !fileRef.getHttpUrl().isEmpty()) {<em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String<\/em>&nbsp;name&nbsp;=&nbsp;ZipDownloadUtils.getFileName(fileRef.getHttpUrl());<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fileRef.setName(name);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ZipDownloadUtils.writeHttpFileToZip(zipOut, fileRef.getHttpUrl(), subDirPath + ZipDownloadUtils.safeName(fileRef.getName()));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.finish();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; zipOut.flush();<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response.flushBuffer();<br>&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exception e) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw&nbsp;new&nbsp;RuntimeException(\"\u6253\u5305\u4e0b\u8f7d\u5931\u8d25\", e);<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; }<br>}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">3. \u5e38\u89c1\u95ee\u9898\u53ca\u5b89\u5168\u5efa\u8bae<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2022\u00a0<strong>\u9632\u8def\u5f84\u7a7f\u8d8a\uff08Zip Slip\uff09\uff1a<\/strong>\u00a0\u6240\u6709\u76ee\u5f55\/\u6587\u4ef6\u540d\u52a1\u5fc5\u7528safeName\u8fc7\u6ee4\u7279\u6b8a\u5b57\u7b26<\/li>\n\n\n\n<li>\u2022\u00a0<strong>\u5927\u6587\u4ef6\/\u5927\u6279\u91cf\uff1a<\/strong>\u00a0\u5efa\u8bae\u5206\u9875\u3001\u5206\u6279\u5904\u7406<\/li>\n\n\n\n<li>\u2022\u00a0<strong>\u7a7a\u76ee\u5f55\u5199\u5165\uff1a<\/strong>\u00a0\u7edf\u4e00\u5199empty.txt\u6807\u8bc6\u7a7a\u76ee\u5f55<\/li>\n\n\n\n<li>\u2022\u00a0<strong>\u672c\u5730\u6587\u4ef6\u4e0d\u5b58\u5728\uff1a<\/strong>\u00a0Zip\u5305\u5185\u5199\u5165\u63d0\u793a\u4fe1\u606f<\/li>\n\n\n\n<li>\u2022\u00a0<strong>HTTP\u4e0b\u8f7d\u5931\u8d25\uff1a<\/strong>\u00a0Zip\u5305\u5185\u5199\u5165\u201c\u4e0b\u8f7d\u5931\u8d25\u201d\u63d0\u793a<\/li>\n\n\n\n<li>\u2022\u00a0<strong>\u907f\u514d\u6cc4\u9732\u670d\u52a1\u5668\u7edd\u5bf9\u8def\u5f84\uff1a<\/strong>\u00a0\u4ec5\u5728\u65e5\u5fd7\u4e2d\u8bb0\u5f55\u672c\u5730\u8def\u5f84\uff0cZip\u5185\u4e0d\u66b4\u9732<\/li>\n\n\n\n<li>\u2022\u00a0<strong>\u6743\u9650\u6821\u9a8c\uff1a<\/strong>\u00a0\u5b9e\u9645\u751f\u4ea7\u9700\u9a8c\u8bc1\u7528\u6237\u662f\u5426\u6709\u6743\u8bbf\u95ee\u6307\u5b9a\u6587\u4ef6<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">4. \u603b\u7ed3<\/h3>\n\n\n\n<p>\u8fd9\u91cc\u4ecb\u7ecd\u4e86\u5982\u4f55\u4ece\u672c\u5730\u670d\u52a1\u5668\u8def\u5f84\u548cHTTP\u6df7\u5408\u8bfb\u53d6\u6587\u4ef6\u5e76Zip\u6253\u5305\u4e0b\u8f7d\uff0c\u76ee\u5f55\u7ed3\u6784\u7075\u6d3b\u53ef\u63a7\u3002\u53ef\u6839\u636e\u5b9e\u9645\u9700\u6c42\u6269\u5c55\u66f4\u591a\u6765\u6e90\u7c7b\u578b\uff08\u5982\u6570\u636e\u5e93\u3001\u5bf9\u8c61\u5b58\u50a8\u7b49\uff09\u3002<\/p>\n","raw":"","protected":false},"excerpt":{"rendered":"<p>\u9700\u8981\u5c06\u4e00\u6279\u6587\u4ef6\uff08\u53ef\u80fd\u5206\u5e03\u5728\u4e0d\u540c\u76ee\u5f55\u3001\u4e0d\u540c\u6765\u6e90\uff09\u6253\u5305\u6210Zip\u683c\u5f0f\uff0c\u6309\u76ee\u5f55\u7ed3\u6784\u5bfc\u51fa\u7ed9\u7528\u6237\u4e0b\u8f7d\u3002 1. \u6838\u5fc3\u601d\u8def 2. \u4ee3\u7801\u5b9e\u73b0 2.1 &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"emotion":"","emotion_color":"","title_style":"","license":"","footnotes":""},"categories":[7],"tags":[],"class_list":["post-6595","post","type-post","status-publish","format-standard","hentry","category-spring-boot"],"post_thumbnail_image":"","content_first_image":null,"post_medium_image_300":"","post_thumbnail_image_624":"","post_frist_image":null,"post_medium_image":"","post_large_image":"","post_full_image":"","post_all_images":[],"videoAdId":"","listAd":"0","listAdId":"","listAdEvery":6,"total_comments":0,"category_name":"Spring Boot","post_date":"2025-09-29","like_count":"0","praiseWord":"\u9f13\u52b1","copyright_state":"","excitationAd":"0","rewardedVideoAdId":"","detailAdId":"","detailAd":"0","enterpriseMinapp":"0","audios":[],"postImageUrl":"https:\/\/wp-moto-1258805347.cos.ap-shanghai.myqcloud.com\/2023\/05\/20230519082947553.jpg","avatarurls":[],"related_posts":null,"pageviews":135,"next_post_id":6609,"next_post_title":"SpringBoot \u63d2\u4ef6\u5316\u5f00\u53d1\u6a21\u5f0f\uff0c\u5f3a\u70c8\u63a8\u8350\uff01","previous_post_id":6565,"previous_post_title":"SpringBoot\u6574\u5408\u5fae\u4fe1\u767b\u5f55\uff1aOpenID\u4e0eUnionID\u83b7\u53d6\u5168\u6d41\u7a0b\u89e3\u6790","_links":{"self":[{"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/posts\/6595","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/comments?post=6595"}],"version-history":[{"count":1,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/posts\/6595\/revisions"}],"predecessor-version":[{"id":6596,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/posts\/6595\/revisions\/6596"}],"wp:attachment":[{"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/media?parent=6595"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/categories?post=6595"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xinchewhd.com.cn\/index.php\/wp-json\/wp\/v2\/tags?post=6595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}