Request with image by ajax to spring mvc controller - java

I'm trying to send image by ajax:
function putImage() {
var image = document.getElementById('image').files[0];
var formData = new FormData();
formData.append('image', image);
$.ajax({
url: 'http://localhost:8080/ImageStorageREST/image',
type: 'put',
data: formData,
contentType: false,
processData: false,
async: true,
success: function(data) {
console.log("success");
console.log(data);
},
error: function(data) {
console.log("error");
console.log(data);
}
});
}
HTML form:
<form>
<input type="file" multiple accept="image/*,image/jpeg" id="image"/>
<input type="submit" value="Отправить" onClick="putImage(); return false;" />
</form>
The controller's method:
#RequestMapping(value="/image", method=RequestMethod.PUT)
public #ResponseBody String addImage(#RequestPart("image") MultipartFile image) {
return "RECEIVED";
}
Multipart Resolver is registered in dispatcher config file:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000" />
</bean>
I received org.springframework.beans.BeanInstantiationException at server
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.multipart.MultipartFile]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:101)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveModelAttribute(HandlerMethodInvoker.java:775)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:368)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:172)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:879)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)
And request status is
Request URL:http://localhost:8080/ImageStorageREST/image
Request Method:PUT
Status Code:500 Internal Server Error
Remote Address:[::1]:8080
But I see the parameter at browser:
Content-Disposition: form-data; name="image"; filename="format_jpg.jpg"
Content-Type: image/jpeg
......
So why is this exception thrown? I looked a lot of links where the solution was to add multipartResolver bean, but I have it yet.

This problem was caused by using Servlet 2.5 (Tomcat 6.0). The HttpServletRequest class doesn't contain getParts() method.
So I solved my problem by changing controller's method:
#RequestMapping(value="/image", method=RequestMethod.PUT, consumes="multipart/form-data")
public #ResponseBody void addImage(HttpServletRequest request) throws ImageException {
byte[] bytes = getBytesFromFile(request);
Image image = new Image();
image.setByteData(bytes);
imageService.addImage(image);
}
private byte[] getBytesFromFile(HttpServletRequest request) throws ImageException {
ServletFileUpload upload = new ServletFileUpload();
byte[] bytes = null;
FileItemIterator iter;
try {
iter = upload.getItemIterator(request);
while(iter.hasNext()) {
FileItemStream item = iter.next();
InputStream stream = item.openStream();
bytes = IOUtils.toByteArray(stream);
}
return bytes;
} catch (IOException | FileUploadException e) {
throw new ImageException("The problem while storing file. Try again.",e);
}
}

Related

NullPointerException in simple fileupload form using Spring MVC

I am trying to implement simple fileupload using Spring 4.2.3 and HTML form.
I have controller class which handles whole action, simple wrapper class for file, validator and simple view with form in HTML & Thymeleaf.
Almost everything is running fine, mapping works properly and view is appearing. But when I select file from disk and press upload button I have NullPointerException. Can anyone have a look and give some tips please? I have to mention that I am novice in Spring.
Controller:
#Controller
public class FileUploadController {
private static String UPLOAD_LOCATION = "C:/Temp/";
#Autowired
FileValidator fileValidator;
#InitBinder("file")
protected void initBinderFileBucket(WebDataBinder binder) {
binder.setValidator(fileValidator);
}
#RequestMapping(value = "/upload", method = RequestMethod.GET)
public String getSingleUploadPage(ModelMap model) {
FileBucket fileModel = new FileBucket();
model.addAttribute("fileBucket", fileModel);
return "views/fileUploader";
}
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String singleFileUpload(#Valid FileBucket file, BindingResult result, ModelMap model)
throws IOException {
if (result.hasErrors()) {
System.out.println("File Uploader validation error");
return "views/fileUploader";
} else {
System.out.println("Fetching file"); //prints out in console
MultipartFile multipartFile = file.getFile();
System.out.println(multipartFile.getName()); //NullPointer here
return "views/success";
}
}
}
File wrapper:
public class FileBucket {
private MultipartFile file;
//getters & setters + soon other stuff
}
Validator:
#Component
public class FileValidator implements Validator {
public boolean supports(Class<?> clazz) {
return FileBucket.class.isAssignableFrom(clazz);
}
public void validate(Object obj, Errors errors) {
FileBucket file = (FileBucket) obj;
if(file.getFile()!=null){
if (file.getFile().getSize() == 0) {
errors.rejectValue("file", "missingfile");
}
}
}
}
View:
<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:th="http://www.thymeleaf.org"
layout:decorator="templates/baseTemplate">
<head>
<title>Upload Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<div layout:fragment="contentPanel" class="form-container">
<h1>Simple upload</h1>
<form method="POST" enctype="multipart/form-data" action="upload" >
<input type="file" name="file" /> <br />
<input type="submit" value="Upload" />
</form>
</div>
Demo
</body>
</html>
Stacktrace:
INFO: Starting ProtocolHandler ["http-bio-8080"]
Fetching file
kwi 23, 2016 12:39:36 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [spring] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at web.controllers.FileUploadController.singleFileUpload(FileUploadController.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Okay I found out what's causing the problem.
After correcting name in #InitBinder to match argument in controller it was necessary to rename bean responsible for multipart resolving.
From:
#Bean public CommonsMultipartResolver commonsMultipartResolver() {
return new CommonsMultipartResolver();
}
To:
#Bean public CommonsMultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
Otherwise it doesn't work.

Not able to display list on the same page received from controller through ajax call. IllegalStateException

I am trying to display a list on the jsp (on its loading) fetched from controller. The controller is called by ajax, and the list is also received by ajax function as a Json response, but it gives me following error:
java.lang.IllegalStateException: Cannot call sendError() after the response has been committed
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:478)
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.handleHttpMessageNotWritable(DefaultHandlerExceptionResolver.java:344)
at org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.doResolveException(DefaultHandlerExceptionResolver.java:131)
at org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.resolveException(AbstractHandlerExceptionResolver.java:136)
at org.springframework.web.servlet.DispatcherServlet.processHandlerException(DispatcherServlet.java:1120)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:944)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:279)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
However, if the list is returned empty then the success of ajax function is called, so the problem revolves around returning the arraylist as a response.
Below is my jsp:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js> </script>
</head>
<script>
$(document).ready(function() {
var path = window.location.href;
;
alert(path);
$.ajax({
type : "GET",
url : "displaySurvey.htm",
dataType: "json",
data : {
name : window.location.href
},
success : function(response) {
alert("success");
displayTheContent(response);
},
});
});
function displayTheContent(response) {
alert("displayResponse");
$("#displayDiv").empty();
for (var i = 0, l = response.length; i < l; i++) {
var user = response[i];
$("#displayDiv").append(
"<li>" + user.question + " " + user.option1 + "</li>");
}
}
</script>
<body>
<div id="displayDiv"></div>
</body>
</html>
Controller:
#Controller
#RequestMapping("/displaySurvey.htm")
public class DisplaySurveyController extends javax.servlet.http.HttpServlet {
#RequestMapping(method = RequestMethod.GET)
public #ResponseBody ArrayList<SurveyQuestions> submit(#RequestParam("name") String request)
throws AdException {
String surveyId = request.substring(request.lastIndexOf("=") + 1);
try {
SurveyDAO surveyDao = new SurveyDAO();
ArrayList<SurveyQuestions> questionList = (ArrayList<SurveyQuestions>) surveyDao.getSurveyQuestions(surveyId);
return questionList;
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception: " + e.getMessage());
throw new AdException("Could not list the categories", e);
}
}
}
Can anyone help me with this please.

How to pass #RequestBody value to forwarded controller Spring MVC

I have to consume value of #RequestBody to forwarded controller. As I passed JSON as a request body and from one controller it will forward to another controller. But it second controller it gives java.io.IOException
MyController.java
#Controller
public class MyController {
/*
Request JSON like
{"personeId":"123789","personName":"Fitz"}
*/
#RequestMapping(value = "/myapp/first/", method = RequestMethod.POST,
consumes = { "application/json" })
public String authorize(#RequestBody Person person) {
//Looking good
if(Validator.validatePerson(perosn)) {
return "forward:/myapp/second/";
} else {
return "forward:/myapp/secondError/";
}
}
#RequestMapping(value = "/myapp/second/", method = RequestMethod.POST,
consumes = { "application/json" })
public #ResponseBody String login(#RequestBody Person person) {
// Not able to get Person object here.
// Getting java.io.IOException: Stream closed :(
System.out.println("---> "+person.getPersonName());
return "success";
}
#RequestMapping(value = "/myapp/secondError/", method = RequestMethod.POST,
consumes = { "application/json" })
public #ResponseBody String loginError() {
return "error";
}
}
StackTrace
org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet dispatcher threw exception
java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:94)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at java.io.PushbackInputStream.read(PushbackInputStream.java:139)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:168)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:721)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:466)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
at org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:168)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1228)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1011)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
So there is any way to achieve this scenario with Spring MVC.
you are getting the exception because #RequestBody annotation reads the underlying servlet input streams and consumes it, so you cannot read it twice.
If you look closer at the stack trace you can note the origin
org.apache.catalina.connector.InputBuffer.readByte(InputBuffer.java:339)
You are trying to (re)read the data from a stream that is closed.
If you want to keep the first controller as it now you must change the second, you can choose for example to redirect to the second controller and put the object in session or to extract a method from the second controller that does the business logic and call it from the first controller.
If you can put the json in a parameter of the http call (authorize) you can avoid this problem, but (authorize) it's not a REST ednpoint anymore, but something like a "simple" http integration.
You should not forward in that case, but simply call the other methods :
#RequestMapping(value = "/myapp/first/", method = RequestMethod.POST,
consumes = { "application/json" })
public String authorize(#RequestBody Person person) {
//Looking good
if(Validator.validatePerson(perosn)) {
return login(person);
} else {
return loginError();
}
}
And this would only have sense if /myapp/second/ and /myapp/secondError/ are real URLs, if not, and if methods login and loginError should only be called from authorize method, they should simply be private methods in the controller.
Of course, if it involved business rules, it should go in service layer.
I don't think your approach is ideal. I would have only one call to the controller, and then start delegating the different tasks to different services.
if(Validator.validatePerson(perosn)) {
return loginService.login(person);
} else {
return "error";
}
The accepted answer is correct, there is no proper solution.
However here's a workaround that worked for me. I wanted to build a dispatcher that takes in json and forwards the request internally based on a command field:
#Controller
public class StackoverflowExampleController {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
#PostMapping("/post")
public ModelAndView post(#RequestBody String body) {
JsonNode tree = OBJECT_MAPPER.readTree(body);
String command = tree.get("command").asText();
return new ModelAndView("forward:/" + command + "?json=" + URLEncoder.encode(body));
}
#PostMapping("/test")
#ResponseBody
public String test(#RequestParam String json) {
return json;
}
}

JERSEY File upload with jquery/AJAX

I want to upload a file with jersey via jquery/AJAX but I dont get it how to get the file from the input and send it with ajax.
Here is my Code so far:
html
<form action="rest/files/upload" method="post" enctype="multipart/form-data">
<p>
Select a file : <input type="file" name="file" size="50" />
</p>
<input type="submit" value="Upload It" />
</form>
jAVA
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition contentDispositionHeader) {
String filePath = SERVER_UPLOAD_LOCATION_FOLDER + contentDispositionHeader.getFileName();
// save the file to the server
saveFile(fileInputStream, filePath);
String output = "File saved to server location : " + filePath;
return Response.status(200).entity(output).build();
}
// save uploaded file to a defined location on the server
private void saveFile(InputStream uploadedInputStream,
String serverLocation) {
try {
OutputStream outpuStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
outpuStream = new FileOutputStream(new File(serverLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
outpuStream.write(bytes, 0, read);
}
outpuStream.flush();
outpuStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
The code is working with a normal submit in html.
I used this example: jersey file upload
here is my approach so far
var file = $('input[name="file"').get(0).files[0];
var formData = new FormData();
formData.append('file', file);
$.ajax({
url : '/OIS/rest/upload', //Server script to process data
type : 'POST',
data : formData,
cache : false,
contentType : 'multipart/form-data',
dataType : 'application/json',
processData : false,
success : function(data, textStatus, jqXHR) {
var userObj = JSON.parse(jqXHR.responseText);
alert(userObj);
},
error : function(jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});
but it´s throwing a nullpointer exception
Jan 31, 2015 12:51:46 PM org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet [Smart_Office] in context with path [/Smart_Office] threw exception
java.lang.NullPointerException
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.unquoteMediaTypeParameters(MultiPartReaderClientSide.java:244)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readMultiPart(MultiPartReaderClientSide.java:171)
at com.sun.jersey.multipart.impl.MultiPartReaderServerSide.readMultiPart(MultiPartReaderServerSide.java:80)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:157)
at com.sun.jersey.multipart.impl.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:85)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:490)
at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:555)
at com.sun.jersey.multipart.impl.FormDataMultiPartDispatchProvider$FormDataInjectableValuesProvider.getInjectableValues(FormDataMultiPartDispatchProvider.java:122)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1542)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1473)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1419)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1409)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:409)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:540)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:715)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
You server side source cose seams judicious as you have follow one of a well written tutorials, but as you have tried to mix code from this and that articles to bring an Ajaxified Upload with Jersey sample, that wouldn't work seamlessly.
The main issue I would note is being with content negociation between your server side endpoint and your client side code.
I won't get into Jersey internal and look for how that NPE would be thrown but I will suggest to update your client Ajax call to omit contentType handling, setting below properties to false:
contentType
processData
and ommitting the dataType property, so that resulting code will look as follows:
var file = $('input[name="file"').get(0).files[0];
var formData = new FormData();
formData.append('file', file);
$.ajax({
url : '/OIS/rest/upload',
type : 'POST',
data : formData,
cache : false,
contentType : false,
processData : false,
success : function(data, textStatus, jqXHR) {
var userObj = JSON.parse(jqXHR.responseText);
alert(userObj);
},
error : function(jqXHR, textStatus, errorThrown) {
alert(textStatus);
}
});

Spring MVC - AngularJS - File Upload - org.apache.commons.fileupload.FileUploadException

I have a Java Spring MVC Web application as server. And AngularJS based application as client.
In AngularJS, I have to upload a file and send to server.
Here is my html
<form ng-submit="uploadFile()" class="form-horizontal" enctype="multipart/form-data">
<input type="file" name="file" ng-model="document.fileInput" id="file" onchange="angular.element(this).scope().setTitle(this)" />
<input type="text" class="col-sm-4" ng-model="document.title" id="title" />
<button class="btn btn-primary" type="submit">
Submit
</button>
</form>
Here is my UploadController.js
'use strict';
var mainApp=angular.module('mainApp', ['ngCookies']);
mainApp.controller('FileUploadController', function($scope, $http) {
$scope.document = {};
$scope.setTitle = function(fileInput) {
var file=fileInput.value;
var filename = file.replace(/^.*[\\\/]/, '');
var title = filename.substr(0, filename.lastIndexOf('.'));
$("#title").val(title);
$("#title").focus();
$scope.document.title=title;
};
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http({
method: 'POST',
url: '/serverApp/rest/newDocument',
headers: { 'Content-Type': 'multipart/form-data'},
data: formData
})
.success(function(data, status) {
alert("Success ... " + status);
})
.error(function(data, status) {
alert("Error ... " + status);
});
};
});
It is going to the server. Here is my DocumentUploadController.java
#Controller
public class DocumentUploadController {
#RequestMapping(value="/newDocument", headers = "'Content-Type': 'multipart/form-data'", method = RequestMethod.POST)
public void UploadFile(MultipartHttpServletRequest request, HttpServletResponse response) {
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
System.out.println(fileName);
}
}
When I run this I get the following exception
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found] with root cause
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:954)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:892)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
In my applicationContext.xml, I have mentioned
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000" />
</bean>
I am using
spring - 3.2.1.RELAESE
commons-fileupload - 1.2.2
commons-io - 2.4
How to solve this?
It would be great if anyone tel me how to send file and other formdata from angularJS and get it in server.
UPDATE 1
#Michael : I can see this only in the console, when I click submit.
POST http://localhost:9000/serverApp/rest/newDocument 500 (Internal Server Error) angular.js:9499
(anonymous function) angular.js:9499
sendReq angular.js:9333
$http angular.js:9124
$scope.uploadFile invoice.js:113
(anonymous function) angular.js:6541
(anonymous function) angular.js:13256
Scope.$eval angular.js:8218
Scope.$apply angular.js:8298
(anonymous function) angular.js:13255
jQuery.event.dispatch jquery.js:3074
elemData.handle
My server is running in other port 8080. I am uisng yeoman,grunt and bower. So thin gruntfile.js I have mentioned the server port. So it goes to server and running that and throws the exception
UPDATE 2
The boundary is not setting
Request URL:http://localhost:9000/serverApp/rest/newDocument
Request Method:POST
Status Code:500 Internal Server Error
Request Headers view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:792
Content-Type:multipart/form-data
Cookie:ace.settings=%7B%22sidebar-collapsed%22%3A-1%7D; isLoggedIn=true; loggedUser=%7B%22name%22%3A%22admin%22%2C%22password%22%3A%22admin23%22%7D
Host:localhost:9000
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
------WebKitFormBoundaryCWaRAlfQoZEBGofY
Content-Disposition: form-data; name="file"; filename="csv.csv"
Content-Type: text/csv
------WebKitFormBoundaryCWaRAlfQoZEBGofY--
Response Headers view source
connection:close
content-length:5007
content-type:text/html;charset=utf-8
date:Thu, 09 Jan 2014 11:46:53 GMT
server:Apache-Coyote/1.1
I faced the same issue and encountered the same issue even after updating the transformRequest. 'Some how, the header boundary doesn't seem to have set correctly.
Following http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs, the problem is resolved. Extract from the location....
By setting ‘Content-Type’: undefined, the browser sets the Content-Type to multipart/form-data for us and fills in the correct boundary. Manually setting ‘Content-Type’: multipart/form-data will fail to fill in the boundary parameter of the request.
Not sure if this helps any one but perhaps makes it easy for people looking at this post... At least, it makes it less difficult.
Introduction
I have had the same problem and found a complete solution to send both json and file from angular based page to a Spring MVC method.
The main problem is the $http which doesn't send the proper Content-type header (I will explain why).
The theory about multipart/form-data
To send both json and file we need to send a multipart/form-data, which means "we send different items in the body separated by a special separator". This special separator is called "boundary", which is a string that is not present in any of the elements that are going to be sent.
The server needs to know which boundary is being used so it has to be indicated in the Content-type header (Content-Type multipart/form-data; boundary=$the_boundary_used).
So... two things are needed:
In the header --> indicate multipart/form-data AND which boundary is used (here is where $http fails)
In the body --> separate each request parameter with the boundary
Example of a good request:
header
Content-Type multipart/form-data; boundary=---------------------------129291770317552
Which is telling the server "I send a multipart message with the next separator (boundary): ---------------------------129291770317552
body
-----------------------------129291770317552 Content-Disposition: form-data; name="clientInfo"
{ "name": "Johny", "surname":"Cash"}
-----------------------------129291770317552
Content-Disposition: form-data; name="file"; filename="yourFile.pdf"
Content-Type: application/pdf
%PDF-1.4
%õäöü
-----------------------------129291770317552 --
Where we are sending 2 arguments, "clientInfo" and "file" separated by the boundary.
The problem
If the request is sent with $http, the boundary is not sent in the header (point 1), so Spring is not able to process the data (it doesn't know how to split the "parts" of the request).
The other problem is that the boundary is only known by the FormData... but FormData has no accesors so it's impossible to know which boundary is being used!!!
The solution
Instead of using $http in js you should use standard XMLHttpRequest, something like:
//create form data to send via POST
var formData=new FormData();
console.log('loading json info');
formData.append('infoClient',angular.toJson(client,true));
// !!! when calling formData.append the boundary is auto generated!!!
// but... there is no way to know which boundary is being used !!!
console.log('loading file);
var file= ...; // you should load the fileDomElement[0].files[0]
formData.append('file',file);
//create the ajax request (traditional way)
var request = new XMLHttpRequest();
request.open('POST', uploadUrl);
request.send(formData);
Then, in your Spring method you could have something like:
#RequestMapping(value = "/", method = RequestMethod.POST)
public #ResponseBody Object newClient(
#RequestParam(value = "infoClient") String infoClientString,
#RequestParam(value = "file") MultipartFile file) {
// parse the json string into a valid DTO
ClientDTO infoClient = gson.fromJson(infoClientString, ClientDTO.class);
//call the proper service method
this.clientService.newClient(infoClient,file);
return null;
}
Carlos Verdes's answer failed to work with my $http interceptor, which adds authorization headers and so on. So I decided to add to his solution and create mine using $http.
Clientside Angular (1.3.15)
My form (using the controllerAs syntax) is assuming a file and a simple object containing the information we need to send to the server. In this case I'm using a simple name and type String property.
<form>
<input type="text" ng-model="myController.myObject.name" />
<select class="form-control input-sm" ng-model="myController.myObject.type"
ng-options="type as type for type in myController.types"></select>
<input class="input-file" file-model="myController.file" type="file">
</form>
The first step was to create a directive that binds my file to the scope of the designated controller (in this case myController) so I can access it. Binding it directly to a model in your controller won't work as the input type=file isn't a built-in feature.
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Secondly I created a factory called myObject with an instance method create that allows me to transform the data upon invoking create on the server. This method adds everything to a FormData object and converts it using the transformRequest method (angular.identity). It is crucial to set your header to undefined. (Older Angular versions might require something than undefined to be set). This will allow the multidata/boundary marker to be set automatically (see Carlos's post).
myObject.prototype.create = function(myObject, file) {
var formData = new FormData();
formData.append('refTemplateDTO', angular.toJson(myObject));
formData.append('file', file);
return $http.post(url, formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined }
});
}
All that is left to do client side is instantiating a new myObject in myController and invoking the create method in the controller's create function upon submitting my form.
this.myObject = new myObject();
this.create = function() {
//Some pre handling/verification
this.myObject.create(this.myObject, this.file).then(
//Do some post success/error handling
);
}.bind(this);
Serverside Spring (4.0)
On the RestController I can now simply do the following: (Assuming we have a POJO MyObject)
#RequestMapping(method = RequestMethod.POST)
#Secured({ "ROLE_ADMIN" }) //This is why I needed my $httpInterceptor
public void create(MyObject myObject, MultipartFile file) {
//delegation to the correct service
}
Notice, I'm not using requestparameters but just letting spring do the JSON to POJO/DTO conversion. Make sure you got the MultiPartResolver bean set up correctly too and added to your pom.xml. (And Jackson-Mapper if needed)
spring-context.xml
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="268435456" /> <!-- 256 megs -->
</bean>
pom.xml
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
You can try this
.js
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http.post('/serverApp/rest/newDocument', formData, {
transformRequest: function(data, headersGetterFunction) {
return data;
},
headers: { 'Content-Type': undefined }
}).success(function(data, status) {
alert("Success ... " + status);
}).error(function(data, status) {
alert("Error ... " + status);
});
.java
#Controller
public class DocumentUploadController {
#RequestMapping(value="/newDocument", method = RequestMethod.POST)
public #ResponseBody void UploadFile(#RequestParam(value="file", required=true) MultipartFile file) {
String fileName=file.getOriginalFilename();
System.out.println(fileName);
}
}
That's based on https://github.com/murygin/rest-document-archive
There is a good example of file upload
https://murygin.wordpress.com/2014/10/13/rest-web-service-file-uploads-spring-boot/

Categories

Resources