本篇文章希望你先看完官方的API了解一下OSS基本语法和概念再来应该比较容易懂。
- 这里给出官方的OSS API:OSS API
- 官方SDK:点击打开链接
- 官方帮助文档:点击打开链接
- OSS GitHub地址:点击打开链接
- OSS java 依赖jar包地址:点击下载
- 参考文章:http://blog.csdn.net/github_36086968/article/details/53113274
2018-02-03 更新,优化web直传代码,加入注释,新增生成文件夹、移动端临时上传下载、生成签名url
2017-12-21 更新,修复上传图片OSS报错,仍会返回url的BUG,操作是修改uploadFile()和uploadWebFile()方法,在catch打印日志后return null。
2017-11-29 更新,加入web直传需要的 StsServiceUtil,获取文件名的改为截取accessUrl部分,配置变量加入示例,测试类加入baseUrl,更简洁。
一、上传规范
主要用到了aliyun-sdk-oss,aliyun-java-sdk-core,aliyun-java-sdk-sts,joda-time等包。
1.上传图片主要分为本地文件上传(文件流方式)和网络文件上传(如获取微信头像)上传
1)上传本地文件需要参数有InputStraem流、directory目录和fileName文件名,目录是在项目底下的目录,由于不建议直接在项目oss文件夹直接上传图片,所以目录是一定要传的。当传入目录为空时,会直接取文件名,一般是更新和替换的时候传null。
上传自定义格式本地文件用upload(),png格式图片用uploadImage()方法,mp4格式视频用uploadVedio()方法,文件名已封装,如果想自己生成文件名直接调用底层uploadFile()方法。
2)上传网络图片需要参数有fileUrl文件地址、directory目录和fileName文件名,png格式图片用uploadWebImage()方法,文件名已封装,如果想自定义文件名直接调用底层uploadWebFile()方法。
2.如果想更新文件有两种方式,一种是直接更新文件,只更新内容,不更新文件名和文件地址。另一种是替换文件,删除原文件并上传新文件,文件名和地址同时替换。
参数传入InputStream流和fileUrl原文件名。
1)直接更新文件,这个可能存在浏览器原数据缓存,调用updateFile()方法。
2)删除替换文件,由于地址更好,解决缓存问题 ,调用replaceFile()方法。建议更新图片用这种方式。
3.查询文件是否存在
参数传入fileUrl文件地址,通过调用doesObjectExist方法判断返回值。
4.删除文件,分为单个删除和批量删除
参数传入fileUrl文件地址或fileUrls文件地址集合
1.单个上传,调用deleteObject方法。
2.批量上传,调用deleteObjects()方法和deleteBatchObject()方法,deleteObjects()方法主要是用在同一个endpoint和bucketName ,底层是调用OSS的deleteObjects()方法,速度较快。
而deleteBatchObject()还适用于不同的endPoint和bucketName ,底层调用的是我们封装的deleteObject()方法,由于还是一个个去删,速度较慢。
5.Web直传获取签名
注意:为了浏览安全,必须为bucket设置CORS。
主要用于网页端上传时,网页端向服务端请求签名,然后直接上传,不用对服务端产生压力。而且安全可靠。但是这个例子有一个特点,就是用户上传了多少文件,用户上传了什么文件,用户后端程序并不能马上知道,如果想实时知晓用户上传了什么文件,可以采用上传回调。本例子无法实现分片与断点。
详情:https://help.aliyun.com/document_detail/31926.html
http://172.16.1.98:83/wordpress/2017/08/30/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E9%85%8D%E5%90%88web%E7%AB%AF%E4%B8%8A%E4%BC%A0%E8%A7%86%E9%A2%91/
http://172.16.1.98:83/wordpress/2017/08/23/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%AD%BE%E5%90%8D%E5%90%8E%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%88%B0oss/
二、对文件的存储操作
注意需要修改配置!!!
注意需要修改配置!!!
注意需要修改配置!!!
package com.lemo.face.util.oss; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.aliyun.oss.OSSClient; import com.aliyun.oss.common.utils.BinaryUtil; import com.aliyun.oss.common.utils.IOUtils; import com.aliyun.oss.model.DeleteObjectsRequest; import com.aliyun.oss.model.GeneratePresignedUrlRequest; import com.aliyun.oss.model.GetObjectRequest; import com.aliyun.oss.model.ListObjectsRequest; import com.aliyun.oss.model.MatchMode; import com.aliyun.oss.model.OSSObjectSummary; import com.aliyun.oss.model.ObjectListing; import com.aliyun.oss.model.ObjectMetadata; import com.aliyun.oss.model.PolicyConditions; import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.RandomStringUtils; import org.joda.time.DateTime; import org.joda.time.LocalDateTime; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Objects; import lombok.extern.slf4j.Slf4j; /** * @author 杨小华 * @desc 阿里文件云存储管理类 * @create 2017/11/27 14:25 **/ @Slf4j public class OSSClientUtil { static final String ACCESS_KEY_ID = ""; static final String ACCESS_KEY_SECRET = ""; /** * 用户的存储空间(bucket)名称 */ static final String BUCKET_NAME = ""; /** * 对应的映射域名 */ private static final String ACCESS_URL = "http://test.rrzuzu.com/"; /** * 用户的存储空间所在数据中心的访问域名 */ private static final String ENDPOINT = "oss-cn-hangzhou.aliyuncs.com"; /** * 指定项目文件夹 */ private static final String PIC_LOCATION = "face/"; /** * 加密密钥 */ private static final String KEY = "biaoqing"; private static OSSClient ossClient; /** * @desc 静态初始化ossClient * @author 杨小华 * @create 2017/11/25 12:44 **/ static { ossClient = new OSSClient(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET); } /** * @desc 上传自定义格式 * @author 杨小华 * @create 2017/11/24 11:09 **/ public static String upload(InputStream is, String directory, String fileType) { String fileName = getFileName() + "." + fileType; return uploadFile(is, directory, fileName); } /** * @desc 上传视频指定mp4格式 * @author 杨小华 * @create 2017/11/22 15:00 **/ public static String uploadVideo(InputStream is, String directory) { String fileName = getFileName() + ".mp4"; return uploadFile(is, directory, fileName); } /** * @desc 上传图片指定png格式 * @author 杨小华 * @create 2017/11/22 14:59 **/ public static String uploadImage(InputStream is, String directory) { String fileName = getFileName() + ".png"; return uploadFile(is, directory, fileName); } /** * @desc 上传网络图片指定png格式 * @author 杨小华 * @create 2017/11/25 13:37 **/ public static String uploadWebImage(String fileUrl, String directory) { String fileName = getFileName() + ".png"; return uploadWebFile(fileUrl, directory, fileName); } /** * @desc 上传本地文件(文件流上传) * @author 杨小华 * @create 2017/11/23 19:57 **/ public static String uploadFile(InputStream is, String directory, String fileName) { String key = PIC_LOCATION + directory + "/" + fileName; if (Objects.isNull(directory)) { key = fileName; } try { ObjectMetadata objectMetadata = getObjectMetadata(is.available()); ossClient.putObject(BUCKET_NAME, key, is, objectMetadata); } catch (Exception e) { log.error(e.getMessage()); return null; } finally { IOUtils.safeClose(is); } return ACCESS_URL + key; } /** * @desc 上传网络图片 * @author 杨小华 * @create 2017/11/24 15:43 **/ public static String uploadWebFile(String fileUrl, String directory, String fileName) { String key = PIC_LOCATION + directory + "/" + fileName; InputStream is = null; try { Integer length = new URL(fileUrl).openConnection().getContentLength(); is = new URL(fileUrl).openStream(); ObjectMetadata objectMetadata = getObjectMetadata(length); ossClient.putObject(BUCKET_NAME, key, is, objectMetadata); } catch (Exception e) { log.error(e.getMessage()); return null; } finally { IOUtils.safeClose(is); } return ACCESS_URL + key; } /** * @desc 更新文件:只更新内容,不更新文件名和文件地址。 (因为地址没变,可能存在浏览器原数据缓存,不能及时加载新数据,例如图片更新,请注意) * @author 杨小华 * @create 2017/11/23 20:40 **/ public static String updateFile(InputStream is, String fileUrl) { String key = getFileNameByUrl(fileUrl); return uploadFile(is, null, key); } /** * @desc 替换文件:删除原文件并上传新文件,文件名和地址同时替换 解决原数据缓存问题,只要更新了地址,就能重新加载数据) * @author 杨小华 * @create 2017/11/24 14:19 **/ public static String replaceFile(InputStream is, String fileUrl) { boolean flag = deleteObject(fileUrl); String fileName = getFileNameByUrl(fileUrl); if (!flag) { return null; } return uploadFile(is, null, fileName); } /** * @desc 查询文件是否存在 * @author 杨小华 * @create 2017/11/24 10:09 **/ public static boolean doesObjectExist(String key) { boolean result = false; try { //如果带http,提取key值 if (key.indexOf("http") != -1) { key = getFileNameByUrl(key); } result = ossClient.doesObjectExist(BUCKET_NAME, key); } catch (Exception e) { log.error(e.getMessage()); } return result; } /** * @desc 删除Object。 注意:以下所有删除如果文件不存在返回的是true,如果需要先判断是否存在先调用doesObjectExist()方法 * @author 杨小华 * @create 2017/11/24 10:06 **/ public static boolean deleteObject(String fileUrl) { try { String key = getFileNameByUrl(fileUrl); ossClient.deleteObject(BUCKET_NAME, key); } catch (Exception e) { log.error(e.getMessage()); return false; } return true; } /** * @desc 批量删除object(适用于相同的endpoint和bucketName) * @author 杨小华 * @create 2017/11/24 10:02 **/ public static int deleteObjects(List<String> fileUrls) { int count = 0; List<String> keys = getFileNamesByUrl(fileUrls); try { // 删除Objects DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(BUCKET_NAME); deleteRequest.withKeys(keys); count = ossClient.deleteObjects(deleteRequest).getDeletedObjects().size(); } catch (Exception e) { log.error(e.getMessage()); } return count; } /** * @desc 批量文件删除(较慢, 适用于不同endpoint和bucketName) * @author 杨小华 * @create 2017/11/24 13:03 **/ public static int deleteBatchObject(List<String> fileUrls) { int count = 0; for (String url : fileUrls) { if (deleteObject(url)) { count++; } } return count; } /** * @desc web直传获取签名 * @author 杨小华 * @create 2017/9/11 13:01 **/ public static Map<String, Object> getWebSign(String callbackUrl, int seconds) { Map<String, Object> data = Maps.newHashMap(); // 存储目录 String dir = PIC_LOCATION + "web/" + getDirectory(); //回调内容 Map<String, String> callback = Maps.newHashMap(); callback.put("callbackUrl", callbackUrl); callback.put("callbackBody", "filename=${object}&size=${size}&mimeType=${mimeType}&height" + "=${imageInfo.height}&width=${imageInfo.width}"); callback.put("callbackBodyType", "application/x-www-form-urlencoded"); //签名有效期30秒过期 Date expiration = DateTime.now().plusSeconds(seconds).toDate(); // 提交节点 String host = "http://" + BUCKET_NAME + "." + ENDPOINT; try { PolicyConditions policyConds = new PolicyConditions(); // 设置上传文件的大小限制 policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); //指定此次上传的文件名必须是dir变量的值开头 policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); //policy String policy = BinaryUtil.toBase64String(postPolicy.getBytes("utf-8")); //签名 String signature = ossClient.calculatePostSignature(postPolicy); //回调 String callbackData = BinaryUtil.toBase64String(callback.toString().getBytes("utf-8")); data.put("policy", policy); data.put("signature", signature); data.put("callback", callbackData); data.put("dir", dir); data.put("accessKeyId", ACCESS_KEY_ID); data.put("accessUrl", ACCESS_URL); data.put("host", host); data.put("expire", expiration); } catch (Exception e) { log.error(e.getMessage(), e); return null; } return data; } /** * 移动端临时授权上传 * * @return java.util.Map<java.lang.String,java.lang.Object> * @author 杨小华 * @date 2018/1/29 14:11 * @since 1.0.0 */ public static Map<String, Object> getSTSWrite() { Map<String, Object> data = Maps.newHashMap(); // 设置文件目录 String folder = PIC_LOCATION + "app/" + getDirectory(); //权限验证 AssumeRoleResponse.Credentials credentials = STSUtil.createSTSForPutObject(folder); Preconditions.checkState(Objects.nonNull(credentials), "权限获取失败,请重试"); AssumeRoleResponse.Credentials encryptCredentials = DESUtil.encrypt(credentials, KEY); //完整文件名 data.put("oss", encryptCredentials); data.put("folder", folder); data.put("endpoint", ENDPOINT); data.put("buckName", BUCKET_NAME); data.put("accessUrl", ACCESS_URL); return data; } /** * 移动端临时授权下载 * * @return java.util.Map<java.lang.String,java.lang.Object> * @author 杨小华 * @date 2018/1/31 15:33 * @since 1.0.0 */ public static Map<String, Object> getSTSRead() { Map<String, Object> data = Maps.newHashMap(); //权限验证 AssumeRoleResponse.Credentials credentials = STSUtil.createSTSForReadOnly(); Preconditions.checkState(Objects.nonNull(credentials), "权限获取失败,请重试"); AssumeRoleResponse.Credentials encryptCredentials = DESUtil.encrypt(credentials, KEY); //完整文件名 data.put("oss", encryptCredentials); data.put("endpoint", ENDPOINT); data.put("buckName", BUCKET_NAME); return data; } /** * 私有型bucket,生成签名URL * * @param key 表情地址,如face/zip/test.zip * @param seconds 多少秒后过期 * @return java.lang.String * @author 杨小华 * @date 2018/2/2 14:32 * @since 1.0.0 */ public static String getSignUrl(String key, int seconds) { //如果key值不存在 Preconditions.checkArgument(doesObjectExist(key), "key值不存在"); Date expire = DateTime.now().plusSeconds(seconds).toDate(); GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(BUCKET_NAME, key); generatePresignedUrlRequest.setExpiration(expire); URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest); return url.toString(); } /** * 单个下载文件 * * @param key 文件key值 * @param fileUrl 目标文件路径名称 * @return boolean * @author 杨小华 * @date 2018/2/2 18:08 * @since 1.0.0 */ public static boolean getObject(String key, String fileUrl) { ObjectMetadata object = ossClient.getObject(new GetObjectRequest(BUCKET_NAME, key), new File(fileUrl)); if (Objects.nonNull(object)) { return true; } return false; } /** * 批量下载文件 * * @param preFix 下载某个文件夹中的所有 * @param dir 目标目录 * @return java.lang.String * @author 杨小华 * @date 2018/2/2 17:33 * @since 1.0.0 */ public static String listObject(String preFix, String dir) { // 构造ListObjectsRequest请求 ListObjectsRequest listObjectsRequest = new ListObjectsRequest(BUCKET_NAME); //Delimiter 设置为 “/” 时,罗列该文件夹下的文件 listObjectsRequest.setDelimiter("/"); //Prefix 设为某个文件夹名,罗列以此 Prefix 开头的文件 listObjectsRequest.setPrefix(preFix); ObjectListing listing = ossClient.listObjects(listObjectsRequest); //如果改目录下没有文件返回null if (CollectionUtils.isEmpty(listing.getObjectSummaries())) { return null; } // 取第一个目录的key File file = new File(dir + listing.getObjectSummaries().get(0).getKey()); //判断文件所在本地路径是否存在,若无,新建目录 File fileParent = file.getParentFile(); if (!fileParent.exists()) { fileParent.mkdirs(); } // 遍历所有Object:目录下的文件 for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) { //Bucket中存储文件的路径 String key = objectSummary.getKey(); //下载object到文件 ossClient.getObject(new GetObjectRequest(BUCKET_NAME, key), file); } return file.getParent(); } /** * @desc 生成文件名 * @author 杨小华 * @create 2017/11/24 11:15 **/ public static String getFileName() { return LocalDateTime.now().toString("yyyyMMddHHmmssSSS_") + RandomStringUtils .randomNumeric(6); } /** * 生成目录 * * @return java.lang.String * @author 杨小华 * @date 2018/1/29 19:00 * @since 1.0.0 */ public static String getDirectory() { return LocalDateTime.now().toString("yyyy-MM-dd"); } /** * @desc 根据url获取fileName * @author 杨小华 * @create 2017/11/23 20:40 **/ private static String getFileNameByUrl(String fileUrl) { int beginIndex = fileUrl.indexOf(ACCESS_URL); //针对单个图片处理的图片 int endIndex = fileUrl.indexOf("?"); //针对使用模板图片处理的图片 int endIndex2 = fileUrl.indexOf("@!"); if (beginIndex == -1) { return null; } if (endIndex != -1) { return fileUrl.substring(beginIndex + ACCESS_URL.length(), endIndex); } if (endIndex2 != -1) { return fileUrl.substring(beginIndex + ACCESS_URL.length(), endIndex2); } return fileUrl.substring(beginIndex + ACCESS_URL.length()); } /** * @desc 根据url获取fileNames集合 * @author 杨小华 * @create 2017/11/23 20:42 **/ private static List<String> getFileNamesByUrl(List<String> fileUrls) { List<String> fileNames = Lists.newArrayList(); for (String url : fileUrls) { fileNames.add(getFileNameByUrl(url)); } return fileNames; } /** * @desc ObjectMetaData是用户对该object的描述, * 由一系列name-value对组成;其中ContentLength是必须设置的,以便SDK可以正确识别上传Object的大小 * @author 杨小华 * @create 2017/11/23 20:12 **/ private static ObjectMetadata getObjectMetadata(long length) { ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(length); // 被下载时网页的缓存行为 objectMetadata.setCacheControl("no-cache"); objectMetadata.setHeader("Pragma", "no-cache"); return objectMetadata; } }
临时授权:
http://172.16.1.98:83/wordpress/2018/02/01/oss%E7%9A%84%E4%B8%B4%E6%97%B6%E6%8E%88%E6%9D%83%E8%AE%B0%E5%BD%95/
三、Junit4单元测试代码
package com.lemo.erp.base; import com.google.common.collect.Lists; import com.lemo.erp.plugins.oss.OSSClientUtil; import org.junit.Assert; import org.junit.Test; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.List; import java.util.Map; /** * @author 杨小华 * @desc Oss测试类 * @create 2017/11/27 8:56 **/ public class OSSClientUtilTest { private String baseUrl = "http://pic.pingpingapp.com/duduerp/"; /** * @desc 测试上传任意格式的文件(如xml) * @author 杨小华 * @create 2017/11/25 12:49 **/ @Test public void testUpload() throws Exception { File file = new File("C:\\Users\\leimo\\Desktop\\test\\test.xml"); InputStream is = new FileInputStream(file); String result = OSSClientUtil.upload(is, "test", "xml"); Assert.assertTrue(result.contains("xml")); } /** * @desc 测试上传视频 * @author 杨小华 * @create 2017/11/25 13:28 **/ @Test public void testUploadVideo() throws Exception { File file = new File("C:\\Users\\leimo\\Desktop\\test\\test.mp4"); InputStream is = new FileInputStream(file); String result = OSSClientUtil.uploadVideo(is, "test"); Assert.assertTrue(result.contains("mp4")); } /** * @desc 测试上传图片 * @author 杨小华 * @create 2017/11/25 13:25 **/ @Test public void testUploadImage() throws Exception { File file = new File("C:\\Users\\leimo\\Desktop\\test\\test.jpg"); InputStream is = new FileInputStream(file); String result = OSSClientUtil.uploadImage(is, "test"); Assert.assertTrue(result.contains("png")); } /** * @desc 测试上传网络图片 * @author 杨小华 * @create 2017/11/24 16:01 **/ @Test public void testUploadWebImage() throws Exception { String headImg = "http://web.rrzuzu.com/WebStatic/duduerp/static/images/logo.png"; String result = OSSClientUtil.uploadWebImage(headImg, "test"); Assert.assertTrue(result.contains("png")); } /** * @desc 测试上传网络图片指定名称abc.png * @author 杨小华 * @create 2017/11/25 13:41 **/ @Test public void testUploadWebFile() throws Exception { String headImg = "http://web.rrzuzu.com/WebStatic/duduerp/static/images/logo.png"; String result = OSSClientUtil.uploadWebFile(headImg, "test", "abc.png"); Assert.assertTrue(result.contains("test/abc.png")); } /** * @desc 用来测试批量删除的图片123.png * @author 杨小华 * @create 2017/11/25 15:20 **/ @Test public void testUploadWebFile2() throws Exception { String headImg = "http://web.rrzuzu.com/WebStatic/duduerp/static/images/logo.png"; String result = OSSClientUtil.uploadWebFile(headImg, "test", "123.png"); Assert.assertTrue(result.contains("test/123.png")); } /** * @desc 测试更新图片 * @author 杨小华 * @create 2017/11/24 16:03 **/ @Test public void testUpdate() throws Exception { String url = baseUrl + "test/abc.png"; File file = new File("C:\\Users\\leimo\\Desktop\\test\\test.jpg"); InputStream is = new FileInputStream(file); String result = OSSClientUtil.updateFile(is, url); Assert.assertEquals(url, result); } /** * @desc 测试替换图片 * @author 杨小华 * @create 2017/11/24 16:22 **/ @Test public void testReplaceFile() throws Exception { String url = baseUrl + "test/abc.png"; File file = new File("C:\\Users\\leimo\\Desktop\\test\\test.jpg"); InputStream is = new FileInputStream(file); String result = OSSClientUtil.replaceFile(is, url); Assert.assertEquals(url, result); } /** * @desc 测试查询 * @author 杨小华 * @create 2017/11/24 17:31 **/ @Test public void testDoesObjectExist() throws Exception { String url = baseUrl + "test/abc.png?200"; boolean result = OSSClientUtil.doesObjectExist(url); Assert.assertTrue(result); } /** * @desc 测试单个删除 * @author 杨小华 * @create 2017/11/24 17:33 **/ @Test public void testDeleteObject() throws Exception { String url = baseUrl + "test/abc.png"; boolean result = OSSClientUtil.deleteObject(url); System.out.println(result); Assert.assertTrue(result); } /** * @desc 测试批量删除(同一endpoint和buckName) * @author 杨小华 * @create 2017/11/25 13:45 **/ @Test public void testDeleteObjects() throws Exception { List<String> fileUrls = Lists.newArrayList(); fileUrls.add(baseUrl + "test/abc.png"); fileUrls.add(baseUrl + "test/123.png"); int count = OSSClientUtil.deleteObjects(fileUrls); Assert.assertEquals(fileUrls.size(), count); } /** * @desc 测试批量删除(适用不同endpoint和buckName) * @author 杨小华 * @create 2017/11/25 15:18 **/ @Test public void testDeleteBatchObject() { List<String> fileUrls = Lists.newArrayList(); fileUrls.add(baseUrl + "test/abc.png"); fileUrls.add(baseUrl + "test/123.png"); int count = OSSClientUtil.deleteBatchObject(fileUrls); Assert.assertEquals(fileUrls.size(), count); } /** * @desc 测试获取web直传签名 * @author 杨小华 * @create 2017/11/27 9:38 **/ @Test public void testGetSign() { Map<String, Object> sign = OSSClientUtil.getSign(); Assert.assertTrue(sign.containsKey("endpoint")); } }
四、图片处理
1.单张不同的图片格式处理可采用直接在后面拼接或用代码去请求,如:
// 缩放 String style = "image/resize,m_fixed,w_100,h_100"; GetObjectRequest request = new GetObjectRequest(bucketName, key); request.setProcess(style); ossClient.getObject(request, new File("example-resize.jpg")); // 裁剪 style = "image/crop,w_100,h_100,x_100,y_100,r_1"; request = new GetObjectRequest(bucketName, key); request.setProcess(style); ossClient.getObject(request, new File("example-crop.jpg"));
2.多张图片共用同一种格式,采用模板的方式,如用户头像框,可能有多个用户上传,他们的图片格式是一样的。