복붙노트

[SPRING] 머리글에서 값을 가져 와서 body 매개 변수에 추가하라는 모든 요청을 꾸미는 방법?

SPRING

머리글에서 값을 가져 와서 body 매개 변수에 추가하라는 모든 요청을 꾸미는 방법?

저는 Spring MVC를 사용하여 RESTful 서비스를 만들고 있습니다. 현재 컨트롤러에는 다음과 같은 구조가 있습니다.

@RestController
@RequestMapping(path = "myEntity", produces="application/json; charset=UTF-8")
public class MyEntityController {

    @RequestMapping(path={ "", "/"} , method=RequestMethod.POST)
    public ResponseEntity<MyEntity> createMyEntity(
        @RequestBody MyEntity myEntity,
        @RequestHeader("X-Client-Name") String clientName) {
        myEntity.setClientName(clientName);
        //rest of method declaration...
    }

    @RequestMapping(path={ "/{id}"} , method=RequestMethod.PUT)
    public ResponseEntity<MyEntity> updateMyEntity(
        @PathVariable Long id,
        @RequestBody MyEntity myEntity,
        @RequestHeader("X-Client-Name") String clientName) {
        myEntity.setClientName(clientName);
        //rest of method declaration...
    }

    @RequestMapping(path={ "/{id}"} , method=RequestMethod.PATCH)
    public ResponseEntity<MyEntity> partialUpdateMyEntity(
        @PathVariable Long id,
        @RequestBody MyEntity myEntity,
        @RequestHeader("X-Client-Name") String clientName) {
        myEntity.setClientName(clientName);
        //rest of method declaration...
    }
}

보시다시피,이 세 가지 메소드 모두 @RequestHeader ( "X-Client-Name") String clientName 헤더에 대해 동일한 매개 변수를 수신하고 각 메소드에서 동일한 방식으로 myEntity.setClientName (clientName)을 적용합니다. 비슷한 컨트롤러를 만들고 POST의 경우 PUT 및 PATCH 작업에 거의 동일한 코드가 있지만 다른 엔티티에는 포함됩니다. 현재 대부분의 엔티티는 수퍼 클래스로이 필드를 지원하도록 설계되었습니다.

public class Entity {
    protected String clientName;
    //getters and setters ...
}
public class MyEntity extends Entity {
    //...
}

또한 헤더를 요청에 설정했는지 확인하기 위해 인터셉터를 사용합니다.

컨트롤러 클래스와 메소드를 통해 동일한 코드를 반복하지 않으려면 어떻게해야합니까? 그것을 달성하기위한 깨끗한 방법이 있습니까? 또는 변수를 선언하고 모든 행을 반복해야합니까?

이 질문은 스페인 공동체에서도 요구되었습니다. 여기에 링크가 있습니다.

해결법

  1. ==============================

    1.내 제안은 Spring 인터셉터 또는 필터 내부 요청 범위 Bean에 헤더 값을 저장하는 것입니다. 그런 다음 서비스 또는 컨트롤러를 사용하여 저장된 모든 클라이언트 이름 값을 사용하여 원하는 곳에이 bean을 autowire 할 수 있습니다.

    내 제안은 Spring 인터셉터 또는 필터 내부 요청 범위 Bean에 헤더 값을 저장하는 것입니다. 그런 다음 서비스 또는 컨트롤러를 사용하여 저장된 모든 클라이언트 이름 값을 사용하여 원하는 곳에이 bean을 autowire 할 수 있습니다.

    코드 예 :

    public class ClientRequestInterceptor extends HandlerInterceptorAdapter {
    
        private Entity clientEntity;
    
        public ClientRequestInterceptor(Entity clientEntity) {
            this.clientEntity = clientEntity;
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            String clientName = request.getHeader("X-Client-Name");
            clientEntity.setClientName(clientName);
            return true;
        }
    }
    

    구성 파일에서 다음을 수행하십시오.

    @EnableWebMvc
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(clientRequestInterceptor());
        }
    
        @Bean(name="clientEntity")
        @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
        public Entity clientEntity() {
            return new Entity();
        }
    
        @Bean
        public ClientRequestInterceptor clientRequestInterceptor() {
            return new ClientRequestInterceptor(clientEntity());
        }
    
    }
    

    그런 다음 컨트롤러에서이 Bean을 사용해야한다고 가정합니다.

    @RestController
    @RequestMapping(path = "myEntity", produces="application/json; charset=UTF-8")
    public class MyEntityController {
    
        @Autowired
        private Entity clientEntity; // here you have the filled bean
    
        @RequestMapping(path={ "", "/"} , method=RequestMethod.POST)
        public ResponseEntity<MyEntity> createMyEntity(@RequestBody MyEntity myEntity) {
            myEntity.setClientName(clientEntity.getClientName());
            //rest of method declaration...
        }
        // rest of your class methods, without @RequestHeader parameters
    
    }
    

    이 코드를 컴파일하지 않았으므로 실수를 저 지르더라도 수정하십시오.

  2. ==============================

    2.스페인어 사이트 (나는이 질문을 게시 한 곳)에서 흥미로운 대답을 얻었고 그 대답에 따라이 필요에 적응하는 광산을 생성 할 수있었습니다. 여기에 SOes에 대한 나의 대답이있다.

    스페인어 사이트 (나는이 질문을 게시 한 곳)에서 흥미로운 대답을 얻었고 그 대답에 따라이 필요에 적응하는 광산을 생성 할 수있었습니다. 여기에 SOes에 대한 나의 대답이있다.

    @ PaulVargas의 대답과 @ jasilva (컨트롤러에서 상속 사용)의 아이디어에 기반을 두었습니다.이 경우에 대한 더 강력한 해결책이 있습니다. 디자인은 두 부분으로 구성됩니다.

    여기에 설명 된 디자인의 코드가 나와 있습니다.

    //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) {
            //rest of method declaration...
        }
    
        @RequestMapping(path={ "/{id}"} , method=RequestMethod.PUT)
        public ResponseEntity<MyEntity> updateMyEntity(
            @PathVariable Long id,
            @ModelAttribute("entity") MyEntity myEntity) {
            //rest of method declaration...
        }
    
        @RequestMapping(path={ "/{id}"} , method=RequestMethod.PATCH)
        public ResponseEntity<MyEntity> partialUpdateMyEntity(
            @PathVariable Long id,
            @ModelAttribute("entity") MyEntity myEntity) {
            //rest of method declaration...
        }    
    }
    

    이런 식으로 모든 메서드와 컨트롤러에서 이러한 코드 줄을 다시 작성할 필요가 없기 때문에 내가 구한 것에 도달했습니다.

  3. ==============================

    3.RequestBodyAdvice 사용을 고려해 볼 수 있습니다. javadocs를 참조하십시오. http 헤더에 액세스 할 수있는 HttpInputMessage 객체가 인터페이스 메소드에 전달됩니다.

    RequestBodyAdvice 사용을 고려해 볼 수 있습니다. javadocs를 참조하십시오. http 헤더에 액세스 할 수있는 HttpInputMessage 객체가 인터페이스 메소드에 전달됩니다.

  4. from https://stackoverflow.com/questions/36295095/how-to-decorate-all-requests-to-take-a-value-from-header-and-add-it-in-the-body by cc-by-sa and MIT license