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

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

项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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中配置好参数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

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()));
}
}
}

2024-09-12-Thu-T-文件处理微服务
http://example.com/2024/09/12/2024-09-12-Thu-T-文件处理微服务/
Author
Fei
Posted on
September 12, 2024
Licensed under