Springboot 项目中实现文件上传(封装成上传工具模块)

Springboot 项目中实现文件上传(封装成上传工具模块)

背景介绍

1、文件上传并非是直接把本地文件传输到服务器上,而是在接收到前端传来的文件流后,我们首先在服务器上创建了一个相同类型的文件,并以接收到的文件数据去填充它,从而实现了文件上传。

2、在服务器中我们需要有专门的存放路径,用于存放文件,如果没有该文件路径,首先的先创建好对应的文件路径,下面我会做一一介绍。

3、在服务器中存放的文件名称是不允许重复的,不然多次上传同一个文件有可能会覆盖掉原来的文件,这不是我们想要的结果。所以我们采用了UUID这个工具类来生成唯一的文件名称。保证了文件名称的不重复

通过进行封装的方式实现上传文件:一次配置,永久使用

接下来开始逐一讲解并实际应用

一、引入controller层

我们需要提供一个上传的接口,需要在controller当中提供

package tech.niua.common.controller;


import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import tech.niua.common.config.NiuaConfig;
import tech.niua.common.config.ServerConfig;
import tech.niua.common.model.ResultCode;
import tech.niua.common.model.ResultJson;
import tech.niua.common.utils.file.FileUploadUtils;
import tech.niua.core.annotation.ApiVersion;

import java.util.HashMap;
import java.util.Map;

/**
 * @author
 * @title: UploadController
 * @projectName niua_easy_parent
 * @description: 通用文件上传类
 * @date
 */
@RestController
@Api(value = "通用接口", tags = {"通用接口"})
@ApiVersion(1)
@RequestMapping("/{version}/admin/common")
public class CommonController {

    @Autowired
    private ServerConfig serverConfig;


    /**
     * 通用上传请求
     */
    @PostMapping("/upload")
    public ResultJson uploadFile(MultipartFile file) throws Exception {
        try {
            // 上传文件路径
            String filePath = NiuaConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            String url = serverConfig.getUrl() + fileName;

            Map<String, String> prams = new HashMap<String, String>();
            prams.put("fileName", fileName);
            prams.put("url", url);
            return ResultJson.ok(prams);
        } catch (Exception e) {
            return ResultJson.failure(ResultCode.BAD_REQUEST, e.getMessage());
        }
    }
}

二、引入工具类

开始逐一讲解

1、先获取到文件要存放的根目录

// 上传文件路径
String filePath = NiuaConfig.getUploadPath();

这里是获取到我们设置的文件存放到系统的一个根目录信息

(如果是部署到linux系统上文件根目录得从/开始,例:/usr/local/uploadPath)

    public static String getUploadPath()
    {
        //例   profile: D:\\PracticalTraining\\gqj\\uploadPath\\
        return getProfile() + "upload";
    }

2、上传文件返回新文件名称

// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);

引入FileUploadUtils工具类

package tech.niua.common.utils.file;

import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import tech.niua.common.config.NiuaConfig;
import tech.niua.common.constant.Constants;
import tech.niua.common.exception.file.FileNameLengthLimitExceededException;
import tech.niua.common.exception.file.FileSizeLimitExceededException;
import tech.niua.common.exception.file.InvalidExtensionException;
import tech.niua.common.utils.DateUtils;
import tech.niua.common.utils.StringUtils;
import tech.niua.common.utils.uuid.IdUtils;

/**
 * @author wangzhen
 * @title: FileUploadUtils
 * @projectName niua_easy_parent
 * @description: 文件上传工具
 * @date 2020/12/19 下午9:49
 */
public class FileUploadUtils {
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认的文件名最大长度 100
     */
    public static final int DEFAULT_FILE_NAME_LENGTH = 100;

    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = NiuaConfig.getProfile();

    public static void setDefaultBaseDir(String defaultBaseDir)
    {
        FileUploadUtils.defaultBaseDir = defaultBaseDir;
    }

    public static String getDefaultBaseDir()
    {
        return defaultBaseDir;
    }

    /**
     * 以默认配置进行文件上传
     *
     * @param file 上传的文件
     * @return 文件名称
     * @throws Exception
     */
    public static final String upload(MultipartFile file) throws IOException
    {
        try
        {
            return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 根据文件路径上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @return 文件名称
     * @throws IOException
     */
    public static final String upload(String baseDir, MultipartFile file) throws IOException
    {
        try
        {
            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
        }
        catch (Exception e)
        {
            throw new IOException(e.getMessage(), e);
        }
    }

    /**
     * 文件上传
     *
     * @param baseDir 相对应用的基目录
     * @param file 上传的文件
     * @param allowedExtension 上传文件类型
     * @return 返回上传成功的文件名
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws FileNameLengthLimitExceededException 文件名太长
     * @throws IOException 比如读写文件出错时
     * @throws InvalidExtensionException 文件校验异常
     */
    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
            InvalidExtensionException
    {
        int fileNamelength = file.getOriginalFilename().length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
        {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }
        //文件大小校验
        assertAllowed(file, allowedExtension);

        String fileName = extractFilename(file);

        File desc = getAbsoluteFile(baseDir, fileName);
        file.transferTo(desc);
        String pathFileName = getPathFileName(baseDir, fileName);
        return pathFileName;
    }

    /**
     * 编码文件名
     */
    public static final String extractFilename(MultipartFile file)
    {
        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
        return fileName;
    }

    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
    {
        File desc = new File(uploadDir + File.separator + fileName);

        if (!desc.getParentFile().exists())
        {
            desc.getParentFile().mkdirs();
        }
        if (!desc.exists())
        {
            desc.createNewFile();
        }
        return desc;
    }

    private static final String getPathFileName(String uploadDir, String fileName) throws IOException
    {
        int dirLastIndex = NiuaConfig.getProfile().length();
        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
        String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
        return pathFileName;
    }

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        long size = file.getSize();
        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
        {
            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
        }

        String fileName = file.getOriginalFilename();
        String extension = getExtension(file);
        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
        {
            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
                        fileName);
            }
            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
                        fileName);
            }
            else
            {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
        }

    }

    /**
     * 判断MIME类型是否是允许的MIME类型
     *
     * @param extension
     * @param allowedExtension
     * @return
     */
    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
    {
        for (String str : allowedExtension)
        {
            if (str.equalsIgnoreCase(extension))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    public static final String getExtension(MultipartFile file)
    {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension))
        {
            extension = MimeTypeUtils.getExtension(file.getContentType());
        }
        return extension;
    }
}

使用讲解:

(1)我们用到了FileUploadUtils这个工具类,这里我们会做文件大小的校验,如果文件太大,则不允许上传

Springboot 项目中实现文件上传(封装成上传工具模块)_第1张图片

(2)UUID的使用,获取到一个新的唯一的文件名称
String fileName = extractFilename(file);

我们使用IdUtils这个ID生成器工具类,然后通过UUID提供通用唯一识别码(universally unique identifier)(UUID)实现

public static String fastUUID()
{
    return UUID.fastUUID().toString();
}

引入:IdUtils工具类

package tech.niua.common.utils.uuid;

/**
 * @author wangzhen
 * @title: IdUtils
 * @projectName niua_easy_parent
 * @description: ID生成器工具类
 * @date 2020/12/19 下午10:41
 */
public class IdUtils {
    /**
     * 获取随机UUID
     *
     * @return 随机UUID
     */
    public static String randomUUID()
    {
        return UUID.randomUUID().toString();
    }

    /**
     * 简化的UUID,去掉了横线
     *
     * @return 简化的UUID,去掉了横线
     */
    public static String simpleUUID()
    {
        return UUID.randomUUID().toString(true);
    }

    /**
     * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
     *
     * @return 随机UUID
     */
    public static String fastUUID()
    {
        return UUID.fastUUID().toString();
    }

    /**
     * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
     *
     * @return 简化的UUID,去掉了横线
     */
    public static String fastSimpleUUID()
    {
        return UUID.fastUUID().toString(true);
    }
}

引入:UUID

package tech.niua.common.utils.uuid;

import tech.niua.common.exception.UtilException;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author 
 * @title: UUID
 * @projectName niua_easy_parent
 * @description: 提供通用唯一识别码(universally unique identifier)(UUID)实现
 * @date 
 */
public class UUID implements java.io.Serializable, Comparable<UUID>{
    private static final long serialVersionUID = -1185015143654744140L;

    /**
     * SecureRandom 的单例
     *
     */
    private static class Holder
    {
        static final SecureRandom numberGenerator = getSecureRandom();
    }

    /** 此UUID的最高64有效位 */
    private final long mostSigBits;

    /** 此UUID的最低64有效位 */
    private final long leastSigBits;

    /**
     * 私有构造
     *
     * @param data 数据
     */
    private UUID(byte[] data)
    {
        long msb = 0;
        long lsb = 0;
        assert data.length == 16 : "data must be 16 bytes in length";
        for (int i = 0; i < 8; i++)
        {
            msb = (msb << 8) | (data[i] & 0xff);
        }
        for (int i = 8; i < 16; i++)
        {
            lsb = (lsb << 8) | (data[i] & 0xff);
        }
        this.mostSigBits = msb;
        this.leastSigBits = lsb;
    }

    /**
     * 使用指定的数据构造新的 UUID。
     *
     * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
     * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
     */
    public UUID(long mostSigBits, long leastSigBits)
    {
        this.mostSigBits = mostSigBits;
        this.leastSigBits = leastSigBits;
    }

    /**
     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
     *
     * @return 随机生成的 {@code UUID}
     */
    public static UUID fastUUID()
    {
        return randomUUID(false);
    }

    /**
     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
     *
     * @return 随机生成的 {@code UUID}
     */
    public static UUID randomUUID()
    {
        return randomUUID(true);
    }

    /**
     * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
     *
     * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
     * @return 随机生成的 {@code UUID}
     */
    public static UUID randomUUID(boolean isSecure)
    {
        final Random ng = isSecure ? Holder.numberGenerator : getRandom();

        byte[] randomBytes = new byte[16];
        ng.nextBytes(randomBytes);
        randomBytes[6] &= 0x0f; /* clear version */
        randomBytes[6] |= 0x40; /* set to version 4 */
        randomBytes[8] &= 0x3f; /* clear variant */
        randomBytes[8] |= 0x80; /* set to IETF variant */
        return new UUID(randomBytes);
    }

    /**
     * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
     *
     * @param name 用于构造 UUID 的字节数组。
     *
     * @return 根据指定数组生成的 {@code UUID}
     */
    public static UUID nameUUIDFromBytes(byte[] name)
    {
        MessageDigest md;
        try
        {
            md = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException nsae)
        {
            throw new InternalError("MD5 not supported");
        }
        byte[] md5Bytes = md.digest(name);
        md5Bytes[6] &= 0x0f; /* clear version */
        md5Bytes[6] |= 0x30; /* set to version 3 */
        md5Bytes[8] &= 0x3f; /* clear variant */
        md5Bytes[8] |= 0x80; /* set to IETF variant */
        return new UUID(md5Bytes);
    }

    /**
     * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
     *
     * @param name 指定 {@code UUID} 字符串
     * @return 具有指定值的 {@code UUID}
     * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
     *
     */
    public static UUID fromString(String name)
    {
        String[] components = name.split("-");
        if (components.length != 5)
        {
            throw new IllegalArgumentException("Invalid UUID string: " + name);
        }
        for (int i = 0; i < 5; i++)
        {
            components[i] = "0x" + components[i];
        }

        long mostSigBits = Long.decode(components[0]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[1]).longValue();
        mostSigBits <<= 16;
        mostSigBits |= Long.decode(components[2]).longValue();

        long leastSigBits = Long.decode(components[3]).longValue();
        leastSigBits <<= 48;
        leastSigBits |= Long.decode(components[4]).longValue();

        return new UUID(mostSigBits, leastSigBits);
    }

    /**
     * 返回此 UUID 的 128 位值中的最低有效 64 位。
     *
     * @return 此 UUID 的 128 位值中的最低有效 64 位。
     */
    public long getLeastSignificantBits()
    {
        return leastSigBits;
    }

    /**
     * 返回此 UUID 的 128 位值中的最高有效 64 位。
     *
     * @return 此 UUID 的 128 位值中最高有效 64 位。
     */
    public long getMostSignificantBits()
    {
        return mostSigBits;
    }

    /**
     * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
     * 

* 版本号具有以下含意: *

    *
  • 1 基于时间的 UUID *
  • 2 DCE 安全 UUID *
  • 3 基于名称的 UUID *
  • 4 随机生成的 UUID *
* * @return 此 {@code UUID} 的版本号 */
public int version() { // Version is bits masked by 0x000000000000F000 in MS long return (int) ((mostSigBits >> 12) & 0x0f); } /** * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 *

* 变体号具有以下含意: *

    *
  • 0 为 NCS 向后兼容保留 *
  • 2 IETF RFC 4122(Leach-Salz), 用于此类 *
  • 6 保留,微软向后兼容 *
  • 7 保留供以后定义使用 *
* * @return 此 {@code UUID} 相关联的变体号 */
public int variant() { // This field is composed of a varying number of bits. // 0 - - Reserved for NCS backward compatibility // 1 0 - The IETF aka Leach-Salz variant (used by this class) // 1 1 0 Reserved, Microsoft backward compatibility // 1 1 1 Reserved for future definition. return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); } /** * 与此 UUID 相关联的时间戳值。 * *

* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。
* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 * *

* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。
* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 * * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 */ public long timestamp() throws UnsupportedOperationException { checkTimeBase(); return (mostSigBits & 0x0FFFL) << 48// | ((mostSigBits >> 16) & 0x0FFFFL) << 32// | mostSigBits >>> 32; } /** * 与此 UUID 相关联的时钟序列值。 * *

* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 *

* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 * UnsupportedOperationException。 * * @return 此 {@code UUID} 的时钟序列 * * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 */ public int clockSequence() throws UnsupportedOperationException { checkTimeBase(); return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); } /** * 与此 UUID 相关的节点值。 * *

* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 *

* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。
* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 * * @return 此 {@code UUID} 的节点值 * * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 */ public long node() throws UnsupportedOperationException { checkTimeBase(); return leastSigBits & 0x0000FFFFFFFFFFFFL; } /** * 返回此{@code UUID} 的字符串表现形式。 * *

* UUID 的字符串表示形式由此 BNF 描述: * *

     * {@code
     * UUID                   = ----
     * time_low               = 4*
     * time_mid               = 2*
     * time_high_and_version  = 2*
     * variant_and_sequence   = 2*
     * node                   = 6*
     * hexOctet               = 
     * hexDigit               = [0-9a-fA-F]
     * }
     * 
* * * * @return 此{@code UUID} 的字符串表现形式 * @see #toString(boolean) */
@Override public String toString() { return toString(false); } /** * 返回此{@code UUID} 的字符串表现形式。 * *

* UUID 的字符串表示形式由此 BNF 描述: * *

     * {@code
     * UUID                   = ----
     * time_low               = 4*
     * time_mid               = 2*
     * time_high_and_version  = 2*
     * variant_and_sequence   = 2*
     * node                   = 6*
     * hexOctet               = 
     * hexDigit               = [0-9a-fA-F]
     * }
     * 
* * * * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 * @return 此{@code UUID} 的字符串表现形式 */
public String toString(boolean isSimple) { final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); // time_low builder.append(digits(mostSigBits >> 32, 8)); if (false == isSimple) { builder.append('-'); } // time_mid builder.append(digits(mostSigBits >> 16, 4)); if (false == isSimple) { builder.append('-'); } // time_high_and_version builder.append(digits(mostSigBits, 4)); if (false == isSimple) { builder.append('-'); } // variant_and_sequence builder.append(digits(leastSigBits >> 48, 4)); if (false == isSimple) { builder.append('-'); } // node builder.append(digits(leastSigBits, 12)); return builder.toString(); } /** * 返回此 UUID 的哈希码。 * * @return UUID 的哈希码值。 */ @Override public int hashCode() { long hilo = mostSigBits ^ leastSigBits; return ((int) (hilo >> 32)) ^ (int) hilo; } /** * 将此对象与指定对象比较。 *

* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 * * @param obj 要与之比较的对象 * * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} */ @Override public boolean equals(Object obj) { if ((null == obj) || (obj.getClass() != UUID.class)) { return false; } UUID id = (UUID) obj; return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); } // Comparison Operations /** * 将此 UUID 与指定的 UUID 比较。 * *

* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 * * @param val 与此 UUID 比较的 UUID * * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 * */ @Override public int compareTo(UUID val) { // The ordering is intentionally set up so that the UUIDs // can simply be numerically compared as two numbers return (this.mostSigBits < val.mostSigBits ? -1 : // (this.mostSigBits > val.mostSigBits ? 1 : // (this.leastSigBits < val.leastSigBits ? -1 : // (this.leastSigBits > val.leastSigBits ? 1 : // 0)))); } // Private method start /** * 返回指定数字对应的hex值 * * @param val 值 * @param digits 位 * @return 值 */ private static String digits(long val, int digits) { long hi = 1L << (digits * 4); return Long.toHexString(hi | (val & (hi - 1))).substring(1); } /** * 检查是否为time-based版本UUID */ private void checkTimeBase() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } } /** * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) * * @return {@link SecureRandom} */ public static SecureRandom getSecureRandom() { try { return SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { throw new UtilException(e); } } /** * 获取随机数生成器对象
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 * * @return {@link ThreadLocalRandom} */
public static ThreadLocalRandom getRandom() { return ThreadLocalRandom.current(); } }

3、文件上传完成后会获取到一个新的可以访问这个文件的url

String url = serverConfig.getUrl() + fileName;

获取请求的serverConfig配置类

package tech.niua.common.config;

import org.springframework.stereotype.Component;
import tech.niua.common.utils.ServletUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * @author 
 * @title: ServerConfig
 * @projectName niua_easy_parent
 * @description: 服务相关配置
 * @date 
 */
@Component
public class ServerConfig
{
    /**
     * 获取完整的请求路径,包括:域名,端口,上下文访问路径
     *
     * @return 服务地址
     */
    public String getUrl()
    {
        HttpServletRequest request = ServletUtils.getRequest();
        return getDomain(request);
    }

    public static String getDomain(HttpServletRequest request)
    {
        StringBuffer url = request.getRequestURL();
        String contextPath = request.getServletContext().getContextPath();
        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
    }
}

此时前端上传文件后就能够获取到新的文件名称已经访问下载该文件的get请求url

Springboot 项目中实现文件上传(封装成上传工具模块)_第2张图片

4、实体层状态码以及返回json类型实体层配置

ResultCode.java

package tech.niua.common.model;

/**
 * @author Wangzhen
 * 状态码
 * createAt: 2020/5/29
 */
public enum ResultCode {
    /*
    请求返回状态码和说明信息
     */
    SUCCESS(200, "成功"),

    BAD_REQUEST(400, "参数或者语法不对"),
    UNAUTHORIZED(401, "认证失败"),
    LOGIN_ERROR(402, "登录失败,用户名或密码无效"),
    FORBIDDEN(403, "禁止访问"),
    NOT_FOUND(404, "请求的资源不存在"),
    OPERATE_ERROR(405, "操作失败,请求操作的资源不存在"),
    TIME_OUT(408, "请求超时"),

    SERVER_ERROR(500, "服务器内部错误"),

    GENERATOR_FAILURE(501,"生成失败"),

    CHILD_DATA_EXIST(20001, "数据中包含子数据"),
    ROLE_LOAD_RESOURCES(20002, "资源已经使用,请在角色管理中解绑后,在操作"),
    DATA_EXIST(20003, "数据已经存在"),
    NOT_UPDATE(20004, "数据没有更新"),
    REPEAT_SUBMIT(20005, "数据提交重复,请勿重复操作"),
    INSERT_URL(20006, ""),
;
    private int code;
    private String msg;

    ResultCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

}

ResultJson.java

package tech.niua.common.model;

import lombok.Data;

import java.io.Serializable;

/**
 * @author Wangzhen
 * RESTful API 返回类型
 * createAt: 2020/5/29
 */
@Data
public class ResultJson<T> implements Serializable{

    private static final long serialVersionUID = 783015033603078674L;
    private int code;
    private String msg;
    private T data;

    public static ResultJson ok() {
        return ok("");
    }

    public static ResultJson ok(Object o) {
        return new ResultJson(ResultCode.SUCCESS, o);
    }

    public static ResultJson failure(ResultCode code) {
        return failure(code, "");
    }

    public static ResultJson failure(ResultCode code, Object o) {
        return new ResultJson(code, o);
    }

    public ResultJson(ResultCode resultCode) {
        setResultCode(resultCode);
    }

    public ResultJson(ResultCode resultCode, T data) {
        setResultCode(resultCode);
        this.data = data;
    }

    public void setResultCode(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }

    @Override
    public String toString() {
        return "{" +
                "\"code\":" + code +
                ", \"msg\":\"" + msg + '\"' +
                ", \"data\":\"" + data + '\"'+
                '}';
    }
}

三、整体配置分配

Springboot 项目中实现文件上传(封装成上传工具模块)_第3张图片

总结:配置过程使用了大量的工具类,我们配置花费大量的时间,但是配置成封装好的一个上传工具对于以后的时候可以节省大量的时间,也方便扩展。

你可能感兴趣的:(spring,boot,java,spring)