POST JSON не работает с 415 неподдерживаемым типом носителя, Spring 3 mvc

Я пытаюсь отправить запрос POST на сервлет. Запрос отправляется через jQuery таким образом:

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

где newCategory

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

и postJSON

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

С firebug я вижу, что JSON отправлен правильно:

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

Но я получаю 415 неподдерживаемых типов носителей. Spring Контроллер mvc имеет подпись

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

Несколько дней назад это сработало, теперь это не так. При необходимости я покажу больше кода. Благодаря

Ответ 1

Мне удалось, как это сделать. Скажи мне, если я ошибаюсь. Я использовал только один способ сериализации/десериализации: я удалил все аннотации относительно этого (@JSONSerialize и @JSONDeserialize) и зарегистрировал сериализаторы и десериализаторы в классе CustomObjectMapper. Я не нашел статьи, объясняющей это поведение, но я решил таким образом. Надеюсь, это полезно.

Ответ 2

У меня это было раньше с Spring @ResponseBody, и это было потому, что не было заголовка accept, отправленного с запросом. Принять заголовок может быть болью для установки с помощью jQuery, но это сработало для меня source

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

Заголовок Content-Type используется @RequestBody для определения формата, который данные отправляют от клиента в запросе. Заголовок принятия используется @ResponseBody для определения формата отправки данных обратно клиенту в ответ. Вот почему вам нужны оба заголовка.

Ответ 3

добавление типа контента в запрос как application/json разрешило проблему

Ответ 4

У меня была аналогичная проблема, но я обнаружил, что проблема в том, что я забыл предоставить конструктор по умолчанию для DTO, который был аннотирован с помощью @RequestBody.

Ответ 5

Я считаю, что я точно столкнулся с той же проблемой. После бесчисленных часов борьбы с JSON, JavaScript и сервером, я нашел виновника: в моем случае у меня был объект Date в DTO, этот объект Date был преобразован в String, чтобы мы могли показать его в представлении с помощью формат: ЧЧ: мм.

Когда информация JSON была отправлена ​​обратно, этот объект String даты должен был быть преобразован обратно в полный объект Date, поэтому нам также нужен метод его установки в DTO. Большой BUT - вы не можете иметь 2 метода с тем же именем (Overload) в DTO, даже если у них есть другой тип параметра (String vs Date), потому что это также даст вам 415 неподдерживаемый тип носителя.

Это был мой метод контроллера

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

Это был мой пример DTO (id get/set и preAlarm get Методы не включены для сокращения кода):

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

Чтобы сделать все, вам нужно удалить метод с параметром Date type. Эта ошибка очень расстраивает. Надеюсь, это может сэкономить часы отладки.

Ответ 6

Я столкнулся с подобной проблемой, и именно так я ее исправил,

Проблема связана с процессом преобразования с JSON на Java, необходимо иметь правильные библиотеки Jackson для запуска, чтобы преобразование произошло правильно.

Добавьте следующие банки (через зависимость или путем загрузки и добавления в путь к классам.

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

Это должно решить проблему.

Полный код:

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

и подпись контроллера выглядит следующим образом:

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

Надеюсь это поможет

Ответ 7

Я столкнулся с этой проблемой, когда я интегрировал загрузку spring с spring mvc. Я решил это, просто добавив эти зависимости.

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

Ответ 8

Небольшая сторона примечания - наткнулась на эту же ошибку при разработке веб-приложения. Ошибка, которую мы обнаружили, благодаря использованию сервиса с Firefox Poster, заключалась в том, что оба поля и значения в Json должны быть окружены двойными кавычками. Например..

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

В нашем случае мы заполнили json через javascript, что может немного запутать, когда дело касается одиночных/двойных кавычек, из того, что я слышал.

То, что было сказано ранее в этом и других сообщениях, например, включая заголовки "Accept" и "Content-Type", также применяется.

Надежды.

Ответ 9

У меня была та же проблема. Я должен был выполнить следующие действия, чтобы решить проблему:

1. Убедитесь, что у вас есть следующие зависимости:

    <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. Создайте следующий фильтр:

    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. Применить указанный фильтр для запросов в 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>

Надеюсь, это полезно кому-то.

Ответ 10

Минимальная сборка службы REST:

  • проверено с Wildfly
  • зависимостей jackson maven не требуется

pom.xml:

...
<properties>
     <springframework.version>4.3.1.RELEASE</springframework.version>
</properties>
...
<packaging>war</packaging>
...
<dependencies>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${springframework.version}</version>
  </dependency>

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${springframework.version}</version>
  </dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${springframework.version}</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>${springframework.version}</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${springframework.version}</version>
</dependency>

  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
  </dependency>

</dependencies>

<build>
    <sourceDirectory>src/main/java</sourceDirectory>

    <finalName>spring-rest-demo</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>dependency-jars/</classpathPrefix>
                    </manifest>
                </archive>
                <webXml>${project.basedir}\src\main\webapp\WEB-INF\web.xml</webXml>
            </configuration>
        </plugin>
    </plugins>
</build>

...

SRC/Основной/Java/WebApp/WEB-INF/web.xml:

...
<display-name>Spring MVC Application</display-name>

<servlet>
    <servlet-name>RestDemo</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>RestDemo</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
...

SRC/Основной/Java/WebApp/WEB-INF/RestDemo-servlet.xml:

...
<mvc:annotation-driven/>
<context:component-scan base-package="your.package.path" />
...

Контроллер REST:

без каких-либо проверок данных, только для образовательных целей

@RestController
public class SpringRestServiceImpl implements SpringRestService {

    @Autowired
    private VideoGameDao videoGameDao;

    ...

    @RequestMapping(value = "/rest/save", method = RequestMethod.POST, consumes = {"application/json"})
    @Override
    public ResponseEntity save(@RequestBody VideoGame videoGame) {
        return ResponseEntity.ok(videoGameDao.save(videoGame));
    }

    ...
}

Как проверить:

с curl:

curl -i -POST -H "Content-Type: application/json" -d "your-json-here" http://yourserver:8080/spring-rest-demo/rest/save

или с помощью Postman tool

Ответ 11

Я решил эту проблему, добавив данные привязки джексон-json к моему pom.

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

Ответ 12

Пружинный ботинок + пружинный мвн

с вопросом

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

с решением

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

Ответ 13

В свой класс модели добавьте аннотацию свойства json, также есть конструктор по умолчанию

@JsonProperty("user_name")
private String userName;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;