aliyun-oss 通过redis来实现跨域上传图片到阿里 OSS并回显进度条
public class PutObjectProgressListener implements ProgressListener {
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
System.out.println("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
int percent = (int)(this.bytesWritten * 100.0 / this.totalBytes);
System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
public boolean isSucceed() {
return succeed;
}
public static void main(String[] args) {
// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
// 创建OSSClient实例。
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
// 带进度条的上传。
ossClient.putObject(new PutObjectRequest(bucketName, objectName, new FileInputStream("<yourLocalFile>")).
<PutObjectRequest>withProgressListener(new PutObjectProgressListener()));
} catch (Exception e) {
e.printStackTrace();
}
// 关闭OSSClient。
ossClient.shutdown();
}
}
引用到spring boot 中的项目中之后的代码:
1.文件上传及监听器:
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.event.ProgressEvent;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 2018/7/25.
*/
public class OssUploadUtil {
private static Logger logger = LoggerFactory.getLogger(OssUploadUtil.class);
private static final String accessKeyId = OSSProperties.getAccessKey();
private static final String accessKeySecret =OSSProperties.getSecretKey();
private static final String endpoint =OSSProperties.getEndpoint();
private static final int seconds = OSSProperties.getSeconds();
/**
* 带进度的上传
*
* @param request
* @return List<String> 返回的文件地址集合
* @throws Exception
*/
public static List<String> uploadPicWithProgress(HttpServletRequest request, String bucketName, String ossKey,String redisKey,RedisService redisService) throws Exception {
//每次调用都需要实例化一次,实例化的OSSClient shoutDown 一次就不行了
OSSClient oSSClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
DefaultMultipartHttpServletRequest req = (DefaultMultipartHttpServletRequest) request;
request.setCharacterEncoding("UTF-8");
Map<String, MultipartFile> files = req.getFileMap();
int i = 0;
List<String> urlList = Lists.newArrayList();
for (String key : files.keySet()) {
String suffix = "";
MultipartFile file = files.get(key);
/* MultipartFile转File */
File f = null;
try {
f = File.createTempFile("tmpFile", null);
file.transferTo(f);
f.deleteOnExit();
} catch (Exception e) {
e.printStackTrace();
}
if (file.getOriginalFilename().contains(".")) {
suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
}
String fileName = System.currentTimeMillis() + i + suffix;
i++;
try {
PutObjectResult putObjectResult = oSSClient.putObject(new PutObjectRequest(bucketName, ossKey + fileName, f).
<PutObjectRequest>withProgressListener(new PutObjectProgressListener(redisKey,redisService)));
URL imgUrl = oSSClient.generatePresignedUrl(bucketName,ossKey + fileName,new Date());
String url = imgUrl.getAuthority()+imgUrl.getPath();
logger.debug(url);
urlList.add(url);
} catch (OSSException oe) {
logger.error("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.Error Message: " + oe.getErrorCode()
+ "Error Code:" + oe.getErrorCode() + "Request ID:" + oe.getRequestId() + "Host ID:" + oe.getHostId(), oe);
throw new OSSException(oe.getErrorMessage(), oe);
} catch (ClientException ce) {
logger.error("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.Error Message:" + ce.getMessage(), ce);
throw new ClientException(ce);
} finally {
oSSClient.shutdown();
}
}
return urlList;
}
public static class PutObjectProgressListener implements ProgressListener {
private String redisKey;
private RedisService redisService;
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
private int percent = 0;
//构造方法中加入redis
public PutObjectProgressListener() {
}
public PutObjectProgressListener(String redisKey,RedisService redisService) {
this.redisKey = redisKey;
this.redisService = redisService;
//首次添加redis值
redisService.set(redisKey,percent);
}
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
logger.info("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
logger.info(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
percent = (int) (this.bytesWritten*100 / this.totalBytes);
//将进度percent放入redis中
redisService.set(redisKey,percent);
logger.info(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
logger.info(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
logger.info("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
logger.info("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
public boolean isSucceed() {
return succeed;
}
}
}
controller层:
@RestController
@RequestMapping("/V1/upos/oss/")
public class FileUploadController extends BaseController {
private static Logger logger = LoggerFactory.getLogger(FileUploadController.class);
@Autowired
private RedisService redisService;
/**
* 阿里云图片BUCKET
*/
private final String GOODS_PIC_BUCKET_NAME="goods-item-images";
/**
* 阿里云图片默认key
*/
private final String OSS_KEY="uCan-goods";
/**
* 用于存放的上传进度的,redis key 前缀
*/
private final String U_POS_GOODS_PIC="U_POS_GOODS_PIC:";
/**
* 上传文件
* @param request
* @return
* @throws Exception
*/
@RequestMapping("upload.do")
@ResponseBody
public Object uploadSection(HttpServletRequest request) throws Exception {
String redisKey = request.getHeader("ucanPicId");
if(StringUtils.isEmpty(redisKey)){
return ErrorResponse.newInstance("上传uCanPicId不能为空!!");
}
//上传进度同时_往redis中存进度
List<String> urlList= OssUploadUtil.uploadPicWithProgress(request,GOODS_PIC_BUCKET_NAME,OSS_KEY,U_POS_GOODS_PIC+redisKey,redisService);
JSONObject jsonObject = new JSONObject();
jsonObject.put("url","http://"+urlList.get(0));
return SuccessResponse.newInstance(jsonObject);
}
/**
* 获取实时长传进度
* @return
*/
@RequestMapping ("percent.do")
public Object getUploadPercent(@RequestBody JSONObject jsonObject){
String uCanPicId = Objects.isNull(jsonObject.get("ucanPicId")) ? "":jsonObject.get("ucanPicId").toString();
if(StringUtils.isEmpty(uCanPicId)){
return ErrorResponse.newInstance("上传uCanPicId不能为空!!");
}
String redisKey = U_POS_GOODS_PIC+uCanPicId;
int percent = redisService.get(redisKey) == null ? 0: Integer.valueOf(redisService.get(redisKey).toString()).intValue();
//避免死循环请求,每次请求,如果上传进度是0,则加一,当连续调用20次依然为0的时候则返回异常
String countKey = redisKey+"_COUNT";
if(percent == 0){
redisService.incrementBy(countKey,1L);
}
int count = redisService.get(countKey) == null ? 0: Integer.valueOf(redisService.get(countKey).toString()).intValue();
if(count > 20){
return ErrorResponse.newInstance("上传异常,进度为0!!!");
}
if(percent >= 100){
//上传进度到100的时候——————删除该redis值
redisService.delete(redisKey);
//上传进度到100的时候——————删除该redis值
redisService.delete(countKey);
}
JSONObject result = new JSONObject();
result.put("percent",percent);
return SuccessResponse.newInstance(result);
}
}
所需要的maven依赖:
<!--OSS 阿里对象存储 SDK-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
补充:在使用spring boot 上传文件的时候,还需要配置 MultipartResolver,如果是其他项目则可以在xml里配置:
<!-- 定义文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值为5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
<!-- 设定文件上传时写入内存的最大值,如果小于这个参数不会生成临时文件,默认为10240 -->
<property name="maxInMemorySize" value="40960"></property>
<!-- 上传文件的临时路径 -->
<property name="uploadTempDir" value="fileUpload/temp"></property>
<!-- 延迟文件解析 -->
<property name="resolveLazily" value="true"/>
</bean>
如果是spring boot 则可以通过下面这种方式注入,两者本质是一样的,只是方式不同:
@Component("multipartResolver")
public class MultipartResolver extends CommonsMultipartResolver {
private int maxUploadSize = 104857600;
private int maxInMemorySize = 4096;
public int getMaxUploadSize() {
return maxUploadSize;
}
public void setMaxUploadSize(int maxUploadSize) {
this.maxUploadSize = maxUploadSize;
}
public int getMaxInMemorySize() {
return maxInMemorySize;
}
@Override
public void setMaxInMemorySize(int maxInMemorySize) {
this.maxInMemorySize = maxInMemorySize;
}
}
补充:
如果有需要可以看一下这位兄弟的写的,我们知道一个用户登录的时候的请求是只有一个唯一的sessionId的,如果是前后端分离的情况下再使用 session 的方式去保存和记录对应的 百分比,那么从用户请求 -----> 到前端服务-----> 后端服务 ,跨域请求的情况下就会导致同一个用户的请求最终传的后端的时候 session 没有保证是唯一的了,所以在这里我使用redis来保存进度,key值是前端传给我的,为了保证key值的唯一性,可以使用用户登录之后的cookies加上当前的时间戳来生成,最终在改张图片上传完成之后再将该key删掉就ok了
————————————————
版权声明:本文为CSDN博主「代码也文艺」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37107280/article/details/81326738
aliyun-oss 通过redis来实现跨域上传图片到阿里 OSS并回显进度条的更多相关文章
- ueditor富文本编辑器跨域上传图片解决办法
在使用百度富文本编辑器上传图片的过程中,如果是有一台单独的图片服务器就需要将上传的图片放到图片服务器,比如在a.com的编辑器中上传图片,图片要保存到img.com,这就涉及到跨域上传图片,而在ued ...
- php 之跨域上传图片
因为要将所有上传的图片上传到一台独立的图片服务器上面,js上传时存在跨域问题,网上找到这种,通过php curl方式,将图片重新发送到另外一台服务器上保存,并返回图片路径!这种方式存在一定问题:1,上 ...
- 项目二(业务GO)——跨域上传图片(请求接口)
之前,就听过“跨域上传”图片的问题,只是疏于研究,也就一再搁置,直至今天再次遇见这个不能避免的“坑”,才不得不思考一下,怎么“跨域上传”图片或者文件? 问题来源: 何为“跨域”? ——就是给你一个接口 ...
- django —— KindEditor - 跨域上传图片
#跨域上传方法 def frontupload(request): if request.method == 'POST': item = {} file = request.FILES.get('i ...
- iframe跨域上传图片
方案一:用jquery的$.post异步提交,然后把返回来的值用jquery填充到隐藏域中.可是$.post不支持跨域. jQuery.ajax()支持get方式的跨域,这其实是采用jsonp的方式来 ...
- ajax 异步 跨域上传图片
客户端 <label for="text">名称</label> <input type="text" id="text ...
- ajax跨域上传图片
前台页面 var data = new FormData(); data.append('file', file); data.append('app', 'goods'); $.ajax({ url ...
- kindeditor4跨域上传图片解决
项目中正在使用kindeditor, 版本号4.1.10 非常多公司的图片会走CDN,须要单独的一台图片上传服务如:(upload.268xue.com) kindeditor上传图片的简单内部流程: ...
- webservice跨域上传图片
1.上传文件,在一般处理程序中处理 //1.接收post过来的文件 HttpPostedFile file = context.Request.Files[]; || file.ContentLeng ...
随机推荐
- Java成员变量和局部变量区别
成员变量和局部变量区别 变量根据定义位置的不同,我们给变量起了不同的名字.如下图所示: 区别 在类中的位置不同 (重点) 成员变量:类中,方法外 局部变量:方法中或者方法声明上(形式参数) 作用范围 ...
- matlab练习程序(图像投影到点云)
最近接触点云比较多,如果把图像投影到点云应该挺有意思. 首先需要载入图像,然后做个球或其他什么形状的点云,这里可以参考球坐标公式. 最后通过pcshow将像素输出到点云上即可. 原图: 投影后的点云: ...
- 一道常被人轻视的web前端常见面试题(JS)
本文转载自站长之家,如有侵权问题,请联系我,马上删除. 面试题是招聘公司和开发者都非常关心的话题,公司希望通过它了解开发者的真实水平和细节处理能力,而开发者希望能够最大程度地展示自己的水平(甚至超常发 ...
- Python GUI教程一:Hello World
STEP 1:PyQt5基本介绍 Qt是GUI编程中非常受欢迎,也是非常强大的一个工具. PyQt5 是Qt的Python版本.它大概涵盖了620个类,6000多个函数.PyQt5进行双重许可,开发者 ...
- 打造IP代理池,Python爬取Boss直聘,帮你获取全国各类职业薪酬榜
爬虫面临的问题 不再是单纯的数据一把抓 多数的网站还是请求来了,一把将所有数据塞进去返回,但现在更多的网站使用数据的异步加载,爬虫不再像之前那么方便 很多人说js异步加载与数据解析,爬虫可以做到啊,恩 ...
- Centos7 下cobbler安装及配置
1.背景介绍 作为运维,在公司经常遇到一些机械性重复工作要做,例如:为新机器装系统,一台两台机器装系统,可以用光盘.U盘等介质安装,1小时也完成了,但是如果有成百台的服务器还要用光盘.U盘去安装,就显 ...
- swoole中http_server的配置与使用
swoole中为我们提供了一个swoole_http_server类,方便我们处理http请求. 但是它对http协议的支持并不完整,所以一般建议在前面加一层nginx进行代理,对于php文件的处理交 ...
- Oracle - 截取指定日期的alert log
工作中DBA经常会查看alert log来检查数据库后台都记录了些什么日志,如果只想看某一天或者某段时间范围的日志,能够把这些日志从大的alert log中截取下来放到一个单独的文件中,对于查看和下载 ...
- 接口的 COM 组件调用 QueryInterface 因以下错误而失败: 库没有注册。
这个问题原因是因为安装了高版本的office然后卸载掉,又安装了低版本的office导致的. 博主是 office2016卸载后,安装了office2013. EXCEL报错信息为: 无法将类型为“M ...
- django2-登录与出版社
1.django核心功能 因为django功能很多 ,出版社可以使用到部分功能,最快最简单了解django的运行模式,每个点后续细化去梳理 django的路由 django的视图 django的模板 ...