当使用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. 理由很充分特定的场景必须强制使用一个选项而不是另一个选项时
  2. 如果(1)不重要,建议什么方法以及为什么。
360467 次浏览

ResponseEntity表示整个HTTP响应。您可以控制其中的任何内容:状态代码、标题和主体。

@ResponseBody是HTTP响应体的标记,@ResponseStatus声明HTTP响应的状态代码。

@ResponseStatus不是很灵活。它标记了整个方法,因此您必须确保处理程序方法总是以相同的方式表现。你仍然不能设置头信息。你需要HttpServletResponse

基本上,ResponseEntity可以让你做更多的事情。

Sotorios Delimanolis的回答。

的确,ResponseEntity给了你更多的灵活性,但在大多数情况下,你不需要它,你最终会在你的控制器中到处都是这些ResponseEntity,从而使其难以阅读和理解。

如果你想处理特殊情况,比如错误(Not Found, Conflict,等等),你可以在Spring配置中添加HandlerExceptionResolver。所以在你的代码中,你只是抛出一个特定的异常(例如NotFoundException),并决定在你的处理程序中做什么(设置HTTP状态为404),使控制器代码更清楚。

根据官方文档:使用@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);

一个合适的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);
}