2016-10-29 23 views
2

Iは、以下のJSONペイロードを返しバネRESTコントローラを有する:Spring RESTリポジトリからJSONレスポンスをラップする方法は?

[ 
    { 
    "id": 5920, 
    "title": "a title" 
    }, 
    { 
    "id": 5926, 
    "title": "another title", 
    } 
] 

その対応するGETリクエストメソッドでRESTコントローラ:

@RequestMapping(value = "example") 
public Iterable<Souvenir> souvenirs(@PathVariable("user") String user) { 
    return new souvenirRepository.findByUserUsernameOrderById(user); 
} 

すぐお土産クラスはPOJOである:

@Entity 
@Data 
public class Souvenir { 

    @Id 
    @GeneratedValue 
    private long id; 

    private String title; 

    private Date date; 
} 

についてhttps://www.owasp.org/index.php/OWASP_AJAX_Security_Guidelines#Always_return_JSON_with_an_Object_on_the_outsidehttp://haacked.com/archive/2009/06/25/json-hijacking.aspx/私はオブジェクト内で応答をラップしたいと思いますそれは攻撃に対して脆弱ではありません。これは、次のJSONペイロードになり

@RequestMapping(value = "example") 
public SouvenirWrapper souvenirs(@PathVariable("user") String user) { 
    return new SouvenirWrapper(souvenirRepository.findByUserUsernameOrderById(user)); 
} 

@Data 
class SouvenirWrapper { 
    private final List<Souvenir> souvenirs; 

    public SouvenirWrapper(List<Souvenir> souvenirs) { 
    this.souvenirs = souvenirs; 
    } 
} 

{ 
    "souvenirs": [ 
     { 
      "id": 5920, 
      "title": "a title" 
     }, 
     { 
      "id": 5926, 
      "title": "another title", 
     } 
    ] 
    } 

これは、いくつかのJSON/Javascriptの攻撃を防ぐのに役立ちますが、私はの冗長性を好きではないもちろん、私はこのような何かを行うことができますラッパークラス。もちろん、ジェネリックで上記のアプローチを一般化することができます。 Springエコシステムで同じ結果を達成する別の方法がありますか(注釈などありますか?)考え方は、動作がSpringによって自動的に行われるということです。したがって、オブジェクトのリストを返すRESTコントローラがあるときは常に、そのオブジェクトをオブジェクトラッパー内にラップしてオブジェクトの直接リストがシリアル化されないようにすることができます。

+0

春の代替?あなたは何をしゃべってますか? Strutsはそれを持っています、春はありません。あなたの質問を精緻化する。ラッパーだけが帽子です。春はあなたに持っています。もしフィナーレでなければ、メッセージをその場で拡張するかもしれません。 –

+0

ここに行きます:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/method/support/HandlerMethodReturnValueHandler.html。独自の実装では、必要な構造体にラップすることができます。 –

+1

何か面白い質問..実際の値がiterableであれば@ControllerAdviceで再生しようとすることもできますし、デシリアライザをハイジャックすることもできます。おそらくジャクソンのHttpメッセージコンバータを試してみてください。私たちを掲示し続ける:) –

答えて

1

私は以下のソリューション(@ヴァディム・kirilchukのおかげで)になってしまった:

私のコントローラは、まだ正確に以前のようになります。

@RequestMapping(value = "example") 
public Iterable<Souvenir> souvenirs(@PathVariable("user") String user) { 
    return new souvenirRepository.findByUserUsernameOrderById(user); 
} 

私は基本的に実行されますResponseBodyAdviceの次の実装を追加しましたこのAPPRとそう

@ControllerAdvice(basePackages = "package.where.all.my.controllers.are") 
public class JSONResponseWrapper implements ResponseBodyAdvice { 
    @Override 
    public boolean supports(MethodParameter returnType, Class converterType) { 
     return true; 
    } 

    @Override 
    @SuppressWarnings("unchecked") 
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { 
     if (body instanceof List) { 
      return new Wrapper<>((List<Object>) body); 
     } 
     return body; 
    } 

    @Data // just the lombok annotation which provides getter and setter 
    private class Wrapper<T> { 
     private final List<T> list; 

     public Wrapper(List<T> list) { 
      this.list = list; 
     } 
    } 
} 

:参照パッケージ内のコントローラは、(私の理解に)クライアントコールに応えしようとしたとき既存のメソッドシグネチャをコントローラ(public Iterable<Souvenir> souvenirs(@PathVariable("user") String user))に残すことができます。将来のコントローラでは、フレームワークがこの作業の一部を行うため、ラッパーの中でIterablesをラップすることについて心配する必要はありません。

+0

それはあなたを助けてくれてうれしい。ここで注意すべき点は、セキュリティ上の理由で問題ありませんが、コレクションのラッパーを手動で作成し、たとえばコレクションのサイズを指定する場合は非常に便利です。 {size:10、souvenirs:[..]}ラッパーオブジェクトを手動で作成する場合は、他にも可能性があります。 –

0

@RequestBodyはあなたが望むものです。フィールド "id"と "title"を持つPOJOを作成すると、ペイロードJSONがPOJOに自動的に解析されます。非常に使いやすく、@ PathVariableの使い方と同様に、コントローラのメソッドのパラメータに入れておくだけです。

関連する問題