【前后端的那些事】文件上传组件封装

文章目录

  • 效果
  • 前端代码
  • 后端代码
  • 组件封装

效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前端代码

/views/file/file.vue

<template>
  <el-row>
    <el-upload
      v-model:file-list="fileList"
      class="upload-demo"
      multiple
      :auto-upload="false"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      span="10"
      style="margin-right: 20px"
    >
      <el-button type="primary">选择上传的文件</el-button>
    </el-upload>
    <el-button type="success" @click="submit">上传文件</el-button>
  </el-row>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { uploadBatch } from "/src/api/file.ts";

import type { UploadProps, UploadUserFile } from "element-plus";

const fileList = ref<UploadUserFile[]>([]);

const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {
  console.log(file, uploadFiles);
};

const handlePreview: UploadProps["onPreview"] = uploadFile => {
  console.log(uploadFile);
};

const submit = () => {
  console.log(fileList.value);
  // 封装formData
  const data = new FormData();
  fileList.value.forEach(element => {
    data.append("fileList", element.raw);
  });
  uploadBatch(data).then(res => {
    console.log(res);
    if (res.code === 0) {
      ElMessage.success("上传成功");
    } else {
      ElMessage.error("上传失败: " + res.msg);
    }
  });
};
</script>

/src/api/file.ts

import { http } from "@/utils/http";
import { R, baseUrlApi } from "./utils";

/** upload batch */
export const uploadBatch = (data: FormData) => {
  return http.request<R<any>>("post", baseUrlApi("common/file/uploadList"), {
    data,
    headers: {
      "Content-Type": "multipart/form-data"
    }
  });
};

/** upload */
export const upload = (data: FormData) => {
  return http.request<R<any>>("post", baseUrlApi("common/file/upload"), {
    data,
    headers: {
      "Content-Type": "multipart/form-data"
    }
  });
};

/src/api/utils.ts

export const baseUrlApi = (url: string) => `/api_demo/${url}`;

/** 后端返回通用数据类型 */
export type R<T> = {
  code: Number;
  msg: String;
  data: T;
};

/** 同步休眠函数, 参数为毫秒 */
export const sleep = (ms: number): Promise<void> => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

/** 分页数据类型 */
export type PageUtils<T> = {
  /** 总记录数 */
  totalCount: number;
  /** 每页记录数 */
  pageSize: number;
  /** 总页数 */
  totalPage: number;
  /** 当前页数 */
  currPage: number;
  /** 列表数据 */
  list: Array<T>;
};

export const getStoreUser = () => {
  const res = sessionStorage.getItem("user-info");
  // const res = sessionStorage.getItem("user-info");
  console.log(res);
  return JSON.parse(res);
};

后端代码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.fgbg</groupId>
    <artifactId>webrtc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <mybatisplus.version>3.3.1</mybatisplus.version>
        <mysql.version>8.0.28</mysql.version>
        <mssql.version>4.0</mssql.version>
        <oracle.version>11.2.0.3</oracle.version>
        <druid.version>1.1.13</druid.version>
        <quartz.version>2.3.0</quartz.version>
        <commons.lang.version>2.6</commons.lang.version>
        <commons.fileupload.version>1.2.2</commons.fileupload.version>
        <commons.io.version>2.5</commons.io.version>
        <commons.codec.version>1.10</commons.codec.version>
        <commons.configuration.version>1.10</commons.configuration.version>
        <shiro.version>1.9.0</shiro.version>
        <jwt.version>0.7.0</jwt.version>
        <kaptcha.version>0.0.9</kaptcha.version>
        <qiniu.version>7.2.23</qiniu.version>
        <aliyun.oss.version>2.8.3</aliyun.oss.version>
        <qcloud.cos.version>4.4</qcloud.cos.version>
        <swagger.version>2.7.0</swagger.version>
        <joda.time.version>2.9.9</joda.time.version>
        <gson.version>2.8.5</gson.version>
        <hutool.version>4.1.1</hutool.version>
        <lombok.version>1.18.4</lombok.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>


        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons.lang.version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

FileController.java

import com.fgbg.common.R;
import com.fgbg.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/common/file")
public class FileController {
    @Autowired
    @Qualifier("localFileService")
    private FileService fileService;

    /**
     * 批量文件上传接口
     */
    @RequestMapping("/uploadList")
    public R uploadBatch(@RequestParam("fileList") List<MultipartFile> fileList) throws IOException {
        ArrayList<String> ans = new ArrayList<>();
        for (MultipartFile file : fileList) {
            String url = fileService.uploadFile(file, UUID.randomUUID().toString().substring(0, 10)
                    + "-" + file.getOriginalFilename());
            ans.add(url);
        }
        return R.ok().put("data", ans);
    }
    /**
     * 上传文件接口
     */
    @RequestMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile file) throws IOException {
        String url = fileService.uploadFile(file, UUID.randomUUID().toString().substring(0, 10)
                + "-" + file.getOriginalFilename());
        return R.ok().put("data", url);
    }

    /**
     * 下载接口
     */
    @RequestMapping("/download/{fileName}")
    public void download(@PathVariable("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) {
        fileService.downloadFile(fileName, request, response);
    }

    /**
     * 删除接口
     */
    @RequestMapping("/delete")
    public R deleteFile(@RequestParam String fileName) {
        boolean flag = fileService.deleteFile(fileName);
        return R.ok().put("data", flag);
    }
}

FileService.java

import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface FileService {
    /**
     * 上传图片, 返回url
     */
    String uploadFile(MultipartFile file, String fileName) throws IOException;

    /**
     * 下载图片
     */
    void downloadFile(String fileName, HttpServletRequest request, HttpServletResponse response);

    /**
     * 删除图片
     */
    boolean deleteFile(String fileName);
}

LocalFileServiceImpl.java

import com.fgbg.service.FileService;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 基于本地的文件管理服务
 */
@Service("localFileService")
public class LocalFileServiceImpl implements FileService {
    /**
     * 文件访问域名(请求下载的接口)
     */
    private static final String DOMAIN = "http://localhost:9006/api_demo/common/file/download/";

    /**
     * 文件物理存储位置
     */
    private static final String STORE_DIR = "D:\\java_code\\webrtc\\src\\main\\resources\\file";

    /**
     * 上传图片, 返回url
     *
     * @param file
     * @param fileName
     */
    @Override
    public String uploadFile(MultipartFile file, String fileName) throws IOException {
        // 获取文件流
        InputStream is = file.getInputStream();
        // 在服务器中存储文件
        FileUtils.copyInputStreamToFile(is, new File(STORE_DIR + fileName));
        // 返回文件url
        String url = DOMAIN + fileName;
        System.out.println("文件url: " + url);
        return url;
    }

    /**
     * 下载图片
     *
     * @param fileName
     */
    @Override
    public void downloadFile(String fileName, HttpServletRequest request, HttpServletResponse response) {
        // 获取真实的文件路径
        String filePath = STORE_DIR + fileName;
        System.out.println("++++完整路径为:"+filePath);

        try {
            // 下载文件
            // 设置响应头
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);

            // 读取文件内容并写入输出流
            Files.copy(Paths.get(filePath), response.getOutputStream());
            response.getOutputStream().flush();
        } catch (IOException e) {
            response.setStatus(404);
        }
    }

    /**
     * 删除图片
     *
     * @param fileName
     */
    @Override
    public boolean deleteFile(String fileName) {
        // 获取真实的文件路径
        String filePath = STORE_DIR + fileName;
        System.out.println("++++完整路径为:"+filePath);

        File file = new File(filePath);
        return file.delete();
    }
}

组件封装

fileUpload.vue组件封装

<template>
  <el-row>
    <el-upload
      v-model:file-list="localFileList"
      class="upload-demo"
      multiple
      :auto-upload="false"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      span="10"
      style="margin-right: 20px"
    >
      <el-button type="primary">选择上传的文件</el-button>
    </el-upload>
  </el-row>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
import type { UploadProps, UploadUserFile } from "element-plus";

// 定义数据
const props = defineProps({
  fileList: {
    type: Array<UploadUserFile>,
    default: () => []
  }
});

// 将父组件的数据拆解为子组件数据
const localFileList = ref(props.fileList);

// 监听localFileList, 跟新父组件数据
watch(
  localFileList,
  newValue => {
    emits("update:fileList", newValue);
  },
  {
    deep: true
  }
);

// 定义组件事件, 跟新fileList
const emits = defineEmits(["update:fileList"]);

const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {
  console.log(file, uploadFiles);
};

const handlePreview: UploadProps["onPreview"] = uploadFile => {
  console.log(uploadFile);
};
</script>

组件调用

<script setup lang="ts">
import FileUpload from "./fileUpload.vue";
import { ref } from "vue";
import type { UploadUserFile } from "element-plus";
import { ElMessage } from "element-plus";
import { uploadBatch } from "/src/api/file.ts";

const fileList = ref<Array<UploadUserFile>>();

const submit = () => {
  console.log(fileList.value);
  // 封装formData
  const data = new FormData();
  fileList.value.forEach(element => {
    data.append("fileList", element.raw);
  });
  uploadBatch(data).then(res => {
    console.log(res);
    if (res.code === 0) {
      ElMessage.success("上传成功");
    } else {
      ElMessage.error("上传失败: " + res.msg);
    }
  });
};
</script>

<template>
  <el-row>
    <FileUpload v-model:fileList="fileList" />
    <el-button type="success" @click="submit">上传文件</el-button>
  </el-row>
</template>

<style lang="scss" scoped></style>

封装组件使用的效果
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/412802.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

与Sora一样能生成视频、图像,还能一次解读100万数据!

大语言模型&#xff08;LLM&#xff09;在生成文本内容方面非常强&#xff0c;但在理解、生成视频、图像等方面略显不足。尤其是在Sora一夜爆红之后&#xff0c;让人们意识到未来主流模型一定是文本音频图像视频的多模态生成、理解功能。 因此&#xff0c;加州大学伯克利分校的…

linux下查看某个命令在哪里个安装包程序下,以ifconfig命令举例子

yum list | grep net-tools &#xff08;查看yum安装列表中有没有安装指定的软件工具&#xff09;

用 SIL 和 PIL 仿真测试生成的代码

目录 PIL 的目标连接配置 对顶层模型运行 SIL 或 PIL 仿真 对 Model 模块运行 SIL 或 PIL 仿真 SIL 或 PIL 模块仿真 硬件实现设置 使用软件在环 (SIL) 和处理器在环 (PIL) 仿真,测试模型组件与从组件生成的生产代码之间的数字等效性。 使用 SIL 仿真,在您的开发…

JAVA高并发——Future模式

文章目录 1、Future模式解析2、Future模式的主要参与者3、Future模式的简单实现4、JDK中的Future模式5、Guava对Future模式的支持 1、Future模式解析 Future模式是多线程开发中非常常见的一种设计模式&#xff0c;它的核心思想是异步调用。当我们需要调用一个函数时&#xff0…

GaussDB SQL调优:选择合适的分布列

一、背景 GaussDB是华为公司倾力打造的自研企业级分布式关系型数据库&#xff0c;该产品具备企业级复杂事务混合负载能力&#xff0c;同时支持优异的分布式事务&#xff0c;同城跨AZ部署&#xff0c;数据0丢失&#xff0c;支持1000扩展能力&#xff0c;PB级海量存储等企业级数…

王栎鑫前妻晒情侣装,疑与糊糊复合?网友:真的假的

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 吴雅婷元宵晒情侣装&#xff0c;网友热议是否与王栎鑫复合&am…

春秋招笔试题库整理与购买-值得投资的资源

作为一位资深的IT工程师&#xff0c;我深知求职过程中的不易&#xff0c;尤其是在春秋招季节&#xff0c;竞争激烈&#xff0c;每一个环节都可能成为决定成败的关键。因此&#xff0c;我特别了一份覆盖多家知名企业的秋招笔试题库&#xff0c;希望能帮助到正在备战的朋友们。 这…

leetcode移动零

leetcode移动零 Given an integer array nums, move all 0’s to the end of it while maintaining the relative order of the non-zero elements. Note that you must do this in-place without making a copy of the array. Example 1: Input: nums [0,1,0,3,12] Output…

linux下gcc编译时默认是32位还是64位,怎么指定为32or64?

本来是想研究一下long的字节大小sizeof(long)&#xff0c;于是写了代码&#xff1a; #include <stdio.h> int main() {long a 10;printf("%d\n", sizeof(a));return 0; } 我当时使用的是win10系统&#xff0c;使用的是vs 2022&#xff0c;然后对以上代码进行…

@SpringBootApplication

目录 1. SpringBootApplication注解简介 2. 使用SpringBootApplication注解 3. 自定义SpringBootApplication注解 在Spring Boot中&#xff0c;SpringBootApplication是一个非常重要的注解&#xff0c;它用于开启自动配置&#xff0c;简化了我们的开发工作。本文将详细介绍这…

lv21 QT 常用控件 2

1 QT GUI 类继承简介 布局管理器 输出控件 输入控件 按钮 容器 2 按钮示例 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QCheckBox> #include <QLineEdit> #include <QPushButton>class Widget : public QWidget {Q_OBJECTpublic…

【计算机网络】DNS/ICMP协议/NAT技术

文章目录 一、DNS(Domain Name System)1.DNS背景2.域名3.浏览器中输入url后,发生的事情 二、ICMP协议1.什么是ICMP协议2.ICM功能3.ICMP的报文格式4.ping命令5.traceroute命令 三、NAT技术1.NAT技术背景2.NAT IP转换过程3.NAPT4.NAT技术的缺陷5.NAT和代理服务器 四、TCP/IP五层模…

电脑缺失XInput1_4.dll文件的解决办法

在电脑操作中&#xff0c;有用户遇到了XInput1_4.dll文件缺失的问题&#xff0c;导致一些依赖该文件的电脑应用无法正常运行&#xff0c;从而影响用户正常使用。接下来小编分享不同的解决方法&#xff0c;帮助用户轻松解决该问题&#xff0c;找回XInput1_4.dll文件&#xff0c;…

simple-pytest 框架使用指南

simple-pytest 框架使用指南 一、框架介绍简介框架理念&#xff1a;框架地址 二、实现功能三、目录结构四、依赖库五、启动方式六、使用教程1、快速开始1.1、创建用例&#xff1a;1.2、生成py文件1.3、运行脚本1.3.1 单个脚本运行1.3.2 全部运行 1.4 报告查看 2、功能介绍2.1、…

教育体系是什么意思

每当谈及“教育体系”&#xff0c;很多人可能会觉得它只是一个抽象、宏大的概念。但身为老师&#xff0c;我深知它与我们每个人的成长都息息相关。那么&#xff0c;这个常被提及却又略显神秘的“教育体系”究竟是什么意思呢&#xff1f; 在教育的世界里&#xff0c;我们常把“教…

JDK21 新特性

目录 1. 虚拟线程&#xff08;Virtual Threads&#xff09;2. 有序集合&#xff08;Sequenced Collections&#xff09;3. switch 的模式匹配&#xff08;Pattern Matching for switch&#xff09;4. 记录模式&#xff08;Record Patterns&#xff09;5. ZGC6. 准备禁用动态代理…

Mybatis10、动态SQL

官方文档 10.1、介绍 什么是动态SQL&#xff1a;动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句. 官网描述&#xff1a;MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验&#xff0c;你就能体会到根据不同条件拼接 SQL 语句的痛苦。例…

C 嵌入式系统设计模式 10:中介者模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之三&…

【书籍分享 • 第三期】虚拟化与容器技术

文章目录 一、本书内容二、读者对象三、编辑推荐四、前言4.1 云计算技术的发展4.2 KVM、Docker4.3 本书内容简介4.4 作者简介 五、粉丝福利 一、本书内容 《虚拟化与容器技术》通过深入浅出的方式介绍KVM虚拟化技术与Docker容器技术的概念、原理及实现方法&#xff0c;内容包括…

备战蓝桥杯Day17 - 链表

链表 基本概念 链表是由一系列节点组成的元素集合。 每个节点包含两部分&#xff1a;数据域 item 、指向下一个节点的指针 next 通过节点之间的相互链接&#xff0c;形成一个链表 1. 链表的初始化 # 手动建立链表 # 链表的初始化 class Node(object):def __init__(self, …