From 98250fca477e01c3843ad4b7108c3757d0d0a80c Mon Sep 17 00:00:00 2001 From: RuicyWu <1063154311@qq.com> Date: Thu, 18 Jun 2026 09:20:32 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../esign/constants/EsignConfigConstants.java | 3 +- .../esign/logfile/EsignParamRecordUtils.java | 6 +- .../seeyon/apps/esign/node/A4CheckNode.java | 2 + .../esign/node/EsignMultipleSignerNode.java | 2 +- .../apps/esign/node/EsignOneSignerNode.java | 2 +- .../esign/po/signer/DefaultSignerBuilder.java | 12 +- .../esign/service/EsignByTemplateService.java | 2 + .../apps/esign/utils/DocumentA4Checker.java | 112 +++++++++++++----- 8 files changed, 99 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/seeyon/apps/esign/constants/EsignConfigConstants.java b/src/main/java/com/seeyon/apps/esign/constants/EsignConfigConstants.java index 4899ddc..18a388c 100644 --- a/src/main/java/com/seeyon/apps/esign/constants/EsignConfigConstants.java +++ b/src/main/java/com/seeyon/apps/esign/constants/EsignConfigConstants.java @@ -21,7 +21,8 @@ public enum EsignConfigConstants { ESIGN_APP_SECRETMAP("325c8cc6c2a303d6cf1fb5657a16e591","e签宝appIDSecret映射"), ENABLEANTIFAKESIGN("","是否加盖防伪章"), FIXAPPUNIT("true","是否固定要用的E签宝应用主体单位"), - FIXAPPUNITNAME("","固定要用的E签宝应用主体单位名称") + FIXAPPUNITNAME("","固定要用的E签宝应用主体单位名称"), + SIGNPARAM_LOG_URL("","E签宝参数记录路径"), ; private String defaultValue; diff --git a/src/main/java/com/seeyon/apps/esign/logfile/EsignParamRecordUtils.java b/src/main/java/com/seeyon/apps/esign/logfile/EsignParamRecordUtils.java index f8f7ff7..a949ee6 100644 --- a/src/main/java/com/seeyon/apps/esign/logfile/EsignParamRecordUtils.java +++ b/src/main/java/com/seeyon/apps/esign/logfile/EsignParamRecordUtils.java @@ -10,11 +10,11 @@ import java.util.Map; public class EsignParamRecordUtils { - public static void saveEsignParamRecord(Map params) { + public static void saveEsignParamRecord(String logFileUrl,Map params) { try { - String str = "/home/seeyon/Seeyon/A8/ApacheJetspeed/logs_sy"; + String str = logFileUrl; String date = DateUtil.format(new Date(), "yyyyMMddHHmmss"); - FileUtils.writeStringToFile(new File(str+"/esignParams/" + date + ".json"), JsonUtils.toJSONString(params), "UTF-8"); + FileUtils.writeStringToFile(new File(str+ File.separator + "esignParams" + File.separator + date + ".json"), JsonUtils.toJSONString(params), "UTF-8"); }catch (Exception e){ } diff --git a/src/main/java/com/seeyon/apps/esign/node/A4CheckNode.java b/src/main/java/com/seeyon/apps/esign/node/A4CheckNode.java index bdcf7c9..6c1fd9b 100644 --- a/src/main/java/com/seeyon/apps/esign/node/A4CheckNode.java +++ b/src/main/java/com/seeyon/apps/esign/node/A4CheckNode.java @@ -50,6 +50,8 @@ public class A4CheckNode extends ACommonSuperNode { String errMsg = "上传的附件中" + file.getName() +"非标准A4格式的,请修改后再上传(标准A4为21:29)"; formDataVo.getNewFieldDataMap().put("合同审批附件格式校验结果", errMsg); return context.back(errMsg); + }else { + formDataVo.getNewFieldDataMap().put("合同审批附件格式校验结果", ""); } file.delete(); } diff --git a/src/main/java/com/seeyon/apps/esign/node/EsignMultipleSignerNode.java b/src/main/java/com/seeyon/apps/esign/node/EsignMultipleSignerNode.java index fd3abb7..fa9d37b 100644 --- a/src/main/java/com/seeyon/apps/esign/node/EsignMultipleSignerNode.java +++ b/src/main/java/com/seeyon/apps/esign/node/EsignMultipleSignerNode.java @@ -121,7 +121,7 @@ public class EsignMultipleSignerNode extends ACommonSuperNode { aParty.setPartyId("甲方"); aParty.setSignOrder(2); aParty.setSignerType(SignerType.ORG); - aParty.setSealId(getStringField(formDataVo,"选择甲方印章")); + aParty.setSealId(getStringField(formDataVo,"甲方印章ID")); aParty.setAutoSign(doAutoSign); OrgInfo orgInfo = new OrgInfo(); aParty.setOrgInfo(orgInfo); diff --git a/src/main/java/com/seeyon/apps/esign/node/EsignOneSignerNode.java b/src/main/java/com/seeyon/apps/esign/node/EsignOneSignerNode.java index 9d2ca21..b0aa6b2 100644 --- a/src/main/java/com/seeyon/apps/esign/node/EsignOneSignerNode.java +++ b/src/main/java/com/seeyon/apps/esign/node/EsignOneSignerNode.java @@ -129,7 +129,7 @@ public class EsignOneSignerNode extends ACommonSuperNode { aParty.setSignOrder(2); aParty.setSignerType(SignerType.ORG); aParty.setAutoSign(doAutoSign); - aParty.setSealId(getStringField(formDataVo,"选择甲方印章")); + aParty.setSealId(getStringField(formDataVo,"甲方印章ID")); OrgInfo orgInfo = new OrgInfo(); orgInfo.setOrgName(orgName); aParty.setOrgInfo(orgInfo); diff --git a/src/main/java/com/seeyon/apps/esign/po/signer/DefaultSignerBuilder.java b/src/main/java/com/seeyon/apps/esign/po/signer/DefaultSignerBuilder.java index dc4a0b8..e4b68b5 100644 --- a/src/main/java/com/seeyon/apps/esign/po/signer/DefaultSignerBuilder.java +++ b/src/main/java/com/seeyon/apps/esign/po/signer/DefaultSignerBuilder.java @@ -321,7 +321,7 @@ public class DefaultSignerBuilder implements SignerBuilder { } /** - * 查询文件总页数 + * 查询文件总页数,查询失败或页数为0时返回默认值10 */ private Integer getFileTotalPage(String fileId, String appId) { try { @@ -336,14 +336,18 @@ public class DefaultSignerBuilder implements SignerBuilder { EsignBaseResp resp = JsonUtils.parseObject(respStr, EsignBaseResp.class); if (!"0".equals(String.valueOf(resp.getCode()))) { - throw new RuntimeException("查询文件上传状态失败:" + resp.getMessage()); + return 10; } Map data = (Map) resp.getData(); Object pageCount = data.get("fileTotalPageCount"); - return pageCount == null ? 10 : Integer.parseInt(String.valueOf(pageCount)); + if (pageCount == null) { + return 10; + } + int pages = Integer.parseInt(String.valueOf(pageCount)); + return pages > 0 ? pages : 10; } catch (Exception e) { - throw new RuntimeException("获取文件页数异常", e); + return 10; } } diff --git a/src/main/java/com/seeyon/apps/esign/service/EsignByTemplateService.java b/src/main/java/com/seeyon/apps/esign/service/EsignByTemplateService.java index 4597379..3e20ad0 100644 --- a/src/main/java/com/seeyon/apps/esign/service/EsignByTemplateService.java +++ b/src/main/java/com/seeyon/apps/esign/service/EsignByTemplateService.java @@ -4,6 +4,7 @@ import com.seeyon.aicloud.common.JsonUtils; import com.seeyon.apps.esign.config.EsignConfigProvider; import com.seeyon.apps.esign.constants.EsignApiUrl; import com.seeyon.apps.esign.constants.EsignConfigConstants; +import com.seeyon.apps.esign.logfile.EsignParamRecordUtils; import com.seeyon.apps.esign.po.esignapi.EsignApiHeader; import com.seeyon.apps.esign.po.esignapi.EsignBaseResp; import com.seeyon.apps.esign.utils.HttpClient; @@ -42,6 +43,7 @@ public class EsignByTemplateService { esignApiHeader.token(tokenCacheManager.getToken(appId)).appId(appId); String url = configProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST) + EsignApiUrl.SIGN_BY_FILE_URL; log.info("合同发起入参: " + jsonBody); + EsignParamRecordUtils.saveEsignParamRecord(configProvider.getBizConfigByKey(EsignConfigConstants.SIGNPARAM_LOG_URL),params); String respStr = HttpClient.httpPostRaw(url, jsonBody, esignApiHeader.convert2Headers(), "UTF-8"); EsignBaseResp esignBaseResp = JsonUtils.parseObject(respStr, EsignBaseResp.class); Map dataMap = (Map) esignBaseResp.getData(); diff --git a/src/main/java/com/seeyon/apps/esign/utils/DocumentA4Checker.java b/src/main/java/com/seeyon/apps/esign/utils/DocumentA4Checker.java index 5dc0b84..8483b16 100644 --- a/src/main/java/com/seeyon/apps/esign/utils/DocumentA4Checker.java +++ b/src/main/java/com/seeyon/apps/esign/utils/DocumentA4Checker.java @@ -4,13 +4,16 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.usermodel.Section; -import org.apache.poi.xwpf.usermodel.XWPFDocument; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr; -import org.openxmlformats.schemas.wordprocessingml.x2006.main.STPageOrientation; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import javax.xml.parsers.DocumentBuilderFactory; import java.io.*; import java.util.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class DocumentA4Checker { @@ -60,7 +63,7 @@ public class DocumentA4Checker { /** * 校验 PDF 第一页是否竖版 A4 */ - private static boolean checkPdfFirstPageA4(InputStream in) throws IOException { + private static boolean checkPdfFirstPageA4(InputStream in) throws Exception { try (PDDocument document = PDDocument.load(in)) { if (document.getNumberOfPages() == 0) return false; @@ -76,7 +79,7 @@ public class DocumentA4Checker { /** * 校验 doc 第一页是否竖版 A4 */ - private static boolean checkDocFirstPageA4(InputStream in) throws IOException { + private static boolean checkDocFirstPageA4(InputStream in) throws Exception { try (HWPFDocument doc = new HWPFDocument(in)) { Section section = doc.getRange().getSection(0); @@ -92,42 +95,87 @@ public class DocumentA4Checker { } /** - * 校验 docx 第一页是否竖版 A4(POI 5.x 兼容版) + * 校验 docx 第一页是否竖版 A4 + * 直接读取 ZIP 中的 word/document.xml,不依赖 POI ooxml 模块 */ - public static boolean isDocxA4Portrait(InputStream in) throws IOException { - try (XWPFDocument docx = new XWPFDocument(in)) { - CTSectPr sectPr = docx.getDocument().getBody().getSectPr(); - if (sectPr == null || sectPr.getPgSz() == null) { - // 没有设置页面大小 → 默认认为是A4(Word默认行为) - return true; - } - - CTPageSz pgSz = sectPr.getPgSz(); - - // 判断是否横向 - if (pgSz.getOrient() != null) { - STPageOrientation.Enum orient = pgSz.getOrient(); - if (STPageOrientation.LANDSCAPE.equals(orient)) { - return false; - } - } - - // 兼容 BigInteger 和 BigDecimal 两种实现 - Number wTwips = (Number) pgSz.getW(); - Number hTwips = (Number) pgSz.getH(); - - if (wTwips == null || hTwips == null) { + public static boolean isDocxA4Portrait(InputStream in) { + try { + byte[] docXml = extractDocXml(in); + if (docXml == null) { return false; } - float wPt = wTwips.floatValue() / TWIPS_TO_PT; - float hPt = hTwips.floatValue() / TWIPS_TO_PT; + // 不启用 namespace-aware,元素名带 w: 前缀(如 w:pgSz) + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + Document doc = factory.newDocumentBuilder() + .parse(new ByteArrayInputStream(docXml)); + + // 递归搜索 w:pgSz 元素(sectPr 下的页面尺寸定义) + Element pgSz = findElement(doc.getDocumentElement(), "w:pgSz"); + if (pgSz == null) { + return false; + } + + String orient = pgSz.getAttribute("w:orient"); + if ("landscape".equalsIgnoreCase(orient)) { + return false; + } + + String wStr = pgSz.getAttribute("w:w"); + String hStr = pgSz.getAttribute("w:h"); + if (wStr == null || wStr.isEmpty() || hStr == null || hStr.isEmpty()) { + return false; + } + + float wPt = Long.parseLong(wStr) / TWIPS_TO_PT; + float hPt = Long.parseLong(hStr) / TWIPS_TO_PT; return Math.abs(wPt - A4_WIDTH) <= TOLERANCE && Math.abs(hPt - A4_HEIGHT) <= TOLERANCE; + } catch (Exception e) { + e.printStackTrace(); + return false; } } + /** + * 从 docx ZIP 中提取 word/document.xml 的字节内容 + */ + private static byte[] extractDocXml(InputStream in) throws IOException { + try (ZipInputStream zis = new ZipInputStream(in)) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if ("word/document.xml".equals(entry.getName())) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int len; + while ((len = zis.read(buf)) != -1) { + bos.write(buf, 0, len); + } + return bos.toByteArray(); + } + } + } + return null; + } + + /** + * 递归查找指定 tagName 的元素 + */ + private static Element findElement(Node node, String tagName) { + if (node.getNodeType() == Node.ELEMENT_NODE && tagName.equals(node.getNodeName())) { + return (Element) node; + } + NodeList children = node.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Element result = findElement(children.item(i), tagName); + if (result != null) { + return result; + } + } + return null; + } + private static String getFileSuffix(String fileName) { int idx = fileName.lastIndexOf('.'); return idx == -1 ? "" : fileName.substring(idx + 1);