vue + element-ui + springboot + 阿里云OSS 使用表单进行图片文件等的上传(具有上传滚动条效果)

vue__elementui__springboot__OSS__0">vue + element-ui + springboot + 阿里云OSS 使用表单进行图片文件等的上传(具有上传滚动条效果)

  • 使用vue + elementUI的前端页面中,使用el-upload组件,在添加,或者修改时。在表单中,加入图片。一起传给后台 springboot服务器,将文件上传给 阿里云OSS。

  • 具有上传效果 滚动条效果

  • 小编的代码项目地址:https://github.com/kedaya-github/vue_system

所需工具

  • 开通阿里云 OSS对象存储。创建Bucket

  • 前端vue + elementUI项目 —Visual Studio Code

  • 后端 springboot项目 — idea

  • 以下代码复制,修改配置和属性后可直接使用,话不多说,老表,上手吧。

vue_14">vue前端

  • 添加数据时,携带一个文件 + 表单基础数据,一起传递给后台:
  • 页面:
    在这里插入图片描述

html页面

  • 页面代码:

          <el-dialog title="添加品牌" :visible.sync="dialogFormVisible">
              <el-form :model="addBrand" ref="addBrand">
                  <el-form-item label="品牌名称">
                      <el-input v-model="addBrand.name" autocomplete="off"></el-input>
                  </el-form-item>
                  <el-form-item label="品牌首字母">
                      <el-input v-model="addBrand.letter" autocomplete="off"></el-input>
                  </el-form-item>
                  <el-form-item label="添加图片" ref="uploadElement" prop="img">
                      <!-- 
                          添加图片上传:
                          设置:auto-upload="false" ; 关闭组件的默认自动上传
                          action : 随便设置
                          :on-change="handleChange" : 当组件的图片修改时,调用函数方法,来判断图片的格式大小,并替换图片
                          :file-list="fileList" : 展示图片列表
                       -->
                      <el-upload
                          class="upload-demo"
                          action="#"
                          accept="image/jpeg,image/jpg,image/png"
                          ref="upload"
                          :auto-upload="false"
                          :on-change="handleChange"
                          :file-list="fileList">
                          <el-button size="small" type="primary">选择文件</el-button>
                          <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过2MB</div>
                      </el-upload>
                  </el-form-item>
                  <el-form-item>
                      <el-select v-model="checkList" multiple placeholder="请选择">
                          <el-option
                              v-for="(category,index) in categorys"
                              :key="index"
                              :label="category.name"
                              :value="category.id">
                          </el-option>
                      </el-select>
                  </el-form-item>
              </el-form>
              <div slot="footer" class="dialog-footer">
                  <el-button @click="dialogFormVisible = false">取 消</el-button>
                  <el-button type="primary" @click="upload()">确 定</el-button>
              </div>
          </el-dialog>
    

js代码,函数方法

  • 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;
          },
    

上传图片的原理解析

  • :on-change=“handleChange” : 在组件的图片改变时,会调用此函数方法,来判断图片的格式是否正确。
  • :file-list=“fileList” : 存储的文件列表,当前只上传一个文件,修改图片时,使用fileList.slice(-1);剪切掉之前的,只保留一个,存储在fileList属性中
  • 使用 new FormData(); 来存储各项数据 和 文件图片。发送post请求,访问后台

springboot后端代码

  • idea项目

添加上传文件所需要的 pom依赖

			<!-- TODO 上传文件到阿里云 oss对象存储空间 -->
			<dependency>
				<groupId>com.aliyun.oss</groupId>
				<artifactId>aliyun-sdk-oss</artifactId>
				<version>3.5.0</version>
			</dependency>

			<!--	TODO 	MultipartFile转File类型	DiskFileItem需要引入依赖-->
			<dependency>
				<groupId>commons-fileupload</groupId>
				<artifactId>commons-fileupload</artifactId>
				<version>1.3.1</version>
			</dependency>

controller方法

  • 使用普通的 formData表单提交,必须要 post请求

      @PostMapping("/add")
      public ResponseEntity<BaseResult> 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方法

  • 在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);
          }
      }
    

uploadUtils上传文件的工具类

  • 此工具类,可以实现,上传文件进度的滚动条获取

  • 该工具类 具有 上传,获取文件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).
                          <PutObjectRequest>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){
              // <yourObjectName>表示删除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;
              }
          }
      }
    

上传文件的带有滚动条效果

前端HTML代码:

  • 通过在js中设置一个 循环定时器,频繁的访问后台,获取后台的上传进度,返回给前台,在将进度值赋值进 进度条组件中。

      <template>
        <div>
              <el-upload
                  class="upload-demo"
                  action="http://localhost:8090/upload"
                  :on-progress="getProgress"
                  :file-list="fileList"
                  list-type="picture"
                  name="file"
                  :with-credentials="true"
                  style="width:30%">
                  <el-button size="small" type="primary">点击上传</el-button>
              </el-upload>
              <el-progress v-if="isTure" :text-inside="true" :stroke-width="26" :percentage="percentage" :color="customColors" style="width: 30%;"></el-progress>
        </div>
      </template>
      
      <script>
      export default {
        data() { 
          return {
              fileList: [{name: 'food.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}, {name: 'food2.jpeg', url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'}],
              customColors: [
                {color: '#f56c6c', percentage: 20},
                {color: '#e6a23c', percentage: 40},
                {color: 'rgb(33, 187, 207)', percentage: 60},
                {color: '#1989fa', percentage: 80},
                {color: 'rgb(81, 184, 81)', percentage: 100}
              ],  //颜色展示
              isTure : false ,  //是否展示 滚动条
              percentage : 0 , //滚动条数据
      
          }
        },
        methods:{
            getProgress(event, file, fileList){
              //将进度条打开
              this.isTure = true;
              //此方法的开始,将percentage赋值0
              this.percentage = 0;
      
              //访问后台,获取滚动条数据
              //每隔 0.1秒访问一次后台,获取一次进度条数据
              let time = setInterval( () =>{
                  //调用 获取进度条的方法
                  this.getJD();
      
                  if(this.percentage >= 100){
                      clearInterval(time);
                      this.isTure = false;
                      this.percentage = 0;
                      return;
                  }
              } , 100);
            },
            async getJD(){
              let {data} = await this.$ajax.get("/upload/jd");
              console.log(data);
              this.percentage = data;
            }
        },
       }
      </script>
      
      <style>
      </style>
    

后端springboot代码

  • 在图片上传时。上传的进度会一直在后台,执行。并且返回有进度条。我们将进度条值,存储起来。

  • 然后在图片上传中时,我们可以进行其他的访问操作,在访问 设置定时器循环 频繁的访问后台,获取进度值。

  • 以下调用的方法,都是工具类 uploadUtils中的方法。

      @RequestMapping("/upload")
      @RestController
      public class UploadController {
      
          @PostMapping
          public ResponseEntity<String> upload(HttpServletRequest request , MultipartFile file) throws IOException {
              UploadUtils.upload(request , file , "");
              return ResponseEntity.ok("上传成功");
          }
      
          @GetMapping("/jd")
          public ResponseEntity<Integer> getJD(HttpServletRequest request) throws InterruptedException {
              //获取进度
              Integer percent = UploadUtils.getPercent(request);
              System.out.println("我被访问了,进度"+percent);
              return ResponseEntity.ok(percent);
          }
      
          @DeleteMapping("/delete")
          public ResponseEntity<String> delete(){
              UploadUtils.delete("强.jpg" , null);
              return ResponseEntity.ok("删除成功");
          }
      }
    

传成功");
}

	    @GetMapping("/jd")
	    public ResponseEntity<Integer> getJD(HttpServletRequest request) throws InterruptedException {
	        //获取进度
	        Integer percent = UploadUtils.getPercent(request);
	        System.out.println("我被访问了,进度"+percent);
	        return ResponseEntity.ok(percent);
	    }
	
	    @DeleteMapping("/delete")
	    public ResponseEntity<String> delete(){
	        UploadUtils.delete("强.jpg" , null);
	        return ResponseEntity.ok("删除成功");
	    }
	}

http://www.niftyadmin.cn/n/1411005.html

相关文章

C# 的函数编程

http://www.oschina.net/translate/functional-programming-in-csharp?print

DBA必备技能:通过truss跟踪解决监听无法启动案例

作者简介&#xff1a;刘斌&#xff0c;云和恩墨高级技术专家&#xff0c;擅长数据库故障诊断分析&#xff0c;数据库性能优化&#xff0c;自动化运维开发&#xff0c;坚持学习、写作、分享&#xff0c; 在Oracle DBA的日常工作中&#xff0c;通过各种跟踪手段&#xff0c;从数据…

XML有关键字无法识别怎么办?

比如XML会视< 或 >为标记的开始结束&#xff0c;这时候就需要用<![CDATA[ xxxxxx ]]> 把你需要写入的结点内容括起来&#xff0c;如下<select id"PickUpCalUnit_LNGJTM" parameterClass"Hashtable"><![CDATA[SELECT b.CalculatorU…

SpringCloud概念

SpringCloud概念 微服务概述 服务 为别人做事情&#xff0c;满足别人需要在代码中我们写一段代码&#xff0c;提供一个接口供别人使用服务。 集群&分布式概述 单机结构 一个系统业务量很小的时候&#xff0c;代码全放在一个项目中。然后项目部署在一个服务器上&#…

Nginx基于用户名和密码的访问控制

1 安装相关包yum install -y httpd-tools2 创建校验文件htpasswd -cb /etc/nginx/.htpasswd user1 passwd1 chown nginx:nginx /etc/nginx/.htpasswd chmod 400 /etc/nginx/.htpasswd3 加载校验文件vim /etc/nginx/nginx.conf加入如下信息&#xff1a;server {[...]auth_basic …

elmentUI使用tabs标签页展示动态路由

elementUI中tabs标签页中展示动态路由内容 在home界面中添加tabs标签页&#xff0c;导航栏点击坐标路由时&#xff0c;在标签页中&#xff0c;展示路由中的数据。实现动态的效果。 vuex中存储数据 在vue的vuex中存储&#xff0c;标签页路由的相关数据 store.index.js文件中&a…

React 服务端渲染如此轻松 从零开始构建前后端应用

参加或留意了最近举行的JSConf CN 2017的同学&#xff0c;想必对 Next.js 不再陌生&#xff0c; Next.js 的作者之一到场进行了精彩的演讲。其实在更早些时候&#xff0c;由 Facebook 举办的 React Conf 2017&#xff0c;他就到场并有近40分钟的分享。但两次分享带来的 demo 都…