您是否在请求映射方法中用@RequestParam注释了多个参数,并认为它不可读?

当请求中需要一个或两个输入参数时,注释看起来非常简单,但是当列表变长时,您可能会感到不知所措。

您不能在对象内部使用@RequestParam批注,但这并不意味着您没有其他解决方案。 在本文中,我将向您展示如何用object替换多个@RequestParams

1. @RequestParams的列表太长

无论是控制器还是其他类,我都相信您同意很难读取一长串方法参数 。 另外,如果参数类型相同,则更容易出错。

诸如Checkstyle之类的静态代码分析工具可以检测方法中的大量输入,因为它被广泛认为是一种不好的做法。

通常,将一组参数一起传递到应用程序的不同层。 这样的组通常可以形成一个对象 ,您要做的就是提取它并给它起一个适当的名称

让我们看一下用于搜索某些产品的示例GET端点:

@RestController
@RequestMapping("/products")
class ProductController {//...@GetMappingList<Product> searchProducts(@RequestParam String query,@RequestParam(required = false, defaultValue = "0") int offset,@RequestParam(required = false, defaultValue = "10") int limit) {return productRepository.search(query, offset, limit);}}

三个参数不是一个令人关注的数字,但它可以轻松增长。 例如,搜索通常包括排序顺序或一些其他过滤器。 在这种情况下,它们都被传递到数据访问层,因此它们似乎是参数对象提取的理想选择。

2.将@RequestParam绑定到POJO

根据我的经验,开发人员不会替换一长串@RequestParams,因为他们根本不知道这是可能的。 @RequestParam的文档没有提到替代解决方案。

从更新控制器的方法开始,接受POJO作为输入而不是参数列表。

@GetMapping
List<Product> searchProducts(ProductCriteria productCriteria) {return productRepository.search(productCriteria);
}

POJO不需要任何其他注释。 它应具有与将与HTTP请求绑定的请求参数匹配的字段列表,标准的getter / setter和无参数的构造函数。

class ProductCriteria {private String query;private int offset;private int limit;ProductCriteria() {}public String getQuery() {return query;}public void setQuery(String query) {this.query = query;}// other getters/setters}

验证POJO内部的请求参数

好的,但是我们不仅仅使用@RequestParam注释来绑定HTTP参数。 注释的另一个有用功能是可以根据需要标记给定参数。 如果请求中缺少参数,我们的端点可以拒绝它。

为了使用 POJO达到相同的效果(甚至更多!),我们可以使用bean验证 。 Java带有许多内置约束,但是如果需要,您总是创建一个自定义验证 。

让我们回到POJO并向字段添加一些验证规则。 如果只想模仿 @RequestParam(required = false) 的行为,则只需在必填字段上使用 @NotNull 批注

在许多情况下,使用@NotBlack代替@NotNull更有意义,因为它还涵盖了不需要的空字符串问题(长度为零的字符串)。

final class ProductCriteria {@NotBlankprivate String query;@Min(0)private int offset;@Min(1)private int limi;// ...}

请注意:

添加字段的验证注释不足以使其起作用。

您还需要在控制器的方法中使用@Valid批注标记POJO参数。 这样,您通知Spring它应该在绑定步骤上执行验证。

@GetMapping
List<Product> searchProducts(@Valid ProductCriteria productCriteria) {// ...
}

POJO内部的默认请求参数值

@RequestParam批注的另一个有用的功能是能够在HTTP请求中未提供参数时定义默认值。

当我们拥有POJO时,不需要特殊的魔术。 您只需将默认值直接分配给字段。 当请求中缺少参数时,没有任何内容将覆盖预定义的值。

private int offset = 0;
private int limit = 10;

3.多个对象

您没有被迫将所有HTTP参数放在单个对象中。 您可以在多个POJO中对参数进行分组。

为了说明这一点,让我们向端点添加排序条件。 首先,我们需要一个单独的对象。 就像之前一样,它具有一些验证约束。

final class SortCriteria {@NotNullprivate SortOrder order;@NotBlankprivate String sortAttribute;// constructor, getters/setters}

在控制器中,只需将其添加为单独的输入参数即可。 请注意,@ Valid批注在每个应验证的参数上都是必需的。

@GetMapping
List<Product> searchProducts(@Valid ProductCriteria productCriteria, @Valid SortCriteria sortCriteria) {// ...
}

4.嵌套对象

作为多个输入请求对象的替代,我们也可以使用组合。 参数绑定也适用于嵌套对象。

在下面,您可以找到一个示例,其中先前引入的排序条件已移至产品条件POJO。

要验证所有嵌套属性,应将@Valid批注添加到该字段。 请注意,如果该字段为null,Spring将不会验证其属性。 如果所有嵌套属性都是可选的,那可能是理想的解决方案。 如果不是,只需将@NotNull批注放在该嵌套对象字段上。

final class ProductCriteria {@NotNull@Validprivate SortCriteria sort;// ...}

HTTP参数必须使用点符号匹配字段名称。 在我们的情况下,它们应如下所示:

sort.order=ASC&sort.attribute=name

5.不变的DTO

如今,您可以看到一种趋势,它倾向于使用不固定对象,而使用二传手来取代传统的POJO。

不可变的对象有很多好处(还有缺点……但是……)。 我认为,最大的一项是维护简单

您是否曾经在应用程序的数十个层中进行过跟踪,以了解哪些条件导致了对象的特定状态? 这个或那个字段在哪里改变了? 为什么要更新? setter方法的名称什么也没解释。 二传手没有任何意义。

考虑到创建Spring框架的事实,Spring强烈依赖POJO规范就不会让人感到惊讶。 然而,时代变了,旧的模式变成了反模式。

没有简单的方法可以使用参数化的构造函数将HTTP参数神奇地绑定到POJO。 非参数构造函数是不可避免的。 但是,我们可以将该构造函数设为私有 (但遗憾的是不能在嵌套对象中使用)并删除所有的setter。 从公众的角度来看,该对象将变得不可变。

默认情况下,Spring需要使用setter方法将HTTP参数绑定到字段。 幸运的是,可以重新配置绑定程序并使用直接字段访问(通过反射)。

为了为整个应用程序全局配置数据绑定器,您可以创建一个控制器建议组件。 您可以在以@InitBinder批注注释的方法内部更改绑定程序配置,该方法接受绑定程序作为输入。

@ControllerAdvice
class BindingControllerAdvice {@InitBinderpublic void initBinder(WebDataBinder binder) {binder.initDirectFieldAccess();}}

创建该小类后,我们可以返回到POJO并从该类中删除所有setter方法,以使其变为只读状态以供公众使用。

final class ProductCriteria {@NotBlankprivate String query;@Min(0)private int offset = 0;@Min(1)private int limit = 10;private ProductCriteria() {}public String getQuery() {return query;}public int getOffset() {return offset;}public int getLimit() {return limit;}}

重新启动您的应用程序,并使用HTTP请求的参数。 它应该像以前一样工作。

结论

在本文中,您可以看到使用@RequestParam绑定在Spring MVC控制器中的HTTP请求参数可以轻松地替换为对多个属性进行分组的参数对象,仅不过是简单的POJO或可选的不可变DTO。

您可以在GitHub存储库中找到描述的样本 。 我希望所介绍的案例是不言自明的,但是如果有任何疑问或您想花两分钱,我强烈建议您将您的评论留在帖子下方。

翻译自: https://www.javacodegeeks.com/2018/10/how-bind-requestparam-object-spring.html

如何在Spring中将@RequestParam绑定到对象相关推荐

  1. 对象数组转成字符串数组 java_如何在Java中将对象数组转换为字符串数组

    如何在Java中将对象数组转换为字符串数组 我使用以下代码将Object数组转换为String数组: Object Object_Array[]=new Object[100]; // ... get ...

  2. 如何在 Spring 生态中玩转 RocketMQ?

    作者 | 通融.洛夜 来源 | 阿里巴巴云原生公众号 RocketMQ 作为业务消息的首选,在消息和流处理领域被广泛应用.而微服务生态 Spring 框架也是业务开发中最受欢迎的框架,两者的完美契合使 ...

  3. 如何在Spring生态中玩转RocketMQ?

    简介: RocketMQ作为业务消息的首选,在消息和流处理领域被广泛应用.而微服务生态Spring框架也是业务开发中最受欢迎的框架,两者的完美契合使得RocketMQ成为Spring Messagin ...

  4. 如何在Python中将字典键作为列表返回?

    本文翻译自:How to return dictionary keys as a list in Python? In Python 2.7 , I could get dictionary keys ...

  5. 如何在Java中将String转换为int?

    如何在Java中将String转换为int ? 我的字符串仅包含数字,我想返回它代表的数字. 例如,给定字符串"1234" ,结果应为数字1234 . #1楼 好吧,要考虑的一个非 ...

  6. Spring-AOP @AspectJ进阶之绑定代理对象

    概述 实例 概述 使用this()或target()可绑定被代理对象实例,在通过类实例名绑定对象时,还依然具有原来连接点匹配的功能,只不过类名是通过增强方法中同名入参的类型间接决定罢了. 这里我们通过 ...

  7. 如何在Spring Boot应用程序中使用配置文件

    你好朋友, 在本教程中,我们将学习如何在Spring Boot应用程序中使用配置文件. 我们将在本教程中讨论以下几点: 1.什么是Spring Boot Profile,为什么我们需要分析 2.如何使 ...

  8. 如何在Spring Boot App中集成H2数据库

    你好朋友, 在本教程中,我们将尝试探索如何在Spring Boot应用程序中与H2数据库集成. 在进行检查之前,让我们了解有关H2数据库的一些基础知识,如下所述,然后我们将讨论H2数据库与Spring ...

  9. java 自定义xml_6.1 如何在spring中自定义xml标签

    dubbo自定义了很多xml标签,例如,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 1 packagecom.hulk.testdubbo.model ...

最新文章

  1. 新闻网站项目django--注册页
  2. 网站分类前导:获取网站标题和描述及对相关信息进行分词处理
  3. 制作ubuntu 18.04 U盘启动盘
  4. java构造函数传参_java 构造函数 , 参数传递 , lamda表达式
  5. Deploy Oracle 10.2.0.5 on Red Hat Enterprise Linux 6.4
  6. Android滑动返回上一级界面
  7. 31 GroupSock(AddressString)——live555源码阅读(四)网络
  8. pythonos文件目录方法_python12-OS模块(文件/目录方法)
  9. 从源码分析HashSet集合
  10. java传奇_传奇私服登录器Java版附源代码JAVA多媒体源码下载
  11. 依赖注入框架 ----Dagger2 使用详解及源码分析
  12. 计算机病毒模块测试题,计算机病毒分类测试题集
  13. android调用系统录制视频教程,Android开发之使用MediaRecorder录制视频,android视频录制...
  14. 保证RabbitMQ消息的可靠性总结
  15. CAD得到所有图层名(网页版)
  16. 车联网(智能车机)测试行业解决方案
  17. html中div标签圈套,HTML中div标签和span标签的应用
  18. 那些解释起来很蛋疼的IT工种
  19. 虚室教学:足不出户就能做实验
  20. 该卸载PhotoShop了!MIT用AI实现3分钟自动抠图,精细到头发丝

热门文章

  1. JFreeChart(六)之3D饼图/条形图
  2. 全球如何保证区块生成是匀速的?
  3. Tomcat解决HTTP GET中文乱码
  4. Servlet使用适配器模式进行增删改查案例(jdbc.properties)
  5. sql server链接查询
  6. java实现九九乘法表的输出
  7. 2017蓝桥杯省赛---java---A---1(迷宫)
  8. zookeeper出现Error contacting service. It is probably not running.
  9. android:background大小,小Demo小知识-android:foreground与android:background
  10. MySQL、MongoDB、列数据库的区别及应用场景