 Hello developers, my name is Matt Rable and today I'd like to show you how to create a bootiful web application using Spring Boot and View. So this is based on a blog post that I published earlier this week called Bootiful Development with Spring Boot and View. So it goes through and shows you how to build a Beers API that has a list of beers and then it filters out the ones that aren't so great and only gives you a list of good beers. The GitHub repo for this is in the Octa Developer org at Spring Boot View example and if you look in the Octa branch you'll find a demo script that I wrote that basically shows everything that we'll be doing today. It's written in ASCII Dock but it renders just fine in Markdown. If you look at the raw version and you have the ASCII Dock third J plug-in installed then you'll be able to see a screen that's very similar to mine. So let's get started. We'll put this on the left and then we'll open up the terminal window and one thing I would like to tell you is that the brackets at the end of each step indicate IntelliJ Live Templates so IntelliJ Live Templates like Boot, Entity, Lombok will allow you to playback code that you've prerecorded basically. And so all of these live templates are in my GitHub repo at mrable slash idea live templates and you can import these into your copy of IntelliJ and then basically do everything that I'm going to show you today. So we'll start with an alias. Basically you'd go to start.spring.io in your browser but you can also use its REST API and I have an alias called bootiful start that will allow me to basically download an application that includes H2, Lombok, DataJPA, DataREST from SpringData and then Web which is just SpringMBC. So we can create a new directory called SpringView, go into that and then unzip the demo.zip we downloaded into a server directory and go into that server directory and open it up in IntelliJ. Now we can go to the demo application which is one of the main classes and you can create all the classes that I'm going to create in separate packages or it's in its own package but I'm choosing to do it just in the same package or the same file because it's a little bit easier to see everything then. I'm going to start by creating an entity using Lombok and we'll just call this beer and you'll see it uses the data annotation which adds getters and setters and two string to this class. NoArbs constructor, I could obviously just write that in one line as well down here choosing not to and then an ID and a name. We'll also create a repository of SpringDataRepository for it, call this beerRepository extends JPARepository and this repository rest resource will actually allow you to expose this repository as rest endpoints so that's great for demos maybe not so much in the real world but works nicely for what we're doing today and then I'll create a command line runner that puts a bunch of sample data into the database for us and then I'll add that sample data and this is from beeradvocate.com they say that these are some of the top six beers in the world based on user reviews and critics and things like that. So we've got some Kentucky Brunch brand stout and King Julius, Heddy Topper, Marshmallow Hanji a lot of those ones and then we have ones that are widely considered not so great and we'll go ahead and filter those out so just to show you what this looks like at the time being we'll go ahead and start our application. Okay so you can see that those beers were entered into our database and now we could actually look at them if we went to the slash beers endpoint but I want to create a good beers endpoint so we'll do that with boot controller you can see we have a beer controller there it uses our repository and we'll add a good beers endpoint that basically from that repository grabs everything streams it filters it through this is great method and sees if it is great and takes it out if it's not and then returns that to the user so we can restart and now if we go to the good beers endpoint you'll see it doesn't have Budweiser or PBR in there we could also just go to beers and hit that rest repository resource and it has a more restful nomenclature and JSON that's returned all right we can also hit it as a rest API so we can go ahead and use HTT PI 8080 beers and you'll see all those as well as good beers and you could also add a new one so you could do HTTP post a lot of good old Guinness because it's good for you even though I spelled it wrong and then you could update it using HTTP put and then you would specify the ID so this is ID 10 and we could change the name to spell it right there we are and then if we hit good beers we'll see that it's actually in there and then we can delete it as well so HTTP delete 8080 beers 10 now it's gone so you can see we have a full rest API at this point that's working and doing what we wanted it to do so the next step is to create a view app and I have view CLI installed for that so view create client client is the name of my application I'm going to manually select the features I'm going to use TypeScript because I like TypeScript progressive web app support and router and then I'll accept the defaults for everything else so class style component yes Babel yes history mode yep and TS lint and little lint on save and I'll put everything in its own configuration files and then I won't set this as a preset so I can always make this choice in the future okay so now open this up in IntelliJ and you might notice that it recommended that I CD into the client and run MPM run serve well I'm the kind of person that doesn't really like to run three commands but I don't mind running two so I like to type MPM start instead of three words so I'm going to go back to IntelliJ I'm going to open up package.json I'm going to make MPM start work so you can do that by just duplicating the serve command and putting start in there and start is one of those commands or scripts from MPM that allows you to run without two commands test is another one as well as build I think you have to run MPM run build so like now we can do MPM start and our app is running on 8081 so you can see this is the default welcome to your view plus type script app so the first thing we're going to want to do is modify home dot view to call our beers API or a good beers API so in here we'll create a created method this hooks into the view life cycle and it'll be called when this component is created you'll notice we need Axios so MPM I Axios to install it and then we can import it import Axios from Axios and we'll also create an interface for our beers or beer type and it has an ID of number has a name that's a string and it has a Giffy URL we'll go up to Giffy and get a fun image or an animated gift that matches the beer name and then we need a local variable to store the beers in so private beers that's a beer array and we'll just in this slides it to an empty array and then up here we'll take out hello world and we'll go ahead and add a list of our beers your list give it a title of beer list and you'll see it loops through the beers that are set and it just displays their names so for that to work right now you'll notice this actually calls a relative URL so it doesn't actually call 8080 it'll call 8081 good beers and we can use a proxy to proxy it to 8080 so to do that you can create a view config.js and so in this one we're actually specifying the port as 8081 the reason i'm doing that is because if you don't specify a port it defaults to 8080 and we're using spring boot for that but if we actually didn't start spring boot first then it would pick up that port and then spring boot would be blocked so i'm just going to hard code it to 8081 here and then i'm going to proxy that good beers endpoint or that call to 8080 so now i should be able to restart and we should be able to see that list of beers in our browser all right so that's all working the next step is to actually just move it into its own component so we can create a new component and i have a view plugin installed which only really you know creates this and what i'm going to do is i'm going to actually use the home template and just strip out everything that's relative to home so we'll take out this part we'll take out the logo and we'll keep everything else in there and then we'll go ahead and remove the hello world component because we don't need that delete it as an import and then we'll rename this to beer list and now we have our beer list standalone component and we can go back here and basically revert it to what it was in the beginning and then just add the beer list component here and we don't need that hello world and now everything should work just as before if i don't type z in there then you'll notice it has a few ts lint rules that makes it work like you want it to so now if we refresh everything still works right so we just move that into its own component and it's a little tighter and cleaner now so the next thing is to actually have our giffy component so create a new giffy component called giffy image and just to walk you through this code it starts with a class called giffy image and we have a name prop that's passed in from a parent component and then a giffy URL that we will set on each one and so when the component is created it calls the giffy API and this API key here is recommended for demos if you don't limit it to one it'll actually bring back 25 by default so that's a terrible performance thing if we're only going to show one so then we use axios to get that giffy API pass in the name of the beer and then we get the response here we check if there was any return because there might not have been any matches and if there is any then we just grab the first one and then if not we have a dancing cat so it's fun to see a dancing cat so there you are and then the template up here will actually take that giffy URL use it as an image source and put an alt tag on it as well so this be buying syntax actually you don't need it you can use it if you want but the colon is a shortcut for that and then down here I just have a scoped style that only pertains to these images so it just gives them a top margin of 10 so at this point we can go back to our beer list we can actually use this component and we'll specify the name equals beer dot name and then you'll notice it added it right here and view is a bit picky the view cli they like to have commas on the end of things now everything's working and you can see we're getting our images back so pentunky brunch brand stout marshmallow all those kind of funny and the next thing I'd like to show you is how to add pwa support so it's already had it built in because we actually went ahead and you know added it when we created the app so it's only enabled in production so you have to do an npm run build to see that in action and then you can use serve point to the disk directory where it was created and we'll run on port 8081 now we can go back to our client we can refresh and you'll notice what the like kind of confusing and it's very confusing that there's so many when you know we just have beers so what's happening here is it's actually failing to talk to good beers because we just have a relative url for that so we'll have to go back into our beer list and we'll have to make that into local host 8080 because when you're running it using serve it doesn't have that proxy configuration in its path basically so we'll also need to make cores work on the server so you can do that with cross origin annotation from spring and then you can specify the origins as local host 8081 then restart that then back to our client we'll have to rebuild and restart our server and now if we refresh everything should work as before nope not quite so this could be because it is a pwa and we need to clear it out of our browser the old version yep so now you see it's got the latest version and if you look in application and chrome developer tools you'll see the manifest with the information in there of the icons and how you might install this if you click add to home screen it'll actually prompt you and you could say like beers and it'll create an app in your chrome apps folder so that's pretty neat um you can also look at the service workers and you can see that um none of these boxes are checked if you're doing development and have a service worker enabled you might actually want to check update on reload or else it won't actually try to update it and you'll end up with stale data and i'm going to try this offline and see if that works this works like 50% of the time you'll see it almost worked it got the shell but it didn't actually get the api call so you might have to configure some things with pwa's in this register service worker to actually make it so it goes out and caches that good beers call but that's the service worker part um you can also see it with lighthouse test it with lighthouse you'll see we get a pretty good score there in 85 and the reason we don't do better is because down here we're not using htps and it doesn't redirect from htp to htps so if you deployed it to something like heroku or cloud foundry that could certainly work a lot better for you so if you go to our octa developer here and went to the github repo um there's actually scripts for cloud foundry that shows how it builds the client and the server and it basically goes through and replaces that localhost 8080 with whatever the server is deployed to same thing for the uh the core's origin goes and replaces that in the server as well so that's that's cloud foundry there's one for heroku too both of them work i've tested them and when you do that you usually get a hundred score for being a pwa i'd also like to show you that in the audits tab there's also lighthouse embedded in chrome so you can use this and look at the different throttling things and see how you do when you run it there now i'm going to show you how to add authentication with octa so this is going to use open id connect and so this should work with any open id connect provider so go to our server first and we'll go ahead and add dependencies to the maven palm file we'll add our octa spring boot starter and we'll add a dependency for springs alwath 2 support and we'll make it match with what version of spring boot we're using which is 211 and we'll import those and then in application properties i'll add my octa settings so it specifies the issuer and the client id so if i go to this tenant this is where i've actually set my own application up on octa if you go to developer dot octa dot com and click on sign up you can sign up and create your own as well but i can go to this url since i've already signed up and log in with one password because i don't know any of my passwords log in and then i could go to applications i could create a new application single page app go to next and call it like awesome view and i would change all these to 8081 and then click done now the next page you can copy that client id so we can go back to intelligent and we can put it right there and so i've already set it up i'm just going to use the one i already have configured but it's the same thing as the one i just created so now if we restart our spring boot api it should be protected and you should not be able to access it directly so if i go to local host 8080 you can see it prompts me to log in so the reason that happened is because i forgot one crucial step and that is to make it into a resource server so you can add an annotation here called enable resource server restart and then what spring boot will expect or spring security actually is that a access token will be passed in and that will be the authentication or the authorization for the user so now if we just go to 8080 you'll see that full authentication is required to access this resource now we'll go back to our client and we'll add view the octa view SDK so i have a shortcut for that it's just octa view and you'll notice that installs the octa view library as well as types library for the typescript stuff this might eventually be distributed with octa view so the second step that i have right here might not be needed in a month or so and so now i can open up the router and you can see what this router does is it uses a base URL and it has a home route and an about route that uses lazy loading so i'm just going to replace this with one that's authentication aware you'll notice this is a difference right here we're using the octa view plugin and we're specifying that same issue or a client ID and then a redirect uri to come back here as well as these scopes and then we have a link to our beer list and we tell it that it requires authentication and then we have this callback that uses octa view plugin and then before each specifies an author redirect guard so if it has requires author right here it'll redirect octa to log in and so now what we can do is we can take beer list out of home we can actually remove it from here and remove the import and now we can add a link in the beginning and we'll also make this class authentication aware so now it has still a link to home and about but if they're authenticated it shows them a link to the beer list and it also if they're authenticated shows them a logout button and they can click to log in with a login button and then in this class we're actually using auth which the octa view plugin will put on all view classes and then we can check if they're authenticated this annotation is very important this watches for a change in the route and it calls this is authenticated method and then when they click logout it goes ahead logs them out and resets that authenticated variable so now we should be able to restart the client and if we restart you notice we have a login button and it actually logged us in right and the reason that worked is because I already logged in to my octa tenant if I were to log out and do it again it would prompt me this time this is a chrome bug that I've seen for the last week basically after you've run lighthouse for some reason it kind of bleeds into things so now if we look at good beers you'll see there's actually an error down here about cores and the reason for that is spring security isn't quite aware of the cross origin annotation as far as I know and so you can create a cores filter as a workaround and then you can specify from you'll notice we also say that it can allow credentials it allows all methods all headers you might want to lock these down for your application but this is just a demo restart the spring boot api open this in an incognito window so we don't get the bleeding we do have to log in and you'll notice we actually tried to go directly to that beer list and it redirected us to octa puts up in our console so we're not getting that cores error but we actually aren't sending an access token either so on the client we need to go back into this beer list and we need to send that access token so you can see we specify headers and an authorization header or bearer and it passes in that access token so now if we refresh but we don't have to refresh everything's working as expected so another thing I wanted to show you is css grid so there's a cool feature where you can actually go and use css grid to lay out everything in columns and so you can do three columns you can do two columns there is a way to do autofill and make it more responsive so it adjusts to your browser window then you can wrap the beer components or the beer blocks with that grid and it'll lay them out in a nice grid format so you can see them all side by side there so this has been a screencast showing you how to get started with spring boot and view the github repo for this is on octa developer spring boot view example you can find me on twitter my handle is mrable you can also find me on linkedin there i am you can find me on rable designs which is my blog friends don't let friends write authentication and finally we have a youtube channel and we'd love you to subscribe to it thank you for listening and watching and i hope you have a wonderful day