最近写一个小程序,涉及到了文件上传,主要是上传图片。后台是Java+SSM框架,用到了腾讯云COS对象存储,下面详细介绍一下我遇到的各种坑。如有错误,请多指教。
腾讯对象存储
首先Maven工程要导入下面几个包,其中一个是腾讯云存储的官方文档中说明的必须要的包。commons-codec包腾讯的文档中并没有说要导入,但没有的话会报找不到类org.apache.commons.codec.digest…pom文件如下
<!-- 腾讯云 -->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.4.10</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
导入这些包之后,要写一个Util工具
package com.queue.util;
import java.io.InputStream;
import java.util.Random;
import org.springframework.web.multipart.MultipartFile;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
public class TencentCOS {
// 存储桶名称
private static final String bucketName = "queue-1********610";
// secretId
private static final String secretId = "AKIDxwnBRi9***************************so9PdQCt";
//secretKey
private static final String secretKey = "jspvsjS0SnyW0*************************tq65lK";
// 初始化用户身份
private static COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 设置bucket的区域
private static ClientConfig clientConfig = new ClientConfig(new Region("ap-beijing"));
public static String uploadfile(MultipartFile file) throws Exception {
if (file.getSize() > 1024 * 1024) {
throw new Exception("上传图片大小不能超过1M!");
}
// 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
String fileName = null;
// fileName = localFile.getName();
// String substring = fileName.substring(fileName.lastIndexOf("."));
String originalFilename = file.getOriginalFilename();
String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
Random random = new Random();
try {
InputStream inputStream = file.getInputStream();
// 指定要上传到 COS 上的路径
fileName = "images/"+random.nextInt(10000) + System.currentTimeMillis() + substring;
// PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, localFile);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(inputStream.available());
metadata.setCacheControl("no-cache");
metadata.setHeader("Pragma", "no-cache");
metadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
metadata.setContentDisposition("inline;filename=" + fileName);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream, metadata);
cosclient.putObject(putObjectRequest);
}catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭客户端(后台线程)
cosclient.shutdown();
}
return fileName;
}
/**
* Description: 判断OSS服务文件上传时文件的contentType
*
* @param FilenameExtension 文件后缀
* @return String
*/
public static String getcontentType(String FilenameExtension) {
if (FilenameExtension.equalsIgnoreCase(".bmp")) {
return "image/bmp";
}
if (FilenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
FilenameExtension.equalsIgnoreCase(".jpg") ||
FilenameExtension.equalsIgnoreCase(".png")) {
return "image/jpeg";
}
if (FilenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (FilenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (FilenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (FilenameExtension.equalsIgnoreCase(".pptx") ||
FilenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (FilenameExtension.equalsIgnoreCase(".docx") ||
FilenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (FilenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
return "image/jpeg";
}
}
有这个工具类之后上传文件就很方便了,工具类中生成cos客户端在文件上传失败时自动重复上传5次,如果5次都失败了就会报错。
由于我的项目前端是微信小程序,微信小程序传给后台的文件类型是MultipartFile,为了使用方便在工具类中对MultipartFile做了一些操作。主要思路是:
- 提取文件名字+随机数(防重)
- getInputStream() 获取文件输入流
- 获取文件其他信息,metadata
如果您上传的文件是File类型而不是MultipartFile,您可以自己对上边工具类进行一些修改,或去看看其他帖子。
有了以上工具类,在上传文件时就可以这样做:
String suburl = TencentCOS.uploadfile(multfile);
具体后台代码如下:
Controller层
@Controller
@RequestMapping("/img")
public class ImgController {
@Autowired
private IImgService imgService;
/**
* 创建队列
* @param leaderopenid
* @param leaderwxname
* @param quename
* @param state
* @param introduce
* @param file
* @return
* @throws Exception
*/
@RequestMapping("/upload")
public @ResponseBody int doUpload(String leaderopenid, String leaderwxname, String quename, String state,String introduce, String location, @RequestParam(value = "file", required = false) MultipartFile file)
throws Exception {
return imgService.creatQue(leaderopenid, leaderwxname, quename, state, introduce, location, file);
}
service层
@Override
public int creatQue(String leaderopenid, String leaderwxname, String quename, String state, String introduce, String location,
MultipartFile multfile) throws Exception {
String url = "";
if(multfile!=null) {
String suburl = TencentCOS.uploadfile(multfile);
if (suburl.isEmpty()) return 0;
url = "https://queue-1258186610.cos.ap-beijing.myqcloud.com/" + suburl;
System.out.println(url);
}
// 这里是一些其他逻辑...
微信小程序部分
选择图片
/**
* 从相册选择图片添加
*/
ChooseImage() {
wx.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: (res) => {
console.log(res)
if (this.data.imgList.length != 0) {
this.setData({
imgList: this.data.imgList.concat(res.tempFilePaths)
})
} else {
this.setData({
imgList: res.tempFilePaths
})
}
var filep = res.tempFilePaths[0]
this.setData({
filep: filep
})
}
});
},
/**
* 点击图片查看
*/
ViewImage(e) {
wx.previewImage({
urls: this.data.imgList,
current: e.currentTarget.dataset.url
});
},
/**
* 删除图片
*/
DelImg(e) {
wx.showModal({
title: '删除图片',
content: '确定要删除这张图片吗?',
cancelText: '取消',
confirmText: '删除',
success: res => {
if (res.confirm) {
this.data.imgList.splice(e.currentTarget.dataset.index, 1);
this.setData({
imgList: this.data.imgList
})
}
}
})
},
上传图片
wx.uploadFile({
url: 'https://www.paion.xyz/queue/img/upload',
filePath: this.data.filep,
name: 'file',
formData: {
'leaderopenid': openid,
'leaderwxname': e.detail.value.leaderwxname,
'quename': e.detail.value.quename,
'state': "1",
'introduce': e.detail.value.introduce,
'location': app.globalData.LocationInfo
},
success: function (res) {
console.log(res)
if (res.data==0) {
wx.showToast({
title: '创建失败!',
icon: 'none'
})
}else {
wx.showToast({
title: '创建成功!',
duration: 1000
})
wx.navigateTo({
url: '/pages/passUser/passUser',
})
}
},
fail: function (res) {
wx.showToast({
title: '创建失败!',
icon: 'none'
})
}
})
如有不足欢迎吐槽。。。