Spring Boot 简单的文件上传

Spring Boot 文件上传

环境

IDE:IntelliJ IDEA 2019.2.4 (Ultimate Edition)

操作系统:Windows 10 x64

Spring Boot 版本:2.2.2.RELEASE

JDK:1.8

示例

注意:以下示例只是将接收到文件重命名,然后存储到指定的位置,并没有执行其他操作。
项目结构:
项目结构
pom.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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mk</groupId>
    <artifactId>spring-boot-upload</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-upload</name>
    <description>文件上传</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <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>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml 文件:

spring:
  servlet:
    # 参考:org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
    # 参考:https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.html
    multipart:
      enabled: true
      # 指定每个上传的文件的最大值
      max-file-size: 100MB # specifies the maximum size permitted for uploaded files. The default is 1MB
      # 指定一个请求中所有上传的文件的总最大值
      max-request-size: 100MB # specifies the maximum size allowed for multipart/form-data requests. The default is 10MB.
#      file-size-threshold: # specifies the size threshold after which files will be written to disk. The default is 0.
      # 临时存储目录
      location: G:/20191212 # specifies the directory where uploaded files will be stored. When not specified, a temporary directory will be used.

server:
  port: 8086

templates/index.html 文件,即上传页面,主要是第 8 ~ 12 行:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
    <form action="/attachment/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <br />
        <input type="submit" value="upload" />
    </form>
</body>
</html>

com.mk.util.RandomUtils 随机工具类:
注意:该类中有些方法的逻辑并不严谨,请谨慎使用。

package com.mk.util;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

public class RandomUtils {
    private static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    private static Random random = new Random();
    
    /**
     * <p> 返回一个伪随机数,在最小值(包括)和最大值(不包括)之间均匀分布的整数值,该整数值来自这个随机数生成器的序列。
     * @param min 最小值
     * @param max 最大值
     * @return 返回一个伪随机数,在最小值(包括)和最大值(不包括)之间均匀分布的整数值。
     */
    public static int nextInt(int min, int max) {
        return (random.nextInt(max - min) + min);
    }
    
    /**
     * <p> 返回一个在最小值(包括)和最大值(不包括)之间均匀分布的伪随机整数值的字符串形式。
     * @param min 最小值
     * @param max 最大值
     * @return 返回一个在最小值(包括)和最大值(不包括)之间均匀分布的伪随机整数值的字符串形式。
     */
    public static String nextIntToString(int min, int max) {
        return "" + nextInt(min, max);
    }
    
    /**
     * <p> 获取文件的类型名称,即扩展名。
     * <p> 示例:
     * <p> 执行 <code>RandomUtils.getTypeName("file.txt", true);</code>,返回 <code>".txt"</code>
     * <p> 执行 <code>RandomUtils.getTypeName("file.txt", false);</code>,返回 <code>"txt"</code>
     * @param filename 文件名称
     * @param dot 是否保留类型名称前面的点(.),<code>true</code> 保留,<code>false</code> 去除。
     * @return 如果存在,返回文件类型名称。否则返回 <code>null</code>
     */
    public static String getTypeName(String filename, boolean dot) {
        if ((filename == null) || (filename.equals(""))) {
            return null;
        }
        
        int lastOccurrence = filename.lastIndexOf(".");
        if (lastOccurrence != -1) {
            lastOccurrence = (dot == true) ? lastOccurrence : (lastOccurrence + 1);
            String typeName = filename.substring(lastOccurrence);
            return typeName;
        }
        
        return null; // 该文件不存在类型名称
    }
    
    /**
     * <p> 使用当前日期 + 四位随机数作为文件名
     * @param originalFilename 原文件名,此处需要原文件的后缀名(即文件的类型)
     * @return
     */
    public static String createRandomFilenameByDate(String originalFilename) {
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String filename = df.format(new Date()) + (random.nextInt(9000) + 1000) + extension;
        return filename;
    }

    /**
     * 
     * @param originalFilename
     * @param suffix 临时文件的后缀名
     * @return
     */
    public static String createRandomFilenameByDate(String originalFilename, String suffix) {
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String filename = df.format(new Date()) + (random.nextInt(9000) + 1000) + extension;
        return filename + suffix;
    }
    
    /**
     * <p> 使用 UUID 作为文件名
     * @param originalFilename
     * @return
     */
    public static String createRandomFilenameByUUID(String originalFilename) {
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String filename = uuid + extension;
        return filename;
    }
    
    /**
     * <p> 使用当前系统毫秒数 + 四位随机数作为文件名
     * @param originalFilename
     * @return
     */
    public static String createRandomFilenameByTimeMillis(String originalFilename) {
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        long t = System.currentTimeMillis();
        String filename = "" + t + (random.nextInt(9000) + 1000) + extension;
        return filename;
    }
    
    /**
     * <p> 以 yyyy-MM-dd 格式返回当前日期的字符串
     * @return
     */
    public static String createDirectoryNameByDate() {
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    }
    
    /**
     * <p> 按照指定的日期格式,返回一个指定的日期的字符串。如果没有指定日期格式,则使用 "yyyy-MM-dd" 做为默认的日期格式。
     * <p> 请使用 <code>com.mk.commons.util.RandomUtils.createDateFormatStringWith(String, Date)</code> 代替。
     * @param dateFormat 日期格式。例如:"yyyy-MM-dd"
     * @param date 日期。如果日期为 null,则使用当前时间。
     * @return 按照指定的日期格式,返回一个指定的日期的字符串。
     */
    @Deprecated
    public static String createStringBy(String dateFormat, Date date) {
        dateFormat = ((dateFormat == null) || (dateFormat.equals(""))) ? "yyyy-MM-dd" : dateFormat;
        date = (date == null)?(new Date()):date;
        return new SimpleDateFormat(dateFormat).format(date);
    }
    

    /**
     * <p> 按照指定的日期格式,返回一个指定的日期的字符串。如果没有指定日期格式,则使用 "yyyy-MM-dd" 做为默认的日期格式。
     * <p> 具体的日期格式参见:{@link SimpleDateFormat}
     * <p> 注意:不要输入非法的日期格式,因为本方法没有对日期格式进行校验。
     * @param dateFormat 日期格式。如果 dateFormat 为 null 或为空字符串,则使用 "yyyy-MM-dd" 做为默认值。
     * @param date 日期。如果日期为 null,则使用当前时间。
     * @return 按照指定的日期格式,返回一个指定的日期的字符串。
     */
    public static String createDateFormatStringWith(String dateFormat, Date date) {
        dateFormat = ((dateFormat == null) || (dateFormat.equals(""))) ? "yyyy-MM-dd" : dateFormat;
        date = (date == null) ? (new Date()) : date;
        return new SimpleDateFormat(dateFormat).format(date);
    }

    /**
     * <p> 按照指定的日期格式,返回一个附有前缀和后缀的指定的日期的字符串。如果没有指定日期格式,则使用 "yyyy-MM-dd" 做为默认的日期格式。
     * @param prefix 前缀
     * @param dateFormat 日期格式。例如:"yyyy-MM-dd"
     * @param date 日期。如果日期为 null,则使用当前时间。
     * @param suffix 后缀
     * @return 按照指定的日期格式,返回一个附有前缀和后缀的指定的日期的字符串。
     */
    public static String createDateFormatStringWith(String prefix, String dateFormat, Date date, String suffix) {
        prefix = (prefix == null)?"":prefix;
        suffix = (suffix == null)?"":suffix;
        dateFormat = (dateFormat == null)?"yyyy-MM-dd":dateFormat;
        date = (date == null)?(new Date()):date;
        return prefix + (new SimpleDateFormat(dateFormat).format(date)) + suffix;
    }
}

com.mk.controller.IndexController 导航控制器,用于导航到 templates/index.html 页面,见第 12 ~ 15 行:

package com.mk.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * <p>导航控制器</p>
 */
@Controller
public class IndexController {

    @GetMapping(value = {"/"})
    public String index() {
        return "index"; // 跳转到 templates/index.html 页面
    }
}

com.mk.controller.AttachmentController 附件控制器,用于处理上传文件,这里只是将接收到文件重命名,然后存储到指定的位置。

package com.mk.controller;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.mk.util.RandomUtils;

@RestController
@RequestMapping("/attachment")
public class AttachmentController {
    
    @PostMapping("/upload")
    public Map<String, Object> upload(@RequestParam(value = "file") MultipartFile file) {
        Map<String, Object> data = new HashMap<String, Object>();
        
        if ((file != null) && (!file.isEmpty())) {
            // 原文件名
            String originalFilename = file.getOriginalFilename();
            // 构建文件的存储目录
            File directory = new File("G:", RandomUtils.createDateFormatStringWith("yyyyMMdd", new Date()));
            if (!directory.exists()) {
                directory.mkdirs(); // 创建不存在的目录
            }
            // 因为上传的文件可能出现同名,所以需要创建一个新文件名,防止出现同名文件被覆盖的情况。
            String newFilename = RandomUtils.createDateFormatStringWith("yyyyMMddHHmmssSSS", new Date()) // 当前日期的字符串形式
                    + RandomUtils.nextIntToString(1000, 10000) // 随机数,最小 1000,最大 9999
                    + RandomUtils.getTypeName(originalFilename, true); // 获取文件的类型
            // 保存上传的文件到指定的位置
            File destination = new File(directory, newFilename);
            try {
                file.transferTo(destination);
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // 检查文件是否保存成功
            if (destination.exists()) {
                data.put("location", destination.getAbsoluteFile());
                return data;
            }
        }
        return null;
    }
}

效果

在这里插入图片描述
在这里插入图片描述

发布了36 篇原创文章 · 获赞 0 · 访问量 1894

猜你喜欢

转载自blog.csdn.net/qq_29761395/article/details/103521185