IDEA+springboot+thymeleaf调用腾讯云对象存储实现图片上传和调用
前言
本人小白,也开始学springboot,各位大神勿喷。因为项目需要,所以需要实现让用户在前端上传图片,保存到后端,然后在前端显示,类似个人头像这个功能。
后面查到腾讯云有个叫对象存储的东西,可以把图片存在这里面而不用放在服务器上,于是就想用对象存储来做这件事。
为实现这个功能看了不少博客,很遗憾我都忘记是哪些前辈写的了,但是我发现没有一整套的东西来说这件事,基本是分散的,所有就有了写这篇文章和的意图,也算对这阶段的一个总结。
流程
1.前端需要用JS(JQuery)来读取本地文件,并上传到后端。
2.后端调用腾讯云的对象存储,将文件存在里面
3.后端获取对象存储对应用户文件夹下的所有图片路径,因为对象存储上的图片是可以根据一个域名访问到的,可以把存储桶的访问设为公开。
4.把后端的图片路径传到前端显示。
实现
1.前端页面代码:这里主要是一个按钮,点击按钮触发事件
<div >
<p>上传图片</p>
<input style="display: none" type="file" name="file" id="file"/><br>
<img src="" id="img" style="width: 20rem;height: 15rem;">
<button onclick="$('#file').click()">选择</button>
<button onclick="updateImg();">上传</button>
</div>
2.对应前端的JS代码:
var file;
//图片上传到后端的事件
function updateImg() {
var fd = new FormData();
fd.append("file",file);
$.ajax({
type: "post",
url: "uploadImg",
data: fd,
processData: false,
contentType: false,
dataType:"text",
//把文件传到后端
success: function (data) {
$("#img").attr("src",fileurl);//图片预览
if(data){
alert("上传成功");
//location.reload();
}
},
error: function () {
}, xhr: function () {
var xhr = $.ajaxSettings.xhr();
var ot,oloaded,perload,pertime;
xhr.upload.onload = function (){
ot = new Date().getTime();
oloaded=0;
};
xhr.upload.onprogress = function (evt) {
var loaded = evt.loaded;
var tot = evt.total;
var per = Math.floor(100*loaded/tot);
};
return xhr;
}, complete: function () {
}
})
}
//点击选择本地文件事件
$('#file').on('change', function(){
file = document.getElementById('file').files[0];
var fileurl = window.URL.createObjectURL(file);
$("#img").attr("src",fileurl);
});
3.新建TencentCOS的JAVA文件:
实现将图片传到对象存储里
注:在桶里新建一个叫images的文件夹,注意修改以下代码里XXX的内容
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.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 腾讯云对象存储
*
*/
public class TencentCOS {
//注意修改以下XXXX的内容,该为自己的
// 此处填写的存储桶名称
private static final String bucketName = "XXXXX";
// secretId
private static final String secretId = "XXXXXX";
// secretKey
private static final String secretKey = "XXXXXXXXX";
// 1 初始化用户身份信息(secretId, secretKey,可在腾讯云后台中的API密钥管理中查看!
private static COSCredentials cred = new BasicCOSCredentials(secretId,secretKey);
// 2 设置bucket的区域, COS地域的简称请参照
// https://cloud.tencent.com/document/product/436/6224,根据自己创建的存储桶选择地区
private static ClientConfig clientConfig = new ClientConfig(new Region("XXXXXXX"));
/**
* 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20 M 以下的文件使用该接口 大文件上传请参照 API 文档高级 API 上传
*
* @param localFile
*/
public static String uploadfile(File localFile,String wechat) throws CosClientException, CosServiceException {
// 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
String fileName = localFile.getName();
try {
String substring = fileName.substring(fileName.lastIndexOf("."));
Random random = new Random();
// 指定要上传到 COS 上的路径
fileName = "images/"+Now.getNowTime("yyyyMMddHHmmssSSS")+substring;
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName , localFile);
PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭客户端(关闭后台线程)
cosclient.shutdown();
}
return fileName;
}
/**
*
* @Title: downFile
* @Description: 下载文件
* @return
*/
public static void downFile() {
// 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
//要下载的文件路径和名称
String key = "/.jpg";
// 指定文件的存储路径
File downFile = new File("src/test/resources/mydown.txt");
// 指定要下载的文件所在的 bucket 和对象键
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
ObjectMetadata downObjectMeta = cosclient.getObject(getObjectRequest, downFile);
}
/**
* 删除文件
*
* @param key
*/
public static void deletefile(String key) throws CosClientException, CosServiceException {
// 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// 指定要删除的 bucket 和路径
cosclient.deleteObject(bucketName, key);
// 关闭客户端(关闭后台线程)
cosclient.shutdown();
}
//读取文件中的所有文件路径
public static List<String> findallfile(){
COSClient cosclient = new COSClient(cred, clientConfig);
// Bucket的命名格式为 BucketName-APPID ,此处填写的存储桶名称必须为此格式
String bucketName = "XXXXX";
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
// 设置bucket名称
listObjectsRequest.setBucketName(bucketName);
// prefix表示列出的object的key以prefix开始
listObjectsRequest.setPrefix("images/";
// deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
listObjectsRequest.setDelimiter("");
// 设置最大遍历出多少个对象, 一次listobject最大支持1000
listObjectsRequest.setMaxKeys(1000);
ObjectListing objectListing = null;
do {
try {
objectListing = cosclient.listObjects(listObjectsRequest);
} catch (CosServiceException e) {
e.printStackTrace();
// return "none";
} catch (CosClientException e) {
e.printStackTrace();
// return;
}
// common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
List<String> commonPrefixs = objectListing.getCommonPrefixes();
//定义img存储所有图片路径,返回到前端要用的
List<String> imgs = new ArrayList<>();
// object summary表示所有列出的object列表
List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
// 文件的路径key
String key = cosObjectSummary.getKey();
//System.out.println(key);
imgs.add("https://你的桶名.cos.你的地区名.myqcloud.com/"+key);
// 文件的etag
String etag = cosObjectSummary.getETag();
// 文件的长度
long fileSize = cosObjectSummary.getSize();
// 文件的存储类型
String storageClasses = cosObjectSummary.getStorageClass();
}
String nextMarker = objectListing.getNextMarker();
listObjectsRequest.setMarker(nextMarker);
//返回文件路径
return imgs;
} while (objectListing.isTruncated());
}
}
4.新建名为:CosController控制类,将前后端绑定
import com.example.finalappointment.others.TencentCOS;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.Map;
@Controller
public class CosController {
/**
* 把文件上传到腾讯云存储服务器
* @param multfile
* @return
* @throws Exception
*/
@PostMapping("/uploadImg")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile multfile, Map<String,Object> map)throws Exception{
// 获取文件名
String fileName = multfile.getOriginalFilename();
// 获取文件后缀
String prefix=fileName.substring(fileName.lastIndexOf("."));
// 用uuid作为文件名,防止生成的临时文件重复
final File excelFile = File.createTempFile("imagesFile-"+System.currentTimeMillis(), prefix);
// 将MultipartFile转为File
multfile.transferTo(excelFile);
//调用腾讯云工具上传文件
String fileName1 = TencentCOS.uploadfile(excelFile,wechat);
//程序结束时,删除临时文件
deleteFile(excelFile);
//存入图片名称,用于网页显示
map.put("imageName",fileName1);
//返回图片名称
return "index";
}
/**
* 删除临时文件
* @param files
*/
private void deleteFile(File... files) {
for (File file : files) {
if (file.exists()) {
file.delete();
}
}
}
}
5.后端调用函数获取对象存储的所有文件名
//这里我要用thymeleaf的语法
@GetMapping("前端页面名")
public String showimg(ModelMap modelMap){
//调用COS的函数获取所有文件路径
List<String> imgpaths = TencentCOS.findallfile();
//所有文件路径传到前端去
modelMap.addAttribute("imgpaths",imgpaths );
return "前端页面名";
}
6.前端接收图片
<!doctype html>
<html lang="zh-CN" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!--显示后台传过来的图片-->
<div th:each="imgpath:${imgpaths}">
<img th:src="${imgpath}" id="img1" style="width: 20rem;height: 15rem;">
</body>
</html>
总结
这里只是实现上传和预览,没有针对单个用户上传进行区分,这一点根据大家的需求自己调整。
以上肯定还有很多不足之处,希望大家多多指教。