JQuery, Spring MVC @RequestBody und JSON - damit es zusammenarbeitet

70

Ich hätte gerne eine bidirektionale JSON-zu-Java-Serialisierung

Ich verwende erfolgreich den Pfad von Java zu JSON zu JQuery ... ( @ResponseBody) z

@RequestMapping(value={"/fooBar/{id}"}, method=RequestMethod.GET)
     public @ResponseBody FooBar getFooBar(
            @PathVariable String id,
            HttpServletResponse response , ModelMap model) {
        response.setContentType("application/json");
...
}

und In JQuery verwende ich

$.getJSON('fooBar/1', function(data) {
    //do something
});

Dies funktioniert gut (zB Anmerkungen funktionieren bereits, danke an alle Antwortenden)

Wie mache ich jedoch den umgekehrten Pfad: Muss JSON mithilfe von RequestBody wieder in ein Java-Objekt serialisiert werden?

Egal was ich versuche, ich kann so etwas nicht zum Laufen bringen:

@RequestMapping(value={"/fooBar/save"}, method=RequestMethod.POST)
public String saveFooBar(@RequestBody FooBar fooBar,
        HttpServletResponse response , ModelMap model) {

  //This method is never called. (it does when I remove the RequestBody...)
}

Ich habe Jackson richtig konfiguriert (es wird auf dem Weg nach draußen serialisiert) und ich habe MVC als Annotationen eingestellt, die natürlich gesteuert werden

Wie bringe ich es zum Laufen? ist es überhaupt möglich? oder ist Spring / JSON / JQuery oneway (out)?


Aktualisieren:

Ich habe diese Jackson-Einstellung geändert

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

<!-- Bind the return value of the Rest service to the ResponseBody. -->
<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <util:list id="beanList">
            <ref bean="jsonHttpMessageConverter" />
<!--            <ref bean="xmlMessageConverter" /> -->              
        </util:list>
    </property>
</bean>

Zu dem (fast ähnlichen) vorgeschlagenen

<bean id="jacksonMessageConverter"
    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> 

Und es scheint zu funktionieren! Ich weiß nicht genau, was den Trick gemacht hat, aber es funktioniert ...

Eran Medan
quelle
Ich habe die Frage hier besser umformuliert : stackoverflow.com/questions/5930894/… (Ich werde diese schließen, da sie zu lang und unklar zu sein scheint)
Eran Medan
Es sieht so aus, als würde es nicht aufgerufen, weil Sie ein GET durchführen, aber Ihre Methode ist ein POST.
Egervari

Antworten:

100

Ich bin mir ziemlich sicher, dass Sie sich nur registrieren müssen MappingJacksonHttpMessageConverter

(Der einfachste Weg, dies zu tun, ist <mvc:annotation-driven />in XML oder @EnableWebMvcin Java )

Sehen:


Hier ist ein Arbeitsbeispiel:

Maven POM

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion><groupId>test</groupId><artifactId>json</artifactId><packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version><name>json test</name>
    <dependencies>
        <dependency><!-- spring mvc -->
            <groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>3.0.5.RELEASE</version>
        </dependency>
        <dependency><!-- jackson -->
            <groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.4.2</version>
        </dependency>
    </dependencies>
    <build><plugins>
            <!-- javac --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version><configuration><source>1.6</source><target>1.6</target></configuration></plugin>
            <!-- jetty --><plugin><groupId>org.mortbay.jetty</groupId><artifactId>jetty-maven-plugin</artifactId>
            <version>7.4.0.v20110414</version></plugin>
    </plugins></build>
</project>

im Ordner src / main / webapp / WEB-INF

web.xml

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">
    <servlet><servlet-name>json</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>json</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

json-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="classpath:mvc-context.xml" />

</beans>

im Ordner src / main / resources:

mvc-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <mvc:annotation-driven />
    <context:component-scan base-package="test.json" />
</beans>

Im Ordner src / main / java / test / json

TestController.java

@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping(method = RequestMethod.POST, value = "math")
    @ResponseBody
    public Result math(@RequestBody final Request request) {
        final Result result = new Result();
        result.setAddition(request.getLeft() + request.getRight());
        result.setSubtraction(request.getLeft() - request.getRight());
        result.setMultiplication(request.getLeft() * request.getRight());
        return result;
    }

}

Request.java

public class Request implements Serializable {
    private static final long serialVersionUID = 1513207428686438208L;
    private int left;
    private int right;
    public int getLeft() {return left;}
    public void setLeft(int left) {this.left = left;}
    public int getRight() {return right;}
    public void setRight(int right) {this.right = right;}
}

Result.java

public class Result implements Serializable {
    private static final long serialVersionUID = -5054749880960511861L;
    private int addition;
    private int subtraction;
    private int multiplication;

    public int getAddition() { return addition; }
    public void setAddition(int addition) { this.addition = addition; }
    public int getSubtraction() { return subtraction; }
    public void setSubtraction(int subtraction) { this.subtraction = subtraction; }
    public int getMultiplication() { return multiplication; }
    public void setMultiplication(int multiplication) { this.multiplication = multiplication; }
}

Sie können dieses Setup testen, indem Sie es mvn jetty:runin der Befehlszeile ausführen und anschließend eine POST-Anforderung senden:

URL:        http://localhost:8080/test/math
mime type:  application/json
post body:  { "left": 13 , "right" : 7 }

Ich habe dazu das Poster Firefox Plugin verwendet.

So sieht die Antwort aus:

{"addition":20,"subtraction":6,"multiplication":91}
Sean Patrick Floyd
quelle
9
oder benutze <mvc:annotation-driven>ich denke.
Bozho
1
@Eran, Haben Sie log4j ausprobiert? Es wird eine Serialisierungsausnahme oder ein Fehler vom Controller angezeigt.
danny.lesnik
1
Keine Ausnahme in log4j, ich bin kurz davor aufzugeben ... gibt es da draußen ein funktionierendes Beispiel, von dem ich ausgehen kann? (Ein einfacher Antwort- / Anfragetext + JSON / JQuery-Test?)
Eran Medan
2
@Eran Ich weiß, dass Sie Ihr Problem in der Zwischenzeit gelöst haben, aber ich habe jetzt ein funktionierendes Beispiel zu meiner Antwort hinzugefügt
Sean Patrick Floyd
3
@ SeanPatrickFloyd Wonderful. Das ist wirklich klar. Trotzdem bemerkte ich ein kleines Problem, das auftauchte, als ich es versuchte. Der Post-Body im Beispiel wird als {"left": 13; "richtig": 7} was nicht legal ist JSON. Ich habe 400 schlechte Anforderungscodes erhalten, als ich es ausprobiert habe. Dann bemerkte ich, dass dort ein Semikolon war, das nicht Teil der JSON-Syntax ist. Ich fand Erfolg, indem ich folgendes durch curl -curl -v -H "Content-Type: application/json" -X POST -d "{\"left\":13,\"right\":7}" http://localhost:8080/test/math
Stuart Blair
12

Darüber hinaus müssen Sie auch sicher sein, dass Sie haben

 <context:annotation-config/> 

in Ihrer SPring-Konfiguration xml.

Ich würde Ihnen auch empfehlen, diesen Blog-Beitrag zu lesen. Es hat mir sehr geholfen. Frühlingsblog - Ajax-Vereinfachungen im Frühjahr 3.0

Aktualisieren:

habe gerade meinen Arbeitscode überprüft, wo ich @RequestBodyrichtig gearbeitet habe. Ich habe auch diese Bean in meiner Konfiguration:

<bean id="jacksonMessageConverter" 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>

Vielleicht wäre es schön zu sehen, was Log4jgesagt wird. Es gibt normalerweise mehr Informationen und meiner Erfahrung @RequestBodynach schlägt das fehl, wenn der Inhaltstyp Ihrer Anfrage nicht lautet Application/JSON. Sie können Fiddler 2 ausführen, um es zu testen, oder sogar das Mozilla Live HTTP-Header-Plugin kann helfen.

danny.lesnik
quelle
Haben Sie natürlich nicht die Frage noch einmal, ich habe ResponseBody funktioniert, es ist der RequestBody, der nicht funktioniert und ich bin sicher, ich vermisse etwas Grundlegendes ...
Eran Medan
Keine zusätzlichen Fehler in log4j :( und ich habe die gleiche Konfiguration ... Gibt es irgendwo ein funktionierendes Beispiel, das ich herunterladen und die Unterschiede debuggen kann?
Eran Medan
Ich habe Ihre Konfiguration verwendet und die fast identische ersetzt, die ich hatte. Ich weiß wirklich nicht, welche kleine Änderung den Trick bewirkt hat, aber es hat ... also DANKE
Eran Medan
9

Neben den Antworten hier ...

Wenn Sie jquery auf der Client-Seite verwenden, hat dies für mich funktioniert:

Java:

@RequestMapping(value = "/ajax/search/sync") 
public String sync(@RequestBody Foo json) {

Jquery (Sie müssen json2.js von Douglas Crockford einschließen, um die Funktion JSON.stringify zu haben):

$.ajax({
    type: "post",
    url: "sync", //your valid url
    contentType: "application/json", //this is required for spring 3 - ajax to work (at least for me)
    data: JSON.stringify(jsonobject), //json object or array of json objects
    success: function(result) {
        //do nothing
    },
    error: function(){
        alert('failure');
    }
});
Rafael Lean Ansay
quelle
Dies funktioniert, weil Sie einen POST durchführen und das Originalposter GET verwendet hat.
Egervari
5

Wenn Sie die Nachrichtenkonverter nicht selbst konfigurieren möchten, können Sie entweder @EnableWebMvc oder <mvc: annotation-powered /> verwenden , Jackson zum Klassenpfad hinzufügen und Spring gibt Ihnen sowohl JSON als auch XML (und einige andere Konverter) von Standard. Darüber hinaus erhalten Sie einige andere häufig verwendete Funktionen zum Konvertieren, Formatieren und Überprüfen.

matsev
quelle
Alter danke, für diesen brillanten Ratschlag, Totally Loved it
Dipanshu Verma
0

Falls Sie bereit sind, Curl für Anrufe mit JSON 2 und Spring 3.2.0 zu verwenden, lesen Sie die FAQ hier . As AnnotationMethodHandlerAdapter ist veraltet und wird durch RequestMappingHandlerAdapter ersetzt.

AmirHd
quelle