init: WordFileParse docx→HTML 解析服务(含 Word EQ 域公式修复)
服务:Spring Boot 3.2 + docx4j 8.3.9,POST /api/v3/server_office_file/file/parse
接受 .docx,返回 HTML(公式 → LaTeX,图片 → RustFS 外链)
公式支持三类来源:
- OMML(Word 2007+ 公式) → Python omml_mathml2latex
- MathType OLE 对象 → Ruby mathtype2mathml → MathML → LaTeX
- Word EQ 域(老教辅主力) → EqToLatexUtil(本次新增)
本次改动:
1. 新增 java-svc/.../core/EqToLatexUtil.java:
移植自 jby backend-services office-core,EQ 语法 → LaTeX
(\f→\dfrac、\r→\sqrt、\i→\int/\sum/\prod、\s→^{}/_{}、\b→\left\right、
\a→array、\x→\boxed/\overline、\o\al 堆叠、圈码、化学符号、极限、连等式)
品牌标记 JBYU* → WPU*,与采集端一致
2. CtoMathFinder:接上 EQ 分支(原为 not-ported 桩),域代码经
EqToLatexUtil.convert 转 LaTeX 写入 eqLatexMap(WPEQNUM 占位符)
3. WordParseUtil.dealPlaceholder:EQ 的 LaTeX 同样加 \( \) 包裹
(原先因 WPEQNUM 例外不加包裹,前端/MathJax 不渲染)
修前症状:教辅 Word 里分式/方程组/上下标整段丢失(如 {−1/3, 1} 变成 {-,1})
修后实测:46 份教辅 2908 处 EQ 域全部还原,公式总数 2954 处、零未包裹残留
安全:application.yml(含 RustFS 密钥)不入库,提供 application.yml.example;
OssService 的 @Value 默认密钥已清空
This commit is contained in:
235
java-src/utils/OfficeFileUtil.java
Normal file
235
java-src/utils/OfficeFileUtil.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* cn.hutool.core.io.FileUtil
|
||||
* com.alibaba.fastjson.JSON
|
||||
* com.alibaba.fastjson.JSONObject
|
||||
* com.alibaba.fastjson.TypeReference
|
||||
* com.jby.common.exceptions.BusinessException
|
||||
* com.jby.common.util.FileUtil
|
||||
* com.jby.common.util.HttpClientUtil
|
||||
* com.jby.common.util.RequestHeaderUtil
|
||||
* com.jby.oss.domain.param.OssParam
|
||||
* com.jby.system.enums.AttachmentModuleEnum
|
||||
* org.apache.poi.xwpf.usermodel.XWPFDocument
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.beans.factory.annotation.Autowired
|
||||
* org.springframework.stereotype.Component
|
||||
* org.springframework.web.multipart.MultipartFile
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.jby.common.exceptions.BusinessException;
|
||||
import com.jby.common.util.HttpClientUtil;
|
||||
import com.jby.common.util.RequestHeaderUtil;
|
||||
import com.jby.officecore.config.OfficeCoreConfig;
|
||||
import com.jby.officecore.utils.OssServiceUtil;
|
||||
import com.jby.oss.domain.param.OssParam;
|
||||
import com.jby.system.enums.AttachmentModuleEnum;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Component
|
||||
public class OfficeFileUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(OfficeFileUtil.class);
|
||||
private static OfficeCoreConfig officeCoreConfig;
|
||||
|
||||
@Autowired
|
||||
public void setOfficeCoreConfig(OfficeCoreConfig officeCoreConfig) {
|
||||
OfficeFileUtil.officeCoreConfig = officeCoreConfig;
|
||||
}
|
||||
|
||||
public static File writeFile(String content, String savePath) {
|
||||
FileWriter fw = null;
|
||||
BufferedWriter bW = null;
|
||||
try {
|
||||
File file = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
fw = new FileWriter(file);
|
||||
bW = new BufferedWriter(fw);
|
||||
bW.write(content);
|
||||
File file2 = file;
|
||||
return file2;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
finally {
|
||||
if (bW != null) {
|
||||
try {
|
||||
bW.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (fw != null) {
|
||||
try {
|
||||
fw.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeWord(XWPFDocument document, String savePath) {
|
||||
OutputStream os = null;
|
||||
try {
|
||||
File file = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
os = Files.newOutputStream(file.toPath(), new OpenOption[0]);
|
||||
document.write(os);
|
||||
File file2 = file;
|
||||
return file2;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u751f\u6210word\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u751f\u6210word\u6587\u4ef6\u5f02\u5e38\uff01");
|
||||
}
|
||||
finally {
|
||||
if (Objects.nonNull(os)) {
|
||||
try {
|
||||
os.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (Objects.nonNull(document)) {
|
||||
try {
|
||||
document.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeFile(MultipartFile file, String savePath) {
|
||||
try {
|
||||
return OfficeFileUtil.writeFile(file.getInputStream(), savePath);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeFile(InputStream is, String savePath) {
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
int length;
|
||||
File saveFile = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
os = new FileOutputStream(saveFile);
|
||||
byte[] buffer = new byte[15360];
|
||||
while ((length = is.read(buffer)) != -1) {
|
||||
((OutputStream)os).write(buffer, 0, length);
|
||||
}
|
||||
os.flush();
|
||||
File file = saveFile;
|
||||
return file;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
((OutputStream)os).close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static String mf2svg(InputStream is, String imgPath) {
|
||||
HashMap<String, Object> params = null;
|
||||
String result = null;
|
||||
try {
|
||||
File localFile = com.jby.common.util.FileUtil.getFile((String)imgPath);
|
||||
FileUtil.writeFromStream((InputStream)is, (File)localFile);
|
||||
String accessUrl = OssServiceUtil.uploadFile(new OssParam().setModule(AttachmentModuleEnum.OFFICE_IMG.getModule()).setFile(com.jby.common.util.FileUtil.getMultipartFile((String)localFile.getName(), (File)localFile)));
|
||||
params = new HashMap<String, Object>();
|
||||
params.put("fileUrl", accessUrl);
|
||||
params.put("refreshImg", false);
|
||||
Map headers = RequestHeaderUtil.getAuthHeaders();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getMf2SvgApi(), params, (Map)headers);
|
||||
JSONObject json = (JSONObject)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<JSONObject>(){});
|
||||
String string = Objects.isNull(json) ? null : json.getString("svgUrl");
|
||||
return string;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mf2svg exception, imgPath:{}, params:{}, result:{}", new Object[]{imgPath, JSON.toJSONString(params), result, e});
|
||||
String string = null;
|
||||
return string;
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String mf2svg(InputStream is, String ossFolder, String imgName) {
|
||||
HashMap<String, Object> params = null;
|
||||
String result = null;
|
||||
try {
|
||||
String imgUrl = OssServiceUtil.uploadStream(new OssParam().setModule(AttachmentModuleEnum.OFFICE_IMG.getModule()).setFolder(ossFolder).setFileName(imgName).setInputStream(is));
|
||||
params = new HashMap<String, Object>();
|
||||
params.put("fileUrl", imgUrl);
|
||||
params.put("refreshImg", false);
|
||||
Map headers = RequestHeaderUtil.getAuthHeaders();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getMf2SvgApi(), params, (Map)headers);
|
||||
JSONObject json = (JSONObject)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<JSONObject>(){});
|
||||
return Objects.isNull(json) ? null : json.getString("svgUrl");
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mf2svg exception, ossFolder:{}, imgName:{}, params:{}, result:{}", new Object[]{ossFolder, imgName, JSON.toJSONString(params), result, e});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user