h5上传文件到阿里云OSS:
处理逻辑:
第一步:前端点击上传文件按钮
第二步:调服务器接口获取到上传oss相关参数的签名参数值
第三步:前端直接接收到返回的参数进行表单方式上传文件
服务器controller代码:
package cn.network.controller;
import cn.network.entity.Response;
import cn.network.util.OSSPath;
import cn.network.util.OSSWebUpload;
import cn.network.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
@RestController
@RequestMapping("/web/oss")
public class OSSWebController {
@Autowired
private OSSWebUpload oSSWebUpload;
@RequestMapping("/getSignature")
public Map<String, String> createSignature(String type) throws UnsupportedEncodingException {
String folder="video";
if(StringUtil.isEquals(type,"2")){
folder="picture";
};
Map<String, String> signature = oSSWebUpload.createSignature(folder);
return signature;
}
@RequestMapping("/callbackService")
public Response getDemo(HttpServletRequest request) throws IOException {
boolean bool = oSSWebUpload.callbackService(request);
return Response.success();
}
}
OSSWebUpload.java代码:
package cn.network.util;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import lombok.extern.log4j.Log4j2;
import net.sf.json.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URI;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.sql.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@Component
@Log4j2
public class OSSWebUpload {
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.accessKeyId}")
private String accessId;
@Value("${aliyun.oss.accessKeySecret}")
private String accessKey;
@Value("${aliyun.oss.bucketName}")
private String bucket;
/**
* callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
*/
@Value("${aliyun.oss.callbackUrl}")
private String callbackUrl;
/**
* 由前端调用成临时的签名
* @param dir
* @return
* @throws UnsupportedEncodingException
*/
public Map<String, String> createSignature(String dir) throws UnsupportedEncodingException {
String host = "http://" + bucket + "." + endpoint;
OSSClient client = new OSSClient(endpoint, accessId, accessKey);
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = client.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = client.calculatePostSignature(postPolicy);
Map<String, String> respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));
JSONObject jasonCallback = new JSONObject();
jasonCallback.put("callbackUrl", callbackUrl);
jasonCallback.put("callbackBody",
"filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
respMap.put("callback", base64CallbackBody);
return respMap;
}
/**
* 前端上传成功后
* OSS回调处理业务
* @param request
* @throws IOException
* @return
*/
public boolean callbackService(HttpServletRequest request) throws IOException {
//读取参数
String ossCallbackBody = GetPostBody(request.getInputStream(),Integer.parseInt(request.getHeader("content-length")));
log.info("ossCallbackBody:"+ossCallbackBody);
//验证参数
boolean bool = VerifyOSSCallbackRequest(request, ossCallbackBody);
log.info("verify result : " + bool);
return bool;
}
/**
* 获取Post消息体
*
* @param is
* @param contentLen
* @return
*/
private String GetPostBody(InputStream is, int contentLen) {
if (contentLen > 0) {
int readLen = 0;
int readLengthThisTime = 0;
byte[] message = new byte[contentLen];
try {
while (readLen != contentLen) {
readLengthThisTime = is.read(message, readLen, contentLen - readLen);
if (readLengthThisTime == -1) {// Should not happen.
break;
}
readLen += readLengthThisTime;
}
return new String(message);
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
/**
* 验证上传回调的Request
*
* @param request
* @param ossCallbackBody
*/
private boolean VerifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody)
throws NumberFormatException, IOException {
boolean ret = false;
String autorizationInput = new String(request.getHeader("Authorization"));
log.info("autorizationInput:"+autorizationInput);
String pubKeyInput = request.getHeader("x-oss-pub-key-url");
log.info("pubKeyInput:"+pubKeyInput);
byte[] authorization = BinaryUtil.fromBase64String(autorizationInput);
byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
String pubKeyAddr = new String(pubKey);
if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/")
&& !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")) {
System.out.println("pub key addr must be oss addrss");
return false;
}
String retString = executeGet(pubKeyAddr);
retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
retString = retString.replace("-----END PUBLIC KEY-----", "");
String queryString = request.getQueryString();
String uri = request.getRequestURI();
String decodeUri = java.net.URLDecoder.decode(uri, "UTF-8");
String authStr = decodeUri;
if (queryString != null && !queryString.equals("")) {
authStr += "?" + queryString;
}
authStr += "\n" + ossCallbackBody;
ret = doCheck(authStr, authorization, retString);
return ret;
}
/**
* 验证RSA
*
* @param content
* @param sign
* @param publicKey
* @return
*/
private static boolean doCheck(String content, byte[] sign, String publicKey) {
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes());
boolean bverify = signature.verify(sign);
return bverify;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 获取public key
* @param url
* @return
*/
private String executeGet(String url) {
BufferedReader in = null;
String content = null;
try {
// 定义HttpClient
@SuppressWarnings("resource")
DefaultHttpClient client = new DefaultHttpClient();
// 实例化HTTP方法
HttpGet request = new HttpGet();
request.setURI(new URI(url));
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
content = sb.toString();
} catch (Exception e) {
} finally {
if (in != null) {
try {
in.close();// 最后要关闭BufferedReader
} catch (Exception e) {
e.printStackTrace();
}
}
return content;
}
}
}
前端js代码ossUpload.js:
!(function(e){
var a={
serverUrl:"", // serverUrl是 用户获取 '签名和Policy' 等信息的应用服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
selectFileBtnId:'',
upoladFileBtnId:'postfiles',//上传文件的点击上传按钮id
fileContentId:'ossfile',//file预览div id
objectKeyType:'random_name',//local_name 上传文件名字保持本地文件名字 random_name 上传文件名字是随机文件名, 后缀保留
dir:'',//存储到oss的前缀文件夹
host:'',//oss服务地址
accessid:'',//accessid
policyBase64:'',//policy
signature:'',//signature
callbackbody:'',//回调接口地址加密
expire:'',//失效时间
objectKey:'',//文件名
uploadType:"1",//1 .富文本图片上传 2.视频上传
},
ossUpload=function(){};
ossUpload.prototype.config=function(options){
if(options)a.selectFileBtnId=options.selectFileBtnId?options.selectFileBtnId:a.selectFileBtnId;
if(options)a.upoladFileBtnId=options.upoladFileBtnId?options.upoladFileBtnId:a.upoladFileBtnId;
if(options)a.fileContentId=options.fileContentId?options.fileContentId:a.fileContentId;
if(options)a.objectKeyType=options.objectKeyType?options.objectKeyType:a.objectKeyType;
if(options)a.uploadType=options.uploadType?options.uploadType:a.uploadType;
return this;
}
ossUpload.prototype.sendRequest=function(){
var xmlhttp = null;
if (window.XMLHttpRequest){
xmlhttp=new XMLHttpRequest();
}else if (window.ActiveXObject){
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlhttp!=null){
a.serverUrl=layui.config.serverUrl()+"/web/oss/getSignature?type="+a.uploadType;
xmlhttp.open( "GET",a.serverUrl, false );
xmlhttp.send(null);
return xmlhttp.responseText
}else{
alert("Your browser does not support XMLHTTP.");
}
}
/**
* 可以判断当前expire是否超过了当前时间, 如果超过了当前时间, 就重新取一下,3s 作为缓冲。
*/
ossUpload.prototype.getSignature=function(){
var _this=this;
var now =timestamp = Date.parse(new Date()) / 1000;
if (a.expire < now + 3){
var body = _this.sendRequest();
var obj = eval ("(" + body + ")");
a.host = obj['host'];
a.accessid = obj['accessid'];
a.policyBase64 = obj['policy'];
a.signature = obj['signature'];
a.expire = parseInt(obj['expire']);
a.callbackbody = obj['callback'];
a.dir = obj['dir'];
return true;
}
return false;
}
ossUpload.prototype.randomString=function(len) {
len = len || 32;
var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
var maxPos = chars.length;
var pwd = '';
for (i = 0; i < len; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
ossUpload.prototype.getSuffix=function(filename) {
let pos = filename.lastIndexOf('.')
let suffix = ''
if (pos != -1) {
suffix = filename.substring(pos)
}
return suffix;
}
ossUpload.prototype.calculateObjectName=function(filename){
var _this=this;
if (a.objectKeyType == 'local_name'){
a.objectKey = a.dir + "${filename}"
}else if (a.objectKeyType == 'random_name'){
var suffix = _this.getSuffix(filename)
a.objectKey = a.dir + _this.randomString(10) + suffix
}
return ''
}
ossUpload.prototype.getUploadedObjectName=function(filename){
if (a.objectKeyType == 'local_name'){
var tmp_name = a.objectKey
tmp_name = tmp_name.replace("${filename}", filename);
return tmp_name
}else if(a.objectKeyType == 'random_name'){
return a.objectKey;
}
}
/**
* 拼接上传的参数
* @param {Object} up
* @param {Object} filename
* @param {Object} ret
*/
ossUpload.prototype.setUploadParam=function(up, filename, ret){
var _this=this;
if (ret == false){
ret = _this.getSignature()
}
if (filename != '') {
_this.calculateObjectName(filename)
}
new_multipart_params = {
'key' : a.objectKey,
'policy': a.policyBase64,
'OSSAccessKeyId': a.accessid,
'success_action_status' : '200', //让服务端返回200,不然,默认会返回204
'callback' : a.callbackbody,
'signature': a.signature,
};
up.setOption({
'url': a.host,
'multipart_params': new_multipart_params
});
console.log("up:",up);
up.start();
}
ossUpload.prototype.getFormData=function(filename,ret){
var _this=this;
if (ret == false){
ret = _this.getSignature()
}
if (filename != '') {
_this.calculateObjectName(filename)
}
var new_multipart_params = {
'url': a.host,
'key' : a.objectKey,
'policy': a.policyBase64,
'OSSAccessKeyId': a.accessid,
'success_action_status' : '200', //让服务端返回200,不然,默认会返回204
'callback' : a.callbackbody,
'signature': a.signature,
};
return new_multipart_params;
}
window.ossUpload=new ossUpload();
})(window)
前端js代码ossUploadVideo.js:
!(function(e){
var a={
selectFileBtnId:'',
upoladFileBtnId:'postfiles',//上传文件的点击上传按钮id
fileContentId:'ossfile',//file预览div id
uploader:'',
mime_types:[ //只允许上传图片
{ title : "Image files", extensions : "image/*" }
],
filePath:"",
duration:'',//视频时长
delVideos:[],
},
ossUploadVideo=function(){};
ossUploadVideo.prototype.config=function(options){
if(options)a.selectFileBtnId=options.selectFileBtnId?options.selectFileBtnId:a.selectFileBtnId;
if(options)a.upoladFileBtnId=options.upoladFileBtnId?options.upoladFileBtnId:a.upoladFileBtnId;
if(options)a.fileContentId=options.fileContentId?options.fileContentId:a.fileContentId;
if(options)a.objectKeyType=options.objectKeyType?options.objectKeyType:a.objectKeyType;
if(options)a.mime_types=options.mime_types?options.mime_types:a.mime_types;
return this;
}
ossUploadVideo.prototype.getFilePath=function(){
return a.filePath;
}
ossUploadVideo.prototype.delVideos=function(){
return a.delVideos.join("_");
}
ossUploadVideo.prototype.getDuration=function(){
return a.duration;
}
ossUploadVideo.prototype.innerFileHTML=function(videoUrl,duration){
a.filePath=videoUrl;
a.duration=duration;
var html='<div class="videoItem">'+
'<video style="width:161px;height:110px" src="'+layui.config.imgUrl()+videoUrl+'" controls="controls"></video>'+
'</div>';
$("#videoList").html(html);
console.log("html:",html)
}
//音频加载完成后的一系列操作
ossUploadVideo.prototype.duration=function(files){
console.log("files:",files);
//获取录音时长
var url = URL.createObjectURL(files);
//经测试,发现audio也可获取视频的时长
var audioElement = new Audio(url);
var duration;
audioElement.addEventListener("loadedmetadata", function (_event) {
duration = audioElement.duration;
$("#videoAllNum").html(duration+"秒");
a.duration=duration;
console.log("duration:",duration);
//分钟
var minute = duration / 60;
var minutes = parseInt(minute);
if (minutes < 10) {
minutes = "0" + minutes;
}
//秒
var second = duration % 60;
var seconds = Math.round(second);
if (seconds < 10) {
seconds = "0" + seconds;
}
console.log("second:",second);
//总共时长的秒数
var allTime = parseInt(minutes*60 + seconds);
console.log("allTime:",allTime);
});
}
ossUploadVideo.prototype.create=function(){
a.uploader = new plupload.Uploader({
runtimes : 'html5,flash,silverlight,html4',
browse_button :a.selectFileBtnId,
container: document.getElementById('container'),
flash_swf_url : 'lib/plupload-2.1.2/js/Moxie.swf',
silverlight_xap_url : 'lib/plupload-2.1.2/js/Moxie.xap',
url : 'http://oss.aliyuncs.com',
filters: {
mime_types :a.mime_types,
max_file_size : '1500mb', //最大只能上传10mb的文件
prevent_duplicates : true //不允许选取重复文件
},
init: {
PostInit: function() {
},
FilesAdded: function(up, files) {
if(!a.filePath){
plupload.each(files, function(file) {
document.getElementById(a.fileContentId).innerHTML = '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ')<b></b>'
+'<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>'
+'</div>';
});
window.ossUpload.setUploadParam(a.uploader, '', false);
return true;
}
layui.layer.confirm('当前已有视频是否覆盖?', {icon: 3, title:'提示'}, function(index){
layer.close(index);
plupload.each(files, function(file) {
document.getElementById(a.fileContentId).innerHTML = '<div id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ')<b></b>'
+'<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>'
+'</div>';
});
window.ossUpload.setUploadParam(a.uploader, '', false);
return true;
},function(){
console.log("取消啦");
plupload.each(files, function(file) {
up.removeFile(file);
});
});
return false;
},
BeforeUpload: function(up, file) {
window.ossUpload.setUploadParam(up, file.name, true);
},
UploadProgress: function(up, file) {
console.log("file.id:",file.id);
var d = document.getElementById(file.id);
d.getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
var prog = d.getElementsByTagName('div')[0];
var progBar = prog.getElementsByTagName('div')[0]
progBar.style.width= 2*file.percent+'px';
progBar.setAttribute('aria-valuenow', file.percent);
},
FileUploaded: function(up, file, info) {
console.log("info.response:",info.response);
console.log('upload to oss success, object name:' + window.ossUpload.getUploadedObjectName(file.name));
if(a.filePath){
a.delVideos.push(a.filePath);
}
a.filePath= window.ossUpload.getUploadedObjectName(file.name);
if (info.status == 200){
layui.layer.msg("上传完毕");
html='<div id="audio" class="videoItem">'+
'<video style="width:161px;height:110px" src="'+layui.config.imgUrl()+window.ossUpload.getUploadedObjectName(file.name)+'" controls="controls"></video>'+
'</div>';
$(".videoList").html(html);
var _audio = $('#audio');
// //默认的时候让所有的音频加载,否则在火狐ie等浏览器下由于jquery插件的存在导致onloadedmetadata事件不响应
_audio.load();
_audio.onloadedmetadata=window.ossUploadVideo.duration(file.getNative());
}else if (info.status == 203){
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '上传到OSS成功,但是oss访问用户设置的上传回调服务器失败,失败原因是:' + info.response;
}else{
document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = info.response;
}
},
Error: function(up, err) {
if (err.code == -600) {
layui.layer.msg("选择的文件太大了");
}
else if (err.code == -601) {
layui.layer.msg("选择的文件后缀不对");
}
else if (err.code == -602) {
layui.layer.msg("这个文件已经上传过一遍了");
}
else{
layui.layer.msg("\nError xml:" + err.response);
}
}
}
});
a.uploader.init();
}
window.ossUploadVideo=new ossUploadVideo();
})(window)
html页面引用:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加视频</title>
<link rel="stylesheet" type="text/css" href="../../static/css/videoupload.css"/>
</head>
<body>
<fieldset class="layui-elem-field layui-field-title">
<legend>添加视频</legend>
</fieldset>
<div id="addTalkBox">
<form class="layui-form" id="addTalkBoxForm">
<div class="layui-form-item layui-form-text" style="position: relative;" id="container">
<label class="layui-form-label"><span class="myspan">*</span>视频</label>
<div class="layui-input-inline">
<div class="addVideoFileBtn" id="addVideoFileBtn">
<i class="layui-icon layui-icon-add-1" style="font-size: 25px;"></i>
</div>
</div>
<div id="videoList" class="videoList" style="position: absolute;left: 133px;">
<!--<div class="videoItem">
<div class="imgItem-del">
<i class="layui-icon layui-icon-close-fill" style="font-size: 25px;"></i>
</div>
</div>-->
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="myspan">*</span>视频总时长:</label>
<div class="layui-input-inline">
<p id="videoAllNum" style="line-height: 39px;"></p>
</div>
</div>
</div>
</form>
</div>
<script src="../../static/lib/plupload-2.1.2/js/plupload.full.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../../static/js/ossUpload.js" type="text/javascript" charset="utf-8"></script>
<script src="../../static/js/ossUploadVideo.js" type="text/javascript" charset="utf-8"></script>
<script>
window.ossUpload.config({uploadType:2});
window.ossUploadVideo.config({
fileContentId:'videoList',
selectFileBtnId:'addVideoFileBtn',
mime_types:[{
title : "video files",
extensions : "mpg,m4v,mp4,flv,3gp,mov,avi,rmvb,mkv,wmv"
}]
}).create();
//获取上传文件前缀路径
var delVideos=window.ossUploadVideo.delVideos();
//获取视频时长
var duration=window.ossUploadVideo.getDuration();
</script>
</body>
</html>