Spring RESTful 애플리케이션에 ResponseEntity <T> 및 @RestController를 사용하는 경우


163

MVC 및 Rest와 함께 Spring Framework 4.0.7을 사용하고 있습니다.

나는 평화롭게 일할 수 있습니다 :

  • @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. 고체 이유로 또는 특정 시나리오 하나의 옵션 다른 이상 의무적으로 사용해야합니다
  2. (1)이 중요하지 않은 경우 어떤 접근 방식이 제안되며 그 이유는 무엇입니까?

답변:


213

ResponseEntity전체 HTTP 응답을 나타냅니다. 상태 코드, 헤더 및 본문과 관련된 모든 것을 제어 할 수 있습니다.

@ResponseBody는 HTTP 응답 본문의 표시 자이며 HTTP 응답 @ResponseStatus의 상태 코드를 선언합니다.

@ResponseStatus매우 유연하지 않습니다. 전체 메소드를 표시하므로 핸들러 메소드가 항상 동일한 방식으로 작동하는지 확인해야합니다. 그리고 여전히 헤더를 설정할 수 없습니다. HttpServletResponse또는 HttpHeaders매개 변수 가 필요합니다 .

기본적으로 ResponseEntity더 많은 일을 할 수 있습니다.


6
세 번째 관찰에 대한 좋은 지적. 감사합니다…에 대해 똑같이 생각했습니다 ResponseEntity. 더 유연합니다. 에 대한 의문이 생겼습니다 @RestController. 감사합니다
Manuel Jordan

55

Sotorios Delimanolis의 답변을 완성합니다.

ResponseEntity더 많은 유연성 을 제공하는 것이 사실 이지만 대부분의 경우 필요하지 않으며 ResponseEntity컨트롤러의 모든 곳에서 결과를 읽고 이해하기가 어렵습니다.

오류 (찾을 수 없음, 충돌 등)와 같은 특수한 경우를 처리 HandlerExceptionResolver하려면 스프링 구성에을 추가하면 됩니다. 따라서 코드에서 특정 예외 ( NotFoundException예 :)를 throw하고 처리기에서 수행 할 작업 (HTTP 상태를 404로 설정)을 결정하면 컨트롤러 코드가 더 명확 해집니다.


5
귀하의 관점은 (@) ExceptionHandler와 함께 유효합니다. 요점은 : 하나의 메소드 (Try / Catch)에서 모두 처리하려는 경우 HttpEntity가 잘 맞고 많은 (@) RequestMapping에 대한 예외 처리 (@) ExceptionHandler를 재사용하려면 잘 맞습니다. HttpHeaders로 작업 할 수 있기 때문에 HttpEntity를 좋아합니다.
Manuel Jordan

46

공식 문서에 따르면 @RestController 주석으로 REST 컨트롤러 작성

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

메소드에 @ResponseStatus (HttpStatus.OK)를 추가했지만 메소드가 new ResponseEntity <> (user, responseHeaders, HttpStatus.NOT_FOUND)를 반환하면 어떻게 될까요? @ResponseStatus가 응답 코드를 추가로 수정하는지 여부를 생각하고 있습니다.
Pratapi Hemant Patel

4
@Hemant는 @ResponseStatus(HttpStatus.OK)돌아올 때 무시되는 것 같습니다 ResponseEntity<>(user, responseHeaders, HttpStatus.NOT_FOUND). HTTP 응답은404
Danail

ResponseStatus의 JavaDoc에서. 핸들러 코드가 호출되면 상태 코드가 HTTP 응답에 적용되고 {@code ResponseEntity} 또는 {@code "redirect :"}와 같은 다른 방법으로 설정된 상태 정보를 무시합니다.
vzhemevko

14

적절한 REST API는 응답 아래 구성 요소를 가져야합니다.

  1. 상태 코드
  2. 응답 본문
  3. 변경된 리소스의 위치 (예 : 리소스가 생성 된 경우 클라이언트는 해당 위치의 URL을 알고 싶어 함)

ResponseEntity의 주요 목적은 옵션 3을 제공하는 것이 었으며 나머지 옵션은 ResponseEntity 없이도 달성 할 수 있습니다.

따라서 리소스의 위치를 ​​제공하려면 ResponseEntity를 사용하는 것이 좋습니다. 그렇지 않으면 피할 수 있습니다.

언급 된 모든 옵션을 제공하도록 API가 수정 된 예를 고려하십시오.

// Step 1 - Without any options provided
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public @ResponseBody Spittle spittleById(@PathVariable long id) {
  return spittleRepository.findOne(id);
}

// Step 2- We need to handle exception scenarios, as step 1 only caters happy path.
@ExceptionHandler(SpittleNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Error spittleNotFound(SpittleNotFoundException e) {
  long spittleId = e.getSpittleId();
  return new Error(4, "Spittle [" + spittleId + "] not found");
}

// Step 3 - Now we will alter the service method, **if you want to provide location**
@RequestMapping(
    method=RequestMethod.POST
    consumes="application/json")
public ResponseEntity<Spittle> saveSpittle(
    @RequestBody Spittle spittle,
    UriComponentsBuilder ucb) {

  Spittle spittle = spittleRepository.save(spittle);
  HttpHeaders headers = new HttpHeaders();
  URI locationUri =
  ucb.path("/spittles/")
      .path(String.valueOf(spittle.getId()))
      .build()
      .toUri();
  headers.setLocation(locationUri);
  ResponseEntity<Spittle> responseEntity =
      new ResponseEntity<Spittle>(
          spittle, headers, HttpStatus.CREATED)
  return responseEntity;
}

// Step4 - If you are not interested to provide the url location, you can omit ResponseEntity and go with
@RequestMapping(
    method=RequestMethod.POST
    consumes="application/json")
@ResponseStatus(HttpStatus.CREATED)
public Spittle saveSpittle(@RequestBody Spittle spittle) {
  return spittleRepository.save(spittle);
}

근원-행동 봄

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.