m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

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は難しいですね(^^)