From e4c8ddb7b02d6500285672ac63f830316b21007d Mon Sep 17 00:00:00 2001 From: zhangxiongfeng Date: Wed, 5 Aug 2026 08:38:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A4=A7=E5=8D=8E=E5=8F=A3=E9=97=A8?= =?UTF-8?q?=E5=AF=B9=E6=8E=A51.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 65ad2b538e17143405490877880f2e62d3d596fb) --- .../zcloud/basic/info/command/UserAddExe.java | 56 ++++++++++++++++--- .../basic/info/command/UserRemoveExe.java | 4 +- .../basic/info/command/UserUpdateExe.java | 2 +- .../repository/impl/UserRepositoryImpl.java | 45 +++++++++++---- 4 files changed, 85 insertions(+), 22 deletions(-) diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java index 1535cb6f..33540242 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java @@ -89,7 +89,7 @@ public class UserAddExe { private final UserCorpRecordGateway userCorpRecordGateway; private ZcloudRedisUtil zcloudRedisUtil; private final UserCorpRecordRepository userCorpRecordRepository; - @DubboReference(check = false) + @DubboReference private UserFacade userFacade; // private final String sourceCode; // @Value("${seng.message:MS000087}") @@ -100,7 +100,7 @@ public class UserAddExe { private final UserExpandInfoRepository userExpandInfoRepository; private final ImgFilesRepository imgFilesRepository; private final DaHuaConfig daHuaConfig; - @DubboReference(version = "1.0.0", group = "primeport") + @DubboReference private ZcloudDaHuaFacade zcloudDaHuaFacade; @Transactional(rollbackFor = Exception.class) @@ -452,12 +452,41 @@ public class UserAddExe { if (plainIdCard != null && plainIdCard.length() >= 14) { maskedIdCard = plainIdCard.substring(0, 6) + "********" + plainIdCard.substring(plainIdCard.length() - 4); } - log.info("Dubbo调用primeport.zcloudDaHuaFacade.syncPerson, name={}, departmentId(corpId)={}, idCardMask={}", - cmd.getName(), cmd.getDepartmentId(), maskedIdCard); + log.info("========== 开始Dubbo调用primeport.zcloudDaHuaFacade.syncPerson =========="); + log.info("Dubbo调用参数: name={}, departmentId(corpId)={}, idCardMask={}, phone={}, code={}", + cmd.getName(), cmd.getDepartmentId(), maskedIdCard, cmd.getPhone(), cmd.getCode()); + log.info("Dubbo调用参数: paperType={}, departmentType={}, type={}, nation={}, nationName={}", + cmd.getPaperType(), cmd.getDepartmentType(), cmd.getType(), cmd.getNation(), cmd.getNationName()); if (cmd.getPersonBiosignatures() != null) { log.info("Dubbo调用携带人脸生物特征, size={}", cmd.getPersonBiosignatures().size()); + } else { + log.info("Dubbo调用未携带人脸生物特征"); + } + log.info("Dubbo调用 cmd对象完整打印: {}", JSONUtil.toJsonStr(cmd)); + + SingleResponse syncResp = null; + try { + log.info("即将执行 zcloudDaHuaFacade.syncPerson(cmd)..."); + syncResp = zcloudDaHuaFacade.syncPerson(cmd); + log.info("zcloudDaHuaFacade.syncPerson(cmd) 执行完成,已返回"); + } catch (Exception e) { + log.error("========== Dubbo调用primeport.zcloudDaHuaFacade.syncPerson 发生异常 ==========", e); + log.error("异常类型: {}", e.getClass().getName()); + log.error("异常信息: {}", e.getMessage()); + if (throwOnFail) { + throw new BizException("同步大华平台失败,Dubbo调用异常:" + e.getMessage()); + } else { + log.warn("同步大华平台Dubbo调用异常(不影响本地数据保存): {}", e.getMessage()); + return result; + } + } + + log.info("========== Dubbo调用返回结果 =========="); + log.info("返回对象: syncResp={}", syncResp); + if (syncResp != null) { + log.info("返回详情: success={}, errCode={}, errMessage={}, data={}", + syncResp.isSuccess(), syncResp.getErrCode(), syncResp.getErrMessage(), syncResp.getData()); } - SingleResponse syncResp = zcloudDaHuaFacade.syncPerson(cmd); result.setDahuaCode(plainIdCard); userE.setDahuaCode(plainIdCard); if (syncResp == null || !syncResp.isSuccess()) { @@ -476,7 +505,12 @@ public class UserAddExe { if (data != null) { if (data instanceof Map) { Map dataMap = (Map) data; - Object idObj = dataMap.get("id"); + log.info("大华返回data Map内容: {}", dataMap); + // primeport返回的是personId,不是id + Object idObj = dataMap.get("personId"); + if (idObj == null) { + idObj = dataMap.get("id"); + } if (idObj != null) { try { Integer dahuaId = Integer.valueOf(idObj.toString()); @@ -486,10 +520,16 @@ public class UserAddExe { } catch (Exception e) { log.warn("转换大华返回id为Integer失败, idObj={}", idObj); } + } else { + log.warn("大华返回数据中未找到personId或id字段, dataMap keys={}", dataMap.keySet()); } } else if (data instanceof cn.hutool.json.JSONObject) { cn.hutool.json.JSONObject dataJson = (cn.hutool.json.JSONObject) data; - Object idObj = dataJson.get("id"); + log.info("大华返回data JSONObject内容: {}", dataJson); + Object idObj = dataJson.get("personId"); + if (idObj == null) { + idObj = dataJson.get("id"); + } if (idObj != null) { try { Integer dahuaId = Integer.valueOf(idObj.toString()); @@ -499,6 +539,8 @@ public class UserAddExe { } catch (Exception e) { log.warn("转换大华返回id为Integer失败, idObj={}", idObj); } + } else { + log.warn("大华返回数据中未找到personId或id字段"); } } } diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java index 2b8aae97..f986fc0e 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserRemoveExe.java @@ -49,13 +49,13 @@ public class UserRemoveExe { private final UserChangeRecordGateway userChangeRecordGateway; private final UserJobHandoverRepository userJobHandoverRepository; private final HumanUserUpdateExe humanUserUpdateExe; - @DubboReference(check = false) + @DubboReference private UserFacade userFacade; // @Autowired private final ZcloudRedisUtil zcloudRedisUtil; private final UserCorpRecordRepository userCorpRecordRepository; private final DaHuaConfig daHuaConfig; - @DubboReference(version = "1.0.0", group = "primeport") + @DubboReference private ZcloudDaHuaFacade zcloudDaHuaFacade; @Transactional(rollbackFor = Exception.class) diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java index 72b1fc2a..c412ec1b 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java @@ -78,7 +78,7 @@ public class UserUpdateExe { @DubboReference private ZcloudRiskFacade zcloudRiskFacade; private final DaHuaConfig daHuaConfig; - @DubboReference(version = "1.0.0", group = "primeport") + @DubboReference private ZcloudDaHuaFacade zcloudDaHuaFacade; diff --git a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java index 8205737c..d38f7f52 100644 --- a/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java +++ b/web-infrastructure/src/main/java/com/zcloud/basic/info/persistence/repository/impl/UserRepositoryImpl.java @@ -355,11 +355,23 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i roleDeptAddCmd.setDeptId(userDO.getDepartmentId()); List roleDeptAddCmdList = Collections.singletonList(roleDeptAddCmd); userAddCmd.setRoleDepts(roleDeptAddCmdList); - log.info("GBS新增用户开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); + + // 打印详细参数,方便排查底座报错原因 + log.info("【普通用户-底座新增】开始"); + log.info("【普通用户-底座新增】参数详情: account={}, name={}, password={}, tenantId(corpinfoId)={}, roleId={}, departmentId={}", + userAddCmd.getAccount(), userAddCmd.getName(), + userDO.getPassword() != null ? "已设置(长度:" + userDO.getPassword().length() + ")" : "null", + userDO.getCorpinfoId(), userDO.getRoleId(), userDO.getDepartmentId()); + log.info("【普通用户-底座新增】完整JSON: {}", JSONUtil.toJsonStr(userAddCmd)); + log.info("【普通用户-底座新增】userDO完整JSON: {}", JSONUtil.toJsonStr(userDO)); + SingleResponse gbsResult = userFacade.add(userAddCmd); - log.info("GBS新增用户结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); + log.info("【普通用户-底座新增】结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); if (!gbsResult.isSuccess()) { - throw new RuntimeException("GBS新增用户失败,用户id:" + gbsResult.getData()); + String errMsg = String.format("【普通用户-底座新增失败】errCode=%s, errMessage=%s, 用户id=%s", + gbsResult.getErrCode(), gbsResult.getErrMessage(), gbsResult.getData()); + log.error(errMsg); + throw new RuntimeException(errMsg); } userDO.setId(gbsResult.getData()); if (userDO.getSort() == null) { @@ -386,11 +398,14 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i roleDeptAddCmd.setDeptId(userDO.getDepartmentId()); List roleDeptAddCmdList = Collections.singletonList(roleDeptAddCmd); userAddCmd.setRoleDepts(roleDeptAddCmdList); - log.info("GBS新增用户开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); + log.info("【演示用户-底座新增】开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); SingleResponse gbsResult = userFacade.add(userAddCmd); - log.info("GBS新增用户结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); + log.info("【演示用户-底座新增】结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); if (!gbsResult.isSuccess()) { - throw new RuntimeException("GBS新增用户失败,用户id:" + gbsResult.getData()); + String errMsg = String.format("【演示用户-底座新增失败】errCode=%s, errMessage=%s, 用户id=%s", + gbsResult.getErrCode(), gbsResult.getErrMessage(), gbsResult.getData()); + log.error(errMsg); + throw new RuntimeException(errMsg); } userDO.setId(gbsResult.getData()); if (userDO.getSort() == null) { @@ -455,11 +470,14 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i userAddCmd.setRoleDepts(roleDeptAddCmdList); userAddCmd.setId(userDO.getId()); userAddCmd.setPassword(userDO.getPassword()); - log.info("GBS新增用户开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); + log.info("【相关方用户-底座新增】开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); SingleResponse gbsResult = userFacade.add(userAddCmd); - log.info("GBS新增用户结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); + log.info("【相关方用户-底座新增】结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); if (!gbsResult.isSuccess()) { - throw new RuntimeException("GBS新增用户失败,用户id:" + gbsResult.getData()); + String errMsg = String.format("【相关方用户-底座新增失败】errCode=%s, errMessage=%s, 用户id=%s", + gbsResult.getErrCode(), gbsResult.getErrMessage(), gbsResult.getData()); + log.error(errMsg); + throw new RuntimeException(errMsg); } } @@ -772,11 +790,14 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i List roleDeptAddCmdList = Collections.singletonList(roleDeptAddCmd); userAddCmd.setRoleDepts(roleDeptAddCmdList); userAddCmd.setId(userE.getId()); - log.info("GBS新增用户开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); + log.info("【用户恢复入职-底座新增】开始,用户信息:{}", JSONUtil.toJsonStr(userAddCmd)); SingleResponse gbsResult = userFacade.add(userAddCmd); - log.info("GBS新增用户结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); + log.info("【用户恢复入职-底座新增】结束,用户id:{},结果:{}", gbsResult.getData(), JSONUtil.toJsonStr(gbsResult)); if (!gbsResult.isSuccess()) { - throw new RuntimeException("GBS新增用户失败,用户id:" + gbsResult.getData()); + String errMsg = String.format("【用户恢复入职-底座新增失败】errCode=%s, errMessage=%s, 用户id=%s", + gbsResult.getErrCode(), gbsResult.getErrMessage(), gbsResult.getData()); + log.error(errMsg); + throw new RuntimeException(errMsg); } } } From af5c37decff157f45c55d5636450258a7e6fdf74 Mon Sep 17 00:00:00 2001 From: zhangxiongfeng Date: Tue, 11 Aug 2026 18:52:59 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BA=BA=E5=91=98=E5=8F=98=E5=8A=A8?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=A4=A7=E5=8D=8E=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zcloud/basic/info/web/UserController.java | 3 +- .../zcloud/basic/info/command/UserAddExe.java | 88 +++- .../basic/info/command/UserUpdateExe.java | 443 +++++++++++++++++- .../basic/info/service/UserServiceImpl.java | 2 + 4 files changed, 490 insertions(+), 46 deletions(-) diff --git a/web-adapter/src/main/java/com/zcloud/basic/info/web/UserController.java b/web-adapter/src/main/java/com/zcloud/basic/info/web/UserController.java index fe2be1d0..e10afe78 100644 --- a/web-adapter/src/main/java/com/zcloud/basic/info/web/UserController.java +++ b/web-adapter/src/main/java/com/zcloud/basic/info/web/UserController.java @@ -200,5 +200,4 @@ public class UserController { return userService.getUserIdByPhone(getUserIdByPhoneCmd); } -} - +} \ No newline at end of file diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java index ec82ee92..000c4412 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java @@ -102,14 +102,12 @@ public class UserAddExe { private final DaHuaConfig daHuaConfig; @DubboReference private ZcloudDaHuaFacade zcloudDaHuaFacade; - - @Transactional(rollbackFor = Exception.class) public boolean execute(UserAddCmd cmd) { - Boolean b = corpInfoQueryExe.verifyCorpInfo(); + Thread.dumpStack(); + Boolean b = corpInfoQueryExe.verifyCorpInfo(); if (!b) { throw new BizException("请先完善企业信息"); } - log.info("开始新增用户,name: {}, corpinfoId: {}, phone: {}", cmd.getName(), cmd.getCorpinfoId(), cmd.getPhone()); try { ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attrs != null) { @@ -184,6 +182,7 @@ public class UserAddExe { } userE.setRoleId(roleId); } + try { userE.setUserType(CorpTypeEnum.getUserTypeByCode(corpInfoDO.getType())); @@ -203,22 +202,74 @@ public class UserAddExe { } catch (Exception e) { log.error("用户变更记录保存失败(不影响用户主体), userId: {}, error: {}", userE.getId(), e.getMessage(), e); } - DaHuaSyncResult syncResult = syncDaHuaPerson(userE); - if (syncResult.dahuaId != null) { + log.info("========== 新增用户-开始查询大华是否已存在该人员 =========="); + Integer queryDahuaId = null; + String queryDahuaCode = null; + String plainIdCard = userE.getUserIdCard(); + if (plainIdCard != null && !plainIdCard.trim().isEmpty()) { try { - UserE updateDahua = new UserE(); - updateDahua.setId(userE.getId()); - updateDahua.setDahuaId(syncResult.dahuaId); - updateDahua.setDahuaCode(syncResult.dahuaCode); - userRepository.updateDahuaInfo(updateDahua.getId(), updateDahua.getDahuaId(), updateDahua.getDahuaCode()); - log.info("写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}", - userE.getId(), syncResult.dahuaId, syncResult.dahuaCode); + byte[] decodedBytes = Base64.getDecoder().decode(plainIdCard.trim()); + plainIdCard = new String(decodedBytes, StandardCharsets.UTF_8); + } catch (Exception e) { + log.warn("身份证号非Base64格式,按原值处理: {}", plainIdCard); + } + } + log.info("查询大华入参paperNumber(身份证号明文): {}", plainIdCard); + SingleResponse> queryResp = null; + try { + queryResp = zcloudDaHuaFacade.findPersonByPaperNumber(plainIdCard); + log.info("查询大华人员返回完整结果: {}", JSONUtil.toJsonStr(queryResp)); + } catch (Exception e) { + log.error("查询大华人员异常(不影响本地新增), paperNumber={}", plainIdCard, e); + } + if (queryResp != null && queryResp.isSuccess() && queryResp.getData() != null) { + Map dataMap = queryResp.getData(); + Object idObj = dataMap.get("id"); + Object codeObj = dataMap.get("code"); + if (idObj == null && codeObj == null) { + Object innerDataObj = dataMap.get("data"); + if (innerDataObj instanceof Map) { + Map innerData = (Map) innerDataObj; + idObj = innerData.get("id"); + codeObj = innerData.get("code"); + } + } + if (idObj != null) { + queryDahuaId = Integer.valueOf(idObj.toString()); + } + if (codeObj != null) { + queryDahuaCode = codeObj.toString(); + } + } + if (queryDahuaId != null) { + userE.setDahuaId(queryDahuaId); + userE.setDahuaCode(queryDahuaCode); + try { + userRepository.updateDahuaInfo(userE.getId(), queryDahuaId, queryDahuaCode); + log.info("大华已存在该人员,跳过大华新增,直接写回 dahuaId={}, dahuaCode={}, userId={}", queryDahuaId, queryDahuaCode, userE.getId()); } catch (Exception e) { log.error("写回dahuaId/dahuaCode失败(不影响本地数据), userId={}, dahuaId={}, dahuaCode={}", - userE.getId(), syncResult.dahuaId, syncResult.dahuaCode, e); + userE.getId(), queryDahuaId, queryDahuaCode, e); } } else { - log.info("大华同步未返回dahuaId,跳过写回操作, userId={}, dahuaCode={}", userE.getId(), syncResult.dahuaCode); + log.info("大华未找到该人员,开始执行 syncDaHuaPerson 新增大华人员"); + DaHuaSyncResult syncResult = syncDaHuaPerson(userE); + if (syncResult.dahuaId != null) { + try { + UserE updateDahua = new UserE(); + updateDahua.setId(userE.getId()); + updateDahua.setDahuaId(syncResult.dahuaId); + updateDahua.setDahuaCode(syncResult.dahuaCode); + userRepository.updateDahuaInfo(updateDahua.getId(), updateDahua.getDahuaId(), updateDahua.getDahuaCode()); + log.info("写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}", + userE.getId(), syncResult.dahuaId, syncResult.dahuaCode); + } catch (Exception e) { + log.error("写回dahuaId/dahuaCode失败(不影响本地数据), userId={}, dahuaId={}, dahuaCode={}", + userE.getId(), syncResult.dahuaId, syncResult.dahuaCode, e); + } + } else { + log.info("大华同步未返回dahuaId,跳过写回操作, userId={}, dahuaCode={}", userE.getId(), syncResult.dahuaCode); + } } } catch (BizException e) { log.error("新增用户业务异常: {}", e.getMessage(), e); @@ -436,11 +487,6 @@ public class UserAddExe { DaHuaSyncResult result = new DaHuaSyncResult(); result.setDahuaCode(plainIdCard); - if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) { - log.info("大华对接未开启(dockFlag={}), 跳过同步人员到大华", daHuaConfig.getDockFlag()); - userE.setDahuaCode(plainIdCard); - return result; - } DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); Object biosObj = personMap.get("personBiosignatures"); @@ -453,7 +499,7 @@ public class UserAddExe { if (plainIdCard != null && plainIdCard.length() >= 14) { maskedIdCard = plainIdCard.substring(0, 6) + "********" + plainIdCard.substring(plainIdCard.length() - 4); } - log.info("========== 开始Dubbo调用primeport.zcloudDaHuaFacade.syncPerson =========="); + log.info("========== 开始Dubbo222调用primeport.zcloudDaHuaFacade.syncPerson =========="); log.info("Dubbo调用参数: name={}, departmentId(corpId)={}, idCardMask={}, phone={}, code={}", cmd.getName(), cmd.getDepartmentId(), maskedIdCard, cmd.getPhone(), cmd.getCode()); log.info("Dubbo调用参数: paperType={}, departmentType={}, type={}, nation={}, nationName={}", diff --git a/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java b/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java index f8751f88..8599a7fd 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java +++ b/web-app/src/main/java/com/zcloud/basic/info/command/UserUpdateExe.java @@ -40,6 +40,11 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import java.nio.charset.StandardCharsets; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Period; @@ -98,7 +103,74 @@ public class UserUpdateExe { userE.setDahuaCode(userDO.getDahuaCode()); log.info("【getInfoById查询结果】dahuaId={}, dahuaCode={}, name={}, userIdCard={}", userDO.getDahuaId(), userDO.getDahuaCode(), userDO.getName(), userDO.getUserIdCard()); - syncDaHuaPersonUpdate(userUpdateCmd, userDO); + + String newIdCardForQuery = userUpdateCmd.getUserIdCard() != null ? userUpdateCmd.getUserIdCard() : userDO.getUserIdCard(); + String plainIdCardForQuery = newIdCardForQuery; + if (newIdCardForQuery != null && !newIdCardForQuery.trim().isEmpty()) { + try { + byte[] decodedBytes = Base64.getDecoder().decode(newIdCardForQuery.trim()); + plainIdCardForQuery = new String(decodedBytes, StandardCharsets.UTF_8); + } catch (Exception e) { + log.warn("身份证号非Base64格式,按原值处理: {}", newIdCardForQuery); + } + } + + boolean dahuaPersonFound = false; + log.info("修改前查询大华人员入参paperNumber(身份证号明文): {}", plainIdCardForQuery); + Integer queryDahuaId = null; + String queryDahuaCode = null; + SingleResponse> queryResp = null; + try { + log.info("调用大华Dubbo接口: zcloudDaHuaFacade.findPersonByPaperNumber, 参数paperNumber={}", plainIdCardForQuery); + queryResp = zcloudDaHuaFacade.findPersonByPaperNumber(plainIdCardForQuery); + log.info("修改前查询大华人员返回完整结果: {}", JSONUtil.toJsonStr(queryResp)); + } catch (Exception e) { + log.error("修改前查询大华人员异常(不影响本地修改), paperNumber={}", plainIdCardForQuery, e); + } + if (queryResp != null && queryResp.isSuccess() && queryResp.getData() != null) { + Map dataMap = queryResp.getData(); + log.info("修改前查询大华返回data: {}", dataMap); + Object idObj = dataMap.get("id"); + Object codeObj = dataMap.get("code"); + if (idObj == null && codeObj == null) { + Object innerDataObj = dataMap.get("data"); + if (innerDataObj instanceof Map) { + Map innerData = (Map) innerDataObj; + idObj = innerData.get("id"); + codeObj = innerData.get("code"); + } + } + if (idObj != null) { + queryDahuaId = Integer.valueOf(idObj.toString()); + } + if (codeObj != null) { + queryDahuaCode = codeObj.toString(); + } + if (queryDahuaId != null) { + dahuaPersonFound = true; + userDO.setDahuaId(queryDahuaId); + userDO.setDahuaCode(queryDahuaCode); + userE.setDahuaId(queryDahuaId); + userE.setDahuaCode(queryDahuaCode); + log.info("修改前查询大华已存在该人员, dahuaId={}, dahuaCode={}, 走更新逻辑", queryDahuaId, queryDahuaCode); + } else { + log.info("修改前查询大华返回中无id字段,视为不存在, dataMap={}", dataMap); + } + } else { + log.info("修改前查询大华结果为null或失败,视为不存在, queryResp={}", queryResp); + } + + if (!dahuaPersonFound) { + log.info("修改前查询大华未找到该人员, 走新增逻辑, paperNumber={}", plainIdCardForQuery); + Integer addDahuaId = syncDaHuaPersonAdd(userUpdateCmd, userDO, userE); + if (addDahuaId != null) { + log.info("修改前新增大华人员成功, dahuaId={}, dahuaCode={}", userE.getDahuaId(), userE.getDahuaCode()); + } else { + log.info("修改前新增大华人员未获取到dahuaId/dahuaCode,仍继续本地修改"); + } + } else { + syncDaHuaPersonUpdate(userUpdateCmd, userDO); + } UserE oldUserE = new UserE(); BeanUtils.copyProperties(userDO, oldUserE); @@ -353,22 +425,34 @@ public class UserUpdateExe { if (singleObj instanceof Map) { Map faceFileMap = (Map) singleObj; Object thumbUrlObj = faceFileMap.get("thumbUrl"); - if (thumbUrlObj != null) { + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { return thumbUrlObj.toString(); } + Object urlObj = faceFileMap.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } } else if (singleObj instanceof cn.hutool.json.JSONObject) { cn.hutool.json.JSONObject faceJson = (cn.hutool.json.JSONObject) singleObj; Object thumbUrlObj = faceJson.get("thumbUrl"); - if (thumbUrlObj != null) { + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { return thumbUrlObj.toString(); } + Object urlObj = faceJson.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } } else { try { cn.hutool.json.JSONObject faceJson = cn.hutool.json.JSONUtil.parseObj(singleObj); Object thumbUrlObj = faceJson.get("thumbUrl"); - if (thumbUrlObj != null) { + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { return thumbUrlObj.toString(); } + Object urlObj = faceJson.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } } catch (Exception e) { log.warn("解析单个图片对象为JSON失败: {}", e.getMessage()); } @@ -411,29 +495,33 @@ public class UserUpdateExe { if (thumbUrl != null && !thumbUrl.trim().isEmpty()) { String trimmedThumb = thumbUrl.trim(); boolean startsWithHttp = trimmedThumb.startsWith("http://") || trimmedThumb.startsWith("https://"); - boolean containsComma = trimmedThumb.contains(","); - boolean startsWithDataImage = trimmedThumb.startsWith("data:image"); + String cleanBase64 = null; - String cleanBase64; - if (containsComma && startsWithDataImage) { - String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1); - String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1); - String cleanBody = bodyPart.replaceAll("\\s+", ""); - cleanBase64 = prefixPart + cleanBody; + if (startsWithHttp) { + log.info("同步大华人员(更新):人脸为HTTP URL,开始下载转base64, url={}", trimmedThumb); + cleanBase64 = downloadImageToBase64(trimmedThumb); + log.info("同步大华人员(更新):URL下载转base64完成, base64长度={}", cleanBase64 == null ? 0 : cleanBase64.length()); } else { - String pureBody = trimmedThumb.replaceAll("\\s+", ""); - cleanBase64 = "data:image/jpeg;base64," + pureBody; + boolean containsComma = trimmedThumb.contains(","); + boolean startsWithDataImage = trimmedThumb.startsWith("data:image"); + if (containsComma && startsWithDataImage) { + String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1); + String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1); + String cleanBody = bodyPart.replaceAll("\\s+", ""); + cleanBase64 = prefixPart + cleanBody; + } else { + String pureBody = trimmedThumb.replaceAll("\\s+", ""); + cleanBase64 = "data:image/jpeg;base64," + pureBody; + } } + int commaIdx = cleanBase64.indexOf(","); String base64BodyOnly = commaIdx >= 0 ? cleanBase64.substring(commaIdx + 1) : cleanBase64; boolean isLikelyBase64 = base64BodyOnly.matches("^[A-Za-z0-9+/=]+$"); int bodyLen = base64BodyOnly.length(); boolean finalHasPrefix = cleanBase64.startsWith("data:image"); - if (startsWithHttp) { - log.error("同步大华人员(更新)失败:人脸图片传的是HTTP/HTTPS URL,要求必须传带data:image前缀的base64图片"); - throw new BizException("同步大华平台失败:人脸图片不支持URL格式,请上传图片文件"); - } else if (!finalHasPrefix) { + if (!finalHasPrefix) { log.error("同步大华人员(更新)失败:人脸图片最终无data:image前缀,代码补齐逻辑失效"); throw new BizException("同步大华平台失败:人脸图片格式异常"); } else if (!isLikelyBase64) { @@ -453,11 +541,6 @@ public class UserUpdateExe { personMap.put("personBiosignatures", personBiosignatures); } - if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) { - log.info("大华对接未开启(dockFlag={}), 跳过更新大华人员", daHuaConfig.getDockFlag()); - return; - } - DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); Object biosObj = personMap.get("personBiosignatures"); if (biosObj instanceof List) { @@ -489,6 +572,255 @@ public class UserUpdateExe { } } + private Integer syncDaHuaPersonAdd(UserUpdateCmd userUpdateCmd, UserDO userDO, UserE userE) { + log.info("========== 大华人员(新增)检查开始 =========="); + log.info("用户主键userDO.id={}, name={}, userIdCard={}", + userDO.getId(), userDO.getName(), userDO.getUserIdCard()); + + String newName = userUpdateCmd.getName() != null ? userUpdateCmd.getName() : userDO.getName(); + String newIdCard = userUpdateCmd.getUserIdCard() != null ? userUpdateCmd.getUserIdCard() : userDO.getUserIdCard(); + String newPhone = userUpdateCmd.getPhone() != null ? userUpdateCmd.getPhone() : userDO.getPhone(); + String newNation = userUpdateCmd.getNation() != null ? userUpdateCmd.getNation() : userDO.getNation(); + String newNationName = userUpdateCmd.getNationName() != null ? userUpdateCmd.getNationName() : userDO.getNationName(); + Object newFaceFile = userUpdateCmd.getUserImg() != null ? userUpdateCmd.getUserImg() : userUpdateCmd.getFaceFile(); + Long newCorpId = userUpdateCmd.getCorpinfoId() != null ? userUpdateCmd.getCorpinfoId() : userDO.getCorpinfoId(); + + String plainIdCard = newIdCard; + if (newIdCard != null && !newIdCard.trim().isEmpty()) { + try { + byte[] decodedBytes = Base64.getDecoder().decode(newIdCard.trim()); + plainIdCard = new String(decodedBytes, StandardCharsets.UTF_8); + } catch (Exception e) { + log.warn("身份证号非Base64格式,按原值处理: {}", newIdCard); + } + } + + Map personMap = new HashMap<>(); + personMap.put("name", newName); + personMap.put("code", plainIdCard); + personMap.put("paperType", 111); + personMap.put("paperNumber", plainIdCard); + personMap.put("phone", newPhone); + Long realCorpId = newCorpId != null ? newCorpId : 1L; + personMap.put("departmentId", realCorpId); + personMap.put("departmentType", 2); + personMap.put("type", 3); + personMap.put("nationName", newNationName != null && !newNationName.trim().isEmpty() ? newNationName : "汉族"); + try { + if (newNation != null && !newNation.trim().isEmpty()) { + personMap.put("nation", Integer.parseInt(newNation.trim())); + } else { + personMap.put("nation", 1); + } + } catch (Exception e) { + log.warn("民族编码转Integer失败: {}, 用默认值1(汉族)", newNation); + personMap.put("nation", 1); + } + personMap.put("service", "evo-thirdParty"); + + Integer age = null; + Integer sex = null; + if (plainIdCard != null && plainIdCard.length() == 18) { + try { + String birthStr = plainIdCard.substring(6, 14); + LocalDate birthDate = LocalDate.parse(birthStr, DateTimeFormatter.ofPattern("yyyyMMdd")); + age = Period.between(birthDate, LocalDate.now()).getYears(); + String sexChar = plainIdCard.substring(16, 17); + int sexNum = Integer.parseInt(sexChar); + sex = sexNum % 2 == 0 ? 2 : 1; + } catch (Exception e) { + log.warn("从身份证号解析年龄/性别失败, idCard={}", plainIdCard); + } + } + personMap.put("age", age); + personMap.put("sex", sex); + + Object faceFile = newFaceFile; + java.util.function.Function extractThumbFromSingle = (singleObj) -> { + if (singleObj == null) { + return null; + } + if (singleObj instanceof Map) { + Map faceFileMap = (Map) singleObj; + Object thumbUrlObj = faceFileMap.get("thumbUrl"); + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { + return thumbUrlObj.toString(); + } + Object urlObj = faceFileMap.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } + } else if (singleObj instanceof cn.hutool.json.JSONObject) { + cn.hutool.json.JSONObject faceJson = (cn.hutool.json.JSONObject) singleObj; + Object thumbUrlObj = faceJson.get("thumbUrl"); + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { + return thumbUrlObj.toString(); + } + Object urlObj = faceJson.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } + } else { + try { + cn.hutool.json.JSONObject faceJson = cn.hutool.json.JSONUtil.parseObj(singleObj); + Object thumbUrlObj = faceJson.get("thumbUrl"); + if (thumbUrlObj != null && !thumbUrlObj.toString().trim().isEmpty()) { + return thumbUrlObj.toString(); + } + Object urlObj = faceJson.get("url"); + if (urlObj != null && !urlObj.toString().trim().isEmpty()) { + return urlObj.toString().trim().replaceAll("^`+|`+$", ""); + } + } catch (Exception e) { + log.warn("解析单个图片对象为JSON失败: {}", e.getMessage()); + } + } + return null; + }; + + String thumbUrl = null; + if (faceFile != null) { + boolean isArray = false; + Object firstElement = null; + if (faceFile instanceof java.util.Collection) { + isArray = true; + java.util.Collection coll = (java.util.Collection) faceFile; + if (!coll.isEmpty()) { + firstElement = coll.iterator().next(); + } + } else if (faceFile.getClass().isArray()) { + isArray = true; + Object[] arr = (Object[]) faceFile; + if (arr.length > 0) { + firstElement = arr[0]; + } + } else if (faceFile instanceof cn.hutool.json.JSONArray) { + isArray = true; + cn.hutool.json.JSONArray jsonArr = (cn.hutool.json.JSONArray) faceFile; + if (!jsonArr.isEmpty()) { + firstElement = jsonArr.get(0); + } + } + if (isArray) { + if (firstElement != null) { + thumbUrl = extractThumbFromSingle.apply(firstElement); + } + } else { + thumbUrl = extractThumbFromSingle.apply(faceFile); + } + } + + if (thumbUrl != null && !thumbUrl.trim().isEmpty()) { + String trimmedThumb = thumbUrl.trim(); + boolean startsWithHttp = trimmedThumb.startsWith("http://") || trimmedThumb.startsWith("https://"); + String cleanBase64 = null; + + if (startsWithHttp) { + log.info("同步大华人员(新增):人脸为HTTP URL,开始下载转base64, url={}", trimmedThumb); + cleanBase64 = downloadImageToBase64(trimmedThumb); + log.info("同步大华人员(新增):URL下载转base64完成, base64长度={}", cleanBase64 == null ? 0 : cleanBase64.length()); + } else { + boolean startsWithDataImage = trimmedThumb.startsWith("data:image"); + if (trimmedThumb.contains(",") && startsWithDataImage) { + String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1); + String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1); + String cleanBody = bodyPart.replaceAll("\\s+", ""); + cleanBase64 = prefixPart + cleanBody; + } else { + String pureBody = trimmedThumb.replaceAll("\\s+", ""); + cleanBase64 = "data:image/jpeg;base64," + pureBody; + } + } + + int commaIdx = cleanBase64.indexOf(","); + String base64BodyOnly = commaIdx >= 0 ? cleanBase64.substring(commaIdx + 1) : cleanBase64; + boolean isLikelyBase64 = base64BodyOnly.matches("^[A-Za-z0-9+/=]+$"); + int bodyLen = base64BodyOnly.length(); + boolean finalHasPrefix = cleanBase64.startsWith("data:image"); + + if (finalHasPrefix && isLikelyBase64 && bodyLen >= 1000) { + List personBiosignatures = new ArrayList<>(); + DaHuaPersonSyncCmd.PersonBiosignature biosignature = new DaHuaPersonSyncCmd.PersonBiosignature(); + biosignature.setType(3); + biosignature.setIndex(1); + biosignature.setBase64Data(cleanBase64); + personBiosignatures.add(biosignature); + personMap.put("personBiosignatures", personBiosignatures); + } else { + log.warn("同步大华人员(新增):人脸图片校验不通过,放弃传人脸, finalHasPrefix={}, isLikelyBase64={}, bodyLen={}", + finalHasPrefix, isLikelyBase64, bodyLen); + } + } + + DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); + Object biosObj = personMap.get("personBiosignatures"); + if (biosObj instanceof List) { + @SuppressWarnings("unchecked") + List bioList = (List) biosObj; + cmd.setPersonBiosignatures(bioList); + } + String maskedIdCard = plainIdCard; + if (plainIdCard != null && plainIdCard.length() >= 14) { + maskedIdCard = plainIdCard.substring(0, 6) + "********" + plainIdCard.substring(plainIdCard.length() - 4); + } + log.info("Dubbo调用primeport.zcloudDaHuaFacade.syncPerson(新增), name={}, departmentId(corpId)={}, idCardMask={}", + cmd.getName(), cmd.getDepartmentId(), maskedIdCard); + if (cmd.getPersonBiosignatures() != null) { + log.info("Dubbo调用新增大华人员携带人脸生物特征, size={}", cmd.getPersonBiosignatures().size()); + } + try { + SingleResponse syncResp = zcloudDaHuaFacade.syncPerson(cmd); + if (syncResp == null || !syncResp.isSuccess()) { + String errCode = syncResp == null ? "" : syncResp.getErrCode(); + String errMessage = syncResp == null ? "大华Dubbo返回为空" : syncResp.getErrMessage(); + if (errMessage == null || errMessage.trim().isEmpty()) errMessage = "大华人员新增失败"; + log.warn("新增大华人员失败(不影响本地修改), errCode={}, errMessage={}, name={}, idCard={}", errCode, errMessage, newName, maskedIdCard); + return null; + } + log.info("新增大华人员成功, name={}, idCard={}", newName, maskedIdCard); + Object data = syncResp.getData(); + if (data != null) { + Integer dahuaId = null; + if (data instanceof Map) { + Map dataMap = (Map) data; + Object idObj = dataMap.get("personId"); + if (idObj == null) { + idObj = dataMap.get("id"); + } + if (idObj != null) { + dahuaId = Integer.valueOf(idObj.toString()); + } + } else if (data instanceof cn.hutool.json.JSONObject) { + cn.hutool.json.JSONObject dataJson = (cn.hutool.json.JSONObject) data; + Object idObj = dataJson.get("personId"); + if (idObj == null) { + idObj = dataJson.get("id"); + } + if (idObj != null) { + dahuaId = Integer.valueOf(idObj.toString()); + } + } + if (dahuaId != null) { + String dahuaCode = plainIdCard; + userRepository.updateDahuaInfo(userDO.getId(), dahuaId, dahuaCode); + userDO.setDahuaId(dahuaId); + userDO.setDahuaCode(dahuaCode); + userE.setDahuaId(dahuaId); + userE.setDahuaCode(dahuaCode); + log.info("新增大华人员后写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}", + userDO.getId(), dahuaId, dahuaCode); + return dahuaId; + } else { + log.warn("新增大华人员成功但未获取到dahuaId, data={}", data); + } + } + return null; + } catch (Exception e) { + log.error("新增大华人员异常(不影响本地修改), name={}, idCard={}", newName, maskedIdCard, e); + return null; + } + } + @Transactional(rollbackFor = Exception.class) public void editData(UserQryCmd userUpdateCmd) { List userDOList = new ArrayList<>(); @@ -1115,4 +1447,69 @@ public class UserUpdateExe { } + private static String downloadImageToBase64(String urlStr) { + if (urlStr == null || urlStr.trim().isEmpty()) { + throw new BizException("同步大华平台失败:人脸图片URL为空"); + } + String cleanUrl = urlStr.trim().replaceAll("^`+|`+$", ""); + HttpURLConnection conn = null; + InputStream in = null; + try { + URL url = new URL(cleanUrl); + conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(15000); + conn.setReadTimeout(30000); + conn.setRequestMethod("GET"); + conn.setRequestProperty("User-Agent", "Mozilla/5.0 ZCloudGBS"); + int respCode = conn.getResponseCode(); + if (respCode < 200 || respCode >= 300) { + log.error("下载人脸图片失败, HTTP状态码={}, url={}", respCode, cleanUrl); + throw new BizException("同步大华平台失败:人脸图片下载失败(HTTP " + respCode + ")"); + } + String contentType = conn.getContentType(); + in = conn.getInputStream(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[8192]; + int len; + while ((len = in.read(buf)) != -1) { + baos.write(buf, 0, len); + } + byte[] imgBytes = baos.toByteArray(); + if (imgBytes == null || imgBytes.length < 1000) { + log.error("下载人脸图片失败, 文件过小({}字节), url={}", imgBytes == null ? 0 : imgBytes.length, cleanUrl); + throw new BizException("同步大华平台失败:人脸图片下载不完整"); + } + String imgType = "jpeg"; + if (contentType != null) { + String ct = contentType.toLowerCase(); + if (ct.contains("image/png")) { + imgType = "png"; + } else if (ct.contains("image/jpg") || ct.contains("image/jpeg")) { + imgType = "jpeg"; + } else if (ct.contains("image/gif")) { + imgType = "gif"; + } else if (ct.contains("image/webp")) { + imgType = "webp"; + } else if (ct.contains("image/bmp")) { + imgType = "bmp"; + } + } + String base64Body = Base64.getEncoder().encodeToString(imgBytes); + return "data:image/" + imgType + ";base64," + base64Body; + } catch (BizException e) { + throw e; + } catch (Exception e) { + log.error("下载人脸图片异常, url={}", cleanUrl, e); + throw new BizException("同步大华平台失败:人脸图片下载异常(" + e.getMessage() + ")"); + } finally { + if (in != null) { + try { in.close(); } catch (Exception ignore) {} + } + if (conn != null) { + try { conn.disconnect(); } catch (Exception ignore) {} + } + } + } + + } \ No newline at end of file diff --git a/web-app/src/main/java/com/zcloud/basic/info/service/UserServiceImpl.java b/web-app/src/main/java/com/zcloud/basic/info/service/UserServiceImpl.java index 12c089f4..3c97c73a 100644 --- a/web-app/src/main/java/com/zcloud/basic/info/service/UserServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/basic/info/service/UserServiceImpl.java @@ -12,6 +12,7 @@ import com.zcloud.basic.info.dto.clientobject.*; import com.zcloud.basic.info.persistence.dataobject.UserImgDO; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; @@ -41,6 +42,7 @@ public class UserServiceImpl implements UserServiceI { } @Override + @Transactional(rollbackFor = Exception.class) public SingleResponse add(UserAddCmd cmd) { userAddExe.execute(cmd);