What is the preferred way to specify an HTTP "Location" Response Header in Spring MVC 3?
java, rest, spring-mvc
Solution
The key point is to use `UriComponentsBuilder`. There are several ways how you can get the instance of it
- preconfigured `UriComponentsBuilder` from `MvcUriComponentsBuilder`
- `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.
Problem
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?