Mapping JSON to Hibernate models in Spring REST Co

2019-09-17 04:09发布

问题:

Let's say that I have a Spring 4 web application with a Hibernate-based persistence layer. I'd like to create a RestController that supports basic CRUD operations for my models. Creating a method for fetching records works without a hitch:

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

Jackson handles the object serialization, no problem. But what if I want to add a method for creating new records via a POST request? Is there any easy way to support a simple method like this?

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

Is something like this possible? Or do I need to manually map posted form data to a new object?

SOLUTION

Here is how I solved my problem, there were a couple steps. First, my final controller method:

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

I already had a filter applied to all requests to the application API, to allow cross origin resource sharing, but modifications to this were needed to allow requests to specify content type:

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() { }
}

Which is registered in my web.xml file:

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

Now when I make a request, such as the one below, it will correctly map my submitted JSON to my model and persist a new instance:

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);
  });

回答1:

To tell Spring that you want it to apply a deserializer to the content instead of attempt standard HTML form binding you use @RequestBody.

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

@RequestParam is telling it to look for an individual parameter with that name and apply standard databinding, not to deserialize the entire content of the POST into an object.



回答2:

Yes, absolutely. Jackson will automatically do a two-way mapping of entities, so if you want to POST something to the server just use the same JSON format that you see when you do GET.