阿里的oss对象存储服务器,提供了存储空间管理,文件上传下载,文件管理,音频与图像处理等常用操作,基本满足中小企业对于文件处理的需求,但官方提供的Api接口都是简版,demo级别的,并不适合直接使用,故在下在工作之余,对其常用Api进行封装,集成为OssUtils工具类。
阿里官网推举用子access_key_id和access_key_secrt,而不采用全局配置
/**
* 对象存储Oss工具类
*
* @author sunyiran
* @date 2018-11-07
*/
@Slf4j
public class OssUtils {
/**
* 连接URL
*/
private static final String ENDPOINT = "XXXX";
/**
* 实例ID
*/
private static final String ACCESS_KEY_ID = "XXXX";
/**
* 实例密钥
*/
private static final String ACCESS_KEY_SECRET = "XXXX";
/**
* 默认存储空间
*/
private static final String DEFAULT_BUCKETNAME = "syr-test";
/**
* 默认图片格式
*/
private static final String DEFAULT_IMAGE_TYPE = "png";
/**
* 默认压缩比例
*/
private static final int DEFAULT_SCALE = 10;
/**
* 默认水印文字
*/
private static final String DEFAULT_CONTENT = "我的水印";
/**
* 连接实例
*/
private static final OSSClient OSS_CLIENT;
private static final String SUCCESS = "success";
private static final String FAILED = "failed";
static {
// 创建ClientConfiguration实例,按照您的需要修改默认参数。
ClientConfiguration conf = new ClientConfiguration();
// 关闭CNAME选项。
conf.setSupportCname(false);
OSS_CLIENT = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);
}
}
采用不同的存储空间可以讲文件分类别存储,它具有创建,列举,获取详情,删除等操作。
/**
* 存储空间管理工具
*/
public static class BucketUtils {
/**
* 创建新的存储空间
*
* @param bucketName
*/
public static String createBucket(String bucketName) {
CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
// 设置存储空间的权限为公共读,默认是私有。
createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
// 设置存储空间的存储类型为低频访问类型,默认是标准类型。
createBucketRequest.setStorageClass(StorageClass.IA);
try {
OSS_CLIENT.createBucket(createBucketRequest);
return SUCCESS;
} catch (OSSException e) {
log.error(e.getMessage());
return FAILED;
}
}
/**
* 列举存储空间
*
* @param bucketPrefix
*/
public static List listBucket(String bucketPrefix) {
ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
// 列举指定前缀的存储空间。
if (StringUtils.isNotBlank(bucketPrefix)) {
listBucketsRequest.setPrefix(bucketPrefix);
}
try {
return OSS_CLIENT.listBuckets(listBucketsRequest).getBucketList();
} catch (OSSException e) {
log.error(e.getMessage());
return null;
}
}
/**
* 获取存储空间信息
*
* @param bucketName
*/
public static Map getBucketInfo(String bucketName) {
//判断空间是否存在
boolean exists = OSS_CLIENT.doesBucketExist(bucketName);
if (!exists) {
return null;
}
// 存储空间的信息包括地域(Region或Location)、创建日期(CreationDate)、拥有者(Owner)、权限(Grants)等。
Map result = new HashMap<>(4);
BucketInfo info = OSS_CLIENT.getBucketInfo(bucketName);
// 获取地域。
result.put("location", info.getBucket().getLocation());
// 获取创建日期。
result.put("createTime", new SimpleDateFormat("yyyy-MM-dd HH:ss").format(info.getBucket().getCreationDate()));
// 获取拥有者信息。
result.put("owner", info.getBucket().getOwner());
// 获取权限信息。';;
AccessControlList acl = OSS_CLIENT.getBucketAcl(bucketName);
result.put("authority", acl.toString());
return result;
}
/**
* 删除存储空间
*
* @param bucketName
*/
public static boolean deleteBucket(String bucketName) {
//判断空间是否存在
boolean exists = OSS_CLIENT.doesBucketExist(bucketName);
if (!exists) {
return false;
}
// 删除存储空间。
OSS_CLIENT.deleteBucket(bucketName);
return true;
}
}
阿里提供了流传输,分片传输,断点续传,带进度条的等上传操作
/**
* 文件上传工具
*/
public static class UploadUtils {
/**
* 默认上传
*
* @param file
* @return
* @throws IOException
*/
public static String simpleUpload(MultipartFile file) {
try {
return upload(file, DEFAULT_BUCKETNAME);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 自定义存储空间上传配置
*
* @param file
* @return
* @throws IOException
*/
public static String upload(MultipartFile file, String bucketName) throws IOException {
String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString();
// 上传文件流。
PutObjectResult putObject = OSS_CLIENT.putObject(bucketName, putName, file.getInputStream());
String errorResponseAsString = putObject.getResponse().getErrorResponseAsString();
if (StringUtils.isNotBlank(errorResponseAsString)) {
return errorResponseAsString;
}
System.out.println(errorResponseAsString);
return putName;
}
/**
* 合并文件(主要用于文本对象)
*
* @param bucketName
* @param contentType
* @param content
* @return
*/
public static String mergeContent(String bucketName, String contentType, InputStream... content) {
ObjectMetadata meta = new ObjectMetadata();
// 指定上传的内容类型。
meta.setContentType(contentType);
//设置文件名
String fileName = UUID.randomUUID().toString();
AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, fileName, content[0], meta);
AppendObjectResult objectResult = null;
try {
for (int i = 0; i < content.length; i++) {
if (i == 0) {
appendObjectRequest.setPosition(0L);
objectResult = OSS_CLIENT.appendObject(appendObjectRequest);
} else {
appendObjectRequest.setPosition(objectResult.getNextPosition());
appendObjectRequest.setInputStream(content[i]);
OSS_CLIENT.appendObject(appendObjectRequest);
}
}
return fileName;
} catch (OSSException e) {
log.error(e.getMessage());
return FAILED;
}
}
/**
* 分片上传
*
* @param bucketName
* @param file
* @return
* @throws IOException
*/
public static String shardUpload(String bucketName, MultipartFile file) throws IOException {
//设定文件名
String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString();
/* 步骤1:初始化一个分片上传事件。
*/
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, putName);
InitiateMultipartUploadResult result = OSS_CLIENT.initiateMultipartUpload(request);
// 返回uploadId,它是分片上传事件的唯一标识,您可以根据这个ID来发起相关的操作,如取消分片上传、查询分片上传等。
String uploadId = result.getUploadId();
/* 步骤2:上传分片。
*/
// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
List partETags = new ArrayList<>();
// 计算文件有多少个分片。
final long partSize = 1024 * 1024L;
long fileLength = file.getSize();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
// 遍历分片上传。
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
InputStream instep = file.getInputStream();
// 跳过已经上传的分片。
instep.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(putName);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInputStream(instep);
// 设置分片大小。除了最后一个分片没有大小限制,其他的分片最小为100KB。
uploadPartRequest.setPartSize(curPartSize);
// 设置分片号。每一个上传的分片都有一个分片号,取值范围是1~10000,如果超出这个范围,OSS将返回InvalidArgument的错误码。
uploadPartRequest.setPartNumber(i + 1);
// 每个分片不需要按顺序上传,甚至可以在不同客户端上传,OSS会按照分片号排序组成完整的文件。
UploadPartResult uploadPartResult = OSS_CLIENT.uploadPart(uploadPartRequest);
// 每次上传分片之后,OSS的返回结果会包含一个PartETag。PartETag将被保存到partETags中。
partETags.add(uploadPartResult.getPartETag());
}
/* 步骤3:完成分片上传。
*/
// 排序。partETags必须按分片号升序排列。
partETags.sort(Comparator.comparingInt(PartETag::getPartNumber));
// 在执行该操作时,需要提供所有有效的partETags。OSS收到提交的partETags后,会逐一验证每个分片的有效性。当所有的数据分片验证通过后,OSS将把这些分片组合成一个完整的文件。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, putName, uploadId, partETags);
OSS_CLIENT.completeMultipartUpload(completeMultipartUploadRequest);
return putName;
}
/**
* 带进度条上传
*
* @param bucketName
* @param file
* @return
*/
public static String uploadWithProgress(String bucketName, MultipartFile file) throws IOException {
String putName = file.getOriginalFilename() + "_" + UUID.randomUUID().toString();
try {
OSS_CLIENT.putObject(new PutObjectRequest(bucketName, putName, file.getInputStream()).withProgressListener(new PutObjectProgressListener()));
return putName;
} catch (OSSException e) {
log.error(e.getMessage());
return FAILED;
}
}
}
/**
* 文件下载工具类
*/
public static class DownloadUtils {
/**
* 默认下载
*
* @param fileUrl
* @return
*/
public static byte[] simpleDownload(String fileUrl) {
try {
download(DEFAULT_BUCKETNAME, fileUrl);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static byte[] download(String bucketName, String fileUrl) throws IOException {
// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
OSSObject ossObject = OSS_CLIENT.getObject(bucketName, fileUrl);
return ossObjectToByte(ossObject);
}
}
/**
* 文件管理
*/
public static class FileManager {
/**
* 判断文件是否存在
*
* @param bucketName
* @param fileUrl
* @return
*/
public static boolean isExist(String bucketName, String fileUrl) {
// 判断文件是否存在。
return OSS_CLIENT.doesObjectExist(bucketName, fileUrl);
}
/**
* 获取文件信息
*
* @param bucketName
* @param fileUrl
* @return
*/
public static Map getFileInfo(String bucketName, String fileUrl) {
// 获取文件元信息。
ObjectMetadata metadata = OSS_CLIENT.getObjectMetadata(bucketName, fileUrl);
return metadata.getRawMetadata();
}
/**
* 获取指定前缀的文件
*
* @param bucketName
* @param filePrefix
* @return
*/
public static List listFile(String bucketName, String filePrefix) {
// 列举包含指定前缀的文件。默认列举100个文件。
ObjectListing objectListing = OSS_CLIENT.listObjects(new ListObjectsRequest(bucketName).withPrefix(filePrefix));
return objectListing.getObjectSummaries();
}
/**
* 删除文件
*
* @param bucketName
* @param fileUrl
* @return
*/
public static String delete(String bucketName, String fileUrl) {
// 删除文件。
try {
OSS_CLIENT.deleteObject(bucketName, fileUrl);
return SUCCESS;
} catch (OSSException e) {
log.error(e.getMessage());
return FAILED;
}
}
}
/**
* 图片处理工具类
*/
public static class ImageUtils {
public static void test() {
// // 缩放
// String style = "image/resize,m_fixed,w_100,h_100";
// GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-resize.jpg"));
//// 水印
// style = "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-watermark.jpg"));
//// 格式转换
// style = "image/format,png";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-format.png"));
//// 获取图片信息
// style = "image/info";
// request = new GetObjectRequest(bucketName, objectName);
// request.setProcess(style);
// ossClient.getObject(request, new File("example-info.txt"));
//// 关闭OSSClient。
// ossClient.shutdown();
}
/**
* 图片等比例缩放
*
* @param scale
* @param bucketName
* @param fileUrl
* @return
*/
public static byte[] resize(int scale, String bucketName, String fileUrl) {
// 缩放
String style = "image/resize,p_" + scale;
GetObjectRequest request = new GetObjectRequest(bucketName, fileUrl);
request.setProcess(style);
OSSObject object = OSS_CLIENT.getObject(request);
return ossObjectToByte(object);
}
/**
* 添加水印
*
* @param content
* @param bucketName
* @param fileUrl
* @return
*/
public static byte[] waterMark(String content, String bucketName, String fileUrl) {
// 水印
String style = null;
try {
style = "image/watermark,text_" + Base64.getEncoder().encodeToString(content.getBytes("utf8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
GetObjectRequest request = new GetObjectRequest(bucketName, fileUrl);
request.setProcess(style);
OSSObject object = OSS_CLIENT.getObject(request);
return ossObjectToByte(object);
}
}
附本地图片处理方案:
/**
* 等比例压缩图片
*
* @param scale 缩放比例
* @param targetPath 被处理图片路径
* @param path 处理后图片存放路径
* @return
* @throws IOException
*/
public static File changeImgSize(double scale, String targetPath, String path) throws IOException {
BufferedImage img = ImageIO.read(getInputStream(targetPath));
int w = (int) (img.getWidth() * scale);
int h = (int) (img.getHeight() * scale);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_USHORT_555_RGB);
image.getGraphics().drawImage(img, 0, 0, w, h, null);
File destFile = new File(getPath(path));
FileOutputStream out = new FileOutputStream(destFile);
// 可以正常实现bmp、png、gif转jpg
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(image);
out.close();
return destFile;
}
/**
* @author sunyiran
* @date 2018-11-07
*/
@RestController("/file")
public class FileController {
/**
* 文件下载
* @param fileUrl
* @return
*/
@PostMapping("/download")
public static ResponseEntity download(String fileUrl) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Content-Disposition", String.format("attachment; filename=\"%s\"", "test.jpg"));
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
byte[] download = OssUtils.DownloadUtils.simpleDownload(fileUrl);
if (download == null) {
return null;
}
return ResponseEntity.ok().headers(headers)
.contentLength(download.length).contentType(MediaType.parseMediaType("application/octet-stream"))
.body(download);
}
/**
* 上传文件
*
* @param file
* @return
*/
@PostMapping("/upload")
public static String upload(MultipartFile file) {
String fileUrl = OssUtils.UploadUtils.simpleUpload(file);
return fileUrl;
}
}
九、工具类下载路径:
传送门