Spring Bootで画面からAPIへRest Templateでファイルを送信する
シンプルな使い方
jsonで送信する
難しそうな使い方
fileを送信する
やりたいこと
画面からsubmitまたはajaxでファイルを送信する。
問題点
処理の流れが
①画面でファイルを指定する
②画面でsubmitする
③Rest Templateへファイルを送信する
この場合、ファイルオブジェクトの情報をRest Templateへ渡す必要がありますが、MultipartFileをそのまま渡すことはできなかった。
別のファイルを出力したりしないといけないのかと思っていました…
Rest Templateのサンプル
Sample
package com.example.web; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import com.example.form.UploadForm; @Controller public class UploadController { private static final Logger logger = LoggerFactory.getLogger(UploadController.class); @RequestMapping(value = "/upload", method = {RequestMethod.POST}) public String upload(Model model, @ModelAttribute UploadForm form) throws IOException { logger.info(form.getName()); logger.info(form.getUploadFile().getName()); logger.info(form.getUploadFile().getOriginalFilename()); logger.info(String.valueOf(form.getUploadFile().getSize())); RestTemplate restTemplate = new RestTemplate(); MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); ByteArrayResource contentsAsResource = new ByteArrayResource(form.getUploadFile().getBytes()){ @Override public String getFilename(){ return form.getUploadFile().getOriginalFilename(); } }; map.add("name", form.getName()); map.add("uploadFile", contentsAsResource); HttpHeaders formHeaders = new HttpHeaders(); formHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<MultiValueMap<String, Object>>(map, formHeaders); ResponseEntity<String> resposne = restTemplate.exchange("http://localhost:8080/api/upload", HttpMethod.POST, formEntity, String.class); return "/upload"; } }
MultipartFileのデータをByteArrayResourceへ再定義したものを用意して送信することでRestTemplateはファイルとして認識して送信してくれる感じ
受信データ自体はよしなに対応すればいい感じかと…
受信側
package com.example.api; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.example.dto.UploadDto; import com.example.web.UploadController; @RestController public class ApiUploadController { private static final Logger logger = LoggerFactory.getLogger(ApiUploadController.class); @RequestMapping(value = "/api/upload", method = {RequestMethod.POST}) public String upload(UploadDto reqDto) throws IOException { logger.info("/api/upload" + "start"); logger.info(reqDto.getName()); logger.info(reqDto.getUploadFile().getName()); logger.info(reqDto.getUploadFile().getOriginalFilename()); logger.info(new String(reqDto.getUploadFile().getBytes(), "UTF-8")); logger.info("/api/upload" + "end"); return "aaaaa"; } }
Form、DTO
package com.example.form; import java.io.Serializable; import org.springframework.web.multipart.MultipartFile; public class UploadForm implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String name; private MultipartFile uploadFile; public String getName() { return name; } public void setName(String name) { this.name = name; } public MultipartFile getUploadFile() { return uploadFile; } public void setUploadFile(MultipartFile uploadFile) { this.uploadFile = uploadFile; } }
参考
spring mvc - Sending Multipart File as POST parameters with RestTemplate requests - Stack Overflow
所感
まあ、いろいろ探してみるもんかと思いました。
最初はできないような気がすると思っていましたがよくよく考えたらそのあたりのことを考慮していないわけがないと思いましたし…
Springは難しいですね(^^)