当前位置: 首页 > 知识库问答 >
问题:

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

颜志业
2023-03-14

有一个Java spring MVC web应用程序,我正在发出一个jquery ajax post请求。我的控制器设置为接收和发送json数据。一切正常,JSON字符串格式良好,控制器可以创建和填充命令对象,并用JSON请求数据的内容填充它。然而,我正在更新联系人对象的数据,我的JSP表单元素只包含DB更新所需的所有数据的子集。在带有表单的JSP页面的初始GET请求中,我从DB中检索所有必要的数据,填充一个Contact命令对象,然后将该命令对象绑定到模型

如果我在做一个普通的POST submit表单提交,我相信只要将我的命令对象声明为@SessionAttribute,并在onSubmit()POST方法中使用@modeldattribute引用该命令对象就足够了。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

}

有人能告诉我什么是“标准”或“最简单”的方法来使用@Request estbody和JSON请求数据,并使其绑定到现有的/@ModelAtort填充的命令对象,以便命令对象完全由旧数据和新数据构成(以同样的方式,使用完整的POST超文本传输协议提交很容易实现)。

一个相关的问题是上面的代码有什么问题?带有JSON内容的@SessionAttribute和@RequestBody可以一起使用吗?如果是,请解释如何!非常感谢您的任何意见。

我的解决方法是让Spring创建新的命令对象并自动填充表单数据。然后从会话中手动单独调用/检索旧的命令对象,最后手动将表单提交中不存在的所有属性复制到新的命令对象中。现在,我在一个命令对象中拥有了所有必要的数据,可以应用SQL更新。一定有更简单的方法……;)

更新时间:

今天在进一步研究这个问题时发现了这个SOF帖子:

Spring部分更新对象数据绑定

似乎没有现成的已知SPRING解决方案,但需要知道处理它的最佳方法。在我的例子中,是的,我使用的是嵌套的域对象,因此本文提供的解决方法并不好。有人有其他想法吗?明确地说,我希望将JSON格式的数据发布到控制器(而不仅仅是http格式的POST数据)。

好的,我已经为这个打开了一个Spring Source JIRA请求,也许这是一个非常需要的改进:

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

或者,这是一个以聪明的方式利用Jackson转换功能的案例,听起来像是很多管道。

共有2个答案

子车安和
2023-03-14

为什么要使用@Request estbody注释ModelAtort,在JSON的情况下,只需使用@SessionAtcm并使用@ModelAtcm引用该命令对象就足够了。

您使用@Request estbody的动机是什么

看见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

姜杜吟
2023-03-14

这不是一个完整的答案,但我希望它能为你指明正确的方向。

下面是一个类,我们使用它使用Jackson将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的HandlerMethod odArgumentResolver的实现一起使用。

我们没有使用很多Spring的MVC框架。我们只是使用Spring的许多不同部分构建一个JSON API后端。让它全部工作是相当多的管道,但现在我们的控制器非常简单。

不幸的是,我不能显示我们所有的代码,反正代码很长。我希望这至少解决了部分问题。

 类似资料:
  • 最近我正在努力学习SpringMVC。似乎我没有很好地理解@SessionAttributes和@ModelAttribute注释的功能。 这是我的控制器的一部分: 基本上有一个jsp列出所有的项目。用户点击"addToCart"获取特定商品,该商品将被添加到购物车列表中。我最好先解释一下我对这个控制器的理解,你可以告诉我我没有得到什么。 第一次调用ItemController时,将执行creat

  • 我尝试使用和通过Postman发送JSON和多个文件,但它不起作用。有可能在API中同时使用这两个注释吗?

  • 我有一个问题,在我的应用程序Android中使用soap请求。我使用Ksoap2库。这是我的代码: }

  • 我有一个控制器,它的GET方法是这样写的: bean是正确的(getter和setter),服务调用返回带有thingId的正确ThingBean,并且显示了我在edit.jsp的JSP页面。 JSP是: 但是,JSP 显示主题和消息的空白值。是的,这些属性上有吸气剂/二传手。 我有一个非常相似的控制器,工作得很好,除了GET - mapped方法的签名中没有@RequestParam。 我在Sp

  • 我不能用HttpEntity调用Spring RestTem板进行POST请求。我调用RestTem板给出Base64字符串在邮递员,但使用我的java实现,它会给出以下错误: 我的实施是: 我尝试过以下解决方案,但在这里不起作用 这个我也提到过这个

  • 我有一些应用程序在Spring boot中使用微服务架构。我已经在RestTemplate中使用@PathVariable发送了查询参数、对象、模型等。开发应用程序后,我做了一些研究,要求使用@RequestParam和@RequestBody。但我无法理解,也不知道如何使用@RequestBody和@RequestParam。使用@RequestBody而不是@PathVariable有什么好处