[SPRING] restTemplate을 사용하여 Multipart 폼 데이터를 보내는 방법 Spring-mvc
SPRINGrestTemplate을 사용하여 Multipart 폼 데이터를 보내는 방법 Spring-mvc
Jetty와 함께 RestTemplate이 포함 된 파일을 Raspberry Pi에 업로드하려고합니다. 파이에는 서블릿이 실행 중이다.
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter outp = resp.getWriter();
StringBuffer buff = new StringBuffer();
File file1 = (File) req.getAttribute("userfile1");
String p = req.getParameter("path");
boolean success = false;
if (file1 == null || !file1.exists()) {
buff.append("File does not exist\n");
} else if (file1.isDirectory()) {
buff.append("File is a directory\n");
} else {
File outputFile = new File(req.getParameter("userfile1"));
if(isValidPath(p)){
p = DRIVE_ROOT + p;
final File finalDest = new File(p
+ outputFile.getName());
success = false;
try {
copyFileUsingFileChannels(file1, finalDest);
finalDest.setWritable(true);
success = true;
} catch (Exception e) {
e.printStackTrace();
}
if (success){
buff.append("File successfully uploaded.\n");
}
else{
buff.append("Failed to save file.");
}
}
else{
buff.append("Invalid path.\n");
}
}
outp.write(buff.toString());
}
나는 성공적으로 컬로 할 수있다.
curl --form userfile1=@/home/pi/src/CreateNewFolderServlet.java --form press = OK localhost : 2222 / pi / GetFileServlet? path = "/ media /"
이것은 webapp에서 동일한 기능을 사용하기로되어있는 메소드입니다.
@ResponseBody
@RequestMapping(value="/upload/",method=RequestMethod.POST ,produces = "text/plain")
public String uploadFile(MultipartHttpServletRequest request2, HttpServletResponse response2){
Iterator<String> itr = request2.getFileNames();
MultipartFile file = request2.getFile(itr.next());
System.out.println(file.getOriginalFilename() +" uploaded!");
System.out.println(file.toString());
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("userfile1",file);
//reqEntity.addPart("userfile1", file);
String path="/public/";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
System.out.println("1");
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(parts, headers);
String url = url2+"/pi/GetFileServlet?path="+path;
System.out.println("2");
/* restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
restTemplate.getMessageConverters().add(
new MappingJackson2HttpMessageConverter());*/
System.out.println("3");
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, request,String.class);
System.out.println("4");
System.out.println("response : " +response);
if(response==null||response.getBody().trim()==""){
return "error";
}
return response.getBody();
}
이것은 내가 얻는 결과입니다 :
ui-elements.html이 (가) 업로드되었습니다.
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@47e7673e
1
2
3
당신이 볼 수 있듯이 숫자 4는 인쇄되지 않습니다. 콘솔에서는 예외가 없습니다. 디버깅 중에 발견 된 예외 :
org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.web.multipart.support.StandardMultipartFile["inputStream"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.web.multipart.support.StandardMultipartFile["inputStream"])
해결법
-
==============================
1.RestTemplate의 기본 MessageConverters가 MultipartFile 파일에 포함 된 InputStream을 직렬화하는 방법을 알지 못하기 때문에 예외가 발생합니다. RestTemplate을 통해 객체를 보낼 때 대부분의 경우 POJO를 보내려고합니다. MultipartFile 자체 대신 MultipartMap에 MultipartFile의 바이트를 추가하여이 문제를 해결할 수 있습니다.
RestTemplate의 기본 MessageConverters가 MultipartFile 파일에 포함 된 InputStream을 직렬화하는 방법을 알지 못하기 때문에 예외가 발생합니다. RestTemplate을 통해 객체를 보낼 때 대부분의 경우 POJO를 보내려고합니다. MultipartFile 자체 대신 MultipartMap에 MultipartFile의 바이트를 추가하여이 문제를 해결할 수 있습니다.
서블릿 부분에도 문제가 있다고 생각합니다. 예를 들어
File file1 = (File) req.getAttribute("userfile1");
ServletRequest의 getAttribute 메소드는 요청 / 양식 매개 변수가 아니라 서블릿 컨텍스트에 의해 설정된 속성을 리턴하므로 항상 null을 리턴해야합니다. 실제로 컬 예를 사용하고 있습니까?
다음은 서블릿에 파일을 전달하는 Spring MVC 메소드의 예이다.
서블릿 (Spring MVC 컨테이너에서 실행되는 것을 테스트 했음에도) :
@RequestMapping("/pi") private void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { final String path = request.getParameter("destination"); final Part filePart = request.getPart("file"); final String fileName = request.getParameter("filename"); OutputStream out = null; InputStream fileContent = null; final PrintWriter writer = response.getWriter(); try { out = new FileOutputStream(new File(path + File.separator + fileName)); fileContent = filePart.getInputStream(); int read = 0; final byte[] bytes = new byte[1024]; while ((read = fileContent.read(bytes)) != -1) { out.write(bytes, 0, read); } writer.println("New file " + fileName + " created at " + path); } catch (FileNotFoundException fne) { writer.println("You either did not specify a file to upload or are " + "trying to upload a file to a protected or nonexistent " + "location."); writer.println("<br/> ERROR: " + fne.getMessage()); } finally { if (out != null) { out.close(); } if (fileContent != null) { fileContent.close(); } if (writer != null) { writer.close(); } } }
스프링 MVC 메소드 :
@ResponseBody @RequestMapping(value="/upload/", method=RequestMethod.POST, produces = "text/plain") public String uploadFile(MultipartHttpServletRequest request) throws IOException { Iterator<String> itr = request.getFileNames(); MultipartFile file = request.getFile(itr.next()); MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>(); parts.add("file", new ByteArrayResource(file.getBytes())); parts.add("filename", file.getOriginalFilename()); RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(parts, headers); // file upload path on destination server parts.add("destination", "./"); ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/pi", HttpMethod.POST, requestEntity, String.class); if (response != null && !response.getBody().trim().equals("")) { return response.getBody(); } return "error"; }
이들을 사용하여 다음과 같은 컬에 의해 MVC 메소드를 통해 서블릿에 파일을 성공적으로 업로드 할 수 있습니다.
curl --form file=@test.dat localhost:8080/upload/
-
==============================
2.ByteArrayResource에서 전체 파일을 읽는 것은 대용량 파일의 메모리 소비 문제 일 수 있습니다.
ByteArrayResource에서 전체 파일을 읽는 것은 대용량 파일의 메모리 소비 문제 일 수 있습니다.
InputStreamResource를 사용하여 spring mvc 컨트롤러에서 파일 업로드를 프록시 처리 할 수 있습니다.
@RequestMapping(value = "/upload", method = RequestMethod.POST) public ResponseEntity<?> uploadImages(@RequestPart("images") final MultipartFile[] files) throws IOException { LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>(); String response; HttpStatus httpStatus = HttpStatus.CREATED; try { for (MultipartFile file : files) { if (!file.isEmpty()) { map.add("images", new MultipartInputStreamFileResource(file.getInputStream(), file.getOriginalFilename())); } } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); String url = "http://example.com/upload"; HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers); response = restTemplate.postForObject(url, requestEntity, String.class); } catch (HttpStatusCodeException e) { httpStatus = HttpStatus.valueOf(e.getStatusCode().value()); response = e.getResponseBodyAsString(); } catch (Exception e) { httpStatus = HttpStatus.INTERNAL_SERVER_ERROR; response = e.getMessage(); } return new ResponseEntity<>(response, httpStatus); } class MultipartInputStreamFileResource extends InputStreamResource { private final String filename; MultipartInputStreamFileResource(InputStream inputStream, String filename) { super(inputStream); this.filename = filename; } @Override public String getFilename() { return this.filename; } @Override public long contentLength() throws IOException { return -1; // we do not want to generally read the whole stream into memory ... } }
from https://stackoverflow.com/questions/28408271/how-to-send-multipart-form-data-with-resttemplate-spring-mvc by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 로드 된 모든 Spring 빈을 인쇄하십시오 - Spring Boot (0) | 2019.03.18 |
---|---|
[SPRING] java.lang.ClassNotFoundException : org.hibernate.engine.SessionFactoryImplementor (0) | 2019.03.18 |
[SPRING] RestTemplate 대 Apache Http 클라이언트 (봄 프로젝트의 프로덕션 코드 용) (0) | 2019.03.18 |
[SPRING] 각도 4.3 HTTPClient 기본 인증 작동하지 않음 (0) | 2019.03.18 |
[SPRING] Spring MVC 컨트롤러에서 쿼리 문자열 값 가져 오기 (0) | 2019.03.18 |