欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot 文件上传原理解析

程序员文章站 2022-05-03 10:29:13
首先我们要知道什么是spring boot,这里简单说一下,spring boot可以看作是一个框架中的框架--->集成了各种框架,像security、jpa、dat...

首先我们要知道什么是spring boot,这里简单说一下,spring boot可以看作是一个框架中的框架--->集成了各种框架,像security、jpa、data、cloud等等,它无须关心配置可以快速启动开发,有兴趣可以了解下自动化配置实现原理,本质上是 spring 4.0的条件化配置实现,深抛下注解,就会看到了。

  说spring boot 文件上传原理 其实就是spring mvc,因为这部分工作是spring mvc做的而不是spring boot,那么,springmvc又是怎么处理文件上传这个过程的呢?

  图:

Spring Boot 文件上传原理解析

  首先项目启动相关配置,再执行上述第二步的时候 dispatcherservlet会去查找id为multipartresolver的bean,在配置中看到bean指向的是commonsmultipartresolve,其中实现了multipartresolver接口。

  第四步骤这里会判断是否multipart文件即ismultipart方法,返回true:就会调用 multipartresolver 方法,传递httpservletrequest会返回一个multiparthttpservletrequest对象,再有dispatcherservlet进行处理到controller层;返回false:会忽略掉,继续传递httpservletrequest。

  在mvc中需要在配置文件webapplicationcontext.xml中配置 如下:

  <bean id="multipartresolver" class="org.springframework.web.multipart.commons.commonsmultipartresolver">
      <property name="defaultencoding" value="utf-8"/>
      <property name="maxuploadsize" value="100000000"/>
      <property name="uploadtempdir" value="fileupload/temp"/>
  </bean>

  而spring boot已经自动配置好,直接用就行,做个test没什么问题。有默认的上传限制大小,不过在实际开发中我们还是做一些配置的,

如下在application.properties中:

# multipart config
#默认支持文件上传
spring.http.multipart.enabled=true
#文件上传目录
spring.http.multipart.location=/tmp/xunwu/images/
#最大支持文件大小
spring.http.multipart.max-file-size=4mb
#最大支持请求大小
spring.http.multipart.max-request-size=20mb

当然也可以写配置类来实现,具体的就不做展示了。

  看完上述你肯定有个大概的了解了,这里再啰嗦下,spring提供multipart的解析器:multipartresolver,上述说的是commonsmultipartresolver,它是基于commons file upload第三方来实现,这也是在servlet3.0之前的东西,3.0+之后也可以不需要依赖第三方库,可以用standardservletmultipartresolver,同样也是实现了multipartresolver接口,我们可以看下它的实现:

* copyright 2002-2017 the original author or authors.
package org.springframework.web.multipart.support;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.part;
import org.apache.commons.logging.logfactory;
import org.springframework.web.multipart.multipartexception;
import org.springframework.web.multipart.multiparthttpservletrequest;
import org.springframework.web.multipart.multipartresolver;
/**
 * standard implementation of the {@link multipartresolver} interface,
 * based on the servlet 3.0 {@link javax.servlet.http.part} api.
 * to be added as "multipartresolver" bean to a spring dispatcherservlet context,
 * without any extra configuration at the bean level (see below).
 *
 * <p><b>note:</b> in order to use servlet 3.0 based multipart parsing,
 * you need to mark the affected servlet with a "multipart-config" section in
 * {@code web.xml}, or with a {@link javax.servlet.multipartconfigelement}
 * in programmatic servlet registration, or (in case of a custom servlet class)
 * possibly with a {@link javax.servlet.annotation.multipartconfig} annotation
 * on your servlet class. configuration settings such as maximum sizes or
 * storage locations need to be applied at that servlet registration level;
 * servlet 3.0 does not allow for them to be set at the multipartresolver level.
 *
 * @author juergen hoeller
 * @since 3.1
 * @see #setresolvelazily
 * @see httpservletrequest#getparts()
 * @see org.springframework.web.multipart.commons.commonsmultipartresolver
 */
public class standardservletmultipartresolver implements multipartresolver {
  private boolean resolvelazily = false;
  /**
   * set whether to resolve the multipart request lazily at the time of
   * file or parameter access.
   * <p>default is "false", resolving the multipart elements immediately, throwing
   * corresponding exceptions at the time of the {@link #resolvemultipart} call.
   * switch this to "true" for lazy multipart parsing, throwing parse exceptions
   * once the application attempts to obtain multipart files or parameters.
   */
  public void setresolvelazily(boolean resolvelazily) {
    this.resolvelazily = resolvelazily;
  }
  @override
  public boolean ismultipart(httpservletrequest request) {
    // same check as in commons fileupload...
    if (!"post".equals(request.getmethod().tolowercase())) {
      return false;
    }
    string contenttype = request.getcontenttype();
    return (contenttype != null && contenttype.tolowercase().startswith("multipart/"));
  }
  @override
  public multiparthttpservletrequest resolvemultipart(httpservletrequest request) throws multipartexception {
    return new standardmultiparthttpservletrequest(request, this.resolvelazily);
  }
  @override
  public void cleanupmultipart(multiparthttpservletrequest request) {
    // to be on the safe side: explicitly delete the parts,
    // but only actual file parts (for resin compatibility)
    try {
      for (part part : request.getparts()) {
        if (request.getfile(part.getname()) != null) {
          part.delete();
        }
      }
    }
    catch (throwable ex) {
      logfactory.getlog(getclass()).warn("failed to perform cleanup of multipart items", ex);
    }
  }
}

这里是之前写的test的后者实现配置类,可以简单看下,作为了解:

package com.bj.config;
import org.springframework.boot.autoconfigure.condition.conditionalonmissingbean;
import org.springframework.boot.autoconfigure.web.multipartproperties;
import org.springframework.boot.context.properties.enableconfigurationproperties;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.web.multipart.multipartresolver;
import org.springframework.web.multipart.support.standardservletmultipartresolver;
import org.springframework.web.servlet.dispatcherservlet;
import javax.servlet.multipartconfigelement;
@configuration
@enableconfigurationproperties(multipartproperties.class)
public class fileuploadconfig {
  private final multipartproperties multipartproperties;
  public fileuploadconfig(multipartproperties multipartproperties){
    this.multipartproperties=multipartproperties;
  }
  /**
   * 注册解析器
   * @return
   */
  @bean(name= dispatcherservlet.multipart_resolver_bean_name)
  @conditionalonmissingbean(multipartresolver.class)
  public standardservletmultipartresolver multipartresolver(){
    standardservletmultipartresolver multipartresolver = new standardservletmultipartresolver();
    multipartresolver.setresolvelazily(multipartproperties.isresolvelazily());
    return multipartresolver;
  }
  /**
   * 上传配置
   * @return
   */
  @bean
  @conditionalonmissingbean
  public multipartconfigelement multipartconfigelement(){
    return this.multipartproperties.createmultipartconfig();
  }
}

总结

以上所述是小编给大家介绍的spring boot 文件上传原理解析,希望对大家有所帮助