IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> SpringBoot + Vue + MinIO 实现文件上传 -> 正文阅读

[JavaScript知识库]SpringBoot + Vue + MinIO 实现文件上传

1. 搭建 MinIO

1.1 下载

因为不同的版本不知道会不会有影响,所以大家最好和本人的版本保持一致
本人资源:https://download.csdn.net/download/wanzijy/86827739

当然,也可以去官网下载
英文官网:https://min.io/
中文官网:https://www.minio.org.cn/

下载完后,文件夹内只有两个文件(和本人的版本一致的话)
在这里插入图片描述

1.2 启动

进入上述文件的安装目录,然后进入 cmd 模式,输入以下命令:

minio.exe server -address 指定的IP:指定的端口 文件存放的路径

比如:minio.exe server -address 192.168.74.1:9002 E:\minio
当然也可以不指定 IP 和端口,直接输入:minio.exe server E:\minio
在这里插入图片描述

上图中有这么多可以访问的链接是因为没有指定 IP 和端口,那么 MinIO 就会根据我们电脑当前的 IP 去生成这些访问的链接
我下面演示的话,就指定 IP 和端口进行启动


在浏览器中输入上图中的访问链接,然后输入用户名和密码即可进入 MinIO 的可视化管理界面,如下图:

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

大家刚开始进去的话,是不会有我在上面图中框住的东西的
要是能进入上述的可视化界面,则表示 MinIO 搭建成功

简要介绍:
在 MinIO 里,所有的文件都是存储在一个叫做 “” 的地方,其实就是上图我左边框住的东西
我们可以在可视化的管理界面里新建多个桶,用于存储不同类型的文件,方便区分;当然,也可以在代码中新建桶

2. 前端 Vue

2.1 准备

自行新建一个 Vue 项目,引入 element ui 和 Axios

npm install element-ui -S
npm install axios --save

在 main.js 中进行配置

import ElementUI from 'element-ui';  //  导入element-ui包
import 'element-ui/lib/theme-chalk/index.css';  //  导入样式
Vue.use(ElementUI);  //  进行引用

import service from 'axios'
Vue.prototype.$axios = service

在这里使用 element-ui 的上传组件,但不做样式处理

上传组件地址:https://element.eleme.io/#/en-US/component/upload#upload

2.2 html 代码

新建一个 vue 文件

<template>
	<div class="upload">
		<el-upload class="upload-demo" drag multiple accept=".xls, .xlsx" :http-request="fileUpload" action="" @on-success="uploadSuccess" @on-error="uploadError">
			<i class="el-icon-upload"></i>
			<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
			<div class="el-upload__tip" slot="tip">只能上传 xlsx/xls 文件</div>
		</el-upload>
	</div>
</template>

<script>
	import { MessageBox } from 'element-ui';
	import {fileUploading} from '../../student/FileSubmit';  //  路径问题自己进行处理

	departmentsImport(param) {
		var that = this;
		fileUploading(param).then(response => {
			if(response.msg == 'success') {
				MessageBox({
					title: '提示',
					message: '论文定稿提交成功',
					type: 'success'
				});
			} else {
				MessageBox({
					title: '提示',
					message: '文件上传失败,请稍后再试',
					type: 'error'
				})
			}
		})
	},
	uploadSuccess() {
		//  上传成功时的钩子函数
	},
	uploadError() {
		//  当一些错误发生时的钩子函数
    }
</script>

accept=“.xls, .xlsx”

  • 表示只能上传类型为 .xls 和 .xlsx 的文件
  • 这里是 vue 在前端做的校验,与后台服务无关
  • 个人想法:我个人觉得,有一些校验可以在前端进行的话,可以尽量的将这些校验放在前端,不用每一次校验都在服务器里走一圈,然后再告诉用户说不行。要是服务器本来就慢的话,首先给用户的体验就差;最重要的是,能少往服务器发一次请求

2.3 js 代码

新建 FileSubmit.js

export function fileUploading(param) {
    const formData = new FormData();
    formData.append('file', param.file);
    try {
        const response = await service({
            url: '自己后端的请求地址',
            method: 'POST',
            data: formData,
            headers: { 'Content-type': 'multipart/form-data' }
        });
        return response;
    } catch (error) {
        MessageBox({
            title: '提示',
            message: '文件上传失败,请稍后再试',
            type: 'error'
        });
        console.log(error);
    }
}

3. 后端 SpringBoot

3.1 准备

本人使用的 SpringBoot 的版本是:2.2.5.RELEASE

引入 MinIO 依赖

<dependency>
	<groupId>io.minio</groupId>
	<artifactId>minio</artifactId>
	<version>3.0.10</version>
</dependency>

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.62</version>
</dependency>

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

3.2 配置文件

将要连接 MinIO 的信息写在配置文件里,不要写死在代码里
写在配置文件里,当你修改一处后,其他全部的地方都会跟着修改,方便后续的维护和修改

minio:
  endpoint:    #  MinIO服务所在地址
  fileBucketName: #  桶名称
  accessKey: #  访问的key
  secretKey: #  访问的秘钥

3.3 自定义异常

当系统发送错误时,如果使用 Java 原生的 Exception 来向前端返回,技术人员还好,一眼就能看出是什么意思
但是如果是用户的话,你总不能告诉别人,你这里 “Null” 吧 …
所以,我们在项目中,要根据不同的场景,来定制属于不同场景下的异常

异常枚举类

/**
 * 错误码列表
 */
public enum ResultEnum {
	FAIL_FILE_UPLOAD("20002", "文件上传失败"),
	FAIL_FILE_IMPORT("20003", "文件导入失败")
	//  ...
	;
	
	String code;
    String msg;

    ResultEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

自定义异常

/**
 * 自定义业务异常
 */
public class BusinessException extends RuntimeException{

    private String code;

    public BusinessException(String code, String msg) {
        super(msg);
        this.code = code;
    }

    public BusinessException(ResultEnum resultenum) {
        super(resultenum.getMsg());
        this.code = resultenum.getCode();
    }

    public String getCode() {
        return code;
    }

}

3.4 自定义统一返回值

为什么要自定义统一返回值:
要是每一个接口返回值都不同的话,那么前端人员就得对不同的返回值做处理,这样会大大增加工作量。而且,在公司的开发中,前端的开发和后端的开发进度肯定很难做到同步的,那么如果没有统一的返回值,那么当开发一个功能时,总不能是谁先开发好,就谁来制定这个功能的返回值是怎么样的吧。那不得天天干起来?
相反,如果一开始就给所有的接口定义一个统一的返回值,那么大家就各自开发各自的,只要都按照统一的返回值做处理即可

统一返回值

/**
 * 公共返回值
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {

    //  状态码
    private String code;

    //  返回信息
    private String msg;

	//  返回的数据, 使用泛型,由传入的数据来决定类型
    private T data;

}

返回值工具类

/**
 * 统一对外访问接口返回值的工具类
 */
public class ResultUtil {

    public static<T> Result<T> success(T data) {
        Result<T> result = new Result<>();
        result.setCode("10200");
        result.setMsg("success");
        result.setData(data);
        return result;
    }

    public static<T> Result<T> success() {
        Result<T> result = new Result<>();
        result.setCode("10200");
        result.setMsg("success");
        return result;
    }

    public static<T> Result<T> success(String msg, T data) {
        Result<T> result = new Result<>();
        result.setCode("10200");
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

    public static<T> Result<T> success(String msg) {
        Result<T> result = new Result<>();
        result.setCode("10200");
        result.setMsg(msg);
        return result;
    }

    public static<T> Result<T> fail(String code, String msg) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(null);
        return result;
    }

    public static<T> Result<T> fail() {
        Result<T> result = new Result<>();
        result.setCode("10500");
        result.setMsg("系统异常");
        result.setData(null);
        return result;
    }

    public static<T> Result<T> fail(T data) {
        Result<T> result = new Result<>();
        result.setData(data);
        return result;
    }

    public static<T> Result<T> fail(ResultEnum resultEnum) {
        Result<T> result = new Result<>();
        result.setCode(resultEnum.getCode());
        result.setMsg(resultEnum.getMsg());
        result.setData(null);
        return result;
    }

}

上面是本人在项目中自己编写的工具类,大家可以按需采纳

3.5 controller

public class UploadController {

	@Value("${minio.endpoint}")
    private String endpoint;

    @Value("${minio.fileBucketName}")
    private String fileBucketName;

    @Value("${minio.accessKey}")
    private String accessKey;

    @Value("${minio.secretKey}")
    private String secretKey;

	@Override
	@RequestMapping(value = "/file", method = RequestMethod.POST)
    public Result<JSONObject> uploadFile(@RequestPart("file") MultipartFile file) {
        if (file == null) {
            throw new BusinessException(ResultEnum.FAIL_FILE_UPLOAD);
        }

        try {
            JSONObject jsonObject = new JSONObject();
            MinioClient minioClient = getMinioClient(fileBucketName);
            String objectName = getFileName(file);

            // 使用putObject上传一个文件到存储桶中。
            minioClient.putObject(fileBucketName, objectName, file.getInputStream(), file.getContentType());

            //  可以在浏览器上直接访问的地址
            //  在这里要注意的是,刚上传时,图片是不能直接访问的,要去minio服务器中,添加对应的桶的权限,然后重启minio服务器
            //  点击桶右边的三个点 -> Edit policy -> ADD -> Read and Write -> 重启minio 服务器
            String objectUrl = minioClient.getObjectUrl(fileBucketName, objectName);
            jsonObject.put("url", objectUrl);

            return ResultUtil.success(jsonObject);
        } catch(Exception e) {
            return ResultUtil.fail(ResultEnum.FAIL_FILE_UPLOAD);
        }
    }    

	/**
     * 获取 minio 的链接
     * @return  minio链接
     * @throws Exception
     */
    private MinioClient getMinioClient(String bucketName) throws Exception {
        // 使用MinIO服务的URL,端口,Access key和Secret key创建一个MinioClient对象
        MinioClient minioClient = new MinioClient(endpoint, accessKey, secretKey);

        // 检查存储桶是否已经存在
        boolean isExist = minioClient.bucketExists(bucketName);
        if(!isExist) {
            // 创建一个名为 bucketName 的存储桶
            minioClient.makeBucket(bucketName);
            minioClient.setBucketPolicy(bucketName, ".", PolicyType.READ_ONLY);
        }
        return minioClient;
    }

}

到此,文件上传功能就已经全部实现
可以看到,如果上传成功的话,我是返回了文件的 url 给前端
如果此时是想在网页上打开文件进行浏览的话,大家可以去看我的另一篇文章,使用 kkFileView 实现网页文件浏览 :https://blog.csdn.net/wanzijy/article/details/125288413


要注意的是:

  • 刚上传时,图片是不能直接访问的,要去 MinIO 服务器中,添加对应的桶的权限,然后重启 MinIO 服务器
  • 点击桶右边的三个点 -> Edit policy -> ADD -> Read and Write -> 重启 MinIO 服务器
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:19:49  更:2022-11-05 00:20:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 15:57:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码