Commit 18a5c4628480f7eab9a139a72873c3ec7e8dd181
1 parent
05d4aae6
完成 FileConfig 的后端模块
Showing
33 changed files
with
1044 additions
and
37 deletions
yudao-dependencies/pom.xml
| ... | ... | @@ -53,7 +53,10 @@ |
| 53 | 53 | <screw.version>1.0.5</screw.version> |
| 54 | 54 | <guava.version>30.1.1-jre</guava.version> |
| 55 | 55 | <transmittable-thread-local.version>2.12.2</transmittable-thread-local.version> |
| 56 | + <commons-net.version>3.8.0</commons-net.version> | |
| 57 | + <jsch.version>0.1.55</jsch.version> | |
| 56 | 58 | <!-- 三方云服务相关 --> |
| 59 | + <s3.version>2.17.147</s3.version> | |
| 57 | 60 | <aliyun-java-sdk-core.version>4.5.25</aliyun-java-sdk-core.version> |
| 58 | 61 | <aliyun-java-sdk-dysmsapi.version>2.1.0</aliyun-java-sdk-dysmsapi.version> |
| 59 | 62 | <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version> |
| ... | ... | @@ -493,7 +496,28 @@ |
| 493 | 496 | <version>${transmittable-thread-local.version}</version> |
| 494 | 497 | </dependency> |
| 495 | 498 | |
| 499 | + <dependency> | |
| 500 | + <groupId>commons-net</groupId> | |
| 501 | + <artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 --> | |
| 502 | + <version>${commons-net.version}</version> | |
| 503 | + </dependency> | |
| 504 | + <dependency> | |
| 505 | + <groupId>com.jcraft</groupId> | |
| 506 | + <artifactId>jsch</artifactId> <!-- 解决 sftp 连接 --> | |
| 507 | + <version>${jsch.version}</version> | |
| 508 | + </dependency> | |
| 509 | + | |
| 496 | 510 | <!-- 三方云服务相关 --> |
| 511 | + <dependency> | |
| 512 | + <groupId>cn.iocoder.boot</groupId> | |
| 513 | + <artifactId>yudao-spring-boot-starter-file</artifactId> | |
| 514 | + <version>${revision}</version> | |
| 515 | + </dependency> | |
| 516 | + <dependency> | |
| 517 | + <groupId>software.amazon.awssdk</groupId> | |
| 518 | + <artifactId>s3</artifactId> | |
| 519 | + <version>${s3.version}</version> | |
| 520 | + </dependency> | |
| 497 | 521 | |
| 498 | 522 | <!-- SMS SDK begin --> |
| 499 | 523 | <dependency> | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.common.util.json; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ArrayUtil; |
| 4 | 4 | import cn.hutool.core.util.StrUtil; |
| 5 | +import cn.hutool.json.JSONUtil; | |
| 5 | 6 | import com.fasterxml.jackson.core.type.TypeReference; |
| 6 | 7 | import com.fasterxml.jackson.databind.JsonNode; |
| 7 | 8 | import com.fasterxml.jackson.databind.ObjectMapper; |
| ... | ... | @@ -55,7 +56,6 @@ public class JsonUtils { |
| 55 | 56 | if (StrUtil.isEmpty(text)) { |
| 56 | 57 | return null; |
| 57 | 58 | } |
| 58 | - | |
| 59 | 59 | try { |
| 60 | 60 | return objectMapper.readValue(text, clazz); |
| 61 | 61 | } catch (IOException e) { |
| ... | ... | @@ -64,11 +64,26 @@ public class JsonUtils { |
| 64 | 64 | } |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | + /** | |
| 68 | + * 将字符串解析成指定类型的对象 | |
| 69 | + * 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下, | |
| 70 | + * 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。 | |
| 71 | + * | |
| 72 | + * @param text 字符串 | |
| 73 | + * @param clazz 类型 | |
| 74 | + * @return 对象 | |
| 75 | + */ | |
| 76 | + public static <T> T parseObject2(String text, Class<T> clazz) { | |
| 77 | + if (StrUtil.isEmpty(text)) { | |
| 78 | + return null; | |
| 79 | + } | |
| 80 | + return JSONUtil.toBean(text, clazz); | |
| 81 | + } | |
| 82 | + | |
| 67 | 83 | public static <T> T parseObject(byte[] bytes, Class<T> clazz) { |
| 68 | 84 | if (ArrayUtil.isEmpty(bytes)) { |
| 69 | 85 | return null; |
| 70 | 86 | } |
| 71 | - | |
| 72 | 87 | try { |
| 73 | 88 | return objectMapper.readValue(bytes, clazz); |
| 74 | 89 | } catch (IOException e) { |
| ... | ... | @@ -90,7 +105,6 @@ public class JsonUtils { |
| 90 | 105 | if (StrUtil.isEmpty(text)) { |
| 91 | 106 | return new ArrayList<>(); |
| 92 | 107 | } |
| 93 | - | |
| 94 | 108 | try { |
| 95 | 109 | return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz)); |
| 96 | 110 | } catch (IOException e) { | ... | ... |
yudao-framework/yudao-spring-boot-starter-file/pom.xml
| ... | ... | @@ -54,20 +54,16 @@ |
| 54 | 54 | <dependency> |
| 55 | 55 | <groupId>commons-net</groupId> |
| 56 | 56 | <artifactId>commons-net</artifactId> <!-- 解决 ftp 连接 --> |
| 57 | - <version>3.8.0</version> | |
| 58 | 57 | </dependency> |
| 59 | 58 | <dependency> |
| 60 | 59 | <groupId>com.jcraft</groupId> |
| 61 | 60 | <artifactId>jsch</artifactId> <!-- 解决 sftp 连接 --> |
| 62 | - <version>0.1.55</version> | |
| 63 | 61 | </dependency> |
| 64 | 62 | |
| 65 | - | |
| 66 | 63 | <!-- 三方云服务相关 --> |
| 67 | 64 | <dependency> |
| 68 | 65 | <groupId>software.amazon.awssdk</groupId> |
| 69 | 66 | <artifactId>s3</artifactId> |
| 70 | - <version>2.17.147</version> | |
| 71 | 67 | </dependency> |
| 72 | 68 | |
| 73 | 69 | <!-- Test 测试相关 --> | ... | ... |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/FileClientFactory.java
| ... | ... | @@ -5,10 +5,10 @@ public interface FileClientFactory { |
| 5 | 5 | /** |
| 6 | 6 | * 获得文件客户端 |
| 7 | 7 | * |
| 8 | - * @param channelId 渠道编号 | |
| 8 | + * @param configId 配置编号 | |
| 9 | 9 | * @return 文件客户端 |
| 10 | 10 | */ |
| 11 | - FileClient getFileClient(Long channelId); | |
| 11 | + FileClient getFileClient(Long configId); | |
| 12 | 12 | |
| 13 | 13 | /** |
| 14 | 14 | * 创建文件客户端 | ... | ... |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/FileClientFactoryImpl.java
| ... | ... | @@ -23,10 +23,10 @@ public class FileClientFactoryImpl implements FileClientFactory { |
| 23 | 23 | private final ConcurrentMap<Long, AbstractFileClient<?>> clients = new ConcurrentHashMap<>(); |
| 24 | 24 | |
| 25 | 25 | @Override |
| 26 | - public FileClient getFileClient(Long channelId) { | |
| 27 | - AbstractFileClient<?> client = clients.get(channelId); | |
| 26 | + public FileClient getFileClient(Long configId) { | |
| 27 | + AbstractFileClient<?> client = clients.get(configId); | |
| 28 | 28 | if (client == null) { |
| 29 | - log.error("[getFileClient][配置编号({}) 找不到客户端]", channelId); | |
| 29 | + log.error("[getFileClient][配置编号({}) 找不到客户端]", configId); | |
| 30 | 30 | } |
| 31 | 31 | return client; |
| 32 | 32 | } |
| ... | ... | @@ -50,20 +50,7 @@ public class FileClientFactoryImpl implements FileClientFactory { |
| 50 | 50 | FileStorageEnum storageEnum = FileStorageEnum.getByStorage(storage); |
| 51 | 51 | Assert.notNull(storageEnum, String.format("文件配置(%s) 为空", storageEnum)); |
| 52 | 52 | // 创建客户端 |
| 53 | -// switch (storageEnum) { | |
| 54 | -// case WX_PUB: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config); | |
| 55 | -// case WX_LITE: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config); | |
| 56 | -// case WX_APP: return (AbstractFileClient<Config>) new WXPubFileClient(channelId, (WXFileClientConfig) config); | |
| 57 | -// case ALIPAY_WAP: return (AbstractFileClient<Config>) new AlipayWapFileClient(channelId, (AlipayFileClientConfig) config); | |
| 58 | -// case ALIPAY_QR: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config); | |
| 59 | -// case ALIPAY_APP: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config); | |
| 60 | -// case ALIPAY_PC: return (AbstractFileClient<Config>) new AlipayQrFileClient(channelId, (AlipayFileClientConfig) config); | |
| 61 | -// } | |
| 62 | 53 | return (AbstractFileClient<Config>) ReflectUtil.newInstance(storageEnum.getClientClass(), configId, config); |
| 63 | -// storageEnum.getClientClass().newInstance() | |
| 64 | -// // 创建失败,错误日志 + 抛出异常 | |
| 65 | -// log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", config); | |
| 66 | -// throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", config)); | |
| 67 | 54 | } |
| 68 | 55 | |
| 69 | 56 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-file/src/main/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClientConfig.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.file.core.client.s3; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; |
| 5 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
| 5 | 6 | import lombok.Data; |
| 6 | 7 | import org.hibernate.validator.constraints.URL; |
| 7 | 8 | |
| ... | ... | @@ -70,11 +71,12 @@ public class S3FileClientConfig implements FileClientConfig { |
| 70 | 71 | @NotNull(message = "accessSecret 不能为空") |
| 71 | 72 | private String accessSecret; |
| 72 | 73 | |
| 73 | - @AssertTrue(message = "domain 不能为空") | |
| 74 | 74 | @SuppressWarnings("RedundantIfStatement") |
| 75 | + @AssertTrue(message = "domain 不能为空") | |
| 76 | + @JsonIgnore | |
| 75 | 77 | public boolean isDomainValid() { |
| 76 | 78 | // 如果是七牛,必须带有 domain |
| 77 | - if (endpoint.contains(ENDPOINT_QINIU) && StrUtil.isEmpty(domain)) { | |
| 79 | + if (StrUtil.contains(endpoint, ENDPOINT_QINIU) && StrUtil.isEmpty(domain)) { | |
| 78 | 80 | return false; |
| 79 | 81 | } |
| 80 | 82 | return true; | ... | ... |
yudao-framework/yudao-spring-boot-starter-file/src/test/java/cn/iocoder/yudao/framework/file/core/client/s3/S3FileClientTest.java
| ... | ... | @@ -49,10 +49,12 @@ public class S3FileClientTest { |
| 49 | 49 | public void testQiniu() { |
| 50 | 50 | S3FileClientConfig config = new S3FileClientConfig(); |
| 51 | 51 | // 配置成你自己的 |
| 52 | - config.setAccessKey(System.getenv("QINIU_ACCESS_KEY")); | |
| 53 | - config.setAccessSecret(System.getenv("QINIU_SECRET_KEY")); | |
| 54 | - config.setBucket("s3-test-yudao"); | |
| 55 | - config.setDomain("http://r8oo8po1q.hn-bkt.clouddn.com"); // 如果有自定义域名,则可以设置。http://static.yudao.iocoder.cn | |
| 52 | +// config.setAccessKey(System.getenv("QINIU_ACCESS_KEY")); | |
| 53 | +// config.setAccessSecret(System.getenv("QINIU_SECRET_KEY")); | |
| 54 | + config.setAccessKey("b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8"); | |
| 55 | + config.setAccessSecret("kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP"); | |
| 56 | + config.setBucket("ruoyi-vue-pro"); | |
| 57 | + config.setDomain("http://test.yudao.iocoder.cn"); // 如果有自定义域名,则可以设置。http://static.yudao.iocoder.cn | |
| 56 | 58 | // 默认上海的 endpoint |
| 57 | 59 | config.setEndpoint("s3-cn-south-1.qiniucs.com"); |
| 58 | 60 | ... | ... |
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
| ... | ... | @@ -42,8 +42,10 @@ public interface ErrorCodeConstants { |
| 42 | 42 | ErrorCode CODEGEN_SYNC_COLUMNS_NULL = new ErrorCode(1003001006, "同步的字段不存在"); |
| 43 | 43 | ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1003001007, "同步失败,不存在改变"); |
| 44 | 44 | |
| 45 | - // ========== 字典类型(测试) 1003000000 ========== | |
| 46 | - ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1003000000, "测试示例不存在"); | |
| 45 | + // ========== 字典类型(测试)1001005000 ========== | |
| 46 | + ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1001005000, "测试示例不存在"); | |
| 47 | 47 | |
| 48 | + // ========== 文件配置 1001006000 ========== | |
| 49 | + ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1001006000, "文件配置不存在"); | |
| 48 | 50 | |
| 49 | 51 | } | ... | ... |
yudao-module-infra/yudao-module-infra-impl/pom.xml
| ... | ... | @@ -109,6 +109,13 @@ |
| 109 | 109 | <groupId>de.codecentric</groupId> |
| 110 | 110 | <artifactId>spring-boot-admin-starter-server</artifactId> <!-- 实现 Spring Boot Admin Server 服务端 --> |
| 111 | 111 | </dependency> |
| 112 | + | |
| 113 | + <!-- 三方云服务相关 --> | |
| 114 | + <dependency> | |
| 115 | + <groupId>cn.iocoder.boot</groupId> | |
| 116 | + <artifactId>yudao-spring-boot-starter-file</artifactId> | |
| 117 | + </dependency> | |
| 118 | + | |
| 112 | 119 | </dependencies> |
| 113 | 120 | |
| 114 | 121 | </project> | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.http
0 → 100644
| 1 | +### 请求 /infra/file-config/create 接口 => 成功 | |
| 2 | +POST {{baseUrl}}/infra/file-config/create | |
| 3 | +Content-Type: application/json | |
| 4 | +tenant-id: {{adminTenentId}} | |
| 5 | +Authorization: Bearer {{token}} | |
| 6 | + | |
| 7 | +{ | |
| 8 | + "name": "S3 - 七牛云", | |
| 9 | + "remark": "", | |
| 10 | + "storage": 20, | |
| 11 | + "config": { | |
| 12 | + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", | |
| 13 | + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", | |
| 14 | + "bucket": "ruoyi-vue-pro", | |
| 15 | + "endpoint": "s3-cn-south-1.qiniucs.com", | |
| 16 | + "domain": "http://test.yudao.iocoder.cn", | |
| 17 | + "region": "oss-cn-beijing" | |
| 18 | + } | |
| 19 | +} | |
| 20 | + | |
| 21 | +### 请求 /infra/file-config/update 接口 => 成功 | |
| 22 | +PUT {{baseUrl}}/infra/file-config/update | |
| 23 | +Content-Type: application/json | |
| 24 | +tenant-id: {{adminTenentId}} | |
| 25 | +Authorization: Bearer {{token}} | |
| 26 | + | |
| 27 | +{ | |
| 28 | + "id": 2, | |
| 29 | + "name": "S3 - 七牛云", | |
| 30 | + "remark": "", | |
| 31 | + "config": { | |
| 32 | + "accessKey": "b7yvuhBSAGjmtPhMFcn9iMOxUOY_I06cA_p0ZUx8", | |
| 33 | + "accessSecret": "kXM1l5ia1RvSX3QaOEcwI3RLz3Y2rmNszWonKZtP", | |
| 34 | + "bucket": "ruoyi-vue-pro", | |
| 35 | + "endpoint": "s3-cn-south-1.qiniucs.com", | |
| 36 | + "domain": "http://test.yudao.iocoder.cn", | |
| 37 | + "region": "oss-cn-beijing" | |
| 38 | + } | |
| 39 | +} | |
| 40 | + | |
| 41 | +### 请求 /infra/file-config/test 接口 => 成功 | |
| 42 | +GET {{baseUrl}}/infra/file-config/test?id=2 | |
| 43 | +Content-Type: application/json | |
| 44 | +tenant-id: {{adminTenentId}} | |
| 45 | +Authorization: Bearer {{token}} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileConfigController.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigRespVO; | |
| 8 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; | |
| 9 | +import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; | |
| 10 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 11 | +import cn.iocoder.yudao.module.infra.service.file.FileConfigService; | |
| 12 | +import io.swagger.annotations.Api; | |
| 13 | +import io.swagger.annotations.ApiImplicitParam; | |
| 14 | +import io.swagger.annotations.ApiOperation; | |
| 15 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 16 | +import org.springframework.validation.annotation.Validated; | |
| 17 | +import org.springframework.web.bind.annotation.*; | |
| 18 | + | |
| 19 | +import javax.annotation.Resource; | |
| 20 | +import javax.validation.Valid; | |
| 21 | + | |
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 23 | + | |
| 24 | +@Api(tags = "管理后台 - 文件配置") | |
| 25 | +@RestController | |
| 26 | +@RequestMapping("/infra/file-config") | |
| 27 | +@Validated | |
| 28 | +public class FileConfigController { | |
| 29 | + | |
| 30 | + @Resource | |
| 31 | + private FileConfigService fileConfigService; | |
| 32 | + | |
| 33 | + @PostMapping("/create") | |
| 34 | + @ApiOperation("创建文件配置") | |
| 35 | + @PreAuthorize("@ss.hasPermission('infra:file-config:create')") | |
| 36 | + public CommonResult<Long> createFileConfig(@Valid @RequestBody FileConfigCreateReqVO createReqVO) { | |
| 37 | + return success(fileConfigService.createFileConfig(createReqVO)); | |
| 38 | + } | |
| 39 | + | |
| 40 | + @PutMapping("/update") | |
| 41 | + @ApiOperation("更新文件配置") | |
| 42 | + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") | |
| 43 | + public CommonResult<Boolean> updateFileConfig(@Valid @RequestBody FileConfigUpdateReqVO updateReqVO) { | |
| 44 | + fileConfigService.updateFileConfig(updateReqVO); | |
| 45 | + return success(true); | |
| 46 | + } | |
| 47 | + | |
| 48 | + @PutMapping("/update-master") | |
| 49 | + @ApiOperation("更新文件配置为 Master") | |
| 50 | + @PreAuthorize("@ss.hasPermission('infra:file-config:update')") | |
| 51 | + public CommonResult<Boolean> updateFileConfigMaster(@RequestParam("id") Long id) { | |
| 52 | + fileConfigService.updateFileConfigMaster(id); | |
| 53 | + return success(true); | |
| 54 | + } | |
| 55 | + | |
| 56 | + @DeleteMapping("/delete") | |
| 57 | + @ApiOperation("删除文件配置") | |
| 58 | + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | |
| 59 | + @PreAuthorize("@ss.hasPermission('infra:file-config:delete')") | |
| 60 | + public CommonResult<Boolean> deleteFileConfig(@RequestParam("id") Long id) { | |
| 61 | + fileConfigService.deleteFileConfig(id); | |
| 62 | + return success(true); | |
| 63 | + } | |
| 64 | + | |
| 65 | + @GetMapping("/get") | |
| 66 | + @ApiOperation("获得文件配置") | |
| 67 | + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) | |
| 68 | + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") | |
| 69 | + public CommonResult<FileConfigRespVO> getFileConfig(@RequestParam("id") Long id) { | |
| 70 | + FileConfigDO fileConfig = fileConfigService.getFileConfig(id); | |
| 71 | + return success(FileConfigConvert.INSTANCE.convert(fileConfig)); | |
| 72 | + } | |
| 73 | + | |
| 74 | + @GetMapping("/page") | |
| 75 | + @ApiOperation("获得文件配置分页") | |
| 76 | + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") | |
| 77 | + public CommonResult<PageResult<FileConfigRespVO>> getFileConfigPage(@Valid FileConfigPageReqVO pageVO) { | |
| 78 | + PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(pageVO); | |
| 79 | + return success(FileConfigConvert.INSTANCE.convertPage(pageResult)); | |
| 80 | + } | |
| 81 | + | |
| 82 | + @GetMapping("/test") | |
| 83 | + @ApiOperation("测试文件配置是否正确") | |
| 84 | + @PreAuthorize("@ss.hasPermission('infra:file-config:query')") | |
| 85 | + public CommonResult<String> testFileConfig(@RequestParam("id") Long id) { | |
| 86 | + String url = fileConfigService.testFileConfig(id); | |
| 87 | + return success(url); | |
| 88 | + } | |
| 89 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigBaseVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; | |
| 2 | + | |
| 3 | +import io.swagger.annotations.ApiModelProperty; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import javax.validation.constraints.NotNull; | |
| 7 | + | |
| 8 | +/** | |
| 9 | +* 文件配置 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 10 | +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 11 | +*/ | |
| 12 | +@Data | |
| 13 | +public class FileConfigBaseVO { | |
| 14 | + | |
| 15 | + @ApiModelProperty(value = "配置名", required = true, example = "S3 - 阿里云") | |
| 16 | + @NotNull(message = "配置名不能为空") | |
| 17 | + private String name; | |
| 18 | + | |
| 19 | + @ApiModelProperty(value = "备注", example = "我是备注") | |
| 20 | + private String remark; | |
| 21 | + | |
| 22 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigCreateReqVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; | |
| 2 | + | |
| 3 | +import io.swagger.annotations.ApiModel; | |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | + | |
| 9 | +import javax.validation.constraints.NotNull; | |
| 10 | +import java.util.Map; | |
| 11 | + | |
| 12 | +@ApiModel("管理后台 - 文件配置创建 Request VO") | |
| 13 | +@Data | |
| 14 | +@EqualsAndHashCode(callSuper = true) | |
| 15 | +@ToString(callSuper = true) | |
| 16 | +public class FileConfigCreateReqVO extends FileConfigBaseVO { | |
| 17 | + | |
| 18 | + @ApiModelProperty(value = "存储器", required = true, example = "1", notes = "参见 FileStorageEnum 枚举类") | |
| 19 | + @NotNull(message = "存储器不能为空") | |
| 20 | + private Integer storage; | |
| 21 | + | |
| 22 | + @ApiModelProperty(value = "存储配置", required = true, notes = "配置是动态参数,所以使用 Map 接收") | |
| 23 | + @NotNull(message = "存储配置不能为空") | |
| 24 | + private Map<String, Object> config; | |
| 25 | + | |
| 26 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigPageReqVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.annotations.ApiModel; | |
| 5 | +import io.swagger.annotations.ApiModelProperty; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.EqualsAndHashCode; | |
| 8 | +import lombok.ToString; | |
| 9 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 10 | + | |
| 11 | +import java.util.Date; | |
| 12 | + | |
| 13 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 14 | + | |
| 15 | +@ApiModel("管理后台 - 文件配置分页 Request VO") | |
| 16 | +@Data | |
| 17 | +@EqualsAndHashCode(callSuper = true) | |
| 18 | +@ToString(callSuper = true) | |
| 19 | +public class FileConfigPageReqVO extends PageParam { | |
| 20 | + | |
| 21 | + @ApiModelProperty(value = "配置名", example = "S3 - 阿里云") | |
| 22 | + private String name; | |
| 23 | + | |
| 24 | + @ApiModelProperty(value = "存储器", example = "1") | |
| 25 | + private Integer storage; | |
| 26 | + | |
| 27 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 28 | + @ApiModelProperty(value = "开始创建时间") | |
| 29 | + private Date beginCreateTime; | |
| 30 | + | |
| 31 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 32 | + @ApiModelProperty(value = "结束创建时间") | |
| 33 | + private Date endCreateTime; | |
| 34 | + | |
| 35 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigRespVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | |
| 4 | +import io.swagger.annotations.ApiModel; | |
| 5 | +import io.swagger.annotations.ApiModelProperty; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.EqualsAndHashCode; | |
| 8 | +import lombok.ToString; | |
| 9 | + | |
| 10 | +import javax.validation.constraints.NotNull; | |
| 11 | +import java.util.Date; | |
| 12 | + | |
| 13 | +@ApiModel("管理后台 - 文件配置 Response VO") | |
| 14 | +@Data | |
| 15 | +@EqualsAndHashCode(callSuper = true) | |
| 16 | +@ToString(callSuper = true) | |
| 17 | +public class FileConfigRespVO extends FileConfigBaseVO { | |
| 18 | + | |
| 19 | + @ApiModelProperty(value = "编号", required = true, example = "1") | |
| 20 | + private Long id; | |
| 21 | + | |
| 22 | + @ApiModelProperty(value = "存储配置", required = true) | |
| 23 | + private FileClientConfig config; | |
| 24 | + | |
| 25 | + @ApiModelProperty(value = "是否为主配置", required = true, example = "true") | |
| 26 | + @NotNull(message = "是否为主配置不能为空") | |
| 27 | + private Boolean master; | |
| 28 | + | |
| 29 | + @ApiModelProperty(value = "创建时间", required = true) | |
| 30 | + private Date createTime; | |
| 31 | + | |
| 32 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/vo/config/FileConfigUpdateReqVO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.controller.admin.file.vo.config; | |
| 2 | + | |
| 3 | +import io.swagger.annotations.ApiModel; | |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | + | |
| 9 | +import javax.validation.constraints.NotNull; | |
| 10 | +import java.util.Map; | |
| 11 | + | |
| 12 | +@ApiModel("管理后台 - 文件配置更新 Request VO") | |
| 13 | +@Data | |
| 14 | +@EqualsAndHashCode(callSuper = true) | |
| 15 | +@ToString(callSuper = true) | |
| 16 | +public class FileConfigUpdateReqVO extends FileConfigBaseVO { | |
| 17 | + | |
| 18 | + @ApiModelProperty(value = "编号", required = true, example = "1") | |
| 19 | + @NotNull(message = "编号不能为空") | |
| 20 | + private Long id; | |
| 21 | + | |
| 22 | + @ApiModelProperty(value = "存储配置", required = true, notes = "配置是动态参数,所以使用 Map 接收") | |
| 23 | + @NotNull(message = "存储配置不能为空") | |
| 24 | + private Map<String, Object> config; | |
| 25 | + | |
| 26 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/convert/file/FileConfigConvert.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.convert.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigRespVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 8 | +import org.mapstruct.Mapper; | |
| 9 | +import org.mapstruct.Mapping; | |
| 10 | +import org.mapstruct.factory.Mappers; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 文件配置 Convert | |
| 16 | + * | |
| 17 | + * @author 芋道源码 | |
| 18 | + */ | |
| 19 | +@Mapper | |
| 20 | +public interface FileConfigConvert { | |
| 21 | + | |
| 22 | + FileConfigConvert INSTANCE = Mappers.getMapper(FileConfigConvert.class); | |
| 23 | + | |
| 24 | + @Mapping(target = "config", ignore = true) | |
| 25 | + FileConfigDO convert(FileConfigCreateReqVO bean); | |
| 26 | + | |
| 27 | + @Mapping(target = "config", ignore = true) | |
| 28 | + FileConfigDO convert(FileConfigUpdateReqVO bean); | |
| 29 | + | |
| 30 | + FileConfigRespVO convert(FileConfigDO bean); | |
| 31 | + | |
| 32 | + List<FileConfigRespVO> convertList(List<FileConfigDO> list); | |
| 33 | + | |
| 34 | + PageResult<FileConfigRespVO> convertPage(PageResult<FileConfigDO> page); | |
| 35 | + | |
| 36 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileConfigDO.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.dal.dataobject.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | |
| 4 | +import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 6 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 8 | +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; | |
| 9 | +import lombok.*; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 文件配置表 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +@TableName(value = "infra_file_config", autoResultMap = true) | |
| 18 | +@EqualsAndHashCode(callSuper = true) | |
| 19 | +@ToString(callSuper = true) | |
| 20 | +@Builder | |
| 21 | +@NoArgsConstructor | |
| 22 | +@AllArgsConstructor | |
| 23 | +public class FileConfigDO extends BaseDO { | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 配置编号,数据库自增 | |
| 27 | + */ | |
| 28 | + private Long id; | |
| 29 | + /** | |
| 30 | + * 配置名 | |
| 31 | + */ | |
| 32 | + private String name; | |
| 33 | + /** | |
| 34 | + * 存储器 | |
| 35 | + * | |
| 36 | + * 枚举 {@link FileStorageEnum} | |
| 37 | + */ | |
| 38 | + private Integer storage; | |
| 39 | + /** | |
| 40 | + * 备注 | |
| 41 | + */ | |
| 42 | + private String remark; | |
| 43 | + /** | |
| 44 | + * 是否为主配置 | |
| 45 | + * | |
| 46 | + * 由于我们可以配置多个文件配置,默认情况下,使用主配置进行文件的上传 | |
| 47 | + */ | |
| 48 | + private Boolean master; | |
| 49 | + | |
| 50 | + /** | |
| 51 | + * 支付渠道配置 | |
| 52 | + */ | |
| 53 | + @TableField(typeHandler = JacksonTypeHandler.class) | |
| 54 | + private FileClientConfig config; | |
| 55 | + | |
| 56 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileContentDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.dal.dataobject.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | |
| 4 | +import com.baomidou.mybatisplus.annotation.IdType; | |
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 7 | +import lombok.*; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 文件内容表 | |
| 11 | + * | |
| 12 | + * 专门用于存储 {@link cn.iocoder.yudao.framework.file.core.client.db.DBFileClient} 的文件内容 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +@TableName("infra_file_content") | |
| 18 | +@EqualsAndHashCode(callSuper = true) | |
| 19 | +@ToString(callSuper = true) | |
| 20 | +@Builder | |
| 21 | +@NoArgsConstructor | |
| 22 | +@AllArgsConstructor | |
| 23 | +public class FileContentDO extends BaseDO { | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 编号,数据库自增 | |
| 27 | + */ | |
| 28 | + @TableId(type = IdType.INPUT) | |
| 29 | + private String id; | |
| 30 | + /** | |
| 31 | + * 配置编号 | |
| 32 | + * | |
| 33 | + * 关联 {@link FileConfigDO#getId()} | |
| 34 | + */ | |
| 35 | + private Long configId; | |
| 36 | + /** | |
| 37 | + * 路径,即文件名 | |
| 38 | + */ | |
| 39 | + private String path; | |
| 40 | + /** | |
| 41 | + * 文件内容 | |
| 42 | + */ | |
| 43 | + private byte[] content; | |
| 44 | + | |
| 45 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/file/FileDO.java
| ... | ... | @@ -11,6 +11,7 @@ import java.io.InputStream; |
| 11 | 11 | |
| 12 | 12 | /** |
| 13 | 13 | * 文件表 |
| 14 | + * 每次文件上传,都会记录一条记录到该表中 | |
| 14 | 15 | * |
| 15 | 16 | * @author 芋道源码 |
| 16 | 17 | */ |
| ... | ... | @@ -24,11 +25,21 @@ import java.io.InputStream; |
| 24 | 25 | public class FileDO extends BaseDO { |
| 25 | 26 | |
| 26 | 27 | /** |
| 27 | - * 文件路径 | |
| 28 | + * 编号,数据库自增 | |
| 28 | 29 | */ |
| 29 | 30 | @TableId(type = IdType.INPUT) |
| 30 | 31 | private String id; |
| 31 | 32 | /** |
| 33 | + * 配置编号 | |
| 34 | + * | |
| 35 | + * 关联 {@link FileConfigDO#getId()} | |
| 36 | + */ | |
| 37 | + private Long configId; | |
| 38 | + /** | |
| 39 | + * 路径,即文件名 | |
| 40 | + */ | |
| 41 | + private String path; | |
| 42 | + /** | |
| 32 | 43 | * 文件类型 |
| 33 | 44 | * |
| 34 | 45 | * 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取 |
| ... | ... | @@ -36,8 +47,17 @@ public class FileDO extends BaseDO { |
| 36 | 47 | @TableField(value = "`type`") |
| 37 | 48 | private String type; |
| 38 | 49 | /** |
| 50 | + * 访问地址 | |
| 51 | + */ | |
| 52 | + private String url; | |
| 53 | + /** | |
| 54 | + * 文件大小 | |
| 55 | + */ | |
| 56 | + private Integer size; | |
| 57 | + /** | |
| 39 | 58 | * 文件内容 |
| 40 | 59 | */ |
| 60 | + @Deprecated | |
| 41 | 61 | private byte[] content; |
| 42 | 62 | |
| 43 | 63 | } | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/file/FileConfigMapper.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.dal.mysql.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | +import org.apache.ibatis.annotations.Select; | |
| 10 | + | |
| 11 | +import java.util.Date; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 文件配置 Mapper | |
| 15 | + * | |
| 16 | + * @author 芋道源码 | |
| 17 | + */ | |
| 18 | +@Mapper | |
| 19 | +public interface FileConfigMapper extends BaseMapperX<FileConfigDO> { | |
| 20 | + | |
| 21 | + default PageResult<FileConfigDO> selectPage(FileConfigPageReqVO reqVO) { | |
| 22 | + return selectPage(reqVO, new LambdaQueryWrapperX<FileConfigDO>() | |
| 23 | + .likeIfPresent(FileConfigDO::getName, reqVO.getName()) | |
| 24 | + .eqIfPresent(FileConfigDO::getStorage, reqVO.getStorage()) | |
| 25 | + .betweenIfPresent(FileConfigDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) | |
| 26 | + .orderByDesc(FileConfigDO::getId)); | |
| 27 | + } | |
| 28 | + | |
| 29 | + @Select("SELECT id FROM infra_file_config WHERE update_time > #{maxUpdateTime} LIMIT 1") | |
| 30 | + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime); | |
| 31 | + | |
| 32 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/file/FileConfigRefreshConsumer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.mq.consumer.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | |
| 4 | +import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage; | |
| 5 | +import cn.iocoder.yudao.module.infra.service.file.FileConfigService; | |
| 6 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | +import org.springframework.stereotype.Component; | |
| 8 | + | |
| 9 | +import javax.annotation.Resource; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 针对 {@link FileConfigRefreshMessage} 的消费者 | |
| 13 | + * | |
| 14 | + * @author 芋道源码 | |
| 15 | + */ | |
| 16 | +@Component | |
| 17 | +@Slf4j | |
| 18 | +public class FileConfigRefreshConsumer extends AbstractChannelMessageListener<FileConfigRefreshMessage> { | |
| 19 | + | |
| 20 | + @Resource | |
| 21 | + private FileConfigService fileConfigService; | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public void onMessage(FileConfigRefreshMessage message) { | |
| 25 | + log.info("[onMessage][收到 FileConfig 刷新消息]"); | |
| 26 | + fileConfigService.initFileClients(); | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/consumer/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.infra.mq.consumer; |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/message/file/FileConfigRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.mq.message.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 文件配置数据刷新 Message | |
| 8 | + */ | |
| 9 | +@Data | |
| 10 | +public class FileConfigRefreshMessage extends AbstractChannelMessage { | |
| 11 | + | |
| 12 | + @Override | |
| 13 | + public String getChannel() { | |
| 14 | + return "infra.file-config.refresh"; | |
| 15 | + } | |
| 16 | + | |
| 17 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/message/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.infra.mq.message; |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/file/FileConfigProducer.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.mq.producer.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | |
| 4 | +import cn.iocoder.yudao.module.infra.mq.message.file.FileConfigRefreshMessage; | |
| 5 | +import org.springframework.stereotype.Component; | |
| 6 | + | |
| 7 | +import javax.annotation.Resource; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * 文件配置相关消息的 Producer | |
| 11 | + */ | |
| 12 | +@Component | |
| 13 | +public class FileConfigProducer { | |
| 14 | + | |
| 15 | + @Resource | |
| 16 | + private RedisMQTemplate redisMQTemplate; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 发送 {@link FileConfigRefreshMessage} 消息 | |
| 20 | + */ | |
| 21 | + public void sendFileConfigRefreshMessage() { | |
| 22 | + FileConfigRefreshMessage message = new FileConfigRefreshMessage(); | |
| 23 | + redisMQTemplate.send(message); | |
| 24 | + } | |
| 25 | + | |
| 26 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java deleted
| 1 | -package cn.iocoder.yudao.module.infra.mq.producer; |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigService.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 8 | + | |
| 9 | +import javax.validation.Valid; | |
| 10 | +import java.util.Collection; | |
| 11 | +import java.util.List; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 文件配置 Service 接口 | |
| 15 | + * | |
| 16 | + * @author 芋道源码 | |
| 17 | + */ | |
| 18 | +public interface FileConfigService { | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 初始化文件客户端 | |
| 22 | + */ | |
| 23 | + void initFileClients(); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 创建文件配置 | |
| 27 | + * | |
| 28 | + * @param createReqVO 创建信息 | |
| 29 | + * @return 编号 | |
| 30 | + */ | |
| 31 | + Long createFileConfig(@Valid FileConfigCreateReqVO createReqVO); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 更新文件配置 | |
| 35 | + * | |
| 36 | + * @param updateReqVO 更新信息 | |
| 37 | + */ | |
| 38 | + void updateFileConfig(@Valid FileConfigUpdateReqVO updateReqVO); | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 更新文件配置为 Master | |
| 42 | + * | |
| 43 | + * @param id 编号 | |
| 44 | + */ | |
| 45 | + void updateFileConfigMaster(Long id); | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 删除文件配置 | |
| 49 | + * | |
| 50 | + * @param id 编号 | |
| 51 | + */ | |
| 52 | + void deleteFileConfig(Long id); | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 获得文件配置 | |
| 56 | + * | |
| 57 | + * @param id 编号 | |
| 58 | + * @return 文件配置 | |
| 59 | + */ | |
| 60 | + FileConfigDO getFileConfig(Long id); | |
| 61 | + | |
| 62 | + /** | |
| 63 | + * 获得文件配置列表 | |
| 64 | + * | |
| 65 | + * @param ids 编号 | |
| 66 | + * @return 文件配置列表 | |
| 67 | + */ | |
| 68 | + List<FileConfigDO> getFileConfigList(Collection<Long> ids); | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * 获得文件配置分页 | |
| 72 | + * | |
| 73 | + * @param pageReqVO 分页查询 | |
| 74 | + * @return 文件配置分页 | |
| 75 | + */ | |
| 76 | + PageResult<FileConfigDO> getFileConfigPage(FileConfigPageReqVO pageReqVO); | |
| 77 | + | |
| 78 | + /** | |
| 79 | + * 测试文件配置是否正确,通过上传文件 | |
| 80 | + * | |
| 81 | + * @param id 编号 | |
| 82 | + * @return 文件 URL | |
| 83 | + */ | |
| 84 | + String testFileConfig(Long id); | |
| 85 | + | |
| 86 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.file; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.io.resource.ResourceUtil; | |
| 5 | +import cn.hutool.core.util.IdUtil; | |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | |
| 9 | +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; | |
| 10 | +import cn.iocoder.yudao.framework.file.core.client.FileClient; | |
| 11 | +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig; | |
| 12 | +import cn.iocoder.yudao.framework.file.core.client.FileClientFactory; | |
| 13 | +import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum; | |
| 14 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; | |
| 15 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; | |
| 16 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; | |
| 17 | +import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert; | |
| 18 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 19 | +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; | |
| 20 | +import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer; | |
| 21 | +import lombok.extern.slf4j.Slf4j; | |
| 22 | +import org.springframework.context.annotation.Lazy; | |
| 23 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 24 | +import org.springframework.stereotype.Service; | |
| 25 | +import org.springframework.validation.annotation.Validated; | |
| 26 | + | |
| 27 | +import javax.annotation.PostConstruct; | |
| 28 | +import javax.annotation.Resource; | |
| 29 | +import javax.validation.Validator; | |
| 30 | +import java.util.Collection; | |
| 31 | +import java.util.Date; | |
| 32 | +import java.util.List; | |
| 33 | +import java.util.Map; | |
| 34 | + | |
| 35 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 36 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * 文件配置 Service 实现类 | |
| 40 | + * | |
| 41 | + * @author 芋道源码 | |
| 42 | + */ | |
| 43 | +@Service | |
| 44 | +@Validated | |
| 45 | +@Slf4j | |
| 46 | +public class FileConfigServiceImpl implements FileConfigService { | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 | |
| 50 | + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 | |
| 51 | + */ | |
| 52 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | |
| 56 | + */ | |
| 57 | + private volatile Date maxUpdateTime; | |
| 58 | + | |
| 59 | + @Resource | |
| 60 | + private FileClientFactory fileClientFactory; | |
| 61 | + /** | |
| 62 | + * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的 | |
| 63 | + */ | |
| 64 | + private FileClient masterFileClient; | |
| 65 | + | |
| 66 | + @Resource | |
| 67 | + private FileConfigMapper fileConfigMapper; | |
| 68 | + | |
| 69 | + @Resource | |
| 70 | + private FileConfigProducer fileConfigProducer; | |
| 71 | + | |
| 72 | + @Resource | |
| 73 | + private Validator validator; | |
| 74 | + | |
| 75 | + @Resource | |
| 76 | + @Lazy // 注入自己,所以延迟加载 | |
| 77 | + private FileConfigService self; | |
| 78 | + | |
| 79 | + @Override | |
| 80 | + @PostConstruct | |
| 81 | + public void initFileClients() { | |
| 82 | + // 获取文件配置,如果有更新 | |
| 83 | + List<FileConfigDO> configs = loadFileConfigIfUpdate(maxUpdateTime); | |
| 84 | + if (CollUtil.isEmpty(configs)) { | |
| 85 | + return; | |
| 86 | + } | |
| 87 | + | |
| 88 | + // 创建或更新支付 Client | |
| 89 | + configs.forEach(config -> { | |
| 90 | + fileClientFactory.createOrUpdateFileClient(config.getId(), config.getStorage(), config.getConfig()); | |
| 91 | + // 如果是 master,进行设置 | |
| 92 | + if (Boolean.TRUE.equals(config.getMaster())) { | |
| 93 | + masterFileClient = fileClientFactory.getFileClient(config.getId()); | |
| 94 | + } | |
| 95 | + }); | |
| 96 | + | |
| 97 | + // 写入缓存 | |
| 98 | + maxUpdateTime = CollectionUtils.getMaxValue(configs, FileConfigDO::getUpdateTime); | |
| 99 | + log.info("[initFileClients][初始化 FileConfig 数量为 {}]", configs.size()); | |
| 100 | + } | |
| 101 | + | |
| 102 | + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | |
| 103 | + public void schedulePeriodicRefresh() { | |
| 104 | + self.initFileClients(); | |
| 105 | + } | |
| 106 | + | |
| 107 | + /** | |
| 108 | + * 如果文件配置发生变化,从数据库中获取最新的全量文件配置。 | |
| 109 | + * 如果未发生变化,则返回空 | |
| 110 | + * | |
| 111 | + * @param maxUpdateTime 当前文件配置的最大更新时间 | |
| 112 | + * @return 文件配置列表 | |
| 113 | + */ | |
| 114 | + private List<FileConfigDO> loadFileConfigIfUpdate(Date maxUpdateTime) { | |
| 115 | + // 第一步,判断是否要更新。 | |
| 116 | + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | |
| 117 | + log.info("[loadFileConfigIfUpdate][首次加载全量文件配置]"); | |
| 118 | + } else { // 判断数据库中是否有更新的文件配置 | |
| 119 | + if (fileConfigMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) { | |
| 120 | + return null; | |
| 121 | + } | |
| 122 | + log.info("[loadFileConfigIfUpdate][增量加载全量文件配置]"); | |
| 123 | + } | |
| 124 | + // 第二步,如果有更新,则从数据库加载所有文件配置 | |
| 125 | + return fileConfigMapper.selectList(); | |
| 126 | + } | |
| 127 | + | |
| 128 | + @Override | |
| 129 | + public Long createFileConfig(FileConfigCreateReqVO createReqVO) { | |
| 130 | + // 插入 | |
| 131 | + FileConfigDO fileConfig = FileConfigConvert.INSTANCE.convert(createReqVO) | |
| 132 | + .setConfig(parseClientConfig(createReqVO.getStorage(), createReqVO.getConfig())) | |
| 133 | + .setMaster(false); // 默认非 master | |
| 134 | + fileConfigMapper.insert(fileConfig); | |
| 135 | + // 发送刷新配置的消息 | |
| 136 | + fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 137 | + // 返回 | |
| 138 | + return fileConfig.getId(); | |
| 139 | + } | |
| 140 | + | |
| 141 | + @Override | |
| 142 | + public void updateFileConfig(FileConfigUpdateReqVO updateReqVO) { | |
| 143 | + // 校验存在 | |
| 144 | + FileConfigDO config = this.validateFileConfigExists(updateReqVO.getId()); | |
| 145 | + // 更新 | |
| 146 | + FileConfigDO updateObj = FileConfigConvert.INSTANCE.convert(updateReqVO) | |
| 147 | + .setConfig(parseClientConfig(config.getStorage(), updateReqVO.getConfig())); | |
| 148 | + fileConfigMapper.updateById(updateObj); | |
| 149 | + // 发送刷新配置的消息 | |
| 150 | + fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 151 | + } | |
| 152 | + | |
| 153 | + @Override | |
| 154 | + public void updateFileConfigMaster(Long id) { | |
| 155 | + // 校验存在 | |
| 156 | + this.validateFileConfigExists(id); | |
| 157 | + // 更新 | |
| 158 | + fileConfigMapper.updateById(new FileConfigDO().setId(id).setMaster(true)); | |
| 159 | + // 发送刷新配置的消息 | |
| 160 | + fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 161 | + } | |
| 162 | + | |
| 163 | + private FileClientConfig parseClientConfig(Integer storage, Map<String, Object> config) { | |
| 164 | + // 获取配置类 | |
| 165 | + Class<? extends FileClientConfig> configClass = FileStorageEnum.getByStorage(storage) | |
| 166 | + .getConfigClass(); | |
| 167 | + FileClientConfig clientConfig = JsonUtils.parseObject2(JsonUtils.toJsonString(config), configClass); | |
| 168 | + // 参数校验 | |
| 169 | + ValidationUtils.validate(validator, clientConfig); | |
| 170 | + // 设置参数 | |
| 171 | + return clientConfig; | |
| 172 | + } | |
| 173 | + | |
| 174 | + @Override | |
| 175 | + public void deleteFileConfig(Long id) { | |
| 176 | + // 校验存在 | |
| 177 | + this.validateFileConfigExists(id); | |
| 178 | + // 删除 | |
| 179 | + fileConfigMapper.deleteById(id); | |
| 180 | + // 发送刷新配置的消息 | |
| 181 | + fileConfigProducer.sendFileConfigRefreshMessage(); | |
| 182 | + } | |
| 183 | + | |
| 184 | + private FileConfigDO validateFileConfigExists(Long id) { | |
| 185 | + FileConfigDO config = fileConfigMapper.selectById(id); | |
| 186 | + if (config == null) { | |
| 187 | + throw exception(FILE_CONFIG_NOT_EXISTS); | |
| 188 | + } | |
| 189 | + return config; | |
| 190 | + } | |
| 191 | + | |
| 192 | + @Override | |
| 193 | + public FileConfigDO getFileConfig(Long id) { | |
| 194 | + return fileConfigMapper.selectById(id); | |
| 195 | + } | |
| 196 | + | |
| 197 | + @Override | |
| 198 | + public List<FileConfigDO> getFileConfigList(Collection<Long> ids) { | |
| 199 | + return fileConfigMapper.selectBatchIds(ids); | |
| 200 | + } | |
| 201 | + | |
| 202 | + @Override | |
| 203 | + public PageResult<FileConfigDO> getFileConfigPage(FileConfigPageReqVO pageReqVO) { | |
| 204 | + return fileConfigMapper.selectPage(pageReqVO); | |
| 205 | + } | |
| 206 | + | |
| 207 | + @Override | |
| 208 | + public String testFileConfig(Long id) { | |
| 209 | + // 校验存在 | |
| 210 | + this.validateFileConfigExists(id); | |
| 211 | + // 上传文件 | |
| 212 | + byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); | |
| 213 | + return fileClientFactory.getFileClient(id).upload(content, IdUtil.fastSimpleUUID() + ".jpg"); | |
| 214 | + } | |
| 215 | + | |
| 216 | +} | ... | ... |
yudao-module-infra/yudao-module-infra-impl/src/test/resources/file/erweima.jpg renamed to yudao-module-infra/yudao-module-infra-impl/src/main/resources/file/erweima.jpg
18 KB
yudao-module-infra/yudao-module-infra-impl/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
0 → 100755
| 1 | +package cn.iocoder.yudao.module.infra.service.file; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO; | |
| 5 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO; | |
| 7 | +import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO; | |
| 8 | +import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper; | |
| 9 | +import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest; | |
| 10 | +import org.junit.jupiter.api.Disabled; | |
| 11 | +import org.junit.jupiter.api.Test; | |
| 12 | +import org.springframework.context.annotation.Import; | |
| 13 | + | |
| 14 | +import javax.annotation.Resource; | |
| 15 | + | |
| 16 | +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | |
| 17 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | |
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | |
| 19 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | |
| 20 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 21 | +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS; | |
| 22 | +import static org.junit.jupiter.api.Assertions.*; | |
| 23 | + | |
| 24 | +/** | |
| 25 | +* {@link FileConfigServiceImpl} 的单元测试类 | |
| 26 | +* | |
| 27 | +* @author 芋道源码 | |
| 28 | +*/ | |
| 29 | +@Import(FileConfigServiceImpl.class) | |
| 30 | +public class FileConfigServiceImplTest extends BaseDbUnitTest { | |
| 31 | + | |
| 32 | + @Resource | |
| 33 | + private FileConfigServiceImpl fileConfigService; | |
| 34 | + | |
| 35 | + @Resource | |
| 36 | + private FileConfigMapper fileConfigMapper; | |
| 37 | + | |
| 38 | + @Test | |
| 39 | + public void testCreateFileConfig_success() { | |
| 40 | + // 准备参数 | |
| 41 | + FileConfigCreateReqVO reqVO = randomPojo(FileConfigCreateReqVO.class); | |
| 42 | + | |
| 43 | + // 调用 | |
| 44 | + Long fileConfigId = fileConfigService.createFileConfig(reqVO); | |
| 45 | + // 断言 | |
| 46 | + assertNotNull(fileConfigId); | |
| 47 | + // 校验记录的属性是否正确 | |
| 48 | + FileConfigDO fileConfig = fileConfigMapper.selectById(fileConfigId); | |
| 49 | + assertPojoEquals(reqVO, fileConfig); | |
| 50 | + } | |
| 51 | + | |
| 52 | + @Test | |
| 53 | + public void testUpdateFileConfig_success() { | |
| 54 | + // mock 数据 | |
| 55 | + FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class); | |
| 56 | + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 | |
| 57 | + // 准备参数 | |
| 58 | + FileConfigUpdateReqVO reqVO = randomPojo(FileConfigUpdateReqVO.class, o -> { | |
| 59 | + o.setId(dbFileConfig.getId()); // 设置更新的 ID | |
| 60 | + }); | |
| 61 | + | |
| 62 | + // 调用 | |
| 63 | + fileConfigService.updateFileConfig(reqVO); | |
| 64 | + // 校验是否更新正确 | |
| 65 | + FileConfigDO fileConfig = fileConfigMapper.selectById(reqVO.getId()); // 获取最新的 | |
| 66 | + assertPojoEquals(reqVO, fileConfig); | |
| 67 | + } | |
| 68 | + | |
| 69 | + @Test | |
| 70 | + public void testUpdateFileConfig_notExists() { | |
| 71 | + // 准备参数 | |
| 72 | + FileConfigUpdateReqVO reqVO = randomPojo(FileConfigUpdateReqVO.class); | |
| 73 | + | |
| 74 | + // 调用, 并断言异常 | |
| 75 | + assertServiceException(() -> fileConfigService.updateFileConfig(reqVO), FILE_CONFIG_NOT_EXISTS); | |
| 76 | + } | |
| 77 | + | |
| 78 | + @Test | |
| 79 | + public void testDeleteFileConfig_success() { | |
| 80 | + // mock 数据 | |
| 81 | + FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class); | |
| 82 | + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据 | |
| 83 | + // 准备参数 | |
| 84 | + Long id = dbFileConfig.getId(); | |
| 85 | + | |
| 86 | + // 调用 | |
| 87 | + fileConfigService.deleteFileConfig(id); | |
| 88 | + // 校验数据不存在了 | |
| 89 | + assertNull(fileConfigMapper.selectById(id)); | |
| 90 | + } | |
| 91 | + | |
| 92 | + @Test | |
| 93 | + public void testDeleteFileConfig_notExists() { | |
| 94 | + // 准备参数 | |
| 95 | + Long id = randomLongId(); | |
| 96 | + | |
| 97 | + // 调用, 并断言异常 | |
| 98 | + assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_NOT_EXISTS); | |
| 99 | + } | |
| 100 | + | |
| 101 | + @Test | |
| 102 | + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 | |
| 103 | + public void testGetFileConfigPage() { | |
| 104 | + // mock 数据 | |
| 105 | + FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class, o -> { // 等会查询到 | |
| 106 | + o.setName(null); | |
| 107 | + o.setStorage(null); | |
| 108 | + o.setCreateTime(null); | |
| 109 | + }); | |
| 110 | + fileConfigMapper.insert(dbFileConfig); | |
| 111 | + // 测试 name 不匹配 | |
| 112 | + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName(null))); | |
| 113 | + // 测试 storage 不匹配 | |
| 114 | + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(null))); | |
| 115 | + // 测试 createTime 不匹配 | |
| 116 | + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(null))); | |
| 117 | + // 准备参数 | |
| 118 | + FileConfigPageReqVO reqVO = new FileConfigPageReqVO(); | |
| 119 | + reqVO.setName(null); | |
| 120 | + reqVO.setStorage(null); | |
| 121 | + reqVO.setBeginCreateTime(null); | |
| 122 | + reqVO.setEndCreateTime(null); | |
| 123 | + | |
| 124 | + // 调用 | |
| 125 | + PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(reqVO); | |
| 126 | + // 断言 | |
| 127 | + assertEquals(1, pageResult.getTotal()); | |
| 128 | + assertEquals(1, pageResult.getList().size()); | |
| 129 | + assertPojoEquals(dbFileConfig, pageResult.getList().get(0)); | |
| 130 | + } | |
| 131 | + | |
| 132 | +} | ... | ... |
yudao-module-pay/yudao-module-pay-impl/src/main/java/cn/iocoder/yudao/module/pay/service/merchant/PayChannelServiceImpl.java
| ... | ... | @@ -127,6 +127,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 127 | 127 | PayChannelDO channel = PayChannelConvert.INSTANCE.convert(reqVO); |
| 128 | 128 | settingConfigAndCheckParam(channel, reqVO.getConfig()); |
| 129 | 129 | channelMapper.insert(channel); |
| 130 | + // TODO 芋艿:缺少刷新本地缓存的机制 | |
| 130 | 131 | return channel.getId(); |
| 131 | 132 | } |
| 132 | 133 | |
| ... | ... | @@ -138,6 +139,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 138 | 139 | PayChannelDO channel = PayChannelConvert.INSTANCE.convert(updateReqVO); |
| 139 | 140 | settingConfigAndCheckParam(channel, updateReqVO.getConfig()); |
| 140 | 141 | channelMapper.updateById(channel); |
| 142 | + // TODO 芋艿:缺少刷新本地缓存的机制 | |
| 141 | 143 | } |
| 142 | 144 | |
| 143 | 145 | @Override |
| ... | ... | @@ -146,6 +148,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 146 | 148 | this.validateChannelExists(id); |
| 147 | 149 | // 删除 |
| 148 | 150 | channelMapper.deleteById(id); |
| 151 | + // TODO 芋艿:缺少刷新本地缓存的机制 | |
| 149 | 152 | } |
| 150 | 153 | |
| 151 | 154 | private void validateChannelExists(Long id) { |
| ... | ... | @@ -224,6 +227,7 @@ public class PayChannelServiceImpl implements PayChannelService { |
| 224 | 227 | if (ObjectUtil.isNull(payClass)) { |
| 225 | 228 | throw exception(CHANNEL_NOT_EXISTS); |
| 226 | 229 | } |
| 230 | + // TODO @芋艿:不要使用 hutool 的 json 工具,用项目的 | |
| 227 | 231 | PayClientConfig config = JSONUtil.toBean(configStr, payClass); |
| 228 | 232 | |
| 229 | 233 | // 验证参数 | ... | ... |
yudao-server/src/main/resources/application.yaml