JQuery ajax发送json数据时,object的属性如何不用中括号而用点表示?

发布于 2022-09-05 15:24:17 字数 9479 浏览 24 评论 0

我用jquery ajax方法向后台传递一个json对象,其中还有嵌套的json对象和数组,demo如下

$(function () {
        var json = {
            key01: "value01",
            obj01: {
                key11: "value11",
                key12: "value12"
            },
            arr01: [
                {
                    key21: "value21",
                    key22: "value22"
                }
            ]
        };
        $.ajax({
            url: '#',
            type: "POST",
            async: false,
            data: json,
            dataType: "json"
        });
    });

浏览器实际发送的数据如下

key01:value01
obj01[key11]:value11
obj01[key12]:value12
arr01[0][key21]:value21
arr01[0][key22]:value22

而我期望的数据应该是

key01:value01
obj01.key11:value11
obj01.key12:value12
arr01[0].key21:value21
arr01[0].key22:value22

属性应该跟在后面,而不是用中括号包围
请问有什么好的办法吗?只能操作字符串吗?


一点补充:
我现在这个系统后台并不是使用@RequestBody来接收参数的,而是用spring-beans将传入的参数组装成实体然后在Controller中使用,
所以并不能向后台直接发json(无论是否序列化),而是要以"application/x-www-form-urlencoded"的形式发送key:value对,
这正好是ajax的默认处理方式,唯一的问题是ajax在将json对象转化为key:value对时,产生的key格式不合适,它将对象的属性也当作数组元素进行了命名,
导致后台报错如下:

严重: Servlet.service() for servlet [springmvc] in context with path [/ppm] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'shippingItems[0][quantity]' of bean class [net.shopxx.entity.Shipping]: Property referenced in indexed property path 'shippingItems[0][quantity]' is neither an array nor a List nor a Map; returned value was [1]] with root cause
org.springframework.beans.InvalidPropertyException: Invalid property 'shippingItems[0][quantity]' of bean class [net.shopxx.entity.Shipping]: Property referenced in indexed property path 'shippingItems[0][quantity]' is neither an array nor a List nor a Map; returned value was [1]
    at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1024)
    at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:902)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
    at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:740)
    at org.springframework.validation.DataBinder.doBind(DataBinder.java:636)
    at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:191)
    at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:112)
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:153)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:106)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:123)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
    at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
    at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
    at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
    at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
    at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
    at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
    at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
    at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at net.shopxx.filter.SiteStatusFilter.doFilterInternal(SiteStatusFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2549)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2538)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

你应该注意到了问题就出在shippingItems[0][quantity]这个key上,
经测试,若它是shippingItems[0].quantity则问题解决。

要把后台调整成使用@RequestBody来接收牵扯太大,所以就只能在前端这边想办法了,
但是我又觉得手动转化成字符串来处理不够优雅,所以想看看各位大神有没有什么好的点子,谢谢。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

云淡月浅 2022-09-12 15:24:17

看来是没有什么所谓的优雅的方法了,感觉可以结题了。
我最后还是用了操作字符串的方法,Demo如下:

$(function () {
        var json = {
            key01: "value01",
            obj01: {
                key11: "value11",
                key12: "value12"
            },
            arr01: [
                {
                    key21: "value21",
                    key22: "value22"
                }
            ]
        };
        var jsonParam = decodeURIComponent($.param(json))
            .replace(/\[([^ \[\]]*?[^ \[\]\d]+?[^ \[\]]*?)\]/g, ".$1");
        $.ajax({
            url: '#',
            type: "POST",
            data: jsonParam,
            dataType: "json"
        });
    });

这里还是要感谢@catchme进行的深入分析,以及提示了var res = decodeURIComponent($.param(json));这一方法。
最后,有兴趣的可以看看/\[([^ \[\]]*?[^ \[\]\d]+?[^ \[\]]*?)\]/g这个正则表达式有没有更好的写法,欢迎评论。

蓝眼睛不忧郁 2022-09-12 15:24:17

通过jQuery使用Ajax,参数为对象或者数组时,就是使用[]而不是.
jQuery处理参数的函数为param,可以通过$.param(data)方式使用

// 因为在内部会对参数进行 encodeURIComponent 编码,所以这里需要参数进行 decodeURIComponent 解码
var res = decodeURIComponent($.param(json))
console.log(res) // key01=value01&obj01[key11]=value11&obj01[key12]=value12&arr01[0][key21]=value21&arr01[0][key22]=value22

来看看jQuery的内部是如何对参数进行处理的,jQuery.3.2.18423

// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
    var prefix,
        s = [],
        // add 函数为对参数进行 queryString 处理
        add = function( key, valueOrFunction ) {

            // If value is a function, invoke it and use its return value
            // 如果value是函数,就执行函数,返回的结果作为参数再进行处理
            var value = jQuery.isFunction( valueOrFunction ) ?
                valueOrFunction() :
                valueOrFunction;

            s[ s.length ] = encodeURIComponent( key ) + "=" +
                encodeURIComponent( value == null ? "" : value );
        };

    // If an array was passed in, assume that it is an array of form elements.
    if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {

        // Serialize the form elements
        jQuery.each( a, function() {
            add( this.name, this.value );
        } );

    } else {

        // If traditional, encode the "old" way (the way 1.3.2 or older
        // did it), otherwise encode params recursively.
        // 这里就是处理你的 json 对象,转到 buildParams 函数进行具体的处理,把 add 函数也传递过去了
        for ( prefix in a ) {
            buildParams( prefix, a[ prefix ], traditional, add );
        }
    }

    // Return the resulting serialization
    return s.join( "&" );
};
function buildParams( prefix, obj, traditional, add ) {
    var name;
    // 如果子对象是数组
    if ( Array.isArray( obj ) ) {

        // Serialize array item.
        jQuery.each( obj, function( i, v ) {
            // rbracket.test( prefix ) 检测 key 中是否有[],如 name[]='jack'
            if ( traditional || rbracket.test( prefix ) ) {

                // Treat each array item as a scalar.
                // 这里调用 param 函数内传过来的 add 函数进行 queryString
                add( prefix, v );

            } else {

                // Item is non-scalar (array or object), encode its numeric index.
                // 看第一个参数,jQuery 内部是会对 key 自动添加 [] 的,而不是开发者自己定义使用 [] 还是 . 的
                buildParams(
                    prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
                    v,
                    traditional,
                    add
                );
            }
        } );

    } else if ( !traditional && jQuery.type( obj ) === "object" ) {

        // Serialize object item.
        for ( name in obj ) {
            buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
        }

    } else {

        // Serialize scalar item.
        add( prefix, obj );
    }
}

对于所有的对象或者数组,jQuery内部都是使用[]来处理参数的,所以楼主可以使用JSON.stringify来处理你的数据


题主,你在ajax的配置中增加processData:false 看看,增加了这个配置参数,jQuery就不会对你需要传输的数据进行处理了

秋意浓 2022-09-12 15:24:17

用中括号代码这是一个数组,用点表示是对象。
其中obj01是一个对象,但是也可以使用数组的方式来访问。所以第一个可以直接obj01.key11
arr01里面是一个json数组,需要用下标的方式来访问,如果数组里面只有一条数据,那可以直接用对象来表示。

dawn曙光 2022-09-12 15:24:17

把 json 序列化一下,然后后端再解析,不要直接传对象

data: JSON.stringify(json)
痴情 2022-09-12 15:24:17

.代替[],这个操作真的是没见过,还有,ajax传递一边都是key,value的形式,如果value是数组或者对象的话建议使用JSON.stringify()转化为json串,传到后台再做解析

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文