定制开发SpringBoot文件上传

文件上传

Spring MVC定制开发对文件上传做了简化,在Spring Boot定制开发中对此做了更进一步的简化,定制开发文件上传更为方便。

Java定制开发中的文件上传一共涉及两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMultipartResolver,其中 CommonsMultipartResolver使用commons-fileupload来处理multipart 请求,而StandardServletMultipartResolver则是基于Servlet 3.0来处理multipart 请求的,定制开发因此若使用StandardServletMultipartResolver,定制开发则不需要添加额外的jar包。Tomcat 7.0定制开发开始就支持Servlet 3.0 了,定制开发因此可以直接使用StandardServletMultipartResolver。而在Spring Boot 定制开发提供的文件上传自动化配置类MultipartAutoConfiguration中,定制开发默认也是采用StandardServletMultipartResolver,定制开发部分源码如下:

public class 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;	}}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

定制开发根据这里的配置可以看出,定制开发如果开发者没有提供 MultipartResolver,定制开发那么默认采用的MultipartResolver就是StandardServletMultipartResolver。因此,在Spring Boot定制开发中上传文件甚至可以做到零配置。定制开发下面来看具体上传过程。

1. 定制开发单文件上传

1.1 单文件上传简单实现

首先创建一个Spring Boot项目并添加spring-boot-starter-web 依赖。
然后在resources目录下的static目录中创建一个upload.html文件,内容如下:

<!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="请选择文件">    <input type="submit" value="上传"></form></body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这是一个很简单的文件上传页面,上传接口是/upload,注意请求方法是 post,enctype是multipart/form-data。

enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。

默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。

描述
application/x-www-form-urlencoded在发送前编码所有字符(默认)
multipart/form-data不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain空格转换为 “+” 加号,但不对特殊字符编码。

接着创建文件上传处理接口,代码如下:

@RestControllerpublic class FileUploadController {    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");    @PostMapping("/upload")    public String upload(MultipartFile uploadFile, HttpServletRequest req) {        String realPath =                req.getSession().getServletContext().getRealPath("/uploadFile/");        String format = sdf.format(new Date());        File folder = new File(realPath + format);        String filePath="";        if (!folder.isDirectory()) {            folder.mkdirs();            String oldName = uploadFile.getOriginalFilename();            String newName = UUID.randomUUID().toString() +                    oldName.substring(oldName.lastIndexOf("."), oldName.length());            try {                uploadFile.transferTo(new File(folder, newName));                 filePath = req.getScheme() + "://" + req.getServerName() + ":" +                        req.getServerPort() + "/uploadFile/" + format + newName;                            } catch (IOException e) {                e.printStackTrace();                return "上传失败! ";            }        }        return filePath;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

代码解释:

  • 第7~12代码表示规划上传文件的保存路径为项目运行目录下的uploadFile文件夹,并在文件夹中通过日期对所上传的文件归类保存。
  • 第13~15行代码表示给上传的文件重命名,这是为了避免文件重名。第17行是文件保存操作。
  • 第18~20行是生成上传文件的访问路径,并将访问路径返回。

最后在浏览器中进行测试。
运行项目,在浏览器中输入“http://localhost:8080/upload.html”进行文件上传

单击“请选择文件”按钮上传文件,文件上传成功后,会返回上传文件的访问路径

1.2 单文件上传优化

但是这样做还是有问题,上传图片到服务器根路径下的文件夹里,若重启服务器,图片又无法访问,这是因为每次重启服务器之后,都会在系统临时文件夹内,创建一个新的服务器,图片就保存在这里,若重启,又会产生一个新的服务器,此时访问的就是新服务器的图片资源,而图片根本就不在新服务器内。还有就是上面一个传相同日期的文件的时候会出现无法上传文件。

而且,系统的临时文件夹会定期清理,很有可能导致以前上传的文件丢失。

  • windows的临时文件夹位置:
C:\Users\User\AppData\Local\Temp
  • 1
  • Linux的临时文件夹位置:
/tmp
  • 1

以方案4为例,在windows上进行

application.yml文件中自定义图片保存位置

设置的图片保存路径的末尾必须有 /,代码中默认保存路径最后已经带有/
Linux上的路径示例: /usr/developmentTool/myproject/bookstoreAPI/files/images/
Windows上的路径 示例: E:/images/

file-save-path: E:/uploadFile/
  • 1

改变原来的代码

@RestControllerpublic class FileUploadController1 {    @Value("${file-save-path}")    private String fileSavePath;    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");    @PostMapping("/upload1")    public String upload(MultipartFile uploadFile, HttpServletRequest req) {        String filePath = "";        String format = sdf.format(new Date());        File folder = new File(fileSavePath + format);        if (!folder.isDirectory()) {            folder.mkdirs();            String oldName = uploadFile.getOriginalFilename();            String newName = UUID.randomUUID().toString() +                    oldName.substring(oldName.lastIndexOf("."), oldName.length());            try {                uploadFile.transferTo(new File(folder, newName));                filePath = req.getScheme() + "://" + req.getServerName() + ":" +                        req.getServerPort() + "/uploadFile/" + format + newName;            } catch (IOException e) {                e.printStackTrace();                return "上传失败! ";            }        }        String oldName = uploadFile.getOriginalFilename();        String newName = UUID.randomUUID().toString() +                oldName.substring(oldName.lastIndexOf("."), oldName.length());        try {            uploadFile.transferTo(new File(folder, newName));            filePath = req.getScheme() + "://" + req.getServerName() + ":" +                    req.getServerPort() + "/uploadFile/" + format + newName;        } catch (IOException e) {            e.printStackTrace();            return "上传失败! ";        }        return filePath;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

如果选择这种方式不能忘记对静态资源的映射

配置资源映射(重点

@Configurationpublic class WebConfig implements WebMvcConfigurer {	/**     * 图片保存路径,自动从yml文件中获取数据     *   示例: E:/images/     */    @Value("${file-save-path}")    private String fileSavePath;        @Override    public void addResourceHandlers(ResourceHandlerRegistry registry) {        /**         * 配置资源映射         * 意思是:如果访问的资源路径是以“/images/”开头的,         * 就给我映射到本机的“E:/images/”这个文件夹内,去找你要的资源         * 注意:E:/images/ 后面的 “/”一定要带上         */        registry.addResourceHandler("/uploadFile/**")                .addResourceLocations("file:"+fileSavePath);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
最后在浏览器中进行测试。
  • 1

运行项目,在浏览器中输入“http://localhost:8080/upload.html”进行文件上传,和上面效果一样,但是可以在指定的地址下找到上传的文件.

静态资源位置除了classpath下面的4个路径之外,还有一个"/",因此这里的图片虽然是静态资源却可以直接访问到。

至此,一个简单的图片上传逻辑就完成了,对于开发者而言,只需要专注于图片上传的业务逻辑,而不需要在配置上花费太多时间。
当然,如果开发者需要对图片上传的细节进行配置,也是允许的,代码如下:

#是否开启文件上传支持,默认为true。spring. servlet.multipart.enabled=true #文件写入磁盘的阈值,默认为0。spring.servlet.multipart.file-size-threshold=0#上传文件的临时保存位置。spring.servlet.multipart.location=E:\ltemp#上传的单个文件的最大大小,默认为1MB。spring.servlet.multipart.max-file-size=1MB#多文件上传时文件的总大小,默认为10MB。spring.servlet.multipart.max-request-size=10MB#文件是否延迟解析,默认为false。spring.servlet.multipart.resolve-lazily=false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2. 多文件上传

多文件上传和单文件上传基本一致,首先修改HTML文件,代码如下:

@RestControllerpublic class FileUploadController2 {    @Value("${file-save-path}")    private String fileSavePath;    ArrayList<String> mylist=new ArrayList();    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");    @PostMapping("/uploads")    public ArrayList upload(MultipartFile[] uploadFiles, HttpServletRequest req) {        String filePath = "";        for(MultipartFile uploadFile:uploadFiles){            String format = sdf.format(new Date());            File folder = new File(fileSavePath + format);            if (!folder.isDirectory()) {                folder.mkdirs();                String oldName = uploadFile.getOriginalFilename();                String newName = UUID.randomUUID().toString() +                        oldName.substring(oldName.lastIndexOf("."), oldName.length());                try {                    uploadFile.transferTo(new File(folder, newName));                    filePath = req.getScheme() + "://" + req.getServerName() + ":" +                            req.getServerPort() + "/uploadFile/" + format + newName;                } catch (IOException e) {                    e.printStackTrace();                }            }            String oldName = uploadFile.getOriginalFilename();            String newName = UUID.randomUUID().toString() +                    oldName.substring(oldName.lastIndexOf("."), oldName.length());            try {                uploadFile.transferTo(new File(folder, newName));                filePath = req.getScheme() + "://" + req.getServerName() + ":" +                        req.getServerPort() + "/uploadFile/" + format + newName;            } catch (IOException e) {                e.printStackTrace();            }            mylist.add(filePath);        }        return mylist;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

运行项目,在浏览器中输入“http://localhost:8080/uploads.html”进行文件上传,在选择文件时安住ctrl多选文件上传,和上面效果一样,可以在指定的地址下找到上传的文件.

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发