• 阿里云OSS工具类


    【前言】

           我们上家公司的存储系统用的是FastDFS(智能一代云平台(二十八):对前后端分离和FastDFS的使用的再理解);现在在职的公司用的是阿里云的OSS(OSS的官方文档),在工作的时候整理一个上传OSS文件的工具类,现在与大家分享一下。

    【工具类】

           1、工具类的代码:

    1. package zhanghan.oss.utils;
    2. import com.aliyun.oss.ClientException;
    3. import com.aliyun.oss.OSSClient;
    4. import com.aliyun.oss.OSSException;
    5. import com.aliyun.oss.model.ObjectMetadata;
    6. import com.aliyun.oss.model.PutObjectResult;
    7. import com.fasterxml.jackson.annotation.JsonValue;
    8. import org.apache.commons.io.FilenameUtils;
    9. import org.apache.commons.lang3.time.DateUtils;
    10. import org.springframework.util.StringUtils;
    11. import org.springframework.web.multipart.MultipartFile;
    12. import zhanghan.oss.exception.OSSCreateBucketRuntimeException;
    13. import zhanghan.oss.exception.OSSGeneratePresignedUrlRuntimeException;
    14. import zhanghan.oss.exception.OssPutObjectRuntimeException;
    15. import java.io.InputStream;
    16. import java.net.URL;
    17. import java.util.Date;
    18. import java.util.UUID;
    19. /**
    20. * OSS上传工具类-张晗-2017/10/10
    21. */
    22. public class OSSUtil {
    23. private volatile static OSSClient instance;
    24. private OSSUtil() {
    25. }
    26. /**
    27. * 单例
    28. * @return OSS工具类实例
    29. */
    30. private static OSSClient getOSSClient() {
    31. if (instance == null) {
    32. synchronized (OSSUtil.class) {
    33. if (instance == null) {
    34. instance = new OSSClient(OSS_END_POINT, OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET);
    35. }
    36. }
    37. }
    38. return instance;
    39. }
    40. //定义日志
    41. private final static LogUtils logger = LogUtils.getLogger(OSSUtil.class);
    42. //OSS 的地址
    43. private final static String OSS_END_POINT = "http://oss-cn-qingdao.aliyuncs.com";
    44. //OSS 的key值
    45. private final static String OSS_ACCESS_KEY_ID = "OSSKEY";
    46. //OSS 的secret值
    47. private final static String OSS_ACCESS_KEY_SECRET = "OSSSECRET";
    48. //OSS 的bucket名字
    49. private final static String OSS_BUCKET_NAME = "zhanghan-test";
    50. //设置URL过期时间为10年
    51. private final static Date OSS_URL_EXPIRATION = DateUtils.addDays(new Date(), 365 * 10);
    52. //文件路径的枚举
    53. public enum FileDirType {
    54. ZHANGHAN_TEST("test");
    55. private String dir;
    56. FileDirType(String dir) {
    57. this.dir = dir;
    58. }
    59. @JsonValue
    60. public String getDir() {
    61. return dir;
    62. }
    63. }
    64. /**
    65. * 上传文件---去除URL中的?后的时间戳
    66. * @param file 文件
    67. * @param fileDir 上传到OSS上文件的路径
    68. * @return 文件的访问地址
    69. */
    70. public static String upload(MultipartFile file, FileDirType fileDir) {
    71. OSSUtil.createBucket();
    72. String fileName = OSSUtil.uploadFile(file, fileDir);
    73. String fileOssURL = OSSUtil.getImgUrl(fileName, fileDir);
    74. int firstChar = fileOssURL.indexOf("?");
    75. if (firstChar > 0) {
    76. fileOssURL = fileOssURL.substring(0, firstChar);
    77. }
    78. return fileOssURL;
    79. }
    80. /**
    81. * 当Bucket不存在时创建Bucket
    82. *
    83. * @throws OSSException 异常
    84. * @throws ClientException Bucket命名规则:
    85. * 1.只能包含小写字母、数字和短横线,
    86. * 2.必须以小写字母和数字开头和结尾
    87. * 3.长度在3-63之间
    88. */
    89. private static void createBucket() {
    90. try {
    91. if (!OSSUtil.getOSSClient().doesBucketExist(OSS_BUCKET_NAME)) {//判断是否存在该Bucket,不存在时再重新创建
    92. OSSUtil.getOSSClient().createBucket(OSS_BUCKET_NAME);
    93. }
    94. } catch (Exception e) {
    95. logger.error("{}", "创建Bucket失败,请核对Bucket名称(规则:只能包含小写字母、数字和短横线,必须以小写字母和数字开头和结尾,长度在3-63之间)");
    96. throw new OSSCreateBucketRuntimeException("创建Bucket失败,请核对Bucket名称(规则:只能包含小写字母、数字和短横线,必须以小写字母和数字开头和结尾,长度在3-63之间)");
    97. }
    98. }
    99. /**
    100. * 上传到OSS服务器 如果同名文件会覆盖服务器上的
    101. * @param file 文件
    102. * @param fileDir 上传到OSS上文件的路径
    103. * @return 文件的访问地址
    104. */
    105. private static String uploadFile(MultipartFile file, FileDirType fileDir) {
    106. String fileName = String.format(
    107. "%s.%s",
    108. UUID.randomUUID().toString(),
    109. FilenameUtils.getExtension(file.getOriginalFilename()));
    110. try (InputStream inputStream = file.getInputStream()) {
    111. //创建上传Object的Metadata
    112. ObjectMetadata objectMetadata = new ObjectMetadata();
    113. objectMetadata.setContentLength(inputStream.available());
    114. objectMetadata.setCacheControl("no-cache");
    115. objectMetadata.setHeader("Pragma", "no-cache");
    116. objectMetadata.setContentType(getContentType(FilenameUtils.getExtension("." + file.getOriginalFilename())));
    117. objectMetadata.setContentDisposition("inline;filename=" + fileName);
    118. //上传文件
    119. PutObjectResult putResult = OSSUtil.getOSSClient().putObject(OSS_BUCKET_NAME, fileDir.getDir() + fileName, inputStream, objectMetadata);
    120. return fileName;
    121. } catch (Exception e) {
    122. logger.error("{}", "上传文件失败");
    123. throw new OssPutObjectRuntimeException("上传文件失败");
    124. }
    125. }
    126. /**
    127. * 获得文件路径
    128. * @param fileUrl 文件的URL
    129. * @param fileDir 文件在OSS上的路径
    130. * @return 文件的路径
    131. */
    132. private static String getImgUrl(String fileUrl, FileDirType fileDir) {
    133. if (StringUtils.isEmpty(fileUrl)) {
    134. logger.error("{}", "文件地址为空");
    135. throw new RuntimeException("文件地址为空");
    136. }
    137. String[] split = fileUrl.split("/");
    138. //获取oss图片URL失败
    139. URL url = OSSUtil.getOSSClient().generatePresignedUrl(OSS_BUCKET_NAME, fileDir.getDir() + split[split.length - 1], OSS_URL_EXPIRATION);
    140. if (url == null) {
    141. logger.error("{}", "获取oss文件URL失败");
    142. throw new OSSGeneratePresignedUrlRuntimeException("获取oss文件URL失败");
    143. }
    144. return url.toString();
    145. }
    146. /**
    147. * 判断OSS服务文件上传时文件的contentType
    148. *
    149. * @param FilenameExtension 文件后缀
    150. * @return 后缀
    151. */
    152. private static String getContentType(String FilenameExtension) {
    153. if (FilenameExtension.equalsIgnoreCase("bmp")) {
    154. return "image/bmp";
    155. }
    156. if (FilenameExtension.equalsIgnoreCase("gif")) {
    157. return "image/gif";
    158. }
    159. if (FilenameExtension.equalsIgnoreCase("jpeg") ||
    160. FilenameExtension.equalsIgnoreCase("jpg") ||
    161. FilenameExtension.equalsIgnoreCase("png")) {
    162. return "image/jpeg";
    163. }
    164. if (FilenameExtension.equalsIgnoreCase("html")) {
    165. return "text/html";
    166. }
    167. if (FilenameExtension.equalsIgnoreCase("txt")) {
    168. return "text/plain";
    169. }
    170. if (FilenameExtension.equalsIgnoreCase("vsd")) {
    171. return "application/vnd.visio";
    172. }
    173. if (FilenameExtension.equalsIgnoreCase("pptx") ||
    174. FilenameExtension.equalsIgnoreCase("ppt")) {
    175. return "application/vnd.ms-powerpoint";
    176. }
    177. if (FilenameExtension.equalsIgnoreCase("docx") ||
    178. FilenameExtension.equalsIgnoreCase("doc")) {
    179. return "application/msword";
    180. }
    181. if (FilenameExtension.equalsIgnoreCase("xml")) {
    182. return "text/xml";
    183. }
    184. return "image/jpeg";
    185. }
    186. }

           2、调用工具类的代码:

    1. /**
    2. * 上传文件测试
    3. * @param multipartFile 待上传的文件
    4. * @return 上传在OSS文件的访问路径
    5. * @throws BusinessException 上传异常
    6. */
    7. public String uploadTest(MultipartFile multipartFile) throws BusinessException{
    8. try {
    9. uploadResult = OSSUtil.upload(multipartFile, OSSUtil.FileDirType.ZHANGHAN_TEST);
    10. } catch (Exception e) {
    11. LoggerUtil.logService(LoggerUtil.spManualLoan, "SPManualLoanServiceImpl-submitLoan", "call OSSUtil.upload; Exception:" + e.getMessage());
    12. throw new BusinessException(WrongMessageEnum.EXCEPTION_STORE);
    13. }
    14. return uploadResult;
    15. }

           3、问题&解决:

              (1) 问题:通过URL在浏览器中访问时报如下错:

      

              (2)解决方案:在阿里云的控制台上,进入OSS的设置界面,将Bucket的访问权限由 私有 设置为 公共读


    【总结】

           阿里云现在很多公司都在用,阿里云稳定,安全,相对来说成本更低;给自己更多思考的是如何让项目减少成本,以及阿里云等带来的商业模式。

  • 相关阅读:
    80年代的兄弟,你会什么?
    设计模式单件模式
    大冒险 这注定是部史诗级的探索。。。
    关于重构JS前端框架的失败经验(顺便怀念那些死去的代码)
    JDBC连接数据库类(主要用于存储过程)
    ActiveRecord学习(六):总结
    ASP.NET中常用的文件上传下载方法
    [整理]ASP.NET2.0新特性概述
    关于NHibernate中one to many 的问题
    关注06德国世界杯:比赛日程表
  • 原文地址:https://www.cnblogs.com/jpfss/p/10146505.html
Copyright © 2020-2023  润新知