Merge branch 'dahua_koumen' into main_koumen

# Conflicts:
#	web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.java
main_koumen
zhaokai 2026-08-11 19:20:04 +08:00
commit 68b225d42a
4 changed files with 493 additions and 69 deletions

View File

@ -201,4 +201,3 @@ public class UserController {
}
}

View File

@ -206,38 +206,57 @@ public class UserAddExe {
} catch (Exception e) {
log.error("用户变更记录保存失败(不影响用户主体), userId: {}, error: {}", userE.getId(), e.getMessage(), e);
}
runAfterCommitAsync(() -> syncDaHuaPersonAndWriteBack(userE));
} catch (BizException e) {
log.error("新增用户业务异常: {}", e.getMessage(), e);
throw e;
} catch (Exception e) {
log.error("新增用户系统异常: {}", e.getMessage(), e);
throw new RuntimeException(e);
}
if (!res) {
throw new BizException("保存失败");
}
cmd.setId(userE.getId());
cmd.setUsername(userE.getUsername());
log.info("新增用户完成, userId: {}, username: {}", userE.getId(), userE.getUsername());
return true;
}
private void runAfterCommitAsync(Runnable runnable) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
CompletableFuture.runAsync(runnable);
}
});
return;
}
CompletableFuture.runAsync(runnable);
}
private void syncDaHuaPersonAndWriteBack(UserE userE) {
log.info("========== 新增用户-开始查询大华是否已存在该人员 ==========");
Integer queryDahuaId = null;
String queryDahuaCode = null;
String plainIdCard = userE.getUserIdCard();
if (plainIdCard != null && !plainIdCard.trim().isEmpty()) {
try {
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<Map<String, Object>> 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<String, Object> 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<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) {
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(), queryDahuaId, queryDahuaCode, e);
}
} else {
log.info("大华未找到该人员,开始执行 syncDaHuaPerson 新增大华人员");
DaHuaSyncResult syncResult = syncDaHuaPerson(userE);
if (syncResult.dahuaId != null) {
try {
@ -255,9 +274,21 @@ public class UserAddExe {
} else {
log.info("大华同步未返回dahuaId跳过写回操作, userId={}, dahuaCode={}", userE.getId(), syncResult.dahuaCode);
}
} catch (Exception e) {
log.error("异步同步大华异常(不影响新增用户主流程), userId={}", userE.getId(), e);
}
} catch (BizException e) {
log.error("新增用户业务异常: {}", e.getMessage(), e);
throw e;
} catch (Exception e) {
log.error("新增用户系统异常: {}", e.getMessage(), e);
throw new RuntimeException(e);
}
if (!res) {
throw new BizException("保存失败");
}
cmd.setId(userE.getId());
cmd.setUsername(userE.getUsername());
log.info("新增用户完成, userId: {}, username: {}", userE.getId(), userE.getUsername());
return true;
}
private DaHuaSyncResult syncDaHuaPerson(UserE userE) {
@ -460,11 +491,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");

View File

@ -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());
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);
}
} 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<String, Object> faceFileMap = (Map<String, Object>) 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,10 +495,15 @@ public class UserUpdateExe {
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");
String cleanBase64;
if (containsComma && startsWithDataImage) {
String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1);
String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1);
@ -424,16 +513,15 @@ public class UserUpdateExe {
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<String, Object> 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<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);
}
}
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);
}
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<Object> 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<String, Object> dataMap = (Map<String, Object>) 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<UserDO> 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) {}
}
}
}
}

View File

@ -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<UserCO> add(UserAddCmd cmd) {
userAddExe.execute(cmd);