2017-10-30 17 views
1

Spring Data Restのエンティティの1つに、レスポンスのヘッダーに追加する属性値があります。これを行う方法?Springデータレストの特定のリソースにカスタムヘッダーを追加する方法

デフォルトの(すべての応答用)ハンドラインターセプタで変更する方法が見つかりました。そして、私はバージョン、エタグ、変更されたものについても見つけました。 これは私が欲しいものではありません。

ヘッダーはRESTリソースの1つに設定する必要があり、値はインスタンス/レコードに依存します。

例として:Personの属性はageです。 Person RESTリソース(GET /person/{id}など)へのリクエストはすべて、httpヘッダーとしてageという値を返す必要があります(例: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

まず、特定のパスにインターセプタをバインドして、問題の半分を解決できます。

2番目の問題は、要求された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()); 
} 

問題:

  • ポスト・ロード・リスナーにも他のパス上の人のすべての負荷に実行し、そう無害ますより良いものにする必要があります。クリーンアップを処理するために、すべてのパスに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()); 
     } 
    } 
} 

これは、追加のクエリのオーバーヘッドを持っているでしょうが、これはおそらく、それが第一レベルのキャッシュからフェッチであることを意味するべきOpenEntityManagerInViewFilterを構成することによって回避することが可能です。

関連する問題