繁体   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