refactor(system/storage): 重构存储管理,新增设置默认存储、修改状态接口

S3 => OSS
This commit is contained in:
2025-03-04 21:29:56 +08:00
parent 98569ae205
commit 37d6efb70e
14 changed files with 209 additions and 74 deletions

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.common.model.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import top.continew.admin.common.enums.DisEnableStatusEnum;
import java.io.Serializable;
/**
* 修改状态请求参数
*
* @author Charles7c
* @since 2025/3/4 20:09
*/
@Data
@Schema(description = "修改状态请求参数")
public class CommonStatusUpdateReq implements Serializable {
/**
* 状态
*/
@Schema(description = "状态", example = "1")
@NotNull(message = "状态非法")
private DisEnableStatusEnum status;
}

View File

@@ -30,15 +30,15 @@ import top.continew.starter.core.enums.BaseEnum;
@RequiredArgsConstructor
public enum StorageTypeEnum implements BaseEnum<Integer> {
/**
* 兼容S3协议存储
*/
S3(1, "兼容S3协议存储"),
/**
* 本地存储
*/
LOCAL(2, "本地存储"),;
LOCAL(1, "本地存储"),
/**
* 对象存储
*/
OSS(2, "对象存储");
private final Integer value;
private final String description;

View File

@@ -54,24 +54,24 @@ public class StorageDO extends BaseDO {
private StorageTypeEnum type;
/**
* Access Key(访问密钥)
* Access Key
*/
@FieldEncrypt
private String accessKey;
/**
* Secret Key(私有密钥)
* Secret Key
*/
@FieldEncrypt
private String secretKey;
/**
* Endpoint(终端节点)
* Endpoint
*/
private String endpoint;
/**
* 桶名称
* Bucket
*/
private String bucketName;

View File

@@ -19,6 +19,7 @@ package top.continew.admin.system.model.query;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.system.enums.StorageTypeEnum;
import top.continew.starter.data.core.annotation.Query;
import top.continew.starter.data.core.enums.QueryType;
@@ -50,4 +51,10 @@ public class StorageQuery implements Serializable {
*/
@Schema(description = "状态", example = "1")
private DisEnableStatusEnum status;
/**
* 类型
*/
@Schema(description = "类型", example = "2")
private StorageTypeEnum type;
}

View File

@@ -16,6 +16,7 @@
package top.continew.admin.system.model.req;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -67,43 +68,45 @@ public class StorageReq implements Serializable {
private StorageTypeEnum type;
/**
* 访问密钥
* Access Key
*/
@Schema(description = "访问密钥", example = "")
@Length(max = 255, message = "访问密钥长度不能超过 {max} 个字符")
@NotBlank(message = "访问密钥不能为空", groups = ValidationGroup.Storage.S3.class)
@Schema(description = "Access Key", example = "")
@Length(max = 255, message = "Access Key长度不能超过 {max} 个字符")
@NotBlank(message = "Access Key不能为空", groups = ValidationGroup.Storage.OSS.class)
private String accessKey;
/**
* 私有密钥
* Secret Key
*/
@Schema(description = "私有密钥", example = "")
@NotBlank(message = "私有密钥不能为空", groups = ValidationGroup.Storage.S3.class)
@Schema(description = "Secret Key", example = "")
@NotBlank(message = "Secret Key不能为空", groups = ValidationGroup.Storage.OSS.class)
private String secretKey;
/**
* 终端节点
* Endpoint
*/
@Schema(description = "终端节点", example = "")
@Length(max = 255, message = "终端节点长度不能超过 {max} 个字符")
@NotBlank(message = "终端节点不能为空", groups = ValidationGroup.Storage.S3.class)
@Schema(description = "Endpoint", example = "")
@Length(max = 255, message = "Endpoint长度不能超过 {max} 个字符")
@NotBlank(message = "Endpoint不能为空", groups = ValidationGroup.Storage.OSS.class)
private String endpoint;
/**
* 桶名称
* Bucket/存储路径
*/
@Schema(description = "桶名称", example = "C:/continew-admin/data/file/")
@Length(max = 255, message = "桶名称长度不能超过 {max} 个字符")
@NotBlank(message = "桶名称不能为空", groups = ValidationGroup.Storage.S3.class)
@Schema(description = "Bucket/存储路径", example = "C:/continew-admin/data/file/")
@Length(max = 255, message = "Bucket长度不能超过 {max} 个字符", groups = ValidationGroup.Storage.OSS.class)
@Length(max = 255, message = "存储路径长度不能超过 {max} 个字符", groups = ValidationGroup.Storage.Local.class)
@NotBlank(message = "Bucket不能为空", groups = ValidationGroup.Storage.OSS.class)
@NotBlank(message = "存储路径不能为空", groups = ValidationGroup.Storage.Local.class)
private String bucketName;
/**
* 域名
* 域名/访问路径
*/
@Schema(description = "域名", example = "http://localhost:8000/file")
@Length(max = 255, message = "域名长度不能超过 {max} 个字符")
@NotBlank(message = "域名不能为空")
@Schema(description = "域名/访问路径", example = "http://localhost:8000/file")
@Length(max = 255, message = "域名长度不能超过 {max} 个字符", groups = ValidationGroup.Storage.OSS.class)
@Length(max = 255, message = "访问路径长度不能超过 {max} 个字符", groups = ValidationGroup.Storage.Local.class)
@NotBlank(message = "访问路径不能为空", groups = ValidationGroup.Storage.Local.class)
private String domain;
/**
@@ -119,16 +122,15 @@ public class StorageReq implements Serializable {
@Length(max = 200, message = "描述长度不能超过 {max} 个字符")
private String description;
/**
* 是否为默认存储
*/
@Schema(description = "是否为默认存储", example = "true")
@NotNull(message = "是否为默认存储不能为空")
private Boolean isDefault;
/**
* 状态
*/
@Schema(description = "状态", example = "1")
private DisEnableStatusEnum status;
/**
* 是否为默认存储
*/
@JsonIgnore
private Boolean isDefault;
}

View File

@@ -63,32 +63,32 @@ public class StorageResp extends BaseDetailResp {
private StorageTypeEnum type;
/**
* 访问密钥
* Access Key
*/
@Schema(description = "访问密钥", example = "")
@Schema(description = "Access Key", example = "")
private String accessKey;
/**
* 私有密钥
* Secret Key
*/
@Schema(description = "私有密钥", example = "")
@Schema(description = "Secret Key", example = "")
@JsonMask(left = 4, right = 3)
private String secretKey;
/**
* 终端节点
* Endpoint
*/
@Schema(description = "终端节点", example = "")
@Schema(description = "Endpoint", example = "")
private String endpoint;
/**
* 桶名称
* Bucket/存储路径
*/
@Schema(description = "桶名称", example = "C:/continew-admin/data/file/")
@Schema(description = "Bucket/存储路径", example = "C:/continew-admin/data/file/")
private String bucketName;
/**
* 域名
* 域名/访问路径
*/
@Schema(description = "域名", example = "http://localhost:8000/file")
private String domain;

View File

@@ -16,6 +16,7 @@
package top.continew.admin.system.service;
import top.continew.admin.common.model.req.CommonStatusUpdateReq;
import top.continew.admin.system.model.entity.StorageDO;
import top.continew.admin.system.model.query.StorageQuery;
import top.continew.admin.system.model.req.StorageReq;
@@ -31,6 +32,21 @@ import top.continew.starter.extension.crud.service.BaseService;
*/
public interface StorageService extends BaseService<StorageResp, StorageResp, StorageQuery, StorageReq>, IService<StorageDO> {
/**
* 修改状态
*
* @param req 状态信息
* @param id ID
*/
void updateStatus(CommonStatusUpdateReq req, Long id);
/**
* 设置默认存储
*
* @param id ID
*/
void setDefault(Long id);
/**
* 查询默认存储
*

View File

@@ -27,7 +27,9 @@ import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.FileStorageServiceBuilder;
import org.dromara.x.file.storage.core.platform.FileStorage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.common.model.req.CommonStatusUpdateReq;
import top.continew.admin.common.util.SecureUtils;
import top.continew.admin.system.enums.StorageTypeEnum;
import top.continew.admin.system.mapper.StorageMapper;
@@ -67,10 +69,13 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
@Override
public void beforeAdd(StorageReq req) {
this.decodeSecretKey(req, null);
CheckUtils.throwIf(Boolean.TRUE.equals(req.getIsDefault()) && this.isDefaultExists(null), "请先取消原有默认存储");
String code = req.getCode();
CheckUtils.throwIf(this.isCodeExists(code, null), "新增失败,[{}] 已存在", code);
this.load(req);
// 单独指定默认存储
req.setIsDefault(false);
if (DisEnableStatusEnum.ENABLE.equals(req.getStatus())) {
this.load(req);
}
}
@Override
@@ -78,16 +83,12 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
StorageDO oldStorage = super.getById(id);
CheckUtils.throwIfNotEqual(req.getCode(), oldStorage.getCode(), "不允许修改存储编码");
CheckUtils.throwIfNotEqual(req.getType(), oldStorage.getType(), "不允许修改存储类型");
this.decodeSecretKey(req, oldStorage);
DisEnableStatusEnum newStatus = req.getStatus();
CheckUtils.throwIf(Boolean.TRUE.equals(oldStorage.getIsDefault()) && DisEnableStatusEnum.DISABLE
.equals(newStatus), "[{}] 是默认存储,不允许禁用", oldStorage.getName());
this.decodeSecretKey(req, oldStorage);
// 重新加载存储引擎
DisEnableStatusEnum oldStatus = oldStorage.getStatus();
if (Boolean.TRUE.equals(req.getIsDefault())) {
CheckUtils.throwIf(this.isDefaultExists(id), "请先取消原有默认存储");
CheckUtils.throwIf(!DisEnableStatusEnum.ENABLE.equals(oldStatus) && !DisEnableStatusEnum.ENABLE
.equals(newStatus), "请先启用该存储");
}
// 先卸载
if (DisEnableStatusEnum.ENABLE.equals(oldStatus)) {
this.unload(BeanUtil.copyProperties(oldStorage, StorageReq.class));
@@ -103,7 +104,7 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
CheckUtils.throwIf(fileService.countByStorageIds(ids) > 0, "所选存储存在文件关联,请删除文件后重试");
List<StorageDO> storageList = baseMapper.lambdaQuery().in(StorageDO::getId, ids).list();
storageList.forEach(s -> {
CheckUtils.throwIfEqual(Boolean.TRUE, s.getIsDefault(), "[{}] 是默认存储,不允许禁用", s.getName());
CheckUtils.throwIfEqual(Boolean.TRUE, s.getIsDefault(), "[{}] 是默认存储,不允许删除", s.getName());
// 卸载启用状态的存储
if (DisEnableStatusEnum.ENABLE.equals(s.getStatus())) {
this.unload(BeanUtil.copyProperties(s, StorageReq.class));
@@ -111,6 +112,43 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
});
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateStatus(CommonStatusUpdateReq req, Long id) {
StorageDO storage = super.getById(id);
// 状态未改变
DisEnableStatusEnum newStatus = req.getStatus();
if (storage.getStatus().equals(newStatus)) {
return;
}
// 修改状态
baseMapper.lambdaUpdate().eq(StorageDO::getId, id).set(StorageDO::getStatus, newStatus).update();
// 加载、卸载存储引擎
StorageReq storageReq = BeanUtil.copyProperties(storage, StorageReq.class);
switch (newStatus) {
case ENABLE:
this.load(storageReq);
break;
case DISABLE:
CheckUtils.throwIfEqual(Boolean.TRUE, storage.getIsDefault(), "[{}] 是默认存储,不允许禁用", storage.getName());
this.unload(storageReq);
break;
default:
break;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void setDefault(Long id) {
StorageDO storage = super.getById(id);
if (Boolean.TRUE.equals(storage.getIsDefault())) {
return;
}
baseMapper.lambdaUpdate().eq(StorageDO::getIsDefault, true).set(StorageDO::getIsDefault, false).update();
baseMapper.lambdaUpdate().eq(StorageDO::getId, id).set(StorageDO::getIsDefault, true).update();
}
@Override
public StorageDO getDefaultStorage() {
return baseMapper.lambdaQuery().eq(StorageDO::getIsDefault, true).one();
@@ -138,8 +176,8 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
fileStorageList.addAll(FileStorageServiceBuilder.buildLocalPlusFileStorage(Collections
.singletonList(config)));
SpringWebUtils.registerResourceHandler(MapUtil.of(URLUtil.url(req.getDomain()).getPath(), bucketName));
} else if (StorageTypeEnum.S3.equals(type)) {
ValidationUtils.validate(req, ValidationGroup.Storage.S3.class);
} else if (StorageTypeEnum.OSS.equals(type)) {
ValidationUtils.validate(req, ValidationGroup.Storage.OSS.class);
FileStorageProperties.AmazonS3Config config = new FileStorageProperties.AmazonS3Config();
config.setPlatform(req.getCode());
config.setAccessKey(req.getAccessKey());
@@ -169,7 +207,7 @@ public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, StorageDO
* @param storage 存储信息
*/
private void decodeSecretKey(StorageReq req, StorageDO storage) {
if (!StorageTypeEnum.S3.equals(req.getType())) {
if (!StorageTypeEnum.OSS.equals(req.getType())) {
return;
}
// 修改时,如果 SecretKey 不修改,需要手动修正

View File

@@ -37,9 +37,9 @@ public interface ValidationGroup extends Default {
}
/**
* 兼容S3协议存储
* 对象存储
*/
interface S3 extends Storage {
interface OSS extends Storage {
}
}
}

View File

@@ -16,9 +16,18 @@
package top.continew.admin.controller.system;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.continew.admin.common.controller.BaseController;
import top.continew.admin.common.model.req.CommonStatusUpdateReq;
import top.continew.admin.system.model.query.StorageQuery;
import top.continew.admin.system.model.req.StorageReq;
import top.continew.admin.system.model.resp.StorageResp;
@@ -33,7 +42,24 @@ import top.continew.starter.extension.crud.enums.Api;
* @since 2023/12/26 22:09
*/
@Tag(name = "存储管理 API")
@Validated
@RestController
@CrudRequestMapping(value = "/system/storage", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
@CrudRequestMapping(value = "/system/storage", api = {Api.LIST, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
public class StorageController extends BaseController<StorageService, StorageResp, StorageResp, StorageQuery, StorageReq> {
@Operation(summary = "修改状态", description = "修改状态")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:storage:updateStatus")
@PutMapping({"/{id}/status"})
public void updateStatus(@Validated @RequestBody CommonStatusUpdateReq req, @PathVariable("id") Long id) {
baseService.updateStatus(req, id);
}
@Operation(summary = "设为默认存储", description = "设为默认存储")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("system:storage:setDefault")
@PutMapping({"/{id}/default"})
public void setDefault(@PathVariable("id") Long id) {
baseService.setDefault(id);
}
}

View File

@@ -77,6 +77,8 @@ VALUES
(1113, '新增', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:add', 3, 1, 1, NOW()),
(1114, '修改', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:update', 4, 1, 1, NOW()),
(1115, '删除', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:delete', 5, 1, 1, NOW()),
(1116, '修改状态', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:updateStatus', 6, 1, 1, NOW()),
(1117, '设为默认存储', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:setDefault', 7, 1, 1, NOW()),
( 1180, '终端管理', 1000, 2, '/system/client', 'SystemClient', 'system/client/index', NULL, 'mobile', b'0', b'0', b'0', NULL, 9, 1, 1, NOW()),
(1181, '列表', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:list', 1, 1, 1, NOW()),
@@ -244,8 +246,8 @@ INSERT INTO `sys_role_dept` (`role_id`, `dept_id`) VALUES (547888897925840927, 5
INSERT INTO `sys_storage`
(`id`, `name`, `code`, `type`, `access_key`, `secret_key`, `endpoint`, `bucket_name`, `domain`, `description`, `is_default`, `sort`, `status`, `create_user`, `create_time`)
VALUES
(1, '开发环境', 'local_dev', 2, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', b'1', 1, 1, 1, NOW()),
(2, '生产环境', 'local_prod', 2, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', b'0', 2, 2, 1, NOW());
(1, '开发环境', 'local_dev', 1, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', b'1', 1, 1, 1, NOW()),
(2, '生产环境', 'local_prod', 1, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', b'0', 2, 2, 1, NOW());
-- 初始化终端数据
INSERT INTO `sys_client`

View File

@@ -256,11 +256,11 @@ CREATE TABLE IF NOT EXISTS `sys_storage` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(100) NOT NULL COMMENT '名称',
`code` varchar(30) NOT NULL COMMENT '编码',
`type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型1兼容S3协议存储2本地存储)',
`access_key` varchar(255) DEFAULT NULL COMMENT 'Access Key(访问密钥)',
`secret_key` varchar(255) DEFAULT NULL COMMENT 'Secret Key(私有密钥)',
`endpoint` varchar(255) DEFAULT NULL COMMENT 'Endpoint(终端节点)',
`bucket_name` varchar(255) DEFAULT NULL COMMENT '桶名称',
`type` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '类型1本地存储2对象存储)',
`access_key` varchar(255) DEFAULT NULL COMMENT 'Access Key',
`secret_key` varchar(255) DEFAULT NULL COMMENT 'Secret Key',
`endpoint` varchar(255) DEFAULT NULL COMMENT 'Endpoint',
`bucket_name` varchar(255) DEFAULT NULL COMMENT 'Bucket',
`domain` varchar(255) NOT NULL DEFAULT '' COMMENT '域名',
`description` varchar(200) DEFAULT NULL COMMENT '描述',
`is_default` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否为默认存储',

View File

@@ -77,6 +77,8 @@ VALUES
(1113, '新增', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:add', 3, 1, 1, NOW()),
(1114, '修改', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:update', 4, 1, 1, NOW()),
(1115, '删除', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:delete', 5, 1, 1, NOW()),
(1116, '修改状态', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:updateStatus', 6, 1, 1, NOW()),
(1117, '设为默认存储', 1110, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:storage:setDefault', 7, 1, 1, NOW()),
( 1180, '终端管理', 1000, 2, '/system/client', 'SystemClient', 'system/client/index', NULL, 'mobile', false, false, false, NULL, 9, 1, 1, NOW()),
(1181, '列表', 1180, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'system:client:list', 1, 1, 1, NOW()),
@@ -244,8 +246,8 @@ INSERT INTO "sys_role_dept" ("role_id", "dept_id") VALUES (547888897925840927, 5
INSERT INTO "sys_storage"
("id", "name", "code", "type", "access_key", "secret_key", "endpoint", "bucket_name", "domain", "description", "is_default", "sort", "status", "create_user", "create_time")
VALUES
(1, '开发环境', 'local_dev', 2, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', true, 1, 1, 1, NOW()),
(2, '生产环境', 'local_prod', 2, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', false, 2, 2, 1, NOW());
(1, '开发环境', 'local_dev', 1, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', true, 1, 1, 1, NOW()),
(2, '生产环境', 'local_prod', 1, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', false, 2, 2, 1, NOW());
-- 初始化终端数据
INSERT INTO "sys_client"

View File

@@ -446,11 +446,11 @@ CREATE INDEX "idx_storage_update_user" ON "sys_storage" ("update_user");
COMMENT ON COLUMN "sys_storage"."id" IS 'ID';
COMMENT ON COLUMN "sys_storage"."name" IS '名称';
COMMENT ON COLUMN "sys_storage"."code" IS '编码';
COMMENT ON COLUMN "sys_storage"."type" IS '类型1兼容S3协议存储2本地存储)';
COMMENT ON COLUMN "sys_storage"."access_key" IS 'Access Key(访问密钥)';
COMMENT ON COLUMN "sys_storage"."secret_key" IS 'Secret Key(私有密钥)';
COMMENT ON COLUMN "sys_storage"."endpoint" IS 'Endpoint(终端节点)';
COMMENT ON COLUMN "sys_storage"."bucket_name" IS '桶名称';
COMMENT ON COLUMN "sys_storage"."type" IS '类型1本地存储2对象存储)';
COMMENT ON COLUMN "sys_storage"."access_key" IS 'Access Key';
COMMENT ON COLUMN "sys_storage"."secret_key" IS 'Secret Key';
COMMENT ON COLUMN "sys_storage"."endpoint" IS 'Endpoint';
COMMENT ON COLUMN "sys_storage"."bucket_name" IS 'Bucket';
COMMENT ON COLUMN "sys_storage"."domain" IS '域名';
COMMENT ON COLUMN "sys_storage"."description" IS '描述';
COMMENT ON COLUMN "sys_storage"."is_default" IS '是否为默认存储';