Docker安装minio,搭建自己的oss服务器
docker search minio
docker pull minio/minio
docker run -p 9000:9000 -p 9090:9090 \
--name minio \
-d --restart=always \
-e "MINIO_ACCESS_KEY=minioadmin" \
-e "MINIO_SECRET_KEY=minioadmin" \
-v /mydata/minio/data:/data \
minio/minio server \
/data --console-address ":9090" -address ":9000"
启动后,访问机器ip+9090,进入minio的界面,输入用户名或密码后可以访问。
Docker安装miniomc突破7天限制
docker pull minio/mc
docker run -it --entrypoint=/bin/sh minio/mc
mc config host add <ALIAS> <YOUR-S3-ENDPOINT> <YOUR-ACCESS-KEY> <YOUR-SECRET-KEY> [--api API-SIGNATURE]
mc config host add minio http://117.72.14.166:9000 GrVCPXySKgGoJiGgXmtv 0xlqSI9GXvnBOtp0GwUj5OshKNBk9JgwoexotbVV
mc ls minio
mc anonymous
mc anonymous set download minio/jichi
oss 模块设计
注意:考虑 oss 的扩展性和切换性。
目前对接的 minio,要考虑,如果作为公共的 oss 服务,如何切换到其他的阿里云 oss 或者对接京东云的 oss。作为基础的 oss 服务,切换等等动作,不应该要求业务方进行改造,以及对切换有感知。
oss 模块集成代码
feat:oss文件服务
feat:oos集成后测试
适配器模式实现 oss 代码
适配器模式用于:接口不符
oss配合nacos实现动态切换
nacos 作为配置中心,可以实现动态配置,适用于比如动态数据源切换,动态切换 oss。
详细可以看代码。
feat:集成nacos动态配置
feat:版本调整
feat:nacos实现文件bean动态切换
代码配置
新建 bootstrap 文件
spring:
application:
name: jc-club-oss
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 117.72.14.166:8848
prefix: ${spring.application.name}
group: DEFAULT_GROUP
namespace:
file-extension: yaml
新建配置
详情示例代码编辑删除
代码:
package com.jingdianjichi.oss.entity;
/**
* 文件类
*
*/
public class FileInfo {
private String fileName;
private Boolean directoryFlag;
private String etag;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public Boolean getDirectoryFlag() {
return directoryFlag;
}
public void setDirectoryFlag(Boolean directoryFlag) {
this.directoryFlag = directoryFlag;
}
public String getEtag() {
return etag;
}
public void setEtag(String etag) {
this.etag = etag;
}
}
package com.jingdianjichi.oss.entity;
import lombok.Data;
@Data
public class Result<T> {
private Boolean success;
private Integer code;
private String message;
private T data;
public static Result ok(){
Result result = new Result();
result.setSuccess(true);
result.setCode(ResultCodeEnum.SUCCESS.getCode());
result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
return result;
}
public static <T> Result ok(T data){
Result result = new Result();
result.setSuccess(true);
result.setCode(ResultCodeEnum.SUCCESS.getCode());
result.setMessage(ResultCodeEnum.SUCCESS.getDesc());
result.setData(data);
return result;
}
public static Result fail(){
Result result = new Result();
result.setSuccess(false);
result.setCode(ResultCodeEnum.FAIL.getCode());
result.setMessage(ResultCodeEnum.FAIL.getDesc());
return result;
}
public static <T> Result fail(T data){
Result result = new Result();
result.setSuccess(false);
result.setCode(ResultCodeEnum.FAIL.getCode());
result.setMessage(ResultCodeEnum.FAIL.getDesc());
result.setData(data);
return result;
}
}
package com.jingdianjichi.oss.entity;
import lombok.Getter;
@Getter
public enum ResultCodeEnum {
SUCCESS(200,"成功"),
FAIL(500,"失败");
public int code;
public String desc;
ResultCodeEnum(int code,String desc){
this.code = code;
this.desc = desc;
}
public static ResultCodeEnum getByCode(int codeVal){
for(ResultCodeEnum resultCodeEnum : ResultCodeEnum.values()){
if(resultCodeEnum.code == codeVal){
return resultCodeEnum;
}
}
return null;
}
}
package com.jingdianjichi.oss.adapter;
import com.jingdianjichi.oss.entity.FileInfo;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.List;
/**
* 文件存储适配器
*/
public interface StorageAdapter {
/**
* 创建bucket桶
*/
void createBucket(String bucket);
/**
* 上传文件
*/
void uploadFile(MultipartFile uploadFile, String bucket, String objectName);
/**
* 列出所有桶
*/
List<String> getAllBucket();
/**
* 列出当前桶及文件
*/
List<FileInfo> getAllFile(String bucket);
/**
* 下载文件
*/
InputStream downLoad(String bucket, String objectName);
/**
* 删除桶
*/
void deleteBucket(String bucket);
/**
* 删除文件
*/
void deleteObject(String bucket, String objectName);
String getUrl(String bucket, String objectName);
}
package com.jingdianjichi.oss.adapter;
import com.jingdianjichi.oss.entity.FileInfo;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
/**
* 阿里云oss适配器
*
*/
public class AliStorageAdapter implements StorageAdapter {
@Override
public void createBucket(String bucket) {
}
@Override
public void uploadFile(MultipartFile uploadFile, String bucket, String objectName) {
}
@Override
public List<String> getAllBucket() {
List<String> bucketNameList = new LinkedList<>();
bucketNameList.add("aliyun");
return bucketNameList;
}
@Override
public List<FileInfo> getAllFile(String bucket) {
return null;
}
@Override
public InputStream downLoad(String bucket, String objectName) {
return null;
}
@Override
public void deleteBucket(String bucket) {
}
@Override
public void deleteObject(String bucket, String objectName) {
}
@Override
public String getUrl(String bucket, String objectName) {
return null;
}
}
package com.jingdianjichi.oss.adapter;
import com.jingdianjichi.oss.entity.FileInfo;
import com.jingdianjichi.oss.util.MinioUtil;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.InputStream;
import java.util.List;
/**
* minioIO存储适配器
*
*/
public class MinioStorageAdapter implements StorageAdapter {
@Resource
private MinioUtil minioUtil;
/**
* minioUrl
*/
@Value("${minio.url}")
private String url;
@Override
@SneakyThrows
public void createBucket(String bucket) {
minioUtil.createBucket(bucket);
}
@Override
@SneakyThrows
public void uploadFile(MultipartFile uploadFile, String bucket, String objectName) {
minioUtil.createBucket(bucket);
if (objectName != null) {
minioUtil.uploadFile(uploadFile.getInputStream(), bucket, objectName + "/" + uploadFile.getOriginalFilename());
} else {
minioUtil.uploadFile(uploadFile.getInputStream(), bucket, uploadFile.getOriginalFilename());
}
}
@Override
@SneakyThrows
public List<String> getAllBucket() {
return minioUtil.getAllBucket();
}
@Override
@SneakyThrows
public List<FileInfo> getAllFile(String bucket) {
return minioUtil.getAllFile(bucket);
}
@Override
@SneakyThrows
public InputStream downLoad(String bucket, String objectName) {
return minioUtil.downLoad(bucket, objectName);
}
@Override
@SneakyThrows
public void deleteBucket(String bucket) {
minioUtil.deleteBucket(bucket);
}
@Override
@SneakyThrows
public void deleteObject(String bucket, String objectName) {
minioUtil.deleteObject(bucket, objectName);
}
@Override
@SneakyThrows
public String getUrl(String bucket, String objectName) {
return url + "/" + bucket + "/" + objectName;
}
}
package com.jingdianjichi.oss.config;
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* minio配置管理
*
*/
@Configuration
public class MinioConfig {
/**
* minioUrl
*/
@Value("${minio.url}")
private String url;
/**
* minio账户
*/
@Value("${minio.accessKey}")
private String accessKey;
/**
* minio密码
*/
@Value("${minio.secretKey}")
private String secretKey;
/**
* 构造minioClient
*/
@Bean
public MinioClient getMinioClient() {
return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
}
}
package com.jingdianjichi.oss.config;
import com.jingdianjichi.oss.adapter.StorageAdapter;
import com.jingdianjichi.oss.adapter.AliStorageAdapter;
import com.jingdianjichi.oss.adapter.MinioStorageAdapter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 文件存储config
*
*/
@Configuration
@RefreshScope
public class StorageConfig {
@Value("${storage.service.type}")
private String storageType;
@Bean
@RefreshScope
public StorageAdapter storageService() {
if ("minio".equals(storageType)) {
return new MinioStorageAdapter();
} else if ("aliyun".equals(storageType)) {
return new AliStorageAdapter();
} else {
throw new IllegalArgumentException("未找到对应的文件存储处理器");
}
}
}
package com.jingdianjichi.oss.controller;
import com.jingdianjichi.oss.entity.Result;
import com.jingdianjichi.oss.service.FileService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
/**
* 文件操作controller
*
*/
@RestController
public class FileController {
@Resource
private FileService fileService;
@RequestMapping("/testGetAllBuckets")
public String testGetAllBuckets() throws Exception {
List<String> allBucket = fileService.getAllBucket();
return allBucket.get(0);
}
@RequestMapping("/getUrl")
public String getUrl(String bucketName, String objectName) throws Exception {
return fileService.getUrl(bucketName, objectName);
}
/**
* 上传文件
*/
@RequestMapping("/upload")
public Result upload(MultipartFile uploadFile, String bucket, String objectName) throws Exception {
String url = fileService.uploadFile(uploadFile, bucket, objectName);
return Result.ok(url);
}
}
package com.jingdianjichi.oss.service;
import com.jingdianjichi.oss.adapter.StorageAdapter;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 文件存储service
*
*/
@Service
public class FileService {
private final StorageAdapter storageAdapter;
public FileService(StorageAdapter storageAdapter) {
this.storageAdapter = storageAdapter;
}
/**
* 列出所有桶
*/
public List<String> getAllBucket() {
return storageAdapter.getAllBucket();
}
/**
* 获取文件路径
*/
public String getUrl(String bucketName,String objectName) {
return storageAdapter.getUrl(bucketName,objectName);
}
/**
* 上传文件
*/
public String uploadFile(MultipartFile uploadFile, String bucket, String objectName){
storageAdapter.uploadFile(uploadFile,bucket,objectName);
objectName = objectName + "/" + uploadFile.getOriginalFilename();
return storageAdapter.getUrl(bucket, objectName);
}
}
package com.jingdianjichi.oss;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* oss服务启动器
*
*/
@SpringBootApplication
@ComponentScan("com.jingdianjichi")
public class OssApplication {
public static void main(String[] args) {
SpringApplication.run(OssApplication.class);
}
}
package com.jingdianjichi.oss.util;
import com.jingdianjichi.oss.entity.FileInfo;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
/**
* minio文件操作工具
*
*/
@Component
public class MinioUtil {
@Resource
private MinioClient minioClient;
/**
* 创建bucket桶
*/
public void createBucket(String bucket) throws Exception {
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
}
}
/**
* 上传文件
*/
public void uploadFile(InputStream inputStream, String bucket, String objectName) throws Exception {
minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
.stream(inputStream, -1, 5242889L).build());
}
/**
* 列出所有桶
*/
public List<String> getAllBucket() throws Exception {
List<Bucket> buckets = minioClient.listBuckets();
return buckets.stream().map(Bucket::name).collect(Collectors.toList());
}
/**
* 列出当前桶及文件
*/
public List<FileInfo> getAllFile(String bucket) throws Exception {
Iterable<Result<Item>> results = minioClient.listObjects(
ListObjectsArgs.builder().bucket(bucket).build());
List<FileInfo> fileInfoList = new LinkedList<>();
for (Result<Item> result : results) {
FileInfo fileInfo = new FileInfo();
Item item = result.get();
fileInfo.setFileName(item.objectName());
fileInfo.setDirectoryFlag(item.isDir());
fileInfo.setEtag(item.etag());
fileInfoList.add(fileInfo);
}
return fileInfoList;
}
/**
* 下载文件
*/
public InputStream downLoad(String bucket, String objectName) throws Exception {
return minioClient.getObject(
GetObjectArgs.builder().bucket(bucket).object(objectName).build()
);
}
/**
* 删除桶
*/
public void deleteBucket(String bucket) throws Exception {
minioClient.removeBucket(
RemoveBucketArgs.builder().bucket(bucket).build()
);
}
/**
* 删除文件
*/
public void deleteObject(String bucket, String objectName) throws Exception {
minioClient.removeObject(
RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()
);
}
/**
* 获取文件url
*/
public String getPreviewFileUrl(String bucketName, String objectName) throws Exception{
GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName).object(objectName).build();
return minioClient.getPresignedObjectUrl(args);
}
}
server:
port: 4000
minio:
url: http://192.168.200.177:9000
accessKey: minioadmin
secretKey: minioadmin
spring:
application:
name: jc-club-oss-dev
profiles:
active: dev
cloud:
nacos:
config:
server-addr: 192.168.200.177:8848
prefix: ${spring.application.name}
group: DEFAULT_GROUP
namespace:
file-extension: yaml
discovery:
enabled: true
server-addr: 192.168.200.177:8848