package com.lcx.test.utils;
import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.Bucket;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.Date;
//import static com.project.lddproject.Authentication.constans.OSSClientConstants.BACKET_NAME;
/**
* 阿里云OSS工具类
* @author Liu...cx..
* @date 2019/11/16 14:10
*/
@Slf4j
@Component
public class AliYunOssUtil {
private static String key;
private static String secret;
/** 形如: http://oss-cn-shenzhen.aliyuncs.com */
private static String endpoint;
/** 提示:官方文档里面介绍,OSSClient可以并发使⽤。即:线程安全。 */
private static OSS ossClient;
//阿里云API的文件夹名称
private static String folder;
/** 重试次数 */
private static int tryTimesUpperLimit = 3;
/** 此参数值随意,但【必须要遵循bucket的命名规则】。此参数主要用于 帮助 判断连接池是否开启着。 */
private static final String IS_CONNECTION_POOL_OPEN_HELPER = "Liu_chunxi";
/**
* 初始化
*
* @param key
* 通行key
* @param secret
* 通行secret
* @param endpoint
* 数据存储区域断点(region)
*/
public static void init(String endpoint, String key, String secret ) {
log.info(" AliYunOssUtil.init been invoked, endpoint -> {}, key -> {}, secret -> {} ",
endpoint, key, secret);
AliYunOssUtil.endpoint = endpoint;
AliYunOssUtil.key = key;
AliYunOssUtil.secret = secret;
initOssClient();
}
/**
* 客户端的初始化
*
* 注:不能判断为null, 当shutdown时,ossClient实例仍然存在
*
* @date 2019/11/18 9:44 之前出现二次上传连接池关闭 下面这个判断逻辑要注释掉
*/
private synchronized static void initOssClient() {
// **********干掉 *************************
//if (isConnectionPoolOpen()) {
// log.info("Connection pool Has been open!");
// return;
// }
// **********干掉 *************************
log.info(" initOssClient been invoked, params endpoint -> {}, key -> {}, "
+ " secret -> {}", endpoint, key, secret);
// ossClient = new OSSClientBuilder().build(endpoint, key, secret);
ossClient = new OSSClient(endpoint, key, secret);
}
/**
* 创建存储空间(如果不存在名为bucketName的存储空间的话)
*
* 注: 存储空间(Bucket)是存储对象(Object)的容器。对象都⾪属于存储空间。
*
* @param bucketName
* 存储空间名
* @return 创建的存储空间对象
*/
public static Bucket createBucketIfNecessary(String bucketName) {
if (ossClient.doesBucketExist(bucketName)) {
return ossClient.getBucketInfo(bucketName).getBucket();
}
// 如果不存在, 那么直接创建
Bucket bucket = ossClient.createBucket(bucketName);
log.info(" created Bucket -> {}", JSON.toJSONString(bucket));
return bucket;
}
/**
* 直接创建存储空间
*
* 注: 存储空间(Bucket)是存储对象(Object)的容器。对象都⾪属于存储空间。
*
* @param bucketName
* 存储空间名
*/
private static void createBucket(String bucketName) {
Bucket bucket = ossClient.createBucket(bucketName);
log.info(" created Bucket -> {}", JSON.toJSONString(bucket));
}
/**
* 简单文件上传
*
* 注:同一个bucketName下,objectName不要一样,否者会覆盖前面的文件
* 追注:对某个Object而言,其的objectName即为其key, 而key需要具有唯一性
*
* @param bucketName
* bucket介绍:存储空间是您⽤于存储对象(Object)的容 器,所有的对象都必须⾪属于某个存储空间。
* @param objectName
* 自定义上传后的文件名
* @param inputStream
* (流的形式)Object
*
*/
public static void uploadFileByInputStream(String bucketName,
String objectName,
InputStream inputStream) {
uploadFileByInputStream(bucketName, objectName, inputStream, 1);
}
/**
* 简单文件上传
* 注:同一个bucketName下,objectName不要一样,否者会覆盖前面的文件
* 追注:对某个Object而言,其的objectName即为其key, 而key需要具有唯一性
*
* @param bucketName
* bucket介绍:存储空间是您⽤于存储对象(Object)的容 器,所有的对象都必须⾪属于某个存储空间。
* @param objectName
* 自定义上传后的文件名
* @param inputStream
* (流的形式)Object
* @param tryTimes
* 第几次调用
*/
private static void uploadFileByInputStream(String bucketName,
String objectName,
InputStream inputStream,
int tryTimes) {
PutObjectResult result;
try {
// 如果存储空间不存在,那么直接创建
if (!ossClient.doesBucketExist(bucketName)) {
createBucket(bucketName);
}
result = ossClient.putObject(bucketName, objectName, inputStream);
log.info(" uploadFileByInputStream result is -> {}", JSON.toJSONString(result));
} catch (Exception e) {
if (isConnectionPoolOpen(e) || tryTimes > tryTimesUpperLimit) {
throw e;
}
// 如果客户端已关闭,那么再次初始化即可
initOssClient();
uploadFileByInputStream(bucketName, objectName, inputStream, ++tryTimes);
}
// 关闭OSSClient。
ossClient.shutdown();
}
/**
* 连接池是否开启(即:连接池是否还未shutdown)
*
* @param e
* 客户端异常
* @return 连接池是否仍然开启着
* -true,连接池开启着(即:连接池未关闭),
* -false连接池已关闭
*/
private static boolean isConnectionPoolOpen(Exception e) {
String message = e.getMessage();
if (message == null) {
return true;
}
return !message.contains("Connection pool shut down");
}
/**
* 连接池是否开启(即:连接池是否还未shutdown)
*
* @return 连接池是否仍然开启着
* -true,连接池开启着(即:连接池未关闭),
* -false连接池已关闭
*/
private static boolean isConnectionPoolOpen() {
if (ossClient == null) {
return false;
}
try {
ossClient.doesBucketExist(IS_CONNECTION_POOL_OPEN_HELPER);
} catch (Exception e) {
return isConnectionPoolOpen(e);
}
return true;
}
/**
* 关闭客户端
*
* 注:此方法只是提供提供出来。因为是多线程共用的同一个客户端,
* 所以一般情况下不关闭客户端即可。
*/
public static void closeClient() {
ossClient.shutdown();
}
/**
* 获取文件可访问URL
*
* @param bucketName
* 文件所在的bucket名
* @param key
* 文件的key(即:文件上传时,自定义的文件名objectName)
* @param expirationTime
* 此连接的有效时长(单位毫秒)
* @return 文件的URL
* @date 2019/9/8 2:34
*/
public static String getFileUrl(String bucketName, String key, long expirationTime){
String url = getFileUrl(bucketName, key, expirationTime, 1);
log.info(" this file's address is -> {}", url);
return url;
}
/**
* 获取文件可访问URL
*
* @param bucketName
* 文件所在的bucket名
* @param key
* 文件的key(即:文件上传时,自定义的文件名objectName)
* @param expirationTime
* 此连接的有效时长(单位毫秒)
* @param tryTimes
* 第几次调用
*
* @return 文件的URL
*/
private static String getFileUrl(String bucketName, String key, long expirationTime, int tryTimes){
long now = System.currentTimeMillis();
try {
return ossClient.generatePresignedUrl(bucketName, key, new Date(now + expirationTime)).toString();
} catch (Exception e) {
if (isConnectionPoolOpen(e) || tryTimes > tryTimesUpperLimit) {
throw e;
}
// 如果客户端已关闭,那么再次初始化即可
initOssClient();
return getFileUrl(bucketName, key, expirationTime, ++tryTimes);
}
}
/**
* main直接测试
*/
/* public static void main(String[] args) throws FileNotFoundException {
init("http://oss-cn-shenzhen.aliyuncs.com", "XXXX", "XXXX");
isConnectionPoolOpen();
String fileurl = "timg.jpg";
InputStream is = new FileInputStream("C:\\Users\\Administrator\\Desktop\\图片\\"+fileurl);
uploadFileByInputStream("lcx-0316", fileurl, is);
long oneHundredYears = 24 * 60 * 60 * 1000L;
System.out.println(
getFileUrl(BACKET_NAME, fileurl, oneHundredYears)
);
}*/
}
因为在项目中许多地方有用到上传,所以单独拆出复用
package com.project.lddproject.Authentication.utils;
import com.project.lddproject.Authentication.constans.OSSClientConstants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import static com.project.lddproject.Authentication.constans.OSSClientConstants.FILESIZE;
/**
* @Author: Liuchunxi
* @Description: 图片上传【OSS图像存储上传抽取】
* @Date: 2019/11/17 16:12
* @Modified:
*/
@Component
public class CommonUpload {
@Value("${aliyun.oss.key}")
private String ACCESS_KEY_ID;
@Value("${aliyun.oss.secret}")
private String ACCESS_KEY_SECRET;
@Value("${aliyun.oss.endpoint}")
private String ENDPOINT;
@Value("${aliyun.oss.bucket-name}")
private String BACKET_NAME;
public String uploadFile(MultipartFile file,String objectAttendance) throws IOException {
AliYunOssUtil.init(ENDPOINT,ACCESS_KEY_ID,ACCESS_KEY_SECRET);
// 图片大小限制于上一步拦截
InputStream is = file.getInputStream();
// 时间戳 + 随机数, 防止文件重名
SecureRandom random = new SecureRandom();
String fileName = file.getOriginalFilename();
//获取文件后缀
String suffix = fileName.substring(fileName.lastIndexOf("."));
//在OSS Bucket下 以日期为界限创建虚拟文件夹分类保存文件(存在直接插入,不存在的话会创建后插入)
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//因为里面要嵌套一个虚拟文件夹,这里是认证相关的图片上传所以写死auth
// String folder = "auth/"+sdf.format(calendar.getTime()) + "/";
String folder = objectAttendance + "/" + sdf.format(calendar.getTime()) + "/";
//(使用这个的话就不用添加后缀了,fileName有后缀)
// String newFileName = "cmd/"+System.currentTimeMillis() + "_" + random.nextInt(1000) + "_" + fileName;
//新建 上传OSS的文件名 random.nextInt(1000) 为时间戳+随机数截取三位
String newFileName = folder + System.currentTimeMillis() + "_" + random.nextInt(1000) + suffix ;
AliYunOssUtil.uploadFileByInputStream(BACKET_NAME,newFileName,is);
long oneHundredYears = 24*60*60*1000L;
String fileUrl = AliYunOssUtil.getFileUrl(BACKET_NAME, newFileName, oneHundredYears);
file.getInputStream().close();
return fileUrl;
}
}
使用到的依赖:
<!--Oss--> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>2.8.1</version> </dependency>