spring boot(学习笔记第四课)
- 文件上传,ControlAdvice的使用
>>>学习视频
学习内容:
- 文件上传(单文件,多文件)
- ControlAdvice的使用
1. 文件上传
- 单文件上传
- 准备upload的前端页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" value="please select file">
<input type="submit" value="upload">
</form>
</body>
</html>
作为静态资源保存在resources/static
下面。action="/upload"
。
- 接下来在server端准备controller。
@Controller
public class FileUploadController {
private SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyyMMdd");
@PostMapping(value = "/upload")
@ResponseBody
public String upload(MultipartFile uploadFile,
HttpServletRequest req) {
String realPath =
req.getSession()
.getServletContext()
.getRealPath("/uploadFile/") + "/";
String format = simpleDateFormat.format(new Date());
File folder = new File(realPath + format);
if (!folder.isDirectory()) {
folder.mkdirs();
}
String oldName = uploadFile.getOriginalFilename();
String newName = UUID.randomUUID().toString() +
oldName.substring(oldName.indexOf("."), oldName.length());
try {
uploadFile.transferTo(new File(folder, newName));
String filePath = req.getScheme() +
"://" + req.getServerName() +
":" + req.getServerPort() +
"/uploadFile/" + format + "/" + newName;
return filePath;
} catch (IOException ex) {
ex.printStackTrace();
}
return "upload failed.";
}
}
在这个例子中,将文件上传过来之后,使用UUID
生成新的文件名,保存在静态资源的一个文件夹中,之后可以通过生成的URL
进行图片的浏览。
- 测试下文件上传
通过debug
观察下文件上传到server之后的文件夹位置。
C:\Users\Dell\AppData\Local\Temp\tomcat-docbase.8080.13912607674277034020\uploadFile
这里的路径是真正server上的保存路径,注意同时upload
之前的部分也是静态资源的查询路径。 - 测试文件上传。
点击upload
按钮,会将文件最终上传。
- 因为生成的
URL
同时也是能够访问的一个静态资源,copy
出来之后在浏览器中访问。
- 多文件同时上传
- 首先更改前端页面,区别就是在
form
的文件input
加上multiple
,其他和单文件上传相同。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Title</title>
</head>
<body>
<form action="/upload_multiple" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFiles" value="please select file" multiple>
<input type="submit" value="upload">
</form>
</body>
</html>
controller
也追加一个多文件上传方法。
单文件的处理和多文件的处理有共同的地方,所以使用IntelliJ IDEA
的方法抽取快捷方式。
选择红圈的代码,之后执行快捷方式,CRTL-ALT-M
。
将方法名字设定成uploadFileToLocal。注意这里CRTL-ALT-M
快捷键按下的时候,选择的代码必须是能够重构到一个方法的完整代码段,之后自行修改方法名。
服务器段的接受多个文件上传controller
的代码。注意参数已经相应修改成了MultipartFile[] uploadFiles
,并且uploadFiles这个变量名和前端input
的组件里面的名字uploadFiles
必须一直。
@PostMapping("/upload_multiple")
public String upload(MultipartFile[] uploadFiles,
HttpServletRequest req){
String realPath=
req.getSession()
.getServletContext()
.getRealPath("/uploadFile/") +"/";
StringBuffer fileLinks = new StringBuffer();
for(MultipartFile uploadFile:uploadFiles) {
String filePath = uploadFileToLocal(uploadFile, req, realPath);
fileLinks.append(filePath);
fileLinks.append("<br>");
}
return fileLinks.toString();
}
2. ControlAdvice的使用
- spring boot的文件上传可以配置最大的文件尺寸是1M,尝试下如果超过的话会出现什么现象。
- 进入
git bash
在,执行命令做成一个2M的文件。
dd if=/dev/zero of=test_file bs=1M count=2
- 上传文件,看看执行效果。
IntellIJ IDEA
上会出现异常的log
。
2024-06-08T16:26:16.091+08:00 WARN 5564 --- [demo] [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded]
- 采用
ControlAdvice
对MaxUploadSizeExceededException进行页面表示。
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public void handleUploadException(MaxUploadSizeExceededException e,
HttpServletResponse response) throws IOException{
response.setContentType("text/html;charset=utf-8");
PrintWriter pw = response.getWriter();
pw.write("文件size上传超过上限");
pw.close();
}
}
再次上传,看看执行结果。
- 也可以通过自定义一个error.html页面来表示指定的错误。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>定制服务器端表示页面</title>
</head>
<body>
<div th:text="${message}"></div>
</body>
</html>
之后修改ControllerAdvice
。
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ModelAndView handleUploadException(MaxUploadSizeExceededException e,
HttpServletResponse response) throws IOException{
ModelAndView mv = new ModelAndView();
mv.addObject("message","文件size超过上传上限");
mv.setViewName("error");
return mv;
}
}
*注意pom.xml
*加入thymeleaf的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
再次访问上传2M
的文件。
2. 添加全局数据
- 定义
ControllerAdvice
类。@ControllerAdvice public class GlobalConfig { @ModelAttribute(value = "info") public Map<String,String> userInfo(){ HashMap<String,String> map = new HashMap<>(); map.put("username","finlay"); map.put("gender","male"); return map; } }
- 在
controller
中取得变量。@GetMapping("/hello") @ResponseBody public String hello(Model model){ Map<String,String> userInfo = (Map<String,String>)model.getAttribute("info"); Set<String> userInfoSet = userInfo.keySet(); Iterator<String> it = userInfoSet.iterator(); StringBuffer response = new StringBuffer(); while(it.hasNext()){ String key = it.next(); String value = userInfo.get(key); response.append("key is " + key + " value is " + value); response.append("<br>"); } return response.toString(); }
- 请求参数的预处理
前端画面可能传递来两个参数,每个参数里面都可能有同样的变量,那么这样前端的input
的命名就会有冲突,可以使用ControllerAdvice
。
- 假如前端有两个数据Book和Author需要后端接受:
@Data public class Book { private String name; private String author; @JsonIgnore protected Float price; @JsonFormat(pattern = "yyyy-MM-dd") private Date publicatationDate; }
@Data public class Author { private String name; private String age; }
- 定义
ControllerAdvice
,进行前端input
变量的映射绑定。@ControllerAdvice public class InputBinder { @InitBinder("author") public void initAuthor(WebDataBinder binder){ binder.setFieldDefaultPrefix("author."); } @InitBinder("book") public void initBook(WebDataBinder binder){ binder.setFieldDefaultPrefix("book."); } }
- 修改后端代码,利用prefix进行对
form
变量的解析。@GetMapping("/book_and_author") @ResponseBody public String bookAndAuthor(@ModelAttribute("book") Book book, @ModelAttribute("author") Author author){ return book.getName() + " >>> " + author.getName(); }
- 使用
get
协议访问,并使用prefix
传递参数。https://localhost:8080/book_and_author?book.name=springboot&book.description=good&author.name=finlay&author.age=20