content: 
  package com.platform.modules.system.service.impl;
  
  import cn.hutool.core.collection.CollectionUtil;
  import lombok.RequiredArgsConstructor;
  import com.platform.exception.BadRequestException;
  import com.platform.modules.security.service.UserCacheManager;
  import com.platform.modules.security.service.dto.AuthorityDto;
  import com.platform.modules.system.domain.Menu;
  import com.platform.modules.system.domain.Role;
  import com.platform.exception.EntityExistException;
  import com.platform.modules.system.domain.User;
  import com.platform.modules.system.repository.RoleRepository;
  import com.platform.modules.system.repository.UserRepository;
  import com.platform.modules.system.service.RoleService;
  import com.platform.modules.system.service.dto.RoleDto;
  import com.platform.modules.system.service.dto.RoleQueryCriteria;
  import com.platform.modules.system.service.dto.RoleSmallDto;
  import com.platform.modules.system.service.dto.UserDto;
  import com.platform.modules.system.service.mapstruct.RoleMapper;
  import com.platform.modules.system.service.mapstruct.RoleSmallMapper;
  import com.platform.utils.*;
  import org.springframework.cache.annotation.CacheConfig;
  import org.springframework.cache.annotation.Cacheable;
  import org.springframework.data.domain.Page;
  import org.springframework.data.domain.Pageable;
  import org.springframework.data.domain.Sort;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  import javax.servlet.http.HttpServletResponse;
  import java.io.IOException;
  import java.util.*;
  import java.util.stream.Collectors;
  
  /**
   * @author AllDataDC
   * @date 2023-01-27
   */
  @Service
  @RequiredArgsConstructor
  @CacheConfig(cacheNames = "role")
  public class RoleServiceImpl implements RoleService {
  
      private final RoleRepository roleRepository;
      private final RoleMapper roleMapper;
      private final RoleSmallMapper roleSmallMapper;
      private final RedisUtils redisUtils;
      private final UserRepository userRepository;
      private final UserCacheManager userCacheManager;
  
      @Override
      public List<RoleDto> queryAll() {
          Sort sort = Sort.by(Sort.Direction.ASC, "level");
          return roleMapper.toDto(roleRepository.findAll(sort));
      }
  
      @Override
      public List<RoleDto> queryAll(RoleQueryCriteria criteria) {
          return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
      }
  
      @Override
      public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) {
          Page<Role> page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
          return PageUtil.toPage(page.map(roleMapper::toDto));
      }
  
      @Override
      @Cacheable(key = "'id:' + #p0")
      @Transactional(rollbackFor = Exception.class)
      public RoleDto findById(long id) {
          Role role = roleRepository.findById(id).orElseGet(Role::new);
          ValidationUtil.isNull(role.getId(), "Role", "id", id);
          return roleMapper.toDto(role);
      }
  
      @Override
      @Transactional(rollbackFor = Exception.class)
      public void create(Role resources) {
          if (roleRepository.findByName(resources.getName()) != null) {
              throw new EntityExistException(Role.class, "username", resources.getName());
          }
          roleRepository.save(resources);
      }
  
      @Override
      @Transactional(rollbackFor = Exception.class)
      public void update(Role resources) {
          Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new);
          ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId());
  
          Role role1 = roleRepository.findByName(resources.getName());
  
          if (role1 != null && !role1.getId().equals(role.getId())) {
              throw new EntityExistException(Role.class, "username", resources.getName());
          }
          role.setName(resources.getName());
          role.setDescription(resources.getDescription());
          role.setDataScope(resources.getDataScope());
          role.setDepts(resources.getDepts());
          role.setLevel(resources.getLevel());
          roleRepository.save(role);
          // 更新相关缓存
          delCaches(role.getId(), null);
      }
  
      @Override
      public void updateMenu(Role resources, RoleDto roleDTO) {
          Role role = roleMapper.toEntity(roleDTO);
          List<User> users = userRepository.findByRoleId(role.getId());
          // 更新菜单
          role.setMenus(resources.getMenus());
          delCaches(resources.getId(), users);
          roleRepository.save(role);
      }
  
      @Override
      @Transactional(rollbackFor = Exception.class)
      public void untiedMenu(Long menuId) {
          // 更新菜单
          roleRepository.untiedMenu(menuId);
      }
  
      @Override
      @Transactional(rollbackFor = Exception.class)
      public void delete(Set<Long> ids) {
          for (Long id : ids) {
              // 更新相关缓存
              delCaches(id, null);
          }
          roleRepository.deleteAllByIdIn(ids);
      }
  
      @Override
      public List<RoleSmallDto> findByUsersId(Long id) {
          return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id)));
      }
  
      @Override
      public Integer findByRoles(Set<Role> roles) {
          if (roles.size() == 0) {
              return Integer.MAX_VALUE;
          }
          Set<RoleDto> roleDtos = new HashSet<>();
          for (Role role : roles) {
              roleDtos.add(findById(role.getId()));
          }
          return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList()));
      }
  
      @Override
      @Cacheable(key = "'auth:' + #p0.id")
      public List<AuthorityDto> mapToGrantedAuthorities(UserDto user) {
          Set<String> permissions = new HashSet<>();
          // 如果是管理员直接返回
          if (user.getIsAdmin()) {
              permissions.add("admin");
              return permissions.stream().map(AuthorityDto::new)
                      .collect(Collectors.toList());
          }
          Set<Role> roles = roleRepository.findByUserId(user.getId());
          permissions = roles.stream().flatMap(role -> role.getMenus().stream())
                  .map(Menu::getPermission)
                  .filter(StringUtils::isNotBlank).collect(Collectors.toSet());
          return permissions.stream().map(AuthorityDto::new)
                  .collect(Collectors.toList());
      }
  
      @Override
      public void download(List<RoleDto> roles, HttpServletResponse response) throws IOException {
          List<Map<String, Object>> list = new ArrayList<>();
          for (RoleDto role : roles) {
              Map<String, Object> map = new LinkedHashMap<>();
              map.put("角色名称", role.getName());
              map.put("角色级别", role.getLevel());
              map.put("描述", role.getDescription());
              map.put("创建日期", role.getCreateTime());
              list.add(map);
          }
          FileUtil.downloadExcel(list, response);
      }
  
      @Override
      public void verification(Set<Long> ids) {
          if (userRepository.countByRoles(ids) > 0) {
              throw new BadRequestException("所选角色存在用户关联，请解除关联再试！");
          }
      }
  
      @Override
      public List<Role> findInMenuId(List<Long> menuIds) {
          return roleRepository.findInMenuId(menuIds);
      }
  
      /**
       * 清理缓存
       * @param id /
       */
      public void delCaches(Long id, List<User> users) {
          users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users;
          if (CollectionUtil.isNotEmpty(users)) {
              users.forEach(item -> userCacheManager.cleanUserCache(item.getUsername()));
              Set<Long> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
              redisUtils.delByKeys(CacheKey.DATA_USER, userIds);
              redisUtils.delByKeys(CacheKey.MENU_USER, userIds);
              redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds);
          }
          redisUtils.del(CacheKey.ROLE_ID + id);
      }
  }
  