Events7:57 with Craig Dennis
Let's automatically set the reviewer on the creation of new reviewers to the logged in users. We will use an annotated event handler to capture the BeforeCreateEvent.
So we have a nicety that we'd like to add to our API. 0:00 We want the creator of the review resource to be set 0:03 as the reviewer when it's created. 0:06 This idea of running certain code at certain times is pretty common request. 0:09 As you can imagine it's usually where the business logic lives and 0:12 since all the controller code is currently tucked away out of sight, 0:16 it might be a little confusing as to where we should add logic like this. 0:19 Well the good news is that this problem has been thought about and 0:23 it has been solved for you. 0:26 Probably, there are eight events that the spring data rest emits. 0:27 These are pretty self-explanatory and 0:31 knowing what you can hook into that will probably make you feel a lot more 0:33 comfortable about not having access to those controllers. 0:37 This is usually where you'd write any custom logic, right? 0:40 So we want to set the reviewer before things are created. 0:44 So we'll use the before create event. 0:47 Let's do this. 0:49 There are a few ways to register events. 0:51 If you wanna capture all entity creation you can write an application listener. 0:53 But in our example we're really only concerned with when reviews are created. 0:56 What we're going to do is write an annotated handler. 1:01 Which we can restrict to a review entity specifically. 1:04 So in our review package, let's make a new class named ReviewEventHandler. 1:07 New Java class ReviewEventHandler. 1:16 Okay and now we'll annotate that with RepositoryEventHandler. 1:24 And with that does is that takes a class and 1:34 it's whatever we're interested in watching which remember that's Review.class. 1:37 So the way that these work is you define what it is that you're 1:41 trying to do in a descriptive method, right. 1:44 So let's go ahead and let's say. 1:46 We're trying to do is we're trying to add the reviewer as it goes, right. 1:49 So let's say public void addReviewerBasedOnLoggedInUser. 1:51 It can be as descriptive as you want. 1:59 So we'll say review review and we want this to happen before, right? 2:01 So we're going to do handle before create. 2:09 So having these as separate methods is pretty nice because each of them are right 2:17 for unit testing right. 2:22 Okay so let's inject our user repository so we can get stuff out of it, so 2:24 we'll say private final UserRepository, 2:28 so users, and I'm gonna go ahead and allow this. 2:33 With this automatically add a constructor parameter and 2:39 then we'll mark our constructor here as auto wired. 2:43 And because we need to have this picked up by a component scan, 2:50 we need to mark it as a component. 2:53 And now let's work our magic. 2:56 So, to get the currently long in user you do this incantation. 2:58 So let's say get user name and that's from security ContextHolder 3:02 has a getContext, I'll go ahead and give us some space. 3:10 Has a getContext, and then it has a getAuthentication, 3:16 and then it has a getName. 3:22 Note that we're going to get a null pointer exception here if they aren't 3:26 authenticated. 3:28 But alas, they should be so we'll go grab our user. 3:29 So we'll say user user = users.findByUserName and 3:33 we'll pass in that username. 3:40 And finally, we'll just set it on the reviewer and 3:50 the review will say setReviewer[user] makes sense right? 3:54 Before things are created, okay? 3:59 I will go and reboot our server here. 4:00 Let's see, let's grab somebody over here to make a review for, 4:06 let's see, let's grab Seth Kroger. 4:12 He is an amazing moderator for us so let's write an appropriate one for him. 4:14 So we're going to make this a post and we're going to erase this one and 4:20 we're gonna go to the authorization we're gonna log in actually as Seth, 4:24 he's got the same password which is password. 4:27 Seth change that, say update request, okay. 4:30 And if we come over here to the body, this is actually a review. 4:33 So what we wanna do is we're gonna have him give us 4:39 a little bit of a harsh rating. 4:42 Let's say the rating. 4:43 Let's do the course first. 4:45 So "course" and now again we've moved this. 4:48 So it's "/api/v1 Courses one so 4:54 basics and we're going to give a rating of two. 4:59 That's pretty harsh stuff, which what, what's he upset about? 5:02 What is Seth upset about? 5:06 Let's see. 5:07 So for the description come here and 5:10 say why why did you use 5:17 system.io.console. 5:22 Well that's a lot isolation points so I have to calm down. 5:27 Do you know how many times I've had to answer 5:30 why this doesn't work in the clip. 5:36 I totally made that up, that's something Seth would never ever say. 5:41 He's one of those amazing moderators that makes everyone feel so 5:45 comfortable in the community and thanks for keeping something so positive and 5:48 being so patient that the students and I really appreciate it. 5:51 Okay let's see if this works. 5:54 So we have not set the reviewer, but Seth is logged in, and 5:56 we're going to click send. 6:00 Here we go. We got a bad request because, 6:02 why did we get bad request? 6:07 No suitable found to read the request body to object. 6:09 Do I have a weird header? 6:15 I did not set this. 6:19 I said it as text that something good to know, right. 6:21 So doesn't know it says and it says right here. 6:23 Can't do with the content type plaintext, right? 6:25 Let's switch this over to my application JSON and they set there. 6:27 Maybe that will be an answer for this one isn't better there in the video. 6:33 So that's maybe one you don't have to answer. 6:36 Boom, there it is and here comes Seth Kroger coming across. 6:39 So as you can imagine, we could do all sorts of other handling in these events, 6:43 including sending notifications, updating caches, some advance validation. 6:46 But whatever business logic you can dream up you can put in there. 6:51 Now one thing to always remember here though is that this action is synchronous 6:54 meaning that it's in the request response loop so users will be waiting for 6:58 this code here to execute. 7:02 So don't do anything too intense In here. 7:04 Awesome, right? 7:07 I know when I was first looking at the spring data rest project 7:08 I was not very trusting. 7:11 I was like, yeah sure I guess we do duplicate 7:13 a lot of code when we write APIs. 7:16 But where's all the business logic code? 7:17 Events are where you can inject that. 7:20 I've also found that these methods make unit testing your business logic 7:22 simple and quick. 7:25 Speaking of testing, it's outside the scope of this workshop. 7:27 But I do beg you to remember that you don't need to test what has 7:30 already been tested by framework creator. 7:33 Remember your boundaries. 7:36 Test only what is your responsibility and what could actually break. 7:37 I suggest you test your validation, your security, and 7:41 that your custom events are working as you intended. 7:43 But please don't go and test status codes and 7:47 error message that you haven't customized. 7:49 Find the right balance, and remember to not test what has been so 7:51 graciously abstracted away for you. 7:54
You need to sign up for Treehouse in order to download course files.Sign up