POST JSON schlägt mit 415 nicht unterstütztem Medientyp Spring 3 mvc fehl

171

Ich versuche, eine POST-Anfrage an ein Servlet zu senden. Die Anfrage wird über jQuery folgendermaßen gesendet:

var productCategory = new Object();
productCategory.idProductCategory = 1;
productCategory.description = "Descrizione2";
newCategory(productCategory);

wo newCategory ist

function newCategory(productCategory)
{
  $.postJSON("ajax/newproductcategory", productCategory, function(
      idProductCategory)
  {
    console.debug("Inserted: " + idProductCategory);
  });
}

und postJSON ist

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    'type': 'POST',
    'url': url,
    'contentType': 'application/json',
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

Mit Firebug sehe ich, dass JSON korrekt gesendet wird:

{"idProductCategory":1,"description":"Descrizione2"}

Aber ich bekomme 415 nicht unterstützten Medientyp. Spring MVC Controller hat Signatur

    @RequestMapping(value = "/ajax/newproductcategory", method = RequestMethod.POST)
public @ResponseBody
Integer newProductCategory(HttpServletRequest request,
        @RequestBody ProductCategory productCategory)

Vor einigen Tagen hat es funktioniert, jetzt ist es nicht mehr. Ich werde bei Bedarf mehr Code anzeigen. Vielen Dank

gc5
quelle
Was hast du seit einigen Tagen geändert? Wäre es nicht var productCategory = { idProductCategory: 1, description: "Descrizione2" };prägnanter und leichter zu lesen? Müssen Sie Spring anweisen, dies application/jsonausdrücklich zu akzeptieren ? Mit anderen Worten, erwartet es, dass die Daten in einer Form vorliegen?
Dave Newton
Viele Dinge, seit ich an einem anderen Teil dieses Projekts gearbeitet habe, und heute habe ich diese Regression gefunden. In diesem Teil habe ich nichts geändert. Ja, ich muss diesen Weg verwenden, da ich Eingaben von einem Formular erhalte.
GC5
Nein, das ist nicht der Fall. Sie erhalten es von einem JSON Ajax-Beitrag, der nicht mit formularcodierten Daten identisch ist.
Dave Newton
1
Sind Sie sicher, dass Jackson auf Ihrem CLASSPATH noch verfügbar ist?
Tomasz Nurkiewicz
1
Wenn Sie Text / JSON anstelle von Anwendung /
JSON

Antworten:

249

Ich hatte dies schon einmal mit Spring @ResponseBody und das lag daran, dass mit der Anfrage kein Accept-Header gesendet wurde. Das Akzeptieren von Headern kann mit jQuery schwierig sein, aber dies hat für mich als Quelle funktioniert

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
    headers: { 
        'Accept': 'application/json',
        'Content-Type': 'application/json' 
    },
    'type': 'POST',
    'url': url,
    'data': JSON.stringify(data),
    'dataType': 'json',
    'success': callback
    });
};

Der Content-Type-Header wird von @RequestBody verwendet, um zu bestimmen, in welchem ​​Format die vom Client in der Anforderung gesendeten Daten vorliegen. Der Accept-Header wird von @ResponseBody verwendet, um zu bestimmen, in welchem ​​Format die Daten in der Antwort an den Client zurückgesendet werden sollen. Deshalb brauchen Sie beide Header.

die auf
quelle
1
Die Header: {...} und JSON.stringify (...) stolpern immer über mich.
Tim Perry
1
Keine Ahnung, warum dies nicht mehr dokumentiert ist. Dieses Problem hat mich so viel Zeit verschwenden lassen. Vielen Dank!
Hugo Nava Kopp
Ich habe erwartet, dass Spring Formulardaten standardmäßig unterstützt, aber nicht. Also, danke für die (jetzt ziemlich alte) Lösung.
RiZKiT
Ich benutzte einen Postboten, um eine Put-Anfrage zu stellen, fügte nur den Inhaltstyp hinzu: '' application / json ". Danke
Janatbek Sharsheyev
21

Hinzufügen eines Inhaltstyps zur Anforderung, application/jsonum das Problem zu beheben

Uiroshan
quelle
18

Ich hatte ein ähnliches Problem, stellte jedoch fest, dass ich es versäumt hatte, einen Standardkonstruktor für das DTO bereitzustellen, der mit @RequestBody kommentiert war.

John Shepherd
quelle
das gleiche ist mir passiert. Ich hatte 2 Methoden mit dem gleichen Namen und bekam 415. Danke!
Daniel Vilas-Boas
12

Ich glaube, ich bin genau auf das gleiche Problem gestoßen. Nach unzähligen Stunden des Kampfes mit JSON, JavaScript und dem Server fand ich den Schuldigen: In meinem Fall hatte ich ein Datumsobjekt im DTO, dieses Datumsobjekt wurde in einen String konvertiert, damit wir es in der Ansicht mit dem anzeigen konnten Format: HH: mm.

Beim Zurücksenden von JSON-Informationen musste dieses Date String-Objekt wieder in ein vollständiges Date-Objekt konvertiert werden. Daher benötigen wir auch eine Methode, um es im DTO festzulegen. Das große ABER ist, dass Sie nicht zwei Methoden mit demselben Namen (Überladung) im DTO haben können, selbst wenn sie unterschiedliche Parametertypen (String vs Date) haben, da dies auch den Fehler 415 Nicht unterstützter Medientyp ergibt.

Dies war meine Controller-Methode

  @RequestMapping(value = "/alarmdownload/update", produces = "application/json", method = RequestMethod.POST)
  public @ResponseBody
  StatusResponse update(@RequestBody AlarmDownloadDTO[] rowList) {
    System.out.println("hola");
    return new StatusResponse();
  }

Dies war mein DTO-Beispiel (ID get / set- und preAlarm get-Methoden sind aus Gründen der Codekürzung nicht enthalten):

@JsonIgnoreProperties(ignoreUnknown = true)
public class AlarmDownloadDTO implements Serializable {

  private static final SimpleDateFormat formatHHmm = new SimpleDateFormat("HH:mm");

  private String id;
  private Date preAlarm;

  public void setPreAlarm(Date date) { 
    this.preAlarm == date;
  }
  public void setPreAlarm(String date) {    
    try {
      this.preAlarm = formatHHmm.parse(date);
    } catch (ParseException e) {
      this.preAlarm = null;
    } catch (NullPointerException e){
      this.preAlarm = null;
    }
  }
}

Damit alles funktioniert, müssen Sie die Methode mit dem Parameter Datumstyp entfernen. Dieser Fehler ist sehr frustrierend. Hoffe, dies kann jemandem Stunden beim Debuggen ersparen.

will824
quelle
Danke - oder Sie können einfach einen der Setter umbenennen. Ich hatte beide public void setParameters(List<Parameter> parameters)& public void setParameters(Parameter... parameters)Methoden in einer Bohne und änderte letztere, addParametersum das Problem für mich zu lösen.
Conor Svensson
Ist das nicht das Problem, dass der Körper dieses.preAlarm == Datum und nicht dieses.preAlarm = Datum ist?
Michael stellt Monica Cellio
12

Ich hatte ein ähnliches Problem und so habe ich es behoben.

Das Problem ist auf den Konvertierungsprozess von JSON nach Java zurückzuführen. Für die korrekte Konvertierung müssen die richtigen Jackson-Laufzeitbibliotheken vorhanden sein.

Fügen Sie die folgenden Jars hinzu (durch Abhängigkeit oder durch Herunterladen und Hinzufügen zum Klassenpfad.

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>

Dies sollte das Problem beheben.

Vollständiger Code:

function() {
  $.ajax({
    type: "POST",
    url: "saveUserDetails.do",
    data: JSON.stringify({
      name: "Gerry",
      ity: "Sydney"
    }),
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    success: function(data) {
      if (data.status == 'OK')
        alert('Person has been added');
      else
        alert('Failed adding person: ' + data.status + ', ' + data.errorMessage);
}

und die Controller-Signatur sieht folgendermaßen aus:

@RequestMapping(value = "/saveUserDetails.do", method = RequestMethod.POST)
public @ResponseBody Person addPerson( @RequestBody final  Person person) {

Hoffe das hilft

vinSan
quelle
Nur jackson-databindist erforderlich.
Alex78191
8

Ich war mit diesem Problem konfrontiert, als ich Spring Boot in Spring MVC integrierte. Ich habe es gelöst, indem ich nur diese Abhängigkeiten hinzugefügt habe.

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>
tief
quelle
5

Eine kleine Randnotiz - bei der Entwicklung einer Webanwendung auf denselben Fehler gestoßen. Der Fehler, den wir beim Spielen mit dem Dienst mit Firefox Poster festgestellt haben, war, dass sowohl Felder als auch Werte im Json in doppelte Anführungszeichen gesetzt werden sollten. Zum Beispiel..

[ {"idProductCategory" : "1" , "description":"Descrizione1"}, 
  {"idProductCategory" : "2" , "description":"Descrizione2"} ]

In unserem Fall haben wir den json über Javascript gefüllt, was nach dem, was ich gehört habe, etwas verwirrend sein kann, wenn es um den Umgang mit einfachen / doppelten Anführungszeichen geht.

Was bereits in diesem und anderen Beiträgen gesagt wurde, wie z. B. die Überschriften "Akzeptieren" und "Inhaltstyp", gilt ebenfalls.

Hoffe t'helps.

Carlos Romero
quelle
3

Ich habe es geschafft, wie es funktioniert. Sag es mir, falls ich falsch liege. Ich habe nur einen Weg zum Serialisieren / Deserialisieren verwendet: Ich habe alle diesbezüglichen Anmerkungen ( @JSONSerializeund @JSONDeserialize) entfernt und Serializer und Deserializer in der CustomObjectMapperKlasse registriert . Ich habe keinen Artikel gefunden, der dieses Verhalten erklärt, aber ich habe es auf diese Weise gelöst. Hoffe es ist nützlich.

gc5
quelle
Passiert mir auch! Irgendeine Erklärung warum es passiert?
Launisch
Können Sie bitte Ihre Methode im Detail erklären?
Dipanshu Verma
1

Ich hatte das gleiche Problem. Ich musste die folgenden Schritte ausführen, um das Problem zu beheben:

1. Stellen Sie sicher, dass Sie die folgenden Abhängigkeiten haben:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson-version}</version> // 2.4.3
    </dependency>

2. Erstellen Sie den folgenden Filter:

    public class CORSFilter extends OncePerRequestFilter {

        @Override
        protected void doFilterInternal(HttpServletRequest request,
                                        HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {

            String origin = request.getHeader("origin");
            origin = (origin == null || origin.equals("")) ? "null" : origin;
            response.addHeader("Access-Control-Allow-Origin", origin);
            response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, UPDATE, DELETE, OPTIONS");
            response.addHeader("Access-Control-Allow-Credentials", "true");
            response.addHeader("Access-Control-Allow-Headers",
                    "Authorization, origin, content-type, accept, x-requested-with");

            filterChain.doFilter(request, response);
        }
    }

3. Wenden Sie den obigen Filter für die Anforderungen in web.xml an

    <filter>
        <filter-name>corsFilter</filter-name>
        <filter-class>com.your.package.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>corsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Ich hoffe, das ist für jemanden nützlich.

Manoj Shrestha
quelle
jackson-coreist eine Abhängigkeit von jackson-databind, daher muss sie nicht direkt hinzugefügt werden.
Alex78191
1
Warum muss der CORS-Filter hinzugefügt werden?
Alex78191
1

Frühlingsstiefel + Feder mvn

mit Problem

@PostMapping("/addDonation")
public String addDonation(@RequestBody DonatorDTO donatorDTO) {

mit Lösung

@RequestMapping(value = "/addDonation", method = RequestMethod.POST)
@ResponseBody
public GenericResponse addDonation(final DonatorDTO donatorDTO, final HttpServletRequest request){
Shahid Hussain Abbasi
quelle
0

Ich habe dieses Problem behoben, indem ich meinem POM eine Jackson-JSON-Datenbindung hinzugefügt habe.

<dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.3</version>
</dependency>
Lingasamy Bagavathi
quelle
0

Fügen Sie in Ihrer Modellklasse eine json-Eigenschaftsanmerkung hinzu und verfügen Sie über einen Standardkonstruktor

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;
deko
quelle
0

Ich hatte das gleiche Problem. Hinzufügen

<mvc:annotation-driven />
<mvc:default-servlet-handler />

zum spring-xml hat es gelöst

OhadR
quelle