前后端分离文件上传

环境

后端:Springboot

前端:vue+elementUI+axios

上传方法

elementUI中,文件上传的控件,同步异步两种上传
文件上传控件,设计的机制就是异步上传
我们之前学的文件上传都是同步

同步:将文件和其他表单信息一起提交到控制器,在控制器中完成对象的保存操作,并且将文件存放于某个目录下,数据存储文件的访问路径

异步
应用场景:当网站负荷本身就高,再去做文件的读写操作,对于CPU和内存是一种很大的消耗
用户大量进行上传文件操作,压力全部都在控制器
通常会用两次请求来完成图片的提交:
第一次请求:请求到主应用服务器中,用来申请一个token令牌允许用户将文件进行上传,并且将文件的存放地址一并响应的前端
第二次请求:将图片内容存储到另一个副服务器(OSS)中

同步实现:

前端

注:非完整表单,去饿了么UI直接展开CV大法即可

  1. 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>
  1. 通过:on-change 进行图片的预览,以及直接将文件的raw属性传递给提前定义的一个变量,改变了类型为对象类型({})
 //上传图片 触发on-change
    showImage(f){
      //渲染照片
      this.imageUrl=URL.createObjectURL(f.raw);
      console.log(f.raw);
      this.file=f.raw;
    },
  },
    
  1. 提交事件
   //提交表单
      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;
    }

异步实现

  1. 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>
  1. 只有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);
      })
    },
  1. 提交表单 到主程序
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;
        }
      });

    }
  1. 获取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;
    }
  1. 图片服务器: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;
    }
  1. 存储服务: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;
    }
Logo

前往低代码交流专区

更多推荐