使用restful方式编程,有时候put方式修改文件。但是默认情况下很多浏览器(比如:chrom)不支持put方式修改文件。spring默认情况下也不支持PUT方式修改文件。如果想要支持,方式如下:
一、后端覆盖StandardServletMultipartResolver。
通过查看springboot的文档,默认情况下,spring使用在配置文件中MultipartAutoConfiguration
中配置了上传文件的默认类StandardServletMultipartResolver 如下:
StandardServletMultipartResolver 里面有下面的内容:表示POST方式才用上传文件的方式处理。
所以我们就要把这个默认的去掉。也就是写一个类继承StandardServletMultipartResolver ,并重写它的isMultipart方法。
二、网上错误的做法:
网上找资料都说要继承CommonsMultipartResolver ,并重写isMultipart方法,这种方式是错误的,会使得spring对文件类型的参数绑定失效。例如:@RequestParam("files") List<MultipartFile> files 获取不到文件内容。
这种做法 如下:
import org.apache.commons.fileupload.FileUploadBase;
import org.springframework.http.HttpMethod;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
public class PostAndPutCommonsMultipartResolver extends CommonsMultipartResolver {
private static final String POST_METHOD = "POST";
private static final String PUT_METHOD = "PUT";
@Override
public boolean isMultipart(HttpServletRequest request) {
boolean isMultipartRequest = false;
if (request != null) {
HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
if (Objects.equals(HttpMethod.POST,httpMethod) || Objects.equals(HttpMethod.PUT,httpMethod)) {
// isMultipartRequest = FileUploadBase.isMultipartContent(new ServletRequestContext(request));
isMultipartRequest = FileUploadBase.isMultipartContent(new ServletRequestContext(request));
}
}
return isMultipartRequest;
}
}
然后,配置bean覆盖默认的CommonsMultipartResolver 。
@Bean(name = "multipartResolver")
public CommonsMultipartResolver createMultipartResolver() {
return new PostAndPutCommonsMultipartResolver();
}
注意上面上传文件的时候,用到一个commons-fileupload包,所以得导入这个包。
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
三、前端调用:
前端调用的时候,由于chrom不支持PUT请求。如果写method="PUT"会自动转为GET方式。
所以在form表单上需要method="POST" 。以POST方式提交。但是在参数里面加上<input type="hidden" name="_method" value="PUT" />,spring接收到这个参数后,后台会以PUT的方式路由到对应的PUT方法上。
<form action="/customers/dV" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_method" value="PUT" />
<input type="text" name="id" value="dV"/>
<input type="file" name="coverImg"/>
<input type="submit" value="提交"/>
</form>
四、正确的做法:
就是把PostAndPutCommonsMultipartResolver继承StandardServletMultipartResolver 。重写isMultipart方法。
public class PostAndPutCommonsMultipartResolver extends StandardServletMultipartResolver {
private static final String POST_METHOD = "POST";
private static final String PUT_METHOD = "PUT";
@Override
public boolean isMultipart(HttpServletRequest request) {
boolean isMultipartRequest = false;
if (request != null) {
HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
if (Objects.equals(HttpMethod.POST,httpMethod) || Objects.equals(HttpMethod.PUT,httpMethod)) {
String contentType = request.getContentType();
isMultipartRequest = (contentType != null && contentType.toLowerCase().startsWith("multipart/"));
}
}
return isMultipartRequest;
}
}
不要忘记配置bean:参考MultipartAutoConfiguration
的配置。
@Autowired
private MultipartProperties multipartProperties;
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public StandardServletMultipartResolver multipartResolver() {
PostAndPutCommonsMultipartResolver multipartResolver = new PostAndPutCommonsMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
前端调用和上面一样。
参考文档:
https://stackoverflow.com/questions/7981640/spring-3-0-fileupload-only-with-post/33658066#33658066 (里面有测试方法编写)
https://stackoverflow.com/questions/18728100/file-upload-via-http-put-request