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';
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:
fileBucketName:
accessKey:
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);
minioClient.putObject(fileBucketName, objectName, file.getInputStream(), file.getContentType());
String objectUrl = minioClient.getObjectUrl(fileBucketName, objectName);
jsonObject.put("url", objectUrl);
return ResultUtil.success(jsonObject);
} catch(Exception e) {
return ResultUtil.fail(ResultEnum.FAIL_FILE_UPLOAD);
}
}
private MinioClient getMinioClient(String bucketName) throws Exception {
MinioClient minioClient = new MinioClient(endpoint, accessKey, secretKey);
boolean isExist = minioClient.bucketExists(bucketName);
if(!isExist) {
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 服务器
|