2014-08-28 2 views
0

Предположим, что у меня есть веб-приложение Spring 4 с уровнем сохранения на основе Hibernate. Я хотел бы создать RestController, который поддерживает основные операции CRUD для моих моделей. Создание метода для выборки записей работает без сучка и задоринки:Сопоставление моделей JSON с Hibernate в Spring контроллеров REST

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

Джексон обрабатывает сериализации объектов, никаких проблем. Но что, если я хочу добавить метод для создания новых записей через запрос 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); 
    }); 
+0

Является ли содержание html формой POST или JSON? – Affe

+0

@Affe: JSON, отправленный либо через запрос AJAX браузера, либо через Spring 'RestTemplate'. – woemler

ответ

1

Чтобы сообщить Spring, что вы хотите, чтобы он применял десериализатор к контенту вместо попытки стандартного связывания HTML-формы, вы используете @RequestBody.

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

@RequestParam говорит его искать отдельный параметр с таким именем и применять стандартную привязку данных, а не десериализации все содержимое POST в объект.

+0

Нужно ли явно указывать 'consumes =" application/something "'? Или он ожидает правильный формат JSON? Нужны ли дополнительные заголовки запроса? – woemler

+0

Только если вы хотите перенаправить запросы с разными заголовками в разные места или заблокировать их. Для простых вещей готовый '' mvc: annotation-driven /> 'будет« правильно ». (обратите внимание, если вы укажете потребление, запросы с допустимым содержимым, но отсутствие заголовка будет отвергнуто, вы можете или не захотите этого.) – Affe

+0

Написание моего метода контроллера, как будто у вас есть, это приводит к ошибкам '415 (Unsupported Media Type). Другой ответ SO (http://stackoverflow.com/questions/11492325/post-json-fails-with-415-unsupported-media-type-spring-3-mvc) предлагает изменить заголовки запросов, но это не помогло ни , – woemler

1

Да, абсолютно. Джексон автоматически сделает двустороннее сопоставление сущностей, поэтому, если вы хотите, чтобы POST что-то серверу, используйте тот же формат JSON, который вы видите, когда делаете GET.

Смежные вопросы