服务: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 默认密钥已清空
111 lines
4.5 KiB
Java
111 lines
4.5 KiB
Java
/*
|
|
* 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");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|