在Spring Boot中实现文件上传仍然使用Spring MVC的MultipartFile类来处理。
我们创建一个 “SpringBootUploadDemo” 的工程
然后我们修改编码格式以及Maven仓库地址,我们省略这个过程了。
接下来,我们修改 “pom.xml” 文件,添加SpringBoot和Web依赖,如下所示
<?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.demo</groupId>
<artifactId>SpringBootUploadDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.13</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.18</version>
</plugin>
</plugins>
</build>
</project>
接下来,我们创建 Appliaction 入口类文件
package com.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
接下来,我们创建 UploadController 控制器
package com.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@Controller
public class UploadController {
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Map map) {
String message = "";
try {
String uploadDir = "E:/idea-workspace/SpringBootUploadDemo/";
File uploadedFile = new File(uploadDir + file.getOriginalFilename());
file.transferTo(uploadedFile);
message = "上传成功";
} catch (IOException e) {
e.printStackTrace();
message = "上传失败:" + e.getMessage();
}
map.put("message", message);
return "upload";
}
}
我们将上传的文件保存到了 “E:/idea-workspace/SpringBootUploadDemo/” 工程目录下。
接下来,我们创建 “resources\static\index.html” 入口文件
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>index</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
</body>
</html>
文件上传通常使用 multipart/form-data 类型的 POST 请求。
接着,我们继续需要创建 “resources\templates\upload.html” 文件
<!doctype html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>upload</title>
</head>
<body>
<p th:text="${message}"></p>
</body>
</html>
接下来,我们运行测试一下啊
我们点击“选择文件”控件选择一张 “head.jpg” 图片
我们点击 “上传” 按钮
我们去 “E:/idea-workspace/SpringBootUploadDemo/” 工程目录下查看一下
如何在网页中显式这张图片呢?我们需要配置本地资源映射路径即可。
package com.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
private static final String UPLOAD_REQ = "/upload/**";
private static final String UPLOAD_DIR = "E:/idea-workspace/SpringBootUploadDemo/";
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(UPLOAD_REQ).addResourceLocations("file:///" + UPLOAD_DIR + "/");
}
}
其中 “UPLOAD_REQ” 是我们的访问请求路径,而 “UPLOAD_DIR” 是映射的真实物理路径。我们配置一个拦截器, 如果访问路径是 addResourceHandler 中的 UPLOAD_REQ 这个路径,那么就 映射到访问本地的addResourceLocations 的 UPLOAD_DIR 参数的这个路径上。
我们只需要访问:http://localhost:8080/upload/head.jpg 就能看到刚刚上传的照片了。
我们重启测试一下
当然,我们还可以使用html中的img标签来显示这个图片。
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
<br />
<img src="http://localhost:8080/upload/head.jpg" />
接下来,我们简单介绍MultipartFile 的常用方法
getName(): 获取文件在服务器上的文件名
getOriginalFilename(): 获取文件在客户端上的原始文件名
getContentType(): 获取文件的内容类型
isEmpty(): 判断文件是否为空
getSize(): 获取文件大小(字节)
getBytes(): 读取文件内容为字节数组
getInputStream(): 获取文件内容的输入流
getResource(): 将文件转换为资源对象
transferTo(File dest): 将文件内容传输到指定的目标文件
transferTo(Path dest): 将文件内容传输到指定的目标路径
一般的文件上传,我们都会限制文件类型和大小,并且对文件进行重命名到指定目录下。很明显,我们可以通过 getContentType() 获取上传文件的类型,通过 getSize() 获取文件的大小,然后对其做限制。这里我们稍微介绍一下文件类型,也就是MIME 类型。MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。常用的 MIME 类型如下所示
XML文件格式:text/xml
CSS样式表(css):text/css
普通文本格式(txt):text/plain
Javascript 脚本文件(js):text/javascript
HTML文件格式(htm, html, shtml):text/html
GIF图像格式(gif):image/gif
PNG图像格式(png):image/png
BMP图像格式(bmp):image/bmp
JPG2图像格式(jpg2):image/jp2
TIF(TIFF)图像格式(tif, tiff):image/tiff
JPG(JPEG)图像格式(jpg, jpeg):image/jpeg
PDF格式(pdf):application/pdf
ZIP压缩文件格式(zip):application/zip
RAR压缩文件格式(rar):application/rar
微软Office Word格式(doc):application/msword
微软Office Word格式(docx):application/vnd.openxmlformats-officedocument.wordprocessingml.document
微软Office Excel格式(xls):application/vnd.ms-excel
微软Office Excel格式(xlsx):application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
微软Office PowerPoint格式(ppt):application/vnd.ms-powerpoint
微软Office PowerPoint格式(pptx):application/vnd.openxmlformats-officedocument.presentationml.presentation
我们将各种限制和文件上传路径添加到配置文件 “application.properties” 中
upload-config.req = upload
upload-config.type = image/jpeg,image/png
upload-config.dir = E:/idea-workspace/SpringBootUploadDemo/
注意,我们的文件类型限制为jpg和png图片,它是一个List类型的配置项,使用逗号分隔多个MIME 类型。 接下来,我们使用一个配置类来读取 “application.properties” 中的配置项
package com.demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Data
@Component
@ConfigurationProperties(prefix = "upload-config")
public class UploadConfig {
private String req;
private String dir;
private List<String> type;
}
Spring Boot工程嵌入的tomcat限制了请求的文件大小,每个文件的配置最大为1Mb,单次请求的文件的总数不能大于10Mb。我们需要修改配置文件(application.properties)中加入两个配置
spring.servlet.multipart.max-file-size = 5MB
spring.servlet.multipart.max-request-size = 5MB
server.tomcat.max-swallow-size = 100MB
注意,上面最重要的是要配置内嵌的 tomcat 的最大吞吐量即 max-swallow-size,可以设置 -1 不限制,也可以设置一下比较大的数字 100M。如果超过文件大小限制的话,就会抛出 “MaxUploadSizeExceededException” 异常,我们可以创建全局异常处理器来处理这个异常,代码如下
package com.demo.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView handler(MaxUploadSizeExceededException e) {
e.printStackTrace();
ModelAndView mv = new ModelAndView();
mv.setViewName("exception");
mv.addObject("message", "文件太大了");
return mv;
}
}
不要忘记补上 “resources\templates\exception.html” 文件
<!doctype html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>exception</title>
</head>
<body>
<div th:text="${message}"></div>
</body>
</html>
接下来,我们修改 “UploadController” 控制器
package com.demo.controller;
import com.demo.config.UploadConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
@Controller
public class UploadController {
@Autowired
private UploadConfig uploadConfig;
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Map map) {
String img = "";
String message = "";
try {
// 检查文件类型
List<String> fileTypeList = uploadConfig.getType();
String fileType = file.getContentType().toLowerCase(Locale.ROOT);
if(!fileTypeList.contains(fileType)){
map.put("img", img);
map.put("message", "文件类型不对:" + fileType);
return "upload";
}
// 重命名
String[] originalFileNameArray = file.getOriginalFilename().split("\\.");
String newFileName = UUID.randomUUID().toString() + "." + originalFileNameArray[1];
// 保存文件
File uploadedFile = new File(uploadConfig.getDir() + newFileName);
file.transferTo(uploadedFile);
// 返回图片地址
img = "/" + uploadConfig.getReq() + "/" + newFileName;
message = "上传成功";
} catch (IOException e) {
e.printStackTrace();
message = "上传失败:" + e.getMessage();
}
map.put("img", img);
map.put("message", message);
return "upload";
}
}
我们判断了文件类型,顺便重新命名了上传文件,同时返回了上传文件图片地址。
不要忘记同步一下 “WebMvcConfig” 里面的代码
package com.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//private static final String UPLOAD_REQ = "/upload/**";
//private static final String UPLOAD_DIR = "E:/idea-workspace/SpringBootUploadDemo/";
@Autowired
private UploadConfig config;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String pathPatterns = "/"+config.getReq()+"/**";
registry.addResourceHandler(pathPatterns).addResourceLocations("file:///" + config.getDir() + "/");
}
}
接下来,修改 “resources\templates\upload.html” 文件内容,增加图片的显示
<p th:text="${message}"></p>
<div th:if="${img}">
<img th:src="${img}" />
</div>
接下来,我们重新运行测试一下啊
还是上传之前的 “head.jpg” 图片
上传成功,图片正常显示了,我们去项目根目录下查看
我们使用一个其他类型的大文件来测试一下
优先检查文件大小,上传的文件超过了 5M
继续测试
上传其他文件类型,大小没有超过5M,就可以检查文件类型了
接下来,我们使用控制器返回图片类型,一般使用输出流字节格式。
package com.demo.controller;
import com.demo.config.UploadConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
@Controller
public class UploadController {
@Autowired
private UploadConfig uploadConfig;
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Map map) {
String img = "";
String message = "";
try {
// 检查文件类型
List<String> fileTypeList = uploadConfig.getType();
System.out.println("文件类型:" + fileTypeList.get(0).toLowerCase(Locale.ROOT));
String fileType = file.getContentType().toLowerCase(Locale.ROOT);
if(!fileTypeList.contains(fileType)){
map.put("img", img);
map.put("message", "文件类型不对:" + fileType);
return "upload";
}
// 重命名
String[] originalFileNameArray = file.getOriginalFilename().split("\\.");
String newFileName = UUID.randomUUID().toString() + "." + originalFileNameArray[1];
// 保存文件
File uploadedFile = new File(uploadConfig.getDir() + newFileName);
file.transferTo(uploadedFile);
// 返回图片地址
img = "/" + uploadConfig.getReq() + "/" + newFileName;
message = "上传成功";
} catch (IOException e) {
e.printStackTrace();
message = "上传失败:" + e.getMessage();
}
map.put("img", img);
map.put("message", message);
return "upload";
}
@GetMapping("/image")
public ResponseEntity<byte[]> image() throws IOException {
// 读取图片文件
File file = new File(uploadConfig.getDir()+ "head.jpg");
byte[] imageBytes = Files.readAllBytes(file.toPath());
// 构建 HTTP 响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
headers.setContentLength(imageBytes.length);
// 返回包含图片字节数组的 ResponseEntity
return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
}
}
我们直接在 “resources\static\index.html” 入口文件中获取图片试试
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
<br />
<img src="http://localhost:8080/upload/head.jpg" />
<br />
<img src="/image" />
我们测试一下
接下来,我们演示图片文件下载
@GetMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
// 读取图片文件
String fileName = "head.jpg";
File file = new File(uploadConfig.getDir() + fileName);
byte[] imageBytes = Files.readAllBytes(file.toPath());
// 构建 HTTP 响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// 返回客户端
return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
}
我们在 “resources\static\index.html” 入口文件中添加下载链接
<br />
<img src="http://localhost:8080/upload/head.jpg" />
<br />
<img src="/image" />
<br />
<a href="/download" target="_blank">download</a>
接下来,我们重新运行测试一下
以下是返回Base64编码的图片字符串
@GetMapping("/base64")
public ResponseEntity<String> base64() throws IOException {
// 读取图片文件
File file = new File(uploadConfig.getDir()+ "head.jpg");
byte[] imageBytes = Files.readAllBytes(file.toPath());
// 将图片字节数组进行 Base64 编码
String base64EncodedImage = Base64Utils.encodeToString(imageBytes);
// 返回 Base64 编码后的图片字符串
String body = "data:image/jpeg;base64," + base64EncodedImage;
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(body);
}
前端使用ajax显示图片,使用src直接请求是不行的。
<script type="text/javascript">
function getImageWithBase64() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/base64', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var img = document.createElement("img");
img.src = `${xhr.responseText}`;
document.body.appendChild(img);
}
};
xhr.send();
}
getImageWithBase64();
</script>
页面效果如下
本工程完整代码下载: https://download.csdn.net/download/richieandndsc/89953259
标签:文件,20,SpringBoot,springframework,file,import,org,上传,String From: https://blog.csdn.net/richieandndsc/article/details/143556877