Как украшать все просьбы HTTP, чтобы брать стоимость заголовка и это добавлять в параметре тела?

Приспособленный и переведенный: 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 {
    //...
}

Заметь, я использую истребителя - перехватчика, чтобы проверять, что заголовок помещен в просьбы.

Вопрос

Как я могу избегать повторять тот же код в драйверах и методах? Существует чистый способ этого добиваться, без повторения кода? Или я осужден повторять параметр и ту же линию кода во всех методах моих будущих драйверов?

5
задан 23.05.2017, 15:39
2 ответа

Основанный на ответе @PaulVargas и в идею о @jasilva (использовать наследство) я смог прибывать в более надежное решение, для которого я нуждаюсь. Вкратце, он разделяется на две части:

  1. Использовать базовый класс для драйверов. Я назову этого BaseController<E extends Entity> так как Entity это главный класс моих организаций. В этом классе я захвачу стоимость параметра @RequestBody E entity и я это распределю в @ModelAttribute как он объясняет @PaulVargas в Вашем ответе. Власть характерных входит в эту часть.

  2. В моих драйверах, я увеличу 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...
    }    
}
1
ответ дан 24.11.2019, 14:40

Возможно перемещать что-то от повторенного кода используя класс 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;
    }
3
ответ дан 24.11.2019, 14:40