在所有的 Web 类应用中,参数的绑定都是一个非常重要的话题,本章中,就来看看 Jersey 中的参数绑定方式。

绑定路径参数

在 Jersey 中,使用 @PathParam 完成路径参数绑定:

  1. package com.example.jerseydemo.parameterbinding;
  2. import javax.ws.rs.GET;
  3. import javax.ws.rs.Path;
  4. import javax.ws.rs.PathParam;
  5. import javax.ws.rs.Produces;
  6. import javax.ws.rs.core.MediaType;
  7. @Path("/pathparam") // 基路径
  8. @Produces(value = MediaType.APPLICATION_JSON)
  9. public class TestService {
  10. /**
  11. * 映射 url中的路径参数
  12. * @param id
  13. * @return
  14. */
  15. @GET
  16. @Path("/test1/{id}")
  17. public String testPathParam(@PathParam("id") String id){
  18. return id;
  19. }
  20. /**
  21. * 映射多个路径参数
  22. * @param key
  23. * @param value
  24. * @return
  25. */
  26. @GET
  27. @Path("/test2/{key}/{value}")
  28. public String testPathParam2(@PathParam("key") String key, @PathParam("value") String value){
  29. return key+":"+value;
  30. }
  31. }

image.png
image.png

映射普通请求参数

在实际开发中,类似对资源的查询等操作,需要通过获取请求中的查询参数内容。Jersey 提供了 @QueryParam 注解完成参数绑定。

  1. package com.example.jerseydemo.parameterbinding;
  2. import javax.ws.rs.GET;
  3. import javax.ws.rs.Path;
  4. import javax.ws.rs.QueryParam;
  5. /**
  6. * @author hanliukui
  7. * @Date 2021/4/3 14:43
  8. */
  9. @Path("/queryparam")
  10. public class QueryParamService {
  11. /**
  12. * 映射 普通参数传参
  13. * @param param1
  14. * @param param2
  15. * @return
  16. */
  17. @GET
  18. @Path("/test1")
  19. public String queryParam1(@QueryParam("aa") String param1,@QueryParam("bb") String param2 ){
  20. return "param1:"+param1+",param2:"+param2;
  21. }
  22. }

image.png

映射表单提交参数

使用表单提交是互联网应用再常见不过的方式,在 SpringMVC 中,提供了各种牛逼的能力来把表单中的数据映射到方法的参数,模型中,但是在这块上,Jersey 同样很强大,但是稍微使用复杂一点。要演示表单提交参数绑定,我们先创建一个简单的 Employee 类:

  1. @Setter
  2. @Getter
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class Employee {
  6. private Long id;
  7. private String name;
  8. private int age;
  9. }

需求:根据提交的数据创建一个 Employee 对象。

  1. /**
  2. * 映射表单提交参数,要求请求是POST,PUT,并且编码格式必须是x-www-form-urlencoded
  3. *
  4. * @param name
  5. * @param age
  6. * @return
  7. */
  8. @PUT
  9. @Path("/form")
  10. @Produces(MediaType.APPLICATION_JSON)
  11. public Employee formParam(@FormParam("name") String name, @FormParam("age") int age) {
  12. return new Employee(1L, name, age);
  13. }

image.png

普通值绑定

第一种方式,在 Jersey 中,提供了一个 @FormParam 注解来完成表单中内容到参数的绑定(API 文档解释,是绑定一个请求实体中的表单参数到资源方法参数 Binds the value(s) of a form parameter contained within a request entity body to a resource method parameter)。
注意几个点:
1、@FormParam 注解只能接受 x-www-form-urlencoded 编码格式的 form 表单提交,这个是必要条件;
2、@FormParam 注解能够完成的绑定类型有:

  • 简单类型;
  • 绑定到一个对象,要求这个对象的类有一个接受单个 String 类型的构造器;

    1. class Employee {
    2. private Long id;
    3. private String name;
    4. private int age;
    5. public Employee() {
    6. }
    7. // 单个 String 类型的构造器
    8. public Employee(String name) {
    9. this.name = name;
    10. }
    11. ...
    12. }
  • 绑定到一个对象,要求这个对象的类有一个 valueOf(String) 或者 fromString(String) 的静态的构建方法,比如

    1. public static Employee valueOf(String name){
    2. return new Employee(name);
    3. }
  • 提供一个 ParamConverterProvider(这个后面讲 Provider);

  • 可以绑定到一个 List,Set 上面,例如:
  1. @POST
  2. @Path("/hobby")
  3. @Produces(MediaType.APPLICATION_JSON)
  4. public Employee formParam(@FormParam("hobby") Set<String> hobbies) {
  5. System.out.println(hobbies);
  6. return new Employee();
  7. }

那么,使用 POST param/hobby?hobby=java&hobby=haha&hobby=hehe 就可以完成 Set 的绑定(注意表单编码格式一定是 x-www-form-urlencoded)。

另外,@FormParam 可以配合一个 @DefaultValue 标签来设置默认值,简单演示:

  1. @PUT
  2. @Path("/form")
  3. @Produces(MediaType.APPLICATION_JSON)
  4. public Employee formParam(@FormParam("name") String name,
  5. @DefaultValue("18") @FormParam("age") int age) {
  6. return new Employee(1L, name, age);
  7. }

当 @FormParam 绑定失败即可使用 @DefaultValue 设置的值。

绑定到对象

在 SpringMVC 中,我们更常见的是直接把请求参数绑定到一个我们需要的模型或者 VO 中。在 Jersey 中,使用 @FormParam 注解无法完成,可以使用 @BeanParam@FormParam 配合使用:

首先修改 Employee 对象:

  1. @Setter
  2. @Getter
  3. @NoArgsConstructor
  4. @AllArgsConstructor
  5. public class Employee {
  6. private Long id;
  7. @FormParam("name")
  8. private String name;
  9. @FormParam("age")
  10. private int age;
  11. }

注意,我们把 @FormParam 标签移动到了 Employee 的对应属性上。当然在实际开发中,更多应该是在 VO 对象类中;

  1. /**
  2. * 直接映射到模型,要求请求是POST,PUT,并且编码格式必须是x-www-form-urlencoded
  3. *
  4. * @param e
  5. * @return
  6. */
  7. @POST
  8. @Path("/formpojo")
  9. @Produces(MediaType.APPLICATION_JSON)
  10. public Employee formPojoParam(@BeanParam Employee e) {
  11. e.setId(2L);
  12. return e;
  13. }

然后,再使用 Jersey 提供了 @BeanParam 注解,完成请求参数到自定义模型的绑定。

注意,在自定义模型中,不光可以使用 @FormParam ,可以使用 @XXXParam ,比如前面提到过的 @PathParam

直接获取表单内容

前面介绍过使用 @FormParam@BeanParam 来获取表单中的数据,下面再介绍一种通过直接获取表单内容的方式:

  1. /**
  2. * 使用MultivaluedMap直接获取POST表单编码格式必须是x-www-form-urlencoded的表单内容
  3. *
  4. * @param fs
  5. * @return
  6. */
  7. @POST
  8. @Path("/formui2")
  9. public String formPojoParam(MultivaluedMap<String, String> fs) {
  10. System.out.println(fs);
  11. return "success";
  12. }

那么获取到的 MultivaluedMap 类型中,就包含了表单里面所有的参数内容。

映射请求头参数

从请求头中获取一些参数,比如请求头中自定义的 token 等信息,可以直接使用 Jersey 提供的 @HeaderParam 注解完成:

  1. /**
  2. * 通过@HeaderParam获取请求头内容
  3. */
  4. @GET
  5. @Path("/head")
  6. public String headParam(@HeaderParam("token") String token) {
  7. System.out.println(token);
  8. return "success";
  9. }

那么在请求的时候,我们可以在头信息中添加:
(2)Jersey参数绑定 - 图5

就可以正常看到后台把 token 绑定到 token 参数中。需要注意的是, @DefaultValue 标签都是可以和这些 @XXXParam 配合使用的,并且也可以添加到需要绑定的模型属性上的。

绑定矩阵参数

矩阵参数听着很奇怪,其实很简单,比如我们在做分页的时候,可以使用类似这样的请求:
/resource;pageSize=10;currentPage=2
注意,这个请求并不是普通的参数提交方式,按照普通的方式,应该是:
/resource?pageSize=10&tPage=2
注意查看两者的区别。
那么使用矩阵参数有什么好处呢?在 REST 架构中,矩阵参数可以把这些参数一起看做一个资源,意思就是上面的两个连接中,第一个 URI 可以看做第二页,每页 10 条 resource 资源,把这个整体作为一个资源去看待;又比如这样一个资源:
/players/ladder;level=king
就可以看成天梯中等级为王者的玩家,把这个概念直接作为一个资源整体看待。

理解了矩阵参数,Jersey 提供了 @MatrixParam 标签来完成矩阵参数的绑定:

  1. /**
  2. * 从请求路径中分离出key=value的值
  3. *
  4. * @param currentPage
  5. * @param pageSize
  6. * @param keyword
  7. * @return
  8. */
  9. @GET
  10. @Path("/matrix")
  11. public String matrix(@MatrixParam("currentPage") int currentPage, @MatrixParam("pageSize") int pageSize,
  12. @MatrixParam("keyword") String keyword) {
  13. System.out.println("currentPage:" + currentPage);
  14. System.out.println("pageSize:" + pageSize);
  15. System.out.println("keyword:" + keyword);
  16. return "success";
  17. }

那么,当我们做出请求

(2)Jersey参数绑定 - 图6

就可以正确的分别解析出其中的 pageSize,currentPagekeyword 参数。但是需要注意一点,Jersey 只能解析出处于最后一个路径中的矩阵参数。

至此,Jersey 提供的最基本的几种请求参数绑定方式介绍完毕,下一结介绍 @Context 注解的使用。