@RequestParam 如何将参数绑定到对象上

有这么一个场景,假设前台传递给我们三个参数 id、name、age ,我们很自然的会想到使用 @RequestParam 来接收前台传递过来的参数,具体示例如下

@GetMapping("/getUserInfo")
public String getUserInfo(
        // 将前台传递过来的参数 id 对应的值绑定至 Integer 类型的参数 id
        // required 的默认值是 true,如果前台传递过来没有该参数,那么就会进行校验并报错
        // 当 required = false 时,如果没有传递参数 id,那么它不会报错,而是使用默认值 10086
        @RequestParam(value="id",required = false,defaultValue = "10086") Integer id,
        @RequestParam(value="name",required = false,defaultValue = "xiaomaomao") String name,
        @RequestParam(value = "age",required = false,defaultValue = "21") Integer age) {

    return "id===" + id + "  name===" + name + "  age===" + age;
}

上面的示例看起来没有什么问题,可是实际上我们不难发现,如果前台传递过来的参数不是三个,而是十个,如果继续使用 @RequestParam 的方式来接收请求参数,就需要十个 @RequestParam ,我们的代码可读性将会变得很差,并且当参数类型相同时,十分容易出错,有没有什么好的解决方案呢?

这个时候可能你会想到使用实体类来接收传递过来的十个参数,想法是正确的,可是 @RequestParam 不支持直接传递实体类的方式,那么有其它的解决办法吗?

答案是有的,具体示例如下

@GetMapping("/getUserInfo")
// 将请求参数中的 id、name、age 与实体类 saleman 进行绑定
public String getUserInfo(Saleman saleman) {
    return saleman.toString();
}

很简单,只需要定义一个实体类就能完美解决,可是,如果要实现类似于 @RequestParam(required=true) 的校验该怎么办呢?

其实也好办,我们可以在实体类里面进行校验

@Data
public class Saleman {
    // id 最小值为 100
    @Min(1)
    // id 不能为空,否则会报错
    @NonNull
    private Integer id;

    // 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
    @NotBlank
    private String name;

    // age 最大值为 30
    @Max(30)
    // age 不能为空,否则校验不通过
    @NonNull
    private Integer age;
}

注意你如果想要这些实体类中的注解生效,就必须要加上 @Valid 注解

@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman) {
    return saleman.toString();
}

这样,我们就模拟出了 @RequestParam(required=true) 的情形了,但是 @RequestParam 注解的作用还包括,如果未提供具体的参数,它会有默认值,这个该怎么实现呢?

做法很简单,只需要在声明实体类属性的时候给一个默认值即可,类似 private Integer id = 2

@Data
public class Saleman {
    // id 最小值为 100
    @Min(1)
    // id 不能为空,否则会报错
    @NonNull
    // 如果前台没有传递 id 参数,那么 id 会有默认值 2,注意这里的默认值一定要符合上面 @Min、@Nonnull 等注解的校验,否则该默认值设置的是不合理的
    private Integer id = 2;

    // 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
    @NotBlank
    private String name = "xiaomaomi";

    // age 最大值为 30
    @Max(30)
    // age 不能为空,否则校验不通过
    @NonNull
    private Integer age = 28;
}


@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman) {
    return saleman.toString();
}

到此,我们就已经模拟出了 @RequestParam 注解的所有功能(空值校验、空值时的默认值)

 

有时候根据业务需求,不会把所有的请求参数封装进同一个实体类中,我们可以将其封装进多个实体类中,具体的用法同上面一个实体类的相同

@Data
public class Saleman {
    // id 最小值为 100
    @Min(1)
    // id 不能为空,否则会报错
    @NonNull
    // 如果前台没有传递 id 参数,那么 id 会有默认值 2,注意这里的默认值一定要符合上面 @Min、@Nonnull 等注解的校验,否则该默认值设置的是不合理的
    private Integer id = 2;

    // 如果是字符串类型的数据,使用 @NotBlank 比 @NoNull 更好,因为 @NotBlank 不仅会校验 null 值,它还会校验空字符串
    @NotBlank
    private String name = "xiaomaomi";

    // age 最大值为 30
    @Max(30)
    // age 不能为空,否则校验不通过
    @NonNull
    private Integer age = 28;
}


@Data
public class Product {
    @Min(100)
    @NonNull
    private Integer id = 10001;
    @NotBlank
    private String productName = "yishengwenhou";
}


@GetMapping("/getUserInfo")
// 要想实体类中的注解生效,必须要在实体类加上 @Valid 注解
public String getUserInfo(@Valid Saleman saleman,@Valid Product product) {
    return saleman.toString() + "--------" + product.toString();
}

但是有一个需要注意的地方,如果两个实体类中有相同的属性,那么前台传入的参数值会同时封装进入两个实体类中,例如前台传入一个 id,而 Saleman、Product 两个实体类都有 id 这个属性,那么 id 对应的参数值就同时封装进了 saleman、product

 

posted @ 2021-09-14 15:29  变体精灵  阅读(6630)  评论(0编辑  收藏  举报