SpringBoot整合阿里云、腾讯云、minio、百度云、华为云、天翼云、金山云、七牛云、移动云、网易数帆等等有关于S3协议下文分布式对象存储接口

前提:在可运行的SpringBoot的项目内引用以下JAR包

 整个工具的代码都在Gitee或者Github地址内

gitee:solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb

github:GitHub - ZeroNing/solomon-parent: 这个项目主要是总结了工作上遇到的问题以及学习一些框架用于整合例如:rabbitMq、reids、Mqtt、S3协议的文件服务器、mongodb

需要引入的JAR包(版本根据自身要求使用,本教程用的版本均为最新)

 <dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-java-sdk-s3</artifactId>
    </dependency>

    <dependency>
      <groupId>com.baidubce</groupId>
      <artifactId>bce-java-sdk</artifactId>
      <exclusions>
        <exclusion>
          <artifactId>jdk.tools</artifactId>
          <groupId>jdk.tools</groupId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>com.qcloud</groupId>
      <artifactId>cos_api</artifactId>
    </dependency>

    <dependency>
      <groupId>com.huaweicloud</groupId>
      <artifactId>esdk-obs-java-bundle</artifactId>
    </dependency>

    <dependency>
      <groupId>com.aliyun.oss</groupId>
      <artifactId>aliyun-sdk-oss</artifactId>
    </dependency>

    <dependency>
      <groupId>net.coobird</groupId>
      <artifactId>thumbnailator</artifactId>
    </dependency>

    <dependency>
      <groupId>io.minio</groupId>
      <artifactId>minio</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>

    <!--解析图片exif 开始-->
    <dependency>
      <groupId>com.drewnoakes</groupId>
      <artifactId>metadata-extractor</artifactId>
    </dependency>

    <dependency>
      <groupId>com.adobe.xmp</groupId>
      <artifactId>xmpcore</artifactId>
    </dependency>
    <!--解析图片exif 结束-->
  </dependencies>

写相对应的对象存储接口

public interface FileServiceInterface {

  /**
   * 上传
   * @param file 文件
   * @param bucketName 桶名
   * @param isUseOriginalName 是否使用原名,不使用原名则使用配置的文件名生成器生成
   * @return
   * @throws Exception
   */
  FileUpload upload(MultipartFile file,String bucketName,boolean isUseOriginalName) throws Exception;

  /**
   * 上传(默认使用文件名生成器生成)
   * @param file 文件
   * @param bucketName 桶名
   * @return
   * @throws Exception
   */
  FileUpload upload(MultipartFile file,String bucketName) throws Exception;

  /**
   * 上传
   * @param is 文件输入流
   * @param bucketName 桶名
   * @param fileName   文件名
   * @param isUseOriginalName 是否使用原名,不使用原名则使用配置的文件名生成器生成
   * @return
   * @throws Exception
   */
  FileUpload upload(InputStream is,String bucketName,String fileName,boolean isUseOriginalName) throws Exception;

  /**
   * 上传(默认使用文件名生成器生成)
   * @param is 文件输入流
   * @param bucketName 桶名
   * @param fileName   文件名
   * @return
   * @throws Exception
   */
  FileUpload upload(InputStream is,String bucketName,String fileName) throws Exception;

  /**
   * 上传(默认使用文件名生成器生成)
   * @param bucketName 桶名
   * @param bi         缓冲区图像类
   * @param fileName   文件名
   * @return
   * @throws Exception
   */
  FileUpload upload(String bucketName, BufferedImage bi, String fileName) throws Exception;

  /**
   * 删除文件
   */
  void deleteFile(String fileName,String bucketName) throws Exception;

  /**
   * 分享
   */
  String share(String fileName,String bucketName,long expiry, TimeUnit unit) throws Exception;

  /**
   * 下载
   */
  InputStream download(String fileName,String bucketName) throws Exception;

  /**
   * 检查桶是否存在
   */
  boolean bucketExists(String bucketName) throws Exception;

  /**
   * 创建桶
   */
  void makeBucket(String bucketName) throws Exception;

  /**
   * 检查桶内文件是否存在
   * @param bucketName 桶名
   * @param objectName 文件名
   * @return
   * @throws Exception
   */
  boolean objectExist(String bucketName,String objectName) throws Exception;

  /**
   * 拷贝文件
   * @param sourceBucket 原桶名
   * @param targetBucket 目标桶名
   * @param sourceObjectName 原文件名
   * @param targetObjectName 目标文件名
   * @return
   * @throws Exception
   */
  boolean copyObject(String sourceBucket,String targetBucket,String sourceObjectName,String targetObjectName) throws Exception;

  /**
   * 生成缩略图
   * @param bucketName 桶名
   * @param objectName 文件名
   * @param filePath   存放路径(允许为空,为空则直接放入桶名下的目录,如果配置有根目录,则存放根目录)
   * @param isUpload   是否上传
   * @param width      宽
   * @param height     高
   */
  InputStream generateThumbnail(String bucketName,String objectName,String filePath,boolean isUpload,int width,int height) throws Exception;
  /**
   * 获取文件MD5
   */
  default String getMd5(MultipartFile file) throws IOException {
    return Md5Utils.getFileMd5Code(file);
  }

  default String getFilePath(String fileName, FileChoiceProperties properties){
    return ValidateUtils.isEmpty(properties.getRootDirectory()) ? fileName : properties.getRootDirectory() + fileName;
  }
}

然后就是继承该接口,并将大部分重复代码抽出来,让每个实现类只关注自己的上传下载

public abstract class AbstractFileService implements FileServiceInterface{

  private static Logger logger = LoggerUtils.logger(AbstractFileService.class);

  @Autowired
  protected FileNamingRulesGenerationService fileNamingRulesGenerationService;

  protected FileChoiceProperties properties;

  public AbstractFileService(FileChoiceProperties properties){
    this.properties = properties;
  }

  @Override
  public FileUpload upload(InputStream is, String bucketName,String fileName) throws Exception {
    return upload(is,bucketName,fileName,false);
  }

  @Override
  public FileUpload upload(InputStream is, String bucketName,String fileName,boolean isUseOriginalName) throws Exception {
    return upload(new MockMultipartFile(fileName,fileName, MediaType.MULTIPART_FORM_DATA_VALUE, is),bucketName,false);
  }

  @Override
  public FileUpload upload(MultipartFile file, String bucketName) throws Exception {
    return upload(file,bucketName,false);
  }

  @Override
  public FileUpload upload(MultipartFile file,String bucketName,boolean isUseOriginalName) throws Exception{
    //创建桶
    makeBucket(bucketName);
    String       filePath = getFilePath(!isUseOriginalName? fileNamingRulesGenerationService.getFileName(file): file.getName(),properties);
    this.upload(file,bucketName,filePath);
    return new FileUpload(bucketName,filePath,file.getInputStream());
  }

  @Override
  public FileUpload upload(String bucketName, BufferedImage bi, String fileName) throws Exception {
    //创建桶
    makeBucket(bucketName);

    String       filePath = getFilePath(fileName,properties);

    ByteArrayOutputStream bs    = new ByteArrayOutputStream();
    ImageOutputStream     imOut = ImageIO.createImageOutputStream(bs);
    ImageIO.write(bi, "jpg", imOut);

    InputStream inputStream = new ByteArrayInputStream(bs.toByteArray());
    MockMultipartFile file =  new MockMultipartFile(fileName,inputStream);

    this.upload(file,bucketName,filePath);
    return new FileUpload(bucketName,filePath,new ByteArrayInputStream(bs.toByteArray()));
  }

  @Override
  public void deleteFile(String fileName, String bucketName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if (!flag || ValidateUtils.isEmpty(fileName)) {
      return;
    }
    delete(bucketName,getFilePath(fileName,properties));
  }

  @Override
  public String share(String fileName, String bucketName, long expiry, TimeUnit unit) throws Exception {
    return shareUrl(bucketName,getFilePath(fileName,properties),expiry,unit);
  }

  @Override
  public InputStream download(String fileName, String bucketName) throws Exception {
    return getObject(bucketName,getFilePath(fileName,properties));
  }

  @Override
  public void makeBucket(String bucketName) throws Exception {
    boolean flag = bucketExists(bucketName);
    if(flag){
      return;
    }
    this.createBucket(bucketName);
  }

  @Override
  public boolean copyObject(String sourceBucket,String targetBucket,String sourceObjectName,String targetObjectName) throws Exception{
    if(!objectExist(sourceBucket,sourceObjectName)){
      throw new BaseException(BaseExceptionCode.FILE_IS_NOT_EXIST_EXCEPTION_CODE);
    }
    copyFile(sourceBucket,getFilePath(sourceObjectName,properties),targetBucket,getFilePath(targetObjectName,properties));
    return true;
  }

  @Override
  public boolean objectExist(String bucketName,String objectName) throws Exception{
    try {
      return checkObjectExist(bucketName,getFilePath(objectName,properties));
    } catch (Throwable e){
      logger.error("检查文件出现异常",e);
      return false;
    }
  }

  @Override
  public InputStream generateThumbnail(String bucketName,String objectName,String filePath,boolean isUpload,int width,int height)throws Exception{
    makeBucket(bucketName);
    String extensionName = fileNamingRulesGenerationService.getExtensionName(objectName);
    objectName = objectName.substring(0,objectName.indexOf("."+extensionName));
    String thumbnailName = new StringBuilder(ValidateUtils.isEmpty(filePath) ? "":filePath).append(objectName).append("_").append(width).append("_").append(height).append(".").append(extensionName).toString();
    if(!objectExist(bucketName,thumbnailName)){
      MockMultipartFile file = null;
      try(ByteArrayOutputStream baos = new ByteArrayOutputStream()){
        ImgUtil.scale(getObject(bucketName,objectName+"."+extensionName), baos, width, height, Color.decode("0xFFFFFF"));
        try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) {
          bais.reset();
          if(isUpload){
            try(InputStream is = new ByteArrayInputStream(bais.readAllBytes());){
              file = new MockMultipartFile(thumbnailName,thumbnailName, MediaType.MULTIPART_FORM_DATA_VALUE, is);
              upload(file,bucketName,true);
            }
          }
        }
      }
      return file.getInputStream();
    } else {
      return getObject(bucketName,getFilePath(thumbnailName,properties));
    }
  }

  protected abstract void upload(MultipartFile file, String bucketName,String filePath) throws Exception;

  protected abstract void delete(String bucketName,String filePath) throws Exception;

  protected abstract String shareUrl(String bucketName,String filePath,long expiry, TimeUnit unit) throws Exception;

  protected abstract InputStream getObject(String bucketName,String filePath) throws Exception;

  protected abstract void createBucket(String bucketName) throws Exception;

  protected abstract boolean checkObjectExist(String bucketName,String objectName) throws Exception;

  protected abstract boolean copyFile(String sourceBucket,String targetBucket,String sourceObjectName,String targetObjectName) throws Exception;
}

 在上述代码中出现了FileNamingRulesGenerationService 是一个文件命名规格接口,可以根据配置文件,进行不同的命名方式,这一部分的代码先放到后面再说,现在主要是几种S3协议的通用整合。

以下是BOS(百度云)整合

/**
 * 百度云文件实现类
 */
public class BOSService extends AbstractFileService {

  private BosClient client;

  private BosClient client() {
    BosClientConfiguration config = new BosClientConfiguration();
    config.setCredentials(new DefaultBceCredentials(properties.getAccessKey(), properties.getSecretKey()));
    config.setEndpoint(properties.getEndpoint());
    return new BosClient(config);
  }

  public BOSService(FileChoiceProperties properties) {
    super(properties);
    this.client = client();
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.doesBucketExist(bucketName);
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception  {
    client.putObject(new PutObjectRequest(bucketName,filePath,file.getInputStream()));
    client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception  {
    client.deleteObject(bucketName, filePath);
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception  {
    return client.generatePresignedUrl(bucketName,filePath,new Date(System.currentTimeMillis()+unit.toMillis(expiry)).getSeconds()).toString();
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception  {
    return client.getObject(bucketName, filePath).getObjectContent();
  }

  @Override
  protected void createBucket(String bucketName) throws Exception  {
    client.createBucket(bucketName);
  }

  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    BosObject response = client.getObject(bucketName,objectName);
    if(ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.getKey())){
      return false;
    } else {
      return true;
    }
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(sourceBucket,sourceObjectName,targetBucket,targetObjectName);
    return true;
  }
}

以下是COS(腾讯云)

/**
 * 腾讯云文件实现类
 */
public class COSService extends AbstractFileService {

  private COSClient client;

  public COSService(FileChoiceProperties properties) {
    super(properties);
    this.client = initClient(properties);
  }

  private static COSClient initClient(FileChoiceProperties properties){
    COSCredentials credentials  = new BasicCOSCredentials(properties.getAccessKey(), properties.getSecretKey());
    Region         region       = new Region(properties.getRegionName());
    ClientConfig   clientConfig = new ClientConfig(region);
    return new COSClient(credentials, clientConfig);
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.doesBucketExist(bucketName);
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception  {
    client.putObject(new PutObjectRequest(bucketName,filePath,file.getInputStream(),null));
    client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception  {
    client.deleteObject(bucketName, filePath);
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception  {
    return client.generatePresignedUrl(bucketName,filePath,new Date(System.currentTimeMillis()+unit.toMillis(expiry))).toString();
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception  {
    return client.getObject(bucketName, filePath).getObjectContent();
  }

  @Override
  protected void createBucket(String bucketName) throws Exception  {
    client.createBucket(bucketName);
  }

  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    COSObject response = client.getObject(bucketName,objectName);
    if(ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.getKey())){
      return false;
    } else {
      return true;
    }
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(sourceBucket,sourceObjectName,targetBucket,targetObjectName);
    return true;
  }
}

以下是KODO(七牛云)

/**
 * 七牛云文件实现类
 */
public class KODOService extends S3Service {

  public KODOService(FileChoiceProperties properties) {
    super(properties);
    AWSCredentials        credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
    AmazonS3ClientBuilder builder     = AmazonS3ClientBuilder.standard();
    builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
    if(ValidateUtils.isNotEmpty(properties.getEndpoint()) && ValidateUtils.isNotEmpty(properties.getRegionName())){
      builder.withEndpointConfiguration(new EndpointConfiguration(properties.getEndpoint(),properties.getRegionName()));
    }
    ClientConfiguration awsClientConfig = new ClientConfiguration();
    boolean             isHttps         = properties.getEndpoint().contains("https");
    awsClientConfig.setProtocol(isHttps ? Protocol.HTTPS : Protocol.HTTP);
    builder.setClientConfiguration(awsClientConfig);
    client = builder.build();
  }

}

以下是Minio

/**
 * Minio文件实现类
 */
public class MinioService extends AbstractFileService {

  public MinioClient client;

  public MinioService(FileChoiceProperties mioProperties) {
    super(mioProperties);
    client = MinioClient.builder().credentials(mioProperties.getAccessKey(), mioProperties.getSecretKey()).endpoint(mioProperties.getEndpoint()).build();
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception {
    client.putObject(
        PutObjectArgs.builder().bucket(bucketName).object(filePath).stream(
            file.getInputStream(), file.getSize(), -1)
            .contentType(FileTypeUtils.getFileType(file.getInputStream(),file.getName()))
            .build());
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception {
    client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(filePath).build());
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception {
    Builder builder = GetPresignedObjectUrlArgs.builder().bucket(bucketName);
    if(expiry >= Integer.MAX_VALUE){
      throw new BaseException(FileErrorCode.MORE_THAN_THE_SHARING_TIME);
    }
    return client.getPresignedObjectUrl(builder.expiry((int)expiry,unit).object(filePath).method(Method.GET).build());
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception {
    StatObjectResponse statObject =client.statObject(StatObjectArgs.builder().bucket(bucketName).object(filePath).build());
    if (statObject != null && statObject.size() > 0) {
      return client.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build());
    } else {
      return null;
    }
  }

  @Override
  protected void createBucket(String bucketName) throws Exception {
    client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
  }

  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    GetObjectResponse response = client.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    if(ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.object())){
      return false;
    } else {
      return true;
    }
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(CopyObjectArgs.builder().source(CopySource.builder().bucket(sourceBucket).object(sourceObjectName).build()).bucket(targetBucket).object(targetObjectName).build());
    return true;
  }

}

以下是OBS(华为云)

/**
 * 华为云文件实现类
 */
public class OBSService extends AbstractFileService {

  private ObsClient client;

  public OBSService(FileChoiceProperties properties) {
    super(properties);
    this.client = client();
  }

  private ObsClient client() {
    return new ObsClient(properties.getAccessKey(), properties.getSecretKey(), properties.getEndpoint());
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.headBucket(bucketName);
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception  {
    client.putObject(bucketName, filePath, file.getInputStream());
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception  {
    client.deleteObject(bucketName, filePath);
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception  {
    TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, unit.toSeconds(expiry));
    request.setBucketName(bucketName);
    request.setObjectKey(filePath);
    TemporarySignatureResponse response = client.createTemporarySignature(request);
    return response.getSignedUrl();
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception {
    return client.getObject(bucketName, filePath).getObjectContent();
  }

  @Override
  protected void createBucket(String bucketName) throws Exception  {
    client.createBucket(bucketName);
  }

  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    ObsObject response = client.getObject(bucketName,objectName);
    if(ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.getObjectKey())){
      return false;
    } else {
      return true;
    }
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(sourceBucket,sourceObjectName,targetBucket,targetObjectName);
    return true;
  }
}

以下是OSS(阿里云)

/**
 * 阿里云文件实现类
 */
public class OSSService extends AbstractFileService {

  private OSS client;

  public OSSService(FileChoiceProperties properties) {
    super(properties);
    this.client     = client();
  }

  public OSS client() {
    return new OSSClientBuilder().build(properties.getEndpoint(), properties.getAccessKey(), properties.getSecretKey());
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.doesBucketExist(bucketName);
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception {
    client.putObject(new PutObjectRequest(bucketName, filePath, file.getInputStream()));
    client.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception {
    client.deleteObject(bucketName, filePath);
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception {
    return client.generatePresignedUrl(bucketName, filePath, new Date(System.currentTimeMillis() + unit.toMillis(expiry)))
        .toString();
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception {
    return client.getObject(bucketName, filePath).getObjectContent();
  }

  @Override
  protected void createBucket(String bucketName) throws Exception {
    client.createBucket(bucketName);
  }
  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    OSSObject response = client.getObject(bucketName,objectName);
    if(ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.getKey())){
      return false;
    } else {
      return true;
    }
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(sourceBucket,sourceObjectName,targetBucket,targetObjectName);
    return true;
  }
}

基于S3协议的文件上传下载方法

public abstract class S3Service extends AbstractFileService {

  protected AmazonS3 client;

  public S3Service(FileChoiceProperties properties) {
    super(properties);
  }

  @Override
  protected void upload(MultipartFile file, String bucketName, String filePath) throws Exception {
    client.putObject(bucketName,filePath,file.getInputStream(), null);
  }

  @Override
  protected void delete(String bucketName, String filePath) throws Exception {
    client.deleteObject(bucketName,filePath);
  }

  @Override
  protected String shareUrl(String bucketName, String filePath, long expiry, TimeUnit unit) throws Exception {
    return client.generatePresignedUrl(bucketName,filePath,new Date(System.currentTimeMillis()+unit.toMillis(expiry))).toString();
  }

  @Override
  protected InputStream getObject(String bucketName, String filePath) throws Exception {
    return client.getObject(bucketName, filePath).getObjectContent();
  }

  @Override
  protected void createBucket(String bucketName) throws Exception {
    client.createBucket(bucketName);
  }

  @Override
  protected boolean checkObjectExist(String bucketName, String objectName) throws Exception {
    S3Object response = client.getObject(bucketName,objectName);
    return (ValidateUtils.isEmpty(response) || ValidateUtils.isEmpty(response.getKey()));
  }

  @Override
  protected boolean copyFile(String sourceBucket, String targetBucket, String sourceObjectName, String targetObjectName)
      throws Exception {
    client.copyObject(sourceBucket,sourceObjectName,targetBucket,targetObjectName);
    return true;
  }

  @Override
  public boolean bucketExists(String bucketName) throws Exception {
    return client.doesBucketExistV2(bucketName);
  }
}

以下是ZOS(天翼云)

/**
 * 天翼云文件实现类
 */
public class ZOSService extends S3Service {

  public ZOSService(FileChoiceProperties properties) {
    super(properties);
    AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
    builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
    if(ValidateUtils.isNotEmpty(properties.getEndpoint()) && ValidateUtils.isNotEmpty(properties.getRegionName())){
      builder.withEndpointConfiguration(new EndpointConfiguration(properties.getEndpoint(),properties.getRegionName()));
    }
    ClientConfiguration awsClientConfig = new ClientConfiguration();
    boolean             isHttps         = properties.getEndpoint().contains("https");
    awsClientConfig.setProtocol(isHttps ? Protocol.HTTPS : Protocol.HTTP);
    builder.setClientConfiguration(awsClientConfig);
    client = builder.build();
  }

}

以下是KS3(金山云)

/**
 * 金山云文件实现类
 */
public class KS3Service extends S3Service {

  public KS3Service(FileChoiceProperties properties) {
    super(properties);
    AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
    builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
    if(ValidateUtils.isNotEmpty(properties.getEndpoint())){
      builder.withEndpointConfiguration(new EndpointConfiguration(properties.getEndpoint(),""));
    }
    ClientConfiguration awsClientConfig = new ClientConfiguration();
    boolean isHttps = properties.getEndpoint().contains("https");
    awsClientConfig.setProtocol(isHttps ? Protocol.HTTPS : Protocol.HTTP);
    builder.setClientConfiguration(awsClientConfig);
    client = builder.build();
  }

}

以下是EOS(移动云)

/**
 * 移动云文件实现类
 */
public class EOSService extends S3Service {

  public EOSService(FileChoiceProperties properties) {
    super(properties);
    AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
    builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
    if(ValidateUtils.isNotEmpty(properties.getEndpoint()) && ValidateUtils.isNotEmpty(properties.getRegionName())){
      builder.withEndpointConfiguration(new EndpointConfiguration(properties.getEndpoint(),properties.getRegionName()));
    }
    ClientConfiguration awsClientConfig = new ClientConfiguration();
    boolean             isHttps         = properties.getEndpoint().contains("https");
    awsClientConfig.setProtocol(isHttps ? Protocol.HTTPS : Protocol.HTTP);
    builder.setClientConfiguration(awsClientConfig);
    client = builder.build();
  }

}

以下是NOS(网易数帆)

/**
 * 网易数帆文件实现类
 */
public class NOSService extends S3Service {

  public NOSService(FileChoiceProperties properties) {
    super(properties);
    AWSCredentials credentials = new BasicAWSCredentials(properties.getAccessKey(), properties.getSecretKey());
    AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
    builder.withCredentials(new AWSStaticCredentialsProvider(credentials));
    if(ValidateUtils.isNotEmpty(properties.getEndpoint()) && ValidateUtils.isNotEmpty(properties.getRegionName())){
      builder.withEndpointConfiguration(new EndpointConfiguration(properties.getEndpoint(),properties.getRegionName()));
    }
    ClientConfiguration awsClientConfig = new ClientConfiguration();
    boolean             isHttps         = properties.getEndpoint().contains("https");
    awsClientConfig.setProtocol(isHttps ? Protocol.HTTPS : Protocol.HTTP);
    builder.setClientConfiguration(awsClientConfig);
    client = builder.build();
  }

}

然后就是文件命名接口

public interface FileNamingRulesGenerationService {

  String getFileName(MultipartFile file);

  /**
   * 获取文件扩展名,不带 .
   */
  default String getExtensionName(String filename) {
    return FileNameUtil.extName(filename);
  }
}
按照时间进行文件命名
public class DateNamingRulesGenerationService implements FileNamingRulesGenerationService {

  @Override
  public String getFileName(MultipartFile file) {
    String contentType = getExtensionName(file.getOriginalFilename());
    return new StringBuilder(DateTimeUtils.getLocalDateTimeString("yyyy/MM/dd/yyyyMMddHHmmssSSS")).append(".").append(contentType).toString();
  }
}
用上传时候文件的原名
public class OriginalNamingRulesGenerationService implements FileNamingRulesGenerationService {

  @Override
  public String getFileName(MultipartFile file) {
    return file.getOriginalFilename();
  }
}
用雪花用作文件名
public class SnowflakeNamingRulesGenerationService implements FileNamingRulesGenerationService {

  private final Snowflake generator;

  public SnowflakeNamingRulesGenerationService(){
    this.generator = new Snowflake();
  }

  @Override
  public String getFileName(MultipartFile file) {
    String contentType = getExtensionName(file.getOriginalFilename());
    return new StringBuilder().append(generator.nextIdStr()).append(".").append(contentType).toString();
  }
用uuid用作文件名
public class UUIDNamingRulesGenerationService implements FileNamingRulesGenerationService {

  @Override
  public String getFileName(MultipartFile file) {
    String contentType = getExtensionName(file.getOriginalFilename());
    return new StringBuilder().append(UUID.randomUUID().toString().replace("-","")).append(".").append(contentType).toString();
  }
}

现在就轮到了文件配置

@ConfigurationProperties(prefix = "file")
public class FileChoiceProperties {

  /**
   * 文件服务选择
   */
  private FileChoiceEnum choice = FileChoiceEnum.DEFAULT;
  /**
   * 文件名规则
   */
  private FileNamingMethodEnum fileNamingMethod = FileNamingMethodEnum.ORIGINAL;

  /**
   * 是一个URL,域名,IPv4或者IPv6地址")
   */
  private String endpoint;

  /**
   * "accessKey类似于用户ID,用于唯一标识你的账户"
   */
  private String accessKey;

  /**
   * "secretKey是你账户的密码"
   */
  private String secretKey;

  /**
   * "默认存储桶"
   */
  private String bucketName;

  /**
   * 根目录
   */
  private String rootDirectory;

  /**
   * 地区(默认腾讯的广州)
   */
  private String regionName = Region.Guangzhou.getValue();

  public String getRegionName() {
    return regionName;
  }

  public void setRegionName(String regionName) {
    this.regionName = regionName;
  }

  public FileChoiceEnum getChoice() {
    return choice;
  }

  public void setChoice(FileChoiceEnum choice) {
    this.choice = choice;
  }

  public FileNamingMethodEnum getFileNamingMethod() {
    return fileNamingMethod;
  }

  public void setFileNamingMethod(FileNamingMethodEnum fileNamingMethod) {
    this.fileNamingMethod = fileNamingMethod;
  }

  public String getEndpoint() {
    return endpoint;
  }

  public void setEndpoint(String endpoint) {
    this.endpoint = endpoint;
  }

  public String getAccessKey() {
    return accessKey;
  }

  public void setAccessKey(String accessKey) {
    this.accessKey = accessKey;
  }

  public String getSecretKey() {
    return secretKey;
  }

  public void setSecretKey(String secretKey) {
    this.secretKey = secretKey;
  }

  public String getBucketName() {
    return bucketName;
  }

  public void setBucketName(String bucketName) {
    this.bucketName = bucketName;
  }

  public String getRootDirectory() {
    return rootDirectory;
  }

  public void setRootDirectory(String rootDirectory) {
    this.rootDirectory = rootDirectory;
  }

然后就是config配置器了

@Configuration
@EnableConfigurationProperties(value={FileChoiceProperties.class})
public class FileConfig {

  private final Logger logger = LoggerUtils.logger(FileConfig.class);

  @Bean
  public FileNamingRulesGenerationService fileNamingMethodService(FileChoiceProperties fileProperties){
    logger.info("选择 {} 命名规则", fileProperties.getFileNamingMethod());
    switch (fileProperties.getFileNamingMethod()) {
      case DATE:
        return new DateNamingRulesGenerationService();
      case UUID:
        return new UUIDNamingRulesGenerationService();
      case SNOWFLAKE:
        return new SnowflakeNamingRulesGenerationService();
      default:
        return new OriginalNamingRulesGenerationService();
    }
  }

@Bean
  @ConditionalOnMissingBean(FileServiceInterface.class)
  @ConditionalOnClass(OkHttpClient.Builder.class)
  public FileServiceInterface fileService(FileChoiceProperties fileProperties){
    logger.info("选择 {} 文件服务", fileProperties.getChoice().getDesc());
    switch (fileProperties.getChoice()) {
      case MINIO:
        return new MinioService(fileProperties);
      case OSS:
        return new OSSService(fileProperties);
      case OBS:
        return new OBSService(fileProperties);
      case COS:
        return new COSService(fileProperties);
      case BOS:
        return new BOSService(fileProperties);
      case KODO:
        return new KODOService(fileProperties);
      case ZOS:
        return new ZOSService(fileProperties);
      case KS3:
        return new KS3Service(fileProperties);
      default:
        return new DefaultService(fileProperties);
    }
  }
}

大概的整合代码思路就在这里,希望大家多多给意见

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值