026从零搭建微服务文件服务(二)

2023年 9月 12日 105.6k 0

写在最前

如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。

源码地址(后端):gitee.com/csps/mingyu…

源码地址(前端):gitee.com/csps/mingyu…

文档地址:gitee.com/csps/mingyu…

OSS 基础表设计

1. OSS对象存储表

DROP TABLE IF EXISTS sys_oss;
CREATE TABLE sys_oss (
    oss_id           BIGINT(20)        NOT NULL                   COMMENT 'OSS对象ID',
    file_name        VARCHAR(255)      NOT NULL DEFAULT ''        COMMENT '文件名',
    original_name    VARCHAR(255)      NOT NULL DEFAULT ''        COMMENT '原名',
    file_suffix      VARCHAR(10)       NOT NULL DEFAULT ''        COMMENT '文件后缀名',
    file_url         VARCHAR(500)      NOT NULL                   COMMENT '文件URL',
    create_time      DATETIME          DEFAULT NULL               COMMENT '创建时间',
    create_by        VARCHAR(64)       DEFAULT ''                 COMMENT '上传人',
    update_time      DATETIME          DEFAULT NULl               COMMENT '更新时间',
    update_by        VARCHAR(64)       DEFAULT ''                 COMMENT '更新人',
    service          VARCHAR(20)       NOT NULL DEFAULT 'minio'   COMMENT '服务商',
    primary key (oss_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='OSS对象存储表';

2. OSS对象存储动态配置表

DROP TABLE IF EXISTS sys_oss_config;
CREATE TABLE sys_oss_config (
    oss_config_id     BIGINT(20)         NOT NULL                 COMMENT 'OSS动态配置ID',
    config_key        VARCHAR(20)        NOT NULL DEFAULT ''      COMMENT '配置key',
    access_key        VARCHAR(255)       DEFAULT ''               COMMENT 'accessKey',
    secret_key        VARCHAR(255)       DEFAULT ''               COMMENT '秘钥',
    bucket_name       VARCHAR(255)       DEFAULT ''               COMMENT '桶名称',
    prefix            VARCHAR(255)       DEFAULT ''               COMMENT '前缀',
    endpoint          VARCHAR(255)       DEFAULT ''               COMMENT '访问站点',
    domain            VARCHAR(255)       DEFAULT ''               COMMENT '自定义域名',
    is_https          CHAR(1)            DEFAULT 'N'              COMMENT '是否https(Y是 N否)',
    region            VARCHAR(255)       DEFAULT ''               COMMENT '域',
    access_policy     CHAR(1)            NOT NULL DEFAULT '1'     COMMENT '桶权限类型(0-private 1-public 2-custom)',
    status            CHAR(1)            DEFAULT '1'              COMMENT '是否默认(0是 1否)',
    extend            VARCHAR(255)       DEFAULT ''               COMMENT '扩展字段',
    create_by         VARCHAR(64)        DEFAULT ''               COMMENT '创建者',
    create_time       DATETIME           DEFAULT NULL             COMMENT '创建时间',
    update_by         VARCHAR(64)        DEFAULT ''               COMMENT '更新者',
    update_time       DATETIME           DEFAULT NULL             COMMENT '更新时间',
    PRIMARY KEY (oss_config_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='OSS对象存储动态配置表';
​
INSERT INTO `sys_oss_config` VALUES (1, 'minio', 'd6zVm5AP07uGCqSmsTxe', 'Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0I', 'mingyue', '', 'mingyue-minio:5000', '', 'N', '', '1', '0', '', 'admin', '2023-09-11 17:50:40', 'admin', '2023-09-11 17:50:40');
COMMIT;

OSS 配置加载

初始化OSS配置

@Override
public void init() {
    List list = this.list();
    // 加载 OSS 初始化配置
    for (SysOssConfig config : list) {
        String configKey = config.getConfigKey();
        if ("0".equals(config.getStatus())) {
            RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);
        }
​
        RedisUtils.setCacheMapValue(OssConstant.SYS_OSS_CONFIG, config.getConfigKey(), JSONUtil.toJsonStr(config));
    }
}

OssApplicationRunner

@Slf4j
@Component
@RequiredArgsConstructor
public class OssApplicationRunner implements ApplicationRunner {
​
    private final SysOssConfigService sysOssConfigService;
​
    @Override
    public void run(ApplicationArguments args) {
        sysOssConfigService.init();
        log.info("初始化 OSS 配置成功");
    }
​
}

改进 OssFactory

@Slf4j
public class OssFactory {
​
  private static final Map CLIENT_CACHE = new ConcurrentHashMap();
​
  /**
   * 获取默认实例
   */
  public static OssClient instance() {
    // 获取redis 默认类型
    String configKey = RedisUtils.getCacheObject(OssConstant.DEFAULT_CONFIG_KEY);
    if (StrUtil.isEmpty(configKey)) {
      throw new OssException("文件存储服务类型无法找到!");
    }
    return instance(configKey);
  }
​
  /**
   * 根据类型获取实例
   */
  public static OssClient instance(String configKey) {
    String json = RedisUtils.getCacheMapValue(OssConstant.SYS_OSS_CONFIG, configKey);
    if (json == null) {
      throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
    }
    OssProperties properties = JSONUtil.toBean(json, OssProperties.class);
    OssClient client = CLIENT_CACHE.get(configKey);
    if (client == null) {
      CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));
      log.info("创建OSS实例 key => {}", configKey);
      return CLIENT_CACHE.get(configKey);
    }
    // 配置不相同则重新构建
    if (!client.checkPropertiesSame(properties)) {
      CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));
      log.info("重载OSS实例 key => {}", configKey);
      return CLIENT_CACHE.get(configKey);
    }
    return client;
  }
​
}

移除 Nacos OSS 配置

因为从数据库加载配置,所以不在需要 Nacos 配置了

oss:
  configKey: minio
  endpoint: mingyue-minio:5000
  domain:
  prefix:
  accessKey: d6zVm5AP07uGCqSmsTxe
  secretKey: Vsm6qQDHgGchukEpyEoeX3dTe7fic60nTi8D9a0I
  bucketName: mingyue
  region: 
  isHttps: N
  accessPolicy: 1

上传测试

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "ossId": "1701490497677180930",
    "fileName": "2023-09-12/d1b5389a465f4bf7985844916d785c06.png",
    "originalName": "head_1.png",
    "fileSuffix": ".png",
    "fileUrl": "http://mingyue-minio:5000/mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png",
    "createTime": "2023-09-12 14:58:41",
    "createBy": "mingyue",
    "service": "minio"
  }
}

OSS 上传信息保存

/**
 * 构建上传文件返回信息
 * @param originalFilename 原始文件名
 * @param suffix 文件后缀
 * @param configKey 配置key
 * @param uploadResult OSS服务返回结果
 * @return
 */
private SysOssVo buildResult(String originalFilename, String suffix, String configKey, UploadResult uploadResult) {
  SysOss oss = new SysOss();
  oss.setFileUrl(uploadResult.getFileUrl());
  oss.setFileSuffix(suffix);
  oss.setFileName(uploadResult.getFileName());
  oss.setOriginalName(originalFilename);
  oss.setService(configKey);
  this.save(oss);
​
  SysOssVo sysOssVo = BeanUtil.toBean(oss, SysOssVo.class);
  return this.matchingUrl(sysOssVo);
}

删除文件

逻辑实现

删除数据库记录的同时需要删除OSS服务对应的文件

@Override
public Boolean deleteByOssIds(List ossIds) {
  List list = this.listByIds(ossIds);
  if (CollUtil.isEmpty(list)) {
    return Boolean.FALSE;
  }
​
  for (SysOss sysOss : list) {
    OssClient storage = OssFactory.instance(sysOss.getService());
    storage.delete(sysOss.getFileUrl());
  }
​
  return this.removeBatchByIds(ossIds);
}

删除接口

@DeleteMapping("/{ossIds}")
@Operation(summary = "删除OSS对象存储",
    parameters = { @Parameter(name = "ossIds", description = "oss对象Ids", required = true) })
public R remove(@NotEmpty(message = "主键不能为空") @PathVariable List ossIds) {
  return R.ok(sysOssService.deleteByOssIds(ossIds));
}

删除测试

删除前打开文件查看:http://mingyue-minio:5000/mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png

curl -X 'DELETE' 
  'http://mingyue-gateway:9100/oss/sysOss/1701490497677180930' 
  -H 'accept: */*' 
  -H 'Authorization: 6H1mlA91zFRa5yEpIl2b2mnCjbG5B44f'

删除后再打开


    NoSuchKey
    The specified key does not exist.
    2023-09-12/d1b5389a465f4bf7985844916d785c06.png
    mingyue
    /mingyue/2023-09-12/d1b5389a465f4bf7985844916d785c06.png
    17841B7B6B41C214
    dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8

下载文件

逻辑实现

@Override
public void download(Long ossId, HttpServletResponse response) throws IOException {
  SysOss sysOss = this.getById(ossId);
  if (ObjectUtil.isNull(sysOss)) {
    throw new ServiceException("文件数据不存在!");
  }
  FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
  response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; ");
  OssClient storage = OssFactory.instance(sysOss.getService());
​
  try (InputStream inputStream = storage.getObjectContent(sysOss.getFileUrl())) {
    int available = inputStream.available();
    IoUtil.copy(inputStream, response.getOutputStream(), available);
    response.setContentLength(available);
  }
  catch (Exception e) {
    throw new ServiceException(e.getMessage());
  }
}

下载接口

@GetMapping("/download/{ossId}")
@Operation(summary = "下载OSS对象存储",
    parameters = { @Parameter(in = ParameterIn.PATH, name = "ossIds", description = "oss对象Ids", required = true) })
public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
  sysOssService.download(ossId, response);
}

下载测试

curl -X 'GET' 
  'http://mingyue-gateway:9100/oss/sysOss/download/1701492631160229889' 
  -H 'accept: */*'

image-20230912190918686

小结

文件服务基础已经完成啦,接下来可以自己尝试集成其他厂商的 OSS 服务。

文件服务更新暂告一段落,接下来弄一弄搜索服务,打算用 ES(Elasticsearch)作为搜索服务基础工具,期待一下吧~~

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论