使用JSON将嵌套对象发布到Spring MVC控制器

我有一个定义了POST处理程序的控制器,如下所示:

@RequestMapping(value="/ajax/saveVendor.do", method = RequestMethod.POST)

public @ResponseBody AjaxResponse saveVendor( @Valid UIVendor vendor,

BindingResult result,

Locale currentLocale )

以JSON格式查看时,UIVendor对象如下所示:

var vendor = 

{

vendorId: 123,

vendorName: "ABC Company",

emails : [

{ emailAddress: "abc123@abc.com", flags: 2 },

{ emailAddress: "xyz@abc.com", flags: 3 }

]

}

UIVendor bean有一个名为ArrayList类型的“电子邮件”字段,带有适当的设置器和获取器(getEmails / setEmails)。NotificationEmail对象也具有适当的公共设置器/获取器。

当我尝试使用以下代码发布对象时:

$.post("ajax/saveVendor.do", $.param(vendor), saveEntityCallback, "json" );

我在日志中收到此错误:

Invalid property 'emails[0][emailAddress]' of bean class [beans.UIVendor]: Property referenced in indexed property path 'emails[0][emailAddress]' is neither an array nor a List nor a Map; returned value was [abc123@abc.com]

如何将这样的嵌套对象正确发布到Spring控制器,并正确反序列化为适当的对象结构。

UPDATE 根据Bohzo的请求,这是UIVendor类的内容。此类包装由Web服务生成的Bean类,将VendorAttributes公开为单独的字段:

package com.mycompany.beans;

import java.util.*;

import org.apache.commons.lang.*;

import com.mycompany.domain.Vendor;

import com.mycompany.domain.VendorAttributes;

import org.apache.commons.logging.*;

import org.codehaus.jackson.annotate.JsonIgnore;

public class UIVendor

{

private final Log logger = LogFactory.getLog( this.getClass() );

private Vendor vendor;

private boolean ftpFlag;

private String ftpHost;

private String ftpPath;

private String ftpUser;

private String ftpPassword;

private List<UINotificationEmail> emails = null;

public UIVendor() { this( new Vendor() ); }

public UIVendor( Vendor vendor )

{

this.vendor = vendor;

loadVendorAttributes();

}

private void loadVendorAttributes()

{

this.ftpFlag = false;

this.ftpHost = this.ftpPassword = this.ftpPath = this.ftpUser = "";

this.emails = null;

for ( VendorAttributes a : this.vendor.getVendorAttributes() )

{

String key = a.getVendorFakey();

String value = a.getVendorFaValue();

int flags = a.getFlags();

if ( StringUtils.isBlank(key) || StringUtils.isBlank(value) ) continue;

if ( key.equals( "ftpFlag" ) )

{

this.ftpFlag = BooleanUtils.toBoolean( value );

}

else if ( key.equals( "ftpHost" ) )

{

this.ftpHost = value;

}

else if ( key.equals("ftpPath") )

{

this.ftpPath = value;

}

else if ( key.equals("ftpUser") )

{

this.ftpUser = value;

}

else if ( key.equals("ftpPassword") )

{

this.ftpPassword = value;

}

else if ( key.equals("email") )

{

UINotificationEmail email = new UINotificationEmail(value, flags);

this.getEmails().add( email );

}

}

}

private void saveVendorAttributes()

{

int id = this.vendor.getVendorId();

List<VendorAttributes> attrs = this.vendor.getVendorAttributes();

attrs.clear();

if ( this.ftpFlag )

{

VendorAttributes flag = new VendorAttributes();

flag.setVendorId( id );

flag.setStatus( "A" );

flag.setVendorFakey( "ftpFlag" );

flag.setVendorFaValue( BooleanUtils.toStringTrueFalse( this.ftpFlag ) );

attrs.add( flag );

if ( StringUtils.isNotBlank( this.ftpHost ) )

{

VendorAttributes host = new VendorAttributes();

host.setVendorId( id );

host.setStatus( "A" );

host.setVendorFakey( "ftpHost" );

host.setVendorFaValue( this.ftpHost );

attrs.add( host );

if ( StringUtils.isNotBlank( this.ftpPath ) )

{

VendorAttributes path = new VendorAttributes();

path.setVendorId( id );

path.setStatus( "A" );

path.setVendorFakey( "ftpPath" );

path.setVendorFaValue( this.ftpPath );

attrs.add( path );

}

if ( StringUtils.isNotBlank( this.ftpUser ) )

{

VendorAttributes user = new VendorAttributes();

user.setVendorId( id );

user.setStatus( "A" );

user.setVendorFakey( "ftpUser" );

user.setVendorFaValue( this.ftpUser );

attrs.add( user );

}

if ( StringUtils.isNotBlank( this.ftpPassword ) )

{

VendorAttributes password = new VendorAttributes();

password.setVendorId( id );

password.setStatus( "A" );

password.setVendorFakey( "ftpPassword" );

password.setVendorFaValue( this.ftpPassword );

attrs.add( password );

}

}

}

for ( UINotificationEmail e : this.getEmails() )

{

logger.debug("Adding email " + e );

VendorAttributes email = new VendorAttributes();

email.setStatus( "A" );

email.setVendorFakey( "email" );

email.setVendorFaValue( e.getEmailAddress() );

email.setFlags( e.getFlags() );

email.setVendorId( id );

attrs.add( email );

}

}

@JsonIgnore

public Vendor getVendor()

{

saveVendorAttributes();

return this.vendor;

}

public int getVendorId()

{

return this.vendor.getVendorId();

}

public void setVendorId( int vendorId )

{

this.vendor.setVendorId( vendorId );

}

public String getVendorType()

{

return this.vendor.getVendorType();

}

public void setVendorType( String vendorType )

{

this.vendor.setVendorType( vendorType );

}

public String getVendorName()

{

return this.vendor.getVendorName();

}

public void setVendorName( String vendorName )

{

this.vendor.setVendorName( vendorName );

}

public String getStatus()

{

return this.vendor.getStatus();

}

public void setStatus( String status )

{

this.vendor.setStatus( status );

}

public boolean isFtpFlag()

{

return this.ftpFlag;

}

public void setFtpFlag( boolean ftpFlag )

{

this.ftpFlag = ftpFlag;

}

public String getFtpHost()

{

return this.ftpHost;

}

public void setFtpHost( String ftpHost )

{

this.ftpHost = ftpHost;

}

public String getFtpPath()

{

return this.ftpPath;

}

public void setFtpPath( String ftpPath )

{

this.ftpPath = ftpPath;

}

public String getFtpUser()

{

return this.ftpUser;

}

public void setFtpUser( String ftpUser )

{

this.ftpUser = ftpUser;

}

public String getFtpPassword()

{

return this.ftpPassword;

}

public void setFtpPassword( String ftpPassword )

{

this.ftpPassword = ftpPassword;

}

public List<UINotificationEmail> getEmails()

{

if ( this.emails == null )

{

this.emails = new ArrayList<UINotificationEmail>();

}

return emails;

}

public void setEmails(List<UINotificationEmail> emails)

{

this.emails = emails;

}

}

UPDATE 2 Here’s the output from Jackson.:

{

"vendorName":"MAIL",

"vendorId":45,

"emails":

[

{

"emailAddress":"dfg",

"success":false,

"failure":false,

"flags":0

}

],

"vendorType":"DFG",

"ftpFlag":true,

"ftpHost":"kdsfjng",

"ftpPath":"dsfg",

"ftpUser":"sdfg",

"ftpPassword":"sdfg",

"status":"A"

}

这是我在POST上返回的对象的结构:

{

"vendorId":"45",

"vendorName":"MAIL",

"vendorType":"DFG",

"ftpFlag":true,

"ftpHost":"kdsfjng",

"ftpUser":"sdfg",

"ftpPath":"dsfg",

"ftpPassword":"sdfg",

"status":"A",

"emails":

[

{

"success":"false",

"failure":"false",

"emailAddress":"dfg"

},

{

"success":"true",

"failure":"true",

"emailAddress":"pfc@sj.org"

}

]

}

我也尝试过使用来自www.json.org的JSON库进行序列化,其结果正是你在上面看到的。但是,当我发布该数据时,传递给控制器​​的UIVendor对象中的所有字段均为空(尽管该对象不是)。

回答:

更新:从Spring 3.1开始,可以在@RequestBody控制器方法参数中使用@Valid。

@RequestMapping(value=”/ajax/saveVendor.do”, method = RequestMethod.POST)

public @ResponseBody AjaxResponse saveVendor( @Valid @RequestBody UIVendor vendor,

BindingResult result,

Locale currentLocale )

经过多次尝试和错误,我终于尽我所能找出问题所在。使用以下控制器方法签名时:

@RequestMapping(value=”/ajax/saveVendor.do”, method = RequestMethod.POST)

public @ResponseBody AjaxResponse saveVendor( @Valid UIVendor vendor,

BindingResult result,

Locale currentLocale )

客户端脚本必须以后数据(通常为“ application / x-www-form-urlencoded”)格式(即field = value&field2 = value2)传递对象中的字段。这是在jQuery中完成的,如下所示:

$.post( “mycontroller.do”, $.param(object), callback, “json” )

对于没有子对象或集合的简单POJO对象,这很好用,但是一旦您为传递的对象引入了极大的复杂性,Spring的映射逻辑就无法识别jQuery用于序列化对象数据的符号:

object[0][field]

我解决此问题的方法是将控制器中的方法签名更改为:

@RequestMapping(value=”/ajax/saveVendor.do”, method = RequestMethod.POST)

public @ResponseBody AjaxResponse saveVendor( @RequestBody UIVendor vendor,

Locale currentLocale )

并将呼叫从客户端更改为:

$.ajax(

{

url:"ajax/mycontroller.do",

type: "POST",

data: JSON.stringify( objecdt ),

success: callback,

dataType: "json",

contentType: "application/json"

} );

这需要使用JSON javascript库。它还将contentType强制为“ application / json”,这是Spring在使用@RequestBody批注时所期望的,并将对象序列化为Jackson可以反序列化为有效对象结构的格式。

唯一的副作用是,现在我必须在controller方法内部处理自己的对象验证,但这相对简单:

BindingResult result = new BeanPropertyBindingResult( object, “MyObject” );

Validator validator = new MyObjectValidator();

validator.validate( object, result );

如果有人对这个过程有任何改进的建议,我非常高兴。

以上是 使用JSON将嵌套对象发布到Spring MVC控制器 的全部内容, 来源链接: utcz.com/qa/402004.html

回到顶部