 Hello Java developers, my name is Matt Raebel. Today I'd like to show you how to build a beautiful crud app with Spring Boot and Angular. Let's giddy up. So this screencast is based off a blog post that I wrote called build a beautiful crud app with Spring Boot and Angular. And as part of that, if you scroll down to the bottom, you will see there's a GitHub repo. That GitHub repo is at Octadev, a zero Spring Boot Angular crud example. And in there, I have a demo dot adoc. So this is the script I will use to create this screencast. And if you'd like, you can use it as well to follow along. I wrote it an ASCII doctor. And I have a handy dandy ASCII doc plugin that makes it look nice and pretty. So in this demo, we'll build a full stack crud app with Spring Boot and Angular. And the final result will be an OAuth 2.0 secure app that you can distribute as a single artifact. And at the same time, I'll show you how you can use Angular's productive workflow of ng serve to continue using it even though you're going to package it all as one in the end. And some features that will implement is Angular material. So it looks beautiful. We'll allow you to edit nested objects. We'll implement the most secure OAuth form of code flow. And we'll do end to end testing with Cyprus. And I also have a GitHub action to show how it all works. So you will need a few prerequisites. I recommend using SDK man for Java. So let's just confirm that we have that installed Java dash version. We do have open JDK 17. We need node 18. And then HTTP IE. And also the OS Xero CLI. All right, looks like we're good to go there. Let's put this on the left here. And here's all the steps we will complete. We'll create a Java REST API with Spring Boot. We'll add a JPA domain model. We'll create an Angular app with the Angular CLI. We'll build a couple components, display the results from our API, and then secure it all with OpenID Connect and OAuth. And we'll configure Spring Security to do the maximum level of security. So let's implementing CSRF and updating Angular to handle that. And then also updating Angular's authentication mechanism to talk to Spring Boot so it knows when you're logged in and when you're not. And then we'll fix some unit tests. We'll configure Maven to patch everything together and verify everything works with Cyprus. So one of the things I did want to let you know is if you just want to get started and don't want to watch this whole video, you can just clone the repo and follow the instructions in the read me. And that will allow you to actually run everything in a matter of minutes. If you do want to follow along and do want to see, you know, how to create everything, I do use IntelliJ Live Templates. So if you go to MRABLE, IntelliJ Live Templates, or IDEA Live Templates here on GitHub, you can see all my various live templates and how to import them into your IntelliJ instance. Now, I did add these last week, so they should all be up to date. Let's get started. First, I'll clear this and I'll go into my downloads directory where nothing exists. And we'll start by creating a new Spring Boot Java REST API. So we're going to use Maven, we're going to give it a group of com octa developer, we're going to call it jug tours, and we're going to give it dependencies of JPA H2 web for Spring MVC and validation. So I'm going to use this command right here for HTTP IE or HTTP PI. And that will give us a jug tours project that has all those various components in it. So now we can open this up in IntelliJ and put that on the right. And then you'll see add a date JPA domain model is the first thing. So this will be under the jug tours package, which we already have created by start.spring.io. And there's two ways you can do this one, you could create the object, and then use my shortcut, or you could just copy and paste this code. So if you were to, you know, do this whole thing, copy and paste it, there's a cool feature of IntelliJ where we'll put this in a model package, you can just paste it, and it actually does everything for you. So that's pretty slick, right? That might be an easy way to do the tutorial. And also you could read the actual blog post and do it the same way, just copy the whole class, put it in here, you'll see, we've got a few things that didn't resolve, we need to create an event class and a user class to handle that. So now I'll resort to using my shortcuts, control in, there we go. New child class, we'll call it event. And I'll use my shortcuts here, which is spring boot angular event. You can see it spits out all that code, but it doesn't resolve the user, right? Because it doesn't exist yet. So we need to create that. And then once that's created, we can go back to our event here and shorten this up a bit, right? So we don't need the fully qualified package names since they're in the same package, and just replace all those. So now we have our entities for basically scheduling a jug tour. A jug tour is Java user group. That's jug. And it's a network of meetups throughout the world, where Java developers go to learn more about Java and new things in that space. So then we'll create a group repository here. And this is an interface, because spring data JPA allows us to just create an interface to do everything and it creates implementation for us. So this will be a group repository and SBA group repo. You see it extends from JPA repository. And why isn't like it always spelled it wrong. So rename that repository. There we go. And now everything compiles. And then we'll also need some data, because it's nice when you load up an app that you don't have to, you know, input the data. So let's just create some sample data. We'll do this in the jug tours package here. We'll call it initializer. The hardest part is spelling it. There it is. And we're going to put a bunch of jugs in the database Omaha jug Kansas City jug, Chicago Dallas Philly Garden State and New York. And then we're just going to save them. And then we're going to add an event to the Garden State jug as well. And then we can start this with MVN spring boot run. And of course, if you don't have Maven installed, you'll have to use the MVNW that ships with the Maven wrapper as part of the application. Once that start up, we can see the groups being created. And there's not much else. So we'll stop it for now. And we'll create a group controller, which will allow us to actually, you know, have that rest API that allows us to, you know, create read update and delete groups. So we'll start with creating a group controller in the web package. And this is a simple rest controller from spring MVC. You'll see it takes in a group repository there and it's constructor. And if you hit the groups endpoint, just as a find all, if you hit groups with an ID, it gets you that specific find by ID, you create one, it creates it call save. If you update it call save as well. The difference is one of them requires actually an ID in the URL as well as post versus put. And then you can delete one as well. And so now we can restart our app. We'll go back to our terminal here. And we could type HTTP. This is for HTTP API groups. And you'll see we're getting all those groups back. So that's working. We can always update a group or create a new one as well. So this is a HTTP post for the San Francisco jug. You'll see that was created. And then just to make sure it's got an ID of eight, right there. Let's make sure the get works for a specific one. All right, so that's working. And then we can do a put to update it to change the address. Now this doesn't do a patch. So it overwrites everything. And, you know, what I would recommend is you implement a patch so you can actually just update the address and not specify all the other things. So we're just doing a simple API. And then we can also delete it. So HTTP, well, let's clear this. So it's up there more. Delete. And now it deletes it. And if we were to, you know, get all our groups again, it would not be in. So our API is all working. Now we need to create the Angular app. So in the jug tours directory, do MPX, Angular, we'll go spell today, Angular 16, we're just going to call it app. And then we're going to have routing and CSS for these styles. And now you could do MPM install Angular CLI and install globally. What the MPX command allows us to do here is install different versions of Angular. So it allows it to just be, you know, to its specific directory instead of globally. So both ways will work. This is just the way I chose to use. So now if we CD into the app directory, we can install Angular material, ng add Angular material. And it prompts us if we want to proceed, say yes. And then I just selected the default. So if you want your app to look like the one I created, just select the defaults. And now we can start the app with MPM start. And if we open it up, this is just the default, you know, Angular app that you get. You'll notice it isn't using any Angular material components because we haven't modified anything yet. So we still need to do that. Put that back on the left. This one on the right. Back to our instructions. So the first thing we're going to do is modify the app components template and move the CSS. So you see at the top here, there's a whole bunch of CSS, we can clap set and just copy it all, then delete this up here, paste it here and remove the style tags. And now we can modify the template. This toolbar doesn't need to be changed, but let's modify this content and just put the router outlet in there. Now we can update the app component to display the list of groups that we created when the app starts up. So you'll see this as a title of jug tours, it's got a loading flag so we can know if it's loading, maybe if you're on a slow connection, you would want that. And then the groups that it retrieves. So we'll just use the HTTP client that comes with Angular. And when the component loads, we'll set loading to true, we'll go and grab those groups, and then we'll set the data there and set the loading to false. So before that's going to compile, we need an actual group.ts. So create this under the model directory, just say yes and add them all. And this just has an ID and a name for the group. And then we'll need to add HTTP client module here as an import. And then if we go back here, it doesn't like that model group for no good reason. So I'm just going to leave it. Now we need to modify the app component HTML to display the list of groups. And you'll see first of all, if loading is true, it'll display the loading one. And then it just uses an ng4 to list the groups. And so to make it so we can talk to API groups from the Angular app, we'll need to define a proxy.conf.js file. So create that in the source directory of the Angular app. And you can see any request to slash API will go to localhost 8080, which is the spring boot app. And then we'll need to update angular.json to use this. So search for the serve command. And then under development, add a proxy config. And then we should be able to restart it or start it if it's not started in the app directory. And you'll want your spring boot app or it looks like it is already started. So we'll just say no, everything. Oh, we do have to restart it because of the proxy config. So I think I have it running back here, I can cancel it there. And then start it here, ng serve or npm start, they both do the same thing. And load it up. And there we are, we're pulling our jug tours or that list of groups from our back end. All right. So now we're going to build an Angular group list component, because you don't want to really have everything in your main component, right? So you want to have different components to do different things. So we'll use the ng command to create or generate for gc for component and group dash list, and we'll make it a standalone because that's something new in Angular 15. And so instead of having to import everything in the app module, you can just have your components be standalone, which allows more reusability between applications. So now we can go into this group list here and replace that. And so if we look at this component, you'll see it imports a common module router link, map button, mat table, mat module, these are all from Angular material. I like it because it's Matt, right? My name's Matt. And then we have the group list here, we're using that loading again, we're displaying columns for our data grid from Angular material, we're using HTTP client where have a very similar, you know, method that goes and calls the groups when the component loads. And then it also allows you to delete groups. And once you delete them, it has a feedback system, it actually shows, you know, that you deleted it or that you saved it or whatnot. And then we'll need to update the Angular template here. And this is using material components for the most part, we have a nav bar at the top that kind of shows breadcrumbs. And then we have the ability to add a new group here, show loading if it's loading. And otherwise, we use ng template in this list, right, we have else list, if it's not loading. And that's where we show this data source of the groups. And we have different columns to find. So the ID, the name, and any events. And then we have for loop here to list events, if there's more than one, and then also the actions. So you can edit or delete in a group. And then these are the mat header row and mat row for displaying all those from Angular material. And now we can create a home component to display a welcome message and a link to the groups page. So we'll do that with ng gc home standalone again. And then we'll just update that home component to have hardly anything in it just a mat button, basically, primary href is groups, manage. Oh, it's given a warning there, what's it say, probably because we haven't imported it into this home component. We'll see. Change the app component to remove the list of groups. So here, right here, we just want that router outlet there. And then in the component itself, we'll remove all this fetching. Just have the title. And then we can remove this implements. And we don't need that group import anymore. But you notice that group import worked even the intelligence end up wouldn't. So don't always trust your ID, trust the command line. And then we can add a route to the home component and group list component to app routing. See, so we're importing those two. And then we're, you know, doing all that. And this might annoy you, it annoys me sometimes where it doesn't have the spaces in there. So this is just an intelligent setting where you can go to type script. I like my spaces, code style. I think it's at spaces, imports. There we are. And now if you reformat, it'll put those spaces in there around those brackets and the imports. All right. And now we can update the styles and style that CSS and app source and have rules for the breadcrumbs and alert classes. So you can see I got these from carry development us here. And so these are just the breadcrumbs. And then these are alerts that I might have borrowed some of that stuff from bootstrap. So as far as I could tell, Angular material doesn't have any alerts in there. So that's why I'm just using these. And then we can run MPM start here. It's not running back here. And if we click manage a jug tour, there you'll see everything's looking pretty good, right? Could almost say it's beautiful. I don't know about quite yet, but I like it looks a lot better than something without Angular material. So let's look at instructions here. Oh, this is one thing. You see how these actions don't quite squish to the right side? We can change it so they do in the group list component CSS. So scroll up to that. Do it here. Come back here and you'll see now they line up nicely on the right. So the next thing is we'll create a group edit component because all this is no fun if you can't like edit it and show that you can do the whole crud thing, right? So we'll create a group edit component, stop this, clear it and ng gc group edit standalone. And then we'll add a route and app routing. So this is just a path of group slash ID. And this is a placeholder for the ID, the colon there. And then the component is group edit component. It should import it. Yep, imports it up there. And then we'll place the code in the group edit component. And this needs an event model to actually compile. But we'll look at everything first. First of all, there's a whole bunch of material elements imported as well as the forms module for Angular forms. And then we just have a group object that we're going to edit. We have activated route router and HTTP client. And this ng on a net allows us to grab the parameters from the route and basically map it to that ID. And then if there is one, go ahead and grab the group. If it's new, then don't and set everything accordingly. And then to save it, it basically decides if you're doing a post or put based on if the ID is passed in, if there is one on the group. And then it goes ahead and does a poster put to that endpoint and then subscribes to the results. And the next thing is to show a success message. And then just have a simple time out that goes back to the list after you've added one. And then there's the ability to cancel if you didn't want to add anything, or you just want to go back to the list. And then the ability to add an event or move an event. So this is the nested form basically that it's cool because it's just a list. And you're just, you know, pushing and splicing, basically taking things away from it. So that works pretty well. And then we'll go in and create a new model object that event object. So you can see export class events got an idea date and a title. And then this is a way of allowing you to pass in partial objects and have all the things set. And then we can update the group to include that. So I did name this incorrectly. So let's refactor that. So it's lowercase. And then in group, we will import it because if we just did events event like this, there's actually a JavaScript object called event. So that's the one that thinks you're using. And we want to do import event. And then we can set it using this logic here basically saying if one's passed in use it. If there aren't any events passed in, then just set it to an empty array. Alright, so that's all compiling. And now the group at a component needs to render a form. So let's go ahead and where were we update group edit component. HTML. And this has those breadcrumbs at the top. And then here's the feedback message. And the form itself, you can see it's named edit form. And it's got an ng submit of save. And we've got this ID that we're basically showing. But most of the time it's read only. And then we have name. And we have the event. So this is where we're basically displaying all the events. And it allows you to create a new one. So this is, you know, indexed properties, basically, allowing us to just modify that event. And then there's a date picker there as well. And then the title and the information and then the ability to remove the event by just passing in the index. And then down here, we have the ability to add an event, which just pushes a new empty object onto their onto the list, and then save and cancel. And so the save button won't be enabled unless the form is valid. And now we can update the group edit component CSS to make the form look better on all devices. So this is just making it a little more squished, but not too wide. And then same thing for the alerts. And now we should be able to edit groups. So if we went to like oh my God, you can see that all works, we could add a two to it. And it's making that change on the back end. If we were to look at, you know, spring boot, you would see the request update, the Omaha jug. And then if we were to edit it and change it and save it, then that works as well. And if we were to add a new, you know, meet up, you know, Venkat's going to speak there maybe and topic is TBD. And you saved it. And that's all working as well. And you could go in there and delete it if you want it. And it's pretty slick how you can do nested forms. Fairly easy and JavaScript easier than I remember doing it with something like struts. And so now we can make the nav bar at the top use angular material colors. Since we do have, you know, this theme that we're using that doesn't quite match, you see that's kind of purple, that's kind of blue. You can do that with using the SBA toolbar shortcut that I have. And that's basically just replacing this toolbar with a math toolbar. You can see that component there, math toolbar. And then since this is not a standalone component, right, the app component, we'll need to import that math toolbar module into the app module. And we can reformat it. So we get those spaces around our imports. And then we can make some other adjustments just to really clean things up. So in the app component dot CSS, if you look for the toolbar rule that ships by default, there's a background color and a color, I'm going to delete those. And then for the Twitter logo, I'm going to change the margins a bit. And for the YouTube logo, just so they line up correctly. So do this here, just the value, and then change the content rule, search for content, and change the margin right here to 65 out of 32, 82 out of 32, and align items is stretch. So now you can see the toolbar is matched up with the buttons. And you know, things are stretching nicely for smaller screens or bigger screens. All right. So now what we'll do is we'll secure our Spring Boot app with OpenID Connect and OAuth. And it's really cool that this is so easy using the Octa Spring Boot starter. So Spring Security added OpenID Connect support way back in 2017. So it's been a while, right? Three, six years. It's awesome because you can use Spring Security to secure your app with any OAuth provider or identity provider. So in, first of all, in the Maven, pom.xml, you can add a new dependency here. And this is the Octa Spring Boot starter. The latest version is 3.0.4. And then we can use the OAuth.0 CLI to basically create an app on OAuth.0. So we'll start by running OAuth.0 login. And this is a form of OAuth called the device flow. We're going to authenticate as a user and then see it generates that device code there. And then I open up a browser and I confirm it. And now if I log in with my normal mechanism, which is GitHub, we're going to sign into GitHub using one password, like we got it right there. And then have mobile user security key instead. Got my UB key right here. And now the OAuth.0 CLI will allow me to do all these different things to my tenant, right? Create new clients, update roles, create roles, create users, all this kind of stuff. So it's a very handy tool. If you like the command line to manipulate everything in your OAuth.0 tenant, we'll go ahead and accept that. Now we're done. We're logged in, right? So we can close that window and squish this over on the left there. And the first thing we're going to want to do is take these things that got sent back to us. We haven't sent back yet because we still need to create this. So we'll clear that. And then we're going to run us zero apps create, we're going to call it bootable, angular, we're going to give it a description. It's going to be a regular web app. The callbacks are these here for both spring boot and for angular so we can have that productive workflow with angular. And then the logout URLs and the reveal secrets is just so we can see the client secret without having to run any other commands or log in anywhere. So once that's created, we'll create a octa.env file. So we'll go here and just do this in IntelliJ, right in the root directory dot octa.env. And we'll put these placeholders in there. And so we need our 0 domain. That's back here, right there. You want to have that trailing slash there that's going to be necessary, the client ID and the client secret. And so if you are on Windows, this part is important use set instead of export. So right here you would type set. And you would name the file dot octa.env dot bat and you would just run it. For this to work, I have to source the file on Mac or Linux. But on Windows, you'll just run it. So then important thing here is to add star.env to your get ignore in case you do check this project in because you don't want to check secrets into source control ever. And so then we can run the source octa.env. And now we can start it and we can use nvm like this. Oh, you get a schmawd plus x. And then we can run it. And then if we open up localhost 8080 in a browser, it'll redirect us to 0. We can use our credentials. And you might be like, hey, that didn't work. But actually it did work. This is the default slash mapping for spring boot. And that is there is one. It's a 404. So we have to do some work to resolve that. The first thing I want to do is basically make spring security angular friendly by creating a spring security configuration file and setting up CSRF. So in the config package, config, security configuration, you can see here, it's not importing everything. And a lot of times that's because if we went back here, it hasn't actually refreshed our Maven file. So you have to do like a reload from disk maybe over here, you have to do re import. And now it's working, right? So it's compiling all that. But this cookie CSRF filter is something we need to create. So that's in the web package there, you can see, let's copy the name so I don't type it wrong. And so this is because in spring security six, it doesn't set an XSRF token cookie by default. And so this solution is recommended by the spring project. And I'm just using it. So we're extending springs open, or once per request filter. And we're, you know, just grabbing that CSRF token from the request, and we're setting it as a header, and that will allow Angular to read it. So now we'll create a user controller to find out if the user is authenticated, as well as to perform global logout. And you might see this up here, that will allow you to load those Maven changes with the octa spring boot starter in there without worrying about, you know, trying to re import it. So this here is a user control it takes in a client registration, which allows you to get the endpoint to do logout, or the issuer to do logout. This is just a get user method that basically if the user is logged in, it'll return that user information from the ID token. And if they're not, it'll just return an empty string. And then down here in the logout, it's getting that issuer, it's getting the origin. And it's basically, you know, sending it to these endpoints. And eventually, also, we'll have an end session endpoint in our OADC metadata. But it's not there right now, you can contact support and get it turned on. But that's why we're doing things this way. And now when we add a new group, we want to tie it to the user. So create a new user repository. And in the group repository, we're going to want to modify the find all where we're going to want to add a new one. That's a list of groups. And we want to find all by user ID, so we can find out all of the groups for a particular user. And then in group controller, we're going to inject the user repository, do the constructor, create that, and we'll modify the groups method to filter by user. This is a collection here. So you can see it just finds all right now. We want to change it to inject that principle, get the name from the principle. And then down in the create group, we're going to want to grab the principle sub, which is what we're using for the ID, and set it on the group. So create group right here. And we want to pass in that authentication principle into the groups method to import that. Everything should be working. All right. We do need to import the user. And I don't know why it doesn't like that. We'll see when it compiles. Speaking of, let's go ahead and restart it. We'll see if it fails to compile. Maybe I just need to make it bigger so I can see it. Maybe just copy the thing since I don't see it. There we go. So don't know what I was doing wrong, but you probably did. So it all works now, right? Now we can start it up. And then I do have this section here on updating Angular to be CSRF aware. But the cool thing is it's already built in, you don't have to do anything. So Angular's HTTP client supports the client side half of CSRF protection. So it'll read the cookie or the header set by Spring Boot, and it'll send back an X access RF token header. And so all that communication will be secure. Now what we need to do is add an OS service into our Angular app. So it can communicate with Spring Boot to know if you're logged in or not. So we'll create an OS service in app. Just main directory here. And what this does is it takes in that model user, which doesn't exist yet. So we'll just copy this and create it here. user.ts. And then if we go back here, it's basically just got a constructor that takes an HTTP client and the location allows you to get the user. If it exists, then it basically, you know, not equal to null sets authentication state to true up here. That's a behavior subject that's listening. But this is the one that's used more. It's just, you know, using last value from this method. And if the user exists, return it, if not, don't. And then the login will allow you to basically redirect to the Spring Boot side of things to do all the OAuth dance. And then it uses cookies to keep that secure communication between Angular and Spring Boot. And then this is posting to that API logout endpoint that we created in user controller. And it just goes to that logout URL after everything succeeded. And then we can modify the home component to use our service, see if the user is logged in. So we have is authenticated as a flag now, and the user itself. And then when the component loads, we check if they're authenticated. And then we get the user information as well. And now we can modify home component to show the login button, if the user is not logged in. So we're saying if the user exists, you know, show this, if don't show this down here. So this is the login template that matches that, please log in, manage your jug tour. Otherwise, manage your jug tour says hello to the person and allows them to log out. And now we need to modify the proxy to have a couple more paths. One for OAuth 2, and one for login that Spring Boot will use both of these. So we don't want our Angular app actually intercepting those endpoints. And now we'll be able to restart our Angular or it is running over here. So because we modify those proxy pass, you will need to restart it. So let's do that running right here. So back to 4200 log in. And now we can manage our jug tour, right? And I can add a new one. For instance, Denver jug. And that save was successful. So that's all working. And it's secure, right? These are only my jugs, they aren't anyone else's. And so they are tied to my user. And you won't see it here. Because it doesn't have it when it first creates it, right? So you can modify that that group controller to print out the user if you want it to. And so now what I'd like to show you to do is how to package it all in the same artifact, because right now, you know, we're running this on 4200, everything's working nicely. But what about, you know, in production, it'd be nice if we just had a jar that we could distribute and have everything packaged in there. So you can do that with Maven pretty easily. Thanks to the front end Maven plugin. So if you go into your palm dot XML, we'll add a couple properties here for the front end Maven plugin version, node version and MPM version. So how the node and MPM versions work is it'll actually download and install it for you. So you don't even have to have node installed on your machine, which is pretty slick. And then we'll add the active profile setting to application properties under resources here. And this will be replaced at build time with the active profile. And then we still need to add the profiles to our palm dot XML. So down at the bottom here, there's a dev profile, it's activated by default, and it sets those spring profiles active as dev and that'll get put into that properties file by this Maven resources plugin. And this Maven resources plugin grabs the app dist app directory, which is where Angular compiles everything to. And then this front end Maven plugin uses that app directory installs node, doesn't MPM install, you can even run MPM test, and basically MPM built. So it has all that as part of the process. And we could run this and see our app running. So let's try that. We can stop the Angular one as well and exit out of there. Now it started up so we can go to local host 8080. And there we are, we have actually our Angular app and all that in there. We can log in. And it's all working. If we log out, then when we log in, it'll prompt us to log in. And now I'm logged in. But if you were to go to groups, you'll see it actually doesn't work in spring boot. And that's because the route is actually in Angular. So we do need to add a filter that'll route everything to Angular, except for obviously our API endpoints. So if we go here, we can add a spa web filter. This will be in the web directory here. And you'll see if the pass starts with API login or OAuth2, don't do anything. And if it contains a dot, do do something and request or no, the dot is again for like dot CSS.js, we don't want to forward those right to the index dot HTML, but we will forward everything else there. And then we can add this to our security configuration up here. You'll see we already have this add filter before for the cookie CRS filter. So add another one, do spa web filter, and then remove that semi colon, and everything will compile. And now if we restart, and we go to that groups endpoint, now it'll take us back. Now the loading thing, I think it's because we aren't logged in. So it's kind of a one thing that you would get if you were doing all the authentication on the front end, is you would have like guards that you could use to basically block someone from going to a particular, you know, page like groups, if they aren't logged in. And so you could create a similar guard and just use that all service to do all that logic, I just skip that stuff. So now we'll verify everything works with Cyprus. So in the app directory, run ng add Cyprus schematic, it'll prompt you to install 250. And then I just selected all the default. So would you like the default ng e to e command to use Cyprus? Yes, component testing, sure, I'm not going to use a component testing, but hey, it's in the project. And now we can upgrade some or update some of the files that created up here, we have Cyprus. The first one is going to be under Cyprus support commands. So there's just a bunch commented out here, we're going to add a new one. And so this is a login command that we're adding. And you can see it uses a side dot origin with our domain that allows it to do cross domain communication, and basically goes and puts in a username puts in a password and then presses enter. The reason it presses enter here instead of clicking on a submit button is on a zero login, there's some like hidden submit buttons. So this is just easier. And it's what people generally do, right, they hit enter, rather than clicking on a button. And then support dot e to e here, we need to add the ability to log in and out before each test. So this is importing those commands. And it's just basically has some logic here that says, hey, you have to set the e to e username and password, we're not hard coding anything, right? That's a bad idea to put hard coded credentials in our app. And we're just visiting the main page clicking login, and then we're using that command to send that username and password in, and then after we'll log out. So the first test is a home dot cy test. So this is under e to e here, we can delete this one, or we could just rename it, call it home dot cy. And this is just, you know, visiting the root. And then because we do log in with that e to e script, it will actually show a log out button instead of a log in button. So that's why I look for that. And then we'll create a groups cy dot ts. This will actually do all the credit and prove all that's working. What this does it first visits that groups endpoint, and the add button should exist. So it's just checking for the existence. And then it clicks it puts in a test group name, saves it, and verifies that the alert shows that it exists, or that doesn't verify what's in it, just that it exists. When you edit it, it clicks, you know, an a link, and verifies that value exists, and then cancels, and then deleting it, it goes into that group, deletes it, verifies the window confirm, and then verifies that. So now what we can do is add credentials for us zero account. So we can actually run these tests. And if you're setting it up on GitHub, you would do it on GitHub, not here. So what we'll do is we'll go ahead and just copy these things into our octa dot env here. So our us zero domain, we can get from up here. It's just the raw value. And then my email, my password from one password. And unfortunately, you do have to put it in the raw. So I will change it shortly after this. And then we do have spring boot running over here. So we want to source that obviously, you don't need those Cypress values for the server side of things. But you will need it for the front end. So we can do source here, right dot dot, that's where it is. And then we can run mpx Cypress run browser is electron, just built right and then config base URL is different, right, because we actually set it up by default to use 4200 or the schematic did, but we want to use local host 8080. And you'll see it does actually create a video there. So there's a Cypress config file that you can turn it off because you don't always need videos. Right. A lot of times it's just a lot of extra. So in here, you can do video false. And you can see all the tests pass. So that's pretty slick. We do want to fix some unit tests. So if you were to run npm test here, it would actually a lot of them would fail because we've added angular material, we've imported angular material into those components and the generated tests that were originally created didn't have angular material in there. So you'll see we're getting some failures here app component, right? The map toolbar is not a known element. So put this just on the left there. And then we'll start looking into those component specs. So we'll need to import the map toolbar module. And if we save, you'll see that one goes away. Group list component doesn't have the HTTP client in there. So group list component spec needs a HTTP client testing module. And we save that group edit component is now complaining. So go into that spec. And we need a router testing module here for that activated route. We're getting closer. Group edit component also needs HTTP client. So HTTP client testing module. Now the home component needs HTTP client. And then the app component should have a title as app. So this is down here. We change it to jug tours, right? So jug tours. And then the group list component needs that router testing module. And then the app component down here is looking for app is running. So this is a map toolbar. And it's the first span, I believe. And then should be chug tours. And now all of our MPM tests are passing. So that's pretty slick. Well, what about the Java side of things, right? If we want MVM tests, all those tests pass. Oh, we've got to be in the right directory. And the answer is yes, there's only one test in here. And it's right down jug tours application test. So you can see there's not much in here. It's just verifying with the context loads. But if we were to exit and create a new shell, stop that one, open up a new terminal here, and do MVM test, it will not work. And that's because the environment variables were set before. So when it tried to load up, you know, the octa settings, it all worked. But now they aren't there. So it gives these errors about it failed to load the context because it basically couldn't find a issuer or the information for doing a lot. And so the way to fix that is to create a test security configuration that can be that's just mocking the IDP for your tests. And you'll see what this does is it has a client registration, client registration repository is just an in memory one. And then it uses example.org, it sets up the end session endpoints, the issuer, you are the redirects, all the different endpoints, mocks out the JWD decoder. And then you can modify this to actually import it. So in addition to the jug tours application, we want that test security config. Get it right. Nope. There we go. And now if we run it again, everything will pass. Very neat, huh? I love it. So last thing is to create a GitHub action to build and test your app. So if we go here, we can create a new directory and file called GitHub workflows main dot yml. And how this works is it basically checks out your project. So you would obviously check this in the GitHub, and then have this action enabled, you would have to enable actions usually enabled by default uses Java 17. It runs that mvn verify to run all the maven tests. And then it runs the e2e test. The cool thing about mvn verify better to run it here is that is actually going to run npm test as well. So that's one of the things we did with that front end maven plugin is set it up. So it would run those front end tests up here as well. I think it did. Oh, you got to do it with dot pprot. That's why it's here in the action there and NTP stands for basically don't show the downloads that maven does. So you can see up here it actually ran those npm tests as well, those Angular tests. So that's pretty slick. And then once you check your application in, you will need to configure GitHub's repository secrets. So it populates all of these things down here, we're going to use those octa or two issue or client ID and client secret to start the spring boot app. And then we need these Cypress ones right to run the tests. And then this is a pretty cool feature where you can upload the screenshots of the failures and kind of see what's wrong at the end of that. So I already have obviously what we use to build this project, right, this repo here. And if we were to go and look at it under settings, down to secrets and variables actions, you can see I already put all those secrets in here, you know, I updated it a while ago, but they're all still working. They're running every night. This audience actually isn't needed. I originally thought it might be but it's not because we aren't sending anything from the client with an access token. So that's how you set all that up. And so I invite you to build something fabulous with spring boot and Angular. Hope you enjoyed this demo, you know, using OpenID connects a recommended practice and a lot of people actually do the authentication on the client. I like doing it on the server and using good old fashioned session cookies, people that say session cookies can't scale. We'll guess what all the fangs use on Facebook, Apple, Netflix, Google, they're using session cookies, they work just fine for them. So you can find the source code on GitHub here. You can also read the blog post. And also, if you like spring boot and Angular, you might love the info queue books that I've recently published new versions of. There's the Jay Hipster mini book, which shows you how to use Jay Hipster to create a spring boot back in an angular front end to build a 21 points health application. And then the angular mini book is one that will be published the 3.0 version in the very new future. Unfortunately, I started that before Angular 16 was out. So it uses Angular 15 spring boot three, but it uses Kotlin for the back end. So it's a little different and uses Gradle to do everything. So if you want to use those instead, go ahead and download both of those are for free from info queue. So the Jay Hipster mini book, right there, Jay Hipster mini book, Angular mini book is there as well. And you can see I sent them in the files last week for 3.0, but obviously hasn't been updated yet. So if you like this video, follow me on Twitter. I'm at MRABLE. I'm also on LinkedIn at MRABLE as well. And follow my team at Octadev on Twitter. And finally, subscribe to our YouTube channel where we publish cool tutorials like this one, as well as a lot of leading information on identity and access management. I hope you have a great day. Cheers.