接着之前的代码,开始我的实验三:文件上传。
简单学习了一下之后发现,springboot实现文件上传真的是太轻松了!一起来看吧!
一、在原有的项目基础之上添加两个依赖:
<!-- 文件上传依赖 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- 非必需 简化io操作 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
二、创建一个配置类,实现WebMvcConfigurer接口
package com.example.demo.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.multipart.MultipartResolver;
//这里采用JavaBean的配置方式
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(1000000);
return multipartResolver;
}
//快速地建立请求和页面之间的映射关系
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//setViewName是用来设置返回哪个页面的
registry.addViewController("/demo/upload").setViewName("/upload");
}
}
在里面我们需要将MultipartResolver这个Bean加到容器中去管理,这是Java配置的常规写法。
第二个重写的方法是addViewControllers,它可以用来做快速的页面请求映射。什么意思呢?我解释一下。
以往我们发出/demo/upload请求是如何定位到upload.html页面的呢?我们是在Controller中写如下代码:
//这个Controller的Mapping为:/demo
@RequestMapping(value = "/upload")
public String upload() {
return "upload";
}
因此,我们输入/demo/upload才能定位到upload.html页面。
但是,在Web项目中,这种页面映射关系太多太多了,难道我们只能在这里写这种冗长的代码吗?
这里就提到了WebMvcConfigurer这个接口的第二个用处了:快速映射。
通过registry.addViewController("/demo/upload").setViewName("/upload");
我们很快就能确定映射关系了,代码是不是少多了?
WebMvcConfigurer这个类其实还有很多妙用,前面我们讲过借助它的addInterceptors方法可以添加拦截器。
三、编写前端页面
<!DOCTYPE html>
<!-- thymeleaf -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>upload.html</title>
</head>
<body>
<!-- 把提交的文件提交到success请求,enctype设置提交的信息是multipart的,多部分形式的包括二进制文件等 -->
<form th:action="@{/demo/success}" enctype="multipart/form-data" method="post">
<input type="file" name="file" /><br/>
<input type="submit" value="提交" />
</form>
</body>
</html>
当我们选择好了文件点击提交之后,表单就会把数据发送给/demo/success请求,然后去处理。
值得一提的是,enctype="multipart/form-data"
默认表单只能提交一些简单数据,这里进行设置之后,表单就能提交二进制文件之类的了。
四、最后编写Controller,将提交上来的文件存储到本地就成功了
@PostMapping(value = "/success")
@ResponseBody
public String success(MultipartFile file) {
try {
FileUtils.writeByteArrayToFile(new File("e:/upload/" + file.getOriginalFilename()), file.getBytes());
return "ok";
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "wrong";
}
}
@ResponseBody表示我们最后直接返回给前端页面一个字符串,而不是页面
FileUtils调用方法writeByteArrayToFile:顾名思义,就是将一个Byte数组中的信息,写到一个文件中去。
那么我们第一个参数要指定写入文件的文件名和存储路径。
五、注意坑点
第一次做完的时候运行程序500崩掉了,找了半天没发现到底是什么原因。直到在网上偶然发现一篇博客,正好解决了我的问题。
就是SpringBoot自动配置的问题。SpringBoot中默认自动把MultipartResolver这个类配置好了,所以我再配置的时候就出问题了。
解决方法,关闭掉SpringBoot对其的自动配置,在application.properties文件中:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
原博客链接:https://www.cnblogs.com/virgosnail/p/10282083.html
坑点二:
在文件上传的时候,要用post请求,用get会产生错误
六、测试
待上传的文件1.txt:
上传前upload文件夹没有一个文件:
运行程序上传:
显示成功上传
我们看看upload文件夹,看看是不是上传成功了:
果真有一个一模一样的文件: