Подтвердить что ты не робот

Spring RequestMapping для контроллеров, которые производят и потребляют JSON

С несколькими контроллерами Spring, которые используют и создают application/json, мой код полон длинных аннотаций, таких как:

    @RequestMapping(value = "/foo", method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)

Есть ли способ, чтобы произвести "композитный/унаследованный/агрегированный" аннотацию со значениями по умолчанию для consumes и produces, так что я мог бы вместо того, чтобы написать что - то вроде:

    @JSONRequestMapping(value = "/foo", method = RequestMethod.POST)

Как мы определяем что-то вроде @JSONRequestMapping выше? Обратите внимание, что value и method переданные так же, как в @RequestMapping, также хороши, чтобы иметь возможность передавать consumes или produces если значение по умолчанию не подходит.

Мне нужно контролировать то, что я возвращаю. Мне нужны методы аннотации produces/consumes чтобы я получил соответствующие заголовки Content-Type.

4b9b3361

Ответ 1

Как и в случае с Spring 4.2.x, вы можете создавать собственные аннотации сопоставления, используя @RequestMapping в качестве мета-аннотации. Итак:

Есть ли способ создать "составной/унаследованный/агрегированный" аннотации с значениями по умолчанию для потребления и создания, так что я вместо этого мог бы написать что-то вроде:

@JSONRequestMapping(value = "/foo", method = RequestMethod.POST)

Да, есть такой путь. Вы можете создать мета-аннотацию, как показано ниже:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(consumes = "application/json", produces = "application/json")
public @interface JsonRequestMapping {
    @AliasFor(annotation = RequestMapping.class, attribute = "value")
    String[] value() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "method")
    RequestMethod[] method() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "params")
    String[] params() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "headers")
    String[] headers() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "consumes")
    String[] consumes() default {};

    @AliasFor(annotation = RequestMapping.class, attribute = "produces")
    String[] produces() default {};
}

Затем вы можете использовать настройки по умолчанию или даже переопределить их по своему усмотрению:

@JsonRequestMapping(method = POST)
public String defaultSettings() {
    return "Default settings";
}

@JsonRequestMapping(value = "/override", method = PUT, produces = "text/plain")
public String overrideSome(@RequestBody String json) {
    return json;
}

Вы можете узнать больше о AliasFor в Spring javadoc и github wiki.

Ответ 2

Простой ответ на ваш вопрос заключается в отсутствии Аннотации-наследования в Java. Тем не менее, есть способ использовать аннотации Spring таким образом, который, я думаю, поможет решить вашу проблему.

@RequestMapping поддерживается как на уровне типа, так и на уровне метода.

Когда вы помещаете @RequestMapping на уровне типа, большинство атрибутов "унаследованы" для каждого метода в этом классе. Это упомянутый в справочной документации Spring. Посмотрите api docs, чтобы узнать, как обрабатывать каждый атрибут при добавлении @RequestMapping к типу. Я обобщил это для каждого атрибута ниже:

  • name: значение на уровне уровня объединяется со значением на уровне метода, используя '#' в качестве разделителя.
  • value: Значение на уровне типа наследуется методом.
  • path: Значение на уровне типа наследуется методом.
  • method: Значение на уровне типа наследуется методом.
  • params: Значение на уровне типа наследуется методом.
  • headers: Значение на уровне типа наследуется методом.
  • consumes: значение на уровне уровня переопределяется методом.
  • produces: значение на уровне уровня переопределяется методом.

Вот краткий пример контроллера, который демонстрирует, как вы могли бы это использовать:

package com.example;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/", 
        consumes = MediaType.APPLICATION_JSON_VALUE, 
        produces = MediaType.APPLICATION_JSON_VALUE, 
        method = {RequestMethod.GET, RequestMethod.POST})
public class JsonProducingEndpoint {

    private FooService fooService;

    @RequestMapping(path = "/foo", method = RequestMethod.POST)
    public String postAFoo(@RequestBody ThisIsAFoo theFoo) {
        fooService.saveTheFoo(theFoo);
        return "http://myservice.com/foo/1";
    }

    @RequestMapping(path = "/foo/{id}", method = RequestMethod.GET)
    public ThisIsAFoo getAFoo(@PathVariable String id) {
        ThisIsAFoo foo = fooService.getAFoo(id);
        return foo;
    }

    @RequestMapping(path = "/foo/{id}", produces = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.GET)
    public ThisIsAFooXML getAFooXml(@PathVariable String id) {
        ThisIsAFooXML foo = fooService.getAFoo(id);
        return foo;
    }
}

Ответ 3

Вы можете использовать аннотацию @RestController вместо @Controller.

Ответ 4

Вам не нужно настраивать расход или производить атрибут вообще. Spring будет автоматически обслуживать JSON на основе следующих факторов.

  • Заголовок accept запроса application/json
  • @ResponseBody аннотированный метод
  • Библиотека Джексона на пути к классу

Вы также должны следить за предложением Wim и определять свой контроллер с помощью аннотации @RestController. Это избавит вас от аннотации каждого метода запроса с помощью @ResponseBody

Еще одно преимущество этого подхода состояло бы в том, что клиент хочет XML вместо JSON, он получит его. Им просто нужно указать xml в заголовке accepts.

Ответ 5

В Spring есть 2 аннотации: @RequestBody и @ResponseBody. Эти аннотации потребляют, соответственно производят JSON. Еще одна информация здесь.