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
.
Ответы
Ответ 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. Еще одна информация здесь.