【问题标题】:Mapping JSON to Hibernate models in Spring REST Controllers在 Spring REST 控制器中将 JSON 映射到 Hibernate 模型
【发布时间】:2014-10-22 15:28:30
【问题描述】:

假设我有一个带有基于 Hibernate 的持久层的 Spring 4 Web 应用程序。我想为我的模型创建一个支持基本 CRUD 操作的 RestController。创建获取记录的方法很顺利:

@RequestMapping(value = "/stuff/list", method = RequestMethod.GET)
public List<Stuff> getStuff(){
    return stuffService.findAll();
}

Jackson 处理对象序列化,没问题。但是如果我想添加一个通过 POST 请求创建新记录的方法呢?有没有简单的方法来支持这样的简单方法?

@RequestMapping(value = "/stuff/new", method = RequestMethod.POST)
public Integer getStuff(@RequestParam("stuff") Stuff stuff){
    return stuffService.save(stuff);
}

这样的事情可能吗?还是我需要手动将发布的表单数据映射到新对象?

解决方案

这是我解决问题的方法,有几个步骤。首先,我的最终控制器方法:

@RequestMapping(value = "/stuff/new", method = RequestMethod.POST)
public Integer getStuff(@RequestBody Stuff stuff){
    return stuffService.save(stuff);
}

我已经对应用程序 API 的所有请求应用了一个过滤器,以允许跨源资源共享,但需要对此进行修改以允许请求指定内容类型:

public class SimpleCORSFilter implements Filter{

    @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
            FilterChain filterChain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
        filterChain.doFilter(servletRequest, servletResponse);

    }

    @Override public void init(FilterConfig filterConfig) throws ServletException { }

    @Override public void destroy() { }
}

在我的web.xml 文件中注册:

<filter>
    <filter-name>cors</filter-name>
    <filter-class>com.company.app.util.SimpleCORSFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>cors</filter-name>
    <url-pattern>/api/*</url-pattern>
</filter-mapping>

现在当我发出如下请求时,它会正确地将我提交的 JSON 映射到我的模型并持久化一个新实例:

var stuff = {
    name: "Some stuff",
    description: "This is some stuff."
}

$.ajax({
    url: url,
    method: "post",
    dataType: "json",
    data: JSON.stringify(stuff),
    contentType: "application/json"
  }).done(function(data){
    console.log(data);
  }).fail(function(x, status, e){
    console.log(e);
  });

【问题讨论】:

  • 内容是html表单POST还是JSON?
  • @Affe:JSON,由浏览器 AJAX 请求或通过 Spring RestTemplate 发送。

标签: java json hibernate rest spring-mvc


【解决方案1】:

要告诉 Spring 您希望它对内容应用反序列化程序,而不是尝试标准 HTML 表单绑定,请使用 @RequestBody

@RequestMapping(value = "/stuff/new", method = RequestMethod.POST)
public Integer getStuff(@RequestBody Stuff stuff){
    return stuffService.save(stuff);
}

@RequestParam 告诉它查找具有该名称的单个参数并应用标准数据绑定,而不是将 POST 的全部内容反序列化为对象。

【讨论】:

  • 是否需要明确设置consumes = "application/something"?或者它会期望正确的 JSON 格式吗?是否需要任何额外的请求标头?
  • 仅当您想将具有不同标头的请求路由到不同位置或将其锁定时。对于简单的事情,开箱即用的&lt;mvc:annotation-driven /&gt; 将“正确处理”。 (请注意,如果您指定消耗,具有有效内容但缺少标头的请求将被拒绝,您可能希望也可能不希望。)
  • 像你这样写我的控制器方法会导致415 (Unsupported Media Type) 错误。另一个 SO 答案 (stackoverflow.com/questions/11492325/…) 建议更改请求标头,但这也无济于事。
  • 您是使用 mvc:annotation-driven 配置调度程序还是手动设置? Jackson 在类路径上吗?
  • 我使用了&lt;mvc:annotation-driven&gt;,但做了一些修改(见上文)。 Jackson 在类路径上,并且可以很好地进行对象序列化。
【解决方案2】:

是的,当然。 Jackson 将自动进行实体的双向映射,因此如果您想将 POST 某些内容发送到服务器,只需使用您在执行 GET 时看到的相同 JSON 格式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-18
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    相关资源
    最近更新 更多