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

gc5
fonte
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.

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

uiroshan
fonte
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.

John Shepherd
fonte
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.

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

vinSan
fonte
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>
profundo
fonte
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.

Carlos Romero
fonte
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.

gc5
fonte
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.

Manoj Shrestha
fonte
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){
Shahid Hussain Abbasi
fonte
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>
Lingasamy Bagavathi
fonte
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;
deko
fonte
0

Eu tive o mesmo problema. adicionando

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

para o spring-xml resolveu

OhadR
fonte