项目上需要同步用户给第三方,所以增删改用户信息时,会发布用户同步事件,在涉及到组织项增删改查时,会发布同步事件,然后在监听器处理组织项同步逻辑,发到http、mq等组件上,让第三方去获取。这里就会关系到事务问题,因为用户保存逻辑处理、同步事件发布都在同一个方法中,方法执行完之后才会提交事务,若提交事务时出现sql异常,但是这时已经发布了同步事件了,造成数据不一致。所以得需要用户逻辑处理完,提交了保存事件之后再进行同步逻辑处理。只需要在事务监听器上配好TransactionPhase.AFTER_COMMIT即可。这如果事务提交有异常,就不会进行用户同步了。
贴代码:
新建事件类:
/** * 组织项同步事件 * @author lfq * @version 1.0 * @date 2022/10/21 */ @Getter @Setter @ToString public class OrganSynchEvent extends ApplicationEvent { private static final long serialVersionUID = 617313570247857471L; private List<OrganInfo> organInfoList; private List<UserInfo> userInfoList; private SyncTypeEnum operateType; private String roleId; private List<String> childIds; public OrganSynchEvent(Object source) { super(source); } public OrganSynchEvent(Object source, List<UserInfo> userInfoList, List<OrganInfo> organInfoList, SyncTypeEnum operateType) { super(source); this.userInfoList = userInfoList; this.operateType = operateType; this.organInfoList = organInfoList; } public OrganSynchEvent(Object source, String roleId, List<String> childIds, SyncTypeEnum operateType) { super(source); this.roleId = roleId; this.operateType = operateType; this.childIds = childIds; } } |
监听器类:
/**
* 组织项同步监听器
* @author lfq
* @date 2022/10/21
*/
@Component
@Slf4j
public class OrganSynchListener {
@Autowired
private OrganSynchProperties properties;
@Autowired(required = false)
private OrganSynchService organSynchService;
@Autowired(required = false)
@Qualifier("taskExecutor")
private ThreadPoolTaskExecutor taskExecutor;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = OrganSynchEvent.class)
public void onApplicationEvent(OrganSynchEvent event) {
if (taskExecutor != null && properties.isEnabled() && organSynchService != null) {
taskExecutor.execute(() -> {
List<UserInfo> userInfoList = event.getUserInfoList();
List<OrganInfo> organInfoList = event.getOrganInfoList();
SyncTypeEnum operateType = event.getOperateType();
String roleId = event.getRoleId();
List<String> childIds = event.getChildIds();
try {
if ((SyncTypeEnum.USER_ADD.equals(operateType) || SyncTypeEnum.USER_UPDATE.equals(operateType)) && !CollectionUtils.isEmpty(userInfoList)) {
for (UserInfo userInfo : userInfoList) {
SynchModel synchModel = new SynchModel(operateType.name(), UserSyncModel.toUserSyncModel(userInfo));
organSynchService.synch(synchModel);
}
} else if ((SyncTypeEnum.ORG_ADD.equals(operateType) || SyncTypeEnum.ORG_UPDATE.equals(operateType)) && !CollectionUtils.isEmpty(organInfoList)) {
for (OrganInfo organInfo : organInfoList) {
SynchModel synchModel = new SynchModel(operateType.name(), OrganSyncModel.toOrganSyncModel(organInfo));
organSynchService.synch(synchModel);
}
} else if ((SyncTypeEnum.USER_DELETE.equals(operateType) || SyncTypeEnum.ORG_DELETE.equals(operateType)) && !CollectionUtils.isEmpty(organInfoList)) {
Set<String> ids = organInfoList.stream().map(OrganInfoBase::getRid).collect(Collectors.toSet());
Map<String, Set<String>> idMap = new HashMap<>();
idMap.put("ids", ids);
SynchModel synchModel = new SynchModel(operateType.name(), idMap);
organSynchService.synch(synchModel);
} else if ((SyncTypeEnum.ROLE_ORGAN_BIND.equals(operateType) || SyncTypeEnum.ROLE_ORGAN_UNBIND.equals(operateType)) && StringUtils.isNotBlank(roleId) && !CollectionUtils.isEmpty(childIds)) {
Map<String, Object> map = new HashMap<>();
map.put("roleId", roleId);
map.put("ids", childIds);
SynchModel synchModel = new SynchModel(operateType.name(), map);
organSynchService.synch(synchModel);
}
} catch (Exception e) {
//todo 同步失败处理
log.info(e.getMessage());
}
});
}
}
} |
http同步实现类,有多种同步方式,这里只贴http的同步方式
/** * 以http接口调用方式同步组织项 * @author lfq */ @Slf4j public class OrganSynchSynchByHttp implements OrganSynchService{ private OrganSynchProperties properties; private RestTemplate restTemplateBalanced; private RestTemplate restTemplate; public OrganSynchSynchByHttp() {} public OrganSynchSynchByHttp(OrganSynchProperties properties, RestTemplate restTemplateBalanced, RestTemplate restTemplate) { this.properties = properties; this.restTemplate = restTemplate; this.restTemplateBalanced = restTemplateBalanced; } @Override public void synch(SynchModel synchModel) { log.info(String.format("同步操作:type = [%s], content = [%s]" , synchModel.getType(), synchModel.getContent())); //设置请求头参数 HttpHeaders headers = new HttpHeaders(); headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE); HttpEntity request = new HttpEntity<>(JsonUtil.toJsonString(synchModel), headers); String url = properties.getSynchPath(); if (StringUtils.isBlank(url)){ throw new ServiceException("请配置第三方同步接口:mainweb.organ.sync.synchPath"); } ResponseEntity<Object> responseEntity = null; try { responseEntity = getRestTemplate(url).exchange(url, HttpMethod.POST, request, Object.class); }catch (Exception e){ if (e instanceof HttpServerErrorException){ HttpServerErrorException d = (HttpServerErrorException) e; throw new ServiceException(String.format("%s请求异常, body:{%s},message: {%s}", url,d.getResponseBodyAsString(Charset.forName("UTF-8")), e.getMessage()), e); }else if (e instanceof HttpClientErrorException){ HttpClientErrorException d = (HttpClientErrorException) e; throw new ServiceException(String.format("%s请求异常, body:{%s},message: {%s}", url,d.getResponseBodyAsString(Charset.forName("UTF-8")), e.getMessage()), e); } else { throw new ServiceException(e); } } checkSuccess(url, responseEntity); log.info(String.format("%s请求响应, statusCode:{%s},body:{%s}", url, responseEntity.getStatusCodeValue(), responseEntity.getBody())); } private RestTemplate getRestTemplate(String url){ Integer st = url.indexOf("//") + 2; Integer en = url.indexOf("/",st); String d = url.substring(st, en); if (d.contains(".")){ return restTemplate; }else { return restTemplateBalanced; } } /** * 检查返回是否成功,Http状态小于400 * @param url * @param response */ private static void checkSuccess(String url, ResponseEntity<?> response) { if(response != null && response.getStatusCodeValue() >= 400) { if (response.getBody() instanceof Byte){ try { throw new ServiceException("远程调用出错[" + url + "]:" +response.getStatusCode()+", content:" + new String((byte[]) response.getBody(), "utf-8")); }catch (Exception e){} } throw new ServiceException("远程调用出错[" + url + "]:" +response.getStatusCode()+", content:" + response.getBody()); } } } |
使用:
// 发布 用户同步 事件 applicationContext.publishEvent(new OrganSynchEvent("", Arrays.asList(userInfo), null, SyncTypeEnum.USER_ADD)); |