При использовании ResponseEntity <T> и @RestController для Spring приложений RESTful

Я работаю с Spring Framework 4.0.7 вместе с MVC и Rest

Я могу работать в мире с:

  • @Controller
  • ResponseEntity<T>

Например:

@Controller
@RequestMapping("/person")
@Profile("responseentity")
public class PersonRestResponseEntityController {

С помощью метода (только для создания)

@RequestMapping(value="/", method=RequestMethod.POST)
public ResponseEntity<Void> createPerson(@RequestBody Person person, UriComponentsBuilder ucb){
    logger.info("PersonRestResponseEntityController  - createPerson");
    if(person==null)
        logger.error("person is null!!!");
    else
        logger.info("{}", person.toString());

    personMapRepository.savePerson(person);
    HttpHeaders headers = new HttpHeaders();
    headers.add("1", "uno");
    //http://localhost:8080/spring-utility/person/1
    headers.setLocation(ucb.path("/person/{id}").buildAndExpand(person.getId()).toUri());

    return new ResponseEntity<>(headers, HttpStatus.CREATED);
}

чтобы вернуть что-то

@RequestMapping(value="/{id}", method=RequestMethod.GET)
public ResponseEntity<Person> getPerson(@PathVariable Integer id){
    logger.info("PersonRestResponseEntityController  - getPerson - id: {}", id);
    Person person = personMapRepository.findPerson(id);
    return new ResponseEntity<>(person, HttpStatus.FOUND);
}

Работает нормально

Я могу сделать то же самое с:

  • @RestController (Я знаю, что это то же самое, что @Controller + @ResponseBody)
  • @ResponseStatus

Например:

@RestController
@RequestMapping("/person")
@Profile("restcontroller")
public class PersonRestController {

С помощью метода (только для создания)

@RequestMapping(value="/", method=RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void createPerson(@RequestBody Person person, HttpServletRequest request, HttpServletResponse response){
    logger.info("PersonRestController  - createPerson");
    if(person==null)
        logger.error("person is null!!!");
    else
        logger.info("{}", person.toString());

    personMapRepository.savePerson(person);
    response.setHeader("1", "uno");

    //http://localhost:8080/spring-utility/person/1
    response.setHeader("Location", request.getRequestURL().append(person.getId()).toString());
}

чтобы вернуть что-то

@RequestMapping(value="/{id}", method=RequestMethod.GET)
@ResponseStatus(HttpStatus.FOUND)
public Person getPerson(@PathVariable Integer id){
    logger.info("PersonRestController  - getPerson - id: {}", id);
    Person person = personMapRepository.findPerson(id);
    return person;
}

Мои вопросы:

  • когда по твердой причине или конкретному сценарию один параметр должен обязательно использоваться над другим
  • Если (1) не имеет значения, какой подход предлагается и почему.

Ответ 1

ResponseEntity предназначен для представления всего HTTP-ответа. Вы можете контролировать все, что входит в это: код состояния, заголовки и тело.

@ResponseBody является маркером для тела ответа HTTP, а @ResponseStatus объявляет код состояния ответа HTTP.

@ResponseStatus не очень гибкий. Он отмечает весь метод, поэтому вы должны быть уверены, что ваш метод обработчика всегда будет вести себя одинаково. И вы все еще не можете установить заголовки. Вам понадобится параметр HttpServletResponse или HttpHeaders.

В принципе, ResponseEntity позволяет вам делать больше.

Ответ 2

Чтобы выполнить ответ от Sotorios Delimanolis.

Верно, что ResponseEntity дает вам большую гибкость, но в большинстве случаев вам это не понадобится, и вы получите все эти ResponseEntity везде в своем контроллере, что затруднит чтение и понимание.

Если вы хотите обрабатывать особые случаи, такие как ошибки (Not Found, Conflict и т.д.), вы можете добавить HandlerExceptionResolver к своему Spring. Поэтому в вашем коде вы просто бросаете конкретное исключение (например, NotFoundException) и решаете, что делать в вашем обработчике (настройка статуса HTTP на 404), что делает код контроллера более понятным.

Ответ 3

Согласно официальной документации: Создание контроллеров REST с аннотацией @RestController

@RestController представляет собой аннотацию стереотипа, объединяющую @ResponseBody и @Controller. Более того, это дает больше Контроллер, а также может нести дополнительную семантику в будущих выпусках структуры.

Кажется, что для ясности лучше использовать @RestController, но вы также можете объединить с ResponseEntity для гибкости при необходимости (Согласно официальному учебнику и код здесь и мой вопрос, чтобы подтвердить, что).

Например:

@RestController
public class MyController {

    @GetMapping(path = "/test")
    @ResponseStatus(HttpStatus.OK)
    public User test() {
        User user = new User();
        user.setName("Name 1");

        return user;
    }

}

совпадает с:

@RestController
public class MyController {

    @GetMapping(path = "/test")
    public ResponseEntity<User> test() {
        User user = new User();
        user.setName("Name 1");

        HttpHeaders responseHeaders = new HttpHeaders();
        // ...
        return new ResponseEntity<>(user, responseHeaders, HttpStatus.OK);
    }

}

Таким образом, вы можете определить ResponseEntity только при необходимости.

Обновление

Вы можете использовать это:

    return ResponseEntity.ok().headers(responseHeaders).body(user);