推送订阅功能

This commit is contained in:
chenxing
2026-08-14 09:03:17 +08:00
parent 0233ecb525
commit e55c2cb209
15 changed files with 1154 additions and 2 deletions
@@ -22,6 +22,8 @@ import com.yunhai.userbase.model.application.ApplicationInfoQuery;
import com.yunhai.userbase.model.application.ApplicationInfoRequest;
import com.yunhai.userbase.model.application.ApplicationInfoSortVo;
import com.yunhai.userbase.model.application.ApplicationInfoVo;
import com.yunhai.userbase.model.application.PushSettingRequest;
import com.yunhai.userbase.model.application.PushSettingVo;
import com.yunhai.userbase.event.ApplicationInfoCacheChangedEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
@@ -266,4 +268,52 @@ public class ApplicationInfoService implements IApplicationInfoService {
public List<ApplicationInfoSortVo> findListByCategoryId(Integer categoryId) {
return applicationInfoRepository.findSortVoByCategoryId(categoryId);
}
@Override
@Transactional
@CachePut(value = "appInfo", key = "#id")
public ApplicationInfo savePushSetting(Integer id, PushSettingRequest request) {
Objects.requireNonNull(id, "应用ID不能为空");
Objects.requireNonNull(request, "推送设置入参不能为空");
ApplicationInfo entity = applicationInfoRepository.findById(id)
.orElseThrow(() -> new RuntimeException("应用不存在: " + id));
if (request.getPushBaseUrl() != null) {
entity.setPushBaseUrl(request.getPushBaseUrl());
}
if (request.getPushEnabled() != null) {
entity.setPushEnabled(request.getPushEnabled());
}
if (request.getPushEventTypes() != null) {
entity.setPushEventTypes(request.getPushEventTypes());
}
if (request.getPushSchoolIds() != null) {
entity.setPushSchoolIds(request.getPushSchoolIds());
}
if (request.getPushRoleIds() != null) {
entity.setPushRoleIds(request.getPushRoleIds());
}
// pushSecret:null=不修改;空串=清空(后续复用 appSecret)
if (request.getPushSecret() != null) {
entity.setPushSecret(request.getPushSecret());
}
return applicationInfoRepository.save(entity);
}
@Override
public PushSettingVo getPushSetting(Integer id) {
Objects.requireNonNull(id, "应用ID不能为空");
ApplicationInfo entity = applicationInfoRepository.findById(id)
.orElseThrow(() -> new RuntimeException("应用不存在: " + id));
PushSettingVo vo = new PushSettingVo();
vo.setId(entity.getId());
vo.setAppKey(entity.getAppKey());
vo.setName(entity.getName());
vo.setPushBaseUrl(entity.getPushBaseUrl());
vo.setPushEnabled(entity.getPushEnabled());
vo.setPushEventTypes(entity.getPushEventTypes());
vo.setPushSchoolIds(entity.getPushSchoolIds());
vo.setPushRoleIds(entity.getPushRoleIds());
vo.setPushSecret(entity.getPushSecret());
return vo;
}
}
@@ -5,6 +5,9 @@ import com.yunhai.platform.utils.exception.DException;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.userbase.enums.GroupTypeEnum;
import com.yunhai.userbase.enums.IEnum;
import com.yunhai.userbase.event.DataSyncEvent;
import com.yunhai.userbase.model.push.PushInterfaceType;
import org.springframework.context.ApplicationEventPublisher;
import com.yunhai.userbase.model.sysgroup.SysGroupBatchRequest;
import com.yunhai.userbase.model.sysgroup.SysGroupMoveRequest;
import com.yunhai.userbase.model.sysgroup.SysGroupQuery;
@@ -23,6 +26,7 @@ import org.springframework.util.StringUtils;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -55,6 +59,9 @@ public class SysGroupService implements ISysGroupService {
@Autowired
private SysGroupModulePermRepository sysGroupModulePermRepository;
@Autowired
private ApplicationEventPublisher eventPublisher;
// ===================== 基础增删改(含根节点保护) =====================
@Override
@@ -75,7 +82,8 @@ public class SysGroupService implements ISysGroupService {
entity.setParentId(parentId);
entity.setType(typeEnum);
entity.setSort(nextSort(parentId));
sysGroupRepository.save(entity);
SysGroup saved = sysGroupRepository.save(entity);
publishGroupEvent(PushInterfaceType.ADD_GROUP, saved.getId());
}
@Override
@@ -96,6 +104,7 @@ public class SysGroupService implements ISysGroupService {
}
// 注:移动请走 move 接口,edit 不改 parentId,避免与移动逻辑混淆
sysGroupRepository.save(entity);
publishGroupEvent(PushInterfaceType.UPDATE_GROUP, id);
}
@Override
@@ -117,6 +126,7 @@ public class SysGroupService implements ISysGroupService {
sysGroupAppRelRepository.deleteByGroupIdBulk(id);
sysGroupModulePermRepository.deleteByGroupIdBulk(id);
sysGroupRepository.deleteById(id);
publishGroupEvent(PushInterfaceType.DELETE_GROUP, id);
}
@Override
@@ -326,6 +336,8 @@ public class SysGroupService implements ISysGroupService {
batch.add(g);
}
sysGroupRepository.saveAll(batch);
publishGroupEvent(PushInterfaceType.ADD_GROUP,
batch.stream().map(SysGroup::getId).collect(Collectors.toList()));
}
// ===================== 子组排序 =====================
@@ -392,6 +404,7 @@ public class SysGroupService implements ISysGroupService {
moveEntity.setParentId(pid);
moveEntity.setSort(nextSort(pid));
sysGroupRepository.save(moveEntity);
publishGroupEvent(PushInterfaceType.UPDATE_GROUP, moveId);
}
/**
@@ -522,4 +535,23 @@ public class SysGroupService implements ISysGroupService {
vo.setType(entity.getType() == null ? null : entity.getType().getKey());
return vo;
}
// ===================== 推送事件(AFTER_COMMIT 由 PushDispatcher 消费,push_enabled 默认 0 不触发) =====================
private void publishGroupEvent(PushInterfaceType type, Integer groupId) {
DataSyncEvent e = new DataSyncEvent();
e.setType(type);
e.setGroupIds(Collections.singletonList(groupId));
eventPublisher.publishEvent(e);
}
private void publishGroupEvent(PushInterfaceType type, List<Integer> groupIds) {
if (groupIds == null || groupIds.isEmpty()) {
return;
}
DataSyncEvent e = new DataSyncEvent();
e.setType(type);
e.setGroupIds(groupIds);
eventPublisher.publishEvent(e);
}
}
@@ -18,6 +18,9 @@ import com.yunhai.userbase.repository.SysUserGroupRelRepository;
import com.yunhai.userbase.repository.SysUserRepository;
import com.yunhai.userbase.service.ISysGroupService;
import com.yunhai.userbase.service.ISysUserService;
import com.yunhai.userbase.event.DataSyncEvent;
import com.yunhai.userbase.model.push.PushInterfaceType;
import org.springframework.context.ApplicationEventPublisher;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
@@ -79,6 +82,9 @@ public class SysUserService implements ISysUserService {
@Autowired
private SysUserAppRoleRelRepository sysUserAppRoleRelRepository;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Autowired
private SysGroupRepository sysGroupRepository;
@@ -130,7 +136,8 @@ public class SysUserService implements ISysUserService {
// disabled 用枚举存储:不传时默认 NORMAL(正常/未禁用)
entity.setDisabled(request.getDisabled() != null ? resolveStatus(request.getDisabled()) : StatusEnum.NORMAL);
entity.setExpired(request.getExpired() != null ? request.getExpired() : false);
sysUserRepository.save(entity);
SysUser saved = sysUserRepository.save(entity);
publishUserEvent(PushInterfaceType.ADD_USER, saved.getId());
// 写入组用户关联
SysUserGroupRel rel = new SysUserGroupRel();
@@ -175,6 +182,7 @@ public class SysUserService implements ISysUserService {
entity.setExpired(request.getExpired());
}
sysUserRepository.save(entity);
publishUserEvent(PushInterfaceType.UPDATE_USER, id);
}
@Override
@@ -188,6 +196,7 @@ public class SysUserService implements ISysUserService {
// AI-FIX(角色授权): 删除用户时级联清理用户-业务角色绑定(逻辑外键无物理 FK,避免残留孤儿数据)
sysUserAppRoleRelRepository.deleteByUserIdBulk(id);
sysUserRepository.deleteById(id);
publishUserEvent(PushInterfaceType.DELETE_USER, id);
}
@Override
@@ -211,6 +220,7 @@ public class SysUserService implements ISysUserService {
throw new DException("存在无效用户");
}
List<Integer> deletedUserIds = new ArrayList<>();
for (Integer userId : userIds) {
// 删除当前组关联
sysUserGroupRelRepository.deleteByUserIdAndGroupId(userId, groupId);
@@ -218,8 +228,12 @@ public class SysUserService implements ISysUserService {
if (sysUserGroupRelRepository.countByUserId(userId) == 0) {
sysUserAppRoleRelRepository.deleteByUserIdBulk(userId);
sysUserRepository.deleteById(userId);
deletedUserIds.add(userId);
}
}
if (!deletedUserIds.isEmpty()) {
publishUserEvent(PushInterfaceType.DELETE_USER, deletedUserIds);
}
}
@Override
@@ -230,6 +244,7 @@ public class SysUserService implements ISysUserService {
// 实体 disabled 字段为 StatusEnum(0=正常/未禁用,1=禁用):boolean 直接映射枚举
entity.setDisabled(disabled ? StatusEnum.DISABLED : StatusEnum.NORMAL);
sysUserRepository.save(entity);
publishUserEvent(PushInterfaceType.UPDATE_USER, id);
}
@Override
@@ -247,6 +262,8 @@ public class SysUserService implements ISysUserService {
user.setDisabled(targetStatus);
}
sysUserRepository.saveAll(users);
publishUserEvent(PushInterfaceType.UPDATE_USER,
users.stream().map(SysUser::getId).collect(Collectors.toList()));
}
@Override
@@ -362,6 +379,7 @@ public class SysUserService implements ISysUserService {
}
sysUserGroupRelRepository.saveAll(rels);
}
publishUserEvent(PushInterfaceType.UPDATE_USER, userIds);
}
@Override
@@ -936,4 +954,23 @@ public class SysUserService implements ISysUserService {
return null;
}
}
// ===================== 推送事件 =====================
private void publishUserEvent(PushInterfaceType type, Integer userId) {
DataSyncEvent e = new DataSyncEvent();
e.setType(type);
e.setUserIds(Collections.singletonList(userId));
eventPublisher.publishEvent(e);
}
private void publishUserEvent(PushInterfaceType type, List<Integer> userIds) {
if (userIds == null || userIds.isEmpty()) {
return;
}
DataSyncEvent e = new DataSyncEvent();
e.setType(type);
e.setUserIds(userIds);
eventPublisher.publishEvent(e);
}
}