Приспособленный и переведенный: How to украси тебя all requests to take в value from header and add it in the body parameter?
Я создаю серию услуг RESTful используя Спринг MVC. В настоящее время, у меня есть следующая структура для драйвера:
@RestController
@RequestMapping(path = "myEntity", produces="application/json; charset=UTF-8")
public class MyEntityController {
@RequestMapping(path={ "", "/"} , method=RequestMethod.POST)
public ResponseEntity createMyEntity(
@RequestBody MyEntity myEntity,
@RequestHeader("X-Client-Name") String clientName) {
myEntity.setClientName(clientName);
//resto de declaración del método...
}
@RequestMapping(path={ "/{id}"} , method=RequestMethod.PUT)
public ResponseEntity updateMyEntity(
@PathVariable Long id,
@RequestBody MyEntity myEntity,
@RequestHeader("X-Client-Name") String clientName) {
myEntity.setClientName(clientName);
//resto de declaración del método...
}
@RequestMapping(path={ "/{id}"} , method=RequestMethod.PATCH)
public ResponseEntity partialUpdateMyEntity(
@PathVariable Long id,
@RequestBody MyEntity myEntity,
@RequestHeader("X-Client-Name") String clientName) {
myEntity.setClientName(clientName);
//resto de declaración del método...
}
}
Поскольку возможно видеть, эти три метода получают тот же параметр для заголовка @RequestHeader("X-Client-Name") String clientName
и он применяется того же способа в каждом методе: myEntity.setClientName(clientName)
. Я создам сходные драйверы и для операций POST, УДАР В ЛУНКУ and PATCH будут содержать код сходный но ориентируемый на другие организации. В настоящее время, большинство организаций разработано, чтобы выносить этот бег по пересеченной местности класса отец:
public class Entity {
protected String clientName;
//getters y setters ...
}
public class MyEntity extends Entity {
//...
}
Заметь, я использую истребителя - перехватчика, чтобы проверять, что заголовок помещен в просьбы.
Как я могу избегать повторять тот же код в драйверах и методах? Существует чистый способ этого добиваться, без повторения кода? Или я осужден повторять параметр и ту же линию кода во всех методах моих будущих драйверов?
Основанный на ответе @PaulVargas и в идею о @jasilva (использовать наследство) я смог прибывать в более надежное решение, для которого я нуждаюсь. Вкратце, он разделяется на две части:
Использовать базовый класс для драйверов. Я назову этого BaseController<E extends Entity>
так как Entity
это главный класс моих организаций. В этом классе я захвачу стоимость параметра @RequestBody E entity
и я это распределю в @ModelAttribute
как он объясняет @PaulVargas в Вашем ответе. Власть характерных входит в эту часть.
В моих драйверах, я увеличу BaseController<ProperEntity>
где ProperEntity
это класс организации, которую я нуждаюсь в том, чтобы обработать для того, чтобы вставка была автоматической.
Здесь я показываю код для описанного рисунка:
//1.
public abstract class BaseController<E extends Entity> {
@ModelAttribute("entity")
public E populate(
@RequestBody(required=false) E myEntity,
@RequestHeader("X-Client-Name") String clientName) {
if (myEntity != null) {
myEntity.setCreatedBy(clientName);
}
return myEntity;
}
}
//2.
@RestController
@RequestMapping(path = "myEntity", produces="application/json; charset=UTF-8")
public class MyEntityController extends BaseController<MyEntity> {
@RequestMapping(path={ "", "/"} , method=RequestMethod.POST)
public ResponseEntity<MyEntity> createMyEntity(
@ModelAttribute("entity") MyEntity myEntity) {
//resto de declaración del método...
}
@RequestMapping(path={ "/{id}"} , method=RequestMethod.PUT)
public ResponseEntity<MyEntity> updateMyEntity(
@PathVariable Long id,
@ModelAttribute("entity") MyEntity myEntity) {
//resto de declaración del método...
}
@RequestMapping(path={ "/{id}"} , method=RequestMethod.PATCH)
public ResponseEntity<MyEntity> partialUpdateMyEntity(
@PathVariable Long id,
@ModelAttribute("entity") MyEntity myEntity) {
//resto de declaración del método...
}
}
Возможно перемещать что-то от повторенного кода используя класс org.springframework.web.bind.annotation.ModelAttribute
. А именно:
@RestController
@RequestMapping(path = "myEntity", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class MyEntityController {
@ModelAttribute("model")
public MyEntity populate(
@RequestBody MyEntity myEntity,
@RequestHeader("X-Client-Name") String clientName) {
myEntity.setClientName(clientName);
return myEntity;
}
@RequestMapping(path = {"", "/"}, method = RequestMethod.POST)
public ResponseEntity<MyEntity> createMyEntity(
@ModelAttribute("model") MyEntity myEntity) {
⋮
}
@RequestMapping(path = {"/{id}"}, method = RequestMethod.PUT)
public ResponseEntity<MyEntity> updateMyEntity(
@PathVariable Long id,
@ModelAttribute("model") MyEntity myEntity) {
⋮
}
@RequestMapping(path = {"/{id}"}, method = RequestMethod.PATCH)
public ResponseEntity<MyEntity> partialUpdateMyEntity(
@PathVariable Long id,
@ModelAttribute("model") MyEntity myEntity) {
⋮
}
}
Метод populate
он будет призван в каждой просьбе к этому драйверу перед тем, как призывать записанные методы с @RequestMapping
.
Так как этот метод всегда работает в каждой просьбе, payload и заголовке ("X-Client-Name"
) их потребовали, даже для тех методов, которые не используют таких данных, и исключения она брошена, если они не путешествуют в просьбе. Может быть измененным это обязательное условие с признаком required = false
. А именно:
@ModelAttribute("model")
public MyEntity populate(
@RequestBody(required = false) MyEntity myEntity,
@RequestHeader(required = false, value = "X-Client-Name") String clientName) {
if (myEntity != null) {
myEntity.setClientName(clientName);
}
return myEntity;
}