Spring MVC:复杂对象为GET @RequestParam

ren*_*rof 175 java spring-mvc

假设我有一个列出表中对象的页面,我需要放置一个表单来过滤表.过滤器作为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) { ... }
Run Code Online (Sandbox Code Playgroud)

假设我有MyObject:

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

    //Getters and setters
    ...
}
Run Code Online (Sandbox Code Playgroud)

我想做的事情如下:

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

可能吗?我怎样才能做到这一点?

Bij*_*men 225

你绝对可以这样做,只需删除@RequestParam注释,Spring会将你的请求参数干净地绑定到你的类实例:

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

  • 请注意,默认情况下,Spring要求MyObject的getter/setter自动绑定它.否则它不会绑定myObject. (29认同)
  • 如何在MyObject中设置字段是可选/非可选的?不知道如何找到适当的文件.. (18认同)
  • Biju,你能举个例子来说明这个吗?我正在对Rest API进行基本的http GET调用,它没有任何花哨的形式. (8认同)
  • @Biju,有没有办法控制默认值和'MyObject`所需,我们可以用@RequestParam做类似的方式? (5认同)
  • 我有这样的请求参数:`page-number` 和 `page-size`。我的请求 DTO 对象会是什么样子?在 Java 中,我无法创建名为“page-number”或“page-size”的字段。有没有办法告诉 spring 具有给定名称的请求参数应该映射到这个或那个字段?请指教。 (3认同)
  • 是的@Alexey,您可以通过`@ModelAttribute` 来做到这一点-如果您有一个`@ModelAttribute` 注释方法,您可以在那里提供默认值,然后您的真实方法可以从请求中添加其他详细信息-这里是一个链接有关如何执行此操作的更多信息:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-modelattrib-methods (2认同)
  • @BijuKunjummen如何更新`MyObject`以接受Snake案例中的查询参数并将其映射到`MyObject`的camel case成员.例如,`?book_id = 4`,应该与`MyObject`的`bookId`成员一起映射? (2认同)

Prz*_*wak 50

我将添加一些简短的例子.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

控制器类内的请求映射:

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

查询:

http://localhost:8080/app/handle?id=353,234
Run Code Online (Sandbox Code Playgroud)

结果:

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

我希望它有帮助:)

更新/ KOTLIN

因为目前我和Kotlin一起工作很多,如果有人想要定义类似的DTO,Kotlin中的类应该具有以下形式:

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

    override fun toString(): String {
        // to string implementation
    }
}
Run Code Online (Sandbox Code Playgroud)

data像这样的班级:

data class SearchDTO(var id: Array<Long> = arrayOf())
Run Code Online (Sandbox Code Playgroud)

Spring(在Boot中测试)为回答中提到的请求返回以下错误:

"无法将'java.lang.String []'类型的值转换为必需类型'java.lang.Long []';嵌套异常是java.lang.NumberFormatException:对于输入字符串:\"353,234 \""

数据类仅适用于以下请求参数形式:

http://localhost:8080/handle?id=353&id=234
Run Code Online (Sandbox Code Playgroud)

请注意这一点!

  • 我建议尝试使用Spring MVC验证器.示例:http://www.codejava.net/frameworks/spring/spring-mvc-form-validation-example-with-bean-validation-api (4认同)
  • 是否可以将“必需”设置为 dto 字段? (2认同)

Flu*_*ode 11

由于每个帖子下都会弹出如何设置必填字段的问题,我写了一个关于如何设置必填字段的小例子:

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?";
}
Run Code Online (Sandbox Code Playgroud)


hev*_*evi 8

我有一个非常类似的问题.实际上问题是我想的更深.我$.post使用的Content-Type:application/x-www-form-urlencoded; charset=UTF-8是默认使用的jquery .不幸的是,我的系统基于此,当我需要一个复杂的对象时,@RequestParam我不能让它发生.

在我的情况下,我试图用这样的东西发送用户偏好;

 $.post("/updatePreferences",  
    {id: 'pr', preferences: p}, 
    function (response) {
 ...
Run Code Online (Sandbox Code Playgroud)

在客户端,发送到服务器的实际原始数据是;

...
id=pr&preferences%5BuserId%5D=1005012365&preferences%5Baudio%5D=false&preferences%5Btooltip%5D=true&preferences%5Blanguage%5D=en
...
Run Code Online (Sandbox Code Playgroud)

解析为;

id:pr
preferences[userId]:1005012365
preferences[audio]:false
preferences[tooltip]:true
preferences[language]:en
Run Code Online (Sandbox Code Playgroud)

而服务器端是;

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

    ...
        return someService.call(preferences);
    ...
}
Run Code Online (Sandbox Code Playgroud)

我尝试了@ModelAttribute,添加了setter/getters,构造函数具有所有可能性,UserPreferences但没有机会,因为它将发送的数据识别为5个参数,但实际上映射方法只有2个参数.我也试过了Biju的解决方案但是会发生的是,spring使用默认构造函数创建一个UserPreferences对象,并且不会填充数据.

我通过从客户端发送首选项的JSon字符串来解决问题,并将其处理为服务器端的字符串;

客户:

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

服务器:

@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();
        }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,我在REST方法中手动完成了转换.在我看来,spring无法识别发送数据的原因是内容类型.

  • 我也有完全相同的问题。我使用`@RequestMapping(method = POST, path = "/settings/{projectId}") public void settings(@PathVariable String projectId, @RequestBody ProjectSettings settings) 做了更干净的解决方法 (5认同)

归档时间:

查看次数:

166384 次

最近记录:

5 年,11 月 前