java - Spring 3 AJAX POST request with @RequestBody and @ModelAttribute and @SessionAttribute used together? -
have java spring mvc web app, , making jquery ajax post request. controller setup receive , send json data. works, json string formatted, , controller can create , populate command object , populate contents of json request data. however, updating data contact object, , jsp form element contains subset of data required db update. in initial request jsp page form retrieve necessary data db, populate contact command object, , bind command object model.
if doing normal post submit form submission, believe declaring command object @sessionattribute, , referencing command object using @modelattribute in onsubmit() post method sufficient. spring retrieve populated command object session , bind (overwrite) values have changed result of post request. updated command object used parameter db update.
however, using spring 3 , leveraging @requestbody paramater type. cannot spring both give me session object , automatically bind new values request. either gives me old session command object (without applying changes) or new command object values post request.
here little code - doesn't work:
@sessionattributes("contactcommand") @controller public class contactcontroller { @requestmapping(value = "/editcontact", method=requestmethod.get) public string init(modelmap model, locale locale, httpservletrequest request, httpservletresponse response) throws generalexception { final contactcommand cmd = new contactcommand(); // populate data db etc model.addattribute("contactcommand", cmd); // etc } @requestmapping(value="/editcontact",method=requestmethod.post, consumes = "application/json", produces = "application/json") public @responsebody map<string, ? extends object> editcontactinfo(@requestbody @modelattribute("contactcommand") contactcommand cmd, httpservletrequest request, httpservletresponse response) throws generalexception { // business logic command object here }
can please tell me "standard" or "easiest" way use @requestbody json request data , make bind existing / @modelattribute populated command object command object constituted both old , new data (in same way achieved using full post http submit).
a related question wrong code above? can @sessionattribute , @requestbody json content used together? if so, please explain how! thank input.
my work around let spring create new command object , auto-populate form data. make separate call / retrieve manually session old command object, manually copy attributes not present in form submission new command object. have necessary data in 1 command object apply sql update with. there must easier way.... ;)
update:
found sof post today while further researching problem:
spring partial update object data binding
it appears there no known spring solution out of box lot of demand know best way handle it. in case, yes, using nested domain objects workaround offered in post no good. have other ideas? clear, wish post json format data controller (not http form post data).
ok, i've opened spring source jira request one, perhaps needed improvement:
https://jira.springsource.org/browse/spr-10552
or else, case of leveraging jackson conversion capabilities in clever ways sounds lot of plumbing.
this isn't complete answer, hope point in right direction.
following class use deep binding json existing object using jackson. adapted bug report jackson here: https://jira.springsource.org/browse/spr-10552
public class jsonbinder { private objectmapper objectmapper; public jsonbinder( objectmapper objectmapper ) { super(); this.objectmapper = checknotnull( objectmapper ); } public void bind( object objtobindinto, inputstream jsonstream ) throws jsonprocessingexception, ioexception { jsonnode root = objectmapper.readtree( checknotnull( jsonstream ) ); applyrecursively( checknotnull( objtobindinto ), root ); } private void applyrecursively( object objtobindinto, jsonnode node ) throws jsonprocessingexception, ioexception { propertyaccessor propaccessor = null; for( iterator<entry<string, jsonnode>> = node.fields(); i.hasnext(); ) { entry<string, jsonnode> fieldentry = i.next(); jsonnode child = fieldentry.getvalue(); if( child.isarray() ) { // ignore arrays instantiated fresh every time // root.remove(fieldentry.getkey()); } else { if( child.isobject() ) { if( propaccessor == null ) { propaccessor = propertyaccessorfactory.fordirectfieldaccess( objtobindinto ); } object o2 = propaccessor.getpropertyvalue( fieldentry.getkey() ); if( o2 != null ) { // remove jsonnode if object exists // otherwise instantiated when parent gets // deserialized i.remove(); applyrecursively( o2, child ); } } } } objectreader jsonreader = objectmapper.readerforupdating( objtobindinto ); jsonreader.readvalue( node ); } }
we use along implementation of spring's handlermethodargumentresolver.
we don't use lot of spring's mvc framework. building json api backend using lot of different parts of spring. pretty amount of plumbing working, our controllers simple.
unfortunately can't show of our code, it's pretty long anyways. hope solves @ least part of problem.
Comments
Post a Comment