2024-09-12-Thu-T-文件处理微服务

今天哥们又接到一个文件处理的开发需求,要实现一个文件上传、下载的通用服务。为了快速满足这一需求,我使用了SpringBoot + 华为云OBS快速写了一个小小的程序。

项目结构如下:

src
└── main
    ├── java
    │   └── com
    │       └── xmbc
    │           └── file
    │               ├── XmbcFileApplication.java # 启动类
    │               ├── config
    │               │   ├── HuaweiObsConfig.java # 华为云OBS的配置 (1)
    │               │   └── ResourcesConfig.java  
    │               ├── controller 
    │               │   ├── HuaweiObsFileController.java # 文件上传下载的Controller (4)
    │               │   └── SysFileController.java
    │               ├── service
    │               │   ├── ISysFileService.java # 文件处理的接口 (2)
    │               │   └── impl
    │               │       ├── FastDfsSysFileServiceImpl.java
    │               │       ├── HuaweiObsSysFileServiceImpl.java # 华为云OBS的实现 (3)
    │               │       └── LocalSysFileServiceImpl.java
    │               └── utils
    │                   └── FileUploadUtils.java
    └── resources
        ├── application-dev.yaml  # 若依的框架原配置,没啥用,当个备份吧
        ├── application-local.yaml # 本地配置
        ├── banner.txt # 默认的logo
        ├── bootstrap.yaml # 启动类
        └── logback.xml # 日志配置
12 directories, 15 files

好吧,大佬一看就知道这是使用了某个开源的框架,本文使用了若依的框架(对应ruoyi-file)。因为本文作者是个程序菜鸟,为了快速满足开发组长的需求,所以使用起来比较粗糙。

首先,看看我做了什么好事。在bootstrap.yamlapplication-local.yaml中配置好参数,如下:

# bootstrap.yaml
spring:
  profiles:
    active: local

# application-local.yaml

server:
  port: 9300
spring:
  profiles:
    activate:
      on-profile: local
  application:
    name: xmbc-file
  cloud:
    nacos:
      discovery:
        enabled: false # 禁用nacos
obs:
  huawei:
    bucketName: test-xcmg-app-fileprocessing # 华为云OBS的bucket名称
    endPoint: https://obs.cn-east-3.myhuaweicloud.com # 华为云OBS的endpoint

file: # 先随便乱写的,为了保证config可以读取,这里随便写一个。后续有需要再修改
  path: "/" 
  prefix: "xmbc_file" 
  domain: "local.xmbc.com"

启动配置完成之后,我们就根据我上文的目录结构后注释的编号来看看对应的代码:

(1) HuaweiObsConfig.java

package com.xmbc.file.config;

import com.obs.services.ObsClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Minio 配置信息
 *
 * @author xmbc
 */
@Configuration
@ConfigurationProperties(prefix = "obs")
@Data
public class HuaweiObsConfig
{
    /**
     * endpoint填写桶所在的endpoint
     */

    @Value("${obs.huawei.endPoint}")
    String endPoint;



    /**
     * 华为云Access Key
     */
    private String accessKey = System.getenv("HUAWEICLOUD_SDK_AK"); 

    /**
     * 华为云Secret Key
     */
    private String secretKey = System.getenv("HUAWEICLOUD_SDK_SK");

    /**
     * 存储桶名称
     */
    @Value("${obs.huawei.bucketName}")
    private String bucketName;


    /**
     * 创建ObsClient实例
     * 使用永久AK/SK初始化客户端
     */
    @Bean
    public ObsClient getHuaweiObsClient()
    {
        return new ObsClient(accessKey, secretKey,endPoint);
    }
}

(2) ISysFileService.java

package com.xmbc.file.service;

import org.springframework.core.io.InputStreamResource;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件接口
 * 
 * @author xmbc
 */
public interface ISysFileService
{
    /**
     * 文件上传接口
     * 
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    public String uploadFile(MultipartFile file) throws Exception;

    /**
     * 文件下载接口
     *
     * @param fileName 下载的文件
     * @return 访问地址
     * @throws Exception
     */
    public InputStreamResource downloadFile(String fileName) throws Exception;
}

(3) HuaweiObsSysFileServiceImpl.java

package com.xmbc.file.service.impl;

import com.alibaba.nacos.common.utils.IoUtils;
import com.obs.services.ObsClient;
import com.obs.services.model.PutObjectRequest;
import com.obs.services.model.PutObjectResult;
import com.xmbc.file.config.HuaweiObsConfig;
import com.xmbc.file.service.ISysFileService;
import com.xmbc.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;

/**
 *文件存储
 *
 * @author xmbc
 */
@Service(value = "huaweiObsSysFileService")
public class HuaweiObsSysFileServiceImpl implements ISysFileService
{
    @Autowired
    private HuaweiObsConfig huaweiObsConfig;


    @Autowired
    private ObsClient huaweiObsClient;

    /**
     * Minio文件上传接口
     *
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    @Override
    public String uploadFile(MultipartFile file) throws Exception
    {
        String fileName = FileUploadUtils.extractFilename(file);
        InputStream inputStream = file.getInputStream();
        PutObjectRequest request = new PutObjectRequest();
        request.setBucketName(huaweiObsConfig.getBucketName());
        request.setObjectKey(fileName);
        request.setInput(inputStream);
        PutObjectResult putObjectResult = huaweiObsClient.putObject(request);
        IoUtils.closeQuietly(inputStream);

        return putObjectResult.getObjectUrl();
    }

    @Override
    public InputStreamResource downloadFile(String fileName) throws Exception {

        return new InputStreamResource(huaweiObsClient.getObject(huaweiObsConfig.getBucketName(), fileName).getObjectContent());
    }
}

(4) HuaweiObsController.java


package com.xmbc.file.controller;

import com.xmbc.common.core.domain.R;
import com.xmbc.common.core.utils.file.FileUtils;
import com.xmbc.file.service.ISysFileService;
import com.xmbc.system.api.domain.SysFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Optional;

/**
 * 文件请求处理
 * 
 * @author xmbc
 */
@RestController
public class HuaweiObsFileController {
    private static final Logger log = LoggerFactory.getLogger(HuaweiObsFileController.class);

    @Autowired
    @Qualifier("huaweiObsSysFileService")
    private ISysFileService huaweiObsSysFileService;
    /**
     * 上传对象文件
     * @param multipartFile
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/uploadObject", method = {RequestMethod.POST, RequestMethod.PUT} , produces = MediaType.APPLICATION_JSON_VALUE)
    public R<SysFile> uploadObject(@RequestParam("file") MultipartFile multipartFile) throws Exception {

        try
        {
            // 上传并返回访问地址
            String url = huaweiObsSysFileService.uploadFile(multipartFile);
            SysFile sysFile = new SysFile();
            sysFile.setName(FileUtils.getName(url));
            sysFile.setUrl(url);
            return R.ok(sysFile);
        }
        catch (Exception e)
        {
            log.error("上传文件失败", e);
            return R.fail("上传文件失败: " + e.getMessage());
        }
    }


    /**
     * 下载对象文件
     * @param fileName 文件名
     * @return 文件对象
     * @throws IOException
     */
    @RequestMapping(value = "/downloadObject", method = {RequestMethod.GET} , produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity downloadObject(@RequestParam("fileName") String fileName, @RequestParam(value = "openStyle",required = false) String openStyle) throws Exception {
        try
        {
            openStyle= "inline".equals(openStyle)?"inline":"attachment";
            HttpHeaders headers = new HttpHeaders();
            InputStreamResource inputStreamResource = huaweiObsSysFileService.downloadFile(fileName);
            headers.add(HttpHeaders.CONTENT_DISPOSITION, openStyle + "; filename=" + fileName.substring(fileName.lastIndexOf('/')+1));
            return ResponseEntity.ok()
                    .headers(headers)
                    .body(inputStreamResource);
        }
        catch (Exception e)
        {
            log.error("下载文件失败", e);
            return ResponseEntity.of(Optional.of(e.getMessage()));
        }
    }
}
posted @ 2025-11-23 21:18  飞↑  阅读(3)  评论(0)    收藏  举报