Spring cloud Feign 文件上传 MultipartFile 构造

快速入门文件上传

如何还不熟悉如何使用 Spring cloud Feign 实现文件上传。

可以参考翟永超 Spring Cloud Feign的文件上传实现

本篇主要介绍如何构造MultipartFile,首先我们通过@RequestPart("file")@FeignClient等注解成功的构造出了一个上传文件的客户端。
例如:

@RequestMapping(method = RequestMethod.POST
        , value = "/uploadFile"
        , produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}
        , consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
public Map<String, Object> uploadFile(@RequestPart(value = "file") MultipartFile file);

但是,如果我们需要上传一个File对象的时候,将会发现没有合适的MultipartFile实现类构造这个参数。

QuickStart

为了快速的构造MultipartFile实例

我们需要使用到org.springframework.mock.web.MockMultipartFile,所以引入

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
</dependency>

如果使用的是Spring boot 搭建的项目,该依赖的版本将会自动从Spring boot父母pom中继承;否则需要自己设置version标签指定版本。

如果不想引入额外的依赖,由于MockMultipartFile内部没有其他而外库的引用,完全可以单独从源码中复制该文件到项目中即可,文档后面将会附上该文件的源码

FileInputStream in = new FileInputStream("...");
MockMultipartFile multipartFile =
          new MockMultipartFile("file", in);

注意:第一个参数,对应着接口中@RequestPart(value = "file")中的value,也就是file,如果这两个参数不一致,会导致报异常:Required request part ‘file’ is not present

该构造器的缺点是无法控制上传文件的名称,通过这种方式上传可能会造成文件名为空,特别是构造的对象是一个byte数组的情况。

可以使用下面这种构造器:

FileInputStream in = new FileInputStream("...");
String fileName = "this_is_your_file.txt"
MockMultipartFile multipartFile = new MockMultipartFile("file"
        , fileName
        , null
        , FileCopyUtils.copyToByteArray(in));

当然也可以直接使用字节数组来构建,构造方法如下:

public MockMultipartFile(String name, @Nullable byte[] content)

方式二

参考自:翟永超 Spring Cloud Feign的文件上传实现

FileItem fileItem = new DiskFileItemFactory().createItem("file"
        , MediaType.TEXT_PLAIN_VALUE
        , true
        , resource.getFilename());
try (InputStream input = resource.getInputStream();
     OutputStream os = fileItem.getOutputStream()) {
    // 流转移
    IOUtils.copy(input, os);
} catch (Exception e) {
    throw new IllegalArgumentException("Invalid file: " + e, e);
}

该方式不需要而外的依赖,两种方式都复制了流中的内容到内存中,相对而言第一种方式构造相对简单,代码可读性也较高。

第一种方式将文件流中内容复制到了数组中(内存)。
第二种方式是流的转移,对于大文件更加友好。

MockMultipartFile 源码

复制与Spring-test包内org.springframework.mock.web.MockMultipartFile.java

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed 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.
 */

package org.springframework.mock.web;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * Mock implementation of the {@link org.springframework.web.multipart.MultipartFile}
 * interface.
 *
 * <p>Useful in conjunction with a {@link MockMultipartHttpServletRequest}
 * for testing application controllers that access multipart uploads.
 *
 * @author Juergen Hoeller
 * @author Eric Crampton
 * @since 2.0
 * @see MockMultipartHttpServletRequest
 */
public class MockMultipartFile implements MultipartFile {

	private final String name;

	private String originalFilename;

	@Nullable
	private String contentType;

	private final byte[] content;


	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param content the content of the file
	 */
	public MockMultipartFile(String name, @Nullable byte[] content) {
		this(name, "", null, content);
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param contentStream the content of the file as stream
	 * @throws IOException if reading from the stream failed
	 */
	public MockMultipartFile(String name, InputStream contentStream) throws IOException {
		this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param originalFilename the original filename (as on the client's machine)
	 * @param contentType the content type (if known)
	 * @param content the content of the file
	 */
	public MockMultipartFile(
			String name, @Nullable String originalFilename, @Nullable String contentType, @Nullable byte[] content) {

		Assert.hasLength(name, "Name must not be null");
		this.name = name;
		this.originalFilename = (originalFilename != null ? originalFilename : "");
		this.contentType = contentType;
		this.content = (content != null ? content : new byte[0]);
	}

	/**
	 * Create a new MockMultipartFile with the given content.
	 * @param name the name of the file
	 * @param originalFilename the original filename (as on the client's machine)
	 * @param contentType the content type (if known)
	 * @param contentStream the content of the file as stream
	 * @throws IOException if reading from the stream failed
	 */
	public MockMultipartFile(
			String name, @Nullable String originalFilename, @Nullable String contentType, InputStream contentStream)
			throws IOException {

		this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
	}


	@Override
	public String getName() {
		return this.name;
	}

	@Override
	public String getOriginalFilename() {
		return this.originalFilename;
	}

	@Override
	@Nullable
	public String getContentType() {
		return this.contentType;
	}

	@Override
	public boolean isEmpty() {
		return (this.content.length == 0);
	}

	@Override
	public long getSize() {
		return this.content.length;
	}

	@Override
	public byte[] getBytes() throws IOException {
		return this.content;
	}

	@Override
	public InputStream getInputStream() throws IOException {
		return new ByteArrayInputStream(this.content);
	}

	@Override
	public void transferTo(File dest) throws IOException, IllegalStateException {
		FileCopyUtils.copy(this.content, dest);
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值