2013-05-10 87 views
6

擁有一個Java spring MVC web應用程序,並且正在製作jquery ajax post請求。我的控制器設置爲接收和發送json數據。一切正常,JSON字符串格式良好,控制器可以創建並填充Command對象,並使用JSON請求數據的內容填充它。但是,我正在更新Contact對象的數據,而我的JSP表單元素僅包含數據庫更新所需的所有數據的子集。在我使用表單從JSP獲取所有必要數據的初始GET請求中,填充一個Contact Command對象,然後將該命令對象綁定到Model。我相信只要將我的命令對象聲明爲@SessionAttribute,並在我的onSubmit()POST方法中使用@ModelAttribute引用該Command對象就足夠了。 Spring會從我的會話中檢索已填充的命令對象,然後綁定(覆蓋)由於POST請求而發生更改的那些值。這個更新的命令對象可以被用作數據庫更新的參數。Spring 3與@RequestBody和@ModelAttribute和@SessionAttribute一起使用的AJAX POST請求?

但是,我使用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 

} 

誰能告訴我什麼是用JSON請求數據@RequestBody使用的「標準」或「最簡單」的方式,使該綁定到現有的/ @ModelAttribute填充的Command對象,以便Command對象完全由舊數據和新數據構成(以完全POST POST提交的方式輕鬆實現)。

一個相關的問題是上面的代碼有什麼問題?具有JSON內容的@SessionAttribute和@RequestBody是否可以一起使用?如果是這樣,請解釋一下!非常感謝您的任何意見。

我的工作是讓Spring創建新的Command對象並自動填充表單數據。然後單獨調用/從會話中手動檢索舊命令對象,最後手動將表單提交中不存在的所有屬性複製到新命令對象中。現在,我將所有必要的數據放在一個命令對象中,以將我的SQL更新與。必須有一個更簡單的方法....;)

UPDATE:

發現這個SOF後的今天,同時進一步研究這個問題:

Spring Partial Update Object Data Binding

這似乎沒有已知的彈簧解決方案開箱即用,但很多需求知道處理它的最佳方式。就我而言,是的,我使用的是嵌套域對象,因此在帖子中提供的解決方法並不好。有沒有人有任何其他想法?要清楚,我希望將JSON格式的數據發佈到控制器(而不是簡單的http形式發佈數據)。

好吧,我已經打開了這一個泉源JIRA的要求,也許這是一個急需改進:

https://jira.springsource.org/browse/SPR-10552

否則,它是利用在傑克遜轉換能力的情況下,聽起來像很多管道的聰明方式。

回答

0

爲什麼要用@RequestBody註釋ModelAttribute,只要有@SessionAttribute並且在JSON的情況下使用@ModelAttribute引用Command對象就足夠了。

這背後使用@RequestBody

你的動機

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/RequestBody.html

+0

感謝您的回覆。認爲爲了利用json在classpath上提供的自動json對象轉換,使用RequestBody是標準做法。請你能指點我說ModelAttribute足以處理JSON的任何文檔嗎?我在另一篇SOF文章中閱讀了以下內容:「ModelAttribute從表單發佈參數綁定,RequestBody直接將正文傳遞給Json轉換器」:http://stackoverflow.com/questions/13229584/requestbody-or-modelattribute-with-springrest -網頁服務 – arcseldon 2013-05-11 12:33:34

1

這不是一個完整的答案,但我希望它會指向你在正確的方向。

以下是我們用來從JSON到使用Jackson的現有對象進行深度綁定的類。這是改編自傑克遜在這裏的bug報告: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後端。所有這些工作都是相當不錯的,但現在我們的控制器非常簡單。

不幸的是,我無法顯示我們所有的代碼,反正它很長。我希望這能解決至少部分問題。