Browse Source

Update README.md

Git-Leon 7 years ago
parent
commit
0a882a9e62
1 changed files with 397 additions and 0 deletions
  1. 397
    0
      README.md

+ 397
- 0
README.md View File

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