Spring Boot中HttpRequest绑定POJO时部分字段出现空值问题排查
Twilio回调Webhook字段绑定失败问题解决
问题描述
搭建接收Twilio消息投递回调POST请求的Webhook服务器,尝试将请求数据绑定到StatusDeliveryModel对象(使用Lombok生成getter/setter),但ToNumber和FromNumber两个字段始终为空,其他字段绑定正常。通过HttpServletRequest可确认请求中To和From参数值有效,不想手动从request取值赋值,需排查问题原因并解决。
代码示例
StatusDeliveryModel.java
@Data @Getter @Setter public class StatusDeliveryModel { @JsonProperty("SmsSid") private String SmsSid; @JsonProperty("SmsStatus") private String SmsStatus; @JsonProperty("MessageStatus") private String MessageStatus; @JsonProperty("To") private String ToNumber; @JsonProperty("MessageSid") private String MessageSid; @JsonProperty("From") private String FromNumber; @JsonProperty("ApiVersion") private String ApiVersion; }
PostController.java
@RestController public class PostController { @Autowired private MyDataService myDataService; @PostMapping("/insert") public void insertIntoDatabase(@ModelAttribute StatusDeliveryModel statusDeliveryModel, HttpServletRequest request){ System.out.println(statusDeliveryModel.toString()); Enumeration<String> parameterNames = request.getParameterNames(); while (parameterNames.hasMoreElements()) { String paramName = parameterNames.nextElement(); String paramValue = request.getParameter(paramName); System.out.println(paramName + "': " + paramValue); } } }
打印结果
StatusDeliveryModel(SmsSid=XXXXXXXXXXXXXXXXXXXXXXX, SmsStatus=queued, MessageStatus=queued, ToNumber=null, MessageSid=XXXXXXXXXXXXXXXXXXXXXXX, FromNumber=null, ApiVersion=2010-04-01) SmsSid': XXXXXXXXXXXXXXXXXXXXXXX SmsStatus': queued MessageStatus': queued To': +1518XXXXXXX MessageSid': XXXXXXXXXXXXXXXXXXXXXXX From': +1213XXXXXXX ApiVersion': 2010-04-01
问题原因
核心问题是注解使用场景不匹配:
@JsonProperty是Jackson框架的注解,仅用于JSON格式数据的序列化/反序列化,对Spring的表单参数绑定(@ModelAttribute)完全不起作用。- 当前请求是Twilio发送的表单格式(application/x-www-form-urlencoded),Spring通过
@ModelAttribute绑定参数时,会根据JavaBean的属性名(或对应的setter方法名)与请求参数名精确匹配。你的属性名是ToNumber/FromNumber,而请求参数名是To/From,两者无法匹配,导致字段为空。
解决办法
方案1:修改属性名与请求参数一致(推荐)
直接将JavaBean中的属性名改为和请求参数名相同,Spring的@ModelAttribute会自动完成绑定:
@Data public class StatusDeliveryModel { private String SmsSid; private String SmsStatus; private String MessageStatus; private String To; // 与请求参数名一致 private String MessageSid; private String From; // 与请求参数名一致 private String ApiVersion; }
如果后续需要同时处理JSON格式请求,可保留@JsonProperty注解,不影响表单绑定。
方案2:配置Twilio发送JSON格式回调
如果不想修改JavaBean属性名,可以在Twilio控制台配置回调请求为JSON格式,然后将Controller中的@ModelAttribute替换为@RequestBody,此时@JsonProperty注解会生效:
@PostMapping("/insert") public void insertIntoDatabase(@RequestBody StatusDeliveryModel statusDeliveryModel, HttpServletRequest request){ // 业务逻辑不变 }
方案3:自定义表单参数绑定规则(复杂场景)
如果既不想改属性名,也不想修改Twilio配置,可以通过@InitBinder自定义参数绑定规则,将请求参数To/From映射到ToNumber/FromNumber:
@RestController public class PostController { @Autowired private MyDataService myDataService; @InitBinder public void initBinder(WebDataBinder binder) { // 将请求参数"To"绑定到ToNumber属性 binder.registerCustomEditor(String.class, "ToNumber", new PropertyEditorSupport() { @Override public void setAsText(String text) { setValue(text); } }); // 将请求参数"From"绑定到FromNumber属性 binder.registerCustomEditor(String.class, "FromNumber", new PropertyEditorSupport() { @Override public void setAsText(String text) { setValue(text); } }); } @PostMapping("/insert") public void insertIntoDatabase(@ModelAttribute StatusDeliveryModel statusDeliveryModel, HttpServletRequest request){ // 业务逻辑不变 } }
内容的提问来源于stack exchange,提问作者Mehsum Naqvi
相关产品推荐
相关产品推荐

