multipart/form-data 请求体本质上就是。一个请求体包含多个Part,每个Part有自己独立的header和body。
一般用于文件上传,以及一次性提交多种不同数据格式的请求。
这里演示提交一个文件的时,还提交一个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
准确无误的读取到了客户端所有的提交的数据