Je travaille avec Spring Framework 4.0.7, avec MVC et Rest
Je peux travailler en paix avec:
@Controller
ResponseEntity<T>
Par exemple:
@Controller
@RequestMapping("/person")
@Profile("responseentity")
public class PersonRestResponseEntityController {
Avec la méthode (juste pour créer)
@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);
}
retourner quelque chose
@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);
}
Fonctionne bien
Je peux faire la même chose avec:
@RestController
(Je sais que c'est la même chose que @Controller
+ @ResponseBody
)@ResponseStatus
Par exemple:
@RestController
@RequestMapping("/person")
@Profile("restcontroller")
public class PersonRestController {
Avec la méthode (juste pour créer)
@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());
}
retourner quelque chose
@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;
}
Mes questions sont:
ResponseEntity
est censé représenter la totalité de la réponse HTTP. Vous pouvez contrôler tout ce qui y va: code d'état, en-têtes et corps.
@ResponseBody
est un marqueur pour le corps de la réponse HTTP et @ResponseStatus
déclare le code d'état de la réponse HTTP.
@ResponseStatus
n'est pas très flexible. Elle marque toute la méthode, vous devez donc vous assurer que votre méthode de gestionnaire se comportera toujours de la même manière. Et vous ne pouvez toujours pas définir les en-têtes. Vous aurez besoin du paramètre HttpServletResponse
ou d'un paramètre HttpHeaders
.
En gros, ResponseEntity
vous permet de faire plus.
Pour compléter la réponse de Sotorios Delimanolis.
Il est vrai que ResponseEntity
vous donne plus de flexibilité, mais dans la plupart des cas, vous n'en aurez pas besoin et vous vous retrouverez avec ces ResponseEntity
partout dans votre contrôleur, ce qui rend la lecture et la compréhension difficiles.
Si vous souhaitez gérer des cas particuliers tels que des erreurs (non trouvé, conflit, etc.), vous pouvez ajouter un HandlerExceptionResolver
à votre configuration Spring. Ainsi, dans votre code, il vous suffit de lancer une exception spécifique (NotFoundException
par exemple) et de décider quoi faire dans votre gestionnaire (attribuer le statut HTTP à 404), ce qui rend le code du contrôleur plus clair.
Selon la documentation officielle: Création de REST contrôleurs avec l'annotation @RestController
@RestController est une annotation de stéréotype qui combine @ResponseBody et @Controller. Plus que cela, il donne plus de sens à votre contrôleur et peut également porter une sémantique supplémentaire dans les prochaines versions du framework.
Il semble préférable d’utiliser @RestController
pour plus de clarté, mais vous pouvez aussi le combiner avec ResponseEntity
pour plus de souplesse en cas de besoin ( Selon le tutoriel officiel et le code ici et ma question pour le confirmer ).
Par exemple:
@RestController
public class MyController {
@GetMapping(path = "/test")
@ResponseStatus(HttpStatus.OK)
public User test() {
User user = new User();
user.setName("Name 1");
return user;
}
}
est le même que:
@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);
}
}
De cette façon, vous ne pouvez définir ResponseEntity
que lorsque cela est nécessaire.
Mettre à jour
Vous pouvez utiliser ceci:
return ResponseEntity.ok().headers(responseHeaders).body(user);
Une API REST appropriée doit avoir les composants suivants en réponse
ResponseEntity avait pour objectif principal de proposer l'option 3, les options de repos pouvant être réalisées sans ResponseEntity.
Par conséquent, si vous souhaitez indiquer l'emplacement de la ressource, utilisez plutôt ResponseEntity, sinon vous pouvez l'éviter.
Prenons un exemple où une API est modifiée pour fournir toutes les options mentionnées.
// 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);
}
Source - Spring in Action