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

news2024/11/18 19:38:17

文章目录

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

效果

在这里插入图片描述

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

前端代码

/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>

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java SpringBoot 整合 MyBatis 小案例

Java SpringBoot 整合 MyBatis 小案例 基础配置&#xff08;注意版本号&#xff0c;容易报错&#xff09; pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http…

面试经典150题 -- 二叉树搜索树 (总结)

总的链接 : https://leetcode.cn/studyplan/top-interview-150/ 二叉搜索树相关概念 : 二叉搜索树是一个有序树。 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b;若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的根结…

SWIFT:自我认知微调

文档:https://github.com/modelscope/swift/blob/main/docs/source/LLM/%E8%87%AA%E6%88%91%E8%AE%A4%E7%9F%A5%E5%BE%AE%E8%B0%83%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5.md ​​​​​​代码: Swift是如何把自我认知数据集融合到训练集中呢? 1:相关的3个参数

阿里云ECS u1实例性能怎么样?199元一年

阿里云服务器ECS u1实例&#xff0c;2核4G&#xff0c;5M固定带宽&#xff0c;80G ESSD Entry盘优惠价格199元一年&#xff0c;性能很不错&#xff0c;CPU采用Intel Xeon Platinum可扩展处理器&#xff0c;购买限制条件为企业客户专享&#xff0c;实名认证信息是企业用户即可&a…

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候&#xff0c;问到许多年轻的Android开发他所会的设计模式是什么&#xff0c;基本上都会提到单例模式&#xff0c;但是对单例模式也是一知半解&#xff0c;在Android开发中我们经常会运用单例模式&#xff0c;所以我们还是要更了解单例模式才对…

SQL注入漏洞解析--less-46

我们先看一下46关 他说让我们先输入一个数字作为sort,那我们就先输入数字看一下 当我们分别输入1&#xff0c;2&#xff0c;3可以看到按照字母顺序进行了排序&#xff0c;所以它便是一个使用了order by语句进行排序的查询的一种查询输出方式 当输入时出现报错提示&#xff0c;说…

YOLOv9图像标注和格式转换

一、软件安装 labelimg安装&#xff08;anaconda&#xff09; 方法一、 pip install labelImg 方法二、 pip install PyQt5 -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install pyqt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install lxml -i ht…

【迪文屏幕】上电后默认显示背景图片是0

以往的开发&#xff0c;背景图片都是从0开始命名的&#xff0c;这次鬼使神差的没有使用0&#xff0c;而是从1开始命名&#xff0c;上电后不显示&#xff0c;咨询了技术支持&#xff0c;屏幕上电后默认显示0图片&#xff0c;增加了0图片之后&#xff0c;显示正常。 当然有一种情…

浅谈 TCP 三次握手

文章目录 三次握手 三次握手 首先我们需要明确&#xff0c;三次握手的目的是什么&#xff1f; 是为了通信双方之间建立连接&#xff0c;然后传输数据。 那么建立连接的条件是什么呢&#xff1f; 需要确保通信的双方都确认彼此的接收和发送能力正常&#xff0c;满足这个条件&a…

PDF文件转换为图片

现在确实有很多线上的工具可以把pdf文件转为图片&#xff0c;比如smallpdf等等&#xff0c;都很好用。但我们有时会碰到一些敏感数据&#xff0c;或者要批量去转&#xff0c;那么需要自己写脚本来实现&#xff0c;以下脚本可以提供这个功能~ def pdf2img(pdf_dir, result_path…

通过二叉树例题深入理解递归问题

目录 引入&#xff1a; 例1&#xff1a;二叉树的前序遍历&#xff1a; 例2&#xff1a; N叉树的前序遍历&#xff1a; 例3&#xff1a;二叉树的最大深度&#xff1a; 例4&#xff1a;二叉树的最小深度 例5&#xff1a;N叉树的最大深度&#xff1a; 例6&#xff1a;左叶子…

Python实用技巧:处理JSON文件写入换行问题

Python实用技巧&#xff1a;处理JSON文件写入换行问题 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程 &#x1f448; 希望得到您的订阅…

springboot启动自动配置

1.自定义项命名启动类规范&#xff1a; 功能在前名字在后比如 aliyun-oss-spring-boot-starter starter表示启动 springboot版本需要2.7.5 2.创建springboot工程把该删除的文件删除 3.启动类 pom文件导入自定义配置类依赖 比如 <!--第2步--><!-- 启动类 pom…

CSP-202209-3-防疫大数据

CSP-202209-3-防疫大数据 解题思路 一、数据结构定义 对于大模拟的题&#xff0c;合适的数据结构选择十分重要&#xff0c;正确的数据结构选择能够有效的提升解题效率 // 漫游消息结构体 struct RoamingData {int date, user, region; };vector<RoamingData> roamin…

阿里云服务器2024年最新价格表,高性价比配置任你选

随着云计算技术的不断发展&#xff0c;越来越多的企业和个人开始选择云服务器来搭建自己的业务平台。作为国内领先的云服务提供商&#xff0c;阿里云一直致力于为广大用户提供稳定、高效、安全的云计算服务。2024年&#xff0c;阿里云再次升级其服务器产品线&#xff0c;推出了…

FMM 笔记:st-matching(colab上执行)【官方案例解读】

在colab上运行&#xff0c;所以如何在colab上安装fmm&#xff0c;可见FMM 笔记&#xff1a;在colab上执行FMM-CSDN博客 st-matching见论文笔记&#xff1a;Map-Matching for low-sampling-rate GPS trajectories&#xff08;ST-matching&#xff09;-CSDN博客 0 导入库 from…

MySQL 数据优化技巧:提升百万级数据聚合统计速度

MySQL 数据优化技巧&#xff1a;提升百万级数据聚合统计速度 MySQL 数据优化技巧&#xff1a;提升百万级数据聚合统计速度摘要引言索引优化1. 使用合适的索引类型2. 聚簇索引的应用 查询优化3. 减少数据检索范围4. 避免全表扫描 数据库设计优化5. 合理划分数据表6. 使用分区表 …

nginx设置缓存时间

一、设置缓存时间 当网页数据返回给客户端后&#xff0c;可针对静态网页设置缓存时间&#xff0c;在配置文件内的http段内server段添加location&#xff0c;更改字段expires 1d来实现&#xff1a;避免重复请求&#xff0c;加快访问速度 第一步&#xff1a;修改主配置文件 #修…

面试经典150题【11-20】

文章目录 面试经典150题【11-20】388.O(1) 时间插入、删除和获取随机元素238.除自身以外数组的乘积134加油站135.分发糖果42. 接雨水13.罗马数字12.整数 转 罗马数字58.最后一个单词的长度14.最长公共前缀151.反转字符串中的单词 面试经典150题【11-20】 388.O(1) 时间插入、删…

IO进程:信号灯集

程序代码&#xff1a; sem.h: 1 #ifndef __SEM_H__2 #define __SEM_H__3 4 //创建信号灯集并初始化&#xff0c;semcount表示灯个数5 int open_sem(int semcount);6 7 //申请资源操作&#xff0c;semno表示灯的编号8 int P(int semid,int semno);9 10 //释放资源操作&#xff…