更新
This commit is contained in:
		| @ -1,226 +0,0 @@ | |||||||
| package com.yj.earth; |  | ||||||
|  |  | ||||||
| import javax.crypto.Cipher; |  | ||||||
| import javax.crypto.SecretKey; |  | ||||||
| import javax.crypto.SecretKeyFactory; |  | ||||||
| import javax.crypto.spec.IvParameterSpec; |  | ||||||
| import javax.crypto.spec.PBEKeySpec; |  | ||||||
| import javax.crypto.spec.SecretKeySpec; |  | ||||||
| import java.io.*; |  | ||||||
| import java.security.spec.KeySpec; |  | ||||||
| import java.util.Random; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 文件快速加密解密工具类(仅加密文件开头部分,兼顾保护与效率) |  | ||||||
|  */ |  | ||||||
| public class FastFileEncryptor { |  | ||||||
|     // 加密算法参数 |  | ||||||
|     private static final String ALGORITHM = "AES"; |  | ||||||
|     private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; |  | ||||||
|     private static final int KEY_SIZE = 256; // 需JCE无限制权限包 |  | ||||||
|     private static final int IV_LENGTH = 16; // AES块大小 |  | ||||||
|     private static final int ITERATION_COUNT = 65536; |  | ||||||
|     private static final int SALT_LENGTH = 16; |  | ||||||
|     // 只加密文件开头的1MB(可根据需求调整,建议512KB~2MB) |  | ||||||
|     private static final int ENCRYPTED_LENGTH = 1024 * 1024; // 1MB |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 加密文件(仅加密开头部分) |  | ||||||
|      * @param sourceFilePath 源文件路径 |  | ||||||
|      * @param encryptedFilePath 加密后文件路径 |  | ||||||
|      * @param password 加密密码 |  | ||||||
|      * @throws Exception 加密过程异常 |  | ||||||
|      */ |  | ||||||
|     public static void encryptFile(String sourceFilePath, String encryptedFilePath, String password) throws Exception { |  | ||||||
|         File sourceFile = new File(sourceFilePath); |  | ||||||
|         File encryptedFile = new File(encryptedFilePath); |  | ||||||
|  |  | ||||||
|         // 验证源文件 |  | ||||||
|         if (!sourceFile.exists() || !sourceFile.isFile()) { |  | ||||||
|             throw new FileNotFoundException("源文件不存在或不是文件: " + sourceFilePath); |  | ||||||
|         } |  | ||||||
|         // 检查磁盘空间 |  | ||||||
|         if (!checkDiskSpace(encryptedFilePath, sourceFile.length())) { |  | ||||||
|             throw new IOException("目标路径磁盘空间不足,至少需要 " + sourceFile.length() + " 字节"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 生成盐值和IV向量 |  | ||||||
|         byte[] salt = generateRandomBytes(SALT_LENGTH); |  | ||||||
|         byte[] iv = generateRandomBytes(IV_LENGTH); |  | ||||||
|         SecretKey secretKey = generateSecretKey(password, salt); |  | ||||||
|         Cipher cipher = Cipher.getInstance(TRANSFORMATION); |  | ||||||
|         cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv)); |  | ||||||
|  |  | ||||||
|         try ( |  | ||||||
|                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile)); |  | ||||||
|                 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(encryptedFile)) |  | ||||||
|         ) { |  | ||||||
|             // 写入元数据:盐值(16) + IV(16) + 加密长度(4) |  | ||||||
|             bos.write(salt); |  | ||||||
|             bos.write(iv); |  | ||||||
|             bos.write(intToBytes(ENCRYPTED_LENGTH)); |  | ||||||
|             bos.flush(); |  | ||||||
|  |  | ||||||
|             // 加密开头指定长度的字节 |  | ||||||
|             byte[] encryptBuffer = new byte[ENCRYPTED_LENGTH]; |  | ||||||
|             int actualRead = bis.read(encryptBuffer); // 实际读取的字节数(可能文件小于1MB) |  | ||||||
|             if (actualRead > 0) { |  | ||||||
|                 byte[] encryptedBytes = cipher.doFinal(encryptBuffer, 0, actualRead); |  | ||||||
|                 bos.write(encryptedBytes); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // 直接复制剩余未加密的字节 |  | ||||||
|             byte[] copyBuffer = new byte[1024 * 1024]; // 1MB缓冲区加速复制 |  | ||||||
|             int bytesRead; |  | ||||||
|             while ((bytesRead = bis.read(copyBuffer)) != -1) { |  | ||||||
|                 bos.write(copyBuffer, 0, bytesRead); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 解密文件(仅解密开头部分) |  | ||||||
|      * @param encryptedFilePath 加密文件路径 |  | ||||||
|      * @param decryptedFilePath 解密后文件路径 |  | ||||||
|      * @param password 解密密码 |  | ||||||
|      * @throws Exception 解密过程异常 |  | ||||||
|      */ |  | ||||||
|     public static void decryptFile(String encryptedFilePath, String decryptedFilePath, String password) throws Exception { |  | ||||||
|         File encryptedFile = new File(encryptedFilePath); |  | ||||||
|         File decryptedFile = new File(decryptedFilePath); |  | ||||||
|  |  | ||||||
|         // 验证加密文件 |  | ||||||
|         if (!encryptedFile.exists() || !encryptedFile.isFile()) { |  | ||||||
|             throw new FileNotFoundException("加密文件不存在或不是文件: " + encryptedFilePath); |  | ||||||
|         } |  | ||||||
|         // 检查磁盘空间(减去元数据字节数) |  | ||||||
|         long requiredSize = encryptedFile.length() - SALT_LENGTH - IV_LENGTH - 4; |  | ||||||
|         if (!checkDiskSpace(decryptedFilePath, requiredSize)) { |  | ||||||
|             throw new IOException("目标路径磁盘空间不足,至少需要 " + requiredSize + " 字节"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         try ( |  | ||||||
|                 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(encryptedFile)); |  | ||||||
|                 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(decryptedFile)) |  | ||||||
|         ) { |  | ||||||
|             // 读取元数据:盐值、IV、加密长度 |  | ||||||
|             byte[] salt = new byte[SALT_LENGTH]; |  | ||||||
|             byte[] iv = new byte[IV_LENGTH]; |  | ||||||
|             byte[] lengthBytes = new byte[4]; |  | ||||||
|             if (bis.read(salt) != SALT_LENGTH || bis.read(iv) != IV_LENGTH || bis.read(lengthBytes) != 4) { |  | ||||||
|                 throw new IOException("加密文件格式错误,元数据不完整"); |  | ||||||
|             } |  | ||||||
|             int encryptedLength = bytesToInt(lengthBytes); |  | ||||||
|  |  | ||||||
|             // 生成密钥并解密开头部分 |  | ||||||
|             SecretKey secretKey = generateSecretKey(password, salt); |  | ||||||
|             Cipher cipher = Cipher.getInstance(TRANSFORMATION); |  | ||||||
|             cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); |  | ||||||
|  |  | ||||||
|             // 读取加密的开头数据(预留填充空间) |  | ||||||
|             byte[] encryptedBytes = new byte[encryptedLength + 16]; // 最多额外16字节填充 |  | ||||||
|             int actualEncryptedRead = bis.read(encryptedBytes); |  | ||||||
|             if (actualEncryptedRead <= 0) { |  | ||||||
|                 throw new IOException("加密文件内容不完整"); |  | ||||||
|             } |  | ||||||
|             // 解密并写入(只取原始加密长度的字节,去除填充) |  | ||||||
|             byte[] decryptedBytes = cipher.doFinal(encryptedBytes, 0, actualEncryptedRead); |  | ||||||
|             bos.write(decryptedBytes, 0, Math.min(decryptedBytes.length, encryptedLength)); |  | ||||||
|  |  | ||||||
|             // 直接复制剩余未加密的字节 |  | ||||||
|             byte[] copyBuffer = new byte[1024 * 1024]; |  | ||||||
|             int bytesRead; |  | ||||||
|             while ((bytesRead = bis.read(copyBuffer)) != -1) { |  | ||||||
|                 bos.write(copyBuffer, 0, bytesRead); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 生成随机字节数组(盐值或IV) |  | ||||||
|      */ |  | ||||||
|     private static byte[] generateRandomBytes(int length) { |  | ||||||
|         byte[] bytes = new byte[length]; |  | ||||||
|         new Random().nextBytes(bytes); |  | ||||||
|         return bytes; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 基于密码和盐值生成AES密钥 |  | ||||||
|      */ |  | ||||||
|     private static SecretKey generateSecretKey(String password, byte[] salt) throws Exception { |  | ||||||
|         SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); |  | ||||||
|         KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_SIZE); |  | ||||||
|         return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), ALGORITHM); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 检查目标路径磁盘空间 |  | ||||||
|      */ |  | ||||||
|     private static boolean checkDiskSpace(String targetPath, long requiredSize) { |  | ||||||
|         File file = new File(targetPath); |  | ||||||
|         File parent = file.getParentFile(); |  | ||||||
|         if (parent == null) { |  | ||||||
|             parent = new File(System.getProperty("user.dir")); |  | ||||||
|         } |  | ||||||
|         return parent.getFreeSpace() >= requiredSize; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * int转4字节数组(大端序) |  | ||||||
|      */ |  | ||||||
|     private static byte[] intToBytes(int value) { |  | ||||||
|         return new byte[]{ |  | ||||||
|                 (byte) (value >> 24), |  | ||||||
|                 (byte) (value >> 16), |  | ||||||
|                 (byte) (value >> 8), |  | ||||||
|                 (byte) value |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 4字节数组转int(大端序) |  | ||||||
|      */ |  | ||||||
|     private static int bytesToInt(byte[] bytes) { |  | ||||||
|         return ((bytes[0] & 0xFF) << 24) | |  | ||||||
|                 ((bytes[1] & 0xFF) << 16) | |  | ||||||
|                 ((bytes[2] & 0xFF) << 8) | |  | ||||||
|                 (bytes[3] & 0xFF); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     // 测试示例 |  | ||||||
|     public static void main(String[] args) { |  | ||||||
|         try { |  | ||||||
|             // 测试参数(替换为实际文件路径) |  | ||||||
|             String sourceFile = "E:\\yjearth\\poi\\poi.db";       // 原始大文件 |  | ||||||
|             String encryptedFile = "E:\\yjearth\\poi\\poi_enc.db"; // 加密后文件 |  | ||||||
|             String decryptedFile = "E:\\yjearth\\poi\\poi_dec.db"; // 解密后文件 |  | ||||||
|             String password = "MySecretPassword123!";              // 密码 |  | ||||||
|  |  | ||||||
|             // 加密(仅加密开头1MB,速度极快) |  | ||||||
|             System.out.println("开始加密文件..."); |  | ||||||
|             long encryptStart = System.currentTimeMillis(); |  | ||||||
|             encryptFile(sourceFile, encryptedFile, password); |  | ||||||
|             long encryptEnd = System.currentTimeMillis(); |  | ||||||
|             System.out.println("加密完成!耗时:" + (encryptEnd - encryptStart) + "ms,加密文件:" + encryptedFile); |  | ||||||
|  |  | ||||||
|             // 解密(仅解密开头1MB,速度极快) |  | ||||||
|             System.out.println("开始解密文件..."); |  | ||||||
|             long decryptStart = System.currentTimeMillis(); |  | ||||||
|             decryptFile(encryptedFile, decryptedFile, password); |  | ||||||
|             long decryptEnd = System.currentTimeMillis(); |  | ||||||
|             System.out.println("解密完成!耗时:" + (decryptEnd - decryptStart) + "ms,解密文件:" + decryptedFile); |  | ||||||
|  |  | ||||||
|         } catch (Exception e) { |  | ||||||
|             e.printStackTrace(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -72,6 +72,6 @@ public class AuthGenerator { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static void main(String[] args) { |     public static void main(String[] args) { | ||||||
|         System.out.println(generateAuth("标准版", 1000, 365, "DAC653349FD15F1E6DB2F9322AD628F4")); |         System.out.println(generateAuth("标准版", 1000, 365, "35A0DF1D05AEAE77E1E2715CC36A7368")); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,10 +5,14 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||||
| import com.yj.earth.annotation.CheckAuth; | import com.yj.earth.annotation.CheckAuth; | ||||||
| import com.yj.earth.business.domain.Role; | import com.yj.earth.business.domain.Role; | ||||||
|  | import com.yj.earth.business.domain.User; | ||||||
| import com.yj.earth.business.service.RoleService; | import com.yj.earth.business.service.RoleService; | ||||||
|  | import com.yj.earth.business.service.UserService; | ||||||
| import com.yj.earth.common.util.ApiResponse; | import com.yj.earth.common.util.ApiResponse; | ||||||
| import com.yj.earth.dto.role.AddRoleDto; | import com.yj.earth.dto.role.AddRoleDto; | ||||||
|  | import com.yj.earth.dto.role.SetUserDto; | ||||||
| import com.yj.earth.dto.role.UpdateRoleDto; | import com.yj.earth.dto.role.UpdateRoleDto; | ||||||
|  | import com.yj.earth.vo.RoleVo; | ||||||
| import io.swagger.v3.oas.annotations.Operation; | import io.swagger.v3.oas.annotations.Operation; | ||||||
| import io.swagger.v3.oas.annotations.Parameter; | import io.swagger.v3.oas.annotations.Parameter; | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | import io.swagger.v3.oas.annotations.tags.Tag; | ||||||
| @ -16,7 +20,10 @@ import org.springframework.beans.BeanUtils; | |||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
|  | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| @Tag(name = "角色数据管理") | @Tag(name = "角色数据管理") | ||||||
| @CheckAuth | @CheckAuth | ||||||
| @ -25,6 +32,8 @@ import java.util.List; | |||||||
| public class RoleController { | public class RoleController { | ||||||
|     @Resource |     @Resource | ||||||
|     private RoleService roleService; |     private RoleService roleService; | ||||||
|  |     @Resource | ||||||
|  |     private UserService userService; | ||||||
|  |  | ||||||
|     @Operation(summary = "新增角色") |     @Operation(summary = "新增角色") | ||||||
|     @PostMapping("/add") |     @PostMapping("/add") | ||||||
| @ -64,18 +73,33 @@ public class RoleController { | |||||||
|                             @Parameter(description = "分页大小") Integer pageSize, |                             @Parameter(description = "分页大小") Integer pageSize, | ||||||
|                             @Parameter(description = "角色名称") String roleName, |                             @Parameter(description = "角色名称") String roleName, | ||||||
|                             @Parameter(description = "角色状态") Integer status) { |                             @Parameter(description = "角色状态") Integer status) { | ||||||
|  |         // 构建查询条件 | ||||||
|         LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>(); |         LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>(); | ||||||
|  |  | ||||||
|         // 根据角色名称进行模糊搜索 |  | ||||||
|         if (StringUtils.isNotBlank(roleName)) { |         if (StringUtils.isNotBlank(roleName)) { | ||||||
|             queryWrapper.like(Role::getRoleName, roleName); |             queryWrapper.like(Role::getRoleName, roleName); | ||||||
|         } |         } | ||||||
|         // 角色状态 |  | ||||||
|         if (status != null) { |         if (status != null) { | ||||||
|             queryWrapper.eq(Role::getStatus, status); |             queryWrapper.eq(Role::getStatus, status); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // 统计当前条件下每个角色名称的数量 | ||||||
|  |         List<Role> allMatchedRoles = roleService.list(queryWrapper); | ||||||
|  |         Map<String, Long> roleNameCountMap = allMatchedRoles.stream() | ||||||
|  |                 .collect(Collectors.groupingBy(Role::getRoleName, Collectors.counting())); | ||||||
|  |  | ||||||
|  |         // 分页查询 | ||||||
|         Page<Role> rolePage = roleService.page(new Page<>(pageNum, pageSize), queryWrapper); |         Page<Role> rolePage = roleService.page(new Page<>(pageNum, pageSize), queryWrapper); | ||||||
|         return ApiResponse.success(rolePage); |  | ||||||
|  |         // 转换为 Page<RoleVo> | ||||||
|  |         Page<RoleVo> roleVoPage = (Page<RoleVo>) rolePage.convert(role -> { | ||||||
|  |             RoleVo roleVo = new RoleVo(); | ||||||
|  |             BeanUtils.copyProperties(role, roleVo); | ||||||
|  |             // 设置数量 | ||||||
|  |             roleVo.setCount(roleNameCountMap.getOrDefault(role.getRoleName(), 0L).intValue()); | ||||||
|  |             return roleVo; | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         return ApiResponse.success(roleVoPage); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Operation(summary = "管理员数量查询") |     @Operation(summary = "管理员数量查询") | ||||||
| @ -86,4 +110,37 @@ public class RoleController { | |||||||
|         return ApiResponse.success(roleService.count(queryWrapper)); |         return ApiResponse.success(roleService.count(queryWrapper)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "角色数量统计") | ||||||
|  |     @GetMapping("/countByRole") | ||||||
|  |     public ApiResponse countByRole() { | ||||||
|  |         // 返回每一个角色的名称的数量 | ||||||
|  |         return ApiResponse.success(roleService.list().stream().collect(Collectors.groupingBy(Role::getRoleName, Collectors.counting()))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "为角色设置用户") | ||||||
|  |     @PostMapping("/setUser") | ||||||
|  |     public ApiResponse setUser(@RequestBody SetUserDto setUserDto) { | ||||||
|  |         setUserDto.getUserIds().forEach(userId -> { | ||||||
|  |             User user = new User(); | ||||||
|  |             user.setId(userId); | ||||||
|  |             user.setRoleId(setUserDto.getRoleId()); | ||||||
|  |             userService.updateById(user); | ||||||
|  |         }); | ||||||
|  |         return ApiResponse.success(null); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "根据角色ID返回用户信息") | ||||||
|  |     @GetMapping("/getUsersByRoleId") | ||||||
|  |     public ApiResponse getUsersByRoleId(@Parameter(description = "角色ID") String roleId) { | ||||||
|  |         // 查询角色ID为参数的用户列表 | ||||||
|  |         LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>(); | ||||||
|  |         queryWrapper1.eq(User::getRoleId, roleId); | ||||||
|  |         // 查询角色ID不为参数的用户列表 | ||||||
|  |         LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>(); | ||||||
|  |         queryWrapper2.ne(User::getRoleId, roleId); | ||||||
|  |         Map<String, List<User>> result = new HashMap<>(); | ||||||
|  |         result.put("users", userService.list(queryWrapper1)); | ||||||
|  |         result.put("otherUsers", userService.list(queryWrapper2)); | ||||||
|  |         return ApiResponse.success(result); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ package com.yj.earth.business.controller; | |||||||
| import cn.dev33.satoken.stp.StpUtil; | import cn.dev33.satoken.stp.StpUtil; | ||||||
| import cn.hutool.core.io.FileUtil; | import cn.hutool.core.io.FileUtil; | ||||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||||
|  | import com.baomidou.mybatisplus.core.toolkit.StringUtils; | ||||||
| import com.fasterxml.jackson.core.JsonProcessingException; | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
| import com.yj.earth.annotation.CheckAuth; | import com.yj.earth.annotation.CheckAuth; | ||||||
| import com.yj.earth.business.domain.Source; | import com.yj.earth.business.domain.Source; | ||||||
| @ -26,6 +27,7 @@ import org.springframework.web.multipart.MultipartFile; | |||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import java.util.*; | import java.util.*; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| import static com.yj.earth.common.constant.GlobalConstant.DIRECTORY; | import static com.yj.earth.common.constant.GlobalConstant.DIRECTORY; | ||||||
| import static com.yj.earth.common.constant.GlobalConstant.SHOW; | import static com.yj.earth.common.constant.GlobalConstant.SHOW; | ||||||
| @ -127,8 +129,27 @@ public class SourceController { | |||||||
|  |  | ||||||
|     @Operation(summary = "获取资源列表") |     @Operation(summary = "获取资源列表") | ||||||
|     @GetMapping("/list") |     @GetMapping("/list") | ||||||
|     public ApiResponse list() { |     public ApiResponse list(@Parameter(description = "资源类型") String sourceType, | ||||||
|         return ApiResponse.success(sourceService.getSourceListByUserId(StpUtil.getLoginIdAsString())); |                             @Parameter(description = "资源名称") String name, | ||||||
|  |                             @Parameter(description = "分页数量") Integer pageNum, | ||||||
|  |                             @Parameter(description = "分页大小") Integer pageSize) { | ||||||
|  |         // 获取当前登录用户的ID | ||||||
|  |         String userId = StpUtil.getLoginIdAsString(); | ||||||
|  |         List<Source> sourceList = sourceService.getSourceListByUserId(userId, sourceType, name, pageNum, pageSize); | ||||||
|  |         return ApiResponse.success(sourceList); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "获取资源类型列表") | ||||||
|  |     @GetMapping("/typeList") | ||||||
|  |     public ApiResponse typeList() { | ||||||
|  |         return ApiResponse.success(sourceService.list().stream().map(Source::getSourceType).distinct().toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "获取类型及其总数") | ||||||
|  |     @GetMapping("/typeAndCount") | ||||||
|  |     public ApiResponse typeAndCount() { | ||||||
|  |         List<Source> list = sourceService.list(); | ||||||
|  |         return ApiResponse.success(list.stream().collect(Collectors.groupingBy(Source::getSourceType, Collectors.counting()))); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Operation(summary = "拖动资源") |     @Operation(summary = "拖动资源") | ||||||
|  | |||||||
| @ -9,7 +9,6 @@ import jakarta.servlet.http.HttpServletResponse; | |||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.http.HttpStatus; | import org.springframework.http.HttpStatus; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
| import org.springframework.web.multipart.MultipartFile; |  | ||||||
| import org.yaml.snakeyaml.DumperOptions; | import org.yaml.snakeyaml.DumperOptions; | ||||||
| import org.yaml.snakeyaml.Yaml; | import org.yaml.snakeyaml.Yaml; | ||||||
|  |  | ||||||
| @ -18,8 +17,6 @@ import java.net.URLEncoder; | |||||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||||
| import java.nio.file.Files; | import java.nio.file.Files; | ||||||
| import java.nio.file.Paths; | import java.nio.file.Paths; | ||||||
| import java.nio.file.StandardCopyOption; |  | ||||||
| import java.sql.SQLException; |  | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| @ -132,7 +129,6 @@ public class SystemController { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 返回指定状态码与错误信息 |      * 返回指定状态码与错误信息 | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -154,9 +154,21 @@ public class UserController { | |||||||
|  |  | ||||||
|     @Operation(summary = "删除用户") |     @Operation(summary = "删除用户") | ||||||
|     @PostMapping("/deletes") |     @PostMapping("/deletes") | ||||||
|     @RoleAccess(roleNames = "管理员") |  | ||||||
|     public ApiResponse deletes(@Parameter(description = "用户ID列表") @RequestBody List<String> ids) { |     public ApiResponse deletes(@Parameter(description = "用户ID列表") @RequestBody List<String> ids) { | ||||||
|         userService.removeByIds(ids); |         userService.removeByIds(ids); | ||||||
|         return ApiResponse.success(null); |         return ApiResponse.success(null); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Operation(summary = "设置新密码") | ||||||
|  |     @PostMapping("/setNewPassword") | ||||||
|  |     @RoleAccess(roleNames = "管理员") | ||||||
|  |     public ApiResponse setNewPassword(@RequestBody SetNewPasswordDto setNewPasswordDto) { | ||||||
|  |         User user = userService.getById(setNewPasswordDto.getId()); | ||||||
|  |         if (user == null) { | ||||||
|  |             return ApiResponse.failure("用户不存在"); | ||||||
|  |         } | ||||||
|  |         user.setPassword(BCrypt.hashpw(setNewPasswordDto.getNewPassword(), BCrypt.gensalt())); | ||||||
|  |         userService.updateById(user); | ||||||
|  |         return ApiResponse.success(null); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| package com.yj.earth.business.service; | package com.yj.earth.business.service; | ||||||
|  |  | ||||||
|  | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||||
| import com.yj.earth.business.domain.Source; | import com.yj.earth.business.domain.Source; | ||||||
| import com.baomidou.mybatisplus.extension.service.IService; | import com.baomidou.mybatisplus.extension.service.IService; | ||||||
| import com.yj.earth.common.util.ApiResponse; | import com.yj.earth.common.util.ApiResponse; | ||||||
| @ -20,7 +21,7 @@ public interface SourceService extends IService<Source> { | |||||||
|  |  | ||||||
|     String fetchPakDetail(String sourceId); |     String fetchPakDetail(String sourceId); | ||||||
|  |  | ||||||
|     List<Source> getSourceListByUserId(String userId); |     List<Source> getSourceListByUserId(String userId, String type,String name,Integer pageNum, Integer pageSize); | ||||||
|  |  | ||||||
|     String checkIsPass(String parentId, String sourceName); |     String checkIsPass(String parentId, String sourceName); | ||||||
|  |  | ||||||
|  | |||||||
| @ -3,6 +3,9 @@ package com.yj.earth.business.service.impl; | |||||||
| import cn.dev33.satoken.stp.StpUtil; | import cn.dev33.satoken.stp.StpUtil; | ||||||
| import cn.hutool.core.io.FileUtil; | import cn.hutool.core.io.FileUtil; | ||||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||||
|  | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||||||
|  | import com.baomidou.mybatisplus.core.toolkit.StringUtils; | ||||||
|  | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||||
| import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | ||||||
| import com.yj.earth.business.domain.Role; | import com.yj.earth.business.domain.Role; | ||||||
| import com.yj.earth.business.domain.RoleSource; | import com.yj.earth.business.domain.RoleSource; | ||||||
| @ -23,6 +26,7 @@ import lombok.extern.slf4j.Slf4j; | |||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| @ -169,30 +173,59 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme | |||||||
|         return HttpUtil.doGet(url); |         return HttpUtil.doGet(url); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取用户资源列表 |      * 获取用户资源列表 | ||||||
|      */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     public List<Source> getSourceListByUserId(String userId) { |     public List<Source> getSourceListByUserId(String userId, String sourceType, String sourceName, Integer pageNum, Integer pageSize) { | ||||||
|         // 查询该用户信息 |         // 查询该用户信息 | ||||||
|         LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); |         LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); | ||||||
|         queryWrapper.eq(User::getId, userId); |         queryWrapper.eq(User::getId, userId); | ||||||
|         User user = userService.getOne(queryWrapper); |         User user = userService.getOne(queryWrapper); | ||||||
|  |         if (user == null) { | ||||||
|  |             return Collections.emptyList(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // 查询角色信息 |         // 查询角色信息 | ||||||
|         String roleId = user.getRoleId(); |         String roleId = user.getRoleId(); | ||||||
|         LambdaQueryWrapper<Role> roleQueryWrapper = new LambdaQueryWrapper<>(); |         LambdaQueryWrapper<Role> roleQueryWrapper = new LambdaQueryWrapper<>(); | ||||||
|         roleQueryWrapper.eq(Role::getId, roleId); |         roleQueryWrapper.eq(Role::getId, roleId); | ||||||
|         // 如果这个角色是管理员则直接返回所有资源 |         Role role = roleService.getOne(roleQueryWrapper); | ||||||
|         if (roleService.getOne(roleQueryWrapper).getIsSuper() == 1) { |         if (role == null) { | ||||||
|             return sourceService.list(); |             return Collections.emptyList(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 构建资源查询条件 | ||||||
|  |         LambdaQueryWrapper<Source> sourceQueryWrapper = new LambdaQueryWrapper<>(); | ||||||
|  |         if (sourceType != null) { | ||||||
|  |             sourceQueryWrapper.eq(Source::getSourceType, sourceType); | ||||||
|  |         } | ||||||
|  |         if (StringUtils.isNotBlank(sourceName)) { | ||||||
|  |             sourceQueryWrapper.like(Source::getSourceName, sourceName); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 增加资源ID的范围限制 | ||||||
|  |         if (role.getIsSuper() != 1) { | ||||||
|  |             LambdaQueryWrapper<RoleSource> roleSourceQueryWrapper = new LambdaQueryWrapper<>(); | ||||||
|  |             roleSourceQueryWrapper.eq(RoleSource::getRoleId, roleId); | ||||||
|  |             List<RoleSource> roleSourceList = roleSourceService.list(roleSourceQueryWrapper); | ||||||
|  |             List<String> sourceIdList = roleSourceList.stream() | ||||||
|  |                     .map(RoleSource::getSourceId) | ||||||
|  |                     .toList(); | ||||||
|  |             if (sourceIdList.isEmpty()) { | ||||||
|  |                 return Collections.emptyList(); | ||||||
|  |             } | ||||||
|  |             sourceQueryWrapper.in(Source::getId, sourceIdList); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 判断是否需要分页 | ||||||
|  |         if (pageNum != null && pageSize != null) { | ||||||
|  |             // 执行分页查询,返回分页结果中的记录列表 | ||||||
|  |             Page<Source> page = new Page<>(pageNum, pageSize); | ||||||
|  |             Page<Source> resultPage = sourceService.page(page, sourceQueryWrapper); | ||||||
|  |             return resultPage.getRecords(); | ||||||
|  |         } else { | ||||||
|  |             return sourceService.list(sourceQueryWrapper); | ||||||
|         } |         } | ||||||
|         // 查询属于该角色的资源列表 |  | ||||||
|         LambdaQueryWrapper<RoleSource> roleSourceQueryWrapper = new LambdaQueryWrapper<>(); |  | ||||||
|         roleSourceQueryWrapper.eq(RoleSource::getRoleId, roleId); |  | ||||||
|         List<RoleSource> roleSourceList = roleSourceService.list(roleSourceQueryWrapper); |  | ||||||
|         // 从结果提取出资源ID列表 |  | ||||||
|         List<String> sourceIdList = roleSourceList.stream().map(RoleSource::getSourceId).toList(); |  | ||||||
|         return sourceService.listByIds(sourceIdList); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								src/main/java/com/yj/earth/dto/role/SetUserDto.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/main/java/com/yj/earth/dto/role/SetUserDto.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | package com.yj.earth.dto.role; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | public class SetUserDto { | ||||||
|  |     @Schema(description = "角色ID") | ||||||
|  |     private String roleId; | ||||||
|  |     @Schema(description = "用户ID列表") | ||||||
|  |     private List<String> userIds; | ||||||
|  | } | ||||||
| @ -7,6 +7,8 @@ import lombok.Data; | |||||||
| public class UpdateRoleDto { | public class UpdateRoleDto { | ||||||
|     @Schema(description = "主键") |     @Schema(description = "主键") | ||||||
|     private String id; |     private String id; | ||||||
|  |     @Schema(description = "角色名称") | ||||||
|  |     private String roleName; | ||||||
|     @Schema(description = "角色描述") |     @Schema(description = "角色描述") | ||||||
|     private String description; |     private String description; | ||||||
|     @Schema(description = "是否超级管理员") |     @Schema(description = "是否超级管理员") | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								src/main/java/com/yj/earth/dto/user/SetNewPasswordDto.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/main/java/com/yj/earth/dto/user/SetNewPasswordDto.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | package com.yj.earth.dto.user; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | public class SetNewPasswordDto { | ||||||
|  |     @Schema(description = "用户ID") | ||||||
|  |     private String id; | ||||||
|  |     @Schema(description = "新密码") | ||||||
|  |     private String newPassword; | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								src/main/java/com/yj/earth/vo/RoleVo.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/main/java/com/yj/earth/vo/RoleVo.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | package com.yj.earth.vo; | ||||||
|  |  | ||||||
|  | import com.yj.earth.business.domain.Role; | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | public class RoleVo extends Role { | ||||||
|  |     @Schema(description = "数量") | ||||||
|  |     private Integer count; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 ZZX9599
					ZZX9599