一、场景分析
假设有如下一个对象,它的三个属性全部大写。
java">package com.study.member.entity;
import lombok.Data;
@Data
public class Member {private String NAME;private Integer AGE;private String PHONE;
}
在使用 SpringMVC 进行接口调用的时候,会发现入参 member 的属性并没有正确绑定。
java">package com.study.member.controller;import com.study.member.entity.Member;
import com.study.common.base.R;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("member")
public class MemberController {@PostMapping("/register")public R<Void> register(@RequestBody Member member) {System.out.println(member);return R.success();}
}
-------------------------------------------------
POST http://localhost:8080/member/register
Content-Type: application/json{"NAME": "会员","AGE": 11,"PHONE": "12345678"
}
输出:
Member(NAME=null, AGE=null, PHONE=null)
像这种属性全部大写的情况,也是我们平常可能会遇到的场景。
比如,这个接口是开放给第三方回调的,第三方回调的 JSON 报文 的对象属性并不一定都是严格的首字母小写驼峰格式。有时候跨语言系统的相互调用,这种情况就更常见了。
二、解决方案
在 Spring Boot 中,可以通过以下几种方式指定 JSON 填充的属性名称
1、使用 @JsonProperty 注解
在实体类的属性上使用 @JsonProperty 注解来指定在 JSON 中的属性名称。
java">package com.study.member.entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class Member {@JsonProperty(value="NAME")private String NAME;@JsonProperty(value="AGE")private Integer AGE;@JsonProperty(value="PHONE")private String PHONE;
}
-------------------------------------------------
POST http://localhost:8080/member/register
Content-Type: application/json{"NAME": "会员","AGE": 11,"PHONE": "12345678"
}
输出:
Member(NAME=会员, AGE=11, PHONE=12345678)
当然,对象属性你也可以按首字母小写驼峰格式命名,jackson 也能正确绑定。
java">package com.study.member.entity;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;@Data
public class Member {@JsonProperty(value="NAME")private String name;@JsonProperty(value="AGE")private Integer age;@JsonProperty(value="PHONE")private String phone;
}
-------------------------------------------------
POST http://localhost:8080/member/register
Content-Type: application/json{"NAME": "会员","AGE": 11,"PHONE": "12345678"
}
输出:
Member(name=会员, age=11, phone=12345678)
不过,使用这个注解的话,在 JSON 数据反序列化时,使用的也还是 @JsonProperty 注解配置的名称:
java">package com.study.member.entity;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;@Data
public class Member {@JsonProperty(value="NAME")private String name;@JsonProperty(value="AGE")private Integer age;@JsonProperty(value="PHONE")private String phone;
}
-------------------------------------------------
package com.study.member.controller;import com.study.member.entity.Member;
import com.study.common.base.R;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("member")
public class MemberController {@GetMapping("/findByName")public R<Member> findByName(String name) {Member member = new Member();member.setName(name);member.setAge(21);member.setPhone("456");return R.success(member);}
}
-------------------------------------------------
POST http://localhost:8080/member/findByName?name=小林
Content-Type: application/json输出:
{"code": 0,"msg": "success","data": {"NAME": "小林","AGE": 21,"PHONE": "456"}
}
那如果希望对象JSON在反序列化的时候,不改变属性名称,那怎么办呢?使用 @JsonAlias 注解。
2、使用 @JsonAlias 注解
@JsonAlias 可以为属性提供一个或多个别名,在 JSON 处理时可以使用这些别名来填充属性。
java">package com.study.member.entity;import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.Data;@Data
public class Member {@JsonAlias({"NAME", "NICK_NAME"})private String name;@JsonAlias(value="AGE")private Integer age;@JsonAlias(value="PHONE")private String phone;
}
-------------------------------------------------
@RestController
@RequestMapping("member")
public class MemberController {@PostMapping("/register")public R<Void> register(@RequestBody Member member) {System.out.println(member);return R.success();}
}
-------------------------------------------------
###
POST http://localhost:8080/member/register
Content-Type: application/json{"NAME": "会员","NICK_NAME": "一心","AGE": 11,"PHONE": "12345678"
}
输出:
Member(name=一心, age=11, phone=12345678)
可以看到,有多个别名填充同一个属性时,按顺序填充,最后是 NICK_NAME 被填充进去。
这种方式,对象JSON在被反序列化时,并不改变属性名称。
java">@RestController
@RequestMapping("member")
public class MemberController {@GetMapping("/findByName")public R<Member> findByName(String name) {Member member = new Member();member.setName(name);member.setAge(21);member.setPhone("456");return R.success(member);}
}
-------------------------------------------------
GET http://localhost:5911/member/findByName?name=小王
Content-Type: application/json输出:
{"code": 0,"msg": "success","data": {"name": "小王","age": 21,"phone": "456"}
}