4
votes

I'm trying to insert and/or update data into the database using the PUT method via JSON using jQuery 1.6, (Jackson 2.1.1 and Spring 3.2.0).

The JS code is as follows.

 var itemsArray=[];
 var id;

function insertOrUpdate()
{
    var i=0;

    $('input[name="txtCharge[]"]').each(function()
    {
        isNaN($(this).val())||$(this).val()==''?itemsArray[i][2]='':itemsArray[i][2]=$(this).val();
        i++;
    });                

    $.ajax({
        headers: { 
            'Accept': 'application/json',
            'Content-Type': 'application/json' 
        },
        datatype:"json",
        type: "PUT",
        url: "/wagafashion/ajax/InsertZoneCharge.htm",
        data: "items=" + JSON.stringify(itemsArray)+"&zoneId="+id+"&t="+new Date().getTime(),
        success: function(response)
        {
            alert(response);
        },
        error: function(e)
        {
            alert('Error: ' + e);
        }
    });
}

The method inside the Spring controller which is mapped with the URL is as follows.

@RequestMapping(value=("ajax/InsertZoneCharge"), method=RequestMethod.PUT, produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String insertZoneCharge(@RequestBody final MultiValueMap<String, String > data, final HttpServletResponse response, HttpServletRequest request)
{
    String message="";
    try
    {
        Map<String, String> params = data.toSingleValueMap();
        if(params.get("zoneId")==null||params.get("zoneId").equals("")||params.get("items")==null||params.get("items").equals(""))
        {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        }
        else
        {
            message=zoneChargeService.insertZoneCharge(params.get("zoneId"), params.get("items"));
        }
    }
    catch (IOException ex)
    {
        message="An error occured. Data can not be saved.";
        Logger.getLogger(ZoneCharge.class.getName()).log(Level.SEVERE, null, ex);
    }

    return message;
}

The server responds as the question implies,

415 Unsupported Media Type

The header information looks like the following.

Request URL:http://localhost:8080/wagafashion/ajax/InsertZoneCharge.htm
Request Method:PUT
Status Code:415 Unsupported Media Type
Request Headersview source
Accept:application/json
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:352
Content-Type:application/json
Cookie:JSESSIONID=72AAFCC832C29D14FFA937D00D428A81
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/wagafashion/admin_side/ZoneCharge.htm
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17
X-Requested-With:XMLHttpRequest
Request Payload
items=[[1,10,"12.35"],[2,10.5,"16.00"],[3,11,"20.00"],[4,11.5,"30.00"],[5,12,"40.00"],[6,12.5,"50.00"],[7,13,"60.00"],[8,13.5,"70.00"],[9,14,""],[10,14.5,""],[11,15,""],[12,15.5,""],[13,16,""],[14,16.5,""],[15,17,""],[16,17.5,""],[17,18,""],[18,18.5,""],[19,19,""],[20,19.5,""],[24,20,""],[25,20.5,""],[26,21,""],[41,21.5,""]]&zoneId=45&t=1359485680332
Response Headersview source
Content-Length:1048
Content-Type:text/html;charset=utf-8
Date:Tue, 29 Jan 2013 18:54:40 GMT
Server:Apache-Coyote/1.1

The entire dispatcher-servlet.xml file is as follows.

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">


    <context:component-scan base-package="controller" />
    <context:component-scan base-package="validatorbeans" />

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" >
        <mvc:message-converters register-defaults="false">
        <bean id="jacksonMessageConverter"
              p:supportedMediaTypes="application/json"
              class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </mvc:message-converters>
    </mvc:annotation-driven>

    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="mediaTypes" >
            <value>
                atom=application/atom+xml
                html=text/html
                json=application/json
                *=*/*
            </value>
        </property>                    
    </bean>


    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>
            </props>
        </property>
    </bean>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />
</beans>

It works when I remove @RequestBody final MultiValueMap<String, String > data, a method parameter and simply use @PathVariable to accept request parameters.

5
"It works when ..." Do you then actually see the String changed into some JSON structure? And what if you add <property name="defaultContentType" value="application/json" />, or if you remove register-defaults="false" from <mvc:message-converters register-defaults="false">?Arjan
@Arjan - Tried both the ways still not working unfortunately.Tiny
See also the comments at CodeChimp's answer!Arjan
So am I dealing with wrong request payload?Tiny
Above, data: "items=" + JSON.stringify(itemsArray)+"&zoneId="+id+"&t="+new Date().getTime() indeed is not JSON. Well, the value of items is JSON, but the full payload itself has multiple parameters, like items and zoneId and is not pure JSON. That's very much okay if you're sending it as application/x-www-form-urlencoded though (which is the jQuery default). As an aside, note that you can also have jQuery create the content for you: {items: ..., id: ...}.Arjan

5 Answers

7
votes

The content type that the browser sends, Content-Type: application/json, does not seem to match @RequestBody final MultiValueMap<String, String > data.

Either:

1
votes

I had the same problem, the way to solve it was removing @RequestBody and then taking the data from the request (with IOUtils from apache commons). It should be noted that I used the received data just for logging js errors.

/**
 * this method logs with log4j the received js errors 
 */
@RequestMapping(value = "/jsloggerservice/{applicationName}", method = RequestMethod.POST)
public void jsLogger(HttpServletRequest request, HttpServletResponse response) {
    try {
        String message = IOUtils.toString( request.getInputStream());
        log.info("JAVASCRIPT-ERROR: " + message);
        response.getWriter().write("OK");
    } 
    catch (UnsupportedEncodingException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
0
votes

In the server side, in Spring 3, you need this:

<bean id = "mappingJacksonHttpMessageConverter" class = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />

<!-- starting Spring MVC annotation usage,handling request and annotation pojo mapping-->
<bean class ="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
    <property name= "messageConverters" >
         <list>
            <ref bean= "mappingJacksonHttpMessageConverter"/>
         </list>
    </property>
</bean>

Spring 4 uses mappingJackson2HttpMessageConverter. Without AnnotationMethodHandlerAdapter bean declaration, you can also use @RequestBody, while by declaring it we can set mappingJackson2HttpMessageConverter to messageConverters. This is concluded by phenomena that I observed, if wrong please correct.

-1
votes

I think your browser is not supporting whatever your returning. An explaination of an HTTP 415 seems to indicate this. What is the server sending as the Content-Type in the response?

-1
votes

Just in case somebody encounters this: I had two Methods

void setLevel (Level level) void setLevel (String level)

in the Class annotated with @RequestBody and that also caused a 415.