在SpringBoot中使用RestTemplate发送复杂的multipart请求

在SpringBoot中使用RestTemplate发送复杂的multipart请求

multipart/form-data 请求体本质上就是。一个请求体包含多个Part,每个Part有自己独立的headerbody

一般用于文件上传,以及一次性提交多种不同数据格式的请求。

这里演示提交一个文件的时,还提交一个json,一个表单数据到服务器,由SpringBoot处理请求。

通过RestTemplate发送multipart/form-data请求


import java.io.IOException;
import java.nio.file.Paths;
import java.util.Arrays;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

public class MainTest {
	public static void main(String[] args) throws IOException {
		RestTemplate restTemplate = new RestTemplate();

		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.MULTIPART_FORM_DATA); // 多部件表单体

		MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
		// ----------------- 表单 part
		multipartBodyBuilder.part("name", "KevinBlandy");
		/**
		 * 每个表单项都有独立的header
		 * 在这个表单项后额外添加了一个header
		 */
		multipartBodyBuilder.part("skill", Arrays.asList("Java", "Python", "Javascript")).header("myHeader", "myHeaderVal");
		
		// ----------------- 文件 part
		// 从磁盘读取文件
		multipartBodyBuilder.part("file", new FileSystemResource(Paths.get("D:\\17979625.jpg")), MediaType.IMAGE_JPEG);
		// 从classpath读取文件
		multipartBodyBuilder.part("file", new ClassPathResource("app.log"), MediaType.TEXT_PLAIN);
		
		// ----------------- json part
		// json表单项
		multipartBodyBuilder.part("json", "{\"website\": \"SpringBoot中文社区\"}", MediaType.APPLICATION_JSON);

		// build完整的消息体
		MultiValueMap<String, HttpEntity<?>> multipartBody = multipartBodyBuilder.build();
		ResponseEntity<String> responseEntity = restTemplate.postForEntity("http://localhost/test", multipartBody, String.class);
		
		System.out.println(responseEntity);
	}
}

Controlller中处理请求

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/test")
public class TestController {

	private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
	
	@PostMapping
	public Object test (HttpServletRequest request,
						@RequestParam("name") String name,
						@RequestParam("skill") String[] skills,
						@RequestParam("file") MultipartFile[] multipartFiles,
						@RequestParam("json") String json) throws IOException, ServletException {
		
		// 获取封装后的数据
		LOGGER.debug("name={}", name);
		LOGGER.debug("skill=[{}]", String.join(",", skills));
		for (MultipartFile multipartFile : multipartFiles) {
			LOGGER.debug("file,fileName={},size={},contentType={}", multipartFile.getOriginalFilename(), multipartFile.getSize(), multipartFile.getContentType());
		}
		LOGGER.debug("json={}", json);
		
		// 获取指定part中定义的header
		Part part = request.getPart("skill");
		String headerVal = part.getHeader("myHeader");
		LOGGER.debug("myHeader={}", headerVal);
		return "ok";
	}
}

日志输出

o.s.web.servlet.DispatcherServlet        : POST "/test", parameters={masked}
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to io.springboot.twitter.web.controller.TestController#test(HttpServletRequest, String, String[], MultipartFile[], String)
i.s.t.web.controller.TestController      : name=KevinBlandy
i.s.t.web.controller.TestController      : skill=[["Java","Python","Javascript"]]
i.s.t.web.controller.TestController      : file,fileName=17979625.jpg,size=11224,contentType=image/jpeg
i.s.t.web.controller.TestController      : file,fileName=app.log,size=77,contentType=text/plain
i.s.t.web.controller.TestController      : json={"website": "SpringBoot中文社区"}
i.s.t.web.controller.TestController      : myHeader=myHeaderVal
m.m.a.RequestResponseBodyMethodProcessor : Using 'text/plain', given [text/plain, application/json, application/*+json, */*] and supported [application/json, application/*+json, text/plain, */*, text/plain, */*, application/json, application/*+json]
m.m.a.RequestResponseBodyMethodProcessor : Writing ["ok"]
o.s.web.servlet.DispatcherServlet        : Completed 200 OK

准确无误的读取到了客户端所有的提交的数据

我这边碰到这种场景,我拿到的是图片base64,然后表单提交需要带上文件名,这个时候resource的构建,可以通过以下方式

    byte[] bytes = new byte[10];
	ByteArrayResource byteResource = new ByteArrayResource(bytes) {
		@Override
		public String getFilename() {
			return "自定义文件名";
		}
	};
2 个赞