簡體   English   中英

Spring MVC:復雜對象作為 GET @RequestParam

[英]Spring MVC: Complex object as GET @RequestParam

假設我有一個頁面列出了表格上的對象,我需要放置一個表格來過濾表格。 過濾器作為 Ajax GET 發送到這樣的 URL: http : //foo.com/system/controller/action?page=1&prop1= x& prop2=y&prop3=z

而不是在我的控制器上有很多參數,比如:

@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,) { ... }

是否有可能? 我怎樣才能做到這一點?

您絕對可以這樣做,只需刪除@RequestParam注釋,Spring 會將您的請求參數干凈地綁定到您的類實例:

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

我將添加一些來自我的簡短示例。

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}]

我希望它有幫助:)

更新/科特林

因為目前我正在使用 Kotlin 進行很多工作,如果有人想定義類似的 DTO,那么 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 中測試)為回答中提到的請求返回以下錯誤:

“無法將類型 'java.lang.String[]' 的值轉換為所需的類型 'java.lang.Long[]';嵌套異常為 java.lang.NumberFormatException:對於輸入字符串:\\"353,234\\""

數據類僅適用於以下請求參數表單:

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

請注意這一點!

由於每個帖子下都會彈出如何設置必填字段的問題,我寫了一個關於如何設置必填字段的小例子:

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;
    }
}

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

我有一個非常相似的問題。 其實問題比我想象的更深。 我正在使用 jquery $.post它使用Content-Type:application/x-www-form-urlencoded; charset=UTF-8 默認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 ,向UserPreferences添加了具有所有可能性的 setter/getter、構造函數,但沒有機會,因為它將發送的數據識別為 5 個參數,但實際上映射的方法只有 2 個參數。 我也嘗試了 Biju 的解決方案,但是發生的情況是,spring 創建了一個帶有默認構造函數的 UserPreferences 對象,並且不填充數據。

我通過從客戶端發送首選項的 JSon 字符串並在服務器端將其作為字符串處理來解決該問題;

客戶:

 $.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 無法識別發送的數據的原因是內容類型。

雖然引用@ModelAttribute@RequestParam@PathParam等的答案是有效的,但我遇到了一個小問題。 生成的方法參數是 Spring 包裹在 DTO 周圍的代理。 因此,如果您嘗試在需要您自己的自定義類型的上下文中使用它,您可能會得到一些意想不到的結果。

以下將不起作用:

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

就我而言,嘗試在 Jackson 綁定中使用它會導致com.fasterxml.jackson.databind.exc.InvalidDefinitionException

您將需要從 dto 創建一個新對象。

是的,您可以通過一種簡單的方式做到這一點。 請參閱下面的行代碼。

URL - http://localhost:8080/get/request/multiple/param/by/map?name= 'abc' & id='123'

 @GetMapping(path = "/get/request/header/by/map")
    public ResponseEntity<String> getRequestParamInMap(@RequestParam Map<String,String> map){
        // Do your business here 
        return new ResponseEntity<String>(map.toString(),HttpStatus.OK);
    } 

接受的答案就像一個魅力,但如果對象有一個對象列表,它就不會按預期工作,所以這是我經過一些挖掘后的解決方案。

按照這個線程建議,這是我的做法。

  • 前端:將您的對象字符串化而不是將其編碼為 base64 以提交。
  • 后端:解碼 base64 字符串,然后將字符串 json 轉換為所需的對象。

它不是用郵遞員調試 API 的最佳選擇,但它按我的預期工作。

原始對象: {頁面:1,大小:5,過濾器:[{字段:“id”,值:1,比較:“EQ”}

編碼對象: eyJwYWdlIjoxLCJzaXplIjo1LCJmaWx0ZXJzIjpbeyJmaWVsZCI6ImlkUGFyZW50IiwiY29tcGFyaXNvbiI6Ik5VTEwifV19

@GetMapping
fun list(@RequestParam search: String?): ResponseEntity<ListDTO> {
    val filter: SearchFilterDTO = decodeSearchFieldDTO(search)
    ...
}

private fun decodeSearchFieldDTO(search: String?): SearchFilterDTO {
    if (search.isNullOrEmpty()) return SearchFilterDTO()
    return Gson().fromJson(String(Base64.getDecoder().decode(search)), SearchFilterDTO::class.java)
}

這里是 SearchFilterDTO 和 FilterDTO

class SearchFilterDTO(
    var currentPage: Int = 1,
    var pageSize: Int = 10,
    var sort: Sort? = null,
    var column: String? = null,
    var filters: List<FilterDTO> = ArrayList<FilterDTO>(),
    var paged: Boolean = true
)

class FilterDTO(
    var field: String,
    var value: Any,
    var comparison: Comparison
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM