refactor(sis): 定时授权任务通过snail-job触发
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

This commit is contained in:
2025-08-02 15:50:40 +08:00
parent c366a30488
commit f7cdf4bc09
9 changed files with 550 additions and 409 deletions

View File

@@ -13,8 +13,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.dromara.property.domain.vo.ResidentUnitVo;
import org.dromara.property.service.IResidentUnitService;
import org.dromara.sis.api.RemoteSisAuth;
import org.dromara.sis.api.domain.RemotePersonAuth;
import org.dromara.sis.api.RemoteSisAuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@@ -30,7 +29,6 @@ import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 入驻员工Service业务层处理
@@ -50,7 +48,7 @@ public class ResidentPersonServiceImpl implements IResidentPersonService {
private IResidentUnitService residentUnitService;
@DubboReference
private RemoteSisAuth remoteSisAuth;
private RemoteSisAuthService remoteSisAuthService;
/**
* 查询入驻员工
@@ -159,7 +157,7 @@ public class ResidentPersonServiceImpl implements IResidentPersonService {
if (flag && e8Id != null) {
log.info("开始修改授权记录, {}", bo.getUserName());
// 先删除,定时任务增加
Boolean auth = remoteSisAuth.deletePersonAuth(List.of(update.getId()), List.of(e8Id));
Boolean auth = remoteSisAuthService.deletePersonAuth(List.of(update.getId()), List.of(e8Id));
Assert.isTrue(auth, "修改授权记录失败!");
}
@@ -217,7 +215,7 @@ public class ResidentPersonServiceImpl implements IResidentPersonService {
.filter(Objects::nonNull)
.toList();
if (!e8Ids.isEmpty()) {
boolean auth = remoteSisAuth.deletePersonAuth(ids, e8Ids);
boolean auth = remoteSisAuthService.deletePersonAuth(ids, e8Ids);
Assert.isTrue(auth, "删除授权记录失败!");
}
}

View File

@@ -1,38 +0,0 @@
package org.dromara.sis.dubbo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.sis.api.RemoteSisAuth;
import org.dromara.sis.api.domain.RemotePersonAuth;
import org.dromara.sis.service.ISisAuthRecordService;
import java.util.Collection;
/**
* @author lsm
* @apiNote RemoteSisAuthImpl
* @since 2025/7/24
*/
@Slf4j
@DubboService
@RequiredArgsConstructor
public class RemoteSisAuthImpl implements RemoteSisAuth {
private final ISisAuthRecordService sisAuthRecordService;
@Override
public Boolean personAuth(RemotePersonAuth personAuth) {
return sisAuthRecordService.insertByPerson(personAuth);
}
@Override
public Boolean updatePersonAuth(RemotePersonAuth personAuth) {
return sisAuthRecordService.updateByBo(personAuth);
}
@Override
public Boolean deletePersonAuth(Collection<Long> ids, Collection<Long> e8Ids) {
return sisAuthRecordService.deleteByPersonIds(ids, e8Ids);
}
}

View File

@@ -0,0 +1,222 @@
package org.dromara.sis.dubbo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.common.core.constant.CodePrefixConstants;
import org.dromara.sis.api.RemoteSisAuthService;
import org.dromara.sis.api.domain.RemotePersonAuth;
import org.dromara.sis.domain.vo.SisAccessControlVo;
import org.dromara.sis.domain.vo.SisAuthGroupRefVo;
import org.dromara.sis.domain.vo.SisAuthRecordVo;
import org.dromara.sis.domain.vo.SisPersonLibImgVo;
import org.dromara.sis.sdk.e8.E8PlatformApi;
import org.dromara.sis.sdk.e8.domain.accessControl.req.CustomerAuthAddReq;
import org.dromara.sis.sdk.e8.domain.custom.req.CustomAddReq;
import org.dromara.sis.sdk.e8.domain.voucher.req.IssueVoucherReq;
import org.dromara.sis.sdk.huawei.HuaWeiBoxApi;
import org.dromara.sis.sdk.huawei.domain.AddHWPersonReq;
import org.dromara.sis.service.ISisAccessControlService;
import org.dromara.sis.service.ISisAuthGroupRefService;
import org.dromara.sis.service.ISisAuthRecordService;
import org.dromara.sis.service.ISisPersonLibImgService;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
/**
* @author lsm
* @apiNote RemoteSisAuthServiceImpl
* @since 2025/7/24
*/
@Slf4j
@DubboService
@RequiredArgsConstructor
public class RemoteSisAuthServiceImpl implements RemoteSisAuthService {
private final HuaWeiBoxApi huaWeiBoxApi;
private final E8PlatformApi e8PlatformApi;
private final ISisAuthRecordService sisAuthRecordService;
private final ISisPersonLibImgService sisPersonLibImgService;
private final ISisAuthGroupRefService sisAuthGroupRefService;
private final ISisAccessControlService sisAccessControlService;
/**
* 人员授权
*
* @param personAuth 人员授权信息
* @return Boolean
*/
@Override
public Boolean personAuth(RemotePersonAuth personAuth) {
return sisAuthRecordService.insertByPerson(personAuth);
}
/**
* 删除人员授权信息
*
* @param ids 入驻员工ids
* @param e8Ids e8平台人员id是
* @return Boolean
*/
@Override
public Boolean deletePersonAuth(Collection<Long> ids, Collection<Long> e8Ids) {
return sisAuthRecordService.deleteByPersonIds(ids, e8Ids);
}
/**
* 查询人员授权信息
*
* @param authGroupId 权限组id
* @param personId 人员id
* @return Boolean
*/
@Override
public Boolean queryPersonAuth(Long authGroupId, Long personId) {
SisAuthRecordVo vo = sisAuthRecordService.queryByGroupIdAndPersonId(authGroupId, personId);
return vo != null;
}
/**
* 通过MD5查询图片id
*
* @param imgMd5 图片MD5
* @return Long
*/
@Override
public Long queryImgIdByImgMd5(String imgMd5) {
SisPersonLibImgVo vo = sisPersonLibImgService.queryByImgMd5(imgMd5);
return vo != null ? vo.getId() : null;
}
/**
* 图片写入华为盒子
*
* @param person 人员信息
* @param imgByte 图片字节数组
* @return Long 图片id
*/
@Override
public Long syncHuaweiBox(RemotePersonAuth person, byte[] imgByte) {
Long pId;
try {
AddHWPersonReq req = new AddHWPersonReq();
req.setIndex(CodePrefixConstants.PERSON_LIB_IMAGE_CODE_PREFIX + IdUtil.getSnowflakeNextIdStr());
req.setName(person.getName());
req.setGender(person.getSex() == 1 ? "0" : person.getSex() == 2 ? "1" : "-1");
ArrayList<String> pictures = new ArrayList<>();
pictures.add(Base64.getEncoder().encodeToString(imgByte));
req.setPictures(pictures);
pId = huaWeiBoxApi.addPerson(List.of(req));
} catch (Exception e) {
return null;
}
return pId;
}
/**
* 更新人像信息
*
* @param id 入驻员工id
* @param huaweiBoxId 华为盒子id
* @param md5Str 图片MD5
* @return Boolean
*/
@Override
public Boolean updateImgByPersonId(Long id, Long huaweiBoxId, String md5Str) {
return sisPersonLibImgService.updateByPersonId(id, huaweiBoxId, md5Str);
}
/**
* 图片写入E8平台
*
* @param person 人员信息
* @param imgByte 图片字节数组
* @return Long e8平台id
*/
@Override
public Long syncE8Plat(RemotePersonAuth person, byte[] imgByte) {
// 初始化步进器
int count = 0;
Long e8Id;
try {
log.info("e8平台上传照片");
String e8ImgUrl = e8PlatformApi.uploadFace(imgByte);
Assert.notNull(e8ImgUrl, "图片上传E8平台失败");
log.info("e8平台上传照片完成");
count++; // 图片上传完成步进器+1
log.info("e8同步新建人员");
CustomAddReq req = new CustomAddReq();
req.setName(person.getName());
req.setGender(person.getSex() != 1 ? 0 : 1);
e8Id = e8PlatformApi.addCustomer(req).getId();
Assert.notNull(e8Id, "e8同步新建人员失败");
log.info("e8同步新建人员完成");
count++; // 新增人员完成步进器+1
log.info("e8平台开始发行凭证");
IssueVoucherReq voucherReq = new IssueVoucherReq();
voucherReq.setVoucherType(70);
voucherReq.setPersonID(e8Id);
voucherReq.setTxtData(e8ImgUrl);
voucherReq.setCardType(34);
Long voucherId = e8PlatformApi.issueVoucher(voucherReq);
Assert.notNull(voucherId, "e8平台发行凭证失败");
log.info("e8平台发行凭证成功");
count++; // 发行凭证完成步进器+1
// 获取门禁
List<SisAuthGroupRefVo> refVos = sisAuthGroupRefService.queryListByGroupId(person.getAuthGroupId());
Collection<Long> deviceIds = refVos.stream().filter(ref -> ref.getDeviceType() == 1).map(SisAuthGroupRefVo::getDeviceId).toList();
if (CollUtil.isNotEmpty(deviceIds)) {
// 初始化赋值
CustomerAuthAddReq authReq = new CustomerAuthAddReq();
authReq.setPersonIds(List.of(e8Id));
authReq.setStartTime(DateUtil.format(person.getAuthBegDate(), "yyyy-MM-dd HH:mm:ss"));
authReq.setEndTime(DateUtil.format(person.getAuthEndDate(), "yyyy-MM-dd HH:mm:ss"));
List<CustomerAuthAddReq.AuthGroupData> list = new ArrayList<>();
SisAccessControlVo accessControlVo;
for (Long deviceId : deviceIds) {
accessControlVo = sisAccessControlService.queryById(deviceId);
CustomerAuthAddReq.AuthGroupData authData = new CustomerAuthAddReq.AuthGroupData();
authData.setId(Long.parseLong(accessControlVo.getOutDoorCode()));
authData.setType(0);
authData.setGatewayType(1);
list.add(authData);
}
authReq.setAuthData(list);
log.info("e8平台开始授权");
Boolean flag = e8PlatformApi.addCustomerAuth(authReq);
Assert.isTrue(flag, "E8平台授权失败");
log.info("E8平台授权完成!");
count++; // 授权完成步进器+1
}
} catch (Exception e) {
return null;
}
if (count == 4) {
// 授权完成返回e8平台人员Id
return e8Id;
} else if (count >= 2 && count < 4) {
// 人员新建完成,授权失败,删除人员
e8PlatformApi.deleteCustomer(e8Id);
return null;
} else {
return null;
}
}
}

View File

@@ -1,317 +0,0 @@
package org.dromara.sis.task;
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.CodePrefixConstants;
import org.dromara.property.api.RemoteResidentPersonService;
import org.dromara.property.api.domain.vo.RemoteResidentPersonVo;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.sis.api.domain.RemotePersonAuth;
import org.dromara.sis.domain.vo.*;
import org.dromara.sis.sdk.e8.E8PlatformApi;
import org.dromara.sis.sdk.e8.domain.accessControl.req.CustomerAuthAddReq;
import org.dromara.sis.sdk.e8.domain.custom.req.CustomAddReq;
import org.dromara.sis.sdk.e8.domain.voucher.req.IssueVoucherReq;
import org.dromara.sis.sdk.huawei.HuaWeiBoxApi;
import org.dromara.sis.sdk.huawei.domain.AddHWPersonReq;
import org.dromara.sis.service.ISisAccessControlService;
import org.dromara.sis.service.ISisAuthGroupRefService;
import org.dromara.sis.service.ISisAuthRecordService;
import org.dromara.sis.service.ISisPersonLibImgService;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author lsm
* @apiNote AuthSyncTask
* @since 2025/7/26
*/
@Slf4j
@Configuration
@EnableScheduling
@RequiredArgsConstructor
public class AuthSyncTask {
@DubboReference
private RemoteFileService remoteFileService;
@DubboReference
private RemoteResidentPersonService remoteResidentPersonService;
private final HuaWeiBoxApi huaWeiBoxApi;
private final E8PlatformApi e8PlatformApi;
private final ISisAuthRecordService sisAuthRecordService;
private final ISisPersonLibImgService sisPersonLibImgService;
private final ISisAuthGroupRefService sisAuthGroupRefService;
private final ISisAccessControlService sisAccessControlService;
/**
* 每两分钟执行一次
*/
// @Scheduled(cron = "0 */5 * * * ?")
public void autoAuth() {
AtomicReference<List<RemoteResidentPersonVo>> unAuthPersonRef = new AtomicReference<>(new ArrayList<>());
AtomicReference<byte[]> imgByteRef = new AtomicReference<>(new byte[0]);
// 需要先设置模拟上下文
SaTokenContextMockUtil.setMockContext(() -> {
// 模拟登录
StpUtil.login(1);
unAuthPersonRef.set(remoteResidentPersonService.queryUnAuthPerson());
List<RemoteResidentPersonVo> unAuthPerson = unAuthPersonRef.get();
try {
if (CollUtil.isNotEmpty(unAuthPerson)) {
for (RemoteResidentPersonVo person : unAuthPerson) {
log.info("开始定时授权:{}----{}", person.getName(), person.getId());
// 判断是否已存在授权
SisAuthRecordVo authRecord = sisAuthRecordService.queryByGroupIdAndPersonId(person.getAuthGroupId(), person.getId());
if (ObjectUtil.isEmpty(authRecord)) {
log.info("无授权记录:{}----{}", person.getName(), person.getId());
this.syncAuthRecord(person);
imgByteRef.set(remoteFileService.downloadToByteArray(Long.parseLong(person.getOssId())));
// 读取人像
byte[] imgByte = imgByteRef.get();
if (imgByte == null) {
log.info("下载图片失败:{}-----{}", person.getName(), person.getId());
sisAuthRecordService.deleteByPersonIds(List.of(person.getId()), new ArrayList<>());
continue;
}
// String nowMd5 = this.calculateMD5(imgByte);
// SisPersonLibImgVo imgVo = sisPersonLibImgService.queryByImgMd5(nowMd5);
//
// Long huaweiId;
// Boolean update;
// if (ObjectUtil.isEmpty(imgVo)) {
// // 写入华为盒子
// huaweiId = syncHuaweiBox(person, imgByte);
// } else {
// if (imgVo.getRemoteImgId() == null) {
// huaweiId = syncHuaweiBox(person, imgByte);
// } else {
// huaweiId = imgVo.getRemoteImgId();
// }
// }
//
// if (huaweiId == null){
// log.info("华为盒子人像上传失败:{}-----{}", person.getName(), person.getId());
// sisAuthRecordService.deleteByPersonIds(List.of(person.getId()), new ArrayList<>());
// continue;
// }
//
// // 更新人像信息huaweiBoxId
// update = sisPersonLibImgService.updateByPersonId(person.getId(), huaweiId, nowMd5);
// if (!update) {
// log.info("更新人像信息失败:{}-----{}", person.getName(), person.getId());
// sisAuthRecordService.deleteByPersonIds(List.of(person.getId()), new ArrayList<>());
// continue;
// }
// 同步E8平台
Long e8Id = syncE8Plat(person, imgByte);
if (e8Id == null) {
log.info("E8平台授权失败{}-----{}", person.getName(), person.getId());
sisAuthRecordService.deleteByPersonIds(List.of(person.getId()), new ArrayList<>());
continue;
}
// 更新入驻员工E8平台id
remoteResidentPersonService.updateE8Id(person.getId(), e8Id);
} else {
log.info("已存在授权记录:{}-----{}", person.getName(), person.getId());
}
}
} else {
log.info("无待授权人员");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
/**
* 补录授权记录
*
* @param person bean
*/
private void syncAuthRecord(RemoteResidentPersonVo person) {
log.info("开始补录授权记录、人像信息");
RemotePersonAuth personAuth = new RemotePersonAuth();
personAuth.setId(person.getId());
personAuth.setOssId(person.getOssId());
personAuth.setName(person.getName());
personAuth.setPhone(person.getPhone());
personAuth.setSex(person.getGender().intValue());
personAuth.setIdCardNumber(person.getIdCard());
personAuth.setAuthGroupId(person.getAuthGroupId());
personAuth.setAuthBegDate(person.getAuthBegDate());
personAuth.setAuthEndDate(person.getAuthEndDate());
sisAuthRecordService.insertByPerson(personAuth);
log.info("补录授权记录、人像信息完成");
}
/**
* 同步华为盒子
*
* @param vo bean
* @param imgByte 图片字节
* @return Long
*/
private Long syncHuaweiBox(RemoteResidentPersonVo vo, byte[] imgByte) {
Long pId;
try {
log.info("开始写入华为平台");
AddHWPersonReq req = new AddHWPersonReq();
req.setIndex(CodePrefixConstants.PERSON_LIB_IMAGE_CODE_PREFIX + IdUtil.getSnowflakeNextIdStr());
req.setName(vo.getName());
req.setGender(vo.getGender() == 1L ? "0" : vo.getGender() == 2L ? "1" : "-1");
req.setCredentialType("0");
req.setCredentialNumber(vo.getIdCard());
ArrayList<String> pictures = new ArrayList<>();
pictures.add(Base64.getEncoder().encodeToString(imgByte));
req.setPictures(pictures);
pId = huaWeiBoxApi.addPerson(List.of(req));
Assert.notNull(pId, "调用华为盒子新增图片失败");
log.info("写入华为盒子完成pId={}", pId);
} catch (Exception e) {
return null;
}
return pId;
}
/**
* 同步E8平台
*
* @param vo bean
* @param imgByte 图片字节
* @return Long
*/
private Long syncE8Plat(RemoteResidentPersonVo vo, byte[] imgByte) {
// 初始化步进器
int count = 0;
Long e8Id = null;
try {
log.info("e8平台上传照片");
String e8ImgUrl = e8PlatformApi.uploadFace(imgByte);
Assert.notNull(e8ImgUrl, "图片上传E8平台失败");
log.info("e8平台上传照片完成");
count++; // 图片上传完成步进器+1
log.info("e8同步新建人员");
CustomAddReq req = new CustomAddReq();
req.setName(vo.getName());
req.setGender(vo.getGender() != 1L ? 0 : 1);
req.setIdentityType(0);
req.setIdentityNo(vo.getIdCard());
e8Id = e8PlatformApi.addCustomer(req).getId();
Assert.notNull(e8Id, "e8同步新建人员失败");
log.info("e8同步新建人员完成");
count++; // 新增人员完成步进器+1
log.info("e8平台开始发行凭证");
IssueVoucherReq voucherReq = new IssueVoucherReq();
voucherReq.setVoucherType(70);
voucherReq.setPersonID(e8Id);
voucherReq.setTxtData(e8ImgUrl);
voucherReq.setCardType(34);
Long voucherId = e8PlatformApi.issueVoucher(voucherReq);
Assert.notNull(voucherId, "e8平台发行凭证失败");
log.info("e8平台发行凭证成功");
count++; // 发行凭证完成步进器+1
// 获取门禁
List<SisAuthGroupRefVo> refVos = sisAuthGroupRefService.queryListByGroupId(vo.getAuthGroupId());
Collection<Long> deviceIds = refVos.stream().filter(ref -> ref.getDeviceType() == 1).map(SisAuthGroupRefVo::getDeviceId).toList();
if (CollUtil.isNotEmpty(deviceIds)) {
// 初始化赋值
CustomerAuthAddReq authReq = new CustomerAuthAddReq();
authReq.setPersonIds(List.of(e8Id));
authReq.setStartTime(DateUtil.format(vo.getAuthBegDate(), "yyyy-MM-dd HH:mm:ss"));
authReq.setEndTime(DateUtil.format(vo.getAuthEndDate(), "yyyy-MM-dd HH:mm:ss"));
List<CustomerAuthAddReq.AuthGroupData> list = new ArrayList<>();
SisAccessControlVo accessControlVo;
for (Long deviceId : deviceIds) {
accessControlVo = sisAccessControlService.queryById(deviceId);
CustomerAuthAddReq.AuthGroupData authData = new CustomerAuthAddReq.AuthGroupData();
authData.setId(Long.parseLong(accessControlVo.getOutDoorCode()));
authData.setType(0);
authData.setGatewayType(1);
list.add(authData);
}
authReq.setAuthData(list);
log.info("e8平台开始授权");
Boolean flag = e8PlatformApi.addCustomerAuth(authReq);
Assert.isTrue(flag, "E8平台授权失败");
log.info("E8平台授权完成!");
count++; // 授权完成步进器+1
}
} catch (Exception e) {
return null;
}
if (count == 4) {
// 授权完成返回e8平台人员Id
return e8Id;
} else if (count >= 2 && count < 4) {
// 人员新建完成,授权失败,删除人员
e8PlatformApi.deleteCustomer(e8Id);
return null;
} else {
return null;
}
}
/**
* 直接计算字节数组的MD5值
*
* @param data 图片的字节数组
* @return 32位小写MD5字符串
*/
public String calculateMD5(byte[] data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("输入数据不能为null");
}
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data);
return bytesToHex(md.digest());
}
/**
* 字节数组转十六进制字符串
*
* @param bytes 字节数组
* @return 32位十六进制字符串
*/
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
// %02x 表示两位小写十六进制不足两位补0
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}

View File

@@ -83,6 +83,12 @@
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-api-resource</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
<build>

View File

@@ -1,29 +0,0 @@
package org.dromara.job.snailjob.sis;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
import com.aizuda.snailjob.client.model.ExecuteResult;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.property.api.RemoteResidentPersonService;
import org.dromara.property.api.domain.vo.RemoteResidentPersonVo;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author lsm
* @apiNote AuthSyncTask
* @since 2025/8/1
*/
@Component
@JobExecutor(name = "authSyncTask")
public class AuthSyncTask {
@DubboReference
private RemoteResidentPersonService remoteResidentPersonService;
public ExecuteResult jobExecute(JobArgs jobArgs) throws InterruptedException {
List<RemoteResidentPersonVo> unAuthPerson = remoteResidentPersonService.queryUnAuthPerson();
return ExecuteResult.success(unAuthPerson);
}
}

View File

@@ -0,0 +1,243 @@
package org.dromara.job.snailjob.sis;
import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
import com.aizuda.snailjob.client.model.ExecuteResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.property.api.RemoteResidentPersonService;
import org.dromara.property.api.domain.vo.RemoteResidentPersonVo;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.sis.api.RemoteSisAuthService;
import org.dromara.sis.api.domain.RemotePersonAuth;
import org.springframework.stereotype.Component;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author lsm
* @apiNote SyncGrantAuthTask
* @since 2025/8/1
*/
@Slf4j
@Component
@JobExecutor(name = "syncGrantAuthTask")
public class SyncGrantAuthTask {
@DubboReference
private RemoteFileService remoteFileService;
@DubboReference
private RemoteSisAuthService remoteSisAuthService;
@DubboReference
private RemoteResidentPersonService remoteResidentPersonService;
public ExecuteResult jobExecute(JobArgs jobArgs) throws InterruptedException {
AtomicReference<List<RemoteResidentPersonVo>> unAuthPersonRef = new AtomicReference<>(new ArrayList<>());
AtomicReference<byte[]> imgByteRef = new AtomicReference<>(new byte[0]);
// 需要先设置模拟上下文
SaTokenContextMockUtil.setMockContext(() -> {
// 模拟登录
StpUtil.login(1);
unAuthPersonRef.set(remoteResidentPersonService.queryUnAuthPerson());
List<RemoteResidentPersonVo> unAuthPerson = unAuthPersonRef.get();
try {
if (CollUtil.isNotEmpty(unAuthPerson)) {
for (RemoteResidentPersonVo person : unAuthPerson) {
log.info("开始定时授权:{}----{}", person.getName(), person.getId());
// 判断是否存在授权
Boolean auth = remoteSisAuthService.queryPersonAuth(person.getAuthGroupId(), person.getId());
if (!auth) {
log.info("无授权记录:{}----{}", person.getName(), person.getId());
// 补录授权记录、人像信息
Boolean flag = syncAuthRecord(person);
if (!flag) {
log.info("补录授权记录、人像信息失败:{}----{}", person.getName(), person.getId());
continue;
}
// 下载人像
byte[] imgByte;
try {
imgByteRef.set(remoteFileService.downloadToByteArray(Long.parseLong(person.getOssId())));
imgByte = imgByteRef.get();
} catch (Exception e) {
log.info("下载图片失败:{}----{}", person.getName(), person.getId());
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
continue;
}
// 计算图片MD5
String nowMd5 = calculateMD5(imgByte);
// 通过MD5查询相同图片
Long remoteId = remoteSisAuthService.queryImgIdByImgMd5(nowMd5);
Long huaweiId;
if (remoteId == null) {
// 当前本地人像信息不存在相同照片,直接上传华为盒子
huaweiId = syncHuaweiBox(person, imgByte);
} else {
huaweiId = remoteId;
}
if (huaweiId == null) {
log.info("华为盒子人像上传失败:{}-----{}", person.getName(), person.getId());
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
continue;
}
Boolean update = false;
try {
update = remoteSisAuthService.updateImgByPersonId(person.getId(), huaweiId, nowMd5);
} catch (Exception e) {
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
}
if (!update) {
log.info("更新人像信息失败:{}-----{}", person.getName(), person.getId());
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
continue;
}
// 同步人像到E8平台
Long e8Id = syncE8Plat(person, imgByte);
if (e8Id == null) {
log.info("同步人像到E8平台失败{}-----{}", person.getName(), person.getId());
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
continue;
}
// 更新入驻员工E8平台id
remoteResidentPersonService.updateE8Id(person.getId(), e8Id);
} else {
// 存在授权记录,为了避免重复授权,删除授权记录
remoteSisAuthService.deletePersonAuth(List.of(person.getId()), new ArrayList<>());
}
}
} else {
log.info("无待授权人员");
}
} catch (Exception e) {
log.info("同步授权异常");
throw new RuntimeException(e);
}
});
return ExecuteResult.success();
}
/**
* 补录授权记录
*
* @param person bean
*/
private Boolean syncAuthRecord(RemoteResidentPersonVo person) {
log.info("开始补录授权记录、人像信息:{}----{}", person.getName(), person.getId());
RemotePersonAuth personAuth = getRemotePersonAuth(person);
Boolean flag;
try {
flag = remoteSisAuthService.personAuth(personAuth);
if (flag) {
log.info("补录授权记录、人像信息完成:{}----{}", person.getName(), person.getId());
}
} catch (Exception e) {
return false;
}
return flag;
}
/**
* 实体类转换
*/
private RemotePersonAuth getRemotePersonAuth(RemoteResidentPersonVo person) {
RemotePersonAuth personAuth = new RemotePersonAuth();
personAuth.setId(person.getId());
personAuth.setOssId(person.getOssId());
personAuth.setName(person.getName());
personAuth.setPhone(person.getPhone());
personAuth.setSex(person.getGender().intValue());
personAuth.setIdCardNumber(person.getIdCard());
personAuth.setAuthGroupId(person.getAuthGroupId());
personAuth.setAuthBegDate(person.getAuthBegDate());
personAuth.setAuthEndDate(person.getAuthEndDate());
return personAuth;
}
/**
* 同步华为盒子
*
* @param vo bean
* @param imgByte 图片字节
* @return Long
*/
private Long syncHuaweiBox(RemoteResidentPersonVo vo, byte[] imgByte) {
log.info("开始写入华为盒子");
RemotePersonAuth personAuth = getRemotePersonAuth(vo);
Long pId = remoteSisAuthService.syncHuaweiBox(personAuth, imgByte);
if (pId != null) {
log.info("写入华为盒子完成pId={}", pId);
}
return pId;
}
/**
* 同步E8平台
*
* @param vo bean
* @param imgByte 图片字节
* @return Long
*/
private Long syncE8Plat(RemoteResidentPersonVo vo, byte[] imgByte) {
log.info("开始写入E8平台");
RemotePersonAuth personAuth = getRemotePersonAuth(vo);
Long e8Id = remoteSisAuthService.syncE8Plat(personAuth, imgByte);
if (e8Id != null) {
log.info("写入E8平台完成e8Id={}", e8Id);
}
return e8Id;
}
/**
* 直接计算字节数组的MD5值
*
* @param data 图片的字节数组
* @return 32位小写MD5字符串
*/
public String calculateMD5(byte[] data) throws Exception {
if (data == null) {
throw new IllegalArgumentException("输入数据不能为null");
}
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data);
return bytesToHex(md.digest());
}
/**
* 字节数组转十六进制字符串
*
* @param bytes 字节数组
* @return 32位十六进制字符串
*/
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
// %02x 表示两位小写十六进制不足两位补0
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}