[英]Spring 3 AJAX POST request with @RequestBody and @ModelAttribute and @SessionAttribute used together?
有一個Java spring MVC web應用程序,並正在發出jquery ajax post請求。 我的控制器設置為接收和發送json數據。 一切正常,JSON字符串格式良好,Controller可以創建並填充Command對象,並使用JSON請求數據的內容填充它。 但是,我正在更新Contact對象的數據,而我的JSP表單元素僅包含數據庫更新所需的所有數據的子集。 在我對具有表單的JSP頁面的初始GET請求中,我從數據庫中檢索所有必需的數據,填充Contact Command對象,然后將該命令對象綁定到Model。
如果我正在進行正常的POST提交表單提交,我相信只是將我的命令對象聲明為@SessionAttribute,並在我的onSubmit()POST方法中使用@ModelAttribute引用該Command對象就足夠了。 Spring將從我的會話中檢索已填充的命令對象,然后綁定(覆蓋)由於POST請求而更改的那些值。 然后,可以將此更新的命令對象用作DB更新的參數。
但是,我正在使用Spring 3並利用@RequestBody參數類型。 我無法讓Spring給我會話對象並自動綁定請求中的新值。 它或者只提供舊的會話命令對象(不應用更改)或僅提供POST請求中的值的新命令對象。
這是一個小代碼 - 不起作用:
@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 with data from 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 {
// do business logic with command object here
}
任何人都可以告訴我什么是使用@RequestBody與JSON請求數據的“標准”或“最簡單”的方法,並使其綁定到現有的/ @ModelAttribute填充的Command對象,以便Command對象完全由新舊數據構成(以同樣的方式使用完整的POST http提交輕松實現)。
一個相關的問題是上面的代碼有什么問題? @SessionAttribute和帶有JSON內容的@RequestBody可以一起使用嗎? 如果是這樣,請解釋如何! 非常感謝您的任何意見。
我的工作是讓Spring創建新的Command對象並自動填充表單數據。 然后從會話中手動單獨調用/檢索舊命令對象,最后手動將表單提交中不存在的所有屬性復制到新命令對象中。 現在,我將所有必要的數據放在一個命令對象中,以應用我的SQL更新。 必須有一個更簡單的方式......;)
更新:
今天發現這篇SOF帖子,同時進一步研究這個問題:
似乎沒有開箱即用的SPRING解決方案,但需要了解處理它的最佳方法。 在我的情況下,是的,我使用的是嵌套域對象,因此帖子中提供的解決方法並不好。 有沒有人有任何其他想法? 為了清楚起見,我希望將JSON格式數據發布到Controller(而不僅僅是http表單發布數據)。
好的,我已經為這個開了一個Spring Source JIRA請求,也許這是一個非常需要的改進:
https://jira.springsource.org/browse/SPR-10552
或者,這是一個利用傑克遜轉換功能的巧妙方式,聽起來像很多管道。
這不是一個完整的答案,但我希望它會指出你正確的方向。
以下是我們用來使用Jackson從JSON到現有對象進行深度綁定的類。 這是改編自Jackson的錯誤報告: 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>> i = node.fields(); i.hasNext(); )
{
Entry<String, JsonNode> fieldEntry = i.next();
JsonNode child = fieldEntry.getValue();
if( child.isArray() )
{
// We ignore arrays so they get 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 )
{
// Only remove the JsonNode if the object already exists
// Otherwise it will be instantiated when the parent gets
// deserialized
i.remove();
applyRecursively( o2, child );
}
}
}
}
ObjectReader jsonReader = objectMapper.readerForUpdating( objToBindInto );
jsonReader.readValue( node );
}
}
我們使用它和Spring的HandlerMethodArgumentResolver的實現。
我們不使用很多Spring的MVC框架。 我們只是使用Spring的許多不同部分構建JSON API后端。 讓它全部工作是一個相當不錯的管道,但現在我們的控制器非常簡單。
不幸的是,我無法顯示所有代碼,無論如何它都很長。 我希望這至少解決了部分問題。
為什么要使用@RequestBody注釋ModelAttribute,只要擁有@SessionAttribute並使用@ModelAttribute引用該Command對象就足夠了JSON。
你使用@RequestBody的動機是什么?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.