vue+springboot实现文件上传

①后端springboot创建controller

FileController:

package com.example.springboot.controller;

import cn.hutool.core.io.FileUtil;
import com.example.springboot.common.AuthAccess;
import com.example.springboot.common.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;

@RestController
@RequestMapping("/file")
public class FileController {
    @Value("${ip:localhost}")
    String ip;

    @Value("${server.port}")
    String port;

    private static final String ROOT_PATH=System.getProperty("user.dir")+File.separator+"files";
    @PostMapping("/upload")
    public Result upload(MultipartFile file) throws IOException{
        String originFilename= file.getOriginalFilename();
        String mainName= FileUtil.mainName(originFilename);
        String extName=FileUtil.extName(originFilename);
        if(!FileUtil.exist(ROOT_PATH)){
            FileUtil.mkdir(ROOT_PATH);
        }
        if(FileUtil.exist(ROOT_PATH+File.separator+originFilename)){
            originFilename=System.currentTimeMillis()+"_"+mainName+"."+extName;
        }
        File saveFile=new File(ROOT_PATH+File.separator+originFilename);
        file.transferTo(saveFile);
        String url="http://"+ip+":"+port+"/file/download/"+originFilename;
        return Result.success(url);
    }

    @AuthAccess
    @GetMapping("/download/{filename}")
    public void download(@PathVariable String filename,HttpServletResponse response) throws IOException {
//        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); // 附件下载
        response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(filename, "UTF-8")); // 预览
        String filePath=ROOT_PATH+File.separator+filename;
        if(!FileUtil.exist(filePath)){
            return;
        }
        byte[] bytes=FileUtil.readBytes(filePath);
        ServletOutputStream outputStream=response.getOutputStream();
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }
}

②修改yml文件:配置url和port等全局变量

application.yml:

server:
  port: 9090

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://${ip}:3306/honey2024?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8
    username: root
    password: 123456
  servlet:
    multipart:
      max-file-size: 20MB
      max-request-size: 20MB
ip: localhost

③配置全局异常文件

GlobalExeception:

package com.example.springboot.exception;

import com.example.springboot.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
public class GlobalExeception {

    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Result serviceException(ServiceException e){
        return Result.error(e.getCode(),e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result globalException(Exception e){
        e.printStackTrace();
        return Result.error("500","系统错误");
    }

}

运行效果:

访问一下这个url,发现可以预览:说明上传功能和预览,下载功能就完成了

至此后端的工作已经完成

④前端修改编写页面

HomeView.vue:

<template>
  <div>
    <el-container>
      <!--    侧边栏  -->
      <el-aside :width="asideWidth" style="min-height: 100vh; background-color: #001529">
        <div style="height: 60px; color: white; display: flex; align-items: center; justify-content: center">
          <img src="@/assets/logo1.png" alt="" style="width: 40px; height: 40px">
          <span class="logo-title" v-show="!isCollapse">honey2024</span>
        </div>

        <el-menu :collapse="isCollapse" :collapse-transition="false" router background-color="#001529" text-color="rgba(255, 255, 255, 0.65)" active-text-color="#fff" style="border: none" :default-active="$route.path">
          <el-menu-item index="/">
            <i class="el-icon-menu"></i>
            <span slot="title">系统首页</span>
          </el-menu-item>
          <el-menu-item index="/1">
            <i class="el-icon-house"></i>
            <span slot="title">系统首页</span>
          </el-menu-item>
          <el-menu-item index="/2">
            <i class="el-icon-house"></i>
            <span slot="title">系统首页</span>
          </el-menu-item>
          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-menu"></i>
              <span>信息管理</span>
            </template>
            <el-menu-item>用户信息</el-menu-item>
            <el-menu-item>管理员信息</el-menu-item>
            <el-menu-item index="/">系统首页</el-menu-item>
          </el-submenu>
        </el-menu>

      </el-aside>

      <el-container>
        <!--        头部区域-->
        <el-header>

          <i :class="collapseIcon" style="font-size: 26px" @click="handleCollapse"></i>
          <el-breadcrumb separator-class="el-icon-arrow-right" style="margin-left: 20px">
            <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
            <el-breadcrumb-item :to="{ path: '/user' }">用户管理</el-breadcrumb-item>
          </el-breadcrumb>

          <div style="flex: 1; width: 0; display: flex; align-items: center; justify-content: flex-end">
            <i class="el-icon-quanping" style="font-size: 26px" @click="handleFull"></i>
            <el-dropdown placement="bottom">
              <div style="display: flex; align-items: center; cursor: default">
                <img src="@/assets/logo1.png" alt="" style="width: 40px; height: 40px; margin: 0 5px">
                <span>管理员</span>
              </div>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item>个人信息</el-dropdown-item>
                <el-dropdown-item>修改密码</el-dropdown-item>
                <el-dropdown-item @click.native="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </div>

        </el-header>

        <!--        主体区域-->
        <el-main>
          <div style="box-shadow: 0 0 10px rgba(0,0,0,.1); padding: 10px 20px; border-radius: 5px; margin-bottom: 10px">
            早安,骚年,祝你开心每一天!
          </div>
          <div style="display: flex;">
            <el-card style="width: 30%;margin-right: 10px;">
              <div slot="header" class="clearfix">
                <span>青哥哥带你做毕设2024</span>
              </div>
              <div>
                2024毕设正式开始了!青哥哥带你手把手敲出来!
                <div style="margin-top: 20px">
                  <div style="margin: 10px 0"><strong>主题色</strong></div>
                  <el-button type="primary">按钮</el-button>
                  <el-button type="success">按钮</el-button>
                  <el-button type="warning">按钮</el-button>
                  <el-button type="danger">按钮</el-button>
                  <el-button type="info">按钮</el-button>
                </div>
              </div>
            </el-card>
            <el-card style="width: 70%;">
              <div slot="header" class="clearfix">
                <span>渲染用户的数据</span>
              </div>
              <div>
                <el-table :data="users">
                  <el-table-column label="ID" prop="id"/>
                  <el-table-column label="用户名" prop="username"/>
                  <el-table-column label="姓名" prop="name"/>
                  <el-table-column label="地址" prop="address"/>
                  <el-table-column label="文件上传">
                    <template v-slot="scope">
                      <el-upload
                          action="http://localhost:9090/file/upload"
                          :show-file-list="false"
                          :headers="{token: user.token}"
                          :on-success="(row,file,fileList)=>handleTableFileUpload(scope.row,file,fileList)"
                      >
                        <el-button size="mini" type="primary">点击上传</el-button>
                      </el-upload>
                    </template>
                  </el-table-column>
                  <el-table-column label="文件下载">
                    <template v-slot="scope">
                      <el-image v-if="scope.row.avatar" :src="scope.row.avatar" style="width: 50px;height: 50px"></el-image>
                      <div>
                        <el-button @click="preview(scope.row.avatar)">
                          预览
                        </el-button>
                      </div>
                    </template>
                  </el-table-column>
                </el-table>
              </div>
            </el-card>
          </div>
          <div style="display: flex;margin: 10px 0">
            <el-card style="width: 50%;margin-right: 10px;">
              <div slot="header" class="clearfix">
                <span>文件上传下载</span>
              </div>
              <div>
                <el-upload
                    action="http://localhost:9090/file/upload"
                    list-type="picture"
                    :headers="{token: user.token}"
                    :on-success="handleFileUpload"
                >
                  <el-button size="small" type="primary">单文件上传</el-button>
                </el-upload>
              </div>
              <div style="margin: 10px 0">
                <el-upload
                    action="http://localhost:9090/file/upload"
                    :headers="{token: user.token}"
                    :on-success="handleMutipleFileUpload"
                    multiple
                >
                  <el-button size="small" type="success">多文件上传</el-button>
                </el-upload>
                <el-button @click="showUrls" style="margin: 10px 0" type="primary">显示链接</el-button>
              </div>
            </el-card>
          </div>
        </el-main>

      </el-container>


    </el-container>
  </div>
</template>

<script>
import axios from "axios";
import request from '@/utils/request'

export default {
  name: 'HomeView',
  data() {
    return {
      isCollapse: false,  // 不收缩
      asideWidth: '200px',
      collapseIcon: 'el-icon-s-fold',
      users: [],
      user:JSON.parse(localStorage.getItem('honey-user')||'{}'),
      url:'',
      urls:[]
    }
  },
  mounted() {
    // axios.get('http://localhost:9090/user/selectall').then(res=>{
    //   console.log(res.data);
    //   this.users=res.data.data
    // })

    request.get('/user/selectall').then(res => {
      this.users = res.data
    })
  },
  methods: {
    preview(url){
      window.open(url)
    },
    showUrls(){
      console.log(this.urls)
    },
    handleMutipleFileUpload(response,file,fileList){
      this.urls=fileList.map(v=>v.response?.data)
    },
    handleTableFileUpload(row,file,fileList){
      console.log(row,file,fileList)
      row.avatar=file.response.data
      // this.$set(row,'avatar',file.response.data)
      console.log(row)
      request.put('/user/update',row).then(res=>{
        if(res.code==='200'){
          this.$message.success('上传成功')
        }else{
          this.$message.error(res.msg)
        }
      })
    },
    handleFileUpload(response,file,fileList){
      this.fileList=fileList
      console.log(response,file,fileList)
    },
    logout() {
      localStorage.removeItem("honey-user")
      this.$router.push('/login')
    },
    handleFull() {
      document.documentElement.requestFullscreen()
    },
    handleCollapse() {
      this.isCollapse = !this.isCollapse
      this.asideWidth = this.isCollapse ? '64px' : '200px'
      this.collapseIcon = this.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'
    }
  }
}
</script>

<style>
.el-menu--inline {
  background-color: #000c17 !important;
}

.el-menu--inline .el-menu-item {
  background-color: #000c17 !important;
  padding-left: 49px !important;
}

.el-menu-item:hover, .el-submenu__title:hover {
  color: #fff !important;
}

.el-submenu__title:hover i {
  color: #fff !important;
}

.el-menu-item:hover i {
  color: #fff !important;
}

.el-menu-item.is-active {
  background-color: #1890ff !important;
  border-radius: 5px !important;
  width: calc(100% - 8px);
  margin-left: 4px;
}

.el-menu-item.is-active i, .el-menu-item.is-active .el-tooltip {
  margin-left: -4px;
}

.el-menu-item {
  height: 40px !important;
  line-height: 40px !important;
}

.el-submenu__title {
  height: 40px !important;
  line-height: 40px !important;
}

.el-submenu .el-menu-item {
  min-width: 0 !important;
}

.el-menu--inline .el-menu-item.is-active {
  padding-left: 45px !important;
}

/*.el-submenu__icon-arrow {*/
/*  margin-top: -5px;*/
/*}*/

.el-aside {
  transition: width .3s;
  box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
}

.logo-title {
  margin-left: 5px;
  font-size: 20px;
  transition: all .3s; /* 0.3s */
}

.el-header {
  box-shadow: 2px 0 6px rgba(0, 21, 41, .35);
  display: flex;
  align-items: center;
}
</style>

最后效果:实现了单文件或者多文件上传和预览下载的功能

相关推荐
FF在路上21 分钟前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进28 分钟前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web1309332039834 分钟前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
众拾达人1 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.1 小时前
Mybatis-Plus
java·开发语言
不良人天码星1 小时前
lombok插件不生效
java·开发语言·intellij-idea
守护者1701 小时前
JAVA学习-练习试用Java实现“使用Arrays.toString方法将数组转换为字符串并打印出来”
java·学习
源码哥_博纳软云1 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
禾高网络1 小时前
租赁小程序成品|租赁系统搭建核心功能
java·人工智能·小程序
学会沉淀。2 小时前
Docker学习
java·开发语言·学习