|
|
@@ -9,15 +9,17 @@ We recommend you use Gradle for your Spring projects. If you’re a big Ant / Iv
|
|
9
|
9
|
|
|
10
|
10
|
The following build.gradle file has everything we'll need for our project.
|
|
11
|
11
|
|
|
12
|
|
- apply plugin: 'java'
|
|
13
|
|
- apply plugin: 'jetty'
|
|
14
|
|
-
|
|
15
|
|
- repositories { mavenCentral() }
|
|
16
|
|
-
|
|
17
|
|
- dependencies {
|
|
18
|
|
- compile "org.springframework:spring-webmvc:3.2.2.RELEASE"
|
|
19
|
|
- compile "org.codehaus.jackson:jackson-mapper-asl:1.9.9"
|
|
20
|
|
- }
|
|
|
12
|
+```groovy
|
|
|
13
|
+apply plugin: 'java'
|
|
|
14
|
+apply plugin: 'jetty'
|
|
|
15
|
+
|
|
|
16
|
+repositories { mavenCentral() }
|
|
|
17
|
+
|
|
|
18
|
+dependencies {
|
|
|
19
|
+ compile "org.springframework:spring-webmvc:3.2.2.RELEASE"
|
|
|
20
|
+ compile "org.codehaus.jackson:jackson-mapper-asl:1.9.9"
|
|
|
21
|
+}
|
|
|
22
|
+```
|
|
21
|
23
|
|
|
22
|
24
|
Spring's REST support is based on Spring MVC. Therefore, we must add spring-webmvc as a dependency to our project. Also, so that our endpoints can produce JSON output, we needed to include the Jackson JSON library.
|
|
23
|
25
|
|
|
|
@@ -30,24 +32,26 @@ Setting up DispatcherServlet
|
|
30
|
32
|
----------------------------
|
|
31
|
33
|
Spring REST endpoints are built as Spring MVC controllers. Therefore, we'll need to be sure that Spring's DispatcherServlet is configured in our application's /WEB-INF/web.xml:
|
|
32
|
34
|
|
|
33
|
|
- <servlet>
|
|
34
|
|
- <servlet-name>appServlet</servlet-name>
|
|
35
|
|
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
|
36
|
|
- <init-param>
|
|
37
|
|
- <param-name>contextClass</param-name>
|
|
38
|
|
- <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
|
39
|
|
- </init-param>
|
|
40
|
|
- <init-param>
|
|
41
|
|
- <param-name>contextConfigLocation</param-name>
|
|
42
|
|
- <param-value>org.springframework.hello.config</param-value>
|
|
43
|
|
- </init-param>
|
|
44
|
|
- <load-on-startup>1</load-on-startup>
|
|
45
|
|
- </servlet>
|
|
46
|
|
-
|
|
47
|
|
- <servlet-mapping>
|
|
48
|
|
- <servlet-name>appServlet</servlet-name>
|
|
49
|
|
- <url-pattern>/</url-pattern>
|
|
50
|
|
- </servlet-mapping>
|
|
|
35
|
+```xml
|
|
|
36
|
+<servlet>
|
|
|
37
|
+ <servlet-name>appServlet</servlet-name>
|
|
|
38
|
+ <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
|
|
39
|
+ <init-param>
|
|
|
40
|
+ <param-name>contextClass</param-name>
|
|
|
41
|
+ <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
|
|
42
|
+ </init-param>
|
|
|
43
|
+ <init-param>
|
|
|
44
|
+ <param-name>contextConfigLocation</param-name>
|
|
|
45
|
+ <param-value>org.springframework.hello.config</param-value>
|
|
|
46
|
+ </init-param>
|
|
|
47
|
+ <load-on-startup>1</load-on-startup>
|
|
|
48
|
+</servlet>
|
|
|
49
|
+
|
|
|
50
|
+<servlet-mapping>
|
|
|
51
|
+ <servlet-name>appServlet</servlet-name>
|
|
|
52
|
+ <url-pattern>/</url-pattern>
|
|
|
53
|
+</servlet-mapping>
|
|
|
54
|
+```
|
|
51
|
55
|
|
|
52
|
56
|
Here we've configured DispatcherServlet to use AnnotationConfigWebApplicationContext as the context class so that our configuration can be expressed in Java, rather than XML. We've also set told DispatcherServlet (via the contextConfigLocation initialization parameter) that it can find our configuration classes in the org.springframework.hello.config package.
|
|
53
|
57
|
|
|
|
@@ -58,18 +62,21 @@ Creating a Configuration Class
|
|
58
|
62
|
------------------------------
|
|
59
|
63
|
In our Spring configuration, we'll need to enable annotation-oriented Spring MVC. And we'll also need to tell Spring where it can find our endpoint controller class. The following configuration class takes care of both of those things:
|
|
60
|
64
|
|
|
61
|
|
- package org.springframework.hello.config;
|
|
62
|
|
- import org.springframework.context.annotation.ComponentScan;
|
|
63
|
|
- import org.springframework.context.annotation.ComponentScan.Filter;
|
|
64
|
|
- import org.springframework.context.annotation.Configuration;
|
|
65
|
|
- import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
66
|
|
-
|
|
67
|
|
- @Configuration
|
|
68
|
|
- @EnableWebMvc
|
|
69
|
|
- @ComponentScan(basePackages="org.springframework.hello",
|
|
70
|
|
- excludeFilters=@Filter(Configuration.class))
|
|
71
|
|
- public class HelloWorldConfiguration {
|
|
72
|
|
- }
|
|
|
65
|
+
|
|
|
66
|
+```java
|
|
|
67
|
+package org.springframework.hello.config;
|
|
|
68
|
+import org.springframework.context.annotation.ComponentScan;
|
|
|
69
|
+import org.springframework.context.annotation.ComponentScan.Filter;
|
|
|
70
|
+import org.springframework.context.annotation.Configuration;
|
|
|
71
|
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
|
|
72
|
+
|
|
|
73
|
+@Configuration
|
|
|
74
|
+@EnableWebMvc
|
|
|
75
|
+@ComponentScan(basePackages="org.springframework.hello",
|
|
|
76
|
+ excludeFilters=@Filter(Configuration.class))
|
|
|
77
|
+public class HelloWorldConfiguration {
|
|
|
78
|
+}
|
|
|
79
|
+```
|
|
73
|
80
|
|
|
74
|
81
|
The @EnableWebMvc annotation turns on annotation-oriented Spring MVC. And we've also annotated the configuration class with @ComponentScan to have it look for components (including controllers) in the org.springframework.hello package. As it turns out, classes that are annotated with @Configuration are also discovered by component scanning, so we had to specify an exclude filter to keep it from discovering and using our configuration class a second time.
|
|
75
|
82
|
|
|
|
@@ -81,64 +88,70 @@ Before we get too carried away with building the endpoint controller, we need to
|
|
81
|
88
|
|
|
82
|
89
|
What we want is to handle GET requests for /hello-world, optionally with a name query parameter. In response to such a request, we'd like to send back JSON looking something like this:
|
|
83
|
90
|
|
|
84
|
|
- {
|
|
85
|
|
- "id": 1,
|
|
86
|
|
- "content": "Hello, stranger!"
|
|
87
|
|
- }
|
|
|
91
|
+```json
|
|
|
92
|
+{
|
|
|
93
|
+ "id": 1,
|
|
|
94
|
+ "content": "Hello, stranger!"
|
|
|
95
|
+}
|
|
|
96
|
+```
|
|
88
|
97
|
|
|
89
|
98
|
The id field is a unique identifier for the saying, and content is the textual representation of the saying.
|
|
90
|
99
|
|
|
91
|
100
|
To model this representation, we’ll create a representation class:
|
|
92
|
101
|
|
|
93
|
|
- package org.springframework.hello;
|
|
94
|
|
-
|
|
95
|
|
- public class Saying {
|
|
96
|
|
-
|
|
97
|
|
- private final long id;
|
|
98
|
|
- private final String content;
|
|
99
|
|
-
|
|
100
|
|
- public Saying(long id, String content) {
|
|
101
|
|
- this.id = id;
|
|
102
|
|
- this.content = content;
|
|
103
|
|
- }
|
|
104
|
|
-
|
|
105
|
|
- public long getId() {
|
|
106
|
|
- return id;
|
|
107
|
|
- }
|
|
108
|
|
-
|
|
109
|
|
- public String getContent() {
|
|
110
|
|
- return content;
|
|
111
|
|
- }
|
|
112
|
|
-
|
|
|
102
|
+```java
|
|
|
103
|
+package org.springframework.hello;
|
|
|
104
|
+
|
|
|
105
|
+public class Saying {
|
|
|
106
|
+
|
|
|
107
|
+ private final long id;
|
|
|
108
|
+ private final String content;
|
|
|
109
|
+
|
|
|
110
|
+ public Saying(long id, String content) {
|
|
|
111
|
+ this.id = id;
|
|
|
112
|
+ this.content = content;
|
|
113
|
113
|
}
|
|
114
|
114
|
|
|
|
115
|
+ public long getId() {
|
|
|
116
|
+ return id;
|
|
|
117
|
+ }
|
|
|
118
|
+
|
|
|
119
|
+ public String getContent() {
|
|
|
120
|
+ return content;
|
|
|
121
|
+ }
|
|
|
122
|
+
|
|
|
123
|
+}
|
|
|
124
|
+```
|
|
|
125
|
+
|
|
115
|
126
|
Now that we've got our representation class, let's create the endpoint controller that will serve it.
|
|
116
|
127
|
|
|
117
|
128
|
Creating a Resource Controller
|
|
118
|
129
|
------------------------------
|
|
119
|
130
|
In Spring, REST endpoints are just Spring MVC controllers. The following Spring MVC controller handles a GET request for /hello-world and returns our Saying resource:
|
|
120
|
131
|
|
|
121
|
|
- package org.springframework.hello;
|
|
122
|
|
- import java.util.concurrent.atomic.AtomicLong;
|
|
123
|
|
- import org.springframework.stereotype.Controller;
|
|
124
|
|
- import org.springframework.web.bind.annotation.RequestMapping;
|
|
125
|
|
- import org.springframework.web.bind.annotation.RequestMethod;
|
|
126
|
|
- import org.springframework.web.bind.annotation.RequestParam;
|
|
127
|
|
- import org.springframework.web.bind.annotation.ResponseBody;
|
|
128
|
|
-
|
|
129
|
|
- @Controller
|
|
130
|
|
- @RequestMapping("/hello-world")
|
|
131
|
|
- public class HelloWorldResource {
|
|
132
|
|
-
|
|
133
|
|
- private static final String template = "Hello, %s!";
|
|
134
|
|
- private final AtomicLong counter = new AtomicLong();
|
|
|
132
|
+```java
|
|
|
133
|
+package org.springframework.hello;
|
|
|
134
|
+import java.util.concurrent.atomic.AtomicLong;
|
|
|
135
|
+import org.springframework.stereotype.Controller;
|
|
|
136
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
137
|
+import org.springframework.web.bind.annotation.RequestMethod;
|
|
|
138
|
+import org.springframework.web.bind.annotation.RequestParam;
|
|
|
139
|
+import org.springframework.web.bind.annotation.ResponseBody;
|
|
|
140
|
+
|
|
|
141
|
+@Controller
|
|
|
142
|
+@RequestMapping("/hello-world")
|
|
|
143
|
+public class HelloWorldResource {
|
|
135
|
144
|
|
|
136
|
|
- @RequestMapping(method=RequestMethod.GET)
|
|
137
|
|
- public @ResponseBody Saying sayHello(@RequestParam(value="name", required=false, defaultValue="Stranger") String name) {
|
|
138
|
|
- return new Saying(counter.incrementAndGet(), String.format(template, name));
|
|
139
|
|
- }
|
|
140
|
|
-
|
|
|
145
|
+ private static final String template = "Hello, %s!";
|
|
|
146
|
+ private final AtomicLong counter = new AtomicLong();
|
|
|
147
|
+
|
|
|
148
|
+ @RequestMapping(method=RequestMethod.GET)
|
|
|
149
|
+ public @ResponseBody Saying sayHello(@RequestParam(value="name", required=false, defaultValue="Stranger") String name) {
|
|
|
150
|
+ return new Saying(counter.incrementAndGet(), String.format(template, name));
|
|
141
|
151
|
}
|
|
|
152
|
+
|
|
|
153
|
+}
|
|
|
154
|
+```
|
|
142
|
155
|
|
|
143
|
156
|
The key difference between a human-facing controller and a REST endpoint controller is in how the response is created. Rather than rely on a view (such as JSP) to render model data in HTML, an endpoint controller simply returns the data to be written directly to the body of the response.
|
|
144
|
157
|
|