ソースを参照

updated `README.md`

Leon 7 年 前
コミット
df9ed504fd
共有1 個のファイルを変更した51 個の追加408 個の削除を含む
  1. 51
    408
      README.md

+ 51
- 408
README.md ファイルの表示

1
-
2
-
3
-# Part 1 - Domain Implementation<br>
4
-* _Domain objects_ are the backbone for an application and contain the [business logic](https://en.wikipedia.org/wiki/Business_logic).
5
-* Create a sub package of `io.zipcoder.tc_spring_poll_application` named `domain`.
6
-
7
-
8
--
9
-# Part 1.1 - Create class `Option`
10
-* Create an `Option` class in the `domain` sub-package.
11
-* `Option` class signature is annotated with `@Entity`
12
-* `Option` has an `id` instance variable of type `Long`
13
-	* `id` should be `annotated` with
14
-		* `@Id`
15
-			* denotes primary key of this entity
16
-		* `@GeneratedValue`
17
-			* configures the way of increment of the specified `column(field)`
18
-		* `@Column(name = "OPTION_ID")`
19
-			* specifies mapped column for a persistent property or field
20
-
21
-* `Option` has a `value` instance variable of type `String`
22
-	* `value` should be `annotated` with
23
-		* `@Column(name = "OPTION_VALUE")`
24
-
25
-* Create a `getter` and `setter` for each of the respective instance variables.
26
-
27
-
28
--
29
-# Part 1.2 - Create class `Poll`
30
-* Create a `Poll` class in the `domain` sub-package.
31
-* `Poll` class signature is annotated with `@Entity`
32
-* `Poll` has an `id` instance variable of type `Long`
33
-	* `id` should be `annotated` with
34
-		* `@Id`
35
-		* `@GeneratedValue`
36
-		* `Column(name = "POLL_ID")`
37
-
38
-* `Poll` has a `question` instance variable of type `String`
39
-	* `question` should be `annotated` with
40
-		* `@Column(name = "QUESTION")`
41
-
42
-* `Poll` has an `options` instance variable of type `Set` of `Option`
43
-	* `options` should be `annotated` with
44
-		* `@OneToMany(cascade = CascadeType.ALL)`
45
-		* `@JoinColumn(name = "POLL_ID")`
46
-		* `@OrderBy`
47
-
48
-* Create a `getter` and `setter` for each of the respective instance variables.
49
-
50
-
51
-
52
--
53
-# Part 1.3 - Create class `Vote`
54
-* Create a `Vote` class in the `domain` sub-package.
55
-* `Vote` class signature is annotated with `@Entity`
56
-* `Vote` has an `id` instance variable of type `Long`
57
-	* `id` should be `annotated` with
58
-		* `@Id`
59
-		* `@GeneratedValue`
60
-		* `Column(name = "VOTE_ID")`
61
-
62
-* `Vote` has a `option` instance variable of type `Option`
63
-	* `option` should be `annotated` with
64
-		* `@ManyToOne`
65
-		* `@JoinColumn(name = "OPTION_ID")`
66
-
67
-* Create a `getter` and `setter` for each of the respective instance variables.
68
-
69
-
70
-
71
-
72
--
73
--
74
-# Part 2 - Repository Implementation
75
-* _Repositories_ or [Data Access Objects (DAO)](https://en.wikipedia.org/wiki/Data_access_object), provide an abstraction for interacting with _datastores_.
76
-* 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
-* It is customary to have one `Repository` per `domain` object.
78
-* Create a sub-package of `io.zipcoder.tc_spring_poll_application` named `repositories`.
79
-
80
-
81
--
82
-# Part 2.1 - Create interface `OptionRepository`
83
-* Create an `OptionRepository` interface in the `repositories` subpackage.
84
-* `OptionRepository` extends `CrudRepository<Option, Long>`
85
-
86
--
87
-# Part 2.2 - Create interface `PollRepository`
88
-* Create a `PollRepository` interface in the `repositories` subpackage.
89
-* `PollRepository` extends `CrudRepository<Poll, Long>`
90
-
91
--
92
-# Part 2.3 - Create interface `VoteRepository`
93
-* Create a `VoteRepository` interface in the `repositories` subpackage.
94
-* `VoteRepository` extends `CrudRepository<Vote, Long>`
95
-
96
-
97
-
98
-
99
-
100
-
101
 -
1
 -
102
--
103
-# Part 3 - Controller Implementation
104
-* _Controllers_ provides all of the necessary [endpoints](https://en.wikipedia.org/wiki/Web_API#Endpoints) to access and manipulate respective domain objects.
105
-	*  REST resources are identified using URI endpoints.
106
-* Create a sub package of `io.zipcoder.tc_spring_poll_application` named `controller`.
107
-
108
-
109
--
110
-# Part 3.1 - Create class `PollController`
111
-* Create a `PollController` class in the `controller` sub package.
112
-	* `PollController` signature should be `annotated` with `@RestController`
113
-
114
-* `PollController` has a `pollRepository` instance variable of type `PollRepository`
115
-	* `pollRepository` should be `annotated` with `@Inject`
116
-
117
--
118
-# Part 3.1.1 - Create `GET` request method
119
-* 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
-
121
-```java
122
-@RequestMapping(value="/polls", method= RequestMethod.GET)
123
-public ResponseEntity<Iterable<Poll>> getAllPolls() {
124
-    Iterable<Poll> allPolls = pollRepository.findAll();
125
-    return new ResponseEntity<>(allPolls, HttpStatus.OK);
126
-}
127
-```
128
-
129
-* The method above begins with reading all of the polls using the `PollRepository`.
130
-* We then create an instance of `ResponseEntity` and pass in `Poll` data and the `HttpStatus.OK` status value.
131
-* The `Poll` data becomes part of the response body and `OK` (code 200) becomes the response status code.
132
-
133
-
134
-
135
-
136
--
137
-# Part 3.1.2 - Testing via Postman
138
-* Ensure that the `start-class` tag in your `pom.xml` encapsulates `io.zipcoder.springdemo.QuickPollApplication`
139
-* Open a command line and navigate to the project's root directory and run this command:
140
-	* `mvn spring-boot:run`
141
-* Launch the [Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en) app in your Chrome browser and enter the URL `http://localhost:8080/polls` and hit Send.
142
-* Because we don’t have any polls created yet, this command should result in an empty collection.
143
-
144
-
145
-
146
-
147
--
148
-# Part 3.1.3 - Create `POST` request method
149
-* We accomplish the capability to add new polls to the `PollController` by implementing the `POST` verb functionality in a `createPoll` method:
150
-
151
-```java
152
-@RequestMapping(value="/polls", method=RequestMethod.POST)
153
-public ResponseEntity<?> createPoll(@RequestBody Poll poll) {
154
-        poll = pollRepository.save(poll);
155
-        return new ResponseEntity<>(null, HttpStatus.CREATED);
156
-}
157
-```
158
-
159
-* Take note that the method
160
-	* has a parameter of type `@RequestBody Poll poll`
161
-		* `@RequestBody` tells Spring that the entire request body needs to be converted to an instance of Poll
162
-	* delegates the `Poll` persistence to `PollRepository`’s save method
163
-		* `poll = pollRepository.save(poll);`
164
-
165
-
166
-
167
-
168
--
169
-# Part 3.1.4 - Modify `createPoll`
170
-* 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
-
172
-```java
173
-URI newPollUri = ServletUriComponentsBuilder
174
-	.fromCurrentRequest()
175
-	.path("/{id}")
176
-	.buildAndExpand(poll.getId())
177
-	.toUri();
178
-```
179
-
180
-* Modify the `createPoll` method so that it returns a `ResponseEntity` which takes an argument of a `new HttpHeaders()` whose _location_ has been _set_ to the above `newPollUri` via the `setLocation` method.
181
-
182
-
183
-
184
-
185
--
186
-# Part 3.1.5 - Create `GET` request method
187
-* The code snippet below enables us to access an individual poll.
188
-* The _value attribute_ in the `@RequestMapping` takes a URI template `/polls/{pollId}`.
189
-* The placeholder `{pollId}` along with `@PathVarible` annotation allows Spring to examine the request URI path and extract the `pollId` parameter value.
190
-* Inside the method, we use the `PollRepository`’s `findOne` finder method to read the poll and pass it as part of a `ResponseEntity`.
191
-
192
-```java
193
-@RequestMapping(value="/polls/{pollId}", method=RequestMethod.GET)
194
-public ResponseEntity<?> getPoll(@PathVariable Long pollId) {
195
-	Poll p = pollRepository.findOne(pollId);
196
-	return new ResponseEntity<> (p, HttpStatus.OK);
197
-}
198
-```
199
-
200
-
201
-
2
+# Pagination
3
+* To optimize performance, it is important to limit the amount of data returned, especially in the case of a mobile client.
4
+* REST services have the ability to give clients access large datasets in manageable chunks, by splitting the data into discrete pages or _paging data_. 
5
+* For this lab, we will approach this by implementing the _page number pagination pattern_.
202
 
6
 
203
 -
7
 -
204
-# Part 3.1.6 - Create `UPDATE` request method
205
-* The code snippet below enables us to update a poll.
206
-
207
-```java
208
-RequestMapping(value="/polls/{pollId}", method=RequestMethod.PUT)
209
-public ResponseEntity<?> updatePoll(@RequestBody Poll poll, @PathVariable Long pollId) {
210
-        // Save the entity
211
-        Poll p = pollRepository.save(poll);
212
-        return new ResponseEntity<>(HttpStatus.OK);
213
-}
214
-```
215
-
8
+### Get Data From Page 
216
 
9
 
10
+* For example, a client wanting a blog post in page 3 of a hypothetical blog service can use a `GET` method resembling the following:
11
+`http://blog.example.com/posts?page=3`
217
 
12
 
218
 -
13
 -
219
-# Part 3.1.7 - Create `DELETE` request method.
220
-
221
-* The code snippet below enables us to delete a poll.
222
-
223
-```java
224
-@RequestMapping(value="/polls/{pollId}", method=RequestMethod.DELETE)
225
-public ResponseEntity<?> deletePoll(@PathVariable Long pollId) {
226
-        pollRepository.delete(pollId);
227
-        return new ResponseEntity<>(HttpStatus.OK);
228
-}
229
-```
230
-
231
-
232
-
14
+### Limit Data Retrieved From Page
15
+* It is possible for the client to override the default page size by passing in a page-size parameter:
16
+`http://blog.example.com/posts?page=3&size=20`
233
 
17
 
234
 -
18
 -
235
-# Part 3.1.8 - Test
236
-* Restart the QuickPoll application.
237
-* Use Postman to execute a `PUT` to `http://localhost:8080/polls/1` whose request body is the `JSON` object below.
238
-* 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.
239
-
240
-```JSON
241
-{
242
-    "id": 1,
243
-        "question": "What's the best netflix original?",
244
-        "options": [
245
-	    { "id": 1, "value": "Black Mirror" },
246
-	    { "id": 2, "value": "Stranger Things" },
247
-	    { "id": 3, "value": "Orange is the New Black"},
248
-	    { "id": 4, "value": "The Get Down" }
249
-	]
250
-}
251
-```
252
-
19
+### Pagination Specific Information
20
+* Pagination-specific information includes
21
+	* total number of records
22
+	* total number of pages
23
+	* current page number
24
+	* page size
253
 
25
 
254
 -
26
 -
255
-# Part 3.2 - Create class `VoteController`
256
-* Following the principles used to create `PollController`, we implement the `VoteController` class.
257
-* Below is the code for the `VoteController` class along with the functionality to create a vote.
258
-* The `VoteController` uses an injected instance of `VoteRepository` to perform `CRUD` operations on Vote instances.
259
-
260
-```java
261
-@RestController
262
-public class VoteController {
263
-    @Inject
264
-    private VoteRepository voteRepository;
265
-
266
-    @RequestMapping(value = "/polls/{pollId}/votes", method = RequestMethod.POST)
267
-    public ResponseEntity<?> createVote(@PathVariable Long pollId, @RequestBody Vote
268
-            vote) {
269
-        vote = voteRepository.save(vote);
270
-        // Set the headers for the newly created resource
271
-        HttpHeaders responseHeaders = new HttpHeaders();
272
-        responseHeaders.setLocation(ServletUriComponentsBuilder.
273
-                fromCurrentRequest().path("/{id}").buildAndExpand(vote.getId()).toUri());
274
-        return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
275
-    }
276
-}
277
-```
278
-
279
-# Part 3.2.1 - Testing `VoteController`
280
-* To test the voting capabilities, `POST` a new Vote to the `/polls/1/votes` endpoint with the option object expressed in `JSON` below.
281
-* On successful request execution, you will see a Location response header with value http://localhost:8080/polls/1/votes/1.
27
+### Pagination Data
28
+* In the above scenario, one would expect a response body with pagination infromation closely resembling the `JSON` object below.
282
 
29
 
283
 ```JSON
30
 ```JSON
284
 {
31
 {
285
-    "option": { "id": 1, "value": "Black Mirror" }
286
-}
287
-```
288
-
289
-
290
-
291
-
292
--
293
-# Part 3.2.2 - Modify `VoteRepository`
294
-* The method `findAll` in the `VoteRepository` retrieves all votes in a Database rather than a given poll.
295
-* To ensure we can get votes for a given poll, we must add the code below to our `VoteRepository`.
296
-
297
-```java
298
-public interface VoteRepository extends CrudRepository<Vote, Long> {
299
-    @Query(value = "SELECT v.* " +
300
-            "FROM Option o, Vote v " +
301
-            "WHERE o.POLL_ID = ?1 " +
302
-            "AND v.OPTION_ID = o.OPTION_ID", nativeQuery = true)
303
-    public Iterable<Vote> findVotesByPoll(Long pollId);
32
+"data": [
33
+         ... Blog Data
34
+    ],
35
+    "totalPages": 9,
36
+    "currentPageNumber": 2,
37
+    "pageSize": 10,
38
+    "totalRecords": 90
304
 }
39
 }
305
 ```
40
 ```
306
-
307
-* The custom finder method `findVotesByPoll` takes the `ID` of the `Poll` as its parameter.
308
-* The `@Query` annotation on this method takes a native SQL query along with the `nativeQuery` flag set to `true`.
309
-* At runtime, Spring Data JPA replaces the `?1` placeholder with the passed-in `pollId` parameter value.
310
-
311
-
312
-
313
-
314
-
315
-
316
--
317
-# Part 3.2.3 - Modify `VoteController`
318
-* Create a `getAllVotes` method in the `VoteController`
319
-
320
-
321
-```java
322
-@RequestMapping(value="/polls/{pollId}/votes", method=RequestMethod.GET)
323
-public Iterable<Vote> getAllVotes(@PathVariable Long pollId) {
324
-        return voteRepository. findByPoll(pollId);
325
-}
326
-```
327
-
328
-
329
-
330
-
331
-
332
--
333
--
334
-# Part 4 - Data Transfer Object (DTO) Implementation
335
-* The final piece remaining for us is the implementation of the ComputeResult resource.
336
-* 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
337
-* Create a sub package of `java` named `dtos`
338
-
339
--
340
-# Part 4.1 - Create class `OptionCount`
341
-* The `OptionCount` DTO contains the `ID` of the option and a count of votes casted for that option.
342
-
343
-```java
344
-public class OptionCount {
345
-    private Long optionId;
346
-    private int count;
347
-
348
-    public Long getOptionId() {
349
-        return optionId;
350
-    }
351
-
352
-    public void setOptionId(Long optionId) {
353
-        this.optionId = optionId;
354
-    }
355
-
356
-    public int getCount() {
357
-        return count;
358
-    }
359
-
360
-    public void setCount(int count) {
361
-        this.count = count;
362
-    }
363
-}
364
-```
365
-
366
-# Part 4.2 - Create class `VoteResult`
367
-* The `VoteResult` DTO contains the total votes cast and a collection of `OptionCount` instances.
368
-
369
-```java
370
-import java.util.Collection;
371
-public class VoteResult {
372
-    private int totalVotes;
373
-    private Collection<OptionCount> results;
374
-
375
-    public int getTotalVotes() {
376
-        return totalVotes;
377
-    }
378
-
379
-    public void setTotalVotes(int totalVotes) {
380
-        this.totalVotes = totalVotes;
381
-    }
382
-
383
-    public Collection<OptionCount> getResults() {
384
-        return results;
385
-    }
386
-
387
-    public void setResults(Collection<OptionCount> results) {
388
-        this.results = results;
389
-    }
390
-}
391
-```
392
-
393
-
394
-# Part 4.3 - Create class `ComputeResultController`
395
-* Following the principles used in creating the `PollController` and `VoteController`, we create a new `ComputeResultController` class
396
-
397
-```java
398
-@RestController
399
-public class ComputeResultController {
400
-    @Inject
401
-    private VoteRepository voteRepository;
402
-
403
-    @RequestMapping(value = "/computeresult", method = RequestMethod.GET)
404
-    public ResponseEntity<?> computeResult(@RequestParam Long pollId) {
405
-        VoteResult voteResult = new VoteResult();
406
-        Iterable<Vote> allVotes = voteRepository.findVotesByPoll(pollId);
407
-
408
-        // Algorithm to count votes
409
-        return new ResponseEntity<VoteResult>(voteResult, HttpStatus.OK);
410
-    }
411
-```
412
-
413
-
414
-* We inject an instance of `VoteRepository` into the controller, which is used to retrieve votes for a given poll.
415
-* The `computeResult` method takes `pollId` as its parameter.
416
-* The `@RequestParam` annotation instructs Spring to retrieve the `pollId` value from a HTTP query parameter.
417
-* The computed results are sent to the client using a newly created instance of `ResponseEntity`.
418
-
419
-
420
-# Part 4.4 - Test via Postman
421
-* Start/restart the `QuickPoll` application.
422
-* Using the earlier Postman requests, create a poll and cast votes on its options.
423
-* 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
41
+* Read more about REST pagination in Spring by clicking [here](https://dzone.com/articles/rest-pagination-spring).
42
+
43
+
44
+-
45
+# Taking Action!
46
+
47
+0. Create a `src/main/resource/import.sql` file with [DML statements](http://lmgtfy.com/?q=DML+statement) for populating the database upon bootstrap. The `import.sql` should insert at least 10 polls, each with 3 or more options.
48
+	* Below is an example of `SQL` statements for creating a single poll with only one option.
49
+	
50
+		* Poll Creation
51
+		
52
+			```sql
53
+			insert into poll (poll_id, question) values (1, 'What is your favorite color?');
54
+			```
55
+		* Option Creation
56
+	
57
+			```sql
58
+			insert into option (option_id, option_value, poll_id) values (1, 'Red', 1);
59
+			``` 
60
+	
61
+0. Restart your application.
62
+* Ensure database is populated by `import.sql`.
63
+* Utilize Spring's built-in page number pagination support by researching the `PagingAndSortingRepository` class.
64
+* Ensure the `Controller` methods handle `Pageable` arguments.
65
+* Send a `GET` request to `http://localhost:8080/polls?page=0&size=2` via Postman.
66
+	* Ensure the response is a `JSON` object with pagination-specific information.