这问题巧了,SpringMVC 不同参数处理机制引发的思考 | 京东云技术团队
这个问题非常有趣,不是SpringMVC 的问题,是实际开发中混合使用了两种请求方式暴露出来的。
问题场景
功能模块中,提供两个 Http 服务。一个是列表查询(application/json 请求),一个是列表导出(表单请求)。运行环境发现个问题:MVC model 新添加的属性,类似的 Http 请求,一个有值,一个没有
代码如下:
/** * application/json 请求。 这种情况 param.field2 有值 ✔ * @param param RequestResponseBodyMethodProcessr 处理 HttpServletRequest 参数 */ @PostMapping(value = "query") public ResponseResult<Page<SomeData>> queryByCondition(@RequestBody SomeParam param){ // 业务逻辑... } /** * application/x-www-form-urlencoded 请求 这种情况 param.field2 没有有赋值 ❌ * @param param ServletModelAttributeMethodProcessor 处理 HttpServletRequest 参数 */ @PostMapping(value = "export") public void exportExcel(SomeParam param) { // 业务逻辑... } public class SomeParam { // 这个是原有的,有 get set 方法 private String field1; // 这个是新增的,没有get set 方法 (这是一个巧合、意外)。 问题就出在这里。 private String field2; }
❓ 根据代码分析,那应该是 SpringMVC 针对这两种参数处理的机制不同。
针对上述的参数处理,可以参考:
RequestResponseBodyMethodProcessor、 ServletModelAttributeMethodProcessor
Insight RequestResponseBodyMethodProcessor
处理 Http Body 的数据。解析注解 RequestBody 的参数。
针对 MimeType 为 application/json 的请求,按照json 格式进行反序列化。
默认参数处理器
MappingJackson2HttpMessageConverter
string 反序列化为对象,使用的是
com.fasterxml.jackson.databind.ObjectMapper。
上述工程中,对 ObjectMapper 开启 private 属性检测。新增的属性可以正常反序列化。
ObjectMapper mapper = new ObjectMapper(); // 这又是一个巧合、意外 咋还有这个用法 mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
Visibility 具体的用法示例参考: Jackson - Decide What Fields Get (De)Serialized | Baeldung
原理: 如果没有 setter 方法,jackson 会操作 field 来完成赋值。
/** * This concrete sub-class implements property that is set directly assigning to a Field. */ public final static class FieldProperty extends SettableBeanProperty { @Override public final void set(Object instance, Object value) throws IOException { try { _field.set(instance, value); } catch (Exception e) { _throwAsIOE(e, value); } } }
Insight ServletModelAttributeMethodProcessor
自定义 Class 参数解析
通过解析 request parameters, 用来构造和初始化对应的方法入参。
主要通过
ServletRequestDataBinder.bind(request) 来完成。
/** * Apply given property values to the target object. * By default, unknown fields will be ignored. * * @see org.springframework.validation.DataBinder#applyPropertyValues */ protected void applyPropertyValues(MutablePropertyValues mpvs) { try { // Bind request parameters onto target object. // 默认使用 BeanWrapperImpl.setPropertyValue() getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields()); } catch (PropertyBatchUpdateException ex) { // Use bind error processor to create FieldErrors. } }
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException { // 通过遍历 request parameters 来尝试对 target 进行赋值 List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ? ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); for (PropertyValue pv : propertyValues) { try { // etPropertyValue 使用 JDK 的 Introspector 来进行序列化操作。 // 没有setter 方法,自然没法赋值。 setPropertyValue(pv); } } }
总结
- 一件事情出错,不是一处问题造成的。
- 工程开发要规范,用最常规、最稳定的办法来实现。遇到稀奇古怪的问题就是冷门用法带来的。
- 对于常用的框架和工具库熟悉其底层原理,遇到问题可以很快定位。
作者:京东物流 杨攀
来源:京东云开发者社区

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
从2PC和容错共识算法讨论zookeeper中的Create请求 | 京东云技术团队
最近在读《数据密集型应用系统设计》,其中谈到了zookeeper对容错共识算法的应用。这让我想到之前参考的zookeeper学习资料中,误将容错共识算法写成了2PC(两阶段提交协议),所以准备以此文对共识算法和2PC做梳理和区分,也希望它能帮助像我一样对这两者有误解的同学。 1. 2PC(两阶段提交协议) 两阶段提交 (two-phase commit) 协议是一种用于实现跨多个节点的原子事务(分布式事务)提交的算法。它能确保所有节点提交或所有节点中止,并在某些数据库内部使用,也以XA事务的形式在分布式服务中使用。 在 Java EE 中,XA事务使用 JTA(Java Transaction API) 实现。 2PC的实现 2PC包含准备阶段和提交阶段两个阶段,需要借助协调者(事务管理器,如阿里巴巴的Seata) 来实现,参与分布式事务的数据库节点为参与者。当分布式服务中的节点准备提交时,协调者开始准备阶段:发送一个准备请求到每个节点,询问它们是否能够提交,然后协调者会跟踪参与者的响应 如果所有参与者都回答"是",表示它们已经准备好提交,那么协调者在提交阶段发出提交请求,分布式事务提...
- 下一篇
前端文件上传的几种交互造轮子 | 京东云技术团队
背景 前端文件上传本来是一个常规交互操作,没什么特殊性可言,但是最近在做文件上传,需要实现截图粘贴上传,去找了下有没有什么好用的组件,网上提供的方法有,但是没找完整的组件来支持cv上传,经过了解发现可以用剪贴板功能让自己的cv实现文件上传,于是自己就整合了目前几种文件上传的交互方式,码了一个支持cv的vue3文件上传组件(造个轮子)。 介绍 作为一个完整的组件内容还是挺多的,这里主要介绍下上传交互中一些主要功能,包括上传的几种交互方式, 上传进度的获取,上传类型的限制,默认上传请求和自定义上传请求。 以下代码都是非完整代码,大家用于参考实现过程,可以通过以下代码修改来完成自己想要的交互功能。 几种交互 1,点击选择上传 点击选择是最常见的上传交互,之前原生上传控件,样式修改比较麻烦,为了修改上传样式,我们可以把该控件设置隐藏,用其他元素通过从click交互, 来触发该文件选择控件。在选择文件控件上绑定onchange事件,该控件在change后获取到文件,然后调用上传方法,实现如下: <div class="uploader-content" @click="handleClic...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7