web-dev-qa-db-ja.com

Spring MVC:GET @RequestParamとしての複合オブジェクト

テーブル上のオブジェクトを一覧表示するページがあり、テーブルをフィルタリングするためのフォームを配置する必要があるとします。フィルタはそのようなURLへのAjax GETとして送信されます。 http://foo.com/system/controller/action?page=1&prop1=x&prop2=y&prop3=z

そして私のControllerにたくさんのパラメータがある代わりに:

@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    @RequestParam(value = "prop1", required = false) String prop1,
    @RequestParam(value = "prop2", required = false) String prop2,
    @RequestParam(value = "prop3", required = false) String prop3) { ... }

MyObjectがあるとします。

public class MyObject {
    private String prop1;
    private String prop2;
    private String prop3;

    //Getters and setters
    ...
}

私は何かをしたいのですが。

@RequestMapping(value = "/action")
public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    @RequestParam(value = "myObject", required = false) MyObject myObject,) { ... }

出来ますか?どうやってやるの?

159
renanleandrof

@RequestParamアノテーションを削除するだけで、Springはリクエストパラメータをクラスインスタンスに明確にバインドします。

public @ResponseBody List<MyObject> myAction(
    @RequestParam(value = "page", required = false) int page,
    MyObject myObject)
207
Biju Kunjummen

私は私からいくつかの短い例を追加します。

DTOクラス

public class SearchDTO {
    private Long id[];

    public Long[] getId() {
        return id;
    }

    public void setId(Long[] id) {
        this.id = id;
    }
    // reflection toString from Apache commons
    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

コントローラクラス内のリクエストマッピング:

@RequestMapping(value="/handle", method=RequestMethod.GET)
@ResponseBody
public String handleRequest(SearchDTO search) {
    LOG.info("criteria: {}", search);
    return "OK";
}

クエリ:

http://localhost:8080/app/handle?id=353,234

結果:

[http-apr-8080-exec-7] INFO  c.g.g.r.f.w.ExampleController.handleRequest:59 - criteria: SearchDTO[id={353,234}]

それが役立つことを願っています:)

PDATE/KOTLIN

誰かが似たようなDTOを定義したいのであれば、私は現在Kotlinで多くの作業をしているので、Kotlinのクラスは次の形式を持つべきです:

class SearchDTO {
    var id: Array<Long>? = arrayOf()

    override fun toString(): String {
        // to string implementation
    }
}

このようなdataクラスでは、

data class SearchDTO(var id: Array<Long> = arrayOf())

spring(Bootでテスト済み)はanswerに記載されている要求に対して次のエラーを返します。

"タイプ 'Java.lang.String []'の値を必須タイプ 'Java.lang.Long []'への変換に失敗しました。ネストされた例外はJava.lang.NumberFormatExceptionです。\" 353,234\"

データクラスは次のリクエストパラメータ形式でのみ動作します。

http://localhost:8080/handle?id=353&id=234

これに注意してください。

45
Przemek Nowak

私は非常によく似た問題を抱えています。実際問題は私が思ったようにもっと深いです。デフォルトで$.postを使うjquery Content-Type:application/x-www-form-urlencoded; charset=UTF-8を使っています。残念ながら、私は自分のシステムをそれに基づいていて、@RequestParamとして複雑なオブジェクトが必要になったとき、それを実現することができませんでした。

私の場合、私は次のようなものを使ってユーザー設定を送信しようとしています。

 $.post("/updatePreferences",  
    {id: 'pr', preferences: p}, 
    function (response) {
 ...

クライアント側では、サーバーに送信される実際の生データは次のとおりです。

...
id=pr&preferences%5BuserId%5D=1005012365&preferences%5Baudio%5D=false&preferences%5Btooltip%5D=true&preferences%5Blanguage%5D=en
...

として解析されます。

id:pr
preferences[userId]:1005012365
preferences[audio]:false
preferences[tooltip]:true
preferences[language]:en

そしてサーバー側です。

@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") UserPreferences preferences) {

    ...
        return someService.call(preferences);
    ...
}

私は@ModelAttributeを試し、setter/getters、すべての可能性を持つコンストラクタをUserPreferencesに追加しましたが、送信されたデータを5つのパラメータとして認識するため、偶然にもマッピングされたメソッドは2つのパラメータしかありません。私はまたBijuの解決策を試しましたが、起こることは、デフォルトのコンストラクタでUserPreferencesオブジェクトを作成して、データを埋めないことです。

私はクライアント側から設定のJSon文字列を送信し、それがあたかもサーバー側のStringであるかのように処理することで問題を解決しました。

クライアント:

 $.post("/updatePreferences",  
    {id: 'pr', preferences: JSON.stringify(p)}, 
    function (response) {
 ...

サーバ:

@RequestMapping(value = "/updatePreferences")
public
@ResponseBody
Object updatePreferences(@RequestParam("id") String id, @RequestParam("preferences") String preferencesJSon) {


        String ret = null;
        ObjectMapper mapper = new ObjectMapper();
        try {
            UserPreferences userPreferences = mapper.readValue(preferencesJSon, UserPreferences.class);
            return someService.call(userPreferences);
        } catch (IOException e) {
            e.printStackTrace();
        }
}

簡単に言うと、RESTメソッド内で手動で変換を行いました。私の意見では、Springが送信されたデータを認識しないのはコンテントタイプです。

7
hevi

@ModelAttribute@RequestParam@PathParamなどを参照する回答は有効ですが、私が遭遇した小さな落とし穴があります。結果のメソッドパラメータは、SpringがDTOをラップするプロキシです。したがって、独自のカスタムタイプを必要とするコンテキストで使用しようとすると、予期しない結果が生じる可能性があります。

以下は機能しません。

@GetMapping(produces = APPLICATION_JSON_VALUE)
public ResponseEntity<CustomDto> request(@ModelAttribute CustomDto dto) {
    return ResponseEntity.ok(dto);
}

私の場合、ジャクソンバインディングで使用しようとすると、com.fasterxml.jackson.databind.exc.InvalidDefinitionExceptionになりました。

Dtoから新しいオブジェクトを作成する必要があります。

0
DKO

必須フィールドの設定方法に関する質問が各投稿の下に表示されるので、必要に応じてフィールドを設定する方法について小さな例を書きました。

public class ExampleDTO {
@NotNull
private String mandatoryParam;

private String optionalParam;

@DateTimeFormat(iso = ISO.DATE) //accept Dates only in YYYY-MM-DD
@NotNull
private LocalDate testDate;

public String getMandatoryParam() {
    return mandatoryParam;
}
public void setMandatoryParam(String mandatoryParam) {
    this.mandatoryParam = mandatoryParam;
}
public String getOptionalParam() {
    return optionalParam;
}
public void setOptionalParam(String optionalParam) {
    this.optionalParam = optionalParam;
}
public LocalDate getTestDate() {
    return testDate;
}
public void setTestDate(LocalDate testDate) {
    this.testDate = testDate;
}
}

@RequestMapping(value = "/test", method = RequestMethod.GET)
public String testComplexObject (@Valid ExampleDTO e){
        System.out.println(e.getMandatoryParam() + " " + e.getTestDate());
        return "Does this work?";
}
0
user2664623