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

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

在这里插入图片描述

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

控制层代码剖析

    @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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言必学知识点五】指针

指针 导言一、指针与指针变量二、指针变量的创建和指针类型三、指针类型的意义3.1 指针 /- 整数3.2 指针解引用 四、野指针4.1 定义4.2 野指针的成因4.3 指针未初始化4.4 指针越界访问4.5 指针指向的空间被释放4.6 如何规避野指针 五、指针运算5.1指针-整数5.2 指针-指针5.2.1 …

B037-Mybatis基础

目录 为什么需要Mybatis?mybatis简介入门案例其余见代码查询流程增删改流程 - 变动数据要加事务去持久化抽取公共类 mapper接口开发规则概述代码 mapper.xml引入本地约束文件别名日志管理作用log4j的使用规范 井大括号与dollar大括号的区别 框架:半成品&…

Linux篇:信号

一、信号的概念: ①进程必须识别能够处理信号,信号没有产生,也要具备处理信号的能力---信号的处理能力属于进程内置功能的一部分 ②进程即便是没有收到信号,也能知道哪些信号该怎么处理。 ③当进程真的受到了一个具体的信号的时候…

Word公式居中+序号右对齐

Word公式居中序号右对齐 # 号制表位法表格法Mathtype法 # 号 制表位法 表格法 Mathtype法 参考1 参考2

力扣每日一题:2132. 用邮票贴满网格图(2023-12-14)

力扣每日一题 题目:2132. 用邮票贴满网格图 日期:2023-12-14 用时:38 m 32 s 思路:使用前缀和+差分,只是往常是一维,现在变二维了,原理差不多 时间:22ms 内存&#xff1…

certum ev ssl证书1180元一年,360浏览器显示公司名

Certum旗下的EV SSL证书是审核最严的数字证书,不仅对网站传输数据进行加密,还可以对网站身份进行验证,除此之外,它独有的绿色地址栏提升了网站的真实性,增强了客户对网站的信任感。今天就随SSL盾小编了解Certum旗下的E…

【Spring Boot】视图渲染技术之Freemarker

一、引言 1、什么是Freemarker FreeMarker是一款模板引擎,基于模板和要改变的数据,并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。它不是面向最终用户的,而是一个Java类库,是一款…

LAMP平台部署及应用

1、安装PHP软件包 1.1、准备工作 检查软件是否安装,避免冲突 [rootyang ~]# rpm -e php php-cli php-ldap php-common php-mysql --nodeps 错误:未安装软件包 php 错误:未安装软件包 php-cli 错误:未安装软件包 php-ldap 错误…

使用 Python 使用贝叶斯神经网络从理论到实践

一、说明 在本文中,我们了解了如何构建一个机器学习模型,该模型结合了神经网络的强大功能,并且仍然保持概率方法进行预测。为了做到这一点,我们可以构建所谓的贝叶斯神经网络。 这个想法不是优化神经网络的损失&#xff0…

2. PyTorch——Tensor和Numpy

2.1Tensor和Numpy Tensor和Numpy数组之间具有很高的相似性,彼此之间的互操作也非常简单高效。需要注意的是,Numpy和Tensor共享内存。由于Numpy历史悠久,支持丰富的操作,所以当遇到Tensor不支持的操作时,可先转成Numpy…

获取和移除cookie的方法

下载npm的cookie插件, 在utils.js文件中引入插件: 封装原始的Cookies.get()方法: 在xxxx.vue文件中引入方法: 使用getCookie方法获取cookie: 封装 移除cookie: export const removeCookie name>{ const options { path: /, domain: xxx.com }; Cookies.remove(name, opti…

18 5G - NR物理层解决方案支持6G非地面网络中的高移动性

文章目录 非地面网络场景链路仿真参数实验仿真结果 非地面网络场景 链路仿真参数 实验仿真结果 Figure 5 && Figure 6:不同信噪比下的BER和吞吐量 变量 SISO 2x2MIMO 2x4MIMO 2x8MIMOReyleigh衰落、Rician衰落、多径TDL-A(NLOS) 、TDL-E(LOS)(a)QPSK (b)16…

玩期货,千万要注意不同软件的设置啊

参加某公司的期货交易模拟选拔,用的是博易大师,结果这个软件的止损线巨坑,当天下午设置的止损线,在收盘之后软件关闭的情况下就自动作废了,到了晚上夜盘如果价格超相反方向走了,那可能导致巨亏。 幸亏是模拟…

nginx的location与rewrite

目录 一.location 二.rewrite rewrite跳转实现: 语法格式:rewrite [flag]; flag标记说明: 三.基于域名跳转 四.基于ip跳转 五.基于旧域名跳转到新域名后面加目录 六.基于参数匹配的跳转 可以同过全局变量来匹配: 基于目…

最高级别认可!喂车科技荣获国际CMMI5级认证

近日,喂车科技顺利通过全球软件领域最高级别认证CMMI 5级(简称CMMI5)认证! 此次荣获CMMI5级认证,意味着喂车科技在研发管理体系、项目实施交付服务以及项目管理水平等方面均已达到国际领先水平,能够为客户…

如何远程访问Axure RP制作的本地web站点实现协同办公

文章目录 前言1.在AxureRP中生成HTML文件2.配置IIS服务3.添加防火墙安全策略4.使用cpolar内网穿透实现公网访问4.1 登录cpolar web ui管理界面4.2 启动website隧道4.3 获取公网URL地址4.4. 公网远程访问内网web站点4.5 配置固定二级子域名公网访问内网web站点4.5.1创建一条固定…

在windows系统搭建LVGL模拟器(codeblock工程)

1.codeblock准备 下载codeblock(mingw),安装。可参考网上教程。 2.pc_simulator_win_codeblocks 工程获取 仓库地址:lvgl/lv_port_win_codeblocks: Windows PC simulator project for LVGL embedded GUI Library (github.com) 拉取代码到本地硬盘&…

机器学习算法应用场景与评价指标

机器学习算法(一)——分类 机器学习算法(二)——回归 机器学习算法(三)——异常检测 一、应用场景 机器学习的算法选择大部分依赖于具体的问题类型和数据特征。下面是一些典型的场景以及对应的常用算法&am…

面对知识经济的发展,企业该如何做好知识管理?

面对知识经济的发展,企业犹如逆水行舟,不进则退,而知识管理已经成为了企业赖以生存和发展的关键。大家可能对知识经济这个词比较陌生,简单来说,知识经济就是指在经济活动中,知识的产生、获取、传播和应用成…

点石成金》》》从“沙粒”蜕变到“芯片”

每个半导体产品的制造都需要数百个工艺,Lam Research将整个制造过程分为八个步骤:晶圆加工-氧化-光刻-刻蚀-薄膜沉积-互连-测试-封装。 01 晶圆加工 所有半导体工艺都始于一粒沙子!因为沙子所含的硅是生产晶圆所需要的原材料。晶圆是…