想了解阿里OSS对象存储,实现图片上传的内容的可看我的另一篇博客,博客中有完整代码,这篇博客是以上一篇阿里OSS对象存储博客为基础,只写一些与进度有关的内容,细心往下看js代码中有需要注意的地方!
实现方案:
通过ProgressListener类获取进度信息时时存入session,页面通过ajax轮询时时获取session中的数据通过<progress></progress>标签显示;
在这个OSSUploadUtil类中增加一个内部类 PutObjectProgressListener 继承ProgressListener;
这个类PutObjectProgressListener就是实现进度条的核心类,重新这个progressChanged方法,此方法就是实现进度的核心方法,图片进度会通过这个方法时时写入session中;
在类OSSUploadUtil中的这个putObject方法中把
【 PutObjectRequest request = new PutObjectRequest(
config.getBucketName(), fileName, input,
meta); //创建上传请求
ossClient.putObject(request);】
这段代码替换成:
【PutObjectResult putObjectResult = ossClient
.putObject(new PutObjectRequest(config.getBucketName(),
fileName, f)
.<PutObjectRequest> withProgressListener(new PutObjectProgressListener(
request1.getSession(), sum))); 】
进度核心方法内部类:
public static class PutObjectProgressListener implements ProgressListener
{
private HttpSession session;
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
private int percent = 0;
int sum = 0;
// 构造方法中加入session
public PutObjectProgressListener()
{
}
public PutObjectProgressListener(HttpSession mSession, int sum)
{
this.session = mSession;
this.sum = sum;
session.setAttribute("upload_percent", 0);
session.setAttribute("upload_sum", sum);
System.out
.println("====================================================");
System.out.println("sum:" + sum);
}
@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.0 / this.totalBytes);
// 将进度percent放入session中
session.setAttribute("upload_percent", percent);
}
else
{
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
break;
case TRANSFER_FAILED_EVENT:
break;
default:
break;
}
//控制台打印进度
System.out.println("percent:" + percent);
}
public boolean isSucceed()
{
return succeed;
}
}
完整OSSUploadUtil代码(其余有关OSS上传的代码请看另一篇博客):
package com.st.weixin.common;
/**
* Project Name: 液化天然气车用气瓶智慧监测系统
*
*
* FileName: PageController Author: zq Date: 2018/5/2
*
* @since: 1.0.0 Copyright (C), 2015-2018, 坦程物联网有限公司
*/
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
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.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.GenericRequest;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
/**
*
* @ClassName: OSSUploadUtil
* @Description: 阿里云OSS文件上传工具类
* @author AggerChen
* 2016年11月3日 下午12:03:24
*/
public class OSSUploadUtil
{
private static OSSConfig config = null;
/**
*
* @MethodName: uploadFile
* @Description: OSS单文件上传
* @param file
* @param fileType 文件后缀
* @return String 文件地址
*/
public static String uploadFile(MultipartFile file, String fileType,
String oSSConfigkey, HttpServletRequest request, int sum)
{
config = config == null ? new OSSConfig() : config;
String fileName = config.getPicLocation1(oSSConfigkey)
+ UUID.randomUUID().toString().toUpperCase().replace("-", "")
+ "." + fileType; // 文件名,根据UUID来
return putObject(file, fileType, fileName, request, sum);
}
/**
*
* @MethodName: updateFile
* @Description: 更新文件:只更新内容,不更新文件名和文件地址。
* (因为地址没变,可能存在浏览器原数据缓存,不能及时加载新数据,例如图片更新,请注意)
* @param file
* @param fileType
* @param oldUrl
* @return String
*/
public static String updateFile(CommonsMultipartFile file, String fileType,
String oldUrl, HttpServletRequest request, int sum)
{
String fileName = getFileName(oldUrl);
if (fileName == null)
return null;
return putObject(file, fileType, fileName, request, sum);
}
/**
*
* @MethodName: replaceFile
* @Description: 替换文件:删除原文件并上传新文件,文件名和地址同时替换
* 解决原数据缓存问题,只要更新了地址,就能重新加载数据)
* @param file
* @param fileType 文件后缀
* @param oldUrl 需要删除的文件地址
* @return String 文件地址
*/
public static String replaceFile(CommonsMultipartFile file,
String fileType, String oldUrl, String oSSConfigkey,
HttpServletRequest request, int sum)
{
boolean flag = deleteFile(oldUrl); // 先删除原文件
if (!flag)
{
// 更改文件的过期时间,让他到期自动删除。
}
return uploadFile(file, fileType, oSSConfigkey, request, sum);
}
/**
*
* @MethodName: deleteFile
* @Description: 单文件删除
* @param fileUrl 需要删除的文件url
* @return boolean 是否删除成功
*/
public static boolean deleteFile(String fileUrl)
{
config = config == null ? new OSSConfig() : config;
String bucketName = OSSUploadUtil.getBucketName(fileUrl); // 根据url获取bucketName
String fileName = OSSUploadUtil.getFileName(fileUrl); // 根据url获取fileName
if (bucketName == null || fileName == null)
return false;
OSSClient ossClient = null;
try
{
ossClient = new OSSClient(config.getEndpoint(), config
.getAccessKeyId(), config.getAccessKeySecret());
GenericRequest request = new DeleteObjectsRequest(bucketName)
.withKey(fileName);
ossClient.deleteObject(request);
}
catch (Exception oe)
{
oe.printStackTrace();
return false;
}
finally
{
ossClient.shutdown();
}
return true;
}
/**
*
* @MethodName: batchDeleteFiles
* @Description: 批量文件删除(较快):适用于相同endPoint和BucketName
* @param fileUrls 需要删除的文件url集合
* @return int 成功删除的个数
*/
public static int deleteFile(List<String> fileUrls)
{
int deleteCount = 0; // 成功删除的个数
String bucketName = OSSUploadUtil.getBucketName(fileUrls.get(0)); // 根据url获取bucketName
List<String> fileNames = OSSUploadUtil.getFileName(fileUrls); // 根据url获取fileName
if (bucketName == null || fileNames.size() <= 0)
return 0;
OSSClient ossClient = null;
try
{
ossClient = new OSSClient(config.getEndpoint(), config
.getAccessKeyId(), config.getAccessKeySecret());
DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName)
.withKeys(fileNames);
DeleteObjectsResult result = ossClient.deleteObjects(request);
deleteCount = result.getDeletedObjects().size();
}
catch (OSSException oe)
{
oe.printStackTrace();
throw new RuntimeException("OSS服务异常:", oe);
}
catch (ClientException ce)
{
ce.printStackTrace();
throw new RuntimeException("OSS客户端异常:", ce);
}
finally
{
ossClient.shutdown();
}
return deleteCount;
}
/**
*
* @MethodName: batchDeleteFiles
* @Description: 批量文件删除(较慢):适用于不同endPoint和BucketName
* @param fileUrls 需要删除的文件url集合
* @return int 成功删除的个数
*/
public static int deleteFiles(List<String> fileUrls)
{
int count = 0;
for (String url : fileUrls)
{
if (deleteFile(url))
{
count++;
}
}
return count;
}
/**
*
* @MethodName: putObject
* @Description: 上传文件
* @param file
* @param fileType
* @param fileName
* @return String
*/
private static String putObject(MultipartFile file, String fileType,
String fileName, HttpServletRequest request1, int sum)
{
config = config == null ? new OSSConfig() : config;
String url = null; // 默认null
OSSClient ossClient = null;
try
{
ossClient = new OSSClient(config.getEndpoint(), config
.getAccessKeyId(), config.getAccessKeySecret());
// InputStream input = new FileInputStream(file);
InputStream input = file.getInputStream();
ObjectMetadata meta = new ObjectMetadata(); // 创建上传Object的Metadata
meta.setContentType(OSSUploadUtil.contentType(fileType)); // 设置上传内容类型
meta.setCacheControl("no-cache"); // 被下载时网页的缓存行为
/* ========================================================= */
/* MultipartFile转File */
File f = null;
try
{
f = File.createTempFile("tmp", null);
file.transferTo(f);
f.deleteOnExit();
}
catch (Exception e)
{
e.printStackTrace();
}
/*
* 这里用带进度条的OSS上传
* 将session传入PutObjectProgressListener的构造中!官网例子是没有这个操作的 注意new
* PutObjectRequest()的第三个参数是File而不是官网介绍的FileInputStream,否则获取不到进度.
*/
PutObjectResult putObjectResult = ossClient
.putObject(new PutObjectRequest(config.getBucketName(),
fileName, f)
.<PutObjectRequest> withProgressListener(new PutObjectProgressListener(
request1.getSession(), sum)));
// PutObjectRequest request = new PutObjectRequest(
// config.getBucketName(), fileName, input,
// meta); //创建上传请求
// ossClient.putObject(request);
url = config.getEndpoint().replaceFirst("http://",
"http://" + config.getBucketName() + ".")
+ "/" + fileName; // 上传成功再返回的文件路径
System.out.println("url:" + url);
/* ========================================================== */
}
catch (OSSException oe)
{
System.out
.println("--com.st.weixin.common.OSSUploadUtil---1-------");
System.out.println(oe.getMessage());
System.out.println(oe.getErrorCode());
System.out.println(oe.getClass());
System.out.println(oe.getStackTrace());
oe.printStackTrace();
return null;
}
catch (ClientException ce)
{
System.out
.println("---com.st.weixin.common.OSSUploadUtil--2-------");
System.out.println(ce.getMessage());
System.out.println(ce.getErrorCode());
System.out.println(ce.getClass());
System.out.println(ce.getStackTrace());
ce.printStackTrace();
return null;
}
catch (FileNotFoundException e)
{
System.out
.println("---com.st.weixin.common.OSSUploadUtil--3-------");
System.out.println(e.getMessage());
System.out.println(e.getClass());
System.out.println(e.getStackTrace());
e.printStackTrace();
return null;
}
catch (IOException e)
{
System.out
.println("----com.st.weixin.common.OSSUploadUtil-4-------");
System.out.println(e.getMessage());
System.out.println(e.getClass());
System.out.println(e.getStackTrace());
e.printStackTrace();
}
catch (Exception e)
{
System.out
.println("----com.st.weixin.common.OSSUploadUtil-5-------");
System.out.println("309行e.getCause()" + e.getCause());
System.out.println("309行e.getClass()" + e.getClass());
System.out.println("309行e.getLocalizedMessage()"
+ e.getLocalizedMessage());
System.out.println("309行e.getMessage()" + e.getMessage());
System.out.println("309行e.getSuppressed()" + e.getSuppressed());
e.printStackTrace();
}
finally
{
ossClient.shutdown();
}
return url;
}
/**
*
* @MethodName: contentType
* @Description: 获取文件类型
* @param fileType
* @return String
*/
private static String contentType(String fileType)
{
fileType = fileType.toLowerCase();
String contentType = "";
if (fileType.equals("bmp"))
{
contentType = "image/bmp";
}
else if (fileType.equals("gif"))
{
contentType = "image/gif";
}
else if (fileType.equals("png") || fileType.equals("jpeg")
|| fileType.equals("jpg"))
{
contentType = "image/jpeg";
}
else if (fileType.equals("html"))
{
contentType = "text/html";
}
else if (fileType.equals("txt"))
{
contentType = "text/plain";
}
else if (fileType.equals("vsd"))
{
contentType = "application/vnd.visio";
}
else if (fileType.equals("ppt") || fileType.equals("pptx"))
{
contentType = "application/vnd.ms-powerpoint";
}
else if (fileType.equals("doc") || fileType.equals("docx"))
{
contentType = "application/msword";
}
else if (fileType.equals("xml"))
{
contentType = "text/xml";
}
else if (fileType.equals("mp4"))
{
contentType = "video/mp4";
}
else
{
contentType = "application/octet-stream";
}
return contentType;
}
/**
*
* @MethodName: getBucketName
* @Description: 根据url获取bucketName
* @param fileUrl 文件url
* @return String bucketName
*/
private static String getBucketName(String fileUrl)
{
String http = "http://";
String https = "https://";
int httpIndex = fileUrl.indexOf(http);
int httpsIndex = fileUrl.indexOf(https);
int startIndex = 0;
if (httpIndex == -1)
{
if (httpsIndex == -1)
{
return null;
}
else
{
startIndex = httpsIndex + https.length();
}
}
else
{
startIndex = httpIndex + http.length();
}
int endIndex = fileUrl.indexOf(".oss-");
return fileUrl.substring(startIndex, endIndex);
}
/**
*
* @MethodName: getFileName
* @Description: 根据url获取fileName
* @param fileUrl 文件url
* @return String fileName
*/
private static String getFileName(String fileUrl)
{
String str = "aliyuncs.com/";
int beginIndex = fileUrl.indexOf(str);
if (beginIndex == -1)
return null;
return fileUrl.substring(beginIndex + str.length());
}
/**
*
* @MethodName: getFileName
* @Description: 根据url获取fileNames集合
* @param fileUrls 文件url
* @return List<String> fileName集合
*/
private static List<String> getFileName(List<String> fileUrls)
{
List<String> names = new ArrayList<String>();
for (String url : fileUrls)
{
names.add(getFileName(url));
}
return names;
}
public static class PutObjectProgressListener implements ProgressListener
{
private HttpSession session;
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
private int percent = 0;
int sum = 0;
// 构造方法中加入session
public PutObjectProgressListener()
{
}
public PutObjectProgressListener(HttpSession mSession, int sum)
{
this.session = mSession;
this.sum = sum;
session.setAttribute("upload_percent", 0);
session.setAttribute("upload_sum", sum);
}
@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.0 / this.totalBytes);
// 将进度percent放入session中
session.setAttribute("upload_percent", percent);
}
else
{
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
break;
case TRANSFER_FAILED_EVENT:
break;
default:
break;
}
//图片进度打印控制台
System.out.println("percent:" + percent);
}
public boolean isSucceed()
{
return succeed;
}
}
}
控制类代码:
public ModelAndView selectUploadPercent(HttpServletRequest request,HttpServletResponse response){
HttpSession session = request.getSession();
//图片上传进度
int percent = session.getAttribute("upload_percent") == null ? 0: Integer.parseInt(session.getAttribute("upload_percent").toString());
//第几张图片
int sum = session.getAttribute("upload_sum") == null ? 0: Integer.parseInt(session.getAttribute("upload_sum").toString());
//图片全部上传结束
int end = session.getAttribute("upload_end") == null ? 0: Integer.parseInt(session.getAttribute("upload_end").toString());
String jsonStr = "{percent:'+percent+',sum:'+sum+',end:'+end+'}";
Map<String, Integer> map = new HashMap<String, Integer>();
try
{
map.put("percent",percent);
map.put("sum",sum);
map.put("end",end);
JSONArray json1 = JSONArray.fromObject(map);
//将json数据返回
response.getWriter().write(json1.toString());
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
//数据复原
public void clearUploadPercent(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
HttpSession session = request.getSession();
session.setAttribute("upload_percent",0);
session.setAttribute("upload_sum",1);
session.setAttribute("upload_end",0);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("percent",0);
map.put("sum", 0);
map.put("end", 0);
JSONArray json1 = JSONArray.fromObject(map);
response.getWriter().write(json1.toString());
}
页面进度标签:
<div
style="width: 400px; height: 20px; text-align: center; left: 1%; top: 43%; position: absolute;">
<label style="color: blue">
上传第
<span id="sum"></span>张图:
</label>
<progress id="percent" type="circle" value="" max="100">
</progress>
<span id="per" style="color: blue; margin-left: 5px"></span>
</div>
js:
js中需要注意两个问题:
1.写 setInterval或seTimeout这个方法时 方法中直接写要运行的函数名,并赋值一个变量,这个变量必须是全局变量;
2. 在ajax中 同步参数这个async必须是false;[ async : false, ],否则pc端游览器正常,手机端游览器报error错误;这个错误并不是数据 格式不对而引起的,而这是因为手机端在轮询调取ajax时 ajax没有同步而造成了互相之间冲突;
js代码:
//每100ms获取一次图片上传进度
var intervalId;
function interval() {
intervalId = window.setInterval(showPercent, 100)
}
//获取图片进度数据
function showPercent() {
$.ajax( {
type : "POST",
contentType : false,
async : false,
cache : false,
url : "intoNetTCSubmit.htm?method=selectUploadPercent",
dataType : "json",
success : function(data) {
console.log(data);
var end = 0;
var per = 0;
end = data[0].end;
per = data[0].percent + "%"
console.log(per);
console.log("end:" + end);
$("#percent").val(data[0].percent);//图片上传进度
$("#sum").html(data[0].sum == 0 ? 1 : data[0].sum);//第几张图片
$("#per").html(per);
if (end == '-1') { //图片上传结束标识
stopInterval();
//图片上传完成session重置
clearPercent();
}
},
error : function(data) {
console.log(data);
stopInterval();
clearPercent();
alert("ajax异常!!!");
}
});
}
//清除进度数据
function clearPercent() {
$.ajax( {
type : "POST",
contentType : false,
async : false,
cache : false,
url : "intoNetTCSubmit.htm?method=clearUploadPercent",
dataType : "json",
success : function(data) {
console.log("ddd:"+data);
},
});
}
//清除时间
function stopInterval() {
window.clearInterval(intervalId);
}