介绍
文件上传和下载是一个十分常见的应用场景,而这篇文章是一篇基础的文章
如果需要使用 MinIO 就只需要操作服务端文件换成输入流
MinIO使用:https://www.lldwb.top/archives/5639
文件上传
配置方式
原生MVC
注意:有兼容性问题,在 Tomcat 下没问题,但是在 Jetty 下会出错
比如使用如下文件VO类会出现报错,但是支持直接接收 MultipartFile
类型
@Data
public class ProductVO {
/**
* SpringMVC 封装的上传附件对象
* 图片
*/
private MultipartFile file;
}
Web.xml 设置
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 开启文件上传(兼容性不好) -->
<multipart-config/>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
第三方
Maven 依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
案例
单文件
/**
* 添加商品,同时带有上传的附件
*
* @return
*/
@PostMapping("/addFile")
public ResultVo add(ProductVO productVO) throws IOException {
ResultVo vo = new ResultVo();
// 获取上传的路径(上传到本地图片、图片服务器)
// 绝对路径
String uploadPath = "C:\\Users\\32471\\Pictures\\Saved Pictures";
// 获取上传的文件名
MultipartFile multipartFile = productVO.getFile();
// 根据路径构建一个上传的文件对象
File upladFile = new File(uploadPath);
// 判断路径中的文件夹是否存在,不存在则创建出来
if (!upladFile.exists()) {
// 创建文件夹
upladFile.mkdirs();
}
// 目标的文件名
String fileName = multipartFile.getOriginalFilename();
log.info("目标的文件名" + fileName);
log.info("name:" + multipartFile.getName());
// 文件路径
log.info(uploadPath);
// 执行上传
Path path = FileSystems.getDefault().getPath(upladFile.getAbsolutePath(), fileName);
multipartFile.transferTo(path);
return vo;
}
@Data
public class ProductVO {
/**
* 名称
*/
private String name;
/**
* SpringMVC 封装的上传附件对象
* 图片
*/
private MultipartFile file;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/jquery.min.js"></script>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="msg" style="color: red"></div>
<form id="f1" enctype="multipart/form-data">
Nmae:<input type="text" name="name" />
文件:<input type="file" name="file" />
<input type="button" value="提交">
</form>
</body>
<script>
$(() => {
$(':button').on('click', () => {
// 构建 formData 对象
let formData = new FormData($('#f1')[0]);
$.ajax({
url: 'addFiles',
type: 'post',
data: formData,
success(result) {
if (result.code == 500) {
$('#msg').empty();
let errors = result.message;
errors = $.parseJSON(errors);
// $.each(errors, (key, value) => {
value = "错误"
$('#msg').append(value + '<br/>')
// })
}else if(result.code == 200){
value = "成功了"
$('#msg').append(value + '<br/>')
}
},
// 告诉 jquery 不要处理发送的数据类型
processData: false,
// 告诉 jquery 不要设置请求头的 content-Type
contentType: false
})
})
})
</script>
</html>
多文件
@PostMapping("/addFiles")
public ResultVo adds(ProductVOs productVOs) throws IOException {
// 获取上传的路径(上传到本地图片、图片服务器)
// 绝对路径
String uploadPath = "C:\\Users\\32471\\Pictures\\Saved Pictures";
// MultipartFile multipartFile = file;
// 根据路径构建一个上传的文件对象
File upladFile = new File(uploadPath);
// 判断路径中的文件夹是否存在,不存在则创建出来
if (!upladFile.exists()) {
// 创建文件夹
upladFile.mkdirs();
}
for (MultipartFile multipartFile : productVOs.getFile()) {
// 目标的文件名
log.info("name:" + multipartFile.getName());
// 文件路径
log.info(uploadPath);
// 执行上传
multipartFile.transferTo(FileSystems.getDefault().getPath(upladFile.getAbsolutePath(), multipartFile.getOriginalFilename()));
}
ResultVo vo = new ResultVo();
return vo;
}
@Data
public class ProductVOs {
/**
* 名称
*/
private String name;
/**
* SpringMVC 封装的上传附件对象
* 图片
*/
private MultipartFile[] file;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/jquery.min.js"></script>
<script src="js/vue.js"></script>
<script src="js/vue-router.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="msg" style="color: red"></div>
<form id="f1" enctype="multipart/form-data">
Nmae:<input type="text" name="name" />
多文件:<input type="file" name="file" multiple/>
<input type="button" value="提交">
</form>
</body>
<script>
$(() => {
$(':button').on('click', () => {
// 构建 formData 对象
let formData = new FormData($('#f1')[0]);
$.ajax({
url: 'addFiles',
type: 'post',
data: formData,
success(result) {
if (result.code == 500) {
$('#msg').empty();
let errors = result.message;
errors = $.parseJSON(errors);
// $.each(errors, (key, value) => {
value = "错误"
$('#msg').append(value + '<br/>')
// })
}else if(result.code == 200){
value = "成功了"
$('#msg').append(value + '<br/>')
}
},
// 告诉 jquery 不要处理发送的数据类型
processData: false,
// 告诉 jquery 不要设置请求头的 content-Type
contentType: false
})
})
})
</script>
</html>
文件下载
@GetMapping("/download")
public ResponseEntity<InputStreamResource> download(String fileName) throws Exception {
// 获取服务器的路径(上传到本地图片、图片服务器)
// 绝对路径
String downloadPath = "C:\\Users\\32471\\Pictures\\Saved Pictures\\"+fileName;
// 构建文件输入流读取服务器上的文件
FileInputStream inputStream = new FileInputStream(downloadPath);
// 对文件名进行编码,防止在响应头中出现乱码
fileName = URLEncoder.encode(fileName,"UTF-8");
// 设置响应头,告诉浏览器响应的是流数据
HttpHeaders headers = new HttpHeaders();
// 设置头信息,将响应内容处理的方式设置为附件下载
headers.setContentDispositionFormData("attachment",fileName);
// 设置响应类型为流类型
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 创建 InputStreamReader 对象封装输入流,用于读取服务器文件
InputStreamResource inputStreamReader = new InputStreamResource(inputStream);
// 创建 ResponseEntity 对象,封装(InputStreamReader,响应头 HttpHeaders,状态码 201)
// 200 成功,201 成功但是还有数据
ResponseEntity<InputStreamResource> response = new ResponseEntity<>(inputStreamReader,headers,HttpStatus.CREATED);
return response;
}
上传到 MinIo
@PostMapping("/addFiles")
public ResultVo adds(ProductVOs productVOs) throws Exception {
//获取 minioClient
MinioClient minioClient = ApplicationContextHolder.getBean(MinioFactoryBean.class).getObject();
// 遍历多个文件
for (MultipartFile multipartFile : productVOs.getFile()) {
// 获取文件的输入流
InputStream inputStream = multipartFile.getInputStream();
// 上传输入流到 MinIO
minioClient.putObject(PutObjectArgs.builder().bucket("test").object(multipartFile.getOriginalFilename()).stream(inputStream, multipartFile.getSize(), -1).contentType(multipartFile.getContentType()).build());
}
ResultVo vo = new ResultVo();
return vo;
}
从 MinIO 下载
@GetMapping("/download")
public ResponseEntity<InputStreamResource> download(String fileName) throws Exception {
//获取 minioClient
MinioClient minioClient = ApplicationContextHolder.getBean(MinioFactoryBean.class).getObject();
// 从 MinIO 获取输入流
InputStream inputStream = minioClient.getObject(GetObjectArgs.builder().bucket("test").object(fileName).build());
// 对文件名进行编码,防止在响应头中出现乱码
fileName = URLEncoder.encode(fileName, "UTF-8");
// 设置响应头,告诉浏览器响应的是流数据
HttpHeaders headers = new HttpHeaders();
// 设置头信息,将响应内容处理的方式设置为附件下载
headers.setContentDispositionFormData("attachment", fileName);
// 设置响应类型为流类型
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 创建 InputStreamReader 对象封装输入流,用于读取服务器文件
InputStreamResource inputStreamReader = new InputStreamResource(inputStream);
// 创建 ResponseEntity 对象,封装(InputStreamReader,响应头 HttpHeaders,状态码 201)
// 200 成功,201 成功但是还有数据
ResponseEntity<InputStreamResource> response = new ResponseEntity<>(inputStreamReader, headers, HttpStatus.CREATED);
return response;
}