前后端分离同步/异步实现文件上传(boot+vue+elementUI)
前后端分离同步/异步实现文件上传(boot+vue+elementUI)
·
前后端分离文件上传
环境
后端:Springboot
前端:vue+elementUI+axios
上传方法
elementUI中,文件上传的控件,同步和异步两种上传
文件上传控件,设计的机制就是异步上传
我们之前学的文件上传都是同步
同步:将文件和其他表单信息一起提交到控制器,在控制器中完成对象的保存操作,并且将文件存放于某个目录下,数据存储文件的访问路径
异步:
应用场景:当网站负荷本身就高,再去做文件的读写操作,对于CPU和内存是一种很大的消耗
用户大量进行上传文件操作,压力全部都在控制器
通常会用两次请求来完成图片的提交:
第一次请求:请求到主应用服务器中,用来申请一个token令牌允许用户将文件进行上传,并且将文件的存放地址一并响应的前端
第二次请求:将图片内容存储到另一个副服务器(OSS)中
同步实现:
前端
注:非完整表单,去饿了么UI直接展开CV大法即可
- el-upload空间 设置:auto-upload=“false”
<el-form-item label="用户头像">
<el-upload class="avatar-uploader" action="#"
:show-file-list="false"
:on-change="showImage"
:auto-upload="false">
<img v-if="imageUrl" :src="imageUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" style="line-height:178px"></i>
</el-upload>
</el-form-item>
<el-button type="primary" @click="submitForm('actrules')">提交</el-button>
- 通过:on-change 进行图片的预览,以及直接将文件的raw属性传递给提前定义的一个变量,改变了类型为对象类型({})
//上传图片 触发on-change
showImage(f){
//渲染照片
this.imageUrl=URL.createObjectURL(f.raw);
console.log(f.raw);
this.file=f.raw;
},
},
- 提交事件
//提交表单
submitForm () {
this.$refs.actrules.validate((valid) => {
if (valid) {
let param=new FormData(); //创建form对象
param.append("file",this.file);
let config={
Headers:{"Content-Type":"multipart/form-data"},
}
this.$axios.post("http://localhost:8888/add",param,config).then((response)=>{
console.log(response.data);
})
this.$message.success("成功")
} else {
console.log('error submit!!');
this.$message.error("请填写完表单")
return false;
}
});
},
后端
注:前后端分离需要解决跨域问题,在Controller上打注解 :@CrossOrigin(origins = {“*”})
@Value("${image.savepath}")
String savePath;
@PostMapping("/add")
public String add(@RequestParam(value = "file") MultipartFile file) {
//获取后缀
String suffix=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
//使用UUID重新生成文件名 防重名覆盖
String newName=UUID.randomUUID().toString()+suffix;
//文件路径
String imagePath=this.savePath+newName;
try {
//将文件发送到某个绝对路径上
file.transferTo(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
}
return imagePath;
}
异步实现
- action向后端请求token,成功触发on-success方法
<el-form-item label="商品图片">
<el-upload class="avatar-uploader" action="http://localhost:8888/good/getToken" :show-file-list="false"
:on-success="getImageToken">
<img v-if="imgUrl" :src="imgUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" style="line-height:176px"></i>
</el-upload>
</el-form-item>
- 只有action请求成功才会触发on-success方法
//将action中请求的token和file一同发送到文件服务器中
getImageToken(response,file){
console.log(response);
this.imgUrl=URL.createObjectURL(file.raw);
this.file=file.raw;
//将图片上传到另一个应用中(非主应用)
let param=new FormData();
param.append("file",file.raw);
param.append("token",response.token)
let config={
Headers:{"Content-Type":"multipart/form-data"}
}
this.$axios.post("http://localhost:8889/another/upload",param,config).then((response)=>{
console.log(response.data);
})
},
- 提交表单 到主程序
onSubmit(){
this.$refs.goodForm.validate((valid) => {
if (valid) {
// alert('submit!');
let param = new FormData(); //创建form对象
param.append("file", this.file);
let config = {
Headers: { "Content-Type": "multipart/form-data" },
}
//保存
this.$axios.post("http://localhost:8888/add", param, config).then((response) => {
console.log(response.data);
this.$message.success("成功")
})
} else {
console.log('error submit!!');
this.$message.error("请填写完表单")
return false;
}
});
}
- 获取token
@RequestMapping("/getToken")
public Imagetoken getToken(){
System.out.println("获取令牌");
String token= UUID.randomUUID().toString().replaceAll("-", "");
Imagetoken it = new Imagetoken();
it.setToken(token);
imagetokenService.save(it);
return it;
}
- 图片服务器:8889,获取token令牌成功后,方可将图片存储,并将存储地址响应给前端
@Autowired
ImagetokenService imagetokenService;
@Value("${image.savepath}")
String savePath;
@Value("${image.accesspath}")
String accessPath;
/*
* @param token 从前端传来的允许上传的令牌
* @param file 文件
* @return
*/
@PostMapping("/another/upload")
public Map<String,Object> upload(@RequestParam("token") String token, @RequestParam("file") MultipartFile file){
HashMap<String, Object> result = new HashMap<>();
try {
//令牌校验
//条件构造器,查询指定token
LambdaQueryWrapper<Imagetoken> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Imagetoken::getToken,token);
Imagetoken it = imagetokenService.getOne(queryWrapper);
//如果获取到token令牌
if(!Objects.isNull(it)){
//获取后缀
String suffix=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
//UUID重新生成文件名
String newName= UUID.randomUUID().toString()+suffix;
//设置文件路径
String savePath=this.savePath+newName;
String accessPath=this.accessPath+newName;
//保存文件
file.transferTo(new File(savePath));
//仅为模拟,懒得新建R
result.put("code",200);
result.put("savePath",savePath);
result.put("accrssPath",accessPath);
}else {
//没有获取到token
result.put("code",401);
result.put("message","非法请求");
}
} catch (IOException e) {
e.printStackTrace();
result.put("code", 500);
result.put("message", "请求失败,请重新尝试");
}
return result;
}
- 存储服务:8888 主程序
@Value("${image.savepath}")
String savePath;
@PostMapping("/add")
public String add(@RequestParam(value = "file") MultipartFile file) {
//获取后缀
String suffix=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
//使用UUID重新生成文件名 防重名覆盖
String newName=UUID.randomUUID().toString()+suffix;
//文件路径
String imagePath=this.savePath+newName;
try {
//将文件发送到某个绝对路径上
file.transferTo(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
}
return imagePath;
}
更多推荐
已为社区贡献1条内容
所有评论(0)