package com.admin.service.impl; import com.admin.common.dto.GroupCreateDto; import com.admin.common.dto.GroupPermissionAssignDto; import com.admin.common.dto.GroupPermissionDetailDto; import com.admin.common.dto.GroupUpdateDto; import com.admin.common.dto.TunnelGroupAssignTunnelsDto; import com.admin.common.dto.TunnelGroupDetailDto; import com.admin.common.dto.UserGroupAssignUsersDto; import com.admin.common.dto.UserGroupDetailDto; import com.admin.common.lang.R; import com.admin.entity.GroupPermission; import com.admin.entity.GroupPermissionGrant; import com.admin.entity.Tunnel; import com.admin.entity.TunnelGroup; import com.admin.entity.TunnelGroupTunnel; import com.admin.entity.User; import com.admin.entity.UserGroup; import com.admin.entity.UserGroupUser; import com.admin.entity.UserTunnel; import com.admin.mapper.GroupPermissionGrantMapper; import com.admin.mapper.GroupPermissionMapper; import com.admin.mapper.TunnelGroupMapper; import com.admin.mapper.TunnelGroupTunnelMapper; import com.admin.mapper.UserGroupMapper; import com.admin.mapper.UserGroupUserMapper; import com.admin.service.GroupService; import com.admin.service.TunnelService; import com.admin.service.UserService; import com.admin.service.UserTunnelService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @Service public class GroupServiceImpl implements GroupService { @Resource private TunnelGroupMapper tunnelGroupMapper; @Resource private UserGroupMapper userGroupMapper; @Resource private TunnelGroupTunnelMapper tunnelGroupTunnelMapper; @Resource private UserGroupUserMapper userGroupUserMapper; @Resource private GroupPermissionMapper groupPermissionMapper; @Resource private GroupPermissionGrantMapper groupPermissionGrantMapper; @Resource private TunnelService tunnelService; @Resource private UserService userService; @Resource private UserTunnelService userTunnelService; @Override public R getTunnelGroups() { List groups = tunnelGroupMapper.selectList(new QueryWrapper().orderByAsc("id")); List mappings = tunnelGroupTunnelMapper.selectList(new QueryWrapper()); Map> mappingByGroupId = mappings.stream() .collect(Collectors.groupingBy(TunnelGroupTunnel::getTunnelGroupId)); Set tunnelIds = mappings.stream().map(TunnelGroupTunnel::getTunnelId).collect(Collectors.toSet()); Map tunnelNameMap = buildTunnelNameMap(tunnelIds); List result = new ArrayList<>(); for (TunnelGroup group : groups) { TunnelGroupDetailDto dto = new TunnelGroupDetailDto(); dto.setId(group.getId()); dto.setName(group.getName()); dto.setStatus(group.getStatus()); dto.setCreatedTime(group.getCreatedTime()); dto.setUpdatedTime(group.getUpdatedTime()); List groupMappings = mappingByGroupId.getOrDefault(group.getId(), Collections.emptyList()); List ids = groupMappings.stream().map(TunnelGroupTunnel::getTunnelId).collect(Collectors.toList()); List names = ids.stream().map(tunnelNameMap::get).filter(name -> name != null && !name.isBlank()).collect(Collectors.toList()); dto.setTunnelIds(ids); dto.setTunnelNames(names); result.add(dto); } return R.ok(result); } @Override public R createTunnelGroup(GroupCreateDto dto) { String name = dto.getName().trim(); int count = tunnelGroupMapper.selectCount(new QueryWrapper().eq("name", name)); if (count > 0) { return R.err("隧道分组名称已存在"); } long now = System.currentTimeMillis(); TunnelGroup group = new TunnelGroup(); group.setName(name); group.setStatus(normalizeStatus(dto.getStatus())); group.setCreatedTime(now); group.setUpdatedTime(now); tunnelGroupMapper.insert(group); return R.ok(); } @Override public R updateTunnelGroup(GroupUpdateDto dto) { TunnelGroup group = tunnelGroupMapper.selectById(dto.getId()); if (group == null) { return R.err("隧道分组不存在"); } String name = dto.getName().trim(); int count = tunnelGroupMapper.selectCount(new QueryWrapper().eq("name", name).ne("id", dto.getId())); if (count > 0) { return R.err("隧道分组名称已存在"); } group.setName(name); if (dto.getStatus() != null) { group.setStatus(dto.getStatus()); } group.setUpdatedTime(System.currentTimeMillis()); tunnelGroupMapper.updateById(group); return R.ok(); } @Override public R deleteTunnelGroup(Long id) { TunnelGroup group = tunnelGroupMapper.selectById(id); if (group == null) { return R.err("隧道分组不存在"); } List grants = groupPermissionGrantMapper.selectList(new QueryWrapper().eq("tunnel_group_id", id)); revokeGrantRecords(grants); tunnelGroupTunnelMapper.delete(new QueryWrapper().eq("tunnel_group_id", id)); groupPermissionMapper.delete(new QueryWrapper().eq("tunnel_group_id", id)); tunnelGroupMapper.deleteById(id); return R.ok(); } @Override public R assignTunnelsToGroup(TunnelGroupAssignTunnelsDto dto) { TunnelGroup group = tunnelGroupMapper.selectById(dto.getGroupId()); if (group == null) { return R.err("隧道分组不存在"); } Set tunnelIds = new LinkedHashSet<>(dto.getTunnelIds()); if (!tunnelIds.isEmpty()) { List tunnels = tunnelService.list(new QueryWrapper().in("id", tunnelIds)); if (tunnels.size() != tunnelIds.size()) { return R.err("隧道列表中存在无效ID"); } } tunnelGroupTunnelMapper.delete(new QueryWrapper().eq("tunnel_group_id", dto.getGroupId())); if (!tunnelIds.isEmpty()) { long now = System.currentTimeMillis(); for (Long tunnelId : tunnelIds) { TunnelGroupTunnel relation = new TunnelGroupTunnel(); relation.setTunnelGroupId(dto.getGroupId()); relation.setTunnelId(tunnelId); relation.setCreatedTime(now); tunnelGroupTunnelMapper.insert(relation); } } syncByTunnelGroup(dto.getGroupId()); return R.ok(); } @Override public R getUserGroups() { List groups = userGroupMapper.selectList(new QueryWrapper().orderByAsc("id")); List mappings = userGroupUserMapper.selectList(new QueryWrapper()); Map> mappingByGroupId = mappings.stream() .collect(Collectors.groupingBy(UserGroupUser::getUserGroupId)); Set userIds = mappings.stream().map(UserGroupUser::getUserId).collect(Collectors.toSet()); Map userNameMap = buildUserNameMap(userIds); List result = new ArrayList<>(); for (UserGroup group : groups) { UserGroupDetailDto dto = new UserGroupDetailDto(); dto.setId(group.getId()); dto.setName(group.getName()); dto.setStatus(group.getStatus()); dto.setCreatedTime(group.getCreatedTime()); dto.setUpdatedTime(group.getUpdatedTime()); List groupMappings = mappingByGroupId.getOrDefault(group.getId(), Collections.emptyList()); List ids = groupMappings.stream().map(UserGroupUser::getUserId).collect(Collectors.toList()); List names = ids.stream().map(userNameMap::get).filter(name -> name != null && !name.isBlank()).collect(Collectors.toList()); dto.setUserIds(ids); dto.setUserNames(names); result.add(dto); } return R.ok(result); } @Override public R createUserGroup(GroupCreateDto dto) { String name = dto.getName().trim(); int count = userGroupMapper.selectCount(new QueryWrapper().eq("name", name)); if (count > 0) { return R.err("用户分组名称已存在"); } long now = System.currentTimeMillis(); UserGroup group = new UserGroup(); group.setName(name); group.setStatus(normalizeStatus(dto.getStatus())); group.setCreatedTime(now); group.setUpdatedTime(now); userGroupMapper.insert(group); return R.ok(); } @Override public R updateUserGroup(GroupUpdateDto dto) { UserGroup group = userGroupMapper.selectById(dto.getId()); if (group == null) { return R.err("用户分组不存在"); } String name = dto.getName().trim(); int count = userGroupMapper.selectCount(new QueryWrapper().eq("name", name).ne("id", dto.getId())); if (count > 0) { return R.err("用户分组名称已存在"); } group.setName(name); if (dto.getStatus() != null) { group.setStatus(dto.getStatus()); } group.setUpdatedTime(System.currentTimeMillis()); userGroupMapper.updateById(group); return R.ok(); } @Override public R deleteUserGroup(Long id) { UserGroup group = userGroupMapper.selectById(id); if (group == null) { return R.err("用户分组不存在"); } List grants = groupPermissionGrantMapper.selectList(new QueryWrapper().eq("user_group_id", id)); revokeGrantRecords(grants); userGroupUserMapper.delete(new QueryWrapper().eq("user_group_id", id)); groupPermissionMapper.delete(new QueryWrapper().eq("user_group_id", id)); userGroupMapper.deleteById(id); return R.ok(); } @Override public R assignUsersToGroup(UserGroupAssignUsersDto dto) { UserGroup group = userGroupMapper.selectById(dto.getGroupId()); if (group == null) { return R.err("用户分组不存在"); } Set userIds = new LinkedHashSet<>(dto.getUserIds()); if (!userIds.isEmpty()) { List users = userService.list(new QueryWrapper().in("id", userIds).ne("role_id", 0)); if (users.size() != userIds.size()) { return R.err("用户列表中存在无效ID"); } } userGroupUserMapper.delete(new QueryWrapper().eq("user_group_id", dto.getGroupId())); if (!userIds.isEmpty()) { long now = System.currentTimeMillis(); for (Long userId : userIds) { UserGroupUser relation = new UserGroupUser(); relation.setUserGroupId(dto.getGroupId()); relation.setUserId(userId); relation.setCreatedTime(now); userGroupUserMapper.insert(relation); } } syncByUserGroup(dto.getGroupId()); return R.ok(); } @Override public R getGroupPermissions() { List permissions = groupPermissionMapper.selectList(new QueryWrapper().orderByDesc("id")); if (permissions.isEmpty()) { return R.ok(new ArrayList()); } Set userGroupIds = permissions.stream().map(GroupPermission::getUserGroupId).collect(Collectors.toSet()); Set tunnelGroupIds = permissions.stream().map(GroupPermission::getTunnelGroupId).collect(Collectors.toSet()); Map userGroupNameMap = userGroupMapper.selectList(new QueryWrapper().in("id", userGroupIds)).stream() .collect(Collectors.toMap(UserGroup::getId, UserGroup::getName)); Map tunnelGroupNameMap = tunnelGroupMapper.selectList(new QueryWrapper().in("id", tunnelGroupIds)).stream() .collect(Collectors.toMap(TunnelGroup::getId, TunnelGroup::getName)); List result = new ArrayList<>(); for (GroupPermission permission : permissions) { GroupPermissionDetailDto dto = new GroupPermissionDetailDto(); dto.setId(permission.getId()); dto.setUserGroupId(permission.getUserGroupId()); dto.setTunnelGroupId(permission.getTunnelGroupId()); dto.setCreatedTime(permission.getCreatedTime()); dto.setUserGroupName(userGroupNameMap.get(permission.getUserGroupId())); dto.setTunnelGroupName(tunnelGroupNameMap.get(permission.getTunnelGroupId())); result.add(dto); } return R.ok(result); } @Override public R assignGroupPermission(GroupPermissionAssignDto dto) { UserGroup userGroup = userGroupMapper.selectById(dto.getUserGroupId()); if (userGroup == null) { return R.err("用户分组不存在"); } TunnelGroup tunnelGroup = tunnelGroupMapper.selectById(dto.getTunnelGroupId()); if (tunnelGroup == null) { return R.err("隧道分组不存在"); } int existing = groupPermissionMapper.selectCount(new QueryWrapper() .eq("user_group_id", dto.getUserGroupId()) .eq("tunnel_group_id", dto.getTunnelGroupId())); if (existing == 0) { GroupPermission permission = new GroupPermission(); permission.setUserGroupId(dto.getUserGroupId()); permission.setTunnelGroupId(dto.getTunnelGroupId()); permission.setCreatedTime(System.currentTimeMillis()); groupPermissionMapper.insert(permission); } reconcilePermission(dto.getUserGroupId(), dto.getTunnelGroupId()); return existing > 0 ? R.ok("权限已存在,已完成同步") : R.ok(); } @Override public R removeGroupPermission(Long id) { GroupPermission permission = groupPermissionMapper.selectById(id); if (permission == null) { return R.err("权限记录不存在"); } revokeByPermissionPair(permission.getUserGroupId(), permission.getTunnelGroupId()); groupPermissionMapper.deleteById(id); return R.ok(); } private void syncByUserGroup(Long userGroupId) { List permissions = groupPermissionMapper.selectList(new QueryWrapper().eq("user_group_id", userGroupId)); for (GroupPermission permission : permissions) { reconcilePermission(permission.getUserGroupId(), permission.getTunnelGroupId()); } } private void syncByTunnelGroup(Long tunnelGroupId) { List permissions = groupPermissionMapper.selectList(new QueryWrapper().eq("tunnel_group_id", tunnelGroupId)); for (GroupPermission permission : permissions) { reconcilePermission(permission.getUserGroupId(), permission.getTunnelGroupId()); } } private void reconcilePermission(Long userGroupId, Long tunnelGroupId) { Set userIds = userGroupUserMapper.selectList(new QueryWrapper().eq("user_group_id", userGroupId)).stream() .map(UserGroupUser::getUserId) .collect(Collectors.toCollection(LinkedHashSet::new)); Set tunnelIds = tunnelGroupTunnelMapper.selectList(new QueryWrapper().eq("tunnel_group_id", tunnelGroupId)).stream() .map(TunnelGroupTunnel::getTunnelId) .collect(Collectors.toCollection(LinkedHashSet::new)); Set desiredKeys = new HashSet<>(); for (Long userId : userIds) { for (Long tunnelId : tunnelIds) { desiredKeys.add(permissionKey(userId, tunnelId)); } } List currentGrants = groupPermissionGrantMapper.selectList( new QueryWrapper() .eq("user_group_id", userGroupId) .eq("tunnel_group_id", tunnelGroupId) ); Set grantUserTunnelIds = currentGrants.stream().map(GroupPermissionGrant::getUserTunnelId).collect(Collectors.toSet()); Map grantUserTunnelMap = new HashMap<>(); if (!grantUserTunnelIds.isEmpty()) { List userTunnels = userTunnelService.list(new QueryWrapper().in("id", grantUserTunnelIds)); grantUserTunnelMap = userTunnels.stream().collect(Collectors.toMap(ut -> ut.getId().longValue(), Function.identity())); } Map pairUserTunnelMap = new HashMap<>(); if (!userIds.isEmpty() && !tunnelIds.isEmpty()) { List pairUserTunnels = userTunnelService.list(new QueryWrapper() .in("user_id", userIds) .in("tunnel_id", tunnelIds)); for (UserTunnel userTunnel : pairUserTunnels) { pairUserTunnelMap.putIfAbsent(permissionKey(userTunnel.getUserId().longValue(), userTunnel.getTunnelId().longValue()), userTunnel); } } Set pairUserTunnelIds = pairUserTunnelMap.values().stream() .map(ut -> ut.getId().longValue()) .collect(Collectors.toSet()); Map totalGrantCountMap = buildGrantCountMap(pairUserTunnelIds); Set groupManagedUserTunnelIds = buildGroupManagedUserTunnelIds(pairUserTunnelIds); Set currentGrantUserTunnelIds = currentGrants.stream().map(GroupPermissionGrant::getUserTunnelId).collect(Collectors.toSet()); if (!desiredKeys.isEmpty()) { Map userMap = userService.list(new QueryWrapper().in("id", userIds)).stream() .collect(Collectors.toMap(User::getId, Function.identity())); long now = System.currentTimeMillis(); for (Long userId : userIds) { User user = userMap.get(userId); if (user == null) { continue; } for (Long tunnelId : tunnelIds) { String pairKey = permissionKey(userId, tunnelId); UserTunnel userTunnel = pairUserTunnelMap.get(pairKey); if (userTunnel == null) { userTunnel = createGroupManagedUserTunnel(userId, tunnelId, user); pairUserTunnelMap.put(pairKey, userTunnel); createGrant(userGroupId, tunnelGroupId, userTunnel.getId().longValue(), true, now); currentGrantUserTunnelIds.add(userTunnel.getId().longValue()); totalGrantCountMap.put(userTunnel.getId().longValue(), 1L); groupManagedUserTunnelIds.add(userTunnel.getId().longValue()); continue; } Long userTunnelId = userTunnel.getId().longValue(); if (currentGrantUserTunnelIds.contains(userTunnelId)) { continue; } long existingGrantCount = totalGrantCountMap.getOrDefault(userTunnelId, 0L); boolean createdByGroup = groupManagedUserTunnelIds.contains(userTunnelId); createGrant(userGroupId, tunnelGroupId, userTunnelId, createdByGroup, now); currentGrantUserTunnelIds.add(userTunnelId); totalGrantCountMap.put(userTunnelId, existingGrantCount + 1L); } } } List staleGrants = new ArrayList<>(); for (GroupPermissionGrant grant : currentGrants) { UserTunnel userTunnel = grantUserTunnelMap.get(grant.getUserTunnelId()); boolean keep = false; if (userTunnel != null) { String key = permissionKey(userTunnel.getUserId().longValue(), userTunnel.getTunnelId().longValue()); keep = desiredKeys.contains(key); } if (!keep) { staleGrants.add(grant); } } revokeGrantRecords(staleGrants); } private UserTunnel createGroupManagedUserTunnel(Long userId, Long tunnelId, User user) { UserTunnel userTunnel = new UserTunnel(); userTunnel.setUserId(userId.intValue()); userTunnel.setTunnelId(tunnelId.intValue()); userTunnel.setStatus(1); userTunnel.setInFlow(0L); userTunnel.setOutFlow(0L); userTunnel.setFlow(user.getFlow()); userTunnel.setNum(user.getNum()); userTunnel.setFlowResetTime(user.getFlowResetTime()); userTunnel.setExpTime(user.getExpTime()); userTunnelService.save(userTunnel); return userTunnel; } private void createGrant(Long userGroupId, Long tunnelGroupId, Long userTunnelId, boolean createdByGroup, long createdTime) { int exists = groupPermissionGrantMapper.selectCount(new QueryWrapper() .eq("user_group_id", userGroupId) .eq("tunnel_group_id", tunnelGroupId) .eq("user_tunnel_id", userTunnelId)); if (exists > 0) { return; } GroupPermissionGrant grant = new GroupPermissionGrant(); grant.setUserGroupId(userGroupId); grant.setTunnelGroupId(tunnelGroupId); grant.setUserTunnelId(userTunnelId); grant.setCreatedByGroup(createdByGroup ? 1 : 0); grant.setCreatedTime(createdTime); groupPermissionGrantMapper.insert(grant); } private void revokeByPermissionPair(Long userGroupId, Long tunnelGroupId) { List grants = groupPermissionGrantMapper.selectList(new QueryWrapper() .eq("user_group_id", userGroupId) .eq("tunnel_group_id", tunnelGroupId)); revokeGrantRecords(grants); } private void revokeGrantRecords(List grants) { if (grants == null || grants.isEmpty()) { return; } Set candidateUserTunnelIds = new HashSet<>(); Set groupManagedCandidates = new HashSet<>(); for (GroupPermissionGrant grant : grants) { candidateUserTunnelIds.add(grant.getUserTunnelId()); if (grant.getCreatedByGroup() != null && grant.getCreatedByGroup() == 1) { groupManagedCandidates.add(grant.getUserTunnelId()); } groupPermissionGrantMapper.deleteById(grant.getId()); } Set stillGrantedUserTunnelIds = groupPermissionGrantMapper.selectList( new QueryWrapper().in("user_tunnel_id", candidateUserTunnelIds) ).stream() .map(GroupPermissionGrant::getUserTunnelId) .collect(Collectors.toSet()); for (Long userTunnelId : candidateUserTunnelIds) { if (!stillGrantedUserTunnelIds.contains(userTunnelId) && groupManagedCandidates.contains(userTunnelId)) { userTunnelService.removeUserTunnel(userTunnelId.intValue()); } } } private Set buildGroupManagedUserTunnelIds(Set userTunnelIds) { if (userTunnelIds.isEmpty()) { return Collections.emptySet(); } return groupPermissionGrantMapper.selectList(new QueryWrapper() .in("user_tunnel_id", userTunnelIds) .eq("created_by_group", 1)) .stream() .map(GroupPermissionGrant::getUserTunnelId) .collect(Collectors.toSet()); } private Map buildGrantCountMap(Set userTunnelIds) { if (userTunnelIds.isEmpty()) { return new HashMap<>(); } List grants = groupPermissionGrantMapper.selectList(new QueryWrapper().in("user_tunnel_id", userTunnelIds)); Map countMap = new HashMap<>(); for (GroupPermissionGrant grant : grants) { countMap.merge(grant.getUserTunnelId(), 1L, Long::sum); } return countMap; } private Map buildTunnelNameMap(Set tunnelIds) { if (tunnelIds.isEmpty()) { return Collections.emptyMap(); } return tunnelService.list(new QueryWrapper().in("id", tunnelIds)).stream() .collect(Collectors.toMap(Tunnel::getId, Tunnel::getName)); } private Map buildUserNameMap(Set userIds) { if (userIds.isEmpty()) { return Collections.emptyMap(); } return userService.list(new QueryWrapper().in("id", userIds)).stream() .collect(Collectors.toMap(User::getId, User::getUser)); } private String permissionKey(Long userId, Long tunnelId) { return userId + "_" + tunnelId; } private int normalizeStatus(Integer status) { return status == null ? 1 : status; } }