一、配置
添加依赖包
<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>
引入了 spring-boot-starter-thymeleaf 做页面模板引擎。
添加配置
#是否支持 multipart 上传文件
spring.servlet.multipart.enabled=true
#支持文件写入磁盘
#spring.servlet.multipart.file-size-threshold=0
#上传文件的临时目录
#spring.servlet.multipart.location=
#最大支持文件大小
spring.servlet.multipart.maxFileSize=10MB
#最大支持请求大小
spring.servlet.multipart.maxRequestSize=10MB
#是否支持 multipart 上传文件时懒加载
#spring.servlet.multipart.resolve-lazily=false
再启动类中增加相关方法
@SpringBootApplication
public class FileUploadWebApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(FileUploadWebApplication.class, args);
}
//Tomcat large file upload connection reset
@Bean
public TomcatServletWebServerFactory tomcatEmbedded() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}
}
TomcatServletWebServerFactory() 方法主要是为了解决上传文件大于 10M 出现连接重置的问题,此异常内容 GlobalException 也捕获不到。
二、相关代码
单文件上传
上传业务处理:
@PostMapping("/upload")
public String singleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
return "Please select a file to upload";
}
try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
// UPLOADED_FOLDER 文件本地存储地址
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
return "You successfully uploaded '" + file.getOriginalFilename() + "'";
}
异常处理
这里演示的是 MultipartException 的异常处理,也可以稍微改造监控整个项目的异常问题。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MultipartException.class)
public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
return "redirect:/uploadStatus";
}
}
设置一个 @ControllerAdvice 用来监控 Multipart 上传的文件大小是否受限,当出现此异常时在前端页面给出提示。利用 @ControllerAdvice 可以做很多东西,比如全局的统一异常处理等,感兴趣的读者可以抽空了解一下。
多文件上传
@PostMapping("/uploadMore")
public String moreFileUpload(@RequestParam("file") MultipartFile[] files,
RedirectAttributes redirectAttributes) {
if (files.length==0) {
return "Please select a file to upload";
}
for(MultipartFile file:files){
try {
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
return "You successfully uploaded all";
}
总的来说,文件上传的代码还是比较简单的,但是要注意,需要按照实际的需求去处理相关的业务,比如返回上传图片地址,存储文件的相对路径到数据库,
三、采坑记录
1、IDEA控制台 中文乱码问题,
在pom文件中添加 编码格式
IDEA设置编码的地方很多,需要注意要保持一致,
2、设置文件上传路径和显示路径
在开发过程中,如果不设置上传文件路径, 或者路径设置在项目中的文件中的时候,当项目重新发布时,上传的文件就丢失了。
所以这里我把文件上传到了本地文件夹。
这样带来一个问题,怎么显示上传的文件。
① 如果是直接放在tomcat中,可以通过修改tomcat的配置,
在tomcat>conf>server.xml 中,添加文件的映射
② 如果是用的IDEA发布的,可以修改相关配置。
先配置上传文件路径和外部访问路径
#静态资源对外暴露的访问路径
file.staticAccessPath=upload/**
#文件上传目录(注意Linux和Windows上的目录结构不同)
#file.uploadFolder=/root/uploadFiles/
file.uploadFolder=G://upload/
添加文件UploadFilePathConfig 用于映射两个路径的关系
@Configuration
public class UploadFilePathConfig extends WebMvcConfigurerAdapter {
@Value("${file.staticAccessPath}")
private String staticAccessPath;
@Value("${file.uploadFolder}")
private String uploadFolder;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(staticAccessPath).addResourceLocations("file:" + uploadFolder);
}
}
注意,这里的外部访问路径都是相对路径,没有包含项目的根路径context-path, 在前端界面 使用时,需要手动添加。
这里我没有把根目录配置到文件路径中进去,而是在前段拼接。因为我会把文件的路径存储在数据库中,如果带有根路径相关数据,在项目名发生改变的时候改动会很多,
3、关于@RestController 和@Controller 的区别
@RestController是 @Controller 和 @ResponseBody 注解的合体版 ; 如果配置,则返回 相关字符串
如果配置为 @Controller,代表输出对应的页面。
不用弄错了
4、jsp和Thymeleaf混合使用
之前的上传界面是用jsp写的,引入进来之后,jsp界面一直找不到,
报错:
Error resolving template [hello], template might not exist or might not be accessible by any of the configured Template Resolvers
但是反复确认了jsp文件和相关的配置都没有问题,后来才看到
spring boot 不建议使用jsp,并且对JSP支持存在一些限制
- 使用Jetty和Tomcat,如果使用war包装,它应该可以工作。可执行的war在启动时将起作用java -jar,并且也可以部署到任何标准容器。使用可执行jar时不支持JSP。
- Undertow不支持JSP。
- 创建自定义error.jsp页面不会覆盖错误处理的默认视图 。 应该使用自定义错误页面。
但是如果真的要使用jsp,还是有办法的:
1、在配置文件application.properties 中 配置 jsp,和之前的差不多,
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
spring.mvc.view.view-name=jsp/*
spring.mvc.view.order=2
2、在SpringbootApplication文件中添加对应的映射方法,并将相关配置设置到方法中
@Value("${spring.mvc.view.prefix}")
private String prefix;
@Value("${spring.mvc.view.suffix}")
private String suffix;
@Value("${spring.mvc.view.view-name}")
private String viewName;
@Value("${spring.mvc.view.order}")
private int order;
@Bean
InternalResourceViewResolver jspViewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix(prefix);
viewResolver.setSuffix(suffix);
viewResolver.setViewNames(viewName);
viewResolver.setOrder(order);
return viewResolver;
}
3、在控制器中使用
@RequestMapping("/welcome")
public String welcome(Map<String, Object> model) {
model.put("time", new Date());
model.put("message", "www.richduckling.com");
model.put("count", 16);
return "jsp/hello";
}
注意:
这里配置jsp文件位置参数 时,我设置的是“spring.mvc.view.prefix=/WEB-INF/jsp” ,使用时 “return "jsp/hello"”,但是还是报错。重新安置上面的设置,就可以。因为 如果在控制器中不设置jsp路径,会默认去Thymeleaf的相关路径中去找,如果找不到对应的Thymeleaf视图就会报错,于是排在后面用来解析Jsp视图的InternalResourceViewResolver就失效了,不会继续在jsp相关文件中找。无语。