Compare commits

..
2 Commits
Author SHA1 Message Date
chenxing b5f6679eb5 缺失的文件补传
ci-userbase-service / build-and-push (push) Successful in 1m18s
2026-08-13 19:19:58 +08:00
chenxing 5cfed17956 开放接口新增获取组数据相关接口 2026-08-13 19:15:47 +08:00
6 changed files with 215 additions and 0 deletions
@@ -3,6 +3,7 @@ package com.yunhai.userbase.config;
import com.yunhai.platform.appauth.AppAuthFilter; import com.yunhai.platform.appauth.AppAuthFilter;
import com.yunhai.platform.appauth.AppAuthProperties; import com.yunhai.platform.appauth.AppAuthProperties;
import com.yunhai.platform.auth.UserDetailsProvider; import com.yunhai.platform.auth.UserDetailsProvider;
import com.yunhai.userbase.repository.ApplicationInfoRepository;
import com.yunhai.userbase.service.impl.UserCenterService; import com.yunhai.userbase.service.impl.UserCenterService;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -3,6 +3,7 @@ package com.yunhai.userbase.config;
import com.yunhai.platform.auth.UserDetailsProvider; import com.yunhai.platform.auth.UserDetailsProvider;
import com.yunhai.platform.utils.model.BoaUser; import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userbase.service.impl.UserCenterService; import com.yunhai.userbase.service.impl.UserCenterService;
import com.yunhai.userbase.service.impl.UserCenterService;
/** /**
* 平台 {@link UserDetailsProvider} 的 UserBase 本地实现:CAS 会话流解析出登录名/手机号后, * 平台 {@link UserDetailsProvider} 的 UserBase 本地实现:CAS 会话流解析出登录名/手机号后,
@@ -43,6 +43,7 @@ public class SysUserController {
@PostMapping("Add") @PostMapping("Add")
public void add(@RequestBody @Validated(ValidationGroups.Create.class) SysUserRequest request) { public void add(@RequestBody @Validated(ValidationGroups.Create.class) SysUserRequest request) {
List<String> data=new ArrayList<>(); List<String> data=new ArrayList<>();
sysUserService.add(request); sysUserService.add(request);
} }
@@ -0,0 +1,63 @@
package com.yunhai.userbase.controller.oapi;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.userbase.config.Config;
import com.yunhai.userbase.service.ISysGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 组织架构开放接口:供其他业务服务经 yh-app-auth 签名调用({@code /oapi/group/...})。<br>
* <br>
* 路径复用 {@link Config#OPEN_API_PATH} 统一前缀,与基础平台 {@code DefaultUserCenterClient}
* 硬编码的契约严格一致:
* {@code GET /oapi/group/tree}、{@code /byId?groupId=&withSub=}、{@code /list?ids=&withSub=}。<br>
* 接口本身不做验签——签名由 {@code OpenApiAuthEnforceConfiguration} 在过滤器层强制要求,
* 未带 {@code X-App-Key/X-Timestamp/X-Signature} 的请求直接 401。
*/
@RestController
@RequestMapping(Config.OPEN_API_PATH + "group/")
public class GroupController {
@Autowired
private ISysGroupService sysGroupService;
/**
* 获取整个平台的组树(从根节点开始,children 递归嵌套全部后代)。
*/
@GetMapping("tree")
public BoaGroup tree() {
return sysGroupService.getGroups();
}
/**
* 获取单个组;withSub=true 时递归挂上全部子孙(整棵子树)。
*
* @param groupId 组ID(必填)
* @param withSub 是否展开子节点,缺省 false
* @return 组节点;不存在返回 null
*/
@GetMapping("byId")
public BoaGroup byId(@RequestParam("groupId") Integer groupId,
@RequestParam(value = "withSub", required = false) Boolean withSub) {
return sysGroupService.getGroupById(groupId, withSub);
}
/**
* 批量获取组;ids 逗号/空格分隔,按入参顺序返回,不存在的跳过。
*
* @param ids 组ID列表(逗号/空格分隔)
* @param withSub 是否展开子节点,缺省 false
* @return 组节点列表(按入参顺序;不存在的跳过)
*/
@GetMapping("list")
public List<BoaGroup> list(@RequestParam("ids") String ids,
@RequestParam(value = "withSub", required = false) Boolean withSub) {
return sysGroupService.getGroupList(ids, withSub);
}
}
@@ -5,6 +5,7 @@ import com.yunhai.userbase.model.sysgroup.SysGroupMoveRequest;
import com.yunhai.userbase.model.sysgroup.SysGroupQuery; import com.yunhai.userbase.model.sysgroup.SysGroupQuery;
import com.yunhai.userbase.model.sysgroup.SysGroupRequest; import com.yunhai.userbase.model.sysgroup.SysGroupRequest;
import com.yunhai.userbase.model.sysgroup.SysGroupSortRequest; import com.yunhai.userbase.model.sysgroup.SysGroupSortRequest;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.userbase.model.sysgroup.SysGroupVo; import com.yunhai.userbase.model.sysgroup.SysGroupVo;
import java.util.List; import java.util.List;
@@ -51,4 +52,30 @@ public interface ISysGroupService {
* @return 含自身在内的组ID集合;组不存在时返回仅含自身的集合 * @return 含自身在内的组ID集合;组不存在时返回仅含自身的集合
*/ */
List<Integer> listSelfAndDescendantIds(Integer groupId); List<Integer> listSelfAndDescendantIds(Integer groupId);
/**
* 获取整个平台的组树:从根节点(pid=0)开始,children 递归嵌套全部后代。<br>
* 根节点唯一,取最小 id 作为树入口。表为空时返回 null。
*/
BoaGroup getGroups();
/**
* 获取单个组;withSub=true 时递归挂上全部子孙(整棵子树),false/不传时只返回节点本身(children 为 null)。<br>
* 组不存在时返回 null。
*
* @param groupId 组ID
* @param withSub 是否展开子节点,缺省 false
* @return 组节点(BoaGroup)
*/
BoaGroup getGroupById(Integer groupId, Boolean withSub);
/**
* 批量获取组;ids 逗号/空格分隔,按入参顺序返回,不存在的 id 跳过。<br>
* withSub 语义同 {@link #getGroupById(Integer, Boolean)}。
*
* @param ids 组ID列表(逗号/空格分隔)
* @param withSub 是否展开子节点,缺省 false
* @return 组节点列表(按入参顺序;不存在的跳过)
*/
List<BoaGroup> getGroupList(String ids, Boolean withSub);
} }
@@ -2,6 +2,7 @@ package com.yunhai.userbase.service.impl;
import com.yunhai.userbase.entity.SysGroup; import com.yunhai.userbase.entity.SysGroup;
import com.yunhai.platform.utils.exception.DException; 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.GroupTypeEnum;
import com.yunhai.userbase.enums.IEnum; import com.yunhai.userbase.enums.IEnum;
import com.yunhai.userbase.model.sysgroup.SysGroupBatchRequest; import com.yunhai.userbase.model.sysgroup.SysGroupBatchRequest;
@@ -223,6 +224,77 @@ public class SysGroupService implements ISysGroupService {
return vo; return vo;
} }
// ===================== 开放接口:组树(BoaGroup) =====================
/**
* 获取整个平台的组树:从根节点(pid=0)开始,children 递归嵌套全部后代。<br>
* 根节点唯一,取最小 id 作为树入口。表为空或无根时返回 null。
*/
@Override
public BoaGroup getGroups() {
List<SysGroup> all = sysGroupRepository.findAll();
if (all.isEmpty()) {
return null;
}
Map<Integer, List<SysGroup>> childrenMap = buildSortedChildrenMap(all);
List<SysGroup> roots = childrenMap.getOrDefault(ROOT_PARENT_ID, new ArrayList<>());
if (roots.isEmpty()) {
return null;
}
// 根节点唯一,取最小 id 作为整棵树入口
SysGroup root = roots.stream()
.min(Comparator.comparingInt(SysGroup::getId))
.orElse(roots.get(0));
return buildBoaNode(root, childrenMap, true);
}
/**
* 获取单个组;withSub=true 时递归挂上全部子孙(整棵子树),false/不传时只返回节点本身(children 为 null)。<br>
* 组不存在时返回 null。
*/
@Override
public BoaGroup getGroupById(Integer groupId, Boolean withSub) {
if (groupId == null) {
return null;
}
SysGroup entity = sysGroupRepository.findById(groupId).orElse(null);
if (entity == null) {
return null;
}
if (!Boolean.TRUE.equals(withSub)) {
return convertToBoaGroup(entity);
}
List<SysGroup> all = sysGroupRepository.findAll();
Map<Integer, List<SysGroup>> childrenMap = buildSortedChildrenMap(all);
return buildBoaNode(entity, childrenMap, true);
}
/**
* 批量获取组;ids 逗号/空格分隔,按入参顺序返回,不存在的 id 跳过。<br>
* withSub 语义同 {@link #getGroupById(Integer, Boolean)}。
*/
@Override
public List<BoaGroup> getGroupList(String ids, Boolean withSub) {
List<Integer> idList = parseIds(ids);
if (idList.isEmpty()) {
return new ArrayList<>();
}
boolean expand = Boolean.TRUE.equals(withSub);
List<SysGroup> all = sysGroupRepository.findAll();
Map<Integer, SysGroup> allMap = all.stream()
.collect(Collectors.toMap(SysGroup::getId, g -> g, (a, b) -> a));
Map<Integer, List<SysGroup>> childrenMap = buildSortedChildrenMap(all);
List<BoaGroup> result = new ArrayList<>();
for (Integer id : idList) {
SysGroup g = allMap.get(id);
if (g == null) {
continue;
}
result.add(expand ? buildBoaNode(g, childrenMap, true) : convertToBoaGroup(g));
}
return result;
}
// ===================== 批量新增 ===================== // ===================== 批量新增 =====================
@Override @Override
@@ -374,6 +446,56 @@ public class SysGroupService implements ISysGroupService {
// ===================== 私有工具 ===================== // ===================== 私有工具 =====================
/** SysGroup -> BoaGroup(id/name/parentId/type/sort);children 默认 null(未展开)。 */
private BoaGroup convertToBoaGroup(SysGroup entity) {
BoaGroup bg = new BoaGroup();
bg.setId(entity.getId());
bg.setName(entity.getName());
bg.setParentId(entity.getParentId());
bg.setType(entity.getType() == null ? null : entity.getType().getKey());
bg.setSort(entity.getSort());
return bg;
}
/**
* 递归组装 BoaGroup 树节点。withSub=true 时挂上全部子孙(子树),children 为列表(无子则空列表);
* withSub=false 时直接返回节点,children 保持 null(表示未展开)。
*/
private BoaGroup buildBoaNode(SysGroup node, Map<Integer, List<SysGroup>> childrenMap, boolean withSub) {
BoaGroup bg = convertToBoaGroup(node);
if (!withSub) {
return bg;
}
List<BoaGroup> childBgs = new ArrayList<>();
List<SysGroup> children = childrenMap.get(node.getId());
if (children != null) {
for (SysGroup child : children) {
childBgs.add(buildBoaNode(child, childrenMap, true));
}
}
bg.setChildren(childBgs);
return bg;
}
/** 解析逗号/空格分隔的 id 串为 Integer 列表;非数字片段忽略。 */
private List<Integer> parseIds(String ids) {
List<Integer> result = new ArrayList<>();
if (ids == null || ids.trim().isEmpty()) {
return result;
}
for (String s : ids.split("[,\\s]+")) {
if (s == null || s.trim().isEmpty()) {
continue;
}
try {
result.add(Integer.parseInt(s.trim()));
} catch (NumberFormatException ignored) {
// 跳过非数字片段
}
}
return result;
}
/** pid 下已有子节点的最大 sort +1;无子节点返回 1。 */ /** pid 下已有子节点的最大 sort +1;无子节点返回 1。 */
private int nextSort(Integer pid) { private int nextSort(Integer pid) {
Integer max = sysGroupRepository.findMaxSortByParentId(pid); Integer max = sysGroupRepository.findMaxSortByParentId(pid);