OSS阿里云存储——整合Spring文件上传,实现动静网站资源分离

来源:互联网 发布:ceph源码分析 常涛 编辑:程序博客网 时间:2024/05/17 20:32

写在前面

在日常学习或开发java web项目的过程中,难免会遇到各种各样的文件上传问题。传统做法或固有思路,一向是把这些用户上传的静态资源保存在自己的服务器中。这也是初学者普遍的做法。但是,长此以往,大量用户累积的用户静态资源文件,势必会大量占用服务器的存储空间,降低服务器的性能,同时也增加了网站维护的成本。

于是,另一种做法营运而生,就是把网站的静态资源和动态资源实现分离。增加一台服务器专门用来保存静态文件,这不失为一种好办法。但小编今天分享的另一种方法是在第三方云存储服务器的基础上,实现自己的文件上传以及文件云存储,达到网站资源动静分离的目的。

关于阿里云OSS云存储服务器的具体资料和相关文档以及各个语言的API请读者自行百度或浏览官网学习,这里就不做过多的赘述。传送门:阿里云官网OOS对象服务器

以下小编主要分享Spring+OSS云存储服务上传文件的具体操作。

准备工作

1.阿里云账号
2.一台阿里云存储服务器(包半年6.00元左右,购买以及基本配置请参考官网)

开发环境以及工具

1.java 1.8
2.idea
3.Tomcat9 主要用来测试
4.maven3.5

你必须知道的OSS对象服务器的基本概念

1.存储空间(Bucket)

存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。

2.对象/文件(Object)

对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件

3.Region(地域)

Region 表示 OSS 的数据中心所在的地域,物理位置。

4.Endpoint(访问域名)

Endpoint 表示 OSS 对外服务的访问域名。

5.AccessKey(访问密钥)

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

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

以上列出的只是部分基础的概念,详情请参考官方文档。

项目组织结构

项目结构

此项目本来是一个web项目,用到的数据库是mongodb,主要用来记录接口访问日志。化红线的是上传文件的主要功能类。因此,其他配置文件中的具体配置在此不详加赘述,这里只提供基本的思路。更加完美的功能请自行完善。

OSS 接口的配置使用和基本操作封装

使用前导入maven依赖

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

AliOSSConfig.java

/** * @author longping jie * @name AliOSSConfig * @description the class is 阿里云oos上传客户端对象的配置类 * @date 2017/9/20 */public class AliOSSConfig {    public static String END_POINT;    public static String ACCESS_KEY_ID;    public static String ACCESS_KEY_SECRET;    public static int VISIT_GRADE = 3;    static {        //外部接入入口        END_POINT = PropertiesHelper.getValueByKey("END_POINT");        //秘钥id        ACCESS_KEY_ID = PropertiesHelper.getValueByKey("ACCESS_KEY_ID");        //秘钥对应该是        ACCESS_KEY_SECRET = PropertiesHelper.getValueByKey("ACCESS_KEY_SECRET");    }}

这些常量配置从properties配置文件中读取,properties文件和其操作的封装自行处理。

AliOSSBaseTool.java 封装一些OSS的基本操作

package com.longge.upload.util;import com.aliyun.oss.OSSClient;import com.aliyun.oss.model.CannedAccessControlList;import com.aliyun.oss.model.CreateBucketRequest;import com.aliyun.oss.model.OSSObject;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import java.io.ByteArrayInputStream;/** * @author longping jie * @name AliOSSTool * @description the class is 阿里云OSS客户端工具类 * @date 2017/9/20 */public class AliOSSBaseTool {    static Logger logger = LogManager.getLogger(AliOSSBaseTool.class);    /**     * 判断一个存储空间是否存在     *     * @param ossClient     * @param bucketName     * @return     */    public static boolean doesBucketExits(OSSClient ossClient, String bucketName) {        return ossClient.doesBucketExist(bucketName);    }    /**     * 创建一个存储空间     * 并给存储空间对外赋读写权限     * @param ossClient  oss连接     * @param bucketName 存储空间名字     * @param grade      访问等级(1,2,3)(私有,公共读,公共读写)     * @return 是否创建成功     */    public static boolean createBuckName(OSSClient ossClient, String bucketName, int grade) {        boolean res;        if (doesBucketExits(ossClient, bucketName)) return true;        CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);        switch (grade) {            case 1:                createBucketRequest.setCannedACL(CannedAccessControlList.Private);                break;            case 2:                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);                break;            case 3:                createBucketRequest.setCannedACL(CannedAccessControlList.PublicReadWrite);                break;            default:                createBucketRequest.setCannedACL(CannedAccessControlList.Private);                break;        }        ossClient.createBucket(createBucketRequest);        res = true;        return res;    }    /**     * 删除一个存储空间     *     * @param ossClient  oss连接     * @param bucketName 存储空间名字     */    public void deleteBucketName(OSSClient ossClient, String bucketName) {        if (doesBucketExits(ossClient, bucketName)) {            ossClient.deleteBucket(bucketName);        }    }    /**     * 创建一个文件夹     *     * @param ossClient  oss连接     * @param bucketName 存储空间名字     * @param folder     文件夹名     * @return true 创建成功   false文件夹已经存在     */    public static boolean createFolder(OSSClient ossClient, String bucketName, String folder) {        if (!ossClient.doesObjectExist(bucketName, folder)) {            ossClient.putObject(bucketName, folder, new ByteArrayInputStream(new byte[0]));            OSSObject object = ossClient.getObject(bucketName, folder);            String fileDir = object.getKey();            logger.debug("文件夹创建成功:{}", fileDir);            return true;        }        return false;    }    /**     * 删除一个文件夹     *     * @param ossClient  oss连接     * @param bucketName 存储空间名字     * @param folder     文件夹名     * @return true 删除成功   false文件夹已经存在     */    public static boolean deleteFolder(OSSClient ossClient, String bucketName, String folder) {        if (ossClient.doesObjectExist(bucketName, folder)) {            ossClient.deleteObject(bucketName, folder);            logger.debug("删除文件夹成功:{}", folder);            return true;        }        return false;    }    /**     * 根据key删除OSS服务器上的文件     * @param ossClient oss连接     * @param bucketName 存储空间     * @param folder  模拟文件夹名     * @param key Bucket下的文件路径名+文件名 如:"upload/cake.jpg"     */    public static void deleteFile(OSSClient ossClient,String bucketName,String folder,String key){        ossClient.deleteObject(bucketName,folder+key);        logger.debug("删除:{}",bucketName+"下的文件:{}",folder+key+"成功!");    }}

AliOSSApplayUtil.java OOS应用工具类,封装图片上传

package com.longge.upload.util;import com.aliyun.oss.ClientException;import com.aliyun.oss.OSSClient;import com.aliyun.oss.OSSException;import com.aliyun.oss.model.*;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import java.io.*;import java.util.Date;import java.util.UUID;/** * @author longping jie * @name AliOSSUtil * @description the class is 阿里云应用工具类 * @date 2017/9/18 */public class AliOSSApplayUtil {    private final static Logger log = LogManager.getLogger(AliOSSApplayUtil.class);    private static String END_POINT=AliOSSConfig.END_POINT;    private static String ACCESS_KEY_ID=AliOSSConfig.ACCESS_KEY_ID;    private static String ACCESS_KEY_SECRET=AliOSSConfig.ACCESS_KEY_SECRET;    /**     * 获得oss连接对象     * @return oss连接对象     */    private static OSSClient ossClient(){        return new OSSClient(END_POINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);    }    /**     * 上传文件     *     * @param file 文件对象     * @return 保存文件在oos服务器上的路径,上传成功后返回文件的保存路径是一个url连接     * 直接指向云上的资源位置     */    public static String upload(File file,String bucketName,String folder) {        if (file == null) {            return null;        }        //创建OSS客户端        OSSClient ossClient = ossClient();        try (InputStream is = new FileInputStream(file)) {            //判断文件容器是否存在,不存在则创建            AliOSSBaseTool.createBuckName(ossClient,bucketName,AliOSSConfig.VISIT_GRADE);            AliOSSBaseTool.createFolder(ossClient,bucketName,folder);            //文件名            String fileName = file.getName();            //文件大小            Long fileSize = file.length();            //创建上传文件的Metadata            ObjectMetadata metadata = new ObjectMetadata();            //上传文件的长度            metadata.setContentLength(is.available());            //指定该object被下载时的网页的缓存行为            metadata.setCacheControl("no-cache");            //指定该object下设置Header            metadata.setHeader("Pragma","no-cache");            //指定该object被下载时的内容编码方式            metadata.setContentEncoding("utf-8");            //文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,            //如果没有扩展名则填默认值application/octet-stream            metadata.setContentType(getContentType(fileName));            //指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");            //上传文件   (上传文件流的形式)            //此处上传文件            PutObjectResult putResult = ossClient.putObject(bucketName, folder+fileName, is, metadata);            String fileHost = "http://"+bucketName+"."+END_POINT;            if (null != putResult) {                return fileHost+"/"+folder+fileName;            }        } catch (OSSException oe) {            oe.printStackTrace();        } catch (ClientException e) {            e.printStackTrace();        }catch (Exception e){            e.printStackTrace();        }finally {            // 关闭OSS服务,一定要关闭            ossClient.shutdown();        }        return null;    }    /**     * 通过文件名判断并获取OSS服务文件上传时文件的contentType     * @param fileName 文件名     * @return 文件的contentType     */    public static  String getContentType(String fileName){        //文件的后缀名        String fileExtension = fileName.substring(fileName.lastIndexOf("."));        if(".bmp".equalsIgnoreCase(fileExtension)) {            return "image/bmp";        }        if(".gif".equalsIgnoreCase(fileExtension)) {            return "image/gif";        }        if(".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)  || ".png".equalsIgnoreCase(fileExtension) ) {            return "image/jpeg";        }        if(".html".equalsIgnoreCase(fileExtension)) {            return "text/html";        }        if(".txt".equalsIgnoreCase(fileExtension)) {            return "text/plain";        }        if(".vsd".equalsIgnoreCase(fileExtension)) {            return "application/vnd.visio";        }        if(".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {            return "application/vnd.ms-powerpoint";        }        if(".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {            return "application/msword";        }        if(".xml".equalsIgnoreCase(fileExtension)) {            return "text/xml";        }        //默认返回类型        return "image/jpeg";    }}upload方法是文件上传的具体方法,接收File file 参数,在此基础上可以对file进行缩放、裁剪等基础操作后,再传入,然后写入云服务器。上传文件成功后,会根据Controller中自定义的成功信息,返回成功状态,和文件保存的路径,可以把url返回前端界面展示。

Springmvc的multipart配置这个在配置文件中定义。

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        <property name="defaultEncoding" value="utf-8" />        <property name="maxUploadSize" value="104857600" />        <property name="maxInMemorySize" value="4096" />    </bean>

另一种使文件上传,性能更高的做法是,把自己的密钥(或者识别身份的东西)暂时授权给第三方用户(你的网站用户)用户可以直接POST调用阿里云的接口,即省去你自己的服务器中转。这样就更加快速而且高效地实现文件上传的目的。

OSS对象服务器大致的基本功能,小编就暂时分享到这里。有关OOS的细节,还请读者参考官方文档。文章中的不足之处,希望读者在评论区不吝赐教。代码经测试有效,在整合自己项目的过程中,遇到问题,欢迎在此讨论。整个项目的源码,小编完善后,会托管到GitHub或码云上,随后共享。欢迎大家关注…

原创粉丝点击