вторник, 8 ноября 2016 г.

@RestController vs. @Controller


Spring MVC и REST 

Spring - MVC фреймфорк, использующий аннотации, которые позволяют облегчить процесс создания RESTfull веб-сервиса. Основная разница между традиционным Spring MVC контроллером и RESTfull веб-сервис контроллером заключается в способе создания тела HTTP ответа. MVC контроллер опирается на технологию View, а RESTfull веб сервис контроллер  возвращает объект, который представляется в HTTP ответе  в виде JSON или XML. Для более подробного описания перейдите на эту ссылку.

Схема работы Spring MVC

  1. Клиент отправляет запрос к веб-сервису.
  2. Запрос перехватывается DispatcherServlet, который ищет Handler Mappings и соответствующий тип.
  3. Запрос обрабатывается контроллером и результат передается DispatcherServlet, а потом перенаправляется во view.

Использование @ResponseBody 

Когда вы используете аннотацию @ResponseBody для метода, Spring автоматически записывает результат в тело http ответа. Каждый метод в контроллере должен иметь данную аннотацию. Схема работы представлена на рисунке 1.
Рисунок 1.

Что происходит внутри

У Spring есть список HttpMessageConverters. HttpMessageConverter обязан конвертировать тело запроса к определенному классу и и класс к телу ответа, в зависимости от типа. Каждый раз, когда происходит запрос с аннотацией @ResponseBody, Spring ищет  среди всех HttpMessageConverters подходящий и использует его.

Пример

Рассмотрим POJO класс:

import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Employee")
public class Employee {
    String name; 
    String email;
    public String getName() {
       return name;
    }
    public void setName(String name) {
      this.name = name;
    }
    public String getEmail() {
       return email;
    }
    public void setEmail(String email) {
      this.email = email;
    }
    public Employee() {
    } 
}
И класс с аннотацией @Controller:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.spring.model.Employee;
@Controller
@RequestMapping("employees")
public class EmployeeController {
    Employee employee = new Employee();
    @RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
    public @ResponseBody Employee getEmployeeInJSON(@PathVariable String name) {
       employee.setName(name);
       employee.setEmail("employee1@genuitec.com");
    return employee; 
    }
    @RequestMapping(value = "/{name}.xml", method = RequestMethod.GET, produces = "application/xml")
    public @ResponseBody Employee getEmployeeInXML(@PathVariable String name) {
       employee.setName(name);
     employee.setEmail("employee1@genuitec.com");
       return employee; 
    }
}
В результате получим:
JSON: http://localhost:8080/SpringRestControllerExample/rest/employees/Bob

XML: http://localhost:8080/SpringRestControllerExample/rest/employees/Bob.xml

Использование аннотации @RestController

В Spring 4.0 была представлена аннотация @RestController. Применив ее к контроллеру добавляются аннотации @Controller, а так же @ResponseBody применяется ко всем методам. Подробнее можно почитать здесь. Схема работы на рисунке 2.
Рассмотрим этот же пример, но с новой аннотацией, POJO- класс не изменится, а контроллер примет следующий вид:

package com.example.spring.rest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.spring.model.Employee;
@RestController
@RequestMapping("employees")
public class EmployeeController {
    Employee employee = new Employee();
    @RequestMapping(value = "/{name}", method = RequestMethod.GET, produces = "application/json")
    public Employee getEmployeeInJSON(@PathVariable String name) {
       employee.setName(name);
       employee.setEmail("employee1@genuitec.com");
       return employee;
    }
    @RequestMapping(value = "/{name}.xml", method = RequestMethod.GET, produces = "application/xml")
    public Employee getEmployeeInXML(@PathVariable String name) {
       employee.setName(name);
       employee.setEmail("employee1@genuitec.com");
    return employee; 
    } 
}
Заметьте, что не нужно добавлять @ResponseBody к каждому методу. Запустив приложение - получим тот же результат.

PS это мой  перевод данной статьи

6 комментариев :

  1. Не @RequestBody,а @ResponseBody
    Поверяйте правильность стати перед публикацией пожалуйста.

    ОтветитьУдалить
  2. DispatcherServlet - ошибочка в начале статьи

    ОтветитьУдалить
  3. Можно еще короче - @RequestMapping заменить на @GetMapping/@PostMapping/@DeleteMapping...

    ОтветитьУдалить
  4. Напряжная статья, в Java доке куда очевиднее.

    ОтветитьУдалить