簡體   English   中英

Spring 3 AJAX POST請求與@RequestBody以及@ModelAttribute和@SessionAttribute一起使用?

[英]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部分更新對象數據綁定

似乎沒有開箱即用的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的動機是什么?

請參閱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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM