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:
110
java-src/pool/OMml2MmlTransformerPool.java
Normal file
110
java-src/pool/OMml2MmlTransformerPool.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* com.jby.common.exceptions.BusinessException
|
||||
* org.apache.commons.pool2.BasePooledObjectFactory
|
||||
* org.apache.commons.pool2.PooledObject
|
||||
* org.apache.commons.pool2.PooledObjectFactory
|
||||
* org.apache.commons.pool2.impl.DefaultPooledObject
|
||||
* org.apache.commons.pool2.impl.GenericObjectPool
|
||||
* org.apache.commons.pool2.impl.GenericObjectPoolConfig
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.core.io.ClassPathResource
|
||||
*/
|
||||
package com.jby.officecore.pool;
|
||||
|
||||
import com.jby.common.exceptions.BusinessException;
|
||||
import java.util.Objects;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
public enum OMml2MmlTransformerPool {
|
||||
INSTANCE;
|
||||
|
||||
private static final Logger log;
|
||||
private GenericObjectPool<Transformer> objectPool;
|
||||
|
||||
private OMml2MmlTransformerPool() {
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
poolConfig.setMaxTotal(30);
|
||||
poolConfig.setMinIdle(4);
|
||||
poolConfig.setMaxIdle(8);
|
||||
poolConfig.setBlockWhenExhausted(true);
|
||||
poolConfig.setMaxWaitMillis(3000L);
|
||||
poolConfig.setTestOnCreate(true);
|
||||
poolConfig.setTestOnBorrow(true);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
poolConfig.setTestWhileIdle(true);
|
||||
PooledTransformerFactory objectFactory = new PooledTransformerFactory();
|
||||
this.objectPool = new GenericObjectPool((PooledObjectFactory)objectFactory, poolConfig);
|
||||
}
|
||||
|
||||
public Transformer borrowObject() {
|
||||
log.info("\u8f6c\u6362\u5668\u6c60TransformerPool, \u7a7a\u95f2\u5bf9\u8c61\u6570\u91cf:{}, \u6d3b\u8dc3\u5bf9\u8c61\u6570\u91cf:{}, \u963b\u585e\u7b49\u5f85\u6570\u91cf:{},", new Object[]{this.objectPool.getNumIdle(), this.objectPool.getNumActive(), this.objectPool.getNumWaiters()});
|
||||
try {
|
||||
return (Transformer)this.objectPool.borrowObject();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u4ece\u5bf9\u8c61\u6c60\u4e2d\u501f\u51fa\u5bf9\u8c61\u5f02\u5e38", (Throwable)e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void returnObject(Transformer transformer) {
|
||||
log.info("\u8f6c\u6362\u5668\u6c60TransformerPool, \u7a7a\u95f2\u5bf9\u8c61\u6570\u91cf:{}, \u6d3b\u8dc3\u5bf9\u8c61\u6570\u91cf:{}, \u963b\u585e\u7b49\u5f85\u6570\u91cf:{},", new Object[]{this.objectPool.getNumIdle(), this.objectPool.getNumActive(), this.objectPool.getNumWaiters()});
|
||||
if (Objects.nonNull(transformer)) {
|
||||
this.objectPool.returnObject((Object)transformer);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
log = LoggerFactory.getLogger(OMml2MmlTransformerPool.class);
|
||||
}
|
||||
|
||||
public static class PooledTransformerFactory
|
||||
extends BasePooledObjectFactory<Transformer> {
|
||||
private static final Logger log = LoggerFactory.getLogger(PooledTransformerFactory.class);
|
||||
private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
|
||||
|
||||
public Transformer create() throws Exception {
|
||||
return PooledTransformerFactory.buildTransformer();
|
||||
}
|
||||
|
||||
public PooledObject<Transformer> wrap(Transformer transformer) {
|
||||
return new DefaultPooledObject((Object)transformer);
|
||||
}
|
||||
|
||||
public void destroyObject(PooledObject<Transformer> p) throws Exception {
|
||||
super.destroyObject(p);
|
||||
}
|
||||
|
||||
public boolean validateObject(PooledObject<Transformer> p) {
|
||||
return Objects.nonNull(p.getObject());
|
||||
}
|
||||
|
||||
private static Transformer buildTransformer() {
|
||||
try {
|
||||
ClassPathResource resource = new ClassPathResource("xsl/OMML2MML.XSL");
|
||||
StreamSource xslSource = new StreamSource(resource.getInputStream());
|
||||
return TRANSFORMER_FACTORY.newTransformer(xslSource);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u751f\u6210\u8f6c\u6362\u5668\u5f02\u5e38", (Throwable)e);
|
||||
throw new BusinessException("\u751f\u6210\u8f6c\u6362\u5668\u5f02\u5e38");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user