推送订阅添加批量删除功能
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.yunhai.userbase.common.context;
|
||||
|
||||
/**
|
||||
* 开放接口(oapi)调用方来源上下文:在 oapi 请求链路中保存"触发本次数据变更的订阅方 appKey",
|
||||
* 供业务层发布 {@code DataSyncEvent} 时写入事件来源,推送分发器据此回推时排除来源应用自身
|
||||
* (避免应用 A 自己调 oapi 写接口后又收到自己的回声)。<br><br>
|
||||
* <b>生命周期:</b>由 {@code OapiCallerAppInterceptor} 在 {@code preHandle} 写入、
|
||||
* {@code afterCompletion} 强制清除(防线程池复用泄漏)。管理后台 /api/* 写接口不走 oapi 拦截器,
|
||||
* 此处为 null,表示"来源非订阅方",推送不对其做来源排除(全量投递)。<br><br>
|
||||
* 设计与 {@link UserContext} 同套路(ThreadLocal + remove)。
|
||||
*/
|
||||
public class CallerAppContext {
|
||||
|
||||
private static final ThreadLocal<Integer> CALLER_APP_KEY = new ThreadLocal<>();
|
||||
|
||||
public static void setAppKey(Integer appKey) {
|
||||
CALLER_APP_KEY.set(appKey);
|
||||
}
|
||||
|
||||
public static Integer getAppKey() {
|
||||
return CALLER_APP_KEY.get();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
CALLER_APP_KEY.remove();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.yunhai.userbase.config;
|
||||
|
||||
import com.yunhai.platform.appauth.AppAuthFilter;
|
||||
import com.yunhai.userbase.common.context.CallerAppContext;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* oapi 调用方来源注入拦截器:在 oapi 请求处理前,从 yh-app-auth 验签过滤器写入的
|
||||
* {@link AppAuthFilter#APP_AUTH_ATTR}(调用方 appKey)解析出整型 appKey,
|
||||
* 存入 {@link CallerAppContext};请求结束(无论成功/异常)在 {@code afterCompletion} 强制清除,
|
||||
* 防止线程池复用导致 appKey 串号、进而误把其他订阅方排除。<br><br>
|
||||
* 配合 {@code PushDispatcher} 的来源排除逻辑,实现"应用自己触发的变更不回推给自己"。
|
||||
* 管理后台 /api/* 不走此拦截器 → CallerAppContext 为 null → 推送对该来源不做排除(全量投递)。
|
||||
*/
|
||||
@Component
|
||||
public class OapiCallerAppInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler) {
|
||||
Object attr = request.getAttribute(AppAuthFilter.APP_AUTH_ATTR);
|
||||
if (attr == null) {
|
||||
return true;
|
||||
}
|
||||
String appKeyStr = (attr instanceof String) ? (String) attr : String.valueOf(attr);
|
||||
if (StringUtils.isBlank(appKeyStr)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
CallerAppContext.setAppKey(Integer.valueOf(appKeyStr.trim()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
// 非法 appKey 格式:不设置来源,等同"非订阅方来源",推送全量投递
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler, Exception ex) {
|
||||
CallerAppContext.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.yunhai.userbase.model.sysuser;
|
||||
|
||||
/**
|
||||
* 批量删除用户-组关系单项(与 BasePlatform 开放接口模型 {@code SysUserGroupDeleteItem} 字段对齐)。<br>
|
||||
* 每条记录携带自身所属学校范围 {@code schoolId},供 {@code SysUserService.deleteUsers} 逐条校验:<br>
|
||||
* groupId 必须属于 schoolId 子树且不能等于 schoolId(禁止跨校解绑 / 整校移除)。
|
||||
*/
|
||||
public class SysUserGroupDeleteItem {
|
||||
|
||||
/** 待解绑用户 ID */
|
||||
private Integer userId;
|
||||
/** 待解绑的组 ID(必须属于 schoolId 子树,且不能等于 schoolId) */
|
||||
private Integer groupId;
|
||||
/** 学校组 ID:限定该条解绑的学校范围 */
|
||||
private Integer schoolId;
|
||||
|
||||
public Integer getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(Integer userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public Integer getSchoolId() {
|
||||
return schoolId;
|
||||
}
|
||||
|
||||
public void setSchoolId(Integer schoolId) {
|
||||
this.schoolId = schoolId;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user