近两天公司业务需要上传图片,在自己搭建文件上传服务器、使用七牛云存储、使用阿里oss对象存储这几种方式对比后,最终选择了阿里的oss方式。
下面是使用流程:
首先要注册个阿里的主张号,然后进入到管理控制台,选择产品服务,找到对象存储oss选项,没开通过的,先开通,具体细节不做详细讲解,主要上代码。
1.这个是controller层的
/**
*
图片上传
*
@author XXX
*
@date 2018/5/19
*/
@RestController
@RequestMapping("/comm")
public class CommonController {
//上传图片
@RequestMapping(value = "/upPicFile", method = RequestMethod.POST)
public Result upPicFile(HttpServletRequest request) throws Exception{
return ResultGenerator.genSuccessResult(fileParase(1,request));
}
//上传视频
@RequestMapping(value = "/upVidFile", method = RequestMethod.POST)
public Result upVidFile(HttpServletRequest request) throws Exception{
return ResultGenerator.genSuccessResult(fileParase(2,request));
}
//公用方法(视频或图片)
private List fileParase(int type,HttpServletRequest request) throws Exception{
List allFileName=new ArrayList();
int totalBytes = request.getContentLength();
String contentType = request.getContentType();
int position = contentType.indexOf("boundary=");
String startBoundary = "--" + contentType.substring(position+"boundary=".length());
String endBoundary = startBoundary + "--";
//将request的输入流读入到bytes中
InputStream inputStream = request.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
byte[] bytes = new byte[totalBytes];
dataInputStream.readFully(bytes);
dataInputStream.close();
//将字节读入到字符流中
BufferedReader reader = new BufferedReader(new StringReader(new String(bytes)));
int temPosition = 0;
boolean flag = false;
int end = 0;
while(true){
//当读取一次文件信息后
if(flag){
bytes = subBytes(bytes, end, totalBytes);
temPosition = 0;
reader = new BufferedReader(new StringReader(new String(bytes)));
}
//读取一行的信息:------WebKitFormBoundary5R7esAd459uwQsd5,即:lastBoundary
String str = reader.readLine();
//换行算两个字符
temPosition += str.getBytes().length + 2;
//endBoundary:结束
if(str==null||str.equals(endBoundary)){
break;
}
//表示头信息的开始(一个标签,input,select等)
if(str.startsWith(startBoundary)){
//判断当前头对应的表单域类型
str = reader.readLine(); //读取当前头信息的下一行:Content-Disposition行
temPosition += str.getBytes().length+2;
int position1 = str.indexOf("filename="); //判断是否是文件上传
if(position1 != -1){
//读取行,such as:Content-Type: image/jpeg,记录字节数,此处两次换行
//解析当前上传的文件对应的name(input标签的name),以及fieldname:文件名
// int position2 = str.indexOf("name=");
//去掉name与filename之间的"和;以及空格
// String name = str.substring(position2 + "name=".length() + 1, position1-3);
//去掉两个"
String filename = str.substring(position1 + "filename=".length() + + 1,str.length() - 1);
String suffix=filename.substring(filename.indexOf("."));
temPosition += (reader.readLine().getBytes().length + 4);
end = this.locateEnd(bytes, temPosition, totalBytes, endBoundary);
byte[] destBytes = new byte[end-temPosition-2];
System.arraycopy(bytes, temPosition, destBytes, 0, end-temPosition-2);
if(type==1) {
allFileName.add(OSSUtils.uploadPicWithStream(suffix, destBytes));
}
if(type==2) {
allFileName.add(OSSUtils.uploadVidWithStream(suffix, destBytes));
}
flag = true;
}
}
}
return allFileName;
}
/**
* 定位当前头信息的结束位置
* @param bytes
* @param start :开始位置
* @param end :结束位置
* @param endStr :比较字符串
* @return
* TODO
*/
public int locateEnd(byte[] bytes,int start,int end,String endStr){
byte[] endByte = endStr.getBytes();
for(int i=start+1;i
<
end
;
i
++){
if
(
bytes
[
i
]=
=endByte[0]){
int
k
=
1
;
while
(
k
<
endByte
.
length
){
if
(
bytes
[
i
+
k
] !=
endByte
[
k
]){
break
;
}
k
++;
//返回结束符的开始位置
if
(
k
=
=
endByte
.
length
){
return
i
;
}
}
}
return 0;
}
private static byte[] subBytes(byte[] b, int from, int end) {
byte[] result = new byte[end - from];
System.arraycopy(b, from, result, 0, end - from);
return result;
}
}
2. OSSUtils工具类
public class OSSUtils {
/**
* 上传文件
* @param name 想要保存的名字
* @param filename 文件的全名
*/
public static void uploadingFile(String name,String filename){
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(OSSCommons.FILEENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
//上传
ossClient.putObject(OSSCommons.PICTUREBUCKET, name, new File(filename));
ossClient.shutdown();
}
/**
* 文件下载
* @param name 想要下载文件名字
* @param filename 文件的保存名字
* @throws IOException
*/
public static void downloadFile(String name,String filename) throws IOException {
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(OSSCommons.FILEENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
// 下载object到文件
ossClient.getObject(new GetObjectRequest(OSSCommons.PICTUREBUCKET, name), new File(filename));
// 关闭client
ossClient.shutdown();
}
/**
* 视频断点上传
* @param name 想要保存的名字
* @param filename 文件的全名
* @throws Throwable
*/
public static void uploadingVideo(String name,String filename) throws Throwable {
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(OSSCommons.VIDEOENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
// 设置断点续传请求
UploadFileRequest uploadFileRequest = new UploadFileRequest(OSSCommons.VIDEOBUCKET, name);
// 指定上传的本地文件
uploadFileRequest.setUploadFile(filename);
// 指定上传并发线程数
uploadFileRequest.setTaskNum(5);
// 指定上传的分片大小
uploadFileRequest.setPartSize(1 * 1024 * 1024);
// 开启断点续传
uploadFileRequest.setEnableCheckpoint(true);
// 断点续传上传
ossClient.uploadFile(uploadFileRequest);
// 关闭client
ossClient.shutdown();
}
/**
* 视频断点下载
* @param name 想要下载文件名字
* @param filename 文件的保存名字
* @throws Throwable
*/
public static void downloadVideo(String name,String filename) throws Throwable {
// 创建OSSClient实例
OSSClient ossClient = new OSSClient(OSSCommons.VIDEOENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
// 下载请求,10个任务并发下载,启动断点续传
DownloadFileRequest downloadFileRequest = new DownloadFileRequest(OSSCommons.VIDEOBUCKET, name);
downloadFileRequest.setDownloadFile(filename);
downloadFileRequest.setTaskNum(10);
downloadFileRequest.setEnableCheckpoint(true);
// 下载文件
DownloadFileResult downloadRes = ossClient.downloadFile(downloadFileRequest);
// 下载成功时,会返回文件的元信息
downloadRes.getObjectMetadata();
// 关闭client
ossClient.shutdown();
}
/**
* 流方式上传图片
*
* @param
* @return
* @throws Exception
*/
public static String uploadPicWithStream(String suffix,byte[] bytes) throws Exception {
OSSClient ossClient = new OSSClient(OSSCommons.FILEENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
String fileName = System.currentTimeMillis() + suffix;
try {
ossClient.putObject(OSSCommons.PICTUREBUCKET, fileName, new ByteArrayInputStream(bytes));
ossClient.shutdown();
return OSSCommons.pictureURL_PREFIX.concat(fileName);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 流方式上传图片
*
* @param
* @return
* @throws Exception
*/
public static String uploadVidWithStream(String suffix,byte[] bytes) throws Exception {
OSSClient ossClient = new OSSClient(OSSCommons.VIDEOENDPOINT, OSSCommons.ACCESSKEYID, OSSCommons.ACCESSKEYSECRET);
String fileName = System.currentTimeMillis() + suffix;
try {
ossClient.putObject(OSSCommons.VIDEOBUCKET, fileName, new ByteArrayInputStream(bytes));
ossClient.shutdown();
return OSSCommons.VIDEOURL_PREFIX.concat(fileName);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
3.OSSCommons配置类
public class OSSCommons {
//视频下载前缀
public static final String VIDEOURL_PREFIX="阿里oss管理控制台中去找";
//文件预览前缀
public static final String pictureURL_PREFIX="阿里oss管理控制台中去找";
//文件服务器接口地址
public static final String FILEENDPOINT = "阿里oss管理控制台中去找";
//视频服务器接口地址
public static final String VIDEOENDPOINT = "阿里oss管理控制台中去找";
//阿里账号
public static final String ACCESSKEYID = "阿里oss管理控制台中去找";
public static final String ACCESSKEYSECRET = "阿里oss管理控制台中去找";
//文件桶名
public static final String PICTUREBUCKET = "阿里oss管理控制台中去找";
//视频桶名
public static final String VIDEOBUCKET = "阿里oss管理控制台中去找";
}
4.pom.xml文件依赖配置
com.aliyun
3.2.8
com.aliyun
1.1.0
好了,到这里后台的就完事了
下面就是前端调用的代码了
我这里前端使用的vue框架(elementUi,自己网上去找,就是用的这个风格)
let
formData
=
new
FormData
();
formData
.
append
(
"imgStream"
,
file
);
$
.
ajax
({
url:urlTemp
,
type:
'POST'
,
processData:
false
,
contentType :
false
,
data:formData
,
dataType:
"json"
,
success
:
function
(
res
){
//截取最后一个斜杠后的内容(返回的数据是能够访问的图片地址,所以我这里截取了文件名称)
let
temp
=
res
.
data
[
0
];
let
index
=
temp
.
lastIndexOf
(
"
\/
"
);
let
str
=
temp
.
substring
(
index
+
1
,
temp
.
length
);
//后面的自己根据业务逻辑去实现...
}
}
});
上诉前端代码用到的formData 、processData、contentType 这几个概念不清楚的自己去百度扫盲
这块就到这里了,代码复制过去可以直接用的,能用的上的自己拿去用,欢迎讨论