一、文件上传
首先,http上传时候的content-type为multipart/form-data
,默认情况下SpringMVC对该种类型报文的解析器为 org.springframework.web.multipart.MultipartResolver 类型的对象。MultipartResolver本身是个接口,其实现类为 org.springframework.web.multipart.support.StandardServletMultipartResolver
需要说明的是,CommonsMultipartResolver从 Spring Framework 6.0 及其新的 Servlet 5.0+ 基线开始,基于 Apache Commons FileUpload 的过时版本不再可用
SpringMvc在初始化时会从IOC中获取名为”multipartResolver“类型为MultipartResolver类型的Bean作为multipartResolver。
在Springboot的org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中对要使用的multipartResolver进行了配置,具备配置在org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
中,其配置如下
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
可见其默认使用的就是StandardServletMultipartResolver。
我们可以通过配置来对文件大小,存储路径等进行设置,如下:
spring.servlet.multipart.enabled=true
# servlet 接受到文件的时候,会先将其保存在一个临时目录
# 这个参数就可以指定这个目录的位置
spring.servlet.multipart.location=
#允许上传的文件最大值,默认为-1,表示没有限制
spring.servlet.multipart.maxFileSize=-1
#针对 multipart/form-data 请求的最大数量,默认为-1,表示没有限制
spring.servlet.multipart.maxRequestSize=-1
#文件大小超过这个值的会被写入磁盘,默认值为 0,都会写入磁盘,
#小于这个值的会被写在内存中。单位:byte
spring.servlet.multipart.fileSizeThreshold=0
StandardServletMultipartResolver作用就是从HttpServletRequest中获取Part,然后对其进行封装成MultipartFile对象
方式1:原生方式上传
@MultipartConfig(
location="",
maxFileSize=-1,
maxRequestSize=-1,
fileSizeThreshold=50*1024*1024
)
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
public void upload(HttpServletRequest request){
//方式1:读取指定参数的单个文件
Part part = request.getPart("file1");
//方式2:获取请求中所有参数的文件集合
Collection parts = req.getParts();
//获取文件名
String fileName = part.getSubmittedFileName();
//读取文件内容并写入文件
part.write(realPath + "/" + fileName);
//删除临时文件
part.delete();
}
}
方式2:SpringMvc中上传
@RestController
@RequestMapping("/upload")
public class UploadController {
/**
* 说明:这里用了注解@RequestPart,除此以外@RequestParam也是可用的。
* @RequestPart注解解析的是multipart/form-data表单中的数据,
* 可以支持文件参数 如MultipartFile
* @RequestParam 能解析请求格式为‘application/json’的数据 ,
* 同样也支持‘multipart/form-data’
*
* 1、当请求的contentType为“multipart/form-data”的时候@RequestParam
只能解析出String类型的 key-value的这种数据而@RquestPart可以接收
复杂的请求域如:json,xml,字节
* 2、@RequstParam依赖 Converter or PropertyEditor对数据进行解析,
@RequestPart参考‘contentType’依赖HttpMessageConverts对数据
进行解析
*/
@PostMapping("/file1")
public void upload1(@RequestPart MultipartFile file){
//destFile为目标文件,即将上传的文件写到destFile中
file.transferTo(destFile);
}
@PostMapping("/file2")
public void upload2(@RequestPart("param1") MultipartFile file){
}
@PostMapping("/file3")
public void upload3(@RequestPart("param1") MultipartFile file1,
@RequestPart("param2") MultipartFile file2){
}
@PostMapping("/file4")
public void upload4(MultipartFile[] fils) {}
@PostMapping("/file5")
public void upload5(MultipartHttpServletRequest request) {
//1.获取表单中非文件数据
Map parameterMap = request.getParameterMap();
//2、获取表单中文件数据
MultiValueMap multiFileMap = request.getMultiFileMap();
}
}
二、文件下载
方法1:使用HttpServletResponse
@RestController
@RequestMapping("/download")
@Tag(name = "文件下载示例")
public class DownloadController {
@Operation(summary = "访问我下载文件了")
@GetMapping("/v1")
public void download1 (HttpServletResponse response) {
//1. 接受文件名,读取磁盘对应的文件,创建输入流对象
FileInputStream inputStream = new FileInputStream("C:/"+fileName);
//2.获取响应对象的输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.文件下载文件名的编码使用ISO-08859-1编码
//我们需要将我们UTF-8的 filename转换ISO-8859-1编码
//3.1先将字符串以UTF-8转换成字节数组
byte[] bytes = fileName.getBytes("UTF-8");
//3.2再将字节数组以 ISO-8859-1转换字符串
fileName = new String(bytes, "ISO-8859-1");
//4.响应的内容应该是以附件的形式响应给浏览器(设置响应头)
response.setHeader("Content-Disposition", "attachment;filename="+fileName);
//5.响应文件给浏览器
IOUtils.copy(inputStream, outputStream);
//6.关闭流
inputStream.close();
outputStream.close();
}
}
方法2:使用ResponseEntity
@RestController
@RequestMapping("/download")
@Tag(name = "文件下载示例")
public class DownloadController {
@Operation(summary = "访问我下载文件了")
@GetMapping("/v1")
public ResponseEntity<Resource> download1 () {
//要下载的文件路径
Path path = Paths.get(".......") ;
Resource resource = new InputStreamResource(Files.newInputStream(path));
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="
+ URLEncoder.encode(fileInfo.getOriginalName(), "UTF-8"));
return ResponseEntity.ok()
.headers(headers)
.contentLength(Files.size(path))
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource) ;
}
@Operation(summary = "访问我下导出excel文件了")
@GetMapping("/v2")
public ResponseEntity<Resource> download2 () {
//查询数据库得到的数据 TODO
List<DataEntity> dataList = null ;
if(dataList == null){
dataList = new ArrayList<>() ;
}
//输出excel格式数据(这里使用了EasyExcel组件)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ;
EasyExcel.write(outputStream, DataEntity.class)
.sheet("数据")
.doWrite(dataList);
/*
多个sheet输出:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream() ;
ExcelWriter excelWriter = EasyExcel.write(outputStream).build() ;
try{
// 写出sheet数据
doWriteSheet(excelWriter,"我是sheet1",XXXDto.class,xxxDtoList);
doWriteSheet(excelWriter,"我是sheet2",YYYDto.class,yyyDtoList);
}finally {
// 关流
excelWriter.finish();
}
*/
String fileName = "下载文件.xlsx" ;
//字节数
long contentLength = outputStream.size() ;
//进行数据的写出
Resource resource = new ByteArrayResource(outputStream.toByteArray()) ;
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="
+ URLEncoder.encode(fileName, "UTF-8"));
return ResponseEntity.ok()
.headers(headers)
.contentLength(contentLength)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource) ;
}
private void doWriteSheet(ExcelWriter excelWriter,String sheetName,Class<?> clazz,List data){
// 构建sheet对象
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).head(clazz).build();
// 写出sheet数据
excelWriter.write(data, writeSheet);
}
}