|
@@ -1,12 +1,13 @@
|
1
|
1
|
|
2
|
2
|
|
3
|
|
-# Part 1 - Domain Implementation<br>
|
|
3
|
+# Part 1 - Domain Implementation
|
|
4
|
+
|
4
|
5
|
* _Domain objects_ are the backbone for an application and contain the [business logic](https://en.wikipedia.org/wiki/Business_logic).
|
5
|
6
|
* Create a sub package of `io.zipcoder.tc_spring_poll_application` named `domain`.
|
6
|
7
|
|
7
|
8
|
|
8
|
|
--
|
9
|
9
|
## Part 1.1 - Create class `Option`
|
|
10
|
+
|
10
|
11
|
* Create an `Option` class in the `domain` sub-package.
|
11
|
12
|
* `Option` class signature is annotated with `@Entity`
|
12
|
13
|
* `Option` has an `id` instance variable of type `Long`
|
|
@@ -25,8 +26,8 @@
|
25
|
26
|
* Create a `getter` and `setter` for each of the respective instance variables.
|
26
|
27
|
|
27
|
28
|
|
28
|
|
--
|
29
|
29
|
## Part 1.2 - Create class `Poll`
|
|
30
|
+
|
30
|
31
|
* Create a `Poll` class in the `domain` sub-package.
|
31
|
32
|
* `Poll` class signature is annotated with `@Entity`
|
32
|
33
|
* `Poll` has an `id` instance variable of type `Long`
|
|
@@ -48,9 +49,8 @@
|
48
|
49
|
* Create a `getter` and `setter` for each of the respective instance variables.
|
49
|
50
|
|
50
|
51
|
|
51
|
|
-
|
52
|
|
--
|
53
|
52
|
## Part 1.3 - Create class `Vote`
|
|
53
|
+
|
54
|
54
|
* Create a `Vote` class in the `domain` sub-package.
|
55
|
55
|
* `Vote` class signature is annotated with `@Entity`
|
56
|
56
|
* `Vote` has an `id` instance variable of type `Long`
|
|
@@ -67,55 +67,49 @@
|
67
|
67
|
* Create a `getter` and `setter` for each of the respective instance variables.
|
68
|
68
|
|
69
|
69
|
|
70
|
|
-
|
71
|
|
-
|
72
|
|
--
|
73
|
|
--
|
74
|
70
|
# Part 2 - Repository Implementation
|
|
71
|
+
|
75
|
72
|
* _Repositories_ or [Data Access Objects (DAO)](https://en.wikipedia.org/wiki/Data_access_object), provide an abstraction for interacting with _datastores_.
|
76
|
73
|
* Typically DAOs include an interface that provides a set of finder methods such as `findById`, `findAll`, for retrieving data, and methods to persist and delete data.
|
77
|
74
|
* It is customary to have one `Repository` per `domain` object.
|
78
|
75
|
* Create a sub-package of `io.zipcoder.tc_spring_poll_application` named `repositories`.
|
79
|
76
|
|
80
|
77
|
|
81
|
|
--
|
82
|
78
|
## Part 2.1 - Create interface `OptionRepository`
|
|
79
|
+
|
83
|
80
|
* Create an `OptionRepository` interface in the `repositories` subpackage.
|
84
|
81
|
* `OptionRepository` extends `CrudRepository<Option, Long>`
|
85
|
82
|
|
86
|
|
--
|
|
83
|
+
|
87
|
84
|
## Part 2.2 - Create interface `PollRepository`
|
|
85
|
+
|
88
|
86
|
* Create a `PollRepository` interface in the `repositories` subpackage.
|
89
|
87
|
* `PollRepository` extends `CrudRepository<Poll, Long>`
|
90
|
88
|
|
91
|
|
--
|
|
89
|
+
|
92
|
90
|
## Part 2.3 - Create interface `VoteRepository`
|
|
91
|
+
|
93
|
92
|
* Create a `VoteRepository` interface in the `repositories` subpackage.
|
94
|
93
|
* `VoteRepository` extends `CrudRepository<Vote, Long>`
|
95
|
94
|
|
96
|
|
-
|
97
|
|
-
|
98
|
|
-
|
99
|
|
-
|
100
|
|
-
|
101
|
|
--
|
102
|
|
--
|
103
|
95
|
# Part 3 - Controller Implementation
|
|
96
|
+
|
104
|
97
|
* _Controllers_ provides all of the necessary [endpoints](https://en.wikipedia.org/wiki/Web_API#Endpoints) to access and manipulate respective domain objects.
|
105
|
98
|
* REST resources are identified using URI endpoints.
|
106
|
99
|
* Create a sub package of `io.zipcoder.tc_spring_poll_application` named `controller`.
|
107
|
100
|
|
108
|
101
|
|
109
|
|
--
|
110
|
102
|
## Part 3.1 - Create class `PollController`
|
|
103
|
+
|
111
|
104
|
* Create a `PollController` class in the `controller` sub package.
|
112
|
105
|
* `PollController` signature should be `annotated` with `@RestController`
|
113
|
106
|
|
114
|
107
|
* `PollController` has a `pollRepository` instance variable of type `PollRepository`
|
115
|
108
|
* `pollRepository` should be `annotated` with `@Inject`
|
116
|
109
|
|
117
|
|
--
|
|
110
|
+
|
118
|
111
|
### Part 3.1.1 - Create `GET` request method
|
|
112
|
+
|
119
|
113
|
* The method definition below supplies a `GET` request on the `/polls` endpoint which provides a collection of all of the polls available in the QuickPolls application. Copy and paste this into your `PollController` class.
|
120
|
114
|
|
121
|
115
|
```java
|
|
@@ -132,9 +126,8 @@ public ResponseEntity<Iterable<Poll>> getAllPolls() {
|
132
|
126
|
|
133
|
127
|
|
134
|
128
|
|
135
|
|
-
|
136
|
|
--
|
137
|
129
|
### Part 3.1.2 - Testing via Postman
|
|
130
|
+
|
138
|
131
|
* Ensure that the `start-class` tag in your `pom.xml` encapsulates `io.zipcoder.springdemo.QuickPollApplication`
|
139
|
132
|
* Open a command line and navigate to the project's root directory and run this command:
|
140
|
133
|
* `mvn spring-boot:run`
|
|
@@ -143,9 +136,8 @@ public ResponseEntity<Iterable<Poll>> getAllPolls() {
|
143
|
136
|
|
144
|
137
|
|
145
|
138
|
|
146
|
|
-
|
147
|
|
--
|
148
|
139
|
### Part 3.1.3 - Create `POST` request method
|
|
140
|
+
|
149
|
141
|
* We accomplish the capability to add new polls to the `PollController` by implementing the `POST` verb functionality in a `createPoll` method:
|
150
|
142
|
|
151
|
143
|
```java
|
|
@@ -164,9 +156,8 @@ public ResponseEntity<?> createPoll(@RequestBody Poll poll) {
|
164
|
156
|
|
165
|
157
|
|
166
|
158
|
|
167
|
|
-
|
168
|
|
--
|
169
|
159
|
### Part 3.1.4 - Modify `createPoll`
|
|
160
|
+
|
170
|
161
|
* Best practice is to convey the URI to the newly created resource using the Location HTTP header via Spring's `ServletUriComponentsBuilder` utility class. This will ensure that the client has some way of knowing the URI of the newly created Poll.
|
171
|
162
|
|
172
|
163
|
```java
|
|
@@ -181,9 +172,8 @@ URI newPollUri = ServletUriComponentsBuilder
|
181
|
172
|
|
182
|
173
|
|
183
|
174
|
|
184
|
|
-
|
185
|
|
--
|
186
|
175
|
### Part 3.1.5 - Create `GET` request method
|
|
176
|
+
|
187
|
177
|
* The code snippet below enables us to access an individual poll.
|
188
|
178
|
* The _value attribute_ in the `@RequestMapping` takes a URI template `/polls/{pollId}`.
|
189
|
179
|
* The placeholder `{pollId}` along with `@PathVarible` annotation allows Spring to examine the request URI path and extract the `pollId` parameter value.
|
|
@@ -198,10 +188,8 @@ public ResponseEntity<?> getPoll(@PathVariable Long pollId) {
|
198
|
188
|
```
|
199
|
189
|
|
200
|
190
|
|
201
|
|
-
|
202
|
|
-
|
203
|
|
--
|
204
|
191
|
### Part 3.1.6 - Create `UPDATE` request method
|
|
192
|
+
|
205
|
193
|
* The code snippet below enables us to update a poll.
|
206
|
194
|
|
207
|
195
|
```java
|
|
@@ -214,8 +202,6 @@ public ResponseEntity<?> updatePoll(@RequestBody Poll poll, @PathVariable Long p
|
214
|
202
|
```
|
215
|
203
|
|
216
|
204
|
|
217
|
|
-
|
218
|
|
--
|
219
|
205
|
### Part 3.1.7 - Create `DELETE` request method.
|
220
|
206
|
|
221
|
207
|
* The code snippet below enables us to delete a poll.
|
|
@@ -229,10 +215,8 @@ public ResponseEntity<?> deletePoll(@PathVariable Long pollId) {
|
229
|
215
|
```
|
230
|
216
|
|
231
|
217
|
|
232
|
|
-
|
233
|
|
-
|
234
|
|
--
|
235
|
218
|
### Part 3.1.8 - Test
|
|
219
|
+
|
236
|
220
|
* Restart the QuickPoll application.
|
237
|
221
|
* Use Postman to execute a `POST` to `http://localhost:8080/polls/` whose request body is the `JSON` object below.
|
238
|
222
|
* You can modify the request body in Postman by navigating to the `Body` tab, selecting the `raw` radio button, and selecting the `JSON` option from the text format dropdown.
|
|
@@ -251,8 +235,8 @@ public ResponseEntity<?> deletePoll(@PathVariable Long pollId) {
|
251
|
235
|
```
|
252
|
236
|
|
253
|
237
|
|
254
|
|
--
|
255
|
238
|
## Part 3.2 - Create class `VoteController`
|
|
239
|
+
|
256
|
240
|
* Following the principles used to create `PollController`, we implement the `VoteController` class.
|
257
|
241
|
* Below is the code for the `VoteController` class along with the functionality to create a vote.
|
258
|
242
|
* The `VoteController` uses an injected instance of `VoteRepository` to perform `CRUD` operations on Vote instances.
|
|
@@ -277,6 +261,7 @@ public class VoteController {
|
277
|
261
|
```
|
278
|
262
|
|
279
|
263
|
### Part 3.2.1 - Testing `VoteController`
|
|
264
|
+
|
280
|
265
|
* To test the voting capabilities, `POST` a new Vote to the `/polls/1/votes` endpoint with the option object expressed in `JSON` below.
|
281
|
266
|
* On successful request execution, you will see a Location response header with value http://localhost:8080/polls/1/votes/1.
|
282
|
267
|
|
|
@@ -287,10 +272,8 @@ public class VoteController {
|
287
|
272
|
```
|
288
|
273
|
|
289
|
274
|
|
290
|
|
-
|
291
|
|
-
|
292
|
|
--
|
293
|
275
|
### Part 3.2.2 - Modify `VoteRepository`
|
|
276
|
+
|
294
|
277
|
* The method `findAll` in the `VoteRepository` retrieves all votes in a Database rather than a given poll.
|
295
|
278
|
* To ensure we can get votes for a given poll, we must add the code below to our `VoteRepository`.
|
296
|
279
|
|
|
@@ -309,9 +292,8 @@ public interface VoteRepository extends CrudRepository<Vote, Long> {
|
309
|
292
|
* At runtime, Spring Data JPA replaces the `?1` placeholder with the passed-in `pollId` parameter value.
|
310
|
293
|
|
311
|
294
|
|
312
|
|
-
|
313
|
|
--
|
314
|
295
|
### Part 3.2.3 - Modify `VoteController`
|
|
296
|
+
|
315
|
297
|
* Create a `getAllVotes` method in the `VoteController`
|
316
|
298
|
|
317
|
299
|
|
|
@@ -322,15 +304,16 @@ public Iterable<Vote> getAllVotes(@PathVariable Long pollId) {
|
322
|
304
|
}
|
323
|
305
|
```
|
324
|
306
|
|
325
|
|
--
|
326
|
|
--
|
|
307
|
+
|
327
|
308
|
# Part 4 - Data Transfer Object (DTO) Implementation
|
|
309
|
+
|
328
|
310
|
* The final piece remaining for us is the implementation of the ComputeResult resource.
|
329
|
311
|
* Because we don’t have any domain objects that can directly help generate this resource representation, we implement two Data Transfer Objects or DTOs—OptionCount and VoteResult
|
330
|
312
|
* Create a sub package of `java` named `dtos`
|
331
|
313
|
|
332
|
|
--
|
|
314
|
+
|
333
|
315
|
## Part 4.1 - Create class `OptionCount`
|
|
316
|
+
|
334
|
317
|
* The `OptionCount` DTO contains the `ID` of the option and a count of votes casted for that option.
|
335
|
318
|
|
336
|
319
|
```java
|
|
@@ -356,7 +339,9 @@ public class OptionCount {
|
356
|
339
|
}
|
357
|
340
|
```
|
358
|
341
|
|
|
342
|
+
|
359
|
343
|
## Part 4.2 - Create class `VoteResult`
|
|
344
|
+
|
360
|
345
|
* The `VoteResult` DTO contains the total votes cast and a collection of `OptionCount` instances.
|
361
|
346
|
|
362
|
347
|
```java
|
|
@@ -385,6 +370,7 @@ public class VoteResult {
|
385
|
370
|
|
386
|
371
|
|
387
|
372
|
## Part 4.3 - Create class `ComputeResultController`
|
|
373
|
+
|
388
|
374
|
* Following the principles used in creating the `PollController` and `VoteController`, we create a new `ComputeResultController` class
|
389
|
375
|
|
390
|
376
|
```java
|
|
@@ -411,6 +397,7 @@ public class ComputeResultController {
|
411
|
397
|
|
412
|
398
|
|
413
|
399
|
## Part 4.4 - Test via Postman
|
|
400
|
+
|
414
|
401
|
* Start/restart the `QuickPoll` application.
|
415
|
402
|
* Using the earlier Postman requests, create a poll and cast votes on its options.
|
416
|
403
|
* Ensure a JSON file with a `status` of `200` is returned by executing a `GET` request of `http://localhost:8080/computeresults?pollId=1` via Postman
|
|
@@ -538,24 +525,27 @@ Size.poll.options=Options must be greater than {2} and less than {1}
|
538
|
525
|
```
|
539
|
526
|
|
540
|
527
|
|
541
|
|
-
|
542
|
528
|
# Part 6 - Pagination
|
|
529
|
+
|
543
|
530
|
* To optimize performance, it is important to limit the amount of data returned, especially in the case of a mobile client.
|
544
|
531
|
* REST services have the ability to give clients access large datasets in manageable chunks, by splitting the data into discrete pages or _paging data_.
|
545
|
532
|
* For this lab, we will approach this by implementing the _page number pagination pattern_.
|
546
|
533
|
|
547
|
|
--
|
|
534
|
+
|
548
|
535
|
### Get Data From Page
|
|
536
|
+
|
549
|
537
|
* For example, a client wanting a blog post in page 3 of a hypothetical blog service can use a `GET` method resembling the following:
|
550
|
538
|
`http://blog.example.com/posts?page=3`
|
551
|
539
|
|
552
|
|
--
|
|
540
|
+
|
553
|
541
|
### Limit Data Retrieved From Page
|
|
542
|
+
|
554
|
543
|
* It is possible for the client to override the default page size by passing in a page-size parameter:
|
555
|
544
|
`http://blog.example.com/posts?page=3&size=20`
|
556
|
545
|
|
557
|
|
--
|
|
546
|
+
|
558
|
547
|
### Pagination Data
|
|
548
|
+
|
559
|
549
|
* Pagination-specific information includes
|
560
|
550
|
* total number of records
|
561
|
551
|
* total number of pages
|
|
@@ -574,10 +564,11 @@ Size.poll.options=Options must be greater than {2} and less than {1}
|
574
|
564
|
"totalRecords": 90
|
575
|
565
|
}
|
576
|
566
|
```
|
|
567
|
+
|
577
|
568
|
* Read more about REST pagination in Spring by clicking [here](https://dzone.com/articles/rest-pagination-spring).
|
578
|
569
|
|
579
|
570
|
|
580
|
|
--
|
|
571
|
+
|
581
|
572
|
## Part 6.1 - Load Dummy Poll Data
|
582
|
573
|
|
583
|
574
|
* Create a `src/main/resource/import.sql` file with _DML statements_ for populating the database upon bootstrap. The `import.sql` should insert at least 15 polls, each with 3 or more options.
|
|
@@ -597,8 +588,9 @@ Size.poll.options=Options must be greater than {2} and less than {1}
|
597
|
588
|
* Restart your application.
|
598
|
589
|
* Use Postman to ensure database is populated by `import.sql`.
|
599
|
590
|
|
600
|
|
--
|
|
591
|
+
|
601
|
592
|
## Part 6.2 - Spring's Built-in Pagination
|
|
593
|
+
|
602
|
594
|
* Make use of Spring's built-in page number pagination support by researching `org.springframework.data.repository.PagingAndSortingRepository`.
|
603
|
595
|
* Modify respective `Controller` methods to handle `Pageable` arguments.
|
604
|
596
|
* Send a `GET` request to `http://localhost:8080/polls?page=0&size=2` via Postman.
|