使用vue + elementUI的前端页面中,使用el-upload组件,在添加,或者修改时。在表单中,加入图片。一起传给后台 springboot服务器,将文件上传给 阿里云OSS。
具有上传效果 滚动条效果
小编的代码项目地址:https://github.com/kedaya-github/vue_system
开通阿里云 OSS对象存储。创建Bucket
前端vue + elementUI项目 —Visual Studio Code
后端 springboot项目 — idea
以下代码复制,修改配置和属性后可直接使用,话不多说,老表,上手吧。
页面代码:
选择文件
只能上传jpg/png文件,且不超过2MB
js代码:
与html代码,配合一起使用。
具有判断图片的格式 和 大小的方法。
一次只能上传一个文件
//图片方法
//图片进行修改的方法
handleChange(file, fileList) {
let bo = this.beforeAvatarUpload(file);
if(!bo){
//图片不符合规范
this.fileList = []; //图片列表赋值为空
return;
}
//如果图片符合 规范,将之前的图片剪切,覆盖掉
this.fileList = fileList.slice(-1);
},
//图片判断,大小
beforeAvatarUpload(file) {
const isJPG = file.raw.type == 'image/jpeg';
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isJPG) {
this.$message.error('上传头像图片只能是 JPG 格式!');
}
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过 2MB!');
}
return isJPG && isLt2M;
},
//添加方法
async upload(){
//将下拉框 选择的分类id,拼接成字符串,赋值给 addBrand对象中
this.addBrand.categoryIds = this.checkList.toString();
//上传图片 + 表单数据一起传给后台
let fd = new FormData();
//判断是否有文件
if(this.fileList.length != 0){
fd.append("file" , this.fileList[0].raw);
}
//添加格外的表单基本数据
fd.append("name" , this.addBrand.name);
fd.append("letter" , this.addBrand.letter);
fd.append("categoryIds" , this.addBrand.categoryIds);
//必须使用 post请求,因为是原生的 数据提交
let {data} = await this.$ajax.post("/brand/add" , fd);
this.findAll();
this.dialogFormVisible = false;
},
com.aliyun.oss
aliyun-sdk-oss
3.5.0
commons-fileupload
commons-fileupload
1.3.1
使用普通的 formData表单提交,必须要 post请求
@PostMapping("/add")
public ResponseEntity add(MultipartFile file , HttpServletRequest request , Brand brand) throws IOException {
brandService.add(brand);
BaseResult br = brandService.upload(request,file,brand);
//将返回的 br中data 的url地址,赋值给 brand对象地址的 image中
brand.setImage(String.valueOf(br.getData()));
//将当前brand对象的 image属性修改
//修改数据库中的 image字段
brandService.updateImage(brand);
//br为 图片上传的结果, data为上传上图片的url路径
return ResponseEntity.ok(br);
}
在service方法中,调用 uploadUtils工具类,进行提交
当前的提交效果为: 每个数据用户都拥有自己的一个 目录文件夹,来存储文件。 文件夹名称为 brand的id
public BaseResult upload(HttpServletRequest request , MultipartFile file , Brand brand) throws IOException {
//上传图片
String url = "";
//判断file是否为null,前端是否传过来了 图片
if (file == null){
return new BaseResult(CommonUtils.SUCCESS , "失败" , url);
}
try {
//三个参数: file:文件 , request : 请求 , tableName : 目录名称,没有目录可以为"" or null
UploadUtils.upload(request , file , "brand_"+brand.getId());
url = UploadUtils.getURL(file.getOriginalFilename() , "brand_"+brand.getId());
return new BaseResult(CommonUtils.SUCCESS , "成功" , url);
} catch (Exception e) {
e.printStackTrace();
return new BaseResult(CommonUtils.SUCCESS , "失败" , url);
}
}
此工具类,可以实现,上传文件进度的滚动条获取
该工具类 具有 上传,获取文件url地址,删除。等功能
会自动将 MultipartFile 类型 转为 File类型
可以添加 添加上传文件的目录
/**
* @author 遗憾就遗憾吧
* @Date 2019/11/15
* @jdk 1.8
* 阿里云oss上传文件 工具类
*/
public class UploadUtils {
// Endpoint以杭州为例,其它Region请按实际情况填写。
//endpoint 的 地址需要与你的 Bucket地址对应。 如果Bucket为shanghai,就设置为shanghai
private static String endpoint = "http://oss-cn-shanghai.aliyuncs.com";
//云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
private static String accessKeyId = "";
private static String accessKeySecret = "";
private static String bucketName = "2019-11-15";
//滚动条值
private static Integer percent = 0;
/**
* 用于外界赋值,目录名称。
* 需求:每个品牌都拥有自己独立的一个 目录来存储文件
*/
public static void upload(HttpServletRequest request , MultipartFile file , String tableName) throws IOException {
System.out.println(file.getOriginalFilename());
//TODO 进行赋值 文件的上传名称 包含目录 , 在赋值 tableName 中最后加上 / 隔开
String objectName = "";
if (tableName != null && !tableName.isEmpty()){
objectName = tableName+"/"+file.getOriginalFilename();
}else{
objectName = file.getOriginalFilename();
}
//每次进入方法,就滚动条设置0
setPercent(request);
//将 MultipartFile 转为 File类型,进行上传到 oss
File toFile = null;
if (file.equals("") || file.getSize() <= 0) {
file = null;
} else {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
}
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// 带进度条的上传。
PutObjectResult putObjectResult = ossClient.putObject(new PutObjectRequest(bucketName, objectName, toFile).
withProgressListener(new PutObjectProgressListener(request)));
} catch (Exception e) {
e.printStackTrace();
}
// 关闭OSSClient。
ossClient.shutdown();
//最后删除掉,刚创建的 本地临时文件
deleteTempFile(toFile);
}
/**
* @param objectName 文件的名称
* @param tableName 目录的名称
* @return 获取上传文件的的 地址值
*/
public static String getURL(String objectName , String tableName){
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
//通过 ossClient 可以获取 刚上传文件的 访问URL
Date expiration = new Date(new Date().getTime() + 5 * 60 * 10000);
//判断目录是否 为空 或者 null
if (tableName != null && !tableName.isEmpty()){
objectName = tableName+"/"+objectName;
}
URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
System.out.println(url.toString());
// 关闭OSSClient。
ossClient.shutdown();
return url.toString().split("\\?")[0];
}
/**
* @param objectName 删除阿里云OSS上 存储的对应 fileName的文件
* @param tableName 删除阿里云OSS上 存储的对应 fileName的目录
*/
public static void delete(String objectName , String tableName){
// 表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
//判断目录是否 为空 或者 null
if (tableName != null && !tableName.isEmpty()){
objectName = tableName+"/"+objectName;
}
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 删除文件。
ossClient.deleteObject(bucketName, objectName);
// 关闭OSSClient。
ossClient.shutdown();
}
/**
* @param request 获取当前滚动条的数值
* @return
*/
public static Integer getPercent(HttpServletRequest request){
return UploadUtils.percent;
}
/**
* @param request 将滚动条 重置0
*/
private static void setPercent(HttpServletRequest request){
//每次进入,upload上传图片方法,就赋值 upload_percent 为0 ; 重置长度
//防止 GET请求获取 进度条值 upload_percent时,出现异步,先获取的问题
//request.getSession().setAttribute("upload_percent" , 0);
UploadUtils.percent = 0;
}
/**
* 获取流文件,将流文件 赋值给 file
* @param ins
* @param file
*/
private static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除本地临时文件
* @param file
*/
private static void deleteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
/**
* 上传图片的 滚动条进行 存储到 session中。
* 当前存储在成员变量中。可能会产生某些问题
*/
private static class PutObjectProgressListener implements ProgressListener {
private long bytesWritten = 0;
private long totalBytes = -1;
private boolean succeed = false;
private HttpServletRequest request;
public PutObjectProgressListener(HttpServletRequest request) {
this.request = request;
}
@Override
public void progressChanged(ProgressEvent progressEvent) {
long bytes = progressEvent.getBytes();
ProgressEventType eventType = progressEvent.getEventType();
switch (eventType) {
case TRANSFER_STARTED_EVENT:
System.out.println("Start to upload......");
break;
case REQUEST_CONTENT_LENGTH_EVENT:
this.totalBytes = bytes;
System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
break;
case REQUEST_BYTE_TRANSFER_EVENT:
this.bytesWritten += bytes;
if (this.totalBytes != -1) {
int percent = (int) (this.bytesWritten * 100.0 / this.totalBytes);
System.out.println("我在赋值中"+percent);
// request.getSession().setAttribute("upload_percent",percent);
UploadUtils.percent = percent;
System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
} else {
System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
}
break;
case TRANSFER_COMPLETED_EVENT:
this.succeed = true;
System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
break;
case TRANSFER_FAILED_EVENT:
System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
break;
default:
break;
}
}
public boolean isSucceed() {
return succeed;
}
}
}
通过在js中设置一个 循环定时器,频繁的访问后台,获取后台的上传进度,返回给前台,在将进度值赋值进 进度条组件中。
点击上传
在图片上传时。上传的进度会一直在后台,执行。并且返回有进度条。我们将进度条值,存储起来。
然后在图片上传中时,我们可以进行其他的访问操作,在访问 设置定时器循环 频繁的访问后台,获取进度值。
以下调用的方法,都是工具类 uploadUtils中的方法。
@RequestMapping("/upload")
@RestController
public class UploadController {
@PostMapping
public ResponseEntity upload(HttpServletRequest request , MultipartFile file) throws IOException {
UploadUtils.upload(request , file , "");
return ResponseEntity.ok("上传成功");
}
@GetMapping("/jd")
public ResponseEntity getJD(HttpServletRequest request) throws InterruptedException {
//获取进度
Integer percent = UploadUtils.getPercent(request);
System.out.println("我被访问了,进度"+percent);
return ResponseEntity.ok(percent);
}
@DeleteMapping("/delete")
public ResponseEntity delete(){
UploadUtils.delete("强.jpg" , null);
return ResponseEntity.ok("删除成功");
}
}
传成功");
}
@GetMapping("/jd")
public ResponseEntity getJD(HttpServletRequest request) throws InterruptedException {
//获取进度
Integer percent = UploadUtils.getPercent(request);
System.out.println("我被访问了,进度"+percent);
return ResponseEntity.ok(percent);
}
@DeleteMapping("/delete")
public ResponseEntity delete(){
UploadUtils.delete("强.jpg" , null);
return ResponseEntity.ok("删除成功");
}
}