feat(user): 更新用户管理功能以支持大华系统集成

条件
- 实现大华人脸图片的下载和Base64转换功能
- 添加文件服务URL配置注入和使用
- 优化大华系统数据同步的日志记录和错误处理
main_koumen
zhaokai 2026-08-12 15:20:24 +08:00
parent 68b225d42a
commit e682dc86e6
7 changed files with 279 additions and 333 deletions

View File

@ -67,4 +67,7 @@ dahua:
primeportGateway: primeport
nine:
config:
companyId: 2008712261453131776,2046785341004177408
companyId: 2008712261453131776,2046785341004177408
file:
upload:
url: https://jpfz.qhdsafety.com/gbsFileTest/

View File

@ -66,4 +66,7 @@ dahua:
clientSecret: 5ef82f7c-9926-46a3-8d07-136fd054849c
nine:
config:
companyId: 2590800828822460065,2044322367672422400
companyId: 2590800828822460065,2044322367672422400
file:
upload:
url: http://192.168.192.201:8992/file/uploadFiles2/

View File

@ -513,8 +513,7 @@ public class UserAddExe {
} else {
log.info("Dubbo调用未携带人脸生物特征");
}
log.info("Dubbo调用 cmd对象完整打印: {}", JSONUtil.toJsonStr(cmd));
SingleResponse<Object> syncResp = null;
try {
log.info("即将执行 zcloudDaHuaFacade.syncPerson(cmd)...");

View File

@ -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<Integer> 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<Map<String, Object>> 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<String, Object> 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<String, Object> innerData = (Map<String, Object>) 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<Map<String, Object>> 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<String, Object> 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<String, Object> innerData = (Map<String, Object>) 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<Object, String> extractThumbFromSingle = (singleObj) -> {
if (singleObj == null) {
return null;
}
if (singleObj instanceof Map) {
Map<String, Object> faceFileMap = (Map<String, Object>) 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<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);
}
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<Object, String> extractThumbFromSingle = (singleObj) -> {
if (singleObj == null) {
return null;
}
if (singleObj instanceof Map) {
Map<String, Object> faceFileMap = (Map<String, Object>) 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<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 {
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<Map<String, Object>> 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<String, Object> 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<String, Object> 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<DaHuaPersonSyncCmd.PersonBiosignature> faceList =
(List<DaHuaPersonSyncCmd.PersonBiosignature>) biosignatures;
daHuaCmd.setPersonBiosignatures(faceList);
}
try {
SingleResponse<Boolean> 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<String, Object> 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<String, Object> personData) {
Object code = getDaHuaPersonValue(personData, "code");
return code == null ? null : code.toString();
}
private static Object getDaHuaPersonValue(Map<String, Object> 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<String, Object> 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<DaHuaPersonSyncCmd.PersonBiosignature> 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 {
}
}
}

View File

@ -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;
}
}

View File

@ -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<UserMapper, UserDO> 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) {

View File

@ -482,6 +482,7 @@
select count(1)
from user
<where>
1=1 and delete_enum = 'FALSE'
<if test="params.id != null">
and id != #{params.id}
</if>