2017-10-30 2 views
1

Spring 데이터 나머지의 내 엔티티 중 하나가 응답의 헤더에 추가되어야하는 속성 값을 가지고 있습니다. 이 작업을 수행하는 방법?Spring 데이터 나머지의 특정 리소스에 맞춤 헤더를 추가하는 방법

이미 처리기 인터셉터를 사용하여 헤더 (모든 응답)를 변경하는 방법을 발견했습니다. 그리고 버전, etag 및 수정 된 내용도 발견했습니다 .. 이것들은 내가 원하는 것이 아닙니다.

헤더는 REST 리소스 중 하나에 설정되어야하며 값은 인스턴스/레코드에 따라 다릅니다.

그림과 같이 : Person의 속성은 age입니다. Person REST 자원에 대한 모든 요청 (예 : /person/{id} GET)은 age 값을 http 헤더 (예 : age:32)로 리턴해야합니다.

미리 감사드립니다.

+0

https://stackoverflow.com/a/19265876/5380322 – Cepr0

+0

인터셉터가 특정 경로에 매핑 할 수 있습니다 : 당신이 뭔가를 할 수 있었던 것처럼

그래서 그것은 본다. https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/handler/MappedInterceptor.html#getPathPatterns-- 여전히 사람을 참조해야합니다. 그러나 나이를 얻으십시오 –

+0

나는 기록적인 특정한 머리말을 필요로 한 ㄴ다는 것을 언급했다. – codesmith

답변

2

내 이전 답변에서 가장 최근 버전의 SDR API는 방법이 RepositoryRestMvcConfiguration#httpHeadersPreparer()임을 알 수 있습니다.

이 방법은 2.6.8에서 사용할 수 있지만 현재 2.5.10을 사용중인 버전에서는 볼 수 없습니다.

@Configuration 
public class MyConfiguration extends RepositoryRestMvcConfiguration 
{ 
    @Override 
    public HttpHeadersPreparer httpHeadersPreparer() 
    { 
    HttpHeadersPreparer preparer = new HttpHeadersPreparer(){ 
     @Override 
     public HttpHeaders prepareHeaders(PersistentEntityResource resource, Object value) 
     { 
     org.springframework.http.HttpHeaders headers = super.prepareHeaders(resource); 

     if(value instanceof Person){ 
      headers.add("age", ((Person)value).getAge()); 
     } 
     } 

    }; 

    return preparer; 
    } 
} 
+0

앨런, 정말 고마워. 이것은 좋은 해결책처럼 보입니다. 그러나 RepositoryRestMvcConfiguration을 확장하면 다른 구성이 사라집니다. – codesmith

+0

기존 설정에 따라 다릅니다. 해당 인라인 솔루션을 업데이트해야합니다. –

+0

오래된 문제 인 것 같습니다 : https://github.com/spring-projects/spring-boot/issues/2392 – codesmith

0

첫째, 특정 경로에 인터셉터를 바인딩하여 문제가 절반 정도 해결됩니다.

두 번째 문제는 요청한 Person 리소스에 대한 참조를 얻는 것입니다.

public class PersonContext{ 
    private static ThreadLocal<Person> context = new ThreadLocal<Person>(); 

    public static Person getPerson(Person person){ 
     return context.get(); 
    } 

    public static void setPerson(Person person){ 
     context.set(person); 
    } 

    public static void cleanUp(){ 
     context.remove(); 
    } 
} 

표준 JPA 엔티티 리스너가로드 된 사람에 대한 참조를 결합하는 데 사용할 수 있습니다 : 당신은 여기의 ThreadLocal을 사용하여 볼 수 있었다

public class PersonListener{ 

    @PostLoad 
    public void setContext(Person person){ 
     PersonContext.set(person); 
    } 
} 

엔티티 리스너는 엔티티에 등록 할 수 있습니다 :

을 : 현재 스레드 컨텍스트에 바인딩 된 사람에 대한 참조를 획득하고 그에 따라 헤더를 설정할 수 있습니다 인터셉터에서
@Entity 
@EntityListeners(PersonListener.class) 
public class Person(){ 

} 

public class PersonInterceptor extends HandlerInterceptorAdapter { 

    @Override 
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
     Object handler, ModelAndView modelAndView) throws Exception { 

     if(request.getMethod.equals("GET")){ 
      Person person = PersonContext.getPerson(); 
      response.addHeader("age", person.getAge()); 
     } 

     PersonContext.cleanUp(); 
    } 
} 

마지막으로 봄의 데이터 나머지와 인터셉터를 등록 :

@Bean 
public MappedInterceptor myMappedInterceptor() { 
    return new MappedInterceptor(new String[]{"person/**"}, new PersonInterceptor()); 
} 

문제 :

  • 후 부하 리스너는 사람의 모든 하중도 다른 경로에 등 클린업에 실행됩니다 up은 더 좋아질 필요가있다. 모든 경로에 2 차 인터셉터를 등록하여 정리 작업을 처리 하시겠습니까 ?? ??

대체 방법으로는 인터셉터의 데이터베이스를 다시 쿼리 할 수 ​​있습니다. 따라서 위 같은 요격 무언가로 대체 할 수있다 :

public class PersonInterceptor extends HandlerInterceptorAdapter { 

    @Autowired 
    private PersonRepository repository; 

    @Override 
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 
      ModelAndView modelAndView) throws Exception { 

     super.postHandle(request, response, handler, modelAndView); 

     if(request.getMethod.equals("GET")){ 
      Long personID = //extract id by examining request.getServletPath(); 
      Person person = repository.findOne(personID); 
      response.addHeader("age", person.getAge()); 
     } 
    } 
} 

이 제품은 추가 쿼리의 오버 헤드를 할 것이다 그러나 이것은 아마 1 레벨 캐시에서 가져온 의미해야하는 OpenEntityManagerInViewFilter을 구성하여 피할 수 있습니다.

관련 문제