Spring Boot默认使用StandardServletMultipartResolver处理Multipart。
对应的使用StandardMultipartFile来接收文件数据。
private static class StandardMultipartFile implements MultipartFile, Serializable { private final Part part; private final String filename; public StandardMultipartFile(Part part, String filename) { this.part = part; this.filename = filename; } @Override public String getName() { return this.part.getName(); } @Override public String getOriginalFilename() { return this.filename; } @Override public String getContentType() { return this.part.getContentType(); } @Override public boolean isEmpty() { return (this.part.getSize() == 0); } @Override public long getSize() { return this.part.getSize(); } @Override public byte[] getBytes() throws IOException { return FileCopyUtils.copyToByteArray(this.part.getInputStream()); } @Override public InputStream getInputStream() throws IOException { return this.part.getInputStream(); } @Override public void transferTo(File dest) throws IOException, IllegalStateException { this.part.write(dest.getPath()); if (dest.isAbsolute() && !dest.exists()) { // Servlet 3.0 Part.write is not guaranteed to support absolute file paths: // may translate the given path to a relative location within a temp dir // (e.g. on Jetty whereas Tomcat and Undertow detect absolute paths). // At least we offloaded the file from memory storage; it'll get deleted // from the temp dir eventually in any case. And for our user's purposes, // we can manually copy it to the requested location as a fallback. FileCopyUtils.copy(this.part.getInputStream(), new FileOutputStream(dest)); } } }
MultipartFile
CommonsMultipartFile
StandardMultipartFile
MultipartResolver
StandardServletMultipartResolver
CommonsMultipartResolver
如果希望用CommonsMultipartFile来接收文件数据
在没有配置multipartResolver为CommonsMultipartResolver,使用CommonsMultipartResolver来处理Multipart,这种情况下,报如下错误:
Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile': no matching editors or conversion strategy found
如果multipartResolver配置如下:
@Bean(name = "multipartResolver") public CommonsMultipartResolver getCommonsMultipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize(20971520); multipartResolver.setMaxInMemorySize(1048576); return multipartResolver; }
使用CommonsMultipartResolver来处理Multipart,通过CommonsMultipartFile无法接收到文件。
需要关闭Spring Boot的Multipart自动配置
@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
如果希望用StandardMultipartFile来接收文件数据
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.StandardMultipartFile#filename
这里获取的文件名如果是中文的话,总是乱码。
/* * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $ * $Revision: 480424 $ * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ * * ==================================================================== * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.httpclient.methods.multipart; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.httpclient.util.EncodingUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * This class implements a part of a Multipart post object that * consists of a file. * * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a> * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a> * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a> * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a> * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * * @since 2.0 * */ public class MultipartFilePart extends PartBase { /** Default content encoding of file attachments. */ public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; /** Default charset of file attachments. */ public static final String DEFAULT_CHARSET = "ISO-8859-1"; /** Default transfer encoding of file attachments. */ public static final String DEFAULT_TRANSFER_ENCODING = "binary"; /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(MultipartFilePart.class); /** Attachment's file name */ protected static final String FILE_NAME = "; filename="; /** Attachment's file name as a byte array */ private static final byte[] FILE_NAME_BYTES = EncodingUtil.getAsciiBytes(FILE_NAME); /** Source of the file part. */ private PartSource source; /** * FilePart Constructor. * * @param name the name for this part * @param partSource the source for this part * @param contentType the content type for this part, if <code>null</code> the * {@link #DEFAULT_CONTENT_TYPE default} is used * @param charset the charset encoding for this part, if <code>null</code> the * {@link #DEFAULT_CHARSET default} is used */ public MultipartFilePart(String name, PartSource partSource, String contentType, String charset) { super( name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? "ISO-8859-1" : charset, DEFAULT_TRANSFER_ENCODING ); if (partSource == null) { throw new IllegalArgumentException("Source may not be null"); } this.source = partSource; } /** * FilePart Constructor. * * @param name the name for this part * @param partSource the source for this part */ public MultipartFilePart(String name, PartSource partSource) { this(name, partSource, null, null); } /** * FilePart Constructor. * * @param name the name of the file part * @param file the file to post * * @throws FileNotFoundException if the <i>file</i> is not a normal * file or if it is not readable. */ public MultipartFilePart(String name, File file) throws FileNotFoundException { this(name, new FilePartSource(file), null, null); } /** * FilePart Constructor. * * @param name the name of the file part * @param file the file to post * @param contentType the content type for this part, if <code>null</code> the * {@link #DEFAULT_CONTENT_TYPE default} is used * @param charset the charset encoding for this part, if <code>null</code> the * {@link #DEFAULT_CHARSET default} is used * * @throws FileNotFoundException if the <i>file</i> is not a normal * file or if it is not readable. */ public MultipartFilePart(String name, File file, String contentType, String charset) throws FileNotFoundException { this(name, new FilePartSource(file), contentType, charset); } /** * FilePart Constructor. * * @param name the name of the file part * @param fileName the file name * @param file the file to post * * @throws FileNotFoundException if the <i>file</i> is not a normal * file or if it is not readable. */ public MultipartFilePart(String name, String fileName, File file) throws FileNotFoundException { this(name, new FilePartSource(fileName, file), null, null); } /** * FilePart Constructor. * * @param name the name of the file part * @param fileName the file name * @param file the file to post * @param contentType the content type for this part, if <code>null</code> the * {@link #DEFAULT_CONTENT_TYPE default} is used * @param charset the charset encoding for this part, if <code>null</code> the * {@link #DEFAULT_CHARSET default} is used * * @throws FileNotFoundException if the <i>file</i> is not a normal * file or if it is not readable. */ public MultipartFilePart(String name, String fileName, File file, String contentType, String charset) throws FileNotFoundException { this(name, new FilePartSource(fileName, file), contentType, charset); } /** * Write the disposition header to the output stream * @param out The output stream * @throws IOException If an IO problem occurs * @see Part#sendDispositionHeader(OutputStream) */ protected void sendDispositionHeader(OutputStream out) throws IOException { LOG.trace("enter sendDispositionHeader(OutputStream out)"); super.sendDispositionHeader(out); String filename = this.source.getFileName(); if (filename != null) { out.write(FILE_NAME_BYTES); out.write(QUOTE_BYTES); out.write(EncodingUtil.getBytes(filename, getCharSet())); out.write(QUOTE_BYTES); } } /** * Write the data in "source" to the specified stream. * @param out The output stream. * @throws IOException if an IO problem occurs. * @see org.apache.commons.httpclient.methods.multipart.Part#sendData(OutputStream) */ protected void sendData(OutputStream out) throws IOException { LOG.trace("enter sendData(OutputStream out)"); if (lengthOfData() == 0) { // this file contains no data, so there is nothing to send. // we don't want to create a zero length buffer as this will // cause an infinite loop when reading. LOG.debug("No data to send."); return; } byte[] tmp = new byte[4096]; InputStream instream = source.createInputStream(); try { int len; while ((len = instream.read(tmp)) >= 0) { out.write(tmp, 0, len); } } finally { // we're done with the stream, close it instream.close(); } } /** * Returns the source of the file part. * * @return The source. */ protected PartSource getSource() { LOG.trace("enter getSource()"); return this.source; } /** * Return the length of the data. * @return The length. * @throws IOException if an IO problem occurs * @see org.apache.commons.httpclient.methods.multipart.Part#lengthOfData() */ protected long lengthOfData() throws IOException { LOG.trace("enter lengthOfData()"); return source.getLength(); } }
客户端上传代码:
@Test public void test() { String localFile = "E:\\docs\\装饰模式.bmp"; File file = new File(localFile); // String url = "http://localhost:8081/upload"; String url = "http://localhost:8081/upload?version=1.1"; PostMethod filePost = new PostMethod(url){//这个用来中文乱码 public String getRequestCharSet() { return "UTF-8";// } }; // filePost.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"utf-8"); HttpClient client = new HttpClient(); // filePost.setRequestHeader(); try { String secret = UUID.randomUUID().toString(); System.out.println("secret:" + secret); filePost.setParameter("secret", secret); filePost.setParameter("secret", secret); Part[] parts = { new StringPart("newSecret", secret), new StringPart("fileName", "ABC" + file.getName(), "UTF-8"), // "application/octet-stream; charset=ISO-8859-1", "ISO-8859-1" new FilePart("file", file, null, "utf-8") { protected void sendDispositionHeader(OutputStream out) throws IOException { super.sendDispositionHeader(out); String filename = getSource().getFileName(); if (filename != null) { out.write(EncodingUtil.getAsciiBytes(FILE_NAME)); out.write(QUOTE_BYTES); // out.write(EncodingUtil.getBytes(filename, "utf-8")); out.write(EncodingUtil.getBytes(filename, getCharSet())); out.write(QUOTE_BYTES); } } }, // new FilePart(new String(file.getName().getBytes("ISO-8859-1"), "UTF-8"), file) }; filePost.setRequestEntity(new MultipartRequestEntity(parts, filePost.getParams())); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); int status = client.executeMethod(filePost); if (status == HttpStatus.SC_OK) { System.out.println("SUCCESS"); } else { System.out.println("FAIL: status: " + status); } } catch (Exception ex) { ex.printStackTrace(); } finally { filePost.releaseConnection(); } }
相关推荐
深入理解Spring Cloud与微服务构建+Git&GitHub;+Spring Boot+Spring in action+SpringBoot实战
介绍一个基于Spring Boot 3.0、Spring Cloud 2022 & Alibaba的微服务RBAC权限管理系统。该系统可以实现微服务RBAC权限管理,通过RBAC权限管理机制对用户访问系统的权限进行限制,从而提高系统的安全性和可用性。同时...
主要给大家介绍了关于spring boot中几种注入方法的一些个人看法,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决...
描述:Spring Boot中文文档是Spring Boot官方文档的中文翻译版,它包含了Spring Boot的基本介绍、快速入门、核心特性、高级特性等内容,可以帮助用户快速了解和掌握Spring Boot的使用方法和技巧。 Spring Boot是一款...
spring-boot-ssm 是一个基于Spring Boot & Spring & Spring MVC & MyBatis的简单通用的项目,用于快速构建中小型API的后端服务系统. 可以做为一个种子项目,进行改造升级. 另外,还有个对应的Vue+ElementUI的前端项目,...
获取Spring Boot 2微框架的可重用代码配方和代码段 了解Spring Boot 2如何与其他Spring API,工具和框架集成 访问Spring MVC和新的Spring Web Sockets,以实现更简单的Web开发 使用微服务进行Web服务开发并与Spring ...
JDK 8 + Spring Boot 2.7.18
Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置文件介绍及其使用教程所用到的Controller代码 Spring Boot中配置...
基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring Boot + MySQL 开发的博客系统源码 基于 Spring ...
Beginning Spring Boot 2 Beginning Spring Boot 2 Beginning Spring Boot 2
Spring Boot 中文文档 1.5.2 Spring Boot 中文文档 1.5.2 Spring Boot 中文文档 1.5.2
基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 基于spring boot餐厅管理系统源码 ...
This book will help you understand what Spring Boot is, how Spring Boot helps you build Spring-based applications quickly and easily, and the inner workings of Spring Boot using easy-to-follow ...
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot...
Spring Boot简化了基于Spring的应用开发,通过少量的代码就能创建一个独立的、产品级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置,这样你就可以有条不紊地开始。多数Spring Boot应用只...
Spring-Boot-Reference-Guide, Spring Boot Reference Guide中文翻译 -《Spring Boot参考指南》
Pro Spring Boot 2: An Authoritative Guide to Building Microservices, Web and Enterprise Applications, and Best Practices Quickly and productively develop complex Spring applications and microservices...
基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统。 采用前后端分离的模式,微服务版本前端(基于 RuoYi-Vue)。 后端采用Spring Boot、Spring Cloud & Alibaba。 注册中心、配置中心选型Nacos...