What is the preferred way to specify an HTTP “Location” Response Header in Spring MVC 3?
As far as I can tell, Spring will only provide a “Location” in response to a redirect (“redirect:xyz” or RedirectView), however there are scenarios where a Location should be sent along with the entity body (ex, as a result of a “201 Created”).
I’m afraid my only option is manually specifying it:
httpServletResponse.setHeader("Location", "/x/y/z");
Is this correct? Is there a better way to tackle this problem?
Advertisement
Answer
The key point is to use UriComponentsBuilder
.
There are several ways how you can get the instance of it
- preconfigured
UriComponentsBuilder
fromMvcUriComponentsBuilder
UriComponentsBuilder
injected as parameter to method
Preconfigured UriComponentsBuilder
from MvcUriComponentsBuilder
This way you can get UriComponentsBuilder
that is configured to produce URI
that points to some controller methods with predefined parameters.
Here is example from the javadoc for MvcUriComponentsBuilder
:
For example, given this controller:
@RequestMapping("/people/{id}/addresses") class AddressController { @RequestMapping("/{country}") public HttpEntity<Void> getAddressesForCountry(@PathVariable String country) { ... } @RequestMapping(value="/", method=RequestMethod.POST) public void addAddress(Address address) { ... } }
A UriComponentsBuilder can be created:
// Inline style with static import of "MvcUriComponentsBuilder.on" MvcUriComponentsBuilder.fromMethodCall( on(AddressController.class).getAddressesForCountry("US")).buildAndExpand(1);
Another options which sometimes may be preferable is to specify controller method by name:
UriComponents uriComponents = MvcUriComponentsBuilder.fromMethodName( AddressController.class, "getAddressesForCountry", "US").buildAndExpand(1); URI nextUri = uriComponents.toUri();
UriComponentsBuilder
injected as parameter to method
As of spring 3.1 Location
can be crafted using UriComponentBuilder
parameter and set it to the returned ResponseEntity
. UriComponentBuilder
is aware of the context and manipulates with relative paths:
@RequestMapping(method = RequestMethod.POST) public ResponseEntity<?> createCustomer(UriComponentsBuilder b) { UriComponents uriComponents = b.path("/customers/{id}").buildAndExpand(id); HttpHeaders headers = new HttpHeaders(); headers.setLocation(uriComponents.toUri()); return new ResponseEntity<Void>(headers, HttpStatus.CREATED); }
Since version 4.1 you can make it even shorter
@RequestMapping(method = RequestMethod.POST) public ResponseEntity<?> createCustomer(UriComponentsBuilder b) { UriComponents uriComponents = b.path("/customers/{id}").buildAndExpand(id); return ResponseEntity.created(uriComponents.toUri()).build(); }
Thanks to Dieter Hubau to pointing this out.