Merge remote-tracking branch 'source/master'

# Conflicts:
#	yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java
This commit is contained in:
jiangqiang
2022-07-09 10:32:15 +08:00
274 changed files with 1463 additions and 5516 deletions

View File

@ -119,7 +119,6 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-file</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -22,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
@ -59,6 +60,7 @@ public class FileController {
}
@GetMapping("/{configId}/get/{path}")
@PermitAll
@ApiOperation("下载文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "configId", value = "配置编号", required = true, dataTypeClass = Long.class),

View File

@ -1,24 +1,27 @@
package cn.iocoder.yudao.module.infra.controller.admin.redis;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
import cn.iocoder.yudao.framework.redis.core.RedisKeyRegistry;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyValueRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
import cn.iocoder.yudao.module.infra.convert.redis.RedisConvert;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
import java.util.*;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -44,12 +47,66 @@ public class RedisController {
return success(RedisConvert.INSTANCE.build(info, dbSize, commandStats));
}
@GetMapping("/get-key-list")
@ApiOperation("获得 Redis Key 列表")
@GetMapping("/get-key-define-list")
@ApiOperation("获得 Redis Key 模板列表")
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
public CommonResult<List<RedisKeyRespVO>> getKeyList() {
public CommonResult<List<RedisKeyDefineRespVO>> getKeyDefineList() {
List<RedisKeyDefine> keyDefines = RedisKeyRegistry.list();
return success(RedisConvert.INSTANCE.convertList(keyDefines));
}
@GetMapping("/get-key-list")
@ApiOperation("获得 Redis keys 键名列表")
@ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
public CommonResult<Set<String>> getKeyDefineList(@RequestParam("keyTemplate") String keyTemplate) {
return success(getKeyDefineList0(keyTemplate));
}
private Set<String> getKeyDefineList0(String keyTemplate) {
// key 格式化
String key = StrUtil.replace(keyTemplate, "%[s|c|b|d|x|o|f|a|e|g]", parameter -> "*");
// scan 扫描 key
Set<String> keys = new LinkedHashSet<>();
stringRedisTemplate.execute((RedisCallback<Set<String>>) connection -> {
try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(100).build())) {
cursor.forEachRemaining(value -> keys.add(StrUtil.utf8Str(value)));
} catch (Exception e) {
throw new RuntimeException(e);
}
return keys;
});
return keys;
}
@GetMapping("/get-key-value")
@ApiOperation("获得 Redis key 内容")
@ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
public CommonResult<RedisKeyValueRespVO> getKeyValue(@RequestParam("key") String key) {
String value = stringRedisTemplate.opsForValue().get(key);
return success(new RedisKeyValueRespVO(key, value));
}
@DeleteMapping("/delete-key")
@ApiOperation("删除 Redis Key")
@ApiImplicitParam(name = "key", value = "Redis Key", example = "oauth2_access_token:233", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
public CommonResult<Boolean> deleteKey(@RequestParam("key") String key) {
stringRedisTemplate.delete(key);
return success(Boolean.TRUE);
}
@DeleteMapping("/delete-keys")
@ApiOperation("删除 Redis Key 根据模板")
@ApiImplicitParam(name = "keyTemplate", value = "Redis Key 定义", example = "true", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('infra:redis:get-key-list')")
public CommonResult<Boolean> deleteKeys(@RequestParam("keyTemplate") String keyTemplate) {
Set<String> keys = getKeyDefineList0(keyTemplate);
if (CollUtil.isNotEmpty(keys)) {
stringRedisTemplate.delete(keys);
}
return success(Boolean.TRUE);
}
}

View File

@ -13,9 +13,9 @@ import java.time.Duration;
@Data
@Builder
@AllArgsConstructor
public class RedisKeyRespVO {
public class RedisKeyDefineRespVO {
@ApiModelProperty(value = "login_user:%s", required = true, example = "String")
@ApiModelProperty(value = "Key 模板", required = true, example = "login_user:%s")
private String keyTemplate;
@ApiModelProperty(value = "Key 类型的枚举", required = true, example = "String")

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.infra.controller.admin.redis.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@ApiModel("管理后台 - 单个 Redis Key Value Response VO")
@Data
@AllArgsConstructor
public class RedisKeyValueRespVO {
@ApiModelProperty(value = "c5f6990767804a928f4bb96ca249febf", required = true, example = "String")
private String key;
@ApiModelProperty(required = true, example = "String")
private String value;
}

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.infra.convert.redis;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisKeyDefineRespVO;
import cn.iocoder.yudao.module.infra.controller.admin.redis.vo.RedisMonitorRespVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -29,6 +29,6 @@ public interface RedisConvert {
return respVO;
}
List<RedisKeyRespVO> convertList(List<RedisKeyDefine> list);
List<RedisKeyDefineRespVO> convertList(List<RedisKeyDefine> list);
}

View File

@ -35,8 +35,6 @@ public class SecurityConfiguration {
// Spring Boot Admin Server 的安全配置
registry.antMatchers(adminSeverContextPath).anonymous()
.antMatchers(adminSeverContextPath + "/**").anonymous();
// 文件的获取接口,可匿名访问
registry.antMatchers(buildAdminApi("/infra/file/*/get/**"), buildAppApi("/infra/file/get/**")).permitAll();
}
};

View File

@ -1,12 +1,11 @@
package cn.iocoder.yudao.module.infra.service.file;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.file.core.client.FileClient;
import cn.iocoder.yudao.framework.file.core.utils.FileTypeUtils;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO;
import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper;
@ -14,7 +13,6 @@ import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
@ -40,13 +38,12 @@ public class FileServiceImpl implements FileService {
@Override
@SneakyThrows
public String createFile(String name, String path, String mimeType, byte[] content) {
//获取文件的扩展
String extName = FileNameUtil.extName(name);
public String createFile(String name, String path, byte[] content) {
// 计算默认的 path
String type = FileTypeUtils.getMineType(content);
if (StrUtil.isEmpty(path)) {
//使用sha256计算文件都唯一路径降低碰撞概率
String sha256Hex = DigestUtil.sha256Hex(content);
path = StrUtil.isBlank(extName) ? sha256Hex : (sha256Hex + '.' + extName);
path = DigestUtil.md5Hex(content)
+ '.' + StrUtil.subAfter(type, '/', true); // 文件的后缀
}
// 如果 name 为空,则使用 path 填充
if (StrUtil.isEmpty(name)) {
@ -64,7 +61,7 @@ public class FileServiceImpl implements FileService {
file.setName(name);
file.setPath(path);
file.setUrl(url);
file.setType(mimeType);
file.setType(type);
file.setSize(content.length);
fileMapper.insert(file);
return url;