O POST JSON falha com o tipo de mídia 415 não suportado, mvc da Primavera 3


171

Estou tentando enviar uma solicitação POST para um servlet. A solicitação é enviada via jQuery desta maneira:

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

onde newCategory é

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

e postJSON é

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

Com o firebug, vejo que o JSON é enviado corretamente:

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

Mas recebo 415 tipos de mídia não suportados. O controlador mvc Spring possui assinatura

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

Alguns dias atrás, funcionou, agora não é. Vou mostrar mais código, se necessário. obrigado


O que você mudou desde alguns dias atrás? Além disso, não var productCategory = { idProductCategory: 1, description: "Descrizione2" };seria mais conciso e fácil de ler? Você precisa dizer ao Spring para aceitar application/jsonespecificamente? Em outras palavras, ele espera que os dados cheguem em um formulário?
— 21412 Dave

Muitas coisas desde que eu estava trabalhando em outra parte deste projeto e hoje encontrei essa regressão. Nesta parte eu não mudei nada. Sim, tenho que usar dessa maneira porque estou recebendo informações de um formulário.
— Gc5

Não, você não está, está obtendo uma postagem do JSON Ajax, que não é a mesma que os dados codificados por formulário.
— 21412 Dave

1
Você tem certeza de que Jackson ainda está disponível no seu CLASSPATH?
— Tomasz Nurkiewicz

1
se u enviar mensagens de texto / json em vez de application / json u obter o mesmo erro
— Blacksonic

Respostas:


249

Isso já aconteceu antes com o Spring @ResponseBody e foi porque não havia nenhum cabeçalho de aceitação enviado com a solicitação. Aceitar cabeçalho pode ser uma dor de conjunto com jQuery, mas isso funcionou para mim fonte

$.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
    });
};

O cabeçalho Content-Type é usado pelo @RequestBody para determinar qual o formato dos dados enviados pelo cliente na solicitação. O cabeçalho de aceitação é usado pelo @ResponseBody para determinar qual formato enviar os dados de volta ao cliente na resposta. É por isso que você precisa dos dois cabeçalhos.


1
os cabeçalhos: {...} e o JSON.stringify (...) sempre me atrapalham.
— Tim Perry

1
Não faço ideia por que isso não está mais documentado. Esse problema me fez perder muito tempo. Muito obrigado!
— Hugo Nava Kopp

Eu esperava que o Spring suporte dados de formulário por padrão, mas não. Então, obrigado pela solução (agora bastante antiga).
— RiZKiT

Eu estava usando um carteiro para fazer uma solicitação de venda, apenas adicionei o tipo de conteúdo: '' application / json ". Obrigado
— Janatbek Sharsheyev 13/02/19

21

adicionar tipo de conteúdo à solicitação, conforme application/jsonresolvido o problema


18

Eu tive um problema semelhante, mas achei que o problema era que havia esquecido de fornecer um construtor padrão para o DTO que foi anotado com @RequestBody.


A mesma coisa aconteceu comigo. Eu tinha 2 métodos com o mesmo nome e estava recebendo 415. Obrigado!
— Daniel Vilas-Boas

12

Acredito que encontrei exatamente o mesmo problema. Após inúmeras horas de luta com o JSON, o JavaScript e o servidor, encontrei o culpado: no meu caso, eu tinha um objeto Date no DTO, esse objeto Date foi convertido em uma String para que pudéssemos mostrá-lo na exibição com o formato: HH: mm.

Quando as informações JSON estavam sendo enviadas de volta, esse objeto Date String precisava ser convertido novamente em um Date Object completo, portanto, também precisamos de um método para configurá-lo no DTO. O grande problema é que você não pode ter 2 métodos com o mesmo nome (Sobrecarga) no DTO, mesmo se eles tiverem um tipo diferente de parâmetro (String vs Data), pois isso também fornecerá o erro do tipo 415 Mídia não suportada.

Este foi o meu método de controle

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

Este foi meu exemplo de DTO (os métodos id get / set e preAlarm get não estão incluídos na falta de código):

@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;
    }
  }
}

Para que tudo funcione, é necessário remover o método com o parâmetro Date type. Este erro é muito frustrante. Espero que isso possa economizar horas de depuração para alguém.


Obrigado - ou você pode simplesmente mudar o nome de um dos levantadores. Eu tinha tanto public void setParameters(List<Parameter> parameters)e public void setParameters(Parameter... parameters)métodos em um bean, mudando o último para addParametersresolver a questão para mim.
— Conor Svensson

Não é o problema que o corpo é this.preAlarm == date em vez de this.preAlarm = date?
— Michael restaura Monica Cellio

12

Eu enfrentei um problema semelhante e foi assim que o corrigi,

O problema é devido ao processo de conversão de JSON para Java, é necessário ter as bibliotecas jackson de tempo de execução corretas para que a conversão ocorra corretamente.

Adicione os seguintes jars (por dependência ou baixando e adicionando ao caminho de classe.

<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>

Isto deve resolver o problema.

Código completo:

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);
}

e a assinatura do controlador é assim:

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

Espero que isto ajude


Somente jackson-databindé necessário.
— Alex78191

8

Eu enfrentei esse problema quando integrei a bota de mola ao spring mvc. Eu o resolvi apenas adicionando essas dependências.

<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>

5

Uma pequena nota lateral - deparei com esse mesmo erro ao desenvolver um aplicativo da web. O erro que encontramos, brincando com o serviço com o Firefox Poster, foi que os campos e valores no Json deveriam estar entre aspas duplas. Por exemplo..

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

No nosso caso, preenchemos o json via javascript, o que pode ser um pouco confuso quando se trata de lidar com aspas simples / duplas, pelo que ouvi.

O que foi dito antes nesta e em outras postagens, como incluir os cabeçalhos 'Aceitar' e 'Tipo de conteúdo', também se aplica.

Espero que ajude.


3

Eu consegui descobrir como fazê-lo funcionar. Diga-me caso eu esteja errado. Eu usei apenas uma maneira de serializar / desserializar: removi todas as anotações sobre isso ( @JSONSerializee @JSONDeserialize) e registrei os serializadores e desserializadores na CustomObjectMapperclasse. Não encontrei um artigo explicando esse comportamento, mas resolvi dessa maneira. Espero que seja útil.


Acontece o mesmo comigo! Alguma explicação por que isso acontece?
— Whimusical 15/01

Você pode explicar o seu método em detalhes?
— Dipanshu Verma

1

Eu tive o mesmo problema. Eu tive que seguir estas etapas para resolver o problema:

1. Verifique se você possui as seguintes dependências:

    <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. Crie o seguinte filtro:

    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. Aplique o filtro acima para as solicitações em web.xml

    <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>

Espero que isso seja útil para alguém.


jackson-coreé uma dependência de jackson-databind, portanto, não há necessidade de adicioná-lo diretamente.
— Alex78191

1
Por que é necessário adicionar o filtro CORS?
— Alex78191

1

Bota de mola + mola mvn

com problema

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

com solução

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

0

Resolvi esse problema adicionando a ligação de dados jackson-json ao meu pom.

<dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.6.3</version>
</dependency>

0

Na sua Classe Modelo, adicione uma anotação de propriedade json, também tenha um construtor padrão

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

0

Eu tive o mesmo problema. adicionando

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

para o spring-xml resolveu


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.