对前端传入的json对象解析成多个对象

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 如果是多个对象呢?那怎么解决这个问题?此时就可以用到:multiRequestBodyDemo(@MultiRequestBody("dog")Dog dog, @MultiRequestBody("user") User user)这种方式进行接收了。但spring boot是不支持这种方式的。因此,就需要自己写一个解析器来解析这样的传入方式和接收的方式。通常,比如我们有分页和对象时,就可以采用这种方式进行接收。

最近项目中类似:

multiRequestBodyDemo(@MultiRequestBody("dog")

Dog dog, @MultiRequestBody("user") User user)

的注解看到了很多,那么这些注解是Spring MVC自带的吗?当然不是,spring MVC中自带的是@RequestBody的注解,这个注解有什么作用呢?这个注解可以将前端传进来的json数据进行解析成json数据。而如果我们没有采样@MultiRequestBody时,通常的做法是将其首先转成json首先转成json,然后进行json数据解析,然后对相关的属性进行逐一获取。下面的例子来源于网上,同时也是我们常用的解析方式之一。但是,如果我们获取属性过多,必然就会带来一个问题,对于代码会显得很长,不够优雅。

那还有一种方式那就是采样对象去接收,但是对象接收,但是如果是多个对象呢?那怎么解决这个问题?

此时就可以用到:

multiRequestBodyDemo(@MultiRequestBody("dog")

Dog dog, @MultiRequestBody("user") User user)

这种方式进行接收了。但spring boot是不支持这种方式的。因此,就需要自己写一个解析器来解析这样的传入方式和接收的方式。通常,比如我们有分页和对象时,就可以采用这种方式进行接收。

/*** 修改或者新增热门搜索* @param hotSearch* @param request* @return*/@RequestMapping(value="/servehotselectiveajax")
@ResponseBodypublicintservehotselectiveajax(HttpServletRequestreq,HttpServletResponseresp,@RequestBodyJSONObjectobj) {
intcount=0;
intcountAddHotSearch=0;
intcountEditHotSearch=0;
LOGGER.info("data:"+obj.toJSONString());
//data:{"createArr":[{"hotSearchId":"","keyword":"ss","sort":"5","tempid":"21"}],"modifyArr":[{"hotSearchId":"205","keyword":"华为","sort":"2","tempid":"21"},{"hotSearchId":"206","keyword":"游戏本","sort":"3","tempid":"21"},{"hotSearchId":"207","keyword":"平板电视","sort":"3","tempid":"21"},{"hotSearchId":"208","keyword":"连衣裙","sort":"4","tempid":"21"}]}Stringdata=obj.toJSONString();
//解析json数据JSONObjectjson=JSON.parseObject(data);
StringcreateArr=json.getString("createArr");
StringmodifyArr=json.getString("modifyArr");
if(StringUtils.isNotEmpty(createArr)){
JSONArraycreateArray=JSONArray.parseArray(createArr);
for(inti=0;i<createArray.size();i++){
LongtempId=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getLong("tempId");
Stringkeyword=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getString("keyword");
Integersort=JSONObject.parseObject(JSONObject.toJSONString(createArray.get(i))).getInteger("sort");
//创建热门搜索对象HotSearchhotSearch=newHotSearch();
hotSearch.setTempid(tempId);
hotSearch.setKeyword(keyword);
hotSearch.setSort(sort);
hotSearch.setCreateDate(newDate());
hotSearch.setDelFlag("0");
//添加热门搜索信息countAddHotSearch=hotSearchService.addHotSearchSelective(hotSearch);       
            }
        }
if(StringUtils.isNotEmpty(modifyArr)){
JSONArraymodifyArray=JSONArray.parseArray(modifyArr);
for(inti=0;i<modifyArray.size();i++){
LonghotSearchId=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getLong("id");
LongtempId=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getLong("tempId");
Stringkeyword=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getString("keyword");
Integersort=JSONObject.parseObject(JSONObject.toJSONString(modifyArray.get(i))).getInteger("sort");
//创建热门搜索对象HotSearchhotSearch=newHotSearch();
hotSearch.setHotSearchId(hotSearchId);
hotSearch.setTempid(tempId);
hotSearch.setKeyword(keyword);
hotSearch.setSort(sort);
//修改热门搜索信息countEditHotSearch=hotSearchService.modifyHostSearchSelectiveById(hotSearch);   
            }
        }
//判断修改或者新增成功if(countAddHotSearch>0||countEditHotSearch>0){
count=1;
        }
returncount;
    }

MultiRequestBody解析器

解决的问题:

1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收;2、多个对象需要封装到一个对象里才可以用@RequestBody接收。主要优势:1、支持通过注解的value指定JSON的key来解析对象。2、支持通过注解无value,直接根据参数名来解析对象3、支持基本类型的注入4、支持GET和其他请求方式注入5、支持通过注解无value且参数名不匹配JSON串key时,根据属性解析对象。6、支持多余属性(不解析、不报错)、支持参数“共用”(不指定value时,参数名不为JSON串的key)7、支持当value和属性名找不到匹配的key时,对象是否匹配所有属性。

其思路是将前端传入的数据进行获取,也即jsonbody

, 获取请求体JSON字符串。获取之后,将其转成jsonObject。获取自定义元注解@MultiRequestBody中的value,如果@MultiRequestBody注解没有设置value,则取参数名FrameworkServlet作为json解析的key。默认是没有的,因此需要获取controller中的注解value值信息作为key,然后通过key拿到属性信息。进行相应的解析。下面是作者 Wangyang Liu的解析具体实现,具体代码可以到github上去获取,https://github.com/chujianyun/Spring-MultiRequestBody

/*** MultiRequestBody解析器* 解决的问题:* 1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收;* 2、多个对象需要封装到一个对象里才可以用@RequestBody接收。* 主要优势:* 1、支持通过注解的value指定JSON的key来解析对象。* 2、支持通过注解无value,直接根据参数名来解析对象* 3、支持基本类型的注入* 4、支持GET和其他请求方式注入* 5、支持通过注解无value且参数名不匹配JSON串key时,根据属性解析对象。* 6、支持多余属性(不解析、不报错)、支持参数“共用”(不指定value时,参数名不为JSON串的key)* 7、支持当value和属性名找不到匹配的key时,对象是否匹配所有属性。** @author Wangyang Liu  QQ: 605283073* @date 2018/08/27*/publicclassMultiRequestBodyArgumentResolverimplementsHandlerMethodArgumentResolver {
privatestaticfinalStringJSONBODY_ATTRIBUTE="JSON_REQUEST_BODY";
/*** 设置支持的方法参数类型** @param parameter 方法参数* @return 支持的类型*/@OverridepublicbooleansupportsParameter(MethodParameterparameter) {
// 支持带@MultiRequestBody注解的参数returnparameter.hasParameterAnnotation(MultiRequestBody.class);
    }
/*** 参数解析,利用fastjson* 注意:非基本类型返回null会报空指针异常,要通过反射或者JSON工具类创建一个空对象*/@OverridepublicObjectresolveArgument(MethodParameterparameter, ModelAndViewContainermavContainer, NativeWebRequestwebRequest, WebDataBinderFactorybinderFactory) throwsException {
StringjsonBody=getRequestBody(webRequest);
JSONObjectjsonObject=JSON.parseObject(jsonBody);
// 根据@MultiRequestBody注解value作为json解析的keyMultiRequestBodyparameterAnnotation=parameter.getParameterAnnotation(MultiRequestBody.class);
//注解的value是JSON的keyStringkey=parameterAnnotation.value();
Objectvalue;
// 如果@MultiRequestBody注解没有设置value,则取参数名FrameworkServlet作为json解析的keyif (StringUtils.isNotEmpty(key)) {
value=jsonObject.get(key);
// 如果设置了value但是解析不到,报错if (value==null&&parameterAnnotation.required()) {
thrownewIllegalArgumentException(String.format("required param %s is not present", key));
            }
        } else {
// 注解为设置value则用参数名当做json的keykey=parameter.getParameterName();
value=jsonObject.get(key);
        }
// 获取的注解后的类型 LongClass<?>parameterType=parameter.getParameterType();
// 通过注解的value或者参数名解析,能拿到value进行解析if (value!=null) {
//基本类型if (parameterType.isPrimitive()) {
returnparsePrimitive(parameterType.getName(), value);
            }
// 基本类型包装类if (isBasicDataTypes(parameterType)) {
returnparseBasicTypeWrapper(parameterType, value);
// 字符串类型            } elseif (parameterType==String.class) {
returnvalue.toString();
            }
// 其他复杂对象returnJSON.parseObject(value.toString(), parameterType);
        }
// 解析不到则将整个json串解析为当前参数类型if (isBasicDataTypes(parameterType)) {
if (parameterAnnotation.required()) {
thrownewIllegalArgumentException(String.format("required param %s is not present", key));
            } else {
returnnull;
            }
        }
// 非基本类型,不允许解析所有字段,必备参数则报错,非必备参数则返回nullif (!parameterAnnotation.parseAllFields()) {
// 如果是必传参数抛异常if (parameterAnnotation.required()) {
thrownewIllegalArgumentException(String.format("required param %s is not present", key));
            }
// 否则返回nullreturnnull;
        }
// 非基本类型,允许解析,将外层属性解析Objectresult;
try {
result=JSON.parseObject(jsonObject.toString(), parameterType);
        } catch (JSONExceptionjsonException) {
// TODO:: 异常处理返回null是否合理?result=null;
        }
// 如果非必要参数直接返回,否则如果没有一个属性有值则报错if (!parameterAnnotation.required()) {
returnresult;
        } else {
booleanhaveValue=false;
Field[] declaredFields=parameterType.getDeclaredFields();
for (Fieldfield : declaredFields) {
field.setAccessible(true);
if (field.get(result) !=null) {
haveValue=true;
break;
                }
            }
if (!haveValue) {
thrownewIllegalArgumentException(String.format("required param %s is not present", key));
            }
returnresult;
        }
    }
/*** 基本类型解析*/privateObjectparsePrimitive(StringparameterTypeName, Objectvalue) {
finalStringbooleanTypeName="boolean";
if (booleanTypeName.equals(parameterTypeName)) {
returnBoolean.valueOf(value.toString());
        }
finalStringintTypeName="int";
if (intTypeName.equals(parameterTypeName)) {
returnInteger.valueOf(value.toString());
        }
finalStringcharTypeName="char";
if (charTypeName.equals(parameterTypeName)) {
returnvalue.toString().charAt(0);
        }
finalStringshortTypeName="short";
if (shortTypeName.equals(parameterTypeName)) {
returnShort.valueOf(value.toString());
        }
finalStringlongTypeName="long";
if (longTypeName.equals(parameterTypeName)) {
returnLong.valueOf(value.toString());
        }
finalStringfloatTypeName="float";
if (floatTypeName.equals(parameterTypeName)) {
returnFloat.valueOf(value.toString());
        }
finalStringdoubleTypeName="double";
if (doubleTypeName.equals(parameterTypeName)) {
returnDouble.valueOf(value.toString());
        }
finalStringbyteTypeName="byte";
if (byteTypeName.equals(parameterTypeName)) {
returnByte.valueOf(value.toString());
        }
returnnull;
    }
/*** 基本类型包装类解析*/privateObjectparseBasicTypeWrapper(Class<?>parameterType, Objectvalue) {
if (Number.class.isAssignableFrom(parameterType)) {
Numbernumber= (Number) value;
if (parameterType==Integer.class) {
returnnumber.intValue();
            } elseif (parameterType==Short.class) {
returnnumber.shortValue();
            } elseif (parameterType==Long.class) {
returnnumber.longValue();
            } elseif (parameterType==Float.class) {
returnnumber.floatValue();
            } elseif (parameterType==Double.class) {
returnnumber.doubleValue();
            } elseif (parameterType==Byte.class) {
returnnumber.byteValue();
            }
        } elseif (parameterType==Boolean.class) {
returnvalue.toString();
        } elseif (parameterType==Character.class) {
returnvalue.toString().charAt(0);
        }
returnnull;
    }
/*** 判断是否为基本数据类型包装类*/privatebooleanisBasicDataTypes(Classclazz) {
Set<Class>classSet=newHashSet<>();
classSet.add(Integer.class);
classSet.add(Long.class);
classSet.add(Short.class);
classSet.add(Float.class);
classSet.add(Double.class);
classSet.add(Boolean.class);
classSet.add(Byte.class);
classSet.add(Character.class);
returnclassSet.contains(clazz);
    }
/*** 获取请求体JSON字符串*/privateStringgetRequestBody(NativeWebRequestwebRequest) {
HttpServletRequestservletRequest=webRequest.getNativeRequest(HttpServletRequest.class);
// 有就直接获取StringjsonBody= (String) webRequest.getAttribute(JSONBODY_ATTRIBUTE, NativeWebRequest.SCOPE_REQUEST);
// 没有就从请求中读取if (jsonBody==null) {
try {
jsonBody=IOUtils.toString(servletRequest.getReader());
webRequest.setAttribute(JSONBODY_ATTRIBUTE, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOExceptione) {
thrownewRuntimeException(e);
            }
        }
returnjsonBody;
    }
}

当然可以:


微信图片_20221214020703.jpg

还可以:

微信图片_20221214020710.jpg

还可以:

微信图片_20221214020713.jpg

从测试的结果来看,都可以很方便的转成对应的对象信息,方便使用!


目录
相关文章
|
1月前
|
SQL 存储 JSON
SQL,解析 json
SQL,解析 json
67 8
|
3天前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
1月前
|
JSON 前端开发 数据格式
前端的全栈之路Meteor篇(五):自定义对象序列化的EJSON介绍 - 跨设备的对象传输
EJSON是Meteor框架中扩展了标准JSON的库,支持更多数据类型如`Date`、`Binary`等。它提供了序列化和反序列化功能,使客户端和服务器之间的复杂数据传输更加便捷高效。EJSON还支持自定义对象的定义和传输,通过`EJSON.addType`注册自定义类型,确保数据在两端无缝传递。
|
1月前
|
存储 编译器 C语言
C++类与对象深度解析(一):从抽象到实践的全面入门指南
C++类与对象深度解析(一):从抽象到实践的全面入门指南
49 8
|
1月前
|
Python
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
19 1
|
1月前
|
JSON 前端开发 数据格式
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
文章详细讲解了在SpringMVC中如何使用`@RequestMapping`进行路由映射,并介绍了前后端参数传递的多种方式,包括传递单个参数、多个参数、对象、数组、集合以及JSON数据,并且涵盖了参数重命名和从URL中获取参数的方法。
98 0
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
|
1月前
|
JSON JavaScript API
商品详情数据接口解析返回的JSON数据(API接口整套流程)
商品详情数据接口解析返回的JSON数据是API接口使用中的一个重要环节,它涉及从发送请求到接收并处理响应的整个流程。以下是一个完整的API接口使用流程,包括如何解析返回的JSON数据:
|
2月前
|
前端开发 JavaScript
前端基础(十六)_数组对象
本文详细介绍了JavaScript中数组对象的创建和操作方法,包括数组的增删改查、排序、去重、迭代等常用操作。
18 0
|
1月前
|
数据采集 JSON 数据处理
抓取和分析JSON数据:使用Python构建数据处理管道
在大数据时代,电商网站如亚马逊、京东等成为数据采集的重要来源。本文介绍如何使用Python结合代理IP、多线程等技术,高效、隐秘地抓取并处理电商网站的JSON数据。通过爬虫代理服务,模拟真实用户行为,提升抓取效率和稳定性。示例代码展示了如何抓取亚马逊商品信息并进行解析。
抓取和分析JSON数据:使用Python构建数据处理管道
|
18天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
下一篇
无影云桌面