这问题巧了,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);
}
}
}
总结
- 一件事情出错,不是一处问题造成的。
- 工程开发要规范,用最常规、最稳定的办法来实现。遇到稀奇古怪的问题就是冷门用法带来的。
- 对于常用的框架和工具库熟悉其底层原理,遇到问题可以很快定位。
作者:京东物流 杨攀
来源:京东云开发者社区
这问题巧了,SpringMVC 不同参数处理机制引发的思考的更多相关文章
- springmvc(2)--参数绑定
一.以实例来看springmvc各种参数绑定方式 先定义个dto类: public class RestInDto implements Serializable { private static ...
- springmvc请求参数异常统一处理
1.ExceptionHandlerController package com.oy.controller; import java.text.MessageFormat; import org.s ...
- SpringMVC中参数接收
/** * * SpringMVC中参数接收 * 1.接收简单类型 int String * 2.可以使用对象pojo接收 * 3.可以使用集合数据接收参数 * 页面: name="ids ...
- SpringMVC札集(04)——SpringMVC传递参数
自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onL ...
- SpringMVC请求参数接收总结
前提 在日常使用SpringMVC进行开发的时候,有可能遇到前端各种类型的请求参数,这里做一次相对全面的总结.SpringMVC中处理控制器参数的接口是HandlerMethodArgumentRes ...
- SpringMvc路径参数和url的两种实现方式
我们经常采用的SpringMvc路径参数经常的操作是在url后面采用?参数名=值1&参数名2=值2这种方式实现 RequestMapping的作用: 1)当作用在controller时,我们通 ...
- (转)SpringMVC学习(六)——SpringMVC高级参数绑定与@RequestMapping注解
http://blog.csdn.net/yerenyuan_pku/article/details/72511749 高级参数绑定 现在进入SpringMVC高级参数绑定的学习,本文所有案例代码的编 ...
- (转)SpringMVC学习(五)——SpringMVC的参数绑定
http://blog.csdn.net/yerenyuan_pku/article/details/72511611 SpringMVC中的参数绑定还是蛮重要的,所以单独开一篇文章来讲解.本文所有案 ...
- springMVC接受参数总结
springMVC接受参数分类及使用对应注解才能正确接受到参数,否则报400或者接受的参数值为null: 1.接受单个参数 @RequestParam 不需要转json串 2.接受一个实体 @Requ ...
- SpringMVC接受参数若干问题
最近2年在工作问题总结中,好几次遇到了SpringMVC接收参数的问题,今天特别总结下. SpringMVC接收参数的方法: Html参数输入: <input name="stat ...
随机推荐
- w10通过修改注册表实现禁止更新系统
对于Windows系统更新或驱动更新,并不是越新越好,当然新版本的系统可能带来了许多新的功能.漏洞修补.漂亮的用户界面和流畅的系统优化等,但是新版本的系统和驱动更新有可能会造成CPU占用居高不下,文件 ...
- [Java]算法练习:新农村建设
1 题目描述 from 网友 CASE1 输入 A1 A8 输出 [A1,A2,A3,A4,A5,A6,A7,A8] CASE2 输入 A1 K1 输出 [A1,B1,C1,D1,E1,F1,G1,H ...
- [Linux]Xmanager+Xshell远程管理桌面版CentOS物理服务器的桌面版CentOS虚拟机
1 需求/背景 在项目现场有这么一个情况,有1台Gnome版的CentOS的物理服务器,其内运行了2台通过vmware安装的Gnome桌面版的CentOS的虚拟服务器. 按照常规做法是: 将唯一的1台 ...
- LeeCode数组问题(一)
LeeCode 27:移除元素 题目描述: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度length. 不要使用额外的数组空间,你 ...
- RESTful API 为何成为顶流 API 架构风格?
作者孙毅,API7.ai 技术工程师,Apache APISIX Committer 万物互联的世界充满着各式各样的 API ,如何统筹规范 API 至关重要.RESTful API 是目前世界上最流 ...
- C#中使用CAS实现无锁算法
CAS 的基本概念 CAS(Compare-and-Swap)是一种多线程并发编程中常用的原子操作,用于实现多线程间的同步和互斥访问. 它操作通常包含三个参数:一个内存地址(通常是一个共享变量的地址) ...
- workerman、websocket简单聊天功能从0到1实现
一.workerman安装,测试环境为linux 1.在网站根目录,用命令行安装,要是出现root权限提示,输入y回车就行,或者新建一个用户再进入安装 Linux系统可以使用以下脚本测试本机PHP环境 ...
- 在 CentOS 上搭建 Mumble 服务器
Mumble 服务器搭建 前言 Mumble 是一个开源.低延迟.高质量的语音通话平台.可以在多个平台搭建,并且有多个开源的客户端(Windows.Linux.Android.MacOS).这是 官网 ...
- 2022-09-30:以下go语言代码输出什么?A: true true false true false; B: true false false true false; C: true true
2022-09-30:以下go语言代码输出什么?A: true true false true false: B: true false false true false: C: true true ...
- 2022-07-16:以下go语言代码输出什么?A:[];B:[5];C:[5 0 0 0 0];D:[0 0 0 0 0]。 package main import ( “fmt“ )
2022-07-16:以下go语言代码输出什么?A:[]:B:[5]:C:[5 0 0 0 0]:D:[0 0 0 0 0]. package main import ( "fmt" ...