Merge branch 'dahua_koumen' into main_koumen
# Conflicts: # web-app/src/main/java/com/zcloud/basic/info/command/UserAddExe.javamain_koumen
commit
68b225d42a
|
|
@ -201,4 +201,3 @@ public class UserController {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,75 @@ public class UserAddExe {
|
|||
} catch (Exception e) {
|
||||
log.error("用户变更记录保存失败(不影响用户主体), userId: {}, error: {}", userE.getId(), e.getMessage(), e);
|
||||
}
|
||||
runAfterCommitAsync(() -> syncDaHuaPersonAndWriteBack(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 {
|
||||
UserE updateDahua = new UserE();
|
||||
updateDahua.setId(userE.getId());
|
||||
updateDahua.setDahuaId(syncResult.dahuaId);
|
||||
updateDahua.setDahuaCode(syncResult.dahuaCode);
|
||||
userRepository.updateDahuaInfo(updateDahua.getId(), updateDahua.getDahuaId(), updateDahua.getDahuaCode());
|
||||
log.info("写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}",
|
||||
userE.getId(), syncResult.dahuaId, syncResult.dahuaCode);
|
||||
} catch (Exception e) {
|
||||
log.error("写回dahuaId/dahuaCode失败(不影响本地数据), userId={}, dahuaId={}, dahuaCode={}",
|
||||
userE.getId(), syncResult.dahuaId, syncResult.dahuaCode, e);
|
||||
}
|
||||
} else {
|
||||
log.info("大华同步未返回dahuaId,跳过写回操作, userId={}, dahuaCode={}", userE.getId(), syncResult.dahuaCode);
|
||||
}
|
||||
}
|
||||
} catch (BizException e) {
|
||||
log.error("新增用户业务异常: {}", e.getMessage(), e);
|
||||
throw e;
|
||||
|
|
@ -223,43 +291,6 @@ public class UserAddExe {
|
|||
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) {
|
||||
try {
|
||||
DaHuaSyncResult syncResult = syncDaHuaPerson(userE);
|
||||
if (syncResult.dahuaId != null) {
|
||||
try {
|
||||
UserE updateDahua = new UserE();
|
||||
updateDahua.setId(userE.getId());
|
||||
updateDahua.setDahuaId(syncResult.dahuaId);
|
||||
updateDahua.setDahuaCode(syncResult.dahuaCode);
|
||||
userRepository.updateDahuaInfo(updateDahua.getId(), updateDahua.getDahuaId(), updateDahua.getDahuaCode());
|
||||
log.info("写回dahuaId/dahuaCode成功, userId={}, dahuaId={}, dahuaCode={}",
|
||||
userE.getId(), syncResult.dahuaId, syncResult.dahuaCode);
|
||||
} catch (Exception e) {
|
||||
log.error("写回dahuaId/dahuaCode失败(不影响本地数据), userId={}, dahuaId={}, dahuaCode={}",
|
||||
userE.getId(), syncResult.dahuaId, syncResult.dahuaCode, e);
|
||||
}
|
||||
} else {
|
||||
log.info("大华同步未返回dahuaId,跳过写回操作, userId={}, dahuaCode={}", userE.getId(), syncResult.dahuaCode);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("异步同步大华异常(不影响新增用户主流程), userId={}", userE.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private DaHuaSyncResult syncDaHuaPerson(UserE userE) {
|
||||
return syncDaHuaPerson(userE, userE.getFaceFile(), true);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Period;
|
||||
|
|
@ -98,7 +103,74 @@ public class UserUpdateExe {
|
|||
userE.setDahuaCode(userDO.getDahuaCode());
|
||||
log.info("【getInfoById查询结果】dahuaId={}, dahuaCode={}, name={}, userIdCard={}",
|
||||
userDO.getDahuaId(), userDO.getDahuaCode(), userDO.getName(), userDO.getUserIdCard());
|
||||
syncDaHuaPersonUpdate(userUpdateCmd, userDO);
|
||||
|
||||
String newIdCardForQuery = userUpdateCmd.getUserIdCard() != null ? userUpdateCmd.getUserIdCard() : userDO.getUserIdCard();
|
||||
String plainIdCardForQuery = newIdCardForQuery;
|
||||
if (newIdCardForQuery != null && !newIdCardForQuery.trim().isEmpty()) {
|
||||
try {
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(newIdCardForQuery.trim());
|
||||
plainIdCardForQuery = new String(decodedBytes, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
log.warn("身份证号非Base64格式,按原值处理: {}", newIdCardForQuery);
|
||||
}
|
||||
}
|
||||
|
||||
boolean dahuaPersonFound = false;
|
||||
log.info("修改前查询大华人员入参paperNumber(身份证号明文): {}", plainIdCardForQuery);
|
||||
Integer queryDahuaId = null;
|
||||
String queryDahuaCode = null;
|
||||
SingleResponse<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,29 +495,33 @@ public class UserUpdateExe {
|
|||
if (thumbUrl != null && !thumbUrl.trim().isEmpty()) {
|
||||
String trimmedThumb = thumbUrl.trim();
|
||||
boolean startsWithHttp = trimmedThumb.startsWith("http://") || trimmedThumb.startsWith("https://");
|
||||
boolean containsComma = trimmedThumb.contains(",");
|
||||
boolean startsWithDataImage = trimmedThumb.startsWith("data:image");
|
||||
String cleanBase64 = null;
|
||||
|
||||
String cleanBase64;
|
||||
if (containsComma && startsWithDataImage) {
|
||||
String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1);
|
||||
String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1);
|
||||
String cleanBody = bodyPart.replaceAll("\\s+", "");
|
||||
cleanBase64 = prefixPart + cleanBody;
|
||||
if (startsWithHttp) {
|
||||
log.info("同步大华人员(更新):人脸为HTTP URL,开始下载转base64, url={}", trimmedThumb);
|
||||
cleanBase64 = downloadImageToBase64(trimmedThumb);
|
||||
log.info("同步大华人员(更新):URL下载转base64完成, base64长度={}", cleanBase64 == null ? 0 : cleanBase64.length());
|
||||
} else {
|
||||
String pureBody = trimmedThumb.replaceAll("\\s+", "");
|
||||
cleanBase64 = "data:image/jpeg;base64," + pureBody;
|
||||
boolean containsComma = trimmedThumb.contains(",");
|
||||
boolean startsWithDataImage = trimmedThumb.startsWith("data:image");
|
||||
if (containsComma && startsWithDataImage) {
|
||||
String prefixPart = trimmedThumb.substring(0, trimmedThumb.indexOf(",") + 1);
|
||||
String bodyPart = trimmedThumb.substring(trimmedThumb.indexOf(",") + 1);
|
||||
String cleanBody = bodyPart.replaceAll("\\s+", "");
|
||||
cleanBase64 = prefixPart + cleanBody;
|
||||
} else {
|
||||
String pureBody = trimmedThumb.replaceAll("\\s+", "");
|
||||
cleanBase64 = "data:image/jpeg;base64," + pureBody;
|
||||
}
|
||||
}
|
||||
|
||||
int commaIdx = cleanBase64.indexOf(",");
|
||||
String base64BodyOnly = commaIdx >= 0 ? cleanBase64.substring(commaIdx + 1) : cleanBase64;
|
||||
boolean isLikelyBase64 = base64BodyOnly.matches("^[A-Za-z0-9+/=]+$");
|
||||
int bodyLen = base64BodyOnly.length();
|
||||
boolean finalHasPrefix = cleanBase64.startsWith("data:image");
|
||||
|
||||
if (startsWithHttp) {
|
||||
log.error("同步大华人员(更新)失败:人脸图片传的是HTTP/HTTPS URL,要求必须传带data:image前缀的base64图片");
|
||||
throw new BizException("同步大华平台失败:人脸图片不支持URL格式,请上传图片文件");
|
||||
} else if (!finalHasPrefix) {
|
||||
if (!finalHasPrefix) {
|
||||
log.error("同步大华人员(更新)失败:人脸图片最终无data:image前缀,代码补齐逻辑失效");
|
||||
throw new BizException("同步大华平台失败:人脸图片格式异常");
|
||||
} else if (!isLikelyBase64) {
|
||||
|
|
@ -453,11 +541,6 @@ public class UserUpdateExe {
|
|||
personMap.put("personBiosignatures", personBiosignatures);
|
||||
}
|
||||
|
||||
if (daHuaConfig.getDockFlag() == null || daHuaConfig.getDockFlag() != 1) {
|
||||
log.info("大华对接未开启(dockFlag={}), 跳过更新大华人员", daHuaConfig.getDockFlag());
|
||||
return;
|
||||
}
|
||||
|
||||
DaHuaPersonSyncCmd cmd = cn.hutool.core.bean.BeanUtil.toBean(personMap, DaHuaPersonSyncCmd.class);
|
||||
Object biosObj = personMap.get("personBiosignatures");
|
||||
if (biosObj instanceof List) {
|
||||
|
|
@ -489,6 +572,255 @@ public class UserUpdateExe {
|
|||
}
|
||||
}
|
||||
|
||||
private Integer syncDaHuaPersonAdd(UserUpdateCmd userUpdateCmd, UserDO userDO, UserE userE) {
|
||||
log.info("========== 大华人员(新增)检查开始 ==========");
|
||||
log.info("用户主键userDO.id={}, name={}, userIdCard={}",
|
||||
userDO.getId(), userDO.getName(), userDO.getUserIdCard());
|
||||
|
||||
String newName = userUpdateCmd.getName() != null ? userUpdateCmd.getName() : userDO.getName();
|
||||
String newIdCard = userUpdateCmd.getUserIdCard() != null ? userUpdateCmd.getUserIdCard() : userDO.getUserIdCard();
|
||||
String newPhone = userUpdateCmd.getPhone() != null ? userUpdateCmd.getPhone() : userDO.getPhone();
|
||||
String newNation = userUpdateCmd.getNation() != null ? userUpdateCmd.getNation() : userDO.getNation();
|
||||
String newNationName = userUpdateCmd.getNationName() != null ? userUpdateCmd.getNationName() : userDO.getNationName();
|
||||
Object newFaceFile = userUpdateCmd.getUserImg() != null ? userUpdateCmd.getUserImg() : userUpdateCmd.getFaceFile();
|
||||
Long newCorpId = userUpdateCmd.getCorpinfoId() != null ? userUpdateCmd.getCorpinfoId() : userDO.getCorpinfoId();
|
||||
|
||||
String plainIdCard = newIdCard;
|
||||
if (newIdCard != null && !newIdCard.trim().isEmpty()) {
|
||||
try {
|
||||
byte[] decodedBytes = Base64.getDecoder().decode(newIdCard.trim());
|
||||
plainIdCard = new String(decodedBytes, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
log.warn("身份证号非Base64格式,按原值处理: {}", newIdCard);
|
||||
}
|
||||
}
|
||||
|
||||
Map<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) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue