关于OSS的购买和配置,看这篇文章
https://blog.csdn.net/lianzhang861/article/details/82776197
我用的Spring mvc,maven项目,
1.首先引入包
com.aliyun.oss
aliyun-sdk-oss
2.8.3
2.创建OSSUtil
@Controller
public class OSSUtil {
@Value("${endpoint}")
private String endpoint;
@Value("${accessKeyId}")
private String accessKeyId;
@Value("${accessKeySecret}")
private String accessKeySecret;
@Value("${bucketName}")
private String bucketName;
//oss域名前缀,我绑定了CNAME所以用我的域名
private String key = "http://oss.zhulianzhang.com/";
/**
* 上传文件
*
* @param fileName 文件名
* @param inputStream 流
*/
public String uploadFileToOss(String fileName, InputStream inputStream,String folder) {
/**
* 创建OSS客户端
*/
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
String[] names = fileName.split("[.]");
String name = uuid + "." + names[names.length - 1];
ossClient.putObject(new PutObjectRequest(bucketName, folder + name, inputStream));
return key + folder + name;
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
} finally {
ossClient.shutdown();
}
return null;
}
/**
* 多文件上传
*/
public String[] uploadFilesToOss(String[] fileNames, InputStream[] inputStreams,String folder) {
/**
* 创建OSS客户端
*/
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue(
Arrays.asList(fileNames));
ConcurrentLinkedQueue streamConcurrentLinkedQueue = new ConcurrentLinkedQueue<>(
Arrays.asList(inputStreams));
Iterator inputStreamss = streamConcurrentLinkedQueue.iterator();
ConcurrentLinkedQueue c = new ConcurrentLinkedQueue();
for (Iterator iterator = concurrentLinkedQueue.iterator();
iterator.hasNext() && inputStreamss.hasNext(); ) {
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
String[] names = iterator.next().split("[.]");
String name = uuid + "." + names[names.length - 1];
ossClient.putObject(new PutObjectRequest(bucketName, folder + name, inputStreamss.next()));
c.add(key + folder + name);
}
return (String[]) c.toArray(new String[0]);
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
} finally {
ossClient.shutdown();
}
return null;
}
/**
* 删除图片 警告:在没有调用其他方法的情况下,请调用closeClient方法
*
* @param url URL全路径
*/
public void deleteImg(String url,String folder) {
OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
if (url == null || "".equals(url)) {
return;
}
String[] paths = url.split("[.]");
/**
* 文件夹是否存在
*/
if (!ossClient.doesObjectExist(bucketName, folder)) {
ossClient.putObject(bucketName, folder, new ByteArrayInputStream(new byte[0]));
}
String[] name = paths[paths.length - 2].split("[/]");
/**
* 对象是否存在
*/
if (ossClient
.doesObjectExist(bucketName,
folder + name[name.length - 1] + "." + paths[paths.length - 1])) {
/**
* 删除存在对象
*/
ossClient
.deleteObject(bucketName, folder + name[name.length - 1] + "." + paths[paths.length - 1]);
}
ossClient.shutdown();
}
}
配置信息我卸载config.properties调用的,调用方法可以看这篇文章有提到
https://blog.csdn.net/lianzhang861/article/details/82255867
注意:
@Value("${endpoint}") private String endpoint;
这样调用配置的方法貌似只能在controller中使用,所以我在util类前面也加了@controller
config.properties中的配置:
3.controller中使用
@Value("${imgFolder}")
private String imgFolder;
@Value("${videoFolder}")
private String videoFolder;
@Value("${coverFolder}")
private String coverFolder;
// 上传文件到阿里云OSS
@RequestMapping(value = "uploadFileToOss", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
@ResponseBody
public void uploadFileToOss(
@RequestParam Map params,
@RequestParam(value = "file") MultipartFile[] files,
HttpServletRequest request
){
String folder="";
//判断文件类型分配不同文件夹下
if(params.get("attachmentType").equals("IMAGE")){
folder=imgFolder;
}else if(params.get("attachmentType").equals("VIDEO")){
folder=videoFolder;
}
int userId=((TSystemUser)request.getSession().getAttribute("USER")).getUserId();
params.put("userId",userId);
//缩略图,不是视频则保存空
params.put("attachmentThumbnail","");
try {
//因为springmvc注解访问了inputstream封装成了MultipartFile,而inputstream只能被碰一次,所以得把MultipartFile
//在转换成inputstream格式,因为oss上传只接受inputstream格式
for (MultipartFile file : files) { //将MultipartFile转换成inputStream
String fileName = file.getOriginalFilename();
CommonsMultipartFile cFile = (CommonsMultipartFile) file;
DiskFileItem fileItem = (DiskFileItem) cFile.getFileItem();
InputStream inputStream = fileItem.getInputStream();
InputStream stream1;
InputStream stream2;
if(params.get("attachmentType").equals("VIDEO")){
//因为inputStream只能读取一次,所以要复制出来一份
ByteArrayOutputStream baosOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > -1) {
baosOutputStream.write(buffer, 0, len);
}
baosOutputStream.flush();
stream1 = new ByteArrayInputStream(baosOutputStream.toByteArray());
stream2 = new ByteArrayInputStream(baosOutputStream.toByteArray());
baosOutputStream.close();
}else{
stream1=inputStream;
stream2=inputStream;
}
//上传文件到oss返回路径
String fileUrl= ossUtil.uploadFileToOss(fileName,stream1,folder);
params.put("attachmentUrl",fileUrl);
params.put("attachmentName",fileName);
//如果是视频类型,则保存封面
if(params.get("attachmentType").equals("VIDEO")){
//用javacv进行视频截取帧
FFmpegFrameGrabber ff = new FFmpegFrameGrabber(stream2);
ff.start();
int length = ff.getLengthInFrames();
int i = 0;
Frame f = null;
while (i < length) {
// 过滤前5帧,避免出现全黑的图片,依自己情况而定
f = ff.grabImage();
if ((i > 5) && (f.image != null)) {
break;
}
i++;
}
//为了将图片上传OSS,将其转换成inputStream格式
InputStream cover=FrameToBufferedImage(f);
//上传视频封面到oss返回路径
String coverUrl= ossUtil.uploadFileToOss("cover.jpg",cover,coverFolder);
params.put("attachmentThumbnail",coverUrl);
}
inputStream.close();
stream1.close();
stream2.close();
attachmentService.saveFile(params);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//把Frame转换成inputStream类型
public static InputStream FrameToBufferedImage(Frame frame) throws IOException {
//创建BufferedImage对象
Java2DFrameConverter converter = new Java2DFrameConverter();
BufferedImage bufferedImage = converter.getBufferedImage(frame);
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "jpg", os);
InputStream is = new ByteArrayInputStream(os.toByteArray());
return is;
}
我写的是文件上传的通用接口,其中包括视频上传后截取视频封面,所以比较复杂,
关于视频截取封面,参考这个https://blog.csdn.net/lianzhang861/article/details/82014460
坑:
1.oss上传需要传入文件流inputStream或者file类型,而spring mvc接收前台form表单传输的文件流会访问inputstream,转为MultipartFile格式,inputstream只能访问一次,所以在spring mvc中直接获取inputstream会报空,所以需要将multipart格式转化成inputstream
2.转化后的inputstream也只能用一次,而我上传视频时需要先上传文件,在上传截取的封面,需要使用两次inputstream,所以必须复制出来一份inputstream,代码中有写到