分析若依的文件上传处理逻辑

news2024/12/23 18:31:18

分析若依的文件上传处理逻辑

在这里插入图片描述

注:已经从若依框架完成拆分,此处单独分析一下人家精彩的封装,也来理解一下怎么做一个通用的上传接口!如有分析的,理解的不透彻的地方,大家多多包含,欢迎批评指正,但是请不要恶语相向!

控制层代码剖析

    @PostMapping("/upload")
    public AjaxResult uploadFile(MultipartFile file){
        try {
            // 上传文件路径
            String filePath = RuoYiConfig.getUploadPath();
            // 上传并返回新文件名称
            String fileName = FileUploadUtils.upload(filePath, file);
            String url = serverConfig.getUrl() + fileName;
            AjaxResult ajax = AjaxResult.success();
            ajax.put("url", url);
            ajax.put("fileName", fileName);
            ajax.put("newFileName", FileUtils.getName(fileName));
            ajax.put("originalFilename", file.getOriginalFilename());
            return ajax;
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }
  1. @PostMapping("/upload"):这是一个用于处理HTTP POST请求的注解,它将请求映射到/upload路径。在这里,它用于处理文件上传请求。

  2. public AjaxResult uploadFile(MultipartFile file):这是处理文件上传的方法。它接收一个MultipartFile对象,这是Spring提供的用于处理文件上传的类。

  3. String filePath = RuoYiConfig.getUploadPath();:获取文件上传路径,通过RuoYiConfig.getUploadPath()方法获取,是从配置文件中读取的上传路径。

    server:
        port: 8888
    # 项目相关配置
    ruoyi:
        # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
        profile: ./
    
    
  4. String fileName = FileUploadUtils.upload(filePath, file);:调用FileUploadUtils.upload方法实现文件上传,该方法包含文件存储逻辑,根据传入的文件路径和MultipartFile对象,返回新的文件名。下一标题我们将会着重对于这个方法进行解析。

  5. String url = serverConfig.getUrl() + fileName;:构造文件的访问URL,是通过拼接服务器的URL和上传后的文件名得到的。

  6. AjaxResult ajax = AjaxResult.success();:创建一个成功的AjaxResult对象,用于封装返回给客户端的数据。

  7. ajax.put("url", url);:将文件的访问URL放入AjaxResult中,以便客户端获取上传后的文件的访问地址。

  8. ajax.put("fileName", fileName);:将上传后的文件名放入AjaxResult中。

  9. ajax.put("newFileName", FileUtils.getName(fileName));:将上传后的文件名去除路径的部分,只保留文件名放入AjaxResult中。

  10. ajax.put("originalFilename", file.getOriginalFilename());:将原始文件名放入AjaxResult中。

  11. return ajax;:返回封装了文件相关信息的AjaxResult对象,向客户端提供文件上传成功的响应。

  12. } catch (Exception e) { return AjaxResult.error(e.getMessage());}:捕获可能的异常,如果发生异常,返回一个包含异常信息的错误AjaxResult对象,向客户端提供文件上传失败的响应。

upload文件上传方法

点击方法跳进去之后我们可以看到如下代码

package com.it_wanghui_cn.file.utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;

import com.it_wanghui_cn.file.config.RuoYiConfig;
import com.it_wanghui_cn.file.constant.Constants;
import com.it_wanghui_cn.file.exception.FileNameLengthLimitExceededException;
import com.it_wanghui_cn.file.exception.FileSizeLimitExceededException;
import com.it_wanghui_cn.file.exception.InvalidExtensionException;
import com.it_wanghui_cn.file.utils.uuid.Seq;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;


/**
 * 文件上传工具类
 *
 * @author ruoyi
 */
public class FileUploadUtils
{
    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;

    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_APP_MAX_SIZE = 200 * 1024 * 1024;

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

    /**
     * 默认上传的地址
     */
    private static String defaultBaseDir = RuoYiConfig.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 = Objects.requireNonNull(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);

        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        file.transferTo(Paths.get(absPath));
        return getPathFileName(baseDir, fileName);
    }

    /**
     * 编码文件名
     */
    public static final String extractFilename(MultipartFile file)
    {
        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
    }

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

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

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

    /**
     * 文件大小校验
     *
     * @param file 上传的文件
     * @return
     * @throws FileSizeLimitExceededException 如果超出最大大小
     * @throws InvalidExtensionException
     */
    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
            throws FileSizeLimitExceededException, InvalidExtensionException
    {
        long size = file.getSize();
        String fileSuffix;
        if (null != file.getOriginalFilename() && file.getOriginalFilename().contains(".")) {
            fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
        }else {
            fileSuffix = null;
        }
        if ("apk".equals(fileSuffix) || "ipa".equals(fileSuffix)) {
            if (size > DEFAULT_APP_MAX_SIZE)
            {
                throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);
            }
        }else {
            if (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 if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
            {
                throw new InvalidExtensionException.InvalidVideoExtensionException(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(Objects.requireNonNull(file.getContentType()));
        }
        return extension;
    }
}

这是一个文件上传工具类,主要用于处理文件上传的相关逻辑。

  1. 常量定义:

    • DEFAULT_MAX_SIZE:默认文件大小限制为50MB。
    • DEFAULT_APP_MAX_SIZE:默认App文件大小限制为200MB。
    • DEFAULT_FILE_NAME_LENGTH:默认文件名最大长度为100字符。
    • defaultBaseDir:默认的文件上传基目录,初始化时可能从RuoYiConfig中获取。
  2. 上传文件方法:

    • upload(MultipartFile file):使用默认配置上传文件,调用upload(String baseDir, MultipartFile file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)

    • upload(String baseDir, MultipartFile file):根据给定的基目录上传文件,调用upload(String baseDir, MultipartFile file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION)

    • upload(String baseDir, MultipartFile file, String[] allowedExtension):文件上传的核心方法,包含文件大小、文件名长度和文件扩展名的校验逻辑。

          public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
                  throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
                  InvalidExtensionException
          {
              int fileNamelength = Objects.requireNonNull(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);
      
              String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
              file.transferTo(Paths.get(absPath));
              return getPathFileName(baseDir, fileName);
          }
      

      由于这段代码是文件上传的核心方法,我们对其进行细分析:

      1. 文件名长度检查:

        int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
        }
        
        • 获取上传文件的原始文件名,并检查其长度是否超过了设定的最大文件名长度(DEFAULT_FILE_NAME_LENGTH)。
        • 如果超过了限制,抛出FileNameLengthLimitExceededException异常。
      2. 文件扩展名和大小校验:

        assertAllowed(file, allowedExtension);
        
        • 调用assertAllowed方法,对文件的扩展名和大小进行校验。

        • 如果不符合要求,会抛出FileSizeLimitExceededExceptionInvalidExtensionException等异常。

          public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
                      throws FileSizeLimitExceededException, InvalidExtensionException
              {
                  long size = file.getSize();
                  String fileSuffix;
                  if (null != file.getOriginalFilename() && file.getOriginalFilename().contains(".")) {
                      fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
                  }else {
                      fileSuffix = null;
                  }
                  if ("apk".equals(fileSuffix) || "ipa".equals(fileSuffix)) {
                      if (size > DEFAULT_APP_MAX_SIZE)
                      {
                          throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);
                      }
                  }else {
                      if (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 if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
                      {
                          throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
                                  fileName);
                      }
                      else
                      {
                          throw new InvalidExtensionException(allowedExtension, extension, fileName);
                      }
                  }
              }
          

          这是文件上传工具类中的文件校验方法 assertAllowed,以下是对其进行细分析:

          1. 获取文件大小和扩展名:

            long size = file.getSize();
            String fileSuffix;
            if (null != file.getOriginalFilename() && file.getOriginalFilename().contains(".")) {
                fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1);
            } else {
                fileSuffix = null;
            }
            
            • 获取上传文件的大小和原始文件名中的扩展名。
          2. 文件大小校验:

            if ("apk".equals(fileSuffix) || "ipa".equals(fileSuffix)) {
                if (size > DEFAULT_APP_MAX_SIZE) {
                    throw new FileSizeLimitExceededException(DEFAULT_APP_MAX_SIZE / 1024 / 1024);
                }
            } else {
                if (size > DEFAULT_MAX_SIZE) {
                    throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
                }
            }
            
            • 根据文件扩展名(fileSuffix)判断文件类型,如果是apk或ipa文件,检查文件大小是否超过默认限制(DEFAULT_APP_MAX_SIZE),否则检查是否超过常规文件大小限制(DEFAULT_MAX_SIZE)。
            • 如果超过了大小限制,抛出 FileSizeLimitExceededException 异常。
          3. 文件扩展名校验:

            String fileName = file.getOriginalFilename();
            String extension = getExtension(file);
            if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
                // ...
            }
            
            • 获取上传文件的原始文件名和文件扩展名。
            • 如果 allowedExtension 不为空且文件扩展名不在允许的扩展名列表中,进入后续的异常判断逻辑。
          4. 根据文件类型抛出不同的异常:

            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 if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, fileName);
            } else {
                throw new InvalidExtensionException(allowedExtension, extension, fileName);
            }
            
            • 根据不同的文件类型,抛出对应的异常。例如,如果文件类型是图片,抛出 InvalidImageExtensionException 异常。

          所以,综上所述呢,assertAllowed 方法主要用于对文件的大小和扩展名进行校验,确保文件满足预定义的条件,否则抛出相应的异常。

      3. 生成文件名和绝对路径:

        String fileName = extractFilename(file);
        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
        
        • 调用extractFilename方法,根据上传文件生成编码后的文件名。
        • 调用getAbsoluteFile方法,获取文件的绝对路径。
      4. 文件写入磁盘:

        file.transferTo(Paths.get(absPath));
        
        • 使用transferTo方法将文件写入磁盘,具体路径由absPath决定。
      5. 返回文件相对路径:

        return getPathFileName(baseDir, fileName);
        
        • 调用getPathFileName方法,生成相对于上传基目录的文件路径。

      所以,综上所述呢,这段代码通过一系列步骤完成了文件上传的核心逻辑,包括文件名长度、扩展名、大小的校验,生成文件名,将文件写入磁盘,并返回相对路径。异常的处理确保了在上传过程中出现问题时能够向上层抛出相应的异常。

  3. 文件名处理:

    • extractFilename(MultipartFile file):根据上传文件生成编码后的文件名,包括日期路径、文件基名、Seq以及文件扩展名。
    public static final String extractFilename(MultipartFile file)
    {
        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
    }
    
    1. 构造文件名:

      StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
              FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
      
      • 使用字符串格式化工具(可能是自定义的StringUtils.format方法)构建文件名。这个文件名包括以下几个部分:
        • {}/:日期路径,可能是根据上传日期生成的目录结构。
        • {}_:原始文件名去除扩展名后的部分。
        • {}:通过某种方式获取的上传序列号或ID。
        • .:文件名的分隔符。
        • getExtension(file):获取文件的扩展名。
    2. 返回构造的文件名:

      return StringUtils.format(...);
      
      • 返回构造好的文件名。

    所以,综上所述呢,extractFilename 方法主要用于根据上传文件的信息构建一个新的文件名,其中包括日期路径、原始文件名的基本部分、上传序列号或ID,以及文件扩展名。这个文件名通常用于确定上传文件在服务器上的存储位置。

  4. 文件路径操作:

    • getAbsoluteFile(String uploadDir, String fileName):获取文件的绝对路径,并确保其父目录存在。

      public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
          {
              File desc = new File(uploadDir + File.separator + fileName);
      
              if (!desc.exists())
              {
                  if (!desc.getParentFile().exists())
                  {
                      desc.getParentFile().mkdirs();
                  }
              }
              return desc;
          }
      
      

      这就是文件上传工具类中的 getAbsoluteFile 方法,以下是对其进行细分析:

      1. 构造文件对象:

        File desc = new File(uploadDir + File.separator + fileName);
        
        • 创建一个 File 对象,表示上传目录 (uploadDir) 下的特定文件 (fileName)。
      2. 检查文件是否存在:

        if (!desc.exists()) {
            // ...
        }
        
        • 判断文件是否已经存在。如果文件不存在,执行后续的逻辑。
      3. 创建文件父目录:

        if (!desc.getParentFile().exists()) {
            desc.getParentFile().mkdirs();
        }
        
        • 如果文件的父目录不存在,调用 mkdirs() 方法创建父目录。这样可以确保文件存储路径的所有父目录都存在。
      4. 返回文件对象:

        return desc;
        
        • 返回表示上传文件的 File 对象。

      getAbsoluteFile 方法主要用于获取表示上传文件的 File 对象,并确保文件所在的目录结构是存在的。如果文件所在的目录不存在,会先创建这些目录。这样可以保证文件写入磁盘时,其所在的目录结构是正确的。

    • getPathFileName(String uploadDir, String fileName):根据上传目录和文件名构造相对路径,通常用于构造访问URL。

       public static final String getPathFileName(String uploadDir, String fileName) throws IOException
          {
              int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
              String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
              return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
          }
      
  5. 文件大小和扩展名校验:

    • assertAllowed(MultipartFile file, String[] allowedExtension):对上传的文件进行大小和扩展名的校验,根据文件扩展名调用isAllowedExtension方法判断是否允许上传。
    • isAllowedExtension(String extension, String[] allowedExtension):判断文件扩展名是否在允许的扩展名列表中。
  6. 其他方法:

    • getExtension(MultipartFile file):获取文件的扩展名,优先使用原始文件名的扩展名,如果为空,则使用文件的MIME类型来获取扩展名。

总体而言,该工具类提供了一系列方法,用于方便地进行文件上传,并包含了一些常见的文件校验逻辑。

transferTo方法再深入

    default void transferTo(Path dest) throws IOException, IllegalStateException {
        FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
    }

Files.newOutputStream(dest) 是 Java NIO(New I/O)库提供的一种方式,用于创建一个输出流(OutputStream)以写入文件。这方法返回一个输出流,你可以使用它来写入字节到指定的文件。

具体来说,Files.newOutputStream(dest) 的参数 dest 是一个 Path 对象,表示文件路径。下面是一些关键的点:

  1. 创建输出流:

    Path dest = ...; // 指定文件路径
    OutputStream outputStream = Files.newOutputStream(dest);
    
    • 使用 Files.newOutputStream(dest) 创建一个输出流。
  2. 写入数据:

    byte[] data = ...; // 准备写入的数据
    outputStream.write(data);
    
    • 利用得到的输出流,可以使用 write 方法将数据写入文件。
  3. 关闭流:

    outputStream.close();
    
    • 在数据写入完成后,确保调用 close 方法关闭输出流,以释放相关资源。

这个方法的主要优点是简洁且易用,不需要手动创建文件或处理一些底层的操作。它是 Java NIO 中用于文件写入的一部分,提供了更灵活和高性能的 I/O 操作。

看来还是千呼万唤始出来,犹抱琵琶半遮面,我们再进一层

    public static int copy(InputStream in, OutputStream out) throws IOException {
        Assert.notNull(in, "No InputStream specified");
        Assert.notNull(out, "No OutputStream specified");

        int var2;
        try {
            var2 = StreamUtils.copy(in, out);
        } finally {
            close(in);
            close(out);
        }

        return var2;
    }

这是一个用于将输入流(InputStream)的内容复制到输出流(OutputStream)的辅助方法。以下是对这个方法进行细分析:

  1. 参数校验:

    Assert.notNull(in, "No InputStream specified");
    Assert.notNull(out, "No OutputStream specified");
    
    • 使用 Spring Framework 的 Assert 工具类,确保输入流和输出流都不为 null。如果为 null,抛出 IllegalArgumentException 异常。
  2. 流复制:

    try {
        var2 = StreamUtils.copy(in, out);
    } finally {
        close(in);
        close(out);
    }
    
    • try 块中使用 StreamUtils.copy 方法将输入流的内容复制到输出流。StreamUtils.copy 方法是 Spring Framework 提供的用于复制流的实用方法。
    • finally 块中调用 close 方法关闭输入流和输出流。这确保在复制完成或发生异常时都会关闭这两个流,避免资源泄漏。
  3. 返回复制的字节数:

    return var2;
    
    • 返回复制的字节数。StreamUtils.copy 方法通常返回复制的字节数,这里将其作为方法的返回值。

综合而言,这个方法是一个简化的输入流到输出流的复制操作,确保在完成复制或发生异常时关闭输入流和输出流。这种实现方式通常用于避免手动处理流关闭操作,提高代码的简洁性和可读性。

总结

以上就是我们对于若依文件上传接口的一个分析,可能还是比较浅显,由于我也是一个初学者,对于这套优秀的框架掌握尚欠,欢迎大家进行批评指正!

项目源码: https://gitee.com/wanghui1201/FileOperateUtils

可以直接拿去当做轮子用,大家做毕设啥的可以直接用,简单好用,就不用大家自己拆离了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1313398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux Zabbix企业级监控平台本地部署并实现远程访问

前言 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。能监视各种网络参数,保证服务器系统的安全运营;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 本地zabbix web管理界面限制在只能局域…

数据结构 | DFSBFS,Prim代码

树的DFS&BFS prim算法 图的DFS和BFS DFS

Java小案例-RocketMQ的11种消息类型,你知道几种?(延迟消息)

前言 上一节给大家讲了Rocket的顺序消息,这一节和大家聊一下延迟消息,关于顺序消息大家可以点下面这个链接直接看 RocketMQ的延迟消息 延迟消息 延迟消息就是指生产者发送消息之后,消息不会立马被消费,而是等待一定的时间之后…

JMeter下载与安装

文章目录 前言一、安装java环境(JDK下载与安装)二、JMeter下载三、JMeter安装1.解压缩2.配置环境变量 四、JMeter启动(启动成功则代表JMeter安装成功)五、JMeter汉化(将JMeter修改成中文)1.方法一&#xff…

【Linux】内核结构

一、Linux内核结构介绍 Linux内核结构框图 二、图解Linux系统架构 三、驱动认知 1、为什么要学习写驱动2、文件名与设备号3、open函数打通上层到底层硬件的详细过程 四、Shell Shell脚本 一、Linux内核结构介绍 Linux 内核是操作系统的核心部分,它负责管理系…

【Android】MVC与MVP的区别,MVP网络请求实践

一、MVC模式 目录 一、MVC模式二、MVP模式 1、MVP的简单应用 1.1 导入相关依赖包并设置权限1.2 实现Model1.2 实现Presenter1.3 实现View1.4分析项目结构和绑定过程1.5效果展示 2、MVP结合RxJava 一、MVC模式 MVC(Model(模型)——View(视图)——Controller(控制…

三层交换,DHCP的详解与VRRP

目录 一、三层交换 1、三层交换机的作用: 2.vlan的虚拟接口vlanif(ifinterface接口) 3.三层交换机实验 4.拓展实验​编辑 二、DHCP 1.自动获取ip地址: 2.DHCP的好处: 3.分配方式: 4.举例&#xff…

6.rk3588获取摄像头和激光雷达数据(用线程根据时间同步)

文件夹结构如下: 如果没有特殊说明,我们将py文件写在该路径里面。 保存数据的路径如下: ---img_lidar_save ---2023-12-13(根据日期自动生成当天保存数据的文件夹) ---camera_data(相机数据文件夹) ---image(保存相加…

C++1114新标准——模板模板参数(Template Template Parameter)、using

系列文章目录 C11&14新标准——Variadic templates(数量不定的模板参数) C11&14新标准——Uniform Initialization(统一初始化)、Initializer_list(初始化列表)、explicit C11&14新标准—— d…

SpringBoot 究竟是如何跑起来的

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《SpringBoot》。🎯🎯 &…

怎么把文件转成附件放在公众号里?这篇教程给你详细说清楚

文件转附件,其实就是把文件上传到某个网站,获得文件的下载链接,从而放到文章或者其他地方供读者下载使用。因为公众号并不支持直接在文章里面添加下载链接(至少订阅号不行),所以把文件转成下载链接的方式并…

怎么制作GIF动图?教你这几个简单方法

怎么制作gif动图?GIF动图是一种非常有趣且实用的图片格式,它能够以短小精悍的方式展示动画效果,因此在社交媒体和聊天应用中备受追捧。本文将向您介绍几种制作GIF动图的方法,让您轻松制作出自己的动图。 GIF动图制作方法一&#x…

Spark编程实验一:Spark和Hadoop的安装使用

一、目的与要求 1、掌握在Linux虚拟机中安装Hadoop和Spark的方法; 2、熟悉HDFS的基本使用方法; 3、掌握使用Spark访问本地文件和HDFS文件的方法。 二、实验内容 1、安装Hadoop和Spark 进入Linux系统,完成Hadoop伪分布式模式的安装。完成Ha…

【开源项目】智慧水厂—经典开源项目实景三维数字孪生智慧水厂

智慧水务可视化平台是以物联网IOT技术为核心,以数据库系统为支撑,以城市水资源安全提升和建造智能化为目标的智慧水务体系。飞渡科技利用数字孪生技术结合物联网IOT技术,建立起多个基础数据及管理层级矩阵,可以跨部门、跨层级进行…

【Java 集合】ConcurrentLinkedQueue

在日常中, 我们用到的数据结构有很多: 数组, 链表, 树等, 而在这些结构中, 还有一个叫做队列的存在。 和其他的集合相同, Java 原生提供了不同的实现。 而如果我们需要一个线程安全的队列的话, 可以基于实际的场景进行选择, 比如基于数组实现同时操作上会阻塞的 ArrayBlockingQ…

我们为什么经常使用List list = new ArrayList<>() 而不是ArrayListlist = new ArrayList<>()

为什么不直接去Arraylist list new Arraylist();而是直接通过List list new ArrayList();使用接口的好处 在Java中,使用List接口声明ArrayList类的变量是一种良好的编程实践,因为这符合面向接口编程的原则。面向接口编程是一种编程范式&…

canvas基本绘制对象

目录 绘制画布 设置画布 绘制圆形 绘制矩形填充渐变色 绘制文字及文字样式 绘制画布 <canvas id"canvas" width"800" height"600"></canvas> 设置画布 //获得画布元素var canvasdocument.getElementById(canvas);var ctxca…

GitHub Universe 2023 Watch Party in Shanghai:开源开发者日盛会

目录 前言GitHub Universe 2023的背景开源开发者日活动亮点本次参会的意义活动日程最后 前言 作为全球最大的代码托管平台&#xff0c;GitHub每年都会举办一场令开源开发者们翘首以待的盛会——GitHub Universe&#xff0c;今年也不例外&#xff0c;就在2023年的12月10日&…

算法训练营Day14

#Java #二叉树层次遍历 #反转二叉树 开源学习资料 二叉树的层次遍历&#xff1a;力扣题目链接 二叉树的层次遍历很好理解&#xff1a; 就是从根结点一层一层地往下遍历&#xff08;同一层&#xff0c;从左到右&#xff09;&#xff1a; 迭代的方式很好理解&#xff1a;就是…

computed 和 watch 的奇妙世界:让数据驱动你的 Vue 应用(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…