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:
2026-09-29 09:43:13 +08:00
commit 3271fee5cc
360 changed files with 86082 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
/*
* Decompiled with CFR 0.152.
*/
package com.jby.officecore.domain.bo;
import java.io.InputStream;
import java.io.Serializable;
public class ImageBO
implements Serializable {
private static final long serialVersionUID = 6640950035295880234L;
private InputStream is;
private Double width;
private Double height;
private Integer pictureType;
private String pictureUrl;
public InputStream getIs() {
return this.is;
}
public Double getWidth() {
return this.width;
}
public Double getHeight() {
return this.height;
}
public Integer getPictureType() {
return this.pictureType;
}
public String getPictureUrl() {
return this.pictureUrl;
}
public ImageBO setIs(InputStream is) {
this.is = is;
return this;
}
public ImageBO setWidth(Double width) {
this.width = width;
return this;
}
public ImageBO setHeight(Double height) {
this.height = height;
return this;
}
public ImageBO setPictureType(Integer pictureType) {
this.pictureType = pictureType;
return this;
}
public ImageBO setPictureUrl(String pictureUrl) {
this.pictureUrl = pictureUrl;
return this;
}
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ImageBO)) {
return false;
}
ImageBO other = (ImageBO)o;
if (!other.canEqual(this)) {
return false;
}
InputStream this$is = this.getIs();
InputStream other$is = other.getIs();
if (this$is == null ? other$is != null : !this$is.equals(other$is)) {
return false;
}
Double this$width = this.getWidth();
Double other$width = other.getWidth();
if (this$width == null ? other$width != null : !((Object)this$width).equals(other$width)) {
return false;
}
Double this$height = this.getHeight();
Double other$height = other.getHeight();
if (this$height == null ? other$height != null : !((Object)this$height).equals(other$height)) {
return false;
}
Integer this$pictureType = this.getPictureType();
Integer other$pictureType = other.getPictureType();
if (this$pictureType == null ? other$pictureType != null : !((Object)this$pictureType).equals(other$pictureType)) {
return false;
}
String this$pictureUrl = this.getPictureUrl();
String other$pictureUrl = other.getPictureUrl();
return !(this$pictureUrl == null ? other$pictureUrl != null : !this$pictureUrl.equals(other$pictureUrl));
}
protected boolean canEqual(Object other) {
return other instanceof ImageBO;
}
public int hashCode() {
int PRIME = 59;
int result = 1;
InputStream $is = this.getIs();
result = result * 59 + ($is == null ? 43 : $is.hashCode());
Double $width = this.getWidth();
result = result * 59 + ($width == null ? 43 : ((Object)$width).hashCode());
Double $height = this.getHeight();
result = result * 59 + ($height == null ? 43 : ((Object)$height).hashCode());
Integer $pictureType = this.getPictureType();
result = result * 59 + ($pictureType == null ? 43 : ((Object)$pictureType).hashCode());
String $pictureUrl = this.getPictureUrl();
result = result * 59 + ($pictureUrl == null ? 43 : $pictureUrl.hashCode());
return result;
}
public String toString() {
return "ImageBO(is=" + this.getIs() + ", width=" + this.getWidth() + ", height=" + this.getHeight() + ", pictureType=" + this.getPictureType() + ", pictureUrl=" + this.getPictureUrl() + ")";
}
}

View File

@@ -0,0 +1,455 @@
/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.alibaba.fastjson.JSONObject
* org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart
*/
package com.jby.officecore.domain.bo;
import com.alibaba.fastjson.JSONObject;
import com.jby.officecore.domain.bo.ImageBO;
import com.jby.officecore.utils.NumPr;
import java.io.Serializable;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Transformer;
import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
public class ParseBO
implements Serializable {
private static final long serialVersionUID = -1386361606482288851L;
public static final String IMAGES = "images";
public static final String PARSE_ = "parse-";
public static final String OUTPUT_HTML = "output.html";
private static final String JBY_OPEN_OFFICE_XML_ = "JBY_OPEN_OFFICE_XML_";
private static final String JBY_IMAGE_DATA_ = "JBY_IMAGE_DATA_";
private static final String PLACEHOLDER_SUFFIX = "_END";
private static final String IMAGE_ = "image_";
private static final String JBY_EQ_LATEX_ = "JBY_EQ_LATEX_";
public static final String JBY_TEXTBOX = "JBY_TEXTBOX_JBY";
private static final String JBY_MATHTYPE_DATA_ = "JBY_MATHTYPE_DATA_";
private Path tempDir;
private String sourceFilePath;
private String sourceFileUrl;
private String sourceFileMd5;
private String sourceFileBakPath;
private String htmlPath;
private String imagesDir;
private String ossFolder;
private Transformer transformer;
private List<JSONObject> latexReplaceList;
private Map<String, String> imgMap = new HashMap<String, String>();
private Map<String, String> shapeImgMap;
private Map<String, String> openOfficeXmlMap = new HashMap<String, String>();
private Map<String, String> mathTypeMap = new HashMap<String, String>();
private Map<String, String> eqLatexMap = new HashMap<String, String>();
private StyleDefinitionsPart styleDefinitionsPart;
private Map<String, NumPr> numberingDefinitionsMap = new HashMap<String, NumPr>();
private Map<String, ImageBO> imageMap;
private Boolean newParseVersion;
private Integer count = 0;
private Long fileId;
public ParseBO() {
this.shapeImgMap = new HashMap<String, String>();
this.imageMap = new HashMap<String, ImageBO>();
}
private Integer incrCount() {
this.count = this.count + 1;
return this.count;
}
public String getOpenOfficeXmlPlaceholder() {
return JBY_OPEN_OFFICE_XML_ + this.incrCount() + PLACEHOLDER_SUFFIX;
}
public String getMathTypePlaceholder() {
return JBY_IMAGE_DATA_ + this.incrCount() + PLACEHOLDER_SUFFIX;
}
public String getMathTypePlaceholder(String ctOleObjectRid) {
return JBY_MATHTYPE_DATA_ + ctOleObjectRid + PLACEHOLDER_SUFFIX;
}
public String getImgName() {
return IMAGE_ + this.incrCount();
}
public String getEqLatexPlaceholder() {
return JBY_EQ_LATEX_ + this.incrCount() + PLACEHOLDER_SUFFIX;
}
public String getShapeImgPlaceholder() {
return JBY_IMAGE_DATA_ + this.incrCount() + PLACEHOLDER_SUFFIX;
}
public String getImagePlaceholder(String rid) {
return JBY_IMAGE_DATA_ + this.incrCount() + PLACEHOLDER_SUFFIX;
}
public Path getTempDir() {
return this.tempDir;
}
public String getSourceFilePath() {
return this.sourceFilePath;
}
public String getSourceFileUrl() {
return this.sourceFileUrl;
}
public String getSourceFileMd5() {
return this.sourceFileMd5;
}
public String getSourceFileBakPath() {
return this.sourceFileBakPath;
}
public String getHtmlPath() {
return this.htmlPath;
}
public String getImagesDir() {
return this.imagesDir;
}
public String getOssFolder() {
return this.ossFolder;
}
public Transformer getTransformer() {
return this.transformer;
}
public List<JSONObject> getLatexReplaceList() {
return this.latexReplaceList;
}
public Map<String, String> getImgMap() {
return this.imgMap;
}
public Map<String, String> getShapeImgMap() {
return this.shapeImgMap;
}
public Map<String, String> getOpenOfficeXmlMap() {
return this.openOfficeXmlMap;
}
public Map<String, String> getMathTypeMap() {
return this.mathTypeMap;
}
public Map<String, String> getEqLatexMap() {
return this.eqLatexMap;
}
public StyleDefinitionsPart getStyleDefinitionsPart() {
return this.styleDefinitionsPart;
}
public Map<String, NumPr> getNumberingDefinitionsMap() {
return this.numberingDefinitionsMap;
}
public Map<String, ImageBO> getImageMap() {
return this.imageMap;
}
public Boolean getNewParseVersion() {
return this.newParseVersion;
}
public Integer getCount() {
return this.count;
}
public Long getFileId() {
return this.fileId;
}
public ParseBO setTempDir(Path tempDir) {
this.tempDir = tempDir;
return this;
}
public ParseBO setSourceFilePath(String sourceFilePath) {
this.sourceFilePath = sourceFilePath;
return this;
}
public ParseBO setSourceFileUrl(String sourceFileUrl) {
this.sourceFileUrl = sourceFileUrl;
return this;
}
public ParseBO setSourceFileMd5(String sourceFileMd5) {
this.sourceFileMd5 = sourceFileMd5;
return this;
}
public ParseBO setSourceFileBakPath(String sourceFileBakPath) {
this.sourceFileBakPath = sourceFileBakPath;
return this;
}
public ParseBO setHtmlPath(String htmlPath) {
this.htmlPath = htmlPath;
return this;
}
public ParseBO setImagesDir(String imagesDir) {
this.imagesDir = imagesDir;
return this;
}
public ParseBO setOssFolder(String ossFolder) {
this.ossFolder = ossFolder;
return this;
}
public ParseBO setTransformer(Transformer transformer) {
this.transformer = transformer;
return this;
}
public ParseBO setLatexReplaceList(List<JSONObject> latexReplaceList) {
this.latexReplaceList = latexReplaceList;
return this;
}
public ParseBO setImgMap(Map<String, String> imgMap) {
this.imgMap = imgMap;
return this;
}
public ParseBO setShapeImgMap(Map<String, String> shapeImgMap) {
this.shapeImgMap = shapeImgMap;
return this;
}
public ParseBO setOpenOfficeXmlMap(Map<String, String> openOfficeXmlMap) {
this.openOfficeXmlMap = openOfficeXmlMap;
return this;
}
public ParseBO setMathTypeMap(Map<String, String> mathTypeMap) {
this.mathTypeMap = mathTypeMap;
return this;
}
public ParseBO setEqLatexMap(Map<String, String> eqLatexMap) {
this.eqLatexMap = eqLatexMap;
return this;
}
public ParseBO setStyleDefinitionsPart(StyleDefinitionsPart styleDefinitionsPart) {
this.styleDefinitionsPart = styleDefinitionsPart;
return this;
}
public ParseBO setNumberingDefinitionsMap(Map<String, NumPr> numberingDefinitionsMap) {
this.numberingDefinitionsMap = numberingDefinitionsMap;
return this;
}
public ParseBO setImageMap(Map<String, ImageBO> imageMap) {
this.imageMap = imageMap;
return this;
}
public ParseBO setNewParseVersion(Boolean newParseVersion) {
this.newParseVersion = newParseVersion;
return this;
}
public ParseBO setCount(Integer count) {
this.count = count;
return this;
}
public ParseBO setFileId(Long fileId) {
this.fileId = fileId;
return this;
}
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ParseBO)) {
return false;
}
ParseBO other = (ParseBO)o;
if (!other.canEqual(this)) {
return false;
}
Path this$tempDir = this.getTempDir();
Path other$tempDir = other.getTempDir();
if (this$tempDir == null ? other$tempDir != null : !((Object)this$tempDir).equals(other$tempDir)) {
return false;
}
String this$sourceFilePath = this.getSourceFilePath();
String other$sourceFilePath = other.getSourceFilePath();
if (this$sourceFilePath == null ? other$sourceFilePath != null : !this$sourceFilePath.equals(other$sourceFilePath)) {
return false;
}
String this$sourceFileUrl = this.getSourceFileUrl();
String other$sourceFileUrl = other.getSourceFileUrl();
if (this$sourceFileUrl == null ? other$sourceFileUrl != null : !this$sourceFileUrl.equals(other$sourceFileUrl)) {
return false;
}
String this$sourceFileMd5 = this.getSourceFileMd5();
String other$sourceFileMd5 = other.getSourceFileMd5();
if (this$sourceFileMd5 == null ? other$sourceFileMd5 != null : !this$sourceFileMd5.equals(other$sourceFileMd5)) {
return false;
}
String this$sourceFileBakPath = this.getSourceFileBakPath();
String other$sourceFileBakPath = other.getSourceFileBakPath();
if (this$sourceFileBakPath == null ? other$sourceFileBakPath != null : !this$sourceFileBakPath.equals(other$sourceFileBakPath)) {
return false;
}
String this$htmlPath = this.getHtmlPath();
String other$htmlPath = other.getHtmlPath();
if (this$htmlPath == null ? other$htmlPath != null : !this$htmlPath.equals(other$htmlPath)) {
return false;
}
String this$imagesDir = this.getImagesDir();
String other$imagesDir = other.getImagesDir();
if (this$imagesDir == null ? other$imagesDir != null : !this$imagesDir.equals(other$imagesDir)) {
return false;
}
String this$ossFolder = this.getOssFolder();
String other$ossFolder = other.getOssFolder();
if (this$ossFolder == null ? other$ossFolder != null : !this$ossFolder.equals(other$ossFolder)) {
return false;
}
Transformer this$transformer = this.getTransformer();
Transformer other$transformer = other.getTransformer();
if (this$transformer == null ? other$transformer != null : !this$transformer.equals(other$transformer)) {
return false;
}
List<JSONObject> this$latexReplaceList = this.getLatexReplaceList();
List<JSONObject> other$latexReplaceList = other.getLatexReplaceList();
if (this$latexReplaceList == null ? other$latexReplaceList != null : !((Object)this$latexReplaceList).equals(other$latexReplaceList)) {
return false;
}
Map<String, String> this$imgMap = this.getImgMap();
Map<String, String> other$imgMap = other.getImgMap();
if (this$imgMap == null ? other$imgMap != null : !((Object)this$imgMap).equals(other$imgMap)) {
return false;
}
Map<String, String> this$shapeImgMap = this.getShapeImgMap();
Map<String, String> other$shapeImgMap = other.getShapeImgMap();
if (this$shapeImgMap == null ? other$shapeImgMap != null : !((Object)this$shapeImgMap).equals(other$shapeImgMap)) {
return false;
}
Map<String, String> this$openOfficeXmlMap = this.getOpenOfficeXmlMap();
Map<String, String> other$openOfficeXmlMap = other.getOpenOfficeXmlMap();
if (this$openOfficeXmlMap == null ? other$openOfficeXmlMap != null : !((Object)this$openOfficeXmlMap).equals(other$openOfficeXmlMap)) {
return false;
}
Map<String, String> this$mathTypeMap = this.getMathTypeMap();
Map<String, String> other$mathTypeMap = other.getMathTypeMap();
if (this$mathTypeMap == null ? other$mathTypeMap != null : !((Object)this$mathTypeMap).equals(other$mathTypeMap)) {
return false;
}
Map<String, String> this$eqLatexMap = this.getEqLatexMap();
Map<String, String> other$eqLatexMap = other.getEqLatexMap();
if (this$eqLatexMap == null ? other$eqLatexMap != null : !((Object)this$eqLatexMap).equals(other$eqLatexMap)) {
return false;
}
StyleDefinitionsPart this$styleDefinitionsPart = this.getStyleDefinitionsPart();
StyleDefinitionsPart other$styleDefinitionsPart = other.getStyleDefinitionsPart();
if (this$styleDefinitionsPart == null ? other$styleDefinitionsPart != null : !this$styleDefinitionsPart.equals(other$styleDefinitionsPart)) {
return false;
}
Map<String, NumPr> this$numberingDefinitionsMap = this.getNumberingDefinitionsMap();
Map<String, NumPr> other$numberingDefinitionsMap = other.getNumberingDefinitionsMap();
if (this$numberingDefinitionsMap == null ? other$numberingDefinitionsMap != null : !((Object)this$numberingDefinitionsMap).equals(other$numberingDefinitionsMap)) {
return false;
}
Map<String, ImageBO> this$imageMap = this.getImageMap();
Map<String, ImageBO> other$imageMap = other.getImageMap();
if (this$imageMap == null ? other$imageMap != null : !((Object)this$imageMap).equals(other$imageMap)) {
return false;
}
Boolean this$newParseVersion = this.getNewParseVersion();
Boolean other$newParseVersion = other.getNewParseVersion();
if (this$newParseVersion == null ? other$newParseVersion != null : !((Object)this$newParseVersion).equals(other$newParseVersion)) {
return false;
}
Integer this$count = this.getCount();
Integer other$count = other.getCount();
if (this$count == null ? other$count != null : !((Object)this$count).equals(other$count)) {
return false;
}
Long this$fileId = this.getFileId();
Long other$fileId = other.getFileId();
return !(this$fileId == null ? other$fileId != null : !((Object)this$fileId).equals(other$fileId));
}
protected boolean canEqual(Object other) {
return other instanceof ParseBO;
}
public int hashCode() {
int PRIME = 59;
int result = 1;
Path $tempDir = this.getTempDir();
result = result * 59 + ($tempDir == null ? 43 : ((Object)$tempDir).hashCode());
String $sourceFilePath = this.getSourceFilePath();
result = result * 59 + ($sourceFilePath == null ? 43 : $sourceFilePath.hashCode());
String $sourceFileUrl = this.getSourceFileUrl();
result = result * 59 + ($sourceFileUrl == null ? 43 : $sourceFileUrl.hashCode());
String $sourceFileMd5 = this.getSourceFileMd5();
result = result * 59 + ($sourceFileMd5 == null ? 43 : $sourceFileMd5.hashCode());
String $sourceFileBakPath = this.getSourceFileBakPath();
result = result * 59 + ($sourceFileBakPath == null ? 43 : $sourceFileBakPath.hashCode());
String $htmlPath = this.getHtmlPath();
result = result * 59 + ($htmlPath == null ? 43 : $htmlPath.hashCode());
String $imagesDir = this.getImagesDir();
result = result * 59 + ($imagesDir == null ? 43 : $imagesDir.hashCode());
String $ossFolder = this.getOssFolder();
result = result * 59 + ($ossFolder == null ? 43 : $ossFolder.hashCode());
Transformer $transformer = this.getTransformer();
result = result * 59 + ($transformer == null ? 43 : $transformer.hashCode());
List<JSONObject> $latexReplaceList = this.getLatexReplaceList();
result = result * 59 + ($latexReplaceList == null ? 43 : ((Object)$latexReplaceList).hashCode());
Map<String, String> $imgMap = this.getImgMap();
result = result * 59 + ($imgMap == null ? 43 : ((Object)$imgMap).hashCode());
Map<String, String> $shapeImgMap = this.getShapeImgMap();
result = result * 59 + ($shapeImgMap == null ? 43 : ((Object)$shapeImgMap).hashCode());
Map<String, String> $openOfficeXmlMap = this.getOpenOfficeXmlMap();
result = result * 59 + ($openOfficeXmlMap == null ? 43 : ((Object)$openOfficeXmlMap).hashCode());
Map<String, String> $mathTypeMap = this.getMathTypeMap();
result = result * 59 + ($mathTypeMap == null ? 43 : ((Object)$mathTypeMap).hashCode());
Map<String, String> $eqLatexMap = this.getEqLatexMap();
result = result * 59 + ($eqLatexMap == null ? 43 : ((Object)$eqLatexMap).hashCode());
StyleDefinitionsPart $styleDefinitionsPart = this.getStyleDefinitionsPart();
result = result * 59 + ($styleDefinitionsPart == null ? 43 : $styleDefinitionsPart.hashCode());
Map<String, NumPr> $numberingDefinitionsMap = this.getNumberingDefinitionsMap();
result = result * 59 + ($numberingDefinitionsMap == null ? 43 : ((Object)$numberingDefinitionsMap).hashCode());
Map<String, ImageBO> $imageMap = this.getImageMap();
result = result * 59 + ($imageMap == null ? 43 : ((Object)$imageMap).hashCode());
Boolean $newParseVersion = this.getNewParseVersion();
result = result * 59 + ($newParseVersion == null ? 43 : ((Object)$newParseVersion).hashCode());
Integer $count = this.getCount();
result = result * 59 + ($count == null ? 43 : ((Object)$count).hashCode());
Long $fileId = this.getFileId();
result = result * 59 + ($fileId == null ? 43 : ((Object)$fileId).hashCode());
return result;
}
public String toString() {
return "ParseBO(tempDir=" + this.getTempDir() + ", sourceFilePath=" + this.getSourceFilePath() + ", sourceFileUrl=" + this.getSourceFileUrl() + ", sourceFileMd5=" + this.getSourceFileMd5() + ", sourceFileBakPath=" + this.getSourceFileBakPath() + ", htmlPath=" + this.getHtmlPath() + ", imagesDir=" + this.getImagesDir() + ", ossFolder=" + this.getOssFolder() + ", transformer=" + this.getTransformer() + ", latexReplaceList=" + this.getLatexReplaceList() + ", imgMap=" + this.getImgMap() + ", shapeImgMap=" + this.getShapeImgMap() + ", openOfficeXmlMap=" + this.getOpenOfficeXmlMap() + ", mathTypeMap=" + this.getMathTypeMap() + ", eqLatexMap=" + this.getEqLatexMap() + ", styleDefinitionsPart=" + this.getStyleDefinitionsPart() + ", numberingDefinitionsMap=" + this.getNumberingDefinitionsMap() + ", imageMap=" + this.getImageMap() + ", newParseVersion=" + this.getNewParseVersion() + ", count=" + this.getCount() + ", fileId=" + this.getFileId() + ")";
}
}

View File

@@ -0,0 +1,42 @@
/*
* Decompiled with CFR 0.152.
*/
package com.jby.officecore.domain.bo;
import java.io.Serializable;
public class TagStyleBO
implements Serializable {
private static final long serialVersionUID = -5541312317983576319L;
private String tagName;
private String attr;
private String value;
public String getTagName() {
return this.tagName;
}
public String getAttr() {
return this.attr;
}
public String getValue() {
return this.value;
}
public TagStyleBO setTagName(String tagName) {
this.tagName = tagName;
return this;
}
public TagStyleBO setAttr(String attr) {
this.attr = attr;
return this;
}
public TagStyleBO setValue(String value) {
this.value = value;
return this;
}
}