这里介绍下SpringBoot中如何接收前台页面上传的文件,以及如何下载文件。
1、单个文件上传
1.1 单个文件上传实现步骤
首先写一个文件上传的Controller。
com.space.mysql.connect.controller.FileOpController
:
package com.space.mysql.connect.controller;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
* Created by chengxia on 2021/12/12.
* 这里需要尤为注意,Controller注解 ,必须用Controller,不能用原来的RestController!
*/
@Controller
@RequestMapping("/file")
public class FileOpController {
public final static String IMG_PATH_PREFIX = "static/upload";
@RequestMapping("/upload")
public String uploadPage(HttpServletRequest request){
return "fileUploadPage";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receive", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File uploaded success!";
}
}
这个controller中:
public String uploadPage(HttpServletRequest request)
方法返回一个模板名fileUploadPage
,绑定到/file/upload
。这样,当用户访问http://localhost:8080/file/upload
时会跳转到fileUploadPage.html
这个模板。
public String receiveFile(@RequestParam("file")MultipartFile file, HttpServletRequest request)
方法中,上传的文件可以通过函数参数中的file参数获得,在这个函数中将接收到的文件写入到了resources目录下的static/upload
子目录。处理完成之后,返回给用户一个文件上传成功的提示。
然后,写一个文件上传的模板,就是前面提到的fileUploadPage.html
。
templates/fileUploadPage.html
:
File Upload
到这里就完成了。目录结构如下:
运行启动之后,浏览器中访问
http://localhost:8080/file/upload
:
选中文件之后:
上传文件之后:
这时候,查看下工程的目录,会发现文件已经上传到target目录的指定子目录下:
1.2 需要注意的问题
1.2.1 文件上传目录的获得
这里是通过Resource applicationProperties = new ClassPathResource("application.properties")
先获得了配置文件application.properties
的目录,然后通过父目录拼接得到了存放上传文件的目录。这里为什么直接用ClassPathResource获取一个空目录呢?因为会报错,看样子ClassPathResource只支持一个已存在文件的获取,空目录是不行的。
代码中也列出了其他几种获取目录的方式:
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
对应的输出如下,可以供参考:
直接写相对目录获取的路径, src/main/resources/static/upload: /Users/chengxia/Developer/Java/projects/Test/src/main/resources/static/upload
通过系统属性user.dir获取的路径, System.getProperty("user.dir") + /static/upload: /Users/chengxia/Developer/Java/projects/Test/static/upload
通过ServletContext获取的路径, request.getServletContext().getRealPath("/") + /static/upload: /private/var/folders/jv/_wl4thx51kd9fszq10m2sqlr0000gn/T/tomcat-docbase.1230195161197134728.8080/static/upload
上传文件的存放目录:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload
1.2.2 org.springframework.web.multipart.MultipartFile#transferTo
方法
org.springframework.web.multipart.MultipartFile#transferTo
方法在使用时需要注意,只能调用一次,如果有第二次调用,会报错。因为http post文件流只可以接收读取一次,传输完毕则关闭流。如果需要将文件同时保存到两个地方,第二次需要做一次文件复制,不能连续调两遍org.springframework.web.multipart.MultipartFile#transferTo
2、上传文件的时候,同时提交参数
这里只需要修改前面的Controller和模板。
com.space.mysql.connect.controller.FileOpController
:
package com.space.mysql.connect.controller;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
* Created by chengxia on 2021/12/12.
* 这里需要尤为注意,Controller注解 ,必须用Controller,不能用原来的RestController!
*/
@Controller
@RequestMapping("/file")
public class FileOpController {
public final static String IMG_PATH_PREFIX = "static/upload";
@RequestMapping("/upload")
public String uploadPage(HttpServletRequest request){
return "fileUploadPage";
}
@RequestMapping("/uploadParam")
public String uploadPageParam(HttpServletRequest request){
return "fileUploadPageParam";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receive", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileParam", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, @RequestParam() String fileName, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File name, " + fileName + " uploaded success!";
}
}
主要是添加了一个public String uploadPageParam(HttpServletRequest request)
方法,返回一个新的文件上传带form参数的模板。添加了一个public String receiveFile(@RequestParam("file")MultipartFile file, @RequestParam() String fileName, HttpServletRequest request)
方法,在参数中,除了接收文件之外,也接收一个表单参数。
templates/fileUploadPageParam.html
:
File Upload
目录结构如下:
启动服务器之后,访问
http://localhost:8080/file/uploadParam
:
选中文件,填写表单之后:
提交之后:
3、多个文件上传
这里多个文件上传,实际上分为两种情况:一种是多个文件上传的form项,每一个都传了一个文件;另一种是在一个form项中同时传了多个文件。下面在一个例子中演示。
com.space.mysql.connect.controller.FileOpController
:
package com.space.mysql.connect.controller;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
* Created by chengxia on 2021/12/12.
* 这里需要尤为注意,Controller注解 ,必须用Controller,不能用原来的RestController!
*/
@Controller
@RequestMapping("/file")
public class FileOpController {
public final static String IMG_PATH_PREFIX = "static/upload";
@RequestMapping("/upload")
public String uploadPage(HttpServletRequest request){
return "fileUploadPage";
}
@RequestMapping("/uploadParam")
public String uploadPageParam(HttpServletRequest request){
return "fileUploadPageParam";
}
@RequestMapping("/uploadMulti")
public String uploadPageMulti(HttpServletRequest request){
return "fileUploadPageMulti";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receive", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileParam", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, @RequestParam() String fileName, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File name, " + fileName + " uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileMulti1", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file1")MultipartFile file1, @RequestParam("file2")MultipartFile file2, @RequestParam() String filesMark, HttpServletRequest request) throws Exception{
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
if(file1.isEmpty()){
return "file1没有选中任何文件!";
}
// 拿到文件名
String filename = file1.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file1.transferTo(uploadFile);
if(file2.isEmpty()){
return "file2没有选中任何文件!";
}
// 拿到文件名
filename = file2.getOriginalFilename();
// 构建真实的文件路径
uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file2.transferTo(uploadFile);
return "File name, " + filesMark + " uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileMulti2", method = RequestMethod.POST)
public String receiveFile(@RequestParam() MultipartFile[] files, @RequestParam() String filesMark, HttpServletRequest request) throws Exception{
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
for(int i = 0; i < files.length; i++) {
MultipartFile file = files[I];
if(file == null){
continue;
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
}
return "File name, " + filesMark + " uploaded success!";
}
}
templates/fileUploadPageMulti.html
:
File Upload
目录结构:
启动服务器之后,访问
http://localhost:8080/file/uploadMulti
:
分别选中两个文件并填写form后:
点击上面的提交:
控制台输出:
上传文件的存放目录:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload
文件上传到:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload/f1.txt
文件上传到:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload/f2.txt
重新访问http://localhost:8080/file/uploadMulti
,并在下面的表单中同时选中多个文件:
这时候点击下面的提交:
这时候控制台输出:
上传文件的存放目录:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload
文件上传到:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload/a.txt
文件上传到:/Users/chengxia/Developer/Java/projects/Test/connnect/target/classes/static/upload/b.txt
注意上传文件不能太大,否则会报错(控制台):
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field files exceeds its maximum permitted size of 1048576 bytes.
at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl$FileItemStreamImpl$1.raiseError(FileUploadBase.java:630) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.checkLimit(LimitedInputStream.java:76) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:135) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at java.io.FilterInputStream.read(FilterInputStream.java:107) ~[na:1.8.0_181]
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:68) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:293) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.Request.parseParts(Request.java:2869) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.Request.parseParameters(Request.java:3216) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.Request.getParameter(Request.java:1137) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459) [tomcat-embed-core-8.5.28.jar:8.5.28]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.28.jar:8.5.28]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_181]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_181]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.28.jar:8.5.28]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_181]
4、文件下载
相比上传,文件下载要容易得多。
com.space.mysql.connect.controller.FileOpController
:
package com.space.mysql.connect.controller;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
/**
* Created by chengxia on 2021/12/12.
* 这里需要尤为注意,Controller注解 ,必须用Controller,不能用原来的RestController!
*/
@Controller
@RequestMapping("/file")
public class FileOpController {
public final static String IMG_PATH_PREFIX = "static/upload";
@RequestMapping("/upload")
public String uploadPage(HttpServletRequest request){
return "fileUploadPage";
}
@RequestMapping("/download")
public String downloadPage(HttpServletRequest request){
return "fileDownloadPage";
}
@RequestMapping("/uploadParam")
public String uploadPageParam(HttpServletRequest request){
return "fileUploadPageParam";
}
@RequestMapping("/uploadMulti")
public String uploadPageMulti(HttpServletRequest request){
return "fileUploadPageMulti";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receive", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileParam", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file")MultipartFile file, @RequestParam() String fileName, HttpServletRequest request) throws Exception{
if(file.isEmpty()){
return "没有选中任何文件!";
}
//如下随便尝试几种获取module运行目录的几种方式
//直接取相对目录的话,获取到的是project中新建的第一个module中的路径
String directRelativePath = new String("src/main/resources" + File.separator + IMG_PATH_PREFIX);
File directRelativeDir = new File(directRelativePath);
System.out.println("直接写相对目录获取的路径, src/main/resources/static/upload: " + directRelativeDir.getAbsolutePath());
//通过System.getProperty("user.dir")获取module路径
String userDirPath = System.getProperty("user.dir");
File userDirDir = new File(userDirPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过系统属性user.dir获取的路径, System.getProperty(\"user.dir\") + /static/upload: "+userDirDir.getAbsolutePath());
//request.getServletContext().getRealPath("/")获取运行时的路径
String requestServletContextPath = request.getServletContext().getRealPath("/");
File requestServletContextDir = new File(requestServletContextPath + File.separator + IMG_PATH_PREFIX);
System.out.println("通过ServletContext获取的路径, request.getServletContext().getRealPath(\"/\") + /static/upload: "+requestServletContextDir.getAbsolutePath());
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
return "File name, " + fileName + " uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileMulti1", method = RequestMethod.POST)
public String receiveFile(@RequestParam("file1")MultipartFile file1, @RequestParam("file2")MultipartFile file2, @RequestParam() String filesMark, HttpServletRequest request) throws Exception{
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
if(file1.isEmpty()){
return "file1没有选中任何文件!";
}
// 拿到文件名
String filename = file1.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file1.transferTo(uploadFile);
if(file2.isEmpty()){
return "file2没有选中任何文件!";
}
// 拿到文件名
filename = file2.getOriginalFilename();
// 构建真实的文件路径
uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file2.transferTo(uploadFile);
return "File name, " + filesMark + " uploaded success!";
}
/**
* ResponseBody注解的意思是,这里返回的不是一个thymeleaf的模板名,就是一个简单的请求体
* */
@ResponseBody
@RequestMapping(value="/receiveFileMulti2", method = RequestMethod.POST)
public String receiveFile(@RequestParam() MultipartFile[] files, @RequestParam() String filesMark, HttpServletRequest request) throws Exception{
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File uploadFileSaveDir = new File(uploadFileSavePath);
System.out.println("上传文件的存放目录:"+uploadFileSaveDir.getAbsolutePath());
if(!uploadFileSaveDir.exists()){
// 递归生成文件夹
uploadFileSaveDir.mkdirs();
}
for(int i = 0; i < files.length; i++) {
MultipartFile file = files[I];
if(file == null){
continue;
}
// 拿到文件名
String filename = file.getOriginalFilename();
// 构建真实的文件路径
File uploadFile = new File(uploadFileSaveDir.getAbsolutePath() + File.separator + filename);
System.out.println("文件上传到:" + uploadFile.getAbsolutePath());
//文件写到服务器,
file.transferTo(uploadFile);
}
return "File name, " + filesMark + " uploaded success!";
}
@ResponseBody
@RequestMapping(value = "/fetch", method = RequestMethod.POST)
public String fileDownload(@RequestParam() String fileName, HttpServletResponse response)throws Exception{
//这里将文件放在resources目录的static/upload子目录下,通过ClassPathResource的方式先拿到application.properties文件的路径。
//然后,取父目录得到resources目录。
//先通过ClassPathResource获取application.properties的路径
Resource applicationProperties = new ClassPathResource("application.properties");
//然后通过取其父目录获得resources目录,设置上传文件的目录
String uploadFileSavePath = applicationProperties.getFile().getParentFile().getAbsolutePath() + File.separator + "static/upload";
File downloadFile = new File(uploadFileSavePath + File.separator + fileName);
System.out.println("下载文件的完整路径:"+downloadFile.getAbsolutePath());
if(!downloadFile.exists()){
System.out.println("要下载的文件不存在:"+downloadFile.getAbsolutePath());
return "File not exists, download fail!";
}else {
//第一步:设置响应类型
response.setContentType("application/force-download");//应用程序强制下载
//第二读取文件
InputStream in = new FileInputStream(downloadFile);
//设置响应头,对文件进行url编码
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename="+fileName);
response.setContentLength(in.available());
//第三步:读文件写入http响应
OutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while((len = in.read(b))!=-1){
out.write(b, 0, len);
}
out.flush();
out.close();
in.close();
return "Download success!";
}
}
}
controller中多写了两个方法,一个返回下载文件的页面。一个方法处理文件的下载请求,页面传入文件名,程序从原来上传文件的存放目录查找文件,找到就作为下载附件返回,找不到就提示报错。
下载文件的页面模板也很简单。templates/fileDownloadPage.html
:
File Upload
完成后目录结构如下:
启动程序之后,访问
http://localhost:8080/file/download
:
输入下载的文件名:
点击提交,浏览器会弹出下载框,下载文件
a.txt
。如果输入不存在的文件名:
点击提交,就会提示文件不存在:
参考资料
- 为什么java使用MultipartFile的transferTo()方法不能使用两次?
- transferto 文件不存在_解决使用Spring Boot、Multipartfile实现上传提示无法找到文件的问题...
- springboot文件上传前端+后台接收文件(单文件+多文件)