更新
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) {
 | 
			
		||||
        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.yj.earth.annotation.CheckAuth;
 | 
			
		||||
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.UserService;
 | 
			
		||||
import com.yj.earth.common.util.ApiResponse;
 | 
			
		||||
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.vo.RoleVo;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
@ -16,7 +20,10 @@ import org.springframework.beans.BeanUtils;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "角色数据管理")
 | 
			
		||||
@CheckAuth
 | 
			
		||||
@ -25,6 +32,8 @@ import java.util.List;
 | 
			
		||||
public class RoleController {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
    @Resource
 | 
			
		||||
    private UserService userService;
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "新增角色")
 | 
			
		||||
    @PostMapping("/add")
 | 
			
		||||
@ -64,18 +73,33 @@ public class RoleController {
 | 
			
		||||
                            @Parameter(description = "分页大小") Integer pageSize,
 | 
			
		||||
                            @Parameter(description = "角色名称") String roleName,
 | 
			
		||||
                            @Parameter(description = "角色状态") Integer status) {
 | 
			
		||||
        // 构建查询条件
 | 
			
		||||
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
 | 
			
		||||
 | 
			
		||||
        // 根据角色名称进行模糊搜索
 | 
			
		||||
        if (StringUtils.isNotBlank(roleName)) {
 | 
			
		||||
            queryWrapper.like(Role::getRoleName, roleName);
 | 
			
		||||
        }
 | 
			
		||||
        // 角色状态
 | 
			
		||||
        if (status != null) {
 | 
			
		||||
            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);
 | 
			
		||||
        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 = "管理员数量查询")
 | 
			
		||||
@ -86,4 +110,37 @@ public class RoleController {
 | 
			
		||||
        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.hutool.core.io.FileUtil;
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 | 
			
		||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 | 
			
		||||
import com.fasterxml.jackson.core.JsonProcessingException;
 | 
			
		||||
import com.yj.earth.annotation.CheckAuth;
 | 
			
		||||
import com.yj.earth.business.domain.Source;
 | 
			
		||||
@ -26,6 +27,7 @@ import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
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.SHOW;
 | 
			
		||||
@ -127,8 +129,27 @@ public class SourceController {
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "获取资源列表")
 | 
			
		||||
    @GetMapping("/list")
 | 
			
		||||
    public ApiResponse list() {
 | 
			
		||||
        return ApiResponse.success(sourceService.getSourceListByUserId(StpUtil.getLoginIdAsString()));
 | 
			
		||||
    public ApiResponse list(@Parameter(description = "资源类型") String sourceType,
 | 
			
		||||
                            @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 = "拖动资源")
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@ import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import org.yaml.snakeyaml.DumperOptions;
 | 
			
		||||
import org.yaml.snakeyaml.Yaml;
 | 
			
		||||
 | 
			
		||||
@ -18,8 +17,6 @@ import java.net.URLEncoder;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Paths;
 | 
			
		||||
import java.nio.file.StandardCopyOption;
 | 
			
		||||
import java.sql.SQLException;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@ -132,7 +129,6 @@ public class SystemController {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 返回指定状态码与错误信息
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -154,9 +154,21 @@ public class UserController {
 | 
			
		||||
 | 
			
		||||
    @Operation(summary = "删除用户")
 | 
			
		||||
    @PostMapping("/deletes")
 | 
			
		||||
    @RoleAccess(roleNames = "管理员")
 | 
			
		||||
    public ApiResponse deletes(@Parameter(description = "用户ID列表") @RequestBody List<String> ids) {
 | 
			
		||||
        userService.removeByIds(ids);
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 | 
			
		||||
import com.yj.earth.business.domain.Source;
 | 
			
		||||
import com.baomidou.mybatisplus.extension.service.IService;
 | 
			
		||||
import com.yj.earth.common.util.ApiResponse;
 | 
			
		||||
@ -20,7 +21,7 @@ public interface SourceService extends IService<Source> {
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,9 @@ package com.yj.earth.business.service.impl;
 | 
			
		||||
import cn.dev33.satoken.stp.StpUtil;
 | 
			
		||||
import cn.hutool.core.io.FileUtil;
 | 
			
		||||
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.yj.earth.business.domain.Role;
 | 
			
		||||
import com.yj.earth.business.domain.RoleSource;
 | 
			
		||||
@ -23,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
@ -169,30 +173,59 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
 | 
			
		||||
        return HttpUtil.doGet(url);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取用户资源列表
 | 
			
		||||
     */
 | 
			
		||||
    @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<>();
 | 
			
		||||
        queryWrapper.eq(User::getId, userId);
 | 
			
		||||
        User user = userService.getOne(queryWrapper);
 | 
			
		||||
        if (user == null) {
 | 
			
		||||
            return Collections.emptyList();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 查询角色信息
 | 
			
		||||
        String roleId = user.getRoleId();
 | 
			
		||||
        LambdaQueryWrapper<Role> roleQueryWrapper = new LambdaQueryWrapper<>();
 | 
			
		||||
        roleQueryWrapper.eq(Role::getId, roleId);
 | 
			
		||||
        // 如果这个角色是管理员则直接返回所有资源
 | 
			
		||||
        if (roleService.getOne(roleQueryWrapper).getIsSuper() == 1) {
 | 
			
		||||
            return sourceService.list();
 | 
			
		||||
        Role role = roleService.getOne(roleQueryWrapper);
 | 
			
		||||
        if (role == null) {
 | 
			
		||||
            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 {
 | 
			
		||||
    @Schema(description = "主键")
 | 
			
		||||
    private String id;
 | 
			
		||||
    @Schema(description = "角色名称")
 | 
			
		||||
    private String roleName;
 | 
			
		||||
    @Schema(description = "角色描述")
 | 
			
		||||
    private String 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