SpringBoot整合阿里云OSS

阿里云OSS Java工具类

阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。其数据设计持久性不低于 99.9999999999%(12 个 9),服务设计可用性(或业务连续性)不低于 99.995%。
OSS 具有与平台无关的 RESTful API 接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
您可以使用阿里云提供的 API、SDK 接口或者 OSS 迁移工具轻松地将海量数据移入或移出阿里云 OSS。数据存储到阿里云 OSS 以后,您可以选择标准存储(Standard)作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问存储(Infrequent Access)和归档存储(Archive)作为不经常访问数据的存储方式。

以上内容引用自阿里云官网

价格

目前阿里云OSS的价格是40GB/年9元,如果你是白嫖用户,那么请转向七牛。

你以为购买了40G/年的容量就不用付费了吗?那你就错了,这只是存储费用,使用OSS还需要支付流量费用。但是流量费用是单独计算的。

  • 存储价格 0.148 元 /GB/月
  • 流量价格 忙时 0.50 元 /GB
  • 请求费用 0.01 元 /万次
    上述的40G/年指的是存储价格,并不包含流量和请求费用。
    具体内容可参见:计价表

OSS可以做什么?

它可以搭建自己的床图(配合PicGO),备份网站,数据库(配合宝塔)等。也可以在开发过程中充当文件服务器,阿里云OSS宣称99.9999999999%的可靠性,另外加上价格相对低廉,是作为图片/文件服务器的不二之选。

你要知道的一些概念

存储空间(Bucket)

存储空间是用户用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。用户可以根据实际需求,创建不同类型的存储空间来存储不同的数据。

  • 同一个存储空间的内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。
  • 每个用户可以拥有多个存储空间。
  • 存储空间的名称在 OSS 范围内必须是全局唯一的,一旦创建之后无法修改名称。
  • 存储空间内部的对象数目没有限制。

存储空间的命名规范如下:

  • 只能包括小写字母、数字和短横线(-)。

  • 必须以小写字母或者数字开头和结尾。

  • 长度必须在 3–63 字节之间。

对象/文件(Object)

对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的 Key 来标识。对象元信息是一组键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。

对象的生命周期是从上传成功到被删除为止。在整个生命周期内,只有通过追加上传的 Object 可以继续通过追加上传写入数据,其他上传方式上传的 Object 内容无法编辑,您可以通过重复上传同名的对象来覆盖之前的对象。

对象的命名规范如下:

  • 使用 UTF-8 编码。

  • 长度必须在 1–1023 字节之间。

  • 不能以正斜线(/)或者反斜线(\)开头。

Endpoint(访问域名)

Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同的 Region 的时候,需要不同的域名。通过内网和外网访问同一个 Region 所需要的 Endpoint 也是不同的。例如杭州 Region 的外网 Endpoint 是 oss-cn-hangzhou.aliyuncs.com,内网 Endpoint 是 oss-cn-hangzhou-internal.aliyuncs.com。

AccessKey(访问密钥)

AccessKey(简称 AK)指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。OSS 通过使用 AccessKeyId 和 AccessKeySecret 对称加密的方法来验证某个请求的发送者身份。AccessKeyId 用于标识用户;AccessKeySecret 是用户用于加密签名字符串和 OSS 用来验证签名字符串的密钥,必须保密。对于 OSS 来说,AccessKey 的来源有:

  • Bucket 的拥有者申请的 AccessKey。
  • 被 Bucket 的拥有者通过 RAM 授权给第三方请求者的 AccessKey。
  • 被 Bucket 的拥有者通过 STS 授权给第三方请求者的 AccessKey。

JAVA工具类-准备篇

这里介绍一份基于java实现的阿里云OSS工具类,代码基于阿里云官方OSS官方API文档。此项目使用Maven搭建,需要使用几个依赖。具体依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.rayfoo</groupId>
    <artifactId>ALiOSS-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <!-- maven-compiler-plugin 将会使用指定的 JDK 版本将 java 文件编译为 class 文件(针对编译运行环境) -->
        <maven.compiler.target>1.8</maven.compiler.target>
        <!-- maven-compiler-plugin 将会使用指定的 JDK 版本对源代码进行编译(针对编译运行环境) -->
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>


    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.1.5.RELEASE</version>
        </dependency>

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

</project>

此工具类需要调用resource下的aliyunOSS.properties文件,具体配置如下

AccessKey=yourAccessKey
AccessKeySecret=yourAccessKeySecret
Buckets=yourBuckets
EndPoint=https://oss-cn-beijing.aliyuncs.com

由于此工具类又用到我封装的另一个工具类:PropertiesReader,所以在此处提供该工具类的代码。

注意:

  • 这份工具类建议需要1.8及以上版本的JDK
package cn.rayfoo.util;

import java.io.InputStream;
import java.util.Properties;

/**
 * Created by rayfoo@qq.com Luna on 2020/4/15 18:38
 * Description : 读取配置文件工具类
 */
public class PropertiesReader {

    //创建Properties对象
    private static Properties property = new Properties();

    //在静态块中加载资源
    static {
        //使用try(){}.. 获取数据源
        //注意 * 这是jdk1.7开始支持的特性,如果使用的是低版本 需要提升jdk版本 或者更改写法
        try (
                InputStream in = PropertiesReader.class.getResourceAsStream("/aliyunOSS.properties");
        ) {
            property.load(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 返回Properties对象
     * @return
     */
    public static Properties getProperties(){
        return property;
    }

    /**
     * 获取字符串类型的值
     * @param key
     * @return
     */
    public static String get(String key) {
        return property.getProperty(key);
    }

    /**
     * 获取Integer类型的值
     * @param key
     * @return
     */
    public static Integer getInteger(String key) {
        String value = get(key);
        return null == value ? null : Integer.valueOf(value);
    }

    /**
     * 获取Boolean类型的值
     * @param key
     * @return
     */
    public static Boolean getBoolean(String key) {
        String value = get(key);
        return null == value ? null : Boolean.valueOf(value);
    }

    /**
     * 设置一个键值对
     * @param key
     * @param value
     */
    public static void set(String key,String value){
        property.setProperty(key,value);
    }

    /**
     * 添加一个键值对
     * @param key
     * @param value
     */
    public static void add(String key,Object value){
        property.put(key,value);
    }
}

工具类代码

该工具类集成了OSS的上传、下载等功能。

参数介绍

下面的代码中会用到很多个参数名,我们要先明白它们代表什么

参数名 含义
oranName 代表用户传过来未经处理的文件名 例如/img/a.jpg
objectName 代表去掉前面/ 加上uuid后的文件名 如img/330ddd7feb6d456f8ee97092d7675c90a.jgp
realName 指的是存放在OSS中的全路径

属性介绍

属性名 介绍
accessKeyId 这个属性会从aliyunOSS.properties中读取key为AccessKey的内容
accessKeySecret 这个属性会从aliyunOSS.properties中读取key为AccessKeySecret的内容
endpoint 这个属性会从aliyunOSS.properties中读取key为Endpoint的内容
bucketName 这个属性会从aliyunOSS.properties中读取key为BucketName的内容

方法介绍

方法名 介绍
getURLHead() 返回url头信息,即https://+bucketName+endpoint
String getObjectName(String fileURL) 通过文件URL反向解析文件名
List getObjectNames(List fileURLs) 批量获取 objectName
String getRealName(String oranName) 获取存放在OSS中的全路径
void printUploadSuccessInfo(String fileURL) 上传成功后打印文件的存储地址,测试方法
void printDeleteSuccessInfo(String fileURL) 删除成功后打印文件的存储地址,测试方法
String getRandomImageName(String oranName) 在oranName之前加入一个uuid并返回新的oranName
String createBucket(String bucket) 创建一个新的Bucket
String getBucketName(String fileURL) 根据url获取bucketName
void useBucketName(String bucket) 切换到某个bucket
void useBucketNameByURL(String fileURL) 切换到url所在的bucket
String upLoadTextFile(String oranFileName, String content) 上传一个文本文件到服务器上,获取realName
String uploadBytesFile(String oranFileName, byte[] content) 上传一个byte数组到服务器上,可用于web中的图片提交,获取realName
String uploadNetworkFlows(String oranFileName, String url) 上传网络流,获取realName
String uploadFileInputSteam(String oranFileName, File file) 上传文件流,获取realName
String uploadLocalFile(String oranFileName, String localFileName) 上传一个本地文件,获取realName
void deleteFile(String fileURL) 删除指定路径下的一个文件
void deleteFile(List fileURL) 删除指定路径下的多个文件
boolean exists(String fileURL) 存在为true,不存在为false
void downloadFileToLoacal(String fileURL, String localFileName) 从OSS中下载一个文件到本地
StringBuffer downloadStream(String fileURL) 以流的方式读取一个文件 并打印 返回读取到的内容
Object getCloudPropertiesGetValue(String fileName, String key) 以流的方式读取一个云端properties文件的key对应的value 并打印

工具类代码

package cn.rayfoo.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;

import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

/**
 * Created by rayfoo@qq.com Luna on 2020/4/15 23:12
 * Description:阿里云 OSS 文件上传工具类
 * oranName : 代表用户传过来未经处理的文件名 例如/img/a.jpg
 * objectName : 代表去掉前面/ 加上uuid后的文件名 如img/330ddd7feb6d456f8ee97092d7675c90a.jgp
 * getRealName(objectName) : 指的是存放在OSS中的全路径
 */
public class AliOSSUtil {

    //AccessKey
    private static String accessKeyId = null;
    //AccessKeySecret
    private static String accessKeySecret = null;
    //Endpoint
    private static String endpoint = null;
    //bucketName
    private static String bucketName = null;

    /**
     * 静态块
     */
    static {
        //初始化AccessKey
        accessKeyId = PropertiesReader.get("AccessKey");
        //初始化AccessKeySecret
        accessKeySecret = PropertiesReader.get("AccessKeySecret");
        //初始化Endpoint
        endpoint = PropertiesReader.get("EndPoint");
        //初始化bucketName
        bucketName = PropertiesReader.get("Buckets");
    }

    /**
     * 私有化构造
     */
    private AliOSSUtil() {

    }

    /**
     * 获取图片的URL头信息
     *
     * @return 返回url头信息
     */
    private static String getURLHead() {
        //从哪个位置截取
        int cutPoint = endpoint.lastIndexOf('/') + 1;
        //http头
        String head = endpoint.substring(0, cutPoint);
        //服务器地址信息
        String tail = endpoint.substring(cutPoint);
        //返回结果
        return head + bucketName + "." + tail + "/";
    }

    /**
     * 通过文件URL反向解析文件名
     *
     * @param fileURL 文件URL
     * @return 原文件名
     */
    private static String getObjectName(String fileURL) {
        return fileURL.substring(getURLHead().length());
    }

    /**
     * 批量获取 objectName
     *
     * @param fileURLs url列表
     * @return objectName列表
     */
    private static List<String> getObjectNames(List<String> fileURLs) {
        //创建返回对象
        List<String> result = null;
        //迭代转换
        for (String item : fileURLs) {
            result.add(item.substring(getURLHead().length()));
        }
        return result;
    }

    /**
     * 获取存储在服务器上的地址
     *
     * @param oranName 文件名
     * @return 文件URL
     */
    private static String getRealName(String oranName) {
        return getURLHead() + oranName;
    }

    /**
     * 打印文件的存储地址
     *
     * @param fileURL 文件URL
     */
    private static void printUploadSuccessInfo(String fileURL) {
        //上传成功
        System.out.println("upload success, path = " + getRealName(fileURL));
    }

    /**
     * 打印文件的存储地址
     *
     * @param fileURL 文件URL
     */
    private static void printDeleteSuccessInfo(String fileURL) {
        //上传成功
        System.out.println("delete success, path = " + getRealName(fileURL));
    }


    /**
     * 获取一个随机的文件名
     *
     * @param oranName 初始的文件名
     * @return 返回加uuid后的文件名
     */
    private static String getRandomImageName(String oranName) {
        //获取一个uuid 去掉-
        String uuid = UUID.randomUUID().toString().replace("-", "");
        //查一下是否带路径
        int cutPoint = oranName.lastIndexOf("/") + 1;
        //如果存在路径
        if (cutPoint != 0) {
            //掐头 如果开头是/ 则去掉
            String head = oranName.indexOf("/") == 0 ? oranName.substring(1, cutPoint) : oranName.substring(0, cutPoint);
            //去尾
            String tail = oranName.substring(cutPoint);
            //返回正确的带路径的图片名称
            return head + uuid + tail;
        }
        //不存在 直接返回
        return uuid + oranName;
    }

    /**
     * 创建一个Bucket,这个参数由参数传入 并非配置文件读取
     *
     * @param bucket BucketName 此处参数名喂Bucket是为了不和buckName冲突
     */
    public static String createBucket(String bucket) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 创建存储空间。
        ossClient.createBucket(bucket);

        // 关闭OSSClient。
        ossClient.shutdown();

        return bucket;

    }


    /**
     * 根据url获取bucketName
     *
     * @param fileURL 文件的URL
     * @return bucketName
     */
    public static String getBucketName(String fileURL) {
        //前缀
        String prefix = "http://";
        //后缀
        String suffix = ".";
        //截取起始位置
        int beginIndex = fileURL.indexOf(prefix);
        //截取结束位置
        int endIndex = fileURL.indexOf(suffix);
        //如果不是http
        if (beginIndex == -1) {
            prefix = "https://";
            beginIndex = fileURL.indexOf(prefix);
            //如果还是-1 那就是没找到 返回-1即可
            if (beginIndex == -1)
                return null;
        }
        //设置起始位置
        beginIndex = prefix.length();
        //返回bucketName
        return fileURL.substring(beginIndex, endIndex);
    }

    /**
     * 切换bucket
     *
     * @param bucket 新的bucket名称
     */
    public static void useBucketName(String bucket) {
        bucketName = bucket;
        PropertiesReader.set("Buckets", bucket);
    }

    /**
     * 切换bucket
     *
     * @param fileURL 根据URL设置新的BucketName
     */
    public static void useBucketNameByURL(String fileURL) {
        PropertiesReader.set("Buckets", getBucketName(fileURL));
    }

    /**
     * 上传一个文本文件到服务器上
     *
     * @param oranFileName 上传到服务器上的文件路径和名称 文本文件一般以.txt为后缀
     * @param content      上传的内容
     */
    public static String upLoadTextFile(String oranFileName, String content) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));

        //上传成功 打印文件存储地址
        printUploadSuccessInfo(objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }


    /**
     * 上传一个byte数组到服务器上
     *
     * @param oranFileName 上传到服务器上的文件路径和名称
     * @param content      上传的内容
     */
    public static String uploadBytesFile(String oranFileName, byte[] content) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 上传Byte数组。
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));

        //上传成功 打印文件存储地址
        printUploadSuccessInfo(objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }

    /**
     * 上传网络流
     *
     * @param oranFileName 上传到服务器上的文件路径和名称
     * @param url          网络上文件的url
     */
    public static String uploadNetworkFlows(String oranFileName, String url) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try (
                // 上传网络流。
                InputStream inputStream = new URL(url).openStream();) {

            //上传到OSS
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //上传成功 打印文件存储地址
        printUploadSuccessInfo(objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }

    /**
     * 上传文件流
     *
     * @param oranFileName 上传到服务器上的文件路径和名称
     * @param file         来自本地的文件或者文件流
     */
    public static String uploadFileInputSteam(String oranFileName, File file) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 上传文件流。
        try (InputStream inputStream = new FileInputStream(file);) {
            //上传到OSS
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        //上传成功 打印文件存储地址
        printUploadSuccessInfo(objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }

    /**
     * 上传一个本地文件
     *
     * @param oranFileName  上传到服务器上的名称和路径
     * @param localFileName 需要提供路径和文件名
     */
    public static String uploadLocalFile(String oranFileName, String localFileName) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(localFileName));

        // 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
        // ObjectMetadata metadata = new ObjectMetadata();
        // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
        // metadata.setObjectAcl(CannedAccessControlList.Private);
        // putObjectRequest.setMetadata(metadata);

        // 上传文件。
        ossClient.putObject(putObjectRequest);

        //上传成功 打印文件存储地址
        printUploadSuccessInfo(objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }


    /**
     * 删除指定路径下的一个文件
     *
     * @param fileURL 文件的全称
     */
    public static void deleteFile(String fileURL) {

        // 反向解析文件名
        String objectName = getObjectName(fileURL);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
        ossClient.deleteObject(bucketName, objectName);

        //删除成功 打印文件存储地址
        printDeleteSuccessInfo(fileURL);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 删除指定路径下的多个文件--该方法未测试
     *
     * @param fileURL 要删除的多个文件的集合
     */
    public static void deleteFile(List<String> fileURL) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 删除文件。key等同于ObjectName,表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
        List<String> keys = new ArrayList<>();
        //批量添加要删除的元素
        for (String item : fileURL) {
            keys.add(getObjectName(item));
        }

        //删除
        DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys));
        List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();

        //批量添加要删除的元素
        for (String item : fileURL) {
            printDeleteSuccessInfo(item);
        }

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 通过文件的URL 判断文件是否存在
     *
     * @param fileURL 文件的URL
     * @return 文件是否存在
     */
    public static boolean exists(String fileURL) {

        // 反向解析文件名
        String objectName = getObjectName(fileURL);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 判断文件是否存在。doesObjectExist还有一个参数isOnlyInOSS,如果为true则忽略302重定向或镜像;如果为false,则考虑302重定向或镜像。
        boolean found = ossClient.doesObjectExist(bucketName, objectName);

        // 关闭OSSClient。
        ossClient.shutdown();

        //  返回是否存在
        return found;
    }

    /**
     * 从OSS中下载一个文件
     *
     * @param fileURL       文件的url
     * @param localFileName 下载到本地的文件名称
     */
    public static void downloadFileToLoacal(String fileURL, String localFileName) {

        //将url解析成objectName
        String objectName = getObjectName(fileURL);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
        ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(localFileName));

        // 关闭OSSClient。
        ossClient.shutdown();

    }


    /**
     * 以流的方式读取一个文件 并打印
     *
     * @param fileURL 文件的url
     */
    public static StringBuffer downloadStream(String fileURL) {
        //<yourObjectName>表示从OSS下载文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
        String objectName = getObjectName(fileURL);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);

        // 读取文件内容。
        System.out.println("Object content:");

        StringBuffer sb = new StringBuffer();
        //使用try(){}..关闭资源
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));) {
            //读取
            while (true) {
                String line = reader.readLine();
                if (line == null) break;
                sb.append(line);
                System.out.println("\n" + line);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // 关闭OSSClient。
        ossClient.shutdown();
        //返回读取到的内容
        return sb;
    }

    /**
     * 以流的方式读取一个云端properties文件的key对应的value 并打印
     *
     * @param fileName 文件的url
     */
    public static Object getCloudPropertiesGetValue(String fileName, String key) {

        //properties 文件夹的前缀
        String prefix = "properties/";
        //properties 文件夹的后缀
        String suffix = ".properties";

        //<yourObjectName>表示从OSS下载文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
        String objectName = prefix + fileName + suffix;

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = ossClient.getObject(bucketName, objectName);

        // 读取文件内容。
        System.out.println("Object content:");

        //获取一个Properties对象
        Properties properties = PropertiesReader.getProperties();

        try (
                //获取文件流
                InputStream inputStream = ossObject.getObjectContent();) {
            properties.load(inputStream);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // 关闭OSSClient。
        ossClient.shutdown();
        //返回读取到的内容
        return properties.get(key);
    }
}

适用于SpringBoot的简化版工具类

Properties文件

aliyun.AccessKeyID=yourAccessKeyID
aliyun.AccessKeySecret=yourAccessKeySecret
aliyun.Buckets=yourBuckets
aliyun.EndPoint=https://oss-cn-beijing.aliyuncs.com
aliyun.prefix=prefix/

工具类代码

package cn.rayfoo.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * @Author: rayfoo@qq.com
 * @Date: 2020/7/13 3:11 下午
 * @Description:
 */
public class AliyunOSSUtils {

    /**
     * 阿里云的配置参数
     */
    private static String accessKeyId = null;
    private static String accessKeySecret = null;
    private static String endpoint = null;
    private static String bucketName = null;
    /**
     * 存储在OSS中的前缀名
     */
    private static  String file_prefix = null;


    /**
     * 静态块
     */
    static {
        //初始化AccessKey
        accessKeyId = PropertiesReader.get("aliyun.AccessKeyID");
        //初始化AccessKeySecret
        accessKeySecret = PropertiesReader.get("aliyun.AccessKeySecret");
        //初始化Endpoint
        endpoint = PropertiesReader.get("aliyun.EndPoint");
        //初始化bucketName
        bucketName = PropertiesReader.get("aliyun.Buckets");
        //初始化前缀
        file_prefix = PropertiesReader.get("aliyun.prefix");
    }

    /**
     * 私有化构造
     */
    private AliyunOSSUtils() {

    }

    /**
     * 获取图片的URL头信息
     *
     * @return 返回url头信息
     */
    private static String getURLHead() {
        //从哪个位置截取
        int cutPoint = endpoint.lastIndexOf('/') + 1;
        //http头
        String head = endpoint.substring(0, cutPoint);
        //服务器地址信息
        String tail = endpoint.substring(cutPoint);
        //返回结果
        return head + bucketName + "." + tail + "/";
    }

    /**
     * 获取存储在服务器上的地址
     *
     * @param oranName 文件名
     * @return 文件URL
     */
    private static String getRealName(String oranName) {
        return getURLHead() + oranName;
    }

    /**
     * 获取一个随机的文件名
     *
     * @param oranName 初始的文件名
     * @return 返回加uuid后的文件名
     */
    private static String getRandomImageName(String oranName) {
        //获取一个uuid 去掉-
        String uuid = UUID.randomUUID().toString().replace("-", "");
        //查一下是否带路径
        int cutPoint = oranName.lastIndexOf("/") + 1;
        //如果存在路径
        if (cutPoint != 0) {
            //掐头 如果开头是/ 则去掉
            String head = oranName.indexOf("/") == 0 ? oranName.substring(1, cutPoint) : oranName.substring(0, cutPoint);
            //去尾
            String tail = oranName.substring(cutPoint);
            //返回正确的带路径的图片名称
            return file_prefix + head + uuid + tail;
        }
        //不存在 直接返回
        return file_prefix + uuid + oranName;
    }

    /**
     * MultipartFile2File
     * @param multipartFile
     * @return
     */
    private static File transferToFile(MultipartFile multipartFile) {
        //选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferto()方法 。
        File file = null;
        try {
            //获取文件名
            String originalFilename = multipartFile.getOriginalFilename();
            //获取最后一个"."的位置
            int cutPoint = originalFilename.lastIndexOf(".");
            //获取文件名
            String prefix = originalFilename.substring(0,cutPoint);
            //获取后缀名
            String suffix = originalFilename.substring(cutPoint + 1);
            //创建临时文件
            file = File.createTempFile(prefix, suffix);
            //multipartFile2file
            multipartFile.transferTo(file);
            //删除临时文件
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 上传文件流
     *
     * @param oranFileName 上传到服务器上的文件路径和名称
     * @param file         来自本地的文件或者文件流
     */
    public static String uploadFileInputSteam(String oranFileName, MultipartFile file) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 上传文件流
        try (InputStream inputStream = new FileInputStream(transferToFile(file))) {
            //上传到OSS
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }


    /**
     * 上传文件流
     *
     * @param oranFileName 上传到服务器上的文件路径和名称
     * @param file         来自本地的文件或者文件流
     */
    public static String uploadFileInputSteam(String oranFileName, File file) {

        // <yourObjectName>上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg
        String objectName = getRandomImageName(oranFileName);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 上传文件流。
        try (InputStream inputStream = new FileInputStream(file);) {
            //上传到OSS
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // 关闭OSSClient。
        ossClient.shutdown();

        //返回文件在服务器上的全路径+名称
        return getRealName(objectName);
    }

}

SpringBoot+表单上传测试

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
    <h1>文件上传Demo</h1>
    <hr>
    <form id="myform" action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" value="提交">
    </form>
</body>
</html>

后台代码

package cn.rayfoo.controller;

import cn.rayfoo.utils.AliyunOSSUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;

/**
 * @Author: rayfoo@qq.com
 * @Date: 2020/7/13 3:15 下午
 * @Description:
 */
@RestController
public class FileController {

    @PostMapping("/upload")
    public String upload(@RequestParam("file")MultipartFile file, HttpServletRequest request){
        //如果文件为空 返回错误信息
        if(file.isEmpty()){
            return "field";
        }
        //获取原文件名
        String originalFilename = file.getOriginalFilename();

        //返回图片的url
       return AliyunOSSUtils.uploadFileInputSteam(originalFilename,file);
    }

}
posted @ 2020-04-16 15:23  张瑞丰  阅读(6527)  评论(0编辑  收藏  举报