大华口门对接

(cherry picked from commit 65ad2b538e)
dahua_koumen
zhangxiongfeng 2026-08-04 14:13:09 +08:00
parent 85d55a77d9
commit bb0a5912d6
5 changed files with 115 additions and 164 deletions

View File

@ -21,6 +21,10 @@
<groupId>com.zcloud.basic.info</groupId>
<artifactId>web-infrastructure</artifactId>
</dependency>
<dependency>
<groupId>com.zcloud.primeport</groupId>
<artifactId>web-client</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -31,6 +31,8 @@ import com.zcloud.basic.info.domain.model.*;
import com.zcloud.basic.info.dto.*;
import com.zcloud.basic.info.persistence.dataobject.*;
import com.zcloud.basic.info.persistence.repository.*;
import com.zcloud.gbscommon.dahua.cmd.DaHuaPersonSyncCmd;
import com.zcloud.gbscommon.dahua.facade.ZcloudDaHuaFacade;
import com.zcloud.gbscommon.utils.*;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -98,6 +100,8 @@ public class UserAddExe {
private final UserExpandInfoRepository userExpandInfoRepository;
private final ImgFilesRepository imgFilesRepository;
private final DaHuaConfig daHuaConfig;
@DubboReference
private ZcloudDaHuaFacade zcloudDaHuaFacade;
@Transactional(rollbackFor = Exception.class)
public boolean execute(UserAddCmd cmd) {
@ -184,7 +188,6 @@ public class UserAddExe {
userE.setUserType(CorpTypeEnum.getUserTypeByCode(corpInfoDO.getType()));
userE.resetPassword(corpInfoDO.getType());
// ① 先本地落库 + 底座GBS新增。GBS失败抛 RuntimeException整个事务回滚
res = userGateway.add(userE);
if (corpInfoDO != null && !ObjectUtils.isEmpty(corpInfoDO.getCorpName())) {
corpName = corpInfoDO.getCorpName();
@ -200,7 +203,6 @@ public class UserAddExe {
} catch (Exception e) {
log.error("用户变更记录保存失败(不影响用户主体), userId: {}, error: {}", userE.getId(), e.getMessage(), e);
}
// ② 本地和底座都成功后,最后才同步大华。失败→抛异常→回滚本地+GBS避免留下"大华人成功但本地没数据"
DaHuaSyncResult syncResult = syncDaHuaPerson(userE);
if (syncResult.dahuaId != null || (syncResult.dahuaCode != null && !syncResult.dahuaCode.trim().isEmpty())) {
try {
@ -373,11 +375,11 @@ public class UserAddExe {
log.error("同步大华人员失败人脸图片base64主体长度过短({}),缩略图可能损坏", bodyLen);
}
List<Map<String, Object>> personBiosignatures = new ArrayList<>();
Map<String, Object> biosignature = new java.util.LinkedHashMap<>();
biosignature.put("type", 3);
biosignature.put("index", 1);
biosignature.put("base64Data", cleanBase64);
List<DaHuaPersonSyncCmd.PersonBiosignature> 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 {
@ -430,44 +432,35 @@ public class UserAddExe {
}
personMap.put("age", age);
personMap.put("sex", sex);
Map<String, String> extraHeaders = new HashMap<>();
try {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest req = attrs.getRequest();
String token = req.getHeader("token");
String orgid = req.getHeader("orgid");
String tenantId = req.getHeader("tenantId");
if (token != null && !token.trim().isEmpty()) {
extraHeaders.put("token", token);
}
if (orgid != null && !orgid.trim().isEmpty()) {
extraHeaders.put("orgid", orgid);
}
if (tenantId != null && !tenantId.trim().isEmpty()) {
extraHeaders.put("tenantId", tenantId);
}
}
} catch (Exception e) {
log.warn("获取当前请求头异常: {}", e.getMessage());
}
Map<String, Object> syncResult = daHuaConfig.syncPerson(personMap, extraHeaders);
Boolean success = (Boolean) syncResult.get("success");
Boolean skipped = (Boolean) syncResult.get("skipped");
DaHuaSyncResult result = new DaHuaSyncResult();
result.setDahuaCode(plainIdCard);
if (skipped != null && skipped) {
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");
if (biosObj instanceof List) {
@SuppressWarnings("unchecked")
List<DaHuaPersonSyncCmd.PersonBiosignature> bioList = (List<DaHuaPersonSyncCmd.PersonBiosignature>) biosObj;
cmd.setPersonBiosignatures(bioList);
}
log.info("Dubbo调用primeport.zcloudDaHuaFacade.syncPerson, name={}, departmentId(corpId)={}",
cmd.getName(), cmd.getDepartmentId());
SingleResponse<Object> syncResp = zcloudDaHuaFacade.syncPerson(cmd);
String maskedIdCard = plainIdCard;
if (plainIdCard != null && plainIdCard.length() >= 14) {
maskedIdCard = plainIdCard.substring(0, 6) + "********" + plainIdCard.substring(plainIdCard.length() - 4);
}
result.setDahuaCode(plainIdCard);
userE.setDahuaCode(plainIdCard);
if (success == null || !success) {
String errCode = (String) syncResult.getOrDefault("errCode", "");
String errMessage = (String) syncResult.getOrDefault("errMessage", "大华人员同步失败");
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 = "大华人员同步失败";
if (throwOnFail) {
throw new BizException("同步大华平台失败:" + errMessage);
} else {
@ -476,7 +469,7 @@ public class UserAddExe {
return result;
}
}
Object data = syncResult.get("data");
Object data = syncResp.getData();
if (data != null) {
if (data instanceof Map) {
Map<String, Object> dataMap = (Map<String, Object>) data;
@ -996,28 +989,28 @@ public class UserAddExe {
userExpandInfoRepository.updateByPhone(userE.getPhone(),userE.getFlowFlag());
}
// ========== 相关方用户同步大华(统一用 /person/sync重复信息返回false直接跳过不影响本地==========
// ========== 相关方用户同步大华(仅修改场景调大华,新增场景跳过==========
Long xgfUserId = addFlag ? userE.getId() : userDOUpdate.getId();
if (xgfUserId == null) {
log.warn("相关方用户保存后未获取到userId跳过大华同步及dahua信息写回, addFlag={}", addFlag);
} else {
DaHuaSyncResult xgfSyncResult = null;
if (!addFlag) {
Object xgfAvatarSource = cmd.getUserImg();
if (xgfAvatarSource == null) {
xgfAvatarSource = cmd.getUserAvatarUrl();
}
DaHuaSyncResult xgfSyncResult = null;
try {
xgfSyncResult = syncDaHuaPerson(userE, xgfAvatarSource, false);
} catch (Exception e) {
log.error("相关方用户同步大华异常不影响本地保存继续执行写回身份证号为dahuaCode, userId={}, addFlag={}, error={}",
xgfUserId, addFlag, e.getMessage(), e);
}
// 无论大华同步成功/失败/返回false/抛异常都尝试写回dahuaId/dahuaCode
// dahuaId = 大华返回的id成功时才有失败/异常/重复时为null
// dahuaCode = 前端传的身份证号经过Base64解码的明文syncDaHuaPerson里即使失败也已经set到result了
} else {
log.info("相关方用户新增场景,跳过大华同步, userId={}", xgfUserId);
}
Integer xgfDahuaId = xgfSyncResult != null ? xgfSyncResult.dahuaId : null;
String xgfDahuaCode = xgfSyncResult != null ? xgfSyncResult.dahuaCode : null;
// 如果xgfSyncResult异常或dahuaCode为空兜底直接把userE.getUserIdCard()做一次Base64解码写入dahuaCode保证100%写回
if ((xgfDahuaCode == null || xgfDahuaCode.trim().isEmpty()) && userE.getUserIdCard() != null && !userE.getUserIdCard().trim().isEmpty()) {
String idCardRaw = userE.getUserIdCard().trim();
try {

View File

@ -21,6 +21,8 @@ import com.zcloud.basic.info.persistence.repository.UserCorpRecordRepository;
import com.zcloud.basic.info.persistence.repository.UserJobHandoverRepository;
import com.zcloud.basic.info.persistence.repository.UserRepository;
import com.zcloud.basic.info.domain.config.DaHuaConfig;
import com.zcloud.gbscommon.dahua.cmd.DaHuaPersonDeleteCmd;
import com.zcloud.gbscommon.dahua.facade.ZcloudDaHuaFacade;
import com.zcloud.gbscommon.utils.ZcloudRedisUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -28,10 +30,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
@ -53,9 +52,11 @@ public class UserRemoveExe {
@DubboReference(check = false)
private UserFacade userFacade;
// @Autowired
private ZcloudRedisUtil zcloudRedisUtil;
private final ZcloudRedisUtil zcloudRedisUtil;
private final UserCorpRecordRepository userCorpRecordRepository;
private final DaHuaConfig daHuaConfig;
@DubboReference
private ZcloudDaHuaFacade zcloudDaHuaFacade;
@Transactional(rollbackFor = Exception.class)
public boolean execute(Long id) {
@ -79,21 +80,21 @@ public class UserRemoveExe {
// ② 本地操作完成后再删大华。若大华失败 → throw BizException → 本地全部回滚
if (needDeleteDaHua) {
Map<String, Object> deleteResult = daHuaConfig.deletePerson(
Collections.singletonList(dahuaId), getDaHuaExtraHeaders());
Boolean skipped = (Boolean) deleteResult.get("skipped");
if (skipped == null || !skipped) {
Boolean success = (Boolean) deleteResult.get("success");
String errCode = (String) deleteResult.getOrDefault("errCode", "");
String errMessage = (String) deleteResult.getOrDefault("errMessage", "");
if (success == null || !success) {
if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) {
log.info("【单个删除-大华删除跳过】dockFlag未开启, userId={}", id);
} else {
DaHuaPersonDeleteCmd delCmd = new DaHuaPersonDeleteCmd();
delCmd.setIds(Collections.singletonList(dahuaId.longValue()));
SingleResponse<Boolean> delResp = zcloudDaHuaFacade.deletePerson(delCmd);
if (delResp == null || !delResp.isSuccess()) {
String errCode = delResp == null ? "" : delResp.getErrCode();
String errMessage = delResp == null ? "大华Dubbo返回为空" : delResp.getErrMessage();
if (errMessage == null || errMessage.trim().isEmpty()) errMessage = "大华人员删除失败";
log.error("【单个删除-大华删除失败→触发本地回滚】userId={}, dahuaId={}, errCode={}, errMessage={}",
id, dahuaId, errCode, errMessage);
throw new BizException("删除大华平台人员失败:" + errMessage);
}
log.info("【单个删除-大华删除成功】userId={}, dahuaId={}", id, dahuaId);
} else {
log.info("【单个删除-大华删除跳过】dockFlag未开启, userId={}", id);
}
}
} catch (BizException e) {
@ -195,32 +196,6 @@ public class UserRemoveExe {
return true;
}
private Map<String, String> getDaHuaExtraHeaders() {
Map<String, String> extraHeaders = new HashMap<>();
try {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest req = attrs.getRequest();
String token = req.getHeader("token");
String orgid = req.getHeader("orgid");
String tenantId = req.getHeader("tenantId");
if (token != null && !token.trim().isEmpty()) {
extraHeaders.put("token", token);
}
if (orgid != null && !orgid.trim().isEmpty()) {
extraHeaders.put("orgid", orgid);
}
if (tenantId != null && !tenantId.trim().isEmpty()) {
extraHeaders.put("tenantId", tenantId);
}
}
} catch (Exception e) {
log.warn("获取大华透传请求头失败: {}", e.getMessage());
}
return extraHeaders;
}
@Transactional(rollbackFor = Exception.class)
public boolean execute(Long[] ids) {
try {
@ -242,21 +217,21 @@ public class UserRemoveExe {
// ② 本地成功后再删大华。大华失败→throw→本地回滚
if (!dahuaIds.isEmpty()) {
Map<String, String> extraHeaders = getDaHuaExtraHeaders();
Map<String, Object> deleteResult = daHuaConfig.deletePerson(dahuaIds, extraHeaders);
Boolean skipped = (Boolean) deleteResult.get("skipped");
if (skipped == null || !skipped) {
Boolean success = (Boolean) deleteResult.get("success");
String errCode = (String) deleteResult.getOrDefault("errCode", "");
String errMessage = (String) deleteResult.getOrDefault("errMessage", "");
if (success == null || !success) {
if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) {
log.info("【批量删除-大华删除跳过】dockFlag未开启, idList={}", idList);
} else {
DaHuaPersonDeleteCmd delCmd = new DaHuaPersonDeleteCmd();
delCmd.setIds(dahuaIds.stream().map(Integer::longValue).collect(Collectors.toList()));
SingleResponse<Boolean> delResp = zcloudDaHuaFacade.deletePerson(delCmd);
if (delResp == null || !delResp.isSuccess()) {
String errCode = delResp == null ? "" : delResp.getErrCode();
String errMessage = delResp == null ? "大华Dubbo返回为空" : delResp.getErrMessage();
if (errMessage == null || errMessage.trim().isEmpty()) errMessage = "大华人员删除失败";
log.error("【批量删除-大华删除失败→触发本地回滚】localIds={}, dahuaIds={}, errCode={}, errMessage={}",
idList, dahuaIds, errCode, errMessage);
throw new BizException("删除大华平台人员失败:" + errMessage);
}
log.info("【批量删除-大华删除成功】dahuaIds={}", dahuaIds);
} else {
log.info("【批量删除-大华删除跳过】dockFlag未开启, idList={}", idList);
}
}
return true;

View File

@ -21,6 +21,9 @@ import com.zcloud.basic.info.domain.model.*;
import com.zcloud.basic.info.dto.*;
import com.zcloud.basic.info.persistence.dataobject.*;
import com.zcloud.basic.info.persistence.repository.*;
import com.zcloud.gbscommon.dahua.cmd.DaHuaPersonDeleteCmd;
import com.zcloud.gbscommon.dahua.cmd.DaHuaPersonSyncCmd;
import com.zcloud.gbscommon.dahua.facade.ZcloudDaHuaFacade;
import com.zcloud.gbscommon.utils.Tools;
import com.zcloud.gbscommon.utils.ZcloudRedisUtil;
import com.zcloud.gbscommon.zcloudhidden.face.ZcloudHiddenFacade;
@ -35,10 +38,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -78,6 +78,8 @@ public class UserUpdateExe {
@DubboReference
private ZcloudRiskFacade zcloudRiskFacade;
private final DaHuaConfig daHuaConfig;
@DubboReference
private ZcloudDaHuaFacade zcloudDaHuaFacade;
@Transactional(rollbackFor = Exception.class)
@ -442,50 +444,38 @@ public class UserUpdateExe {
throw new BizException("同步大华平台失败:人脸图片不完整");
}
List<Map<String, Object>> personBiosignatures = new ArrayList<>();
Map<String, Object> biosignature = new java.util.LinkedHashMap<>();
biosignature.put("type", 3);
biosignature.put("index", 1);
biosignature.put("base64Data", cleanBase64);
List<DaHuaPersonSyncCmd.PersonBiosignature> 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);
}
Map<String, String> extraHeaders = new HashMap<>();
try {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest req = attrs.getRequest();
String token = req.getHeader("token");
String orgid = req.getHeader("orgid");
String tenantId = req.getHeader("tenantId");
if (token != null && !token.trim().isEmpty()) {
extraHeaders.put("token", token);
}
if (orgid != null && !orgid.trim().isEmpty()) {
extraHeaders.put("orgid", orgid);
}
if (tenantId != null && !tenantId.trim().isEmpty()) {
extraHeaders.put("tenantId", tenantId);
}
}
} catch (Exception e) {
log.warn("获取当前请求头异常: {}", e.getMessage());
}
Map<String, Object> syncResult = daHuaConfig.updatePerson(personMap, extraHeaders);
Boolean success = (Boolean) syncResult.get("success");
Boolean skipped = (Boolean) syncResult.get("skipped");
if (skipped != null && skipped) {
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) {
@SuppressWarnings("unchecked")
List<DaHuaPersonSyncCmd.PersonBiosignature> bioList = (List<DaHuaPersonSyncCmd.PersonBiosignature>) biosObj;
cmd.setPersonBiosignatures(bioList);
}
log.info("Dubbo调用primeport.zcloudDaHuaFacade.updatePerson, name={}, departmentId(corpId)={}",
cmd.getName(), cmd.getDepartmentId());
SingleResponse<Boolean> updateResp = zcloudDaHuaFacade.updatePerson(cmd);
String maskedIdCard = plainIdCard;
if (plainIdCard != null && plainIdCard.length() >= 14) {
maskedIdCard = plainIdCard.substring(0, 6) + "********" + plainIdCard.substring(plainIdCard.length() - 4);
}
if (success == null || !success) {
String errCode = (String) syncResult.getOrDefault("errCode", "");
String errMessage = (String) syncResult.getOrDefault("errMessage", "大华人员更新失败");
if (updateResp == null || !updateResp.isSuccess()) {
String errCode = updateResp == null ? "" : updateResp.getErrCode();
String errMessage = updateResp == null ? "大华Dubbo返回为空" : updateResp.getErrMessage();
if (errMessage == null || errMessage.trim().isEmpty()) errMessage = "大华人员更新失败";
log.error("同步大华人员(更新)失败, errCode={}, errMessage={}, name={}, idCard={}", errCode, errMessage, newName, maskedIdCard);
throw new BizException("同步大华平台失败:" + errMessage);
}
@ -776,35 +766,21 @@ public class UserUpdateExe {
Integer dahuaId = userDO.getDahuaId();
if (dahuaId != null) {
log.info("【离职-同步删除大华人员】userId={}, name={}, dahuaId={}", userDO.getId(), userDO.getName(), dahuaId);
Map<String, String> extraHeaders = new HashMap<>();
try {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs != null) {
HttpServletRequest req = attrs.getRequest();
String token = req.getHeader("token");
String orgid = req.getHeader("orgid");
String tenantId = req.getHeader("tenantId");
if (token != null && !token.trim().isEmpty()) extraHeaders.put("token", token);
if (orgid != null && !orgid.trim().isEmpty()) extraHeaders.put("orgid", orgid);
if (tenantId != null && !tenantId.trim().isEmpty()) extraHeaders.put("tenantId", tenantId);
}
} catch (Exception e) {
log.warn("【离职-获取大华透传请求头异常】: {}", e.getMessage());
}
Map<String, Object> deleteResult = daHuaConfig.deletePerson(Collections.singletonList(dahuaId), extraHeaders);
Boolean skipped = (Boolean) deleteResult.get("skipped");
if (skipped == null || !skipped) {
Boolean success = (Boolean) deleteResult.get("success");
String errCode = (String) deleteResult.getOrDefault("errCode", "");
String errMessage = (String) deleteResult.getOrDefault("errMessage", "");
if (success == null || !success) {
if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) {
log.info("【离职-大华删除跳过】dockFlag未开启, userId={}", userDO.getId());
} else {
DaHuaPersonDeleteCmd delCmd = new DaHuaPersonDeleteCmd();
delCmd.setIds(Collections.singletonList(dahuaId.longValue()));
SingleResponse<Boolean> delResp = zcloudDaHuaFacade.deletePerson(delCmd);
if (delResp == null || !delResp.isSuccess()) {
String errCode = delResp == null ? "" : delResp.getErrCode();
String errMessage = delResp == null ? "大华Dubbo返回为空" : delResp.getErrMessage();
if (errMessage == null || errMessage.trim().isEmpty()) errMessage = "大华人员删除失败";
log.error("【离职-大华删除失败→触发本地回滚】userId={}, dahuaId={}, errCode={}, errMessage={}",
userDO.getId(), dahuaId, errCode, errMessage);
throw new BizException("同步大华平台删除离职人员失败:" + errMessage);
}
log.info("【离职-大华删除成功】userId={}, dahuaId={}", userDO.getId(), dahuaId);
} else {
log.info("【离职-大华删除跳过】dockFlag未开启, userId={}", userDO.getId());
}
} else {
log.info("【离职-跳过同步大华】用户dahuaId为空,未同步过大华平台, userId={}, name={}", userDO.getId(), userDO.getName());
@ -1033,6 +1009,10 @@ public class UserUpdateExe {
}
}
public List<UserJobHandoverDO> collectUserJob(Long userId, Long departmentId, Long corpinfoId, String userChangeRecordId) {
return getUserJob(userId, corpinfoId, userChangeRecordId);
}
private List<UserJobHandoverDO> getUserJob(Long userId, Long corpinfoId, String userChangeRecordId) {
List<UserJobHandoverDO> allJob = new ArrayList<>();
//隐患id

View File

@ -58,4 +58,3 @@ public interface UserMapper extends BaseMapper<UserDO> {
IPage<UserDO> pageByNopermissionAll(IPage<UserDO> iPage, @Param("ew") QueryWrapper<UserDO> queryWrapper);
}