diff --git a/start/src/main/resources/sdk-prod.yml b/start/src/main/resources/sdk-prod.yml index 2df165e7..58279645 100644 --- a/start/src/main/resources/sdk-prod.yml +++ b/start/src/main/resources/sdk-prod.yml @@ -67,4 +67,7 @@ dahua: primeportGateway: primeport nine: config: - companyId: 2008712261453131776,2046785341004177408 \ No newline at end of file + companyId: 2008712261453131776,2046785341004177408 +file: + upload: + url: https://jpfz.qhdsafety.com/gbsFileTest/ \ No newline at end of file diff --git a/start/src/main/resources/sdk-prod2.yml b/start/src/main/resources/sdk-prod2.yml index 0e4f891e..d4bf879b 100644 --- a/start/src/main/resources/sdk-prod2.yml +++ b/start/src/main/resources/sdk-prod2.yml @@ -66,4 +66,7 @@ dahua: clientSecret: 5ef82f7c-9926-46a3-8d07-136fd054849c nine: config: - companyId: 2590800828822460065,2044322367672422400 \ No newline at end of file + companyId: 2590800828822460065,2044322367672422400 +file: + upload: + url: http://192.168.192.201:8992/file/uploadFiles2/ \ 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 f5d3cb8e..76bae264 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 @@ -513,8 +513,7 @@ public class UserAddExe { } else { log.info("Dubbo调用未携带人脸生物特征"); } - log.info("Dubbo调用 cmd对象完整打印: {}", JSONUtil.toJsonStr(cmd)); - + SingleResponse syncResp = null; try { log.info("即将执行 zcloudDaHuaFacade.syncPerson(cmd)..."); 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 8599a7fd..fb834a4a 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 @@ -31,10 +31,11 @@ import com.zcloud.gbscommon.zcloudhidden.request.HiddenStatisticsListQry; import com.zcloud.gbscommon.zcloudhidden.request.HiddenUpdateCmd; import com.zcloud.gbscommon.zcloudhidden.response.HiddenListByUserCO; import com.zcloud.gbscommon.zcloudrisk.facade.ZcloudRiskFacade; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; @@ -61,9 +62,16 @@ import java.util.stream.Collectors; * @Date 2025-11-04 14:07:38 */ @Component -@AllArgsConstructor +@RequiredArgsConstructor @Slf4j public class UserUpdateExe { + private static final Set DAHUA_CORP_TYPE_CODES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + CorpTypeEnum.OrdinaryEnterprises.getCode(), + CorpTypeEnum.groupUnits.getCode(), + CorpTypeEnum.share.getCode(), + CorpTypeEnum.materialCenter.getCode() + ))); + private final UserGateway userGateway; private final UserRepository userRepository; @@ -77,7 +85,7 @@ public class UserUpdateExe { private final UserJobHandoverRepository userJobHandoverRepository; @DubboReference private UserFacade userFacade; - private ZcloudRedisUtil zcloudRedisUtil; + private final ZcloudRedisUtil zcloudRedisUtil; @DubboReference private ZcloudHiddenFacade zcloudHiddenFacade; @DubboReference @@ -85,7 +93,8 @@ public class UserUpdateExe { private final DaHuaConfig daHuaConfig; @DubboReference private ZcloudDaHuaFacade zcloudDaHuaFacade; - + @Value("${file.upload.url:}") + private String fileUrl; @Transactional(rollbackFor = Exception.class) public void execute(UserUpdateCmd userUpdateCmd) { @@ -104,72 +113,10 @@ public class UserUpdateExe { log.info("【getInfoById查询结果】dahuaId={}, dahuaCode={}, name={}, userIdCard={}", userDO.getDahuaId(), userDO.getDahuaCode(), userDO.getName(), userDO.getUserIdCard()); - 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); - } + if (userUpdateCmd.getUserAvatarUrl() != null && !userUpdateCmd.getUserAvatarUrl().trim().isEmpty()) { + syncDaHuaInfo(userUpdateCmd, userDO, userE); } 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); + log.info("userAvatarUrl为空,跳过大华信息同步, userId={}", userDO.getId()); } UserE oldUserE = new UserE(); @@ -323,6 +270,78 @@ public class UserUpdateExe { userChangeRecordGateway.add(userChangeRecordE); } + private void syncDaHuaInfo(UserUpdateCmd userUpdateCmd, UserDO userDO, UserE userE) { + 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; + String encodedDahuaCode = queryDahuaCode == null ? null + : Base64.getEncoder().encodeToString(queryDahuaCode.getBytes(StandardCharsets.UTF_8)); + userDO.setDahuaId(queryDahuaId); + userDO.setDahuaCode(encodedDahuaCode); + userE.setDahuaId(queryDahuaId); + userE.setDahuaCode(encodedDahuaCode); + 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); + } + } + private void syncDaHuaPersonUpdate(UserUpdateCmd userUpdateCmd, UserDO userDO) { log.info("========== 大华人员(更新)检查开始 =========="); log.info("用户主键userDO.id={}, name={}, userIdCard={}, dahuaId={}, dahuaCode={}", @@ -339,19 +358,18 @@ public class UserUpdateExe { 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(); - log.info("【本次请求入参】name是否传={}, phone是否传={}, userIdCard是否传={}, nation是否传={}, nationName是否传={}, userImg是否传={}, faceFile是否传={}, corpinfoId是否传={}", + log.info("【本次请求入参】name是否传={}, phone是否传={}, userIdCard是否传={}, nation是否传={}, nationName是否传={}, userAvatarUrl是否传={}, corpinfoId是否传={}", userUpdateCmd.getName() != null, userUpdateCmd.getPhone() != null, userUpdateCmd.getUserIdCard() != null, userUpdateCmd.getNation() != null, userUpdateCmd.getNationName() != null, - userUpdateCmd.getUserImg() != null, userUpdateCmd.getFaceFile() != null, + userUpdateCmd.getUserAvatarUrl() != null, userUpdateCmd.getCorpinfoId() != null); boolean nameChanged = !Objects.equals(newName, userDO.getName()); boolean idCardChanged = !Objects.equals(newIdCard, userDO.getUserIdCard()); boolean phoneChanged = !Objects.equals(newPhone, userDO.getPhone()); boolean nationChanged = !Objects.equals(newNation, userDO.getNation()) || !Objects.equals(newNationName, userDO.getNationName()); - boolean faceChanged = newFaceFile != null; + boolean faceChanged = userUpdateCmd.getUserAvatarUrl() != null && !userUpdateCmd.getUserAvatarUrl().trim().isEmpty(); boolean corpChanged = !Objects.equals(newCorpId, userDO.getCorpinfoId()); log.info("【变化检测】nameChanged={}({}→{}), idCardChanged={}, phoneChanged={}, nationChanged={}({}/{}→{}/{}), faceChanged={}, corpChanged={}({}→{})", nameChanged, userDO.getName(), newName, @@ -381,7 +399,9 @@ public class UserUpdateExe { personMap.put("id", dahuaId); } personMap.put("name", newName); - personMap.put("code", dahuaCode != null ? dahuaCode : plainIdCard); + personMap.put("code", dahuaCode != null + ? new String(Base64.getDecoder().decode(dahuaCode.trim()), StandardCharsets.UTF_8) + : plainIdCard); personMap.put("paperType", 111); personMap.put("paperNumber", plainIdCard); personMap.put("phone", newPhone); @@ -416,130 +436,7 @@ public class UserUpdateExe { } 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 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 (!finalHasPrefix) { - log.error("同步大华人员(更新)失败:人脸图片最终无data:image前缀,代码补齐逻辑失效"); - throw new BizException("同步大华平台失败:人脸图片格式异常"); - } else if (!isLikelyBase64) { - log.error("同步大华人员(更新)失败:人脸图片base64主体含非base64非法字符"); - throw new BizException("同步大华平台失败:人脸图片格式错误"); - } else if (bodyLen < 1000) { - log.error("同步大华人员(更新)失败:人脸图片base64主体长度过短({}),缩略图可能损坏", bodyLen); - throw new BizException("同步大华平台失败:人脸图片不完整"); - } - - 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); - } + addDaHuaFace(personMap, userUpdateCmd.getUserAvatarUrl()); DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); Object biosObj = personMap.get("personBiosignatures"); @@ -582,7 +479,6 @@ public class UserUpdateExe { 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; @@ -634,123 +530,7 @@ public class UserUpdateExe { } 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); - } - } + addDaHuaFace(personMap, userUpdateCmd.getUserAvatarUrl()); DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); Object biosObj = personMap.get("personBiosignatures"); @@ -802,11 +582,12 @@ public class UserUpdateExe { } if (dahuaId != null) { String dahuaCode = plainIdCard; + String encodedDahuaCode = Base64.getEncoder().encodeToString(dahuaCode.getBytes(StandardCharsets.UTF_8)); userRepository.updateDahuaInfo(userDO.getId(), dahuaId, dahuaCode); userDO.setDahuaId(dahuaId); - userDO.setDahuaCode(dahuaCode); + userDO.setDahuaCode(encodedDahuaCode); userE.setDahuaId(dahuaId); - userE.setDahuaCode(dahuaCode); + userE.setDahuaCode(encodedDahuaCode); log.info("新增大华人员后写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}", userDO.getId(), dahuaId, dahuaCode); return dahuaId; @@ -1044,13 +825,147 @@ public class UserUpdateExe { if (userDO == null) { throw new BizException("未找到该用户"); } - userRepository.updateFaceByPhone(cmd.getUserAvatarUrl(),userDO.getPhone()); -// UserDO userDO = new UserDO(); -// BeanUtils.copyProperties(cmd, userDO); -// return userRepository.updateFaceUrl(userDO); + CorpInfoDO corpInfoDO = userDO.getCorpinfoId() == null + ? null : corpInfoRepository.getById(userDO.getCorpinfoId()); + if (corpInfoDO != null && DAHUA_CORP_TYPE_CODES.contains(corpInfoDO.getType())) { + try { + syncDaHuaUserFace(userDO, cmd.getUserAvatarUrl()); + } catch (Exception e) { + log.error("同步大华人脸异常,不影响本地头像保存, userId={}", userDO.getId(), e); + } + } + userRepository.updateFaceByPhone(cmd.getUserAvatarUrl(), userDO.getPhone()); return true; } + private void syncDaHuaUserFace(UserDO userDO, String userAvatarUrl) { + if (userDO.getDahuaId() != null) { + if (updateDaHuaUserFace(userDO, userDO.getDahuaId(), userAvatarUrl)) { + userRepository.updateDahuaInfo(userDO.getId(), userDO.getDahuaId(), getDaHuaCodeForSave(userDO)); + } + return; + } + + String plainIdCard = decodeUserIdCard(userDO.getUserIdCard()); + if (plainIdCard == null || plainIdCard.trim().isEmpty()) { + log.warn("同步大华人脸失败:用户身份证号为空, userId={}", userDO.getId()); + return; + } + + SingleResponse> queryResponse; + try { + queryResponse = zcloudDaHuaFacade.findPersonByPaperNumber(plainIdCard); + } catch (Exception e) { + log.error("查询大华人员异常,不执行新增,避免产生重复人员, userId={}", userDO.getId(), e); + return; + } + if (queryResponse == null || !queryResponse.isSuccess()) { + log.warn("查询大华人员失败,不执行新增, userId={}, errCode={}, errMessage={}", + userDO.getId(), queryResponse == null ? "" : queryResponse.getErrCode(), + queryResponse == null ? "大华Dubbo返回为空" : queryResponse.getErrMessage()); + return; + } + + Map personData = queryResponse.getData(); + Integer dahuaId = getDaHuaPersonId(personData); + if (dahuaId != null) { + if (updateDaHuaUserFace(userDO, dahuaId, userAvatarUrl)) { + String dahuaCode = getDaHuaPersonCode(personData); + userRepository.updateDahuaInfo(userDO.getId(), dahuaId, + dahuaCode == null || dahuaCode.trim().isEmpty() ? plainIdCard : dahuaCode); + } + return; + } + + UserUpdateCmd userUpdateCmd = new UserUpdateCmd(); + userUpdateCmd.setUserAvatarUrl(userAvatarUrl); + syncDaHuaPersonAdd(userUpdateCmd, userDO, new UserE()); + } + + private static String getDaHuaCodeForSave(UserDO userDO) { + String dahuaCode = decodeBase64Value(userDO.getDahuaCode()); + if (dahuaCode == null || dahuaCode.trim().isEmpty()) { + return decodeUserIdCard(userDO.getUserIdCard()); + } + return dahuaCode; + } + + private boolean updateDaHuaUserFace(UserDO userDO, Integer dahuaId, String userAvatarUrl) { + Map personMap = new HashMap<>(); + personMap.put("id", dahuaId); + personMap.put("departmentId", userDO.getCorpinfoId()); + addDaHuaFace(personMap, userAvatarUrl); + + DaHuaPersonSyncCmd daHuaCmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class); + Object biosignatures = personMap.get("personBiosignatures"); + if (biosignatures instanceof List) { + @SuppressWarnings("unchecked") + List faceList = + (List) biosignatures; + daHuaCmd.setPersonBiosignatures(faceList); + } + + try { + SingleResponse updateResponse = zcloudDaHuaFacade.updatePerson(daHuaCmd); + if (updateResponse == null || !updateResponse.isSuccess()) { + log.warn("同步大华人脸失败,不影响本地头像保存, userId={}, dahuaId={}, errCode={}, errMessage={}", + userDO.getId(), dahuaId, updateResponse == null ? "" : updateResponse.getErrCode(), + updateResponse == null ? "大华Dubbo返回为空" : updateResponse.getErrMessage()); + return false; + } + log.info("同步大华人脸成功, userId={}, dahuaId={}", userDO.getId(), dahuaId); + return true; + } catch (Exception e) { + log.error("同步大华人脸异常,不影响本地头像保存, userId={}, dahuaId={}", + userDO.getId(), dahuaId, e); + return false; + } + } + + private static String decodeUserIdCard(String userIdCard) { + return decodeBase64Value(userIdCard); + } + + private static String decodeBase64Value(String value) { + if (value == null || value.trim().isEmpty()) { + return value; + } + try { + return new String(Base64.getDecoder().decode(value.trim()), StandardCharsets.UTF_8); + } catch (IllegalArgumentException e) { + return value; + } + } + + private static Integer getDaHuaPersonId(Map personData) { + Object id = getDaHuaPersonValue(personData, "id"); + if (id == null) { + return null; + } + try { + return Integer.valueOf(id.toString()); + } catch (NumberFormatException e) { + return null; + } + } + + private static String getDaHuaPersonCode(Map personData) { + Object code = getDaHuaPersonValue(personData, "code"); + return code == null ? null : code.toString(); + } + + private static Object getDaHuaPersonValue(Map personData, String key) { + if (personData == null) { + return null; + } + Object value = personData.get(key); + Object innerData = personData.get("data"); + if (value == null && innerData instanceof Map) { + return ((Map) innerData).get(key); + } + return value; + } + @Transactional(rollbackFor = Exception.class) public void executeResignation(UserResignationCmd userResignationCmd) { //获取用户信息,并更新离职状态为离职 @@ -1447,6 +1362,34 @@ public class UserUpdateExe { } + private void addDaHuaFace(Map personMap, String userAvatarUrl) { + if (userAvatarUrl == null || userAvatarUrl.trim().isEmpty()) { + return; + } + if (fileUrl == null || fileUrl.trim().isEmpty()) { + throw new BizException("同步大华平台失败:文件服务地址未配置"); + } + String baseUrl = fileUrl.trim(); + String avatarPath = userAvatarUrl.trim().replaceAll("^`+|`+$", ""); + String imageUrl = baseUrl.endsWith("/") + ? baseUrl + removeLeadingSlash(avatarPath) + : baseUrl + "/" + removeLeadingSlash(avatarPath); + log.info("同步大华人员:开始下载人脸图片并转为Base64, url={}", imageUrl); + String imageBase64 = downloadImageToBase64(imageUrl); + + List personBiosignatures = new ArrayList<>(); + DaHuaPersonSyncCmd.PersonBiosignature biosignature = new DaHuaPersonSyncCmd.PersonBiosignature(); + biosignature.setType(3); + biosignature.setIndex(1); + biosignature.setBase64Data(imageBase64); + personBiosignatures.add(biosignature); + personMap.put("personBiosignatures", personBiosignatures); + } + + private static String removeLeadingSlash(String path) { + return path.replaceFirst("^/+", ""); + } + private static String downloadImageToBase64(String urlStr) { if (urlStr == null || urlStr.trim().isEmpty()) { throw new BizException("同步大华平台失败:人脸图片URL为空"); @@ -1512,4 +1455,4 @@ public class UserUpdateExe { } -} \ No newline at end of file +} diff --git a/web-client/src/main/java/com/zcloud/basic/info/dto/UserUpdateCmd.java b/web-client/src/main/java/com/zcloud/basic/info/dto/UserUpdateCmd.java index f4b927b9..0285f38a 100644 --- a/web-client/src/main/java/com/zcloud/basic/info/dto/UserUpdateCmd.java +++ b/web-client/src/main/java/com/zcloud/basic/info/dto/UserUpdateCmd.java @@ -63,10 +63,6 @@ public class UserUpdateCmd extends Command { private String userIdCard; @ApiModelProperty(value = "人脸头像url", name = "userAvatarUrl") private String userAvatarUrl; - @ApiModelProperty(value = "人脸图片文件(取thumbUrl字段作为base64传大华)") - private Object faceFile; - @ApiModelProperty(value = "用户头像数组(相关方人员头像,取第一个元素的thumbUrl字段作为base64传大华,优先级高于faceFile)") - private Object userImg; @ApiModelProperty(value = "现住址", name = "currentAddress") private String currentAddress; @ApiModelProperty(value = "户口所在地", name = "locationAddress") @@ -130,4 +126,4 @@ public class UserUpdateCmd extends Command { private String payNumber; @ApiModelProperty(value = "是否缴纳其他人身伤害保险") private Integer isBf; -} \ No newline at end of file +} 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 85fa9851..50461d7a 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 @@ -47,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -568,7 +569,7 @@ public class UserRepositoryImpl extends BaseRepositoryImpl i hasSet = true; } if (dahuaCode != null) { - uw.set("dahua_code", dahuaCode); + uw.set("dahua_code", Base64.getEncoder().encodeToString(dahuaCode.getBytes(StandardCharsets.UTF_8))); hasSet = true; } if (hasSet) { diff --git a/web-infrastructure/src/main/resources/mapper/UserMapper.xml b/web-infrastructure/src/main/resources/mapper/UserMapper.xml index 92b30c18..ccc92eec 100644 --- a/web-infrastructure/src/main/resources/mapper/UserMapper.xml +++ b/web-infrastructure/src/main/resources/mapper/UserMapper.xml @@ -482,6 +482,7 @@ select count(1) from user + 1=1 and delete_enum = 'FALSE' and id != #{params.id}