diff --git a/spring-security-rest-full/README.md b/spring-security-rest-full/README.md index 59cf865b9a..0558678934 100644 --- a/spring-security-rest-full/README.md +++ b/spring-security-rest-full/README.md @@ -6,6 +6,8 @@ ### Relevant Articles: - [Spring Security Expressions - hasRole Example](http://www.baeldung.com/spring-security-expressions-basic) - [REST Pagination in Spring](http://www.baeldung.com/2012/01/18/rest-pagination-in-spring/) +- [HATEOAS for a Spring REST Service](http://www.baeldung.com/2011/11/13/rest-service-discoverability-with-spring-part-5/) +- [REST API Discoverability and HATEOAS](2011/11/06/restful-web-service-discoverability-part-4/) ### Build the Project diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/FooController.java b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/FooController.java index 5e05db1056..32db49f9a7 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/controller/FooController.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/controller/FooController.java @@ -48,8 +48,9 @@ public class FooController { @RequestMapping(value = "/{id}", method = RequestMethod.GET) @ResponseBody - public Foo findOne(@PathVariable("id") final Long id, final UriComponentsBuilder uriBuilder, final HttpServletRequest request, final HttpServletResponse response) { + public Foo findById(@PathVariable("id") final Long id, final HttpServletRequest request, final HttpServletResponse response) { final Foo resourceById = RestPreconditions.checkFound(service.findOne(id)); + eventPublisher.publishEvent(new SingleResourceRetrieved(this, request, response)); return resourceById; } diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/ResourceCreated.java b/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/ResourceCreated.java new file mode 100644 index 0000000000..3a2c8d3187 --- /dev/null +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/ResourceCreated.java @@ -0,0 +1,33 @@ +package org.baeldung.web.hateoas; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.ApplicationEvent; + +public class ResourceCreated extends ApplicationEvent { + private final HttpServletResponse response; + private final HttpServletRequest request; + private final long idOfNewResource; + + public ResourceCreated(final Object source, final HttpServletRequest request, final HttpServletResponse response, final long idOfNewResource) { + super(source); + + this.request = request; + this.response = response; + this.idOfNewResource = idOfNewResource; + } + + public HttpServletResponse getResponse() { + return response; + } + + public HttpServletRequest getRequest() { + return request; + } + + public long getIdOfNewResource() { + return idOfNewResource; + } + +} \ No newline at end of file diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/SingleResourceRetrieved.java b/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/SingleResourceRetrieved.java new file mode 100644 index 0000000000..8a115a1ff6 --- /dev/null +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/hateoas/SingleResourceRetrieved.java @@ -0,0 +1,26 @@ +package org.baeldung.web.hateoas; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.context.ApplicationEvent; + +public class SingleResourceRetrieved extends ApplicationEvent { + private final HttpServletResponse response; + private final HttpServletRequest request; + + public SingleResourceRetrieved(final Object source, final HttpServletRequest request, final HttpServletResponse response) { + super(source); + + this.request = request; + this.response = response; + } + + public HttpServletResponse getResponse() { + return response; + } + + public HttpServletRequest getRequest() { + return request; + } +} \ No newline at end of file diff --git a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SingleResourceRetrievedDiscoverabilityListener.java b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SingleResourceRetrievedDiscoverabilityListener.java index 61fb601ac9..6be6c08df9 100644 --- a/spring-security-rest-full/src/main/java/org/baeldung/web/util/SingleResourceRetrievedDiscoverabilityListener.java +++ b/spring-security-rest-full/src/main/java/org/baeldung/web/util/SingleResourceRetrievedDiscoverabilityListener.java @@ -7,6 +7,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; import com.google.common.base.Preconditions; +import com.google.common.net.HttpHeaders; @Component class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListener { @@ -26,7 +27,7 @@ class SingleResourceRetrievedDiscoverabilityListener implements ApplicationListe final String uriForResourceCreation = requestURL.substring(0, positionOfLastSlash); final String linkHeaderValue = LinkUtil.createLinkHeader(uriForResourceCreation, "collection"); - response.addHeader("Link", linkHeaderValue); + response.addHeader(HttpHeaders.LINK, linkHeaderValue); } } \ No newline at end of file diff --git a/spring-security-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java b/spring-security-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java index d538a94645..86b934ae1e 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/common/web/AbstractLiveTest.java @@ -2,6 +2,7 @@ package org.baeldung.common.web; import static org.apache.commons.lang3.RandomStringUtils.randomNumeric; import static org.baeldung.web.util.HTTPLinkHeaderUtil.extractURIByRel; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -12,6 +13,7 @@ import java.io.Serializable; import java.util.List; import org.baeldung.test.IMarshaller; +import org.hamcrest.core.AnyOf; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +38,18 @@ public abstract class AbstractLiveTest { } // tests + @Test + public void whenInvalidPOSTIsSentToValidURIOfResource_thenAllowHeaderListsTheAllowedActions() { + // Given + final String uriOfExistingResource = createAsUri(); + + // When + final Response res = givenAuth().post(uriOfExistingResource); + + // Then + final String allowHeader = res.getHeader(HttpHeaders.ALLOW); + assertThat(allowHeader, AnyOf. anyOf(containsString("GET"), containsString("PUT"), containsString("DELETE"))); + } // find - one @@ -111,11 +125,13 @@ public abstract class AbstractLiveTest { public abstract void create(); + public abstract String createAsUri(); + protected final void create(final T resource) { createAsUri(resource); } - final String createAsUri(final T resource) { + protected final String createAsUri(final T resource) { final Response response = createAsResponse(resource); Preconditions.checkState(response.getStatusCode() == 201, "create operation: " + response.getStatusCode()); diff --git a/spring-security-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java b/spring-security-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java index b158b22376..36b30d5e57 100644 --- a/spring-security-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java +++ b/spring-security-rest-full/src/test/java/org/baeldung/web/FooLiveTest.java @@ -25,4 +25,9 @@ public class FooLiveTest extends AbstractLiveTest { create(new Foo(randomAlphabetic(6))); } + @Override + public final String createAsUri() { + return createAsUri(new Foo(randomAlphabetic(6))); + } + }