Mapping JSON to Hibernate models in Spring REST Co

2019-09-17 03:35发布

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

2条回答
做个烂人
2楼-- · 2019-09-17 04:19

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.

查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-09-17 04:25

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.

查看更多
登录 后发表回答