This guide walks you through the process of creating a “Hello, World” RESTful web service with Spring.
You will build a service that will accept HTTP GET requests at
http://localhost:8080/greeting
.
It will respond with a JSON representation of a greeting, as the following listing shows:
{"id":1,"content":"Hello, World!"}
You can customize the greeting with an optional name
parameter in the query string, as
the following listing shows:
http://localhost:8080/greeting?name=User
The name
parameter value overrides the default value of World
and is reflected in the
response, as the following listing shows:
{"id":1,"content":"Hello, User!"}
For all Spring applications, you should start with the Spring Initializr. The Initializr offers a fast way to pull in all the dependencies you need for an application and does a lot of the setup for you. This example needs only the Spring Web dependency. The following image shows the Initializr set up for this sample project:
Note
|
The preceding image shows the Initializr with Maven chosen as the build tool. You
can also use Gradle. It also shows values of com.example and rest-service as the Group
and Artifact, respectively. You will use those values throughout the rest of this sample.
|
The following listing shows the pom.xml
file that is created when you choose Maven:
link:initial/pom.xml[role=include]
The following listing shows the build.gradle
file that is created when you choose Gradle:
link:initial/build.gradle[role=include]
Because you will use JSON to send and receive information, you need a JSON library. In this guide, you will use the Jayway JsonPath library.
To include the library in a Maven build, add the following dependency to your pom.xml
file:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
The following listing shows the finished pom.xml
file:
link:complete/pom.xml[role=include]
To include the libary in a Gradle build, add the following dependency to your
build.gradle
file:
testCompile 'com.jayway.jsonpath:json-path'
The following listing shows the finished build.gradle
file:
link:complete/build.gradle[role=include]
Now that you have set up the project and build system, you can create your web service.
Begin the process by thinking about service interactions.
The service will handle GET
requests for /greeting
, optionally with a name
parameter
in the query string. The GET
request should return a 200 OK
response with JSON in the
body that represents a greeting. It should resemble the following output:
{
"id": 1,
"content": "Hello, World!"
}
The id
field is a unique identifier for the greeting, and content
is the textual
representation of the greeting.
To model the greeting representation, create a resource representation class. To do so,
provide a plain old Java object with fields, constructors, and accessors for the id
and
content
data, as the following listing (from
src/main/java/com/example/restservice/Greeting.java
) shows:
link:complete/src/main/java/com/example/restservice/Greeting.java[role=include]
Note
|
This application uses the Jackson JSON library to
automatically marshal instances of type Greeting into JSON. Jackson is included by default by the web starter.
|
In Spring’s approach to building RESTful web services, HTTP requests are handled by a
controller. These components are identified by the
@RestController
annotation, and the GreetingController
shown in the following listing (from
src/main/java/com/example/restservice/GreetingController.java
) handles GET
requests
for /greeting
by returning a new instance of the Greeting
class:
link:complete/src/main/java/com/example/restservice/GreetingController.java[role=include]
This controller is concise and simple, but there is plenty going on under the hood. We break it down step by step.
The @GetMapping
annotation ensures that HTTP GET requests to /greeting
are mapped to the greeting()
method.
Note
|
There are companion annotations for other HTTP verbs (e.g. @PostMapping for POST). There is also a @RequestMapping annotation that they all derive from, and can serve as a synonym (e.g. @RequestMapping(method=GET) ).
|
@RequestParam
binds the value of the query string parameter name
into the name
parameter of the greeting()
method. If the name
parameter is absent in the request,
the defaultValue
of World
is used.
The implementation of the method body creates and returns a new Greeting
object with
id
and content
attributes based on the next value from the counter
and formats the
given name
by using the greeting template
.
A key difference between a traditional MVC controller and the RESTful web service
controller shown earlier is the way that the HTTP response body is created. Rather than
relying on a view technology to perform server-side rendering of the greeting data to
HTML, this RESTful web service controller populates and returns a Greeting
object. The
object data will be written directly to the HTTP response as JSON.
This code uses Spring
@RestController
annotation, which marks the class as a controller where every method returns a domain
object instead of a view. It is shorthand for including both @Controller
and
@ResponseBody
.
The Greeting
object must be converted to JSON. Thanks to Spring’s HTTP message converter
support, you need not do this conversion manually. Because
Jackson 2 is on the classpath, Spring’s
MappingJackson2HttpMessageConverter
is automatically chosen to convert the Greeting
instance to JSON.
Logging output is displayed. The service should be up and running within a few seconds.
Now that the service is up, visit http://localhost:8080/greeting
, where you should see:
{"id":1,"content":"Hello, World!"}
Provide a name
query string parameter by visiting
http://localhost:8080/greeting?name=User
. Notice how the value of the content
attribute changes from Hello, World!
to Hello, User!
, as the following listing shows:
{"id":2,"content":"Hello, User!"}
This change demonstrates that the @RequestParam
arrangement in GreetingController
is
working as expected. The name
parameter has been given a default value of World
but
can be explicitly overridden through the query string.
Notice also how the id
attribute has changed from 1
to 2
. This proves that you are
working against the same GreetingController
instance across multiple requests and that
its counter
field is being incremented on each call as expected.
The following guides may also be helpful: