补:Spring Boot 当中实现文件上传功能(附+源代码)

1. 补:Spring Boot 当中实现文件上传功能(附+源代码)

文章目录

  • [1. 补:Spring Boot 当中实现文件上传功能(附+源代码)](#1. 补:Spring Boot 当中实现文件上传功能(附+源代码))
  • [2. 准备工作](#2. 准备工作)
  • [3. 开始演示:实现文件上传功能(附+源码)](#3. 开始演示:实现文件上传功能(附+源码))
    • [3.1 第一种方式:静态创建方式](#3.1 第一种方式:静态创建方式)
    • [3.2 第二种方式:动态创建方式](#3.2 第二种方式:动态创建方式)
  • [4. 上传文件的注意事项](#4. 上传文件的注意事项)
  • [5. 最后:](#5. 最后:)

2. 准备工作

我们在 pom.xml 文件当中导入相关的 jar 依赖。如下:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>springboot-fileUpload</artifactId>
    <version>1.0-SNAPSHOT</version>



    <!--    导入SpringBoot 父工程-规定写法-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
    </parent>

    <!--    导入web项目场景启动器:会自动导入和web开发相关的jar包所有依赖【库/jar】-->
    <!--    后面还会在说明spring-boot-starter-web 到底引入哪些相关依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--        引入 thymeleaf-start ,项目会自动完成配置,-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--  引入 lombok 插件      -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

编写项目的场景启动器:

java 复制代码
package com.rainbowsea.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication // 项目启动场景
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}

编写相关前端 HTML页面,上传文件的页面。

注意:这里我们是前端使用的是 thymeleaf 视图解析器。所以关于前端映射文件的存放位置,不可以随便放。

html 复制代码
enctype="multipart/form-data" 文件提交
multiple 属性可以选中多个文件信息上传
<input type="reset" value="重新填写"><br> ; type="reset" 清空表单,重新填写表单

前端页面显示效果:


3. 开始演示:实现文件上传功能(附+源码)

3.1 第一种方式:静态创建方式

静态创建方式: 静态方式,先手动在指定的 windows 当中创建好目录,再放入上传的文件。到其目录当中。

java 复制代码
package com.rainbowsea.springboot.controller;


import com.rainbowsea.springboot.utils.WebUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Slf4j
@Controller  // 控制器
public class UploadController {

    // 处理转发到用户注册~可以完成文件上传页面
    @GetMapping("/upload.html")
    public String uploadPage() {

        return "upload";  // 视图解析,pom_>jar,转发到templates/upload.html
        // 注意如果配置了拦截器,资源的上传 upload.html页面也是要放行的
    }


    // 处理用户的注册请求-包括处理文件上传

    // 静态方式,先手动在指定的windows当中创建目录,在放入文件
    @PostMapping("/upload")
    @ResponseBody
    public String upload(
            // 自动封装
            String name,
            String email,
            Integer age,
            String job,
            @RequestParam("header") MultipartFile header,
            @RequestParam("photos") MultipartFile[] photos
    ) throws IOException {
        log.info("上传的信息 name={},email={} age = {} job={} ",name,email,age,job);
        log.info("header={}",header);
        log.info("photos={}",photos);


        // 如果信息都成功得到,我们就将文件保存到指定的目录比如:E:\temp_upload
        // 1. 我们需要先将文件保存到指定的目录,比如:E:\temp_upload
        // 2. 后面我们在演示把文件保存到动态创建的目录当中
        // 首先处理头像的文件,因为只有一张图片
        if(!header.isEmpty()) {  // 处理头像
            String originalFilename = header.getOriginalFilename();
            System.out.println(originalFilename);
            header.transferTo(new File("E:\\temp_upload\\" +originalFilename) );
        }

        // 处理宠物的图片
        if(photos.length > 0) {
            for (MultipartFile photo :photos) {
                String originalFilename = photo.getOriginalFilename();
                System.out.println(originalFilename);
                photo.transferTo(new File("E:\\temp_upload\\" + originalFilename));
            }
        }



        return "注册用户成功/文件上传成功";
    }
}

运行测试:http://localhost:8080/upload.html


3.2 第二种方式:动态创建方式

动态创建方式: 以项目作为根路径创建目录,存放文件。这种方式兼容性更好,没有盘符之说。可移植性更好。

动态创建的核心,就是获取到项目的根路径,从而以项目的根路径,作为参照/相对路径,从而创建存放上传文件的目录。

java 复制代码
package com.rainbowsea.springboot.controller;


import com.rainbowsea.springboot.utils.WebUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Slf4j
@Controller  // 控制器
public class UploadController {

    // 处理转发到用户注册~可以完成文件上传页面
    @GetMapping("/upload.html")
    public String uploadPage() {

        return "upload";  // 视图解析,pom_>jar,转发到templates/upload.html
        // 注意如果配置了拦截器,资源的上传 upload.html页面也是要放行的
    }


    // 处理用户的注册请求-包括处理文件上传
    // 动态创建方式:以项目作为根路径创建目录,存放文件
    // springboot-fileUpload/src/main/resources/static/images
    @PostMapping("/upload")
    @ResponseBody
    public String upload(
            // 自动封装
            String name,
            String email,
            Integer age,
            String job,
            @RequestParam("header") MultipartFile header,
            @RequestParam("photos") MultipartFile[] photos
    ) throws IOException {
        log.info("上传的信息 name={},email={} age = {} job={} ", name, email, age, job);
        log.info("header={}", header);
        log.info("photos={}", photos);


        String path = ResourceUtils.getURL("classpath:").getPath();
        System.out.println("path:" + path);  // 获取到的是这个项目的根路径(类路径)全的。

        // 定义好,我们要在项目中的什么位置存放传过来的文件
        //File file = new File(path + "static/images");

        File file = new File(WebUtils.getUploadFileDirectory());
        // 动态创建指定目录
        if (!file.exists()) { // 如果目录不存在,我们就创建
            file.mkdirs();
        }

        // 首先处理头像的文件,因为只有一张图片
        if (!header.isEmpty()) {  // 处理头像
            String originalFilename = header.getOriginalFilename();  // 获取的文件的名字
            System.out.println(file.getAbsolutePath());  // 获取到文件的绝对路径
            String fileName = UUID.randomUUID().toString() + "_"+ System.currentTimeMillis()+"_"+originalFilename;
            System.out.println(fileName);
            header.transferTo(new File(file.getAbsolutePath() + "/" + fileName));
        }

        // 处理宠物的图片
        if (photos.length > 0) {
            for (MultipartFile photo : photos) {
                String originalFilename = photo.getOriginalFilename();
                System.out.println(file.getAbsolutePath());  // 获取到文件的绝对路径
                String fileName = UUID.randomUUID().toString() + "_"+ System.currentTimeMillis()+"_"+originalFilename;
                // 保存到动态创建的目录
                photo.transferTo(new File(file.getAbsolutePath() + "/" + fileName ));
            }
        }


        return "注册用户成功/文件上传成功";
    }
}

4. 上传文件的注意事项

  1. Spring Boot 的文件上传: 注意如果配置了拦截器,资源的上传 upload.html页面也是要放行的,不然会上传失败。
  2. 注意:在Spring Boot 当中:默认单个文件最大1MB,一次上传多个文件最大10MB,我们可以修改
    MultipartProperties类当中的属性,我们可以通过在 resources类路径下,application.yaml 进行修改
yaml 复制代码
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 50MB
  1. 解决文件覆盖问题,如果文件名相同,会出现覆盖问题,如何解决。------> 在原本上传的文件的文件名后面+加上+时间戳+哈希值,就避免了文件名的重复了,每个文件都是唯一的了。同时使用 "_" 分割,用于后续,想要获取到真正的文件名,作准备
  1. 解决文件分目录存放问题,如果将文件都上传到一个目录下,当上传文件很多时,会造成文件速度变慢,因此,可以将文件上传到不同目录,比如一天上传的文件,统一放到一个文件夹 年/月/日,比如 2022/11/11目录.

这里我们创建一个工具类,来解决,返回一个以系统的年月日作为目录的字符串。

java 复制代码
package com.rainbowsea.springboot.utils;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.SimpleTimeZone;

public class WebUtils {
    private WebUtils() {
    }

    public static String getYearMonthDay() {
        // 如何得到当前的日期-》Java基础 日期,三代类
        LocalDateTime localDateTime = LocalDateTime.now();
        int year = localDateTime.getYear();
        int monthValue = localDateTime.getMonthValue();
        int dayOfMonth = localDateTime.getDayOfMonth();
        String yearMonthDay = year + "-" + monthValue + "-" + dayOfMonth;

        return yearMonthDay;
    }


    /**
     * 以年月日创建目录
     * 返回一个年月日为格式的目录的字符串
     * @return 返回一个年月日为格式的目录的字符串
     */
    public static String getUploadFileDirectory() {
        // 返回一个年月日为格式的目录的字符串
        return "static/images/" + new SimpleDateFormat("yyyy/MM/dd").format(new Date());
    }

    // 测试一下
    public static void main(String[] args) {
        System.out.println(WebUtils.getYearMonthDay());
        System.out.println(getUploadFileDirectory());
    }
}

运行测试:

5. 最后:

"在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。"

相关推荐
黑胡子大叔的小屋12 分钟前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark14 分钟前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
星就前端叭43 分钟前
【开源】一款基于Vue3 + WebRTC + Node + SRS + FFmpeg搭建的直播间项目
前端·后端·开源·webrtc
计算机毕设孵化场1 小时前
计算机毕设-基于springboot的校园社交平台的设计与实现(附源码+lw+ppt+开题报告)
spring boot·课程设计·计算机毕设论文·计算机毕设ppt·计算机毕业设计选题推荐·计算机选题推荐·校园社交平台
雷神乐乐1 小时前
Spring学习(一)——Sping-XML
java·学习·spring
苹果醋31 小时前
Golang的文件加密工具
运维·vue.js·spring boot·nginx·课程设计
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
AI理性派思考者2 小时前
【保姆教程】手把手教你在Linux系统搭建早期alpha项目cysic的验证者&证明者
后端·github·gpu
V+zmm101342 小时前
基于小程序宿舍报修系统的设计与实现ssm+论文源码调试讲解
java·小程序·毕业设计·mvc·ssm
从善若水2 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust