Uploading a file in SpringMVC via ajax - java

First of all I was searching and trying many ways which are described on stackoverflow but it still doesn't work.
I can't upload any file via ajax and SpringMVC. Here is my code. What can be wrong?
Dynamic Web Module 2.5
Spring 4
tomcat 6
jsp code:
<input type="file" id="myName" name="myName" /><br>
<input type="button" value="Upload" onclick="uploadMeNow()"/>
dependencies connected to uploading:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
javascript:
function uploadMeNow() {
var file = new FormData($("#myName"));
$.ajax({
url : "/m61/uploadMe",
data : {file: file},
type : "POST",
processData: false,
contentType: false,
cache: false,
success : function(response) {
if (response.indexOf("saved") >= 0) {
alert('ok')
}
},
error : function (xhr, status, error) {
alert(xhr.responseText);
if (xhr.responseText.indexOf("failed") >= 0) {
alert('not ok')
}
}
});
}
xml:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="20971520" />
<property name="maxInMemorySize" value="1048576" />
</bean>
controller:
#RequestMapping(value = "/uploadMe", method = RequestMethod.POST)
#ResponseBody
public String uploadMe(#RequestParam("file") MultipartFile file) {
System.out.println("aaa");
return "saved";
}
A result: the current request is not a multipart request.
I was also trying by adding to ajax:
headers: {'Content-type':'multipart/form-data'},
result: the request was rejected because no multipart boundary was found
Please help me.

Related

No converter found for return value of type: class org.json.JSONArray

I want to return a JSONArray(org.json.jar) object from spring controller method, this is my java spring controller :
import org.json.JSONArray;
import org.json.JSONException;
#RestController
public class BICOntroller{
#RequestMapping(value="/getStatus", method = RequestMethod.GET)
public ResponseEntity<JSONArray> getStatus() throws JSONException{
ResponseEntity<JSONArray> response = null;
JSONArray arr = new JSONArray();
JSONObject obj = new JSONObject();
//process data
arr.put(obj);
response = new ResponseEntity<JSONArray>(arr, HttpStatus.OK);
return response;
}
}
Angular js call :
$http({
url: 'getStatus',
method: 'GET',
responseType: 'json'
}).then(function(response){
console.log(response);
return response;
}, function(error){
console.log(error);
return error;
});
This gives 500 error :
java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONArray
I have included jackson-core-2.7.5.jar and jackson-databind-2.7.5.jar in the class path.
Thanks!
Adding the dependencies did not work for me. What did work is converting the JSONArray to String.
FYI I am using Spring Boot Application and was trying to return a JSONArray.
Apart from adding dependencies, you may need this.
If you are not using spring boot, update your spring xxx-servlet.xml with message converters for JSON.
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
if you are using spring boot, adding dependencies in pom.xml alone will suffice.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>

Java Spring MVC Controller is not redirecting modelandview

An AJAX-call is done to the Controller:
$.ajax({
cache : false,
type : "POST",
url : url,
data : {
//some data
}
That call is successfully interpreted by the controller:
#RequestMapping(value = "/checkIfRatedOverall")
public ModelAndView checkIfRatedOverall(#ReqestParam.......)
But when i return the ModelAndView nothing happens!
The view stays the same and the browser does not display xxx.jsp
return new ModelAndView("xxx"); //NOTHING HAPPENS
LOG:
JstlView:166 - Forwarding to resource [/WEB-INF/views/xxx.jsp] in InternalResourceView 'xxx'
DispatcherServlet:1251 - Rendering view [org.springframework.web.servlet.view.JstlView: name 'xxx'
DispatcherServlet:1000 - Successfully completed request
your internal view resolver should be like this
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
Check ajax documentation here
$.ajax({ ...}).done(
function( html ) {
$( "#results" ).append( html );
});
What you do with the ajax response? From what I see you are doing nothing with server response.
Use #ResponseBody Attribute and return JSON object instead of model view
#RequestMapping(value = "checkIfRatedOverall", method = RequestMethod.POST)
public #ResponseBody String checkIfRatedOverall(#ReqestParam.......)
{
return jsonStr://return json string
}
In jquery parse the string with JSON.parse(data)
$.ajax({
cache : false,
type : "POST",
url : url,
data : {
//some data
},
success : function(data) {
JSON.parse(data);
}
});

Returning a simple map structure from spring mvc controller to ajax

I am using spring mvc 4 and trying to return a simple map to ajax - from my controller to jsp file.
The controller:
#RequestMapping(value = "/ajaxtest", method = RequestMethod.GET)
public #ResponseBody
Map<String, String> myTest() {
System.out.println("------------------------------------test");
Map<String,String> myMap = new HashMap<String, String>();
myMap.put("a", "1");
myMap.put("b", "2");
return myMap;
}
Ajax from the jsp file:
function testAjax() {
$.ajax({
url : '../../ajaxtest.html',
dataType: "json",
contentType: "application/json;charset=utf-8",
success : function(data) {
alert("1");
alert(data);
}
});
}
But I am not getting any alert but just the error HTTP/1.1 406 Not Acceptable.
However, changing the code to return a simple string works fine.
Controller:
#RequestMapping(value = "/ajaxtest", method = RequestMethod.GET)
public #ResponseBody
String myTest() {
System.out.println("------------------------------------test");
return "hello";
}
Ajax:
function testAjax() {
$.ajax({
url : '../../ajaxtest.html',
success : function(data) {
alert("1");
alert(data);
}
});
}
Alerting 1 and hello from ajax as expected.
I added the jackson jar files as expected (by pom.xml):
dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.5.1</version>
</dependency>
Am I missing something?
I just want to return a simple mapping structure (or other class structure in the future).
Update:
From spring console (Don't sure it's related):
Resolving exception from handler [null]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
Thanks in advance!
Mike
I don't know if it the correct way but I solved it as following.
In the controller, I converted the map to json:
#RequestMapping(value = "/ajaxtest", method = RequestMethod.GET)
public #ResponseBody
String myTest() {
System.out.println("------------------------------------random");
Map<String,String> myMap = new HashMap<String, String>();
myMap.put("a", "1");
myMap.put("b", "2");
ObjectMapper mapper = new ObjectMapper();
String json = "";
try {
json = mapper.writeValueAsString(myMap);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return json;
}
and in the jsp:
function testAjax() {
$.ajax({
url : '../../ajaxtest.html',
type:"GET",
contentType: "application/json;charset=utf-8",
success : function(data) {
alert("1");
alert(data);
var obj = jQuery.parseJSON( data );
alert(obj.a);
alert(obj.b);
}
});
Thanks you all!
Mike
}
Try to add consumes="application/json" and produces={ "application/json"} to the #RequestMapping to let spring process your json
UPDATE 406 error description
HTTP Error 406 Not acceptable
Introduction
A client (e.g. your Web browser or our CheckUpDown robot) can indicate to the Web server (running the Web site) the characteristics of the data it will accept back from the Web server. This is done using 'accept headers' of the following types:
Accept: The MIME types accepted by the client. For example, a browser may only accept back types of data (HTML files, GIF files etc.) it knows how to process.
Accept-Charset: The character sets accepted by the client.
Accept-Encoding: The data encoding accepted by the client e.g. the file formats it understands.
Accept-Language: The natural languages (English, German etc.) accepted by the client.
Accept-Ranges: Whether the client accepts ranges of bytes from the resource i.e. a portion of the resource.
If the Web server detects that the data it wants to return is not acceptable to the client, it returns a header containing the 406 error code.
It means you somehow should change your server logic to accept MIME/Charset/Encoding etc. of the request you sent from client. Can't say exactly what's wrong but try to play with headers and consumes of the RequestMapping.
Your "problem" is due to your request ending in .html. You need to add the following configuration to make it work as you expect
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="defaultContentType" value="application/json" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
and than do as #StanislavL suggested add the produces={ "application/json"} don't add the consumes cause your not posting any JSON
an explanation
When spring determines the representation to which it converts it first looks at the path part of the request (e.g. .html, .json, .xml), than it looks for a parameter explicitly setting the conversion representation, finally goes for an Accept header (the so call PPA strategy)
that is why your example works
function testAjax() {
$.ajax({
url : '../../ajaxtest.html',
success : function(data) {
alert("1");
alert(data);
}
});
}
you're getting HTML back. However with the request
function testAjax() {
$.ajax({
url : '../../ajaxtest.html',
dataType: "json",
contentType: "application/json;charset=utf-8",
success : function(data) {
alert("1");
alert(data);
}
});
}
you're explicitly saying that you expect JSON back from the server, however, .html is hinting that it should be HTML instead, and you end up in problems
To learn the details of the content negotiation strategy you should read this blog, its almost famous by now :) It will also show you the pure java config version
Your Ajax call should something similar to:
$("#someId" ).click(function(){
$.ajax({
url:"getDetails",
type:"GET",
contentType: "application/json; charset=utf-8",
success: function(responseData){
console.log(JSON.stringify(responseData));
// Success Message Handler
},error:function(data,status,er) {
console.log(data)
alert("error: "+data+" status: "+status+" er:"+er);
}
});
});
Spring Controller Code should be as below :
#RequestMapping(value="/getDetails",method=RequestMethod.GET)
public #ResponseBody Map<String,String> showExecutiveSummar(){
Map<String,String> userDetails = new HashMap<String,String>();
userDetails .put("ID","a" );
userDetails .put("FirstName","b" );
userDetails .put("MiddleName","c" );
userDetails .put("LastName","d" );
userDetails .put("Gender","e" );
userDetails .put("DOB","f" );
return userDetails
}
You can also refer to this link for understanding the library which support this functionality.
Try this:
$.ajax({
type:"GET",
url: "/ajaxtest",
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function(data){
alert("1");
alert(data);
}
});
You need this dependency :
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version></version>
</dependency>
Add this if already haven't :
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>

HTTP 406 Error Occured Upgrade to Spring MVC 4.1 Using JSON

After upgrade to Spring MVC 4.1.1, when I using JSON, it will occur HTTP 406 error.
pom.xml
<!-- JSON Support -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
Controller.java
#RequestMapping(value = "/login.action", method = RequestMethod.POST)
public #ResponseBody HashMap<String, Boolean> loginAction(
#RequestParam(value="username", required=true) String username,
#RequestParam(value="password", required=true) String password,
HttpServletRequest request,
HttpSession session,
Model model) {
String ipAddress = request.getRemoteAddr();
HashMap<String, Boolean> result = getLoginResult(username, password);
logger.info(String.format("User: [Username=%s] tried to log in at %s", new Object[] {username, ipAddress}));
if ( result.get("isSuccessful") ) {
getSession(request, session, this.user);
}
return result;
}
login.jsp
<script type="text/javascript">
function doLoginAction(username, password) {
var postData = 'username=' + username + '&password=' + password;
$.ajax({
type: 'POST',
url: '<c:url value="/accounts/login.action" />',
data: postData,
dataType: 'JSON',
success: function(result){
console.log(result);
return processLoginResult(result);
}
});
}
</script>
The log message will output to the console normally.
And the code works fine in Spring MVC 4.0.5.
Do you know how to solve it? Thanks a lot.
Upgrading Jackson's version should fix this issue.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
See the Spring migration wiki on github.

File Image to Servlet Fails

I am trying to upload an image to a servlet, but every once and a while during automated testing, it silently fails.
Do you guys know what would cause this?
Here is the code on the server:
#ResponseBody
#RequestMapping(method = RequestMethod.POST)
public String upload(HttpServletRequest request) throws Exception {
BufferedImage image = null;
#SuppressWarnings("unchecked")
List<FileItem> items = new ServletFileUpload(
new DiskFileItemFactory()).parseRequest(request);
Logger.log(LogLevel.INFO, "Upload contains " + items.size()
+ " items.");
int i = 0;
for (FileItem item : items) {
Logger.log(LogLevel.INFO, "\tItem " + (i++) + ". Name:\t"
+ item.getName() + ", Type:\t" + item.getContentType());
// File is of type "file"
if (!item.isFormField()) {
InputStream inputStream = null;
try {
inputStream = item.getInputStream();
if (inputStream.available() == 0) {
Logger.log(LogLevel.WARN,
"Item shows file type, but no bytes are available");
}
image = ImageIO.read(inputStream);
if (image != null) {
break;
}
} catch (Exception e) {
Logger.log(LogLevel.ERROR,
"There was an error reading the image. "
+ ExceptionUtils.getFullStackTrace(e));
throw new Exception("image provided is not a valid image");
} finally {
if (inputStream != null) {
IOUtils.closeQuietly(inputStream);
}
}
}
}
if (image == null) {
Logger.log(LogLevel.ERROR, "Image was supposedly read correctly, but was null afterwards");
throw new Exception("Image provided could not be read");
}
//do stuff with image
...
}
Here is the test:
public void testImageUpload throws Exception {
HttpPost httppost = new HttpPost("path/to/endpoint");
File file=new File(imgLoc);
FileBody bin = new FileBody(file);
StringBody comment = new StringBody("Filename: " + file);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("upload-file", bin);
reqEntity.addPart("comment", comment);
httppost.setHeader("Accept", "application/json");
httppost.setHeader("Connection","Keep-Alive");
httppost.setEntity(reqEntity);
HttpResponse response =testClient.getClient().execute(httppost);
imgResponse=response.getStatusLine().toString();
System.out.println(imgResponse);
BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line;
while ((line = reader.readLine()) != null){
output = output + " " +line;}
System.out.println("Image Response: "+output);
}
Here is the output from the server when it fails:
2013/10/02 05-53-32,287::LOG:INFO[com.example#upload:L130 -- Upload contains 2 items.]
2013/10/02 05-53-32,288::LOG:INFO[com.example#upload:L133 -- Item 0. Name: Dog.jpg, Type: application/octet-stream]
2013/10/02 05-53-32,288::LOG:WARN[com.example#upload:L140 -- Item shows file type, but no bytes are available]
2013/10/02 05-53-32,289::LOG:INFO[com.example#upload:L133 -- Item 1. Name: null, Type: text/plain; charset=ISO-8859-1]
2013/10/02 05-53-32,290::LOG:ERROR[com.example#upload:L159 -- Image was supposedly read correctly, but was null afterwards]
We catch the exception from the image upload and send back a response code of 422 back to the client, so on the test, we get imgResponse==422 which is a failure case.
Note: this only happens sometimes you run the test.
Here is step by step configuration for file uploading by using Apache Commons FileUpload:
1. Add dependency jars for the following component. Here is the maven dependencies:
pom.xml
<dependencies>
<!-- Spring 3 MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<!-- Apache Commons file upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- JSTL for c: tag -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
If you are not using maven then download respective jar from the maven repository online.
2. Create a FileUploadForm model
FileUploadForm.java
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class FileUploadForm {
private List<MultipartFile> files;
//Getter and setter methods
}
3. Add resolver to MVC config file
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
4. Write FileUploadController
FileUploadController.java
#Controller
public class FileUploadController {
     
    #RequestMapping(value = "/show", method = RequestMethod.GET)
    public String displayForm() {
        return "file_upload_form";
    }
     
    #RequestMapping(value = "/save", method = RequestMethod.POST)
    public String save(
            #ModelAttribute("uploadForm") FileUploadForm uploadForm,
                    Model map) {
         
        List<MultipartFile> files = uploadForm.getFiles();
 
        List<String> fileNames = new ArrayList<String>();
         
        if(null != files && files.size() > 0) {
            for (MultipartFile multipartFile : files) {
 
                String fileName = multipartFile.getOriginalFilename();
                fileNames.add(fileName);
                //Handle file content - multipartFile.getInputStream()
 
            }
        }
         
        map.addAttribute("files", fileNames);
        return "file_upload_success";
    }
}
5. Write jsp views
file_upload_form.jsp
<html>
<head>
<title>Spring MVC Multiple File Upload</title>
<script
src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
//add more file components if Add is clicked
$('#addFile').click(function() {
var fileIndex = $('#fileTable tr').children().length - 1;
$('#fileTable').append(
'<tr><td>'+
' <input type="file" name="files['+ fileIndex +']" />'+
'</td></tr>');
});
});
</script>
</head>
<body>
<h1>Spring Multiple File Upload example</h1>
<form method="post" action="save.html"
**enctype="multipart/form-data"**>
<p>Select files to upload. Press Add button to add more file inputs.</p>
<input id="addFile" type="button" value="Add File" />
<table id="fileTable">
<tr>
<td><input name="files[0]" type="file" /></td>
</tr>
<tr>
<td><input name="files[1]" type="file" /></td>
</tr>
</table>
<br/><input type="submit" value="Upload" />
</form>
</body>
</html>
Reference: http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-multipart
It seems your content type is application/octet-stream. Please add the below Header in your request and give a try
("Content-Type", "multipart/form-data");
You are using InputStream#available. As the documentation states this is the number of bytes that can be read from the stream without blocking. Now, how many bytes are available from the TCP input stream depends on the size of the the packets and how your request is sliced amongst them (and a lot more other factors).
If your intention is to always read the stream in full, forget the available() method, just read it out until the end of stream and you should be fine.
I've come across this before under two conditions. Once was when I ran low on disk space and the other was when I was doing a bit of load test.
If you take a look at the How it works page, you can make the tool dump items to disk or keep them in memory. Under one case I filled up the drive during testing and the other I was keeping items in memory but the load blew my memory limit.
How do you have it set up? How big is the image you are using to test? How many times do yo upload it during your tests? With this info, I should be able to help a bit more.
This code is used on my site currently, works like a charm:
package com.example;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
#Controller
#RequestMapping("/api/media")
public class ImageRestService {
private static final Logger LOG = LoggerFactory.getLogger(ImageRestService.class);
#RequestMapping(value = "/uploadtemp", method = RequestMethod.POST)
public String upload(#RequestParam(value = "image") MultipartFile image) {
try {
BufferedImage bufferedImage = ImageIO.read(image.getInputStream());
// process image here
} catch (IOException e) {
LOG.error("failed to process image", e);
return "failure/view/name";
}
return "success/view/name";
}
}
Maybe the order of the items list is not fixed (timing dependent?). Your code
if (image != null) {
break;
}
quits the loop instead of trying the next parts. In the comments you state we iterate through the files until we can parse one, which should read
if (image != null) {
continue;
}
then.

Categories