Spring Boot Web App Tutorial (Java) | Full Course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody marcus here in this video course i'm going to show you how to build a full stack web application step by step so we're going to build a spring boot based application we're going to add a database and we're going to add a web ui using botton the application that we're gonna build is a crm application it'll feature a login page using spring security so that we can authenticate users it'll have a list view where we can list contacts in our system and edit and delete them you can also filter them like this it also has a dashboard view where you can see the stats of the contacts in our system and finally we're going to turn this into a pwa so that you can install this on your desktop or or device we're also going to walk through production deployment so how we can take this application uh change it to use a postgres database and deploy it to heroku so that we can share the link with anyone else now you can find the uh text version of this tutorial on vaden.com under docs and be sure to go to version 21 or later there are some subtle differences between 14 and 21 i'm gonna go through the 21 and later version here if you're on bottom 14 you can change the version here and follow the tutorial for that version i'll add a link to the text version of the tutorial and the source code in the description below if you have any kind of questions or problems you run into issues while you're working on the project please join us on the vauden discord i'll also add a link to that in the in the description below and there you can chat with the bottom community and and they can usually help you figure out what's what's not working in your project so with that out of the way let's create a new project and get going [Music] all right so the first thing we need to do is download a project starter for that either use the text version of the tutorial and go to the project setup chapter and click on download starter or i will also add a link in the show notes below this will download a zip file that you should extract then typically it's good to move that out of your download folder just so you have it so we're safe and you don't accidentally delete it the next thing we need to do is open that up in a id i'm going to use intellij throughout this tutorial but if you're more familiar with another id you can go ahead and use that instead so i'll open the project by navigating to the desktop selecting the folder and clicking open all right so we'll give this just a minute to load all the dependencies that it needs and then we'll take a look at what we have all right so let's open up the project and just take a peek at the pom file which is the maven project file so what we'll see is that we have a spring boot project using vaudin 21 in our case and if we look at the other dependencies that we have here you'll see that we have a h2 database so that give us an in memory database that we can use throughout the development cycle here we're gonna configure a postgres database uh when we go to production but for now we're gonna use just the memory h2 for easy development uh we also have spring boot jpa for accessing the database and we have spring boot dev tools so that we have live reload as we're coding then if we take a look at the code here in our java folder we'll see that we have an application class here which is the springboot application and this is what we can launch here to run the application so in intellij you can go ahead and click on the run button here you could right click on on the application itself and select run on this so you could select run here or then you could use the maven default command spring boot run in order to run it through the command line if you prefer to do that now while that's starting up we can take a look at the views that we have here so right now as we're starting we have a single view so we have a view that is mapped to an empty route extending vertical layout displaying an image an h2 so heading level two and a paragraph of text all being centered the first time you run the application it will take a couple of minutes because the van build tool will go ahead and download all the maven dependencies that are needed all the front-end dependencies that are needed through mpm and then it's going to build the front-end assets all of this happens once the first time you run the application so it'll take a while but fortunately it's not something you have to do every every single time you start the application so you can see the front end compilation is starting now this might take anywhere from a few seconds to a few minutes depending on your internet connection and your and your uh and your computer how fast it is and while that's going on we can kind of start sorting out our workspace so we have enough room here to to work with all right so we can see now we have the initial view here visible mapping to this uh list view here that we have now one thing to note when you start the application is that especially with intellij it will start performing and indexing and this will take quite a while on on some computers especially so this might take anywhere from from say 10-15 seconds to even a couple minutes while this indexing is going on uh your kind of experience will be a little bit limited in that it won't auto complete and things like that won't work so we'll wait for the indexing to finish then we'll make a small change to the application and make sure that the live reload works the way it's supposed to all right so the indexing is finished and let's just make sure live reload works so i'll remove all the code i had here i'll type add so i'm going to add something to the layout create a new h1 and type in the classic hello world grading here to get live reload to work i need to build the project so depending on your id it might be enough for you to save the file or in intellij you need to actually build it so it's either command or control f9 or press the hammer icon here will happen then this button will uh notice that something has changed and it will reload it and you can see that we have the application uh changes now visible here all right so before we start building anything let's take a quick look at what bond is and how it works close to download window here and go back to the documentation here under design system so one is a component based framework meaning that we have a whole big library of these ready to use building blocks that we can use anything from input fields to combo boxes date pickers number fields so on we can use all of these by initializing new components so for instance we could do a new button give it a caption like click me and we can then add this to the layout so well first of all we could extract this into a variable we could call it button and we can then when we're inside of a layout we can call add to actually display a component in this case we can display the button like this and what will happen then is that it will show up here in our in our view take a while to reload and once it reloads so you can see we have a button here now layouts are what determine how things get displayed so if we were to add another thing here so let's create a new text field here or capturing the name and we'll have this can be called name let's add name here to our to our layout and see how that works out all right so again we'll wait for the live reload to kick in and we'll see that we now have the name and the button on top of each other here they're on top of each other because they're inside of a vertical layout so if we wanted to instead have them next to each other we could instead create a new horizontal layout and add those to that instead so we could add those to a horizontal layout let's call this hl for now and we'll instead add that here to our main layout and again we'll wait for this to reload real quick here and you'll see that they're now next to each other obviously what you're also seeing is that they're not quite aligned the way you would hope them to be because they're both aligned to the top of this horizontal layout so what you can do then is define how things should be aligned here so you can set for instance the default vertical alignment to in our case baseline is a good alignment so aligning the baseline of the text of both components that will make it look kind of visually appealing all right so now we have the two components next to each other aligned properly the final part of kind of how one works is to add functionality by adding listeners so on our button we can add a click listener so whenever this button gets clicked we can decide what we want to do so here we could do for instance we could show a notification so we'll actually need to be careful to pull in the right notification so not the javax management one so we'll pull in the volume flow component here let's say show and what we'll say is then hello and we can get the name from the name field get value like that all right so now we've created some components we've laid them out using layouts and we've added some functionality by adding a listener for an event so let's save this and make sure that it works all right waiting for the reload to kick in and then i'll type in my name click the button and you can see we get a notification saying hello marcus so those are the basics of working with vadin everything is a component so we can create components by instantiating java classes we layout components by putting them into layouts like horizontal layout vertical layout and finally we add interaction by listening for user events and reacting to them all right so now that you know some of the basics of building a vauden application let's start building out the first view so we'll uh go back to the tutorial and go to the creating a view chapter here and what we're gonna focus on here in the first part of the tutorial is building out just this context list view so we're gonna get to the wrapping view here with the navigation bar and everything in in a little while but we'll just focus on building out this view here so we'll have a text field we'll have a button and we'll have a grid containing uh contacts and if you're following along uh it might be easier for you to just go and copy the code from here instead of trying to code along but i'll let you do whatever you feel is is better for you right so uh let's go into our app here and i'll close the sidebar just so we have more space for the code here i'll begin by just removing all of the code we have here and then we'll start working from the top down so page title is what's going to be the page title in the browser uh for this particular page it's going to be the contacts list so we're going to call this contact contacts and then we'll have a pipe and just say bought in crm which will be the application name the route annotation means that this view is mapped to the route uh the empty route so essentially to the context route all right so with that we're ready to start creating the components that we need and as you may remember we'll need a grid and a text field all right so the first thing we'll create is that grid so we'll have a grid uh that's going to hold contacts we'll call this grid and this will be a new grid and we'll pass in contact.class here as the parameter so the grid knows what kind of objects we'll be working with the other thing we need is a text field so we'll create a new text field we'll call this filter text so we know what we have in there and we initialize this to a new text field like that all right so then we get to the constructor and this is kind of where we bootstrap our view where we start creating things first thing i'll do and what i like to do when i'm creating new view is calling add class name and giving this a css class name just so if i end up writing css later on it's going to make things a whole lot easier so we'll call this list view all right then we're going to call set size full which will make this view the same size as the entire browser window because that way we can have that data grid reach all the way to the bottom by default a vertical layout would only be as tall as the components inside of it so that would leave some unused space at the bottom which is not what we want to do then i'm going to call a new method configure grid to actually split out the configuration of this grid and the way i like to do that is just type out the method name use the id to generate the actual method so what are the things we need to configure in this grid well first of all i also like to add a class name for this grid so i can style it later so we'll call it contact grid then i'm going to call set size full on this grid as well that way it's going to take up all the space that's available to it next we're going to configure the columns that we want to show so let's take a look at the contact class here and if you open up the sidebar here you'll see that the starter that we started with has a data directory here which contains our entity classes so we have contact which is what we're looking at here contains a first name a last name a company a status and an email the company contains a name and uh a list of employees belonging to that company and the status is simply a name so in this case the status of a contact might be something like uh closed lost or or closed one or similar to that all right so anyway in this case we have uh the fields first name last name company status and email so when we start configuring the grid here we can tell it which columns we want to be uh showing by default it would be showing all the grids just as they are but we want to configure them a little bit so i'll call grid and set columns and this will take in strings for the column name so i'll say first name last name and email i'll close that again now those are the primitive columns that we had in there but we had a couple of columns that contained objects and if we just call set columns like this those would be just printed as as whatever that object to string is and that might may or may not be what you want to do so what we can do instead of just uh setting the columns like this is define a custom column so we can call grid and we can call add column and what i will take in essentially is a lambda that takes in the contact and should return a string then that we want to display for that column so in this case we're going to do contact.getcompany.getname to get the company name and then we're going to call setheader company so that way we have a have a column showing the company uh by getting its name we'll do the same for the uh for the status so we'll call red dot add column and we have the contact we call contact contact dot get status dot get name and then we'll set the header to be status like this actually going to reorder these so we have the status before the before the company and the last thing i want to do for configuring the grid is making sure that all the columns get automatically resized to a proper width we can do that pretty easily by calling grid and calling get columns to get all the columns and then for each of those columns what we can do is call column dot set auto with to true like that so that way we have configured the grid uh columns that we want to show and then making sure that all of them will be properly sized to fit the content inside of them all right so that takes care of the grid and if you remember we're inside of a vertical layout which means that anything we add to this layout will be placed on top of each other so what we're going to do is we're going to call add and have two things one will be the toolbar with the filter field and the second one will be the grid for the filter field i'm going to again split this into a separate method just to kind of keep the keep the constructor nice and small and kind of easy to understand so we'll call get toolbar for getting that and then we'll pass in the greatest the second component first we need to again generate this method and this method should return the component that we want to return for the toolbar so for the toolbar let's first of all configure this text field that we have so we'll call filtertext.placeholder and the placeholder text we want to be shown there is filter by name then uh we're gonna set the clear button visibility to true so that way if there's something written in the text field somebody can just click on the clear button and clear all of that out we're also gonna optimize this a little bit by setting the value change mode to lazy so what this essentially means is that a little bit later in the tutorial when we start actually implementing the filtering we don't want to actually hit the database on every single keystroke we want to kind of wait for the for the user to stop typing for a little while so that we don't unnecessarily keep fetching everything from the database on every keystroke all right so that takes care of sorting out the uh filtering text field the other thing we need there is a button for adding new contacts so we'll create a new button and the text here will be just add contact and i'll extract this into a variable and the other variable can just be like add contact let's say add contact button like this and then because we want these two components to be next to each other we need a horizontal layout to wrap those so i will create a new horizontal layout pass in the filter text field and the add contact button i'll extract this into a toolbar variable and then i'll take the toolbar add a class name to this because i need it for css later so we'll call this toolbar and then finally we will return this one toolbar all right so if we look at what's happening now is that when a user navigates to the context root of the application this view will get initialized it's a vertical layout so everything inside of it will be displayed on top of each other we make the layout full size we configure the grid columns and then finally we add two components to the grid we get the toolbar component which has a horizontal layout with the text field and the button and then the grid is the second component here again let's uh build this and take a look at what we get in the browser to make sure that we're on the right track again we'll wait for the reload to finish and what we should see right now is that we have the filter toolbar up here and we have an empty grid here the way we'll approach this is that we'll create all the ui components we need for this view first and then we'll start looking at creating the backend implementation that we need for actually populating and updating and saving and all of that all right so the next thing we're going to do is create the editor for the individual contact so in the text version we're going to go to the next chapter and you can see that we're working on this part of the application right now so the form where you can see and edit contact details again if you're uh following the text version you can copy the entire code but i'll walk you through the implementation in the ide so what we're going to do is open up the sidebar here and navigate into the list view package here and we're going to create a new component we create a new component by creating a new java class and i'm going to call this contact form because it's a form for editing contacts and i'm going to add this to my get all right so contact form will extend not from vertical layout or horizontal layout but from form layout which is a layout in button that's suited for creating forms it will it will responsibly either have one or two columns depending on how wide your viewport is creating these own components is something that's very common when you're building bottom applications so you can build compositions of existing components and essentially create your own custom components that you can use in the application so in the case of our form what we'll do is we'll create input fields for all the properties of our contact and then we'll display them in this form layout and we'll add some buttons for things like saving deleting and closing right so i'll just start from the top create a text field for first name and this will be a new text field first name we'll create another text field for last name that'll be also a new text field last name then we'll create a email field field called email and that will map to a new email field so you can kind of see these field names map pretty much one to one to the underlying contact object and we're going to get to that in a in a moment so we'll give this a caption of email then what we'll need for the status and the company are essentially like these drop down selects for that i'm going to use a combo box and the combo box type will be a status for the status select and here again we want to make sure we get the right status so the one in our application and this will be a new combo box status and finally a combo box for the company it's equal to a new combo box for company like this all right um so like i kind of hinted earlier there's a reason why i named these exactly the way i did and that is if we look at the contact entity that we're binding to if these have the same names as our as our entity below we're going to be able to use the bottom binder later to tie those together automatically all right so now we have the the fields created here let's create a new constructor for the contact form so we'll generate a constructor and just the empty constructor right now we're not going to take in anything here essentially we're not going to pass in any of the the field values here what we do want to pass in or taking as as parameters here are the companies and statuses that we want to list in these so we'll add two parameters that we expect the user of this component to pass in so we'll have a list of company objects which will be the companies and then we'll have a list of statuses which will be the statuses all right and then we can start kind of configuring this form component so first of all i'm going to do the same thing as for everything so far i'll add a class name contact form then i will take the company combo box and i'm gonna call set items and i'm gonna pass in those companies that we got from the constructor so these ones because these are our objects i want to tell the combo box what property from there i want to show as the as the visible property so i'm going to call company dot set item label generator and use the company name getter for that we're going to do the exact same for statuses so set items passing the statuses then we're going to set the item generator to status get name like that all right and then we're gonna add all these components to the layout so we're gonna call add and we're gonna just start with the first name that's the last name email then we'll have the company drop down finally the status drop down and then we're gonna create a buttons layout for the save delete and close buttons so we're gonna split this out into a method of its own just to keep the the add method here nice and clean so we'll create a new method called create buttons layout and we will obviously need to implement this so we're going to create the method it will return a component all right so for the buttons layout we'll first of all need some buttons so we'll go up here and create some buttons so we'll have a save button which will be a new button with the caption save then we'll copy this and create two others so we'll have one for delete and one for cancel like this all right and once we have those we can go and configure them so for the save button what i want to do is call add theme variant and we're going to use the button variant primary for this which will make it stand out be clear that's the primary action that we expect people to do the delete button will add the theme variant error so again use the button variant and select the error one and then finally for the cancel button we're gonna add the theme variant tertiary like that okay then i'm gonna add some click shortcuts so people using the keyboard can use these more efficiently so for the save button we want to add the click shortcut enter and for the cancel button we want to add the shortcut escape like that then what we return from this will be a horizontal layout so we want them to be horizontally next to each other new horizontal layout and we'll pass in the save the delete and the cancel buttons like that all right so now we have a a form that contains input fields for all the properties of a contact and we have buttons for saving deleting and canceling now just having this form will of course not kind of make it show up in our application we need to go back to our list view here and add it to the layout so let's do that next all right so back in our list view let's create a field for the contact form so we'll create a new field here called form and then i'm going to add another configuration method here so call this configure figure form form implement this and in here i first of all need to initialize the form so the form will be equal to a new contact form and as you remember it takes in two lists now at this point we haven't connected to the backend yet so we don't have any actual lists of companies and statuses so what i'll do just in for a placeholder right now is use uh collections.emptylist to just pass into empty uh to emptylist collections.emptylist like this and we'll replace those with the actual lists in just a moment and then i'm going to give this form a width of 25 ems so that it has a width all right and what i want to change then instead instead of passing in the grid here directly we're going to create another kind of helper method for configuring this so we're going to instead of passing in the grid here we're going to create a new method called get content and in this method what i want to do is create a wrapper layout a horizontal layout that holds both the grid and the form next to each other so what i'll do here is i'll first of all create a new horizontal layout and pass in both the grid and the form and i'm going to call this content then i'm going to define how these two will kind of uh be spaced so by calling content that's set flex grow we can tell how they uh how the space should be allocated between these so i wanna say that the grid should get two uh thirds of the space and then the form should get one third of the space like this so two and one for the flex grow here also for for this uh layout i want to add a class name so i'm going to call add class name and say content will be be a good class name there and finally let's call set size pull on this so that the contents the right size and then start instead of null we're going to pass in the content here all right so again if we look at what we did we have a field here for the form we configure the form by instantiating a new form passing in to empty collections for now then we pass into the view two components the toolbar which we had from before and then a content which is a horizontal layout containing the grid and the form next to each other so if we go into the browser we can see right now that we have the grid we have the form here on the side and we have the toolbar on the top so we right now have all the ui components that we need for this view the next step for us will be to connect this to our database and display and work with some actual data so up until now we've taken a look at the contact entity that we have but let's take a look at some of the other stuff that we have from our starter so in addition to the actual jpa entity classes that we have here we have repository interfaces for each of those so with the help of these spring boot and spring data will give us the basic create read update and delete operations that we need all right so in addition to those we have a data generator that generates us some test data that we can work with so that way when we start accessing the database we already have some some context there to work with now in order to hook up to the database there are two different ways we could go about doing it we could either just use the repositories directly to access the database but in this case it's a better practice for us to create a service class that works as a middleman here running some business logic and kind of ensuring that we're not accessing the database directly from the ui layer so i'm going to create a new class here called crm service and this will be a spring service class so we'll annotate it with a service annotation and what we'll have here is first of all we'll need to have a constructor where we auto wire in all those repositories that we need so we'll have the contact repository then we'll have the company repository and finally we'll have the status repository like this then i'm going to use the id to bind these to fields all of them like that so that way we'll have access to all of these so this service class will essentially have all the apis that we'll use to connect to the database in our application so the first thing i want to implement here as our public api is a method to find context based on a filter text so let's create a new method here that returns a list of contacts and i'll call this find all contacts that match a string filter text like this and here let's check first of all if filter text is null or if the filter text is empty then we will return the contact repository find all so just return all of the contacts in our in our database else we're gonna do a research so we're gonna return the value we get from calling again the contact repository dot search and pass in the filter text now this is not something that exists yet so we need to go ahead and add this and here what i'll do is i'll use a jpql query now i'm slightly lazy i'm not going to type up the whole query so i'll go here to the to the text version and copy this over and then explain what's happening so what we do here essentially is that we name this uh search term here as a parameter and then we use it in a query where we select contacts where the first name or the last name matches that search term uh and we turn everything into lowercase so it's case insensitive all right so that takes care of the first piece of the api so we have one way of finding contacts so if we don't have a filter we return everything and if we have a filter text we use that query to filter them next thing will be pretty easy we'll have a public method again returning a long call count contacts and this will return contextrepository.count all right next one will be for deleting contacts so it can be a void method delete contact and this takes in the contact that we want to delete and what this will do then is again delegate to the contact repository to delete this contact like so then we'll do the same for saving context so we'll create again a method for save contact taking in a contact and what we'll do here is first of all let's just make sure that we actually got a contact in because sometimes if you mess up with the binder it's easy to pass in a null value here and we'll make our life easier if we check for that so let's uh print out to the system error log that contact is null so assuming as we actually have a contact we can delegate again to the context repository to save this contact like so good all right so that takes care of all the contact related ones that we need then let's create one for finding companies so again a public method that returns a list of company objects called find all companies and this will return the company repository.find all and finally we'll create a similar function for statuses so we'll create a method that returns a list of status objects find all statuses and delegate this again to the status repository find all method like that all right so now we have a service class here that takes in all these repositories in the constructor uh through autowire we have a way of finding contacts with a filter text content context deleting a saving contacts and then finding all the companies and statuses all right so now that we have this service here we can go back to our list view and start using it first thing we need to do is auto wire it so we have access to it in our view so we'll pass in the crm service here we can call this service and we'll create a field for this so we have access to it throughout the entire entire view then as the last thing here i will call a new method update list which we'll use to update the list of contacts so we'll create this method and what update list will do is it will call grid that's set items and the items we'll get from calling service dot find all contacts and then we need to pass in the filter value which we can get from the filter text field get value all right so whenever we call update list we'll go to the database and fetch all the contacts that match this filter that we have currently all right then we also need to hook up the filter text field uh to actually filter as we're typing so we go here into our toolbar we'll call filter text we'll add a value change listener and whenever that happens we call update list and as you remember we're using this lazy value change mode so it waits for the user to stop typing for a little while before it does that and then finally let's go here to the contact form and replace the companies and statuses with their actual content so we use the service to find all companies and then we'll use the service to find all statuses like this all right so let's hit build let's build the application and see if everything worked out so we'll go into our app here and what we can see now is that we have all the contacts here we should be able to filter them so let's start typing in the first name here and sure enough that filters them down we can clear the filter and that shows all of them what we should also see is the companies and the statuses that we passed in here the next thing we want to do is hook up the form so that when we select people in the grid the right person gets selected in the form and that we can edit them we're going to do this in two parts so first what we'll do is we'll hook up the data binding in the form so that we can both edit and validate the input and trigger events from this form and then once we have that done we'll hook up this form uh to the grid so that whenever we select a contact in the grid they'll get selected here on the side all right so let's begin by setting up the form here for that we're going to go back into the contact form class and create a binder so let's create a new binder here a binder is something the bottom uses for binding between a model object and ui components so in this case we're going to work with contacts and we'll call this binder and we'll initialize this to a new bean bean validation binder and this will similarly to the grid taking the contact class as a parameter now what a bean validation binder will do is it will use bean validation annotations on the class that we have to provide validation also in the ui so all of these not empty not null and like email validations will also get used in the ui so that way we don't have to write the same validations twice once in the ui and once in the back end all right so with the binder created we need to call it as well so here in the in the constructor i will add a call to binder dot bind instance fields and pass in this and this is where the naming comes in so as you remember we named the fields here exactly the same as the field names in the contact so that way the binder will take care of binding the first name property of the uh of the contact to the first name text field and so on all right so now that we have the binder taken care of let's add an api that we can use from from the view to set the currently selected contact so let's go and create a new method here and we'll call this public method set contact and this will take in a contact and what we'll do here is we'll save the contact to a field called contact and then we'll call the binder to read this contact bean so that means the binder will read this bean that we pass in and populate these ui fields based on it all right so now that we have a way of passing in a contact and a way of binding the values from that contact to the ui fields the next thing i want to do is define a couple of events that this form can fire and that way kind of inform the view when something has happened so especially we want a save event a delete event and a close event for this we're going to use one component events and if we go again into the text version here into the forms and validation chapter you can see that we have a bunch of events here that i'll copy over and then walk you through so we'll fix the imports here we need to take the button flow registration here i'll close the sidebar so we can see this whole thing so what we essentially do is first of all we create a base class for events that we emit from this form and we extend from the basic component event that vaden provides we add a field for storing the contact that we're working with so whether we're saving or deleting that contact we can save it here then we create specific events for saving deleting and closing passing in that contact to those events so that we can get hold of the content when we're listening to those events in the list view finally we have a add listener method here that takes in the event type and the listener and adds them to the vauden event bus all right so now we have most of the pieces that we need to make this form a fully functional component we have a way of passing in the contact a way of binding it to the ui fields the remaining piece of the puzzle is to hook up the save functionality and the delete and close buttons to actually fire the appropriate events so for that we're going to go into the button layout method here and we'll start just binding these so so we'll add a click listener on the save button and on the click event what we want to do is we want to call a new method called validate and save so there's a little bit more going on in the validation so i don't want to do it inside the lambda i'll just split it out into a into a separate method here so what i do here in validate and save is that first of all i'll try to call binder dot right bean and we'll write the value from the binder back to that contact that we saved in a field then we need to add a catch for the validation exception here for now i'm just going to print the stack trace in a real more kind of real life application we probably want to show some sort of visual notification to the user but assuming that we get past this we now have a valid saved contact and what we want to do is kind of call fire event and we want to create a new save event and this will take in two things so the source component which will be this and it will take in the contact which is the contact all right so now we have the save button hooked up to both validating and saving the value from binder to the contact and firing an event next let's do the same for the delete button so again add a click listener and here the event should just call fire event create a new delete event we pass in this and the contact then we do the close button or slightly the cancel button we add a click listener and here we call fire event new close event and we pass in this in this case it doesn't make any difference what what the contact is if we just want to uh close out of this all right so now we have a complete api for our form we have a way of setting a contact whenever we set the contact the binder reads that bean because it's bound here to the instance fields that means that it will populate all the ui fields with that and then we hooked up the buttons so that whenever we save or delete or cancel we fire an event so at this point we just want to build and make sure everything works there's no visual kind of changes to our application so far so what we need to do next is go to the list view and hook it up so that whenever we change the selected contact here or click add contact the right contact gets populated here and whenever we save or delete we actually want to do those save and delete options operations to the back end okay so let's jump into the into the list view again and see how we can manage the view state so by the view state i mean that when we select a contact we want to show that uh editor with the right contact when we close the form we want it to actually get hidden and when we either save or delete the contact we want those to be hooked up to the back end okay so first thing i want to do is start the view off in the right state so with that i mean that when we don't when we start the application we don't have a selected contact so we shouldn't be showing the form so we're going to call a new method called close editor and what close editor does is it holds the forms set contact with null then we'll call form.setvisible also we hide the form and then finally what we'll do is we'll remove a classname of editing that's something we'll add when we start editing and the reason for that is we'll add some responsive styling so that when we're editing on a narrow screen we can hide the grid and the toolbar to give all the space available just to the form all right so now that we start the application we navigate to this view we start off in the right state so we've closed the editor and we don't see the forum because we don't have anyone selected so the next thing we want to do then is handle somebody getting selected so for that let's go into the configure grid method here and then we'll add a listener so we'll take the grid as a single select so grid supports both multi and single select modes because we only want to select one component one contact we can use the as single select and add a value change listener here all right so when this happened what we want to do is we want to call again a new method edit contact and then we get the uh value from from the event like this and again we'll create the method here and we'll call this contact all right so what we need to do here is handle two different cases one is the the contact may be null so if somebody deselects a selected contact we need to close the editor so that we already have good and in other cases we need to do something about this so essentially we need to do more or less the opposite of what we did just a while ago so we call form that set contact we pass in the contact and then we set the visibility to true because we want it to be shown and then we add a class name of editing here so that we can use that for our responsive styling in in just a moment all right so now we have hopefully a way of selecting a person in the grid let's uh build this and see that that works so now we can see that when we start the app we don't see the form and when we select somebody in the in the grid we can see the right person getting shown here and if we click the same person again to unselect it hides them all right so next up let's hook up the add contact button here so for that we'll go into the get toolbar method here and we have the add contact button already created so we'll take that add a click listener and for that we want to call add contact and we want to create the method here what we want to do is we want to take the grid a single select again and clear it meaning that when we create a new contact we don't want a different content to be selected in the grid because that would be slightly confusing to the user and then once we've cleared the grid we can call edit contact and create a new contact object so start off with a clean slate all right so we'll save this again just make sure that we're on the right track everything is working the reload is is kicking off here so we we can still select people here and we can create a new contact by clicking the add contact here now i hinted towards making some responsive styles so right now if we're on a very narrow screen you can see that this isn't really an optimal use of space here we it would be better if we could just have the entire space available here for the form so for that we can add some css and again we're gonna cheat a little bit and go to the text version and copy those styles so we're gonna go here we're gonna copy these and we're gonna put them in the theme folder so we're gonna go into the frontend directory to the themes and select the style css here right now you can see it's only only pulling in some some icons and we'll add our own style here beneath that right so what the style does is that it adds four narrow viewports on the list view whenever the editing class name is present it will hide both the toolbar and the con contact grid so we'll uh go ahead and save this and then we'll go back to the application and and see if that got picked up and works so we'll uh refresh this and we'll see if this works so now that you now you can see that when we go on a narrow screen we can actually get the entire screen uh as real estate available for the form which is much nicer now of course we need to have a way of getting out of this and that's the next thing we're gonna do so we're going to hook up all these buttons to actually do something so again we'll go into list view and here we're going to go into the configure form method and we're going to add listeners on the forum for those custom events that we we created first event i'm going to hook up is the save event so we'll take the form we'll add a listener for the save event dot class and then we're going to hook it up to a new method on this called save contact and we'll uh create a new method for this it can be a private method void would save contact this takes in the save event i'll call this event and what we want to do here is then use the service to save the contact by getting it from the event like that once that's done we can call update list to make sure that all the updated data gets shown and then we'll call close editor like that all right so that takes care of saving next we'll take the form add a listener for the delete event and again we're going to take the class and then we'll create this dot delete contact and similarly we'll create a new private method for that taking in the delete delete event and what we want to do again is defer to the service to delete the contact so again we can get that from the event and then we want to call update list to make sure the list is up to date and then we want to close the editor like that then finally we want to add a listener for the close event and this one will be easier because we only need to call close editor like that so now we have those events hooked up here so that whenever we save or delete we defer to the defer to the service and close the editor whenever we do anything so let's try this out let's change a contact here click save we can see that that gets shown here we can delete that person and they disappear from there and finally we can try out the close here so if we click on cancel when we're editing especially on a narrow screen we can see that that hides the form as expected so up until now we've only been working on the list view the next thing that we're going to look at is adding a app layout that has this responsive drawer with navigation links and a header and that will allow us to then add a second view for a dashboard that shows stats over the context that we have so in order to add this main layout we're going to go into our java code again to the views package and i'm going to create a new java class here called main layout and main layout will extend from app layout which is a one class that implements that drawer layout in here i'm going to implement the constructor and essentially split out two helper methods one for creating the header and one for creating a drawer i'll call create header and create draw or like that and go ahead and create these methods like that and we'll start implementing them so for the header we're creating a new h1 so just a header level one that says bottom crm and we can extract this into a entire variable called logo and for logo i will add a couple of class names the ones i will add is text l and margin medium the class names here are part of the new utility classes in the vadin lumo design system so you can find all of these described here under the design system documentation if you if you want to use some of the other ones in your application later on all right so we have the logo we've adjusted the text size then and the margin and then what we'll do is create a new horizontal layout to hold on to everything that's going to go into that header so we'll create a new horizontal layout and we'll pass in a new drawer toggle which is something the app layout uses for toggling the drawer and then the logo and this will be the actual header itself then for the header we want to get set the default vertical component alignment to center to make sure everything's nicely aligned we want to call expend on the logo meaning that the logo should take up all the extra space in this layout we'll need that a little bit later on when we add added the log out button then we'll set the header width to full like that and then i'm going to add some utility class names to this one as well so i'm going to call add class names put the padding in the y axis to zero and the padding and the x-axis to medium with the header configured i'm going to call add to nav bar and pass in the header so this is perhaps a little unintuitive that the slot that we're using for the header is actually called the nav bar according to the to the app layout whereas the drawer is what we will use as our nav bar so the drawer then is where we have the links to the different views here we'll create a new router link which is something that we can use to to navigate to a view so we'll give it a caption list and this will navigate to list view dot class all right so that'll be the list view and for the list view we'll set the highlight condition to highlight conditions i like conditions dot same location the reason i'm setting this is that for the default path the empty path essentially that would match any path because every path starts with an empty path so this is something we we need to have here just so it doesn't stay highlighted uh because it thinks every every other view essentially in our application would be a sub sub view of this alright so once we have that we're gonna add to drawer and we're going to create a new vertical layout so we want the links to be vertically aligned on top of each other and we'll pass in the list view link here now that we have the highlight conditions here on on the links the other thing we need to do is define how we want to style those so go into the text version again copy some css here and we're gonna go into the front-end folder once again into the theme folder to the style css and add this style so any time a link has to highlight that tribute we're going to bold and underline it alright so with the main view now created we need to go into the list view and tell it to use this main layout so here where we have the route we need to add a layout parameter and set this to be main layout.class this way whenever this view gets loaded it will get loaded inside of main layout so let's build this and go into the application and see that what we have looks somewhat to be on the right track so you can see we now have the header here we have the drawer toggle that we can use to toggle this drawer and we have the link here and it's highlighted so it's bold and underlined so that looks good now that we have the main layout in place and we have a place to actually have have links to different views we're ready to add another view to our application so for that i'm going to go into the views package here my java source and create a new java class i'm going to call this dashboard view and dashboard view will extend from vertical layout the same as listview we're going to give this a route annotation where the value is equal to dashboard and the layout is equal to the same main layout.class we're also going to give this a page title this will be dashboard we'll have the same login crm all right so the dashboard view if we kind of look at what we're aiming to do will look something like this so we'll have the amount of contacts we have in our in our system and then a pie chart showing how those different contacts are split into different companies so here in our class let's create a new constructor first of all and here we will auto wire in the crm service we'll call it the service and save it into a field called service like this and then i'm gonna give this a class name the same list we've done for everything so far so add class name dash board view then i'm going to set the default component alignment to center so we want everything to be centered horizontally in this vertical layout and then we're going to call add and create two helpers again so one for get contact stats and one for get companies companies chart like that right so we'll go ahead and create these methods like that and let me just rearrange these so they're in the same order so we'll start with the easier one so get the context set so here we need to just show essentially a text with how many contacts we have in the system so for that we can use a span just a plain html span and here the number of contacts we can get from the service by getting count contacts and calling plus contacts to concatenate a string so this will be our stats essentially for sets we'll add some class names again to configure how it looks so we can use text extra-large and then i'll set the margin top to be medium so it doesn't quite touch the top there and then we'll return the stats here all right then for the companies chart we need to do a little bit more so for the chart itself we're going to use bottom charts which is part of the pro library so if you're doing this tutorial and you want to try it out there's a free 14-day day trial or if you're a student it's part of the free student package so you can get it from there as well so we're going to create a new chart and this will be of chart type pi and this chart will then need to get its data somewhere so for that we need a new data series and we're just gonna pull this out into variable and then what we need to do is call service find all the companies and then for each of them kind of pull out the stats so for each company what we can do here is call data series dot add create a new data series item and this takes in two things essentially the it'll be the company name and then the account of employees in the company so we'll take company dot get name and then company dot get employee count and that's something that doesn't exist yet that we need to create for that let's go to the text version here and copy a little bit and then i'll explain what's happening so we'll go into the into the company uh class that we have so in in data entity company we'll go here and we'll add this employee count now there are essentially like two ways we could have gone about getting the count of employees we could have actually fetched all the employees from the database and counted them but that's not very efficient because we only needed to know how many there are so instead we can use a formula to just count how many there are and have a getter that calls that so now we have uh added a series item where we get the name and the amount of employees in each company here and the final thing that we need to do then is we need to take the chart we need to get the configuration and we need to set this series to this data series that we have like this and then finally of course we need to return this chart so again if we look at the big picture here what happens is that we have a vertical layout that centers everything on the horizontal axis we add two components a span containing stats so just the total number of contacts in our system and then the other one being a chart which is a pie chart that pulls from the service all the companies and then uses the formula to get the employee count in each so let's save and build this and right now if we go to our application we should be able to go to dashboard and see it here so the dashboard view itself now works obviously we want to add it here to the main layout so let's finalize this dashboard view implementation by going into the main layout and then adding it here so for that we're just gonna inline it here we're gonna do a new router link to dashboard and that will navigate to dashboardview.class save and build go to the application see that we now have the dashboard view here it's highlighted because we're on the dashboard view we can go to the list view let's go here delete one contact go here verify that the number of contacts here has actually been updated which it has so that looks good we now have two views in our application and we can navigate between them up until now everyone could access everything in our application and that's not what we want to do so next let's secure the application with spring security and add a login screen so we're going to begin by creating the login screen so here in the views package we're going to create a new java class and we're going to call this login view and login view will extend from vertical layout the same way as other views that we've had so far so vertical layout and we're going to implement the before enter listener so that way we can hook on to the before enter event and we'll get back to that in in just a second so first of all let's add a couple of annotations here so first one being the route annotation we're going to map this to the login route and then we're going to give it a page title that will be login and then a pipe and bought in crm all right then what we're going to do is we're going to override the constructor and in the constructor we're going to start constructing the view for the actual login we're going to use a login view component so i'm going to instantiate it up here our private login form we can call this the login and that will be equal to a new login form then in the constructor we're going to add a class name login view we will set the size to full and then we'll align components both in the horizontal and vertical direction so we'll set the set the line items to center and then we'll also set justify content mode to center center so that everything's centered then we're going to configure the login action so where this login form should post to that will be the login path and then finally we'll add the components to the layout with add we'll create a new h1 with saying bought in crm so people know what they're logging into and then the login form all right and in the before enter listener here what we want to do is check if the url has a error query parameter and if so we're going to show that error so if the before enter event dot get location dot get query parameters that get parameters contains a key called error we know that we have an error that we should show so we'll take the login form and set the error to true like that okay so save and build and what should happen right now is that we should have the login view available but it's not enabled yet so there's nothing that forces us to go there but we can navigate there manually because we didn't use the parent layout you can see that we don't have the wrapping app layout here we just have the login form and that's exactly what we want okay so the next step will be to actually enable spring security for that we need to first install a dependency so we will go into the pom file and we need to install the spring boot starter security dependency so just going to copy this over and change validation to security like that then it's important to actually fetch the maven dependencies so go ahead and do that before continuing and once that is done we need to turn off the server and restart it because otherwise those won't get picked up so while that's happening we can start configuring spring security for that we're going to go into our application package here and we're going to create a new package we're going to create a new package called security and here we're going to create a class called security config where we can configure how spring security should work because right now you can see it's not using our login view it's using spring security's default login view which doesn't look as nice all right so how do we use this security config first of all we need to tell spring to enable web security and then we're gonna tell that this is the configuration that we want to use then we're gonna extend from bottom uh web security configure adapter quite a mouthful but that's the kind of naming convention that's used here so hide the sidebar so we have a little bit more space to work with here and we need to override a couple of methods here so so we're going to override configure for http security and we need to make sure that we call super.configure to let the vauden web security configure adapter do its thing and then we are going to set the login view to login view.class so that way we're going to use our our own login view and we actually need to pass in the http configuration object there as well right so that configures one thing the other thing we want to do is we want to exclude an image directory from spring security altogether we can do that by overwriting configure and here again we need to make sure that we call the super configure but let's first ignore a path so we will take the web configuration object call ignoring passing and matchers for slash images star star so anything under the image directory should be ignored by spring security and just served as it is and then finally let's configure a user for our system we can do that by defining the user detail service so user details service and here we're actually configuring a bean so let's add a bean annotation here as well and we're not going to use super here but we are instead going to use an in-memory details manager now this is not something that you would ever want to use in a production application but for this demo it's very good in the von documentation you can find examples of how to hook up to an ldap or another authentication provider for any actual application usage so for this though we're going to just create an in-memory user details manager we're going to create a new user with the builder so we're going to say with username user then we're going to give it the password since this is just a in memory demo we're not even going to bother with encrypting the password so we're going to say no up user pass as the password then we're going to give it some roles user in this case only single role and then finally call build so what we have right now is a con security configuration using the modern web security configure adapter setting the login view to our custom login view ignoring the image folder from web security and using a single user in memory with the username user and password user pass all right so let's save and build and go to the application and see what happens now that we're on the spring security based login page it's not going to have the live reload so i'm going to navigate to the app myself and what you can see happens immediately is i'm getting redirected to the login page here which is what we would expect because we've now secured the application so let's try to log in user user pass login and we got logged in but we can't access any views so the last thing we need to do here is actually grant permission to views that we want the user to be able to access so open the sidebar here and let's go into the views here so here i'm going to add a permit all annotation saying that all logged in users should be able to access this and similarly for the list view we're also going to add a permit all annotation like this so now if this reloads we should be able to access the list page and we are so still reloading there we go now we able to go between these two now we have a way of logging in the last thing kind of regarding security that i want to do is add a log out button up here so for that let's go back into the security package and create a new java class security service and in security service or well first of all let's remember to give this a component annotation so we can auto wire it and what i want to do here is do a public method for logging out so we call it log out and here two things that we need to do first will be to get the current ui get the page and set the location to the path so we want to navigate the user to the empty path after log out then we're going to create a new security context logout handler context logout handler like this pull it out into a variable we call it logout handler and finally we're going to call logouthandler.logout it takes in three things the request response and authentication but in this case we only need to pass in the request we can get that from the vaudin vadin serverlightrequest.getcurrent.hcp server request and let me hide that and then pass null values for the others because they don't matter for this okay so now that we have a service method that we can call to log out let's go into the main layout and add that to our to our header so here i'm gonna create a new button so new button log out and we'll have a click listener so whenever gets clicked we want to call the security service to log out so for that to work we actually need the security service so let's auto wire it in here security service let's call this security service create a field for it and then call securityservice.logout in the button all right then we're going to add this to our header here the well first first of all we actually need to pull this into a into a variable we'll call it log out and we're going to add it here all right so save and build and if everything goes well we should have a log out button which we have and when we click on it we get logged out and sent back to the login page and we're able to log back in so we've now successfully secured the application and only permit access to those who are logged in our application is now basically complete but there are still a couple of things i want to do the first one is configure how the application looks when we install it and when it goes offline and when we're done with that we're going to take a look at testing the application with unit tests integration tests and end-to-end tests okay but let's first take a look at configuring the application installation experience so every one application is a progressive web application by default meaning that people that supported browsers essentially most browsers these days will be able to get an enhanced experience where some things will be cached automatically in the browser for faster access and on many browsers they're able to actually install the application either on their desktop if they're on a computer or on their mobile device you can configure uh some pwa attributes here in the pwa annotation on the application class so i'm going to change the application name here to lot in crm and give it a short name of crm so this is the short name essentially what goes under the icon on say mobile device if the full name can't fit there okay the next thing i want to do is configure the logo and update that to match our application so for that again we're going to go to the text version here to the pwa chapter and download both this image and this image so that we have them so once we have the images let's go and put them in the right places in our application so the first one we need to put under meta in resources icons so that would be if we make this a little bit bigger so we go resources meta and resources icons so we're gonna drag the icon here and replace the one that's already there so we'll overwrite that and then the other thing is the offline icon or image sorry and we're going to put this in the images directory here so we'll move that there and that takes care of that okay so what i want to do next is configure how the application behaves when it goes offline so by default you've noticed when i sometimes when i refresh you see this dark page saying that the application is offline and uh you need to go online to use it but we can customize that page to kind of match our application and in in a real life situation that gives a better user experience to the to the user so we're going to have our own custom html file for that and it needs to be called offline.html in the same resources folder so we'll create a new file here offline.html and we're going to paste in the content that we copy from here so what we have is a plain html document with some styles pulling in this image that we just put in there and have has a custom text here and finally it has a script that listens for when the browser goes back on or detects being back online and that's going to reload the browser so hopefully that will get us back into the application all right so let's configure these in the pw annotation on the application so we have our let's put these on separate lines so it's easier to see them so we have the offline resources here we have the logo already made offline and what we're going to add here as as the other one will be images offline offline.png like that so that way we have that we can also define the offline path to be offline.html so that the custom html page that we have gets picked up right so let's save and build this and go to the application and we're going to wait for this to reload and what i want to do is just verify that these things got picked up so i'm going to open up the developer tools and i'm going to go into the application tab here and first thing i want to check is that the manifest got updated so i can see the custom icon here but for some reason this isn't updated yet so it seems like something is still kind of getting cached somewhere so one thing you might want to do is just go ahead and clear the site data once and refresh this to make sure that everything all the new stuff gets picked up now we can see we have the correct icons here and we should also be able to see that there are some things cached here for instance our offline page and we should also see our offline image here okay so now that we have those uh let's log in here user user pass what we can do as a user now is install this application so depending on the browser the installation experience will look a little bit different but on chrome it's up here in the nav bar it'll ask if we want to install the app we can go ahead and say yes we want to do that and what happens now is that you can see that my application is here with its own icon it's in its own window and now i can use it as a standalone application so that's pretty cool let's go ahead and check out the offline page so i will go and turn off the server and then let's go ahead and refresh here and see so now we can see that we're offline and we have a custom offline page for that so we've now turned the application into an installable pwa and we've customized the icon and the offline page all right so with the application completed let's take a look at writing some tests i'm going to close the standalone application here and just open it up in the browser once again so i'll just go to localhost 8080. we're still offline so we can also go ahead and start the application all right um so what we need first of all is a place for the tests to live so up until now we've only been working here in the source main java folder which is where our application sources live what we're going to add now is a separate test source route for tests so here in the source folder we're going to create a new directory called test and you can see intellij is actually already suggesting that we create a test java folder for maven so this will essentially be a parallel and identical structure to the one we have with the uh with the actual application source and here it's actually really important that we use the same exact package structure because we're going to rely on package access to some variables for testing so let's go ahead and create a package for the list view so i'm going to go here to package and create a com example application views list package so that will be exactly the same path to the test as it is to the list view here and in here we're going to create a unit test that tests the contact form now there's a little bit of setup here so i'm going to go again into the into the text version here and copy the boilerplate and then we can go through it together as you're copying these you can go ahead and just paste them straight on top of of the package and intel j or your id usually will take care of creating the class so what we have here is a test that has a before annotated method here for setup so before every test that we run we have a setup phase where we instantiate all these fields to known values that way we have a way of kind of validating if the right thing happened so what we have is a list of companies and statuses we have a contact we have two companies and two statuses that we want to check so we instantiate the companies we add two companies to it we instantiate the statuses with two statuses and then we create a contact where we set the status in the company okay so now that we have known values for all of these let's go ahead and create a first test here i'm going to create a public void method called form fields populated which will check that the correct form fields were were populated so for this we're going to create a new contact form and pass in the companies and the statuses just like we would when we instantiate it in the ui we're going to pull this into a variable we can call it form and then what we will do is we'll set the contact here to this known contact that we have mark usher okay so then what we want to do is we want to assert that the right values are visible in the ui field so for that we can use assertions and we're gonna assert equals and we're gonna first of all expect that the first name will be mark and we're gonna get the value from the form first name field by calling getvalue like this okay then second let's validate that the last name is correct so we'll change these to last name then we'll do email all right and next we'll do the company so we want to make sure that company 2 got selected so we'll get the company value and finally we'll validate that the status one so the ones that we selected here are selected all right and for this to become a runnable test we need to add a test annotation on it and you can see at least in intellij you know get this uh little help helper here where you can run it so you can go ahead and actually try to run this and hopefully if things went well we'll see that we get a little green check mark here saying that the form works the way we wanted it to work okay so now we have a test that validates that the right things get populated in the ui let's create another test that tests that we get the right values when we modify something and save it so for that let's create a new method again all right and we're going to annotate this with a test annotation as well so again let's create a new contact form pass in the companies and the statuses pull this into a variable called form and then let's create a new contact we'll call this contact and we set this empty contact to our form so we call form dot set to contact with this empty contact that we have and then we'll start populating the ui fields programmatically so we'll get the form get the first name field from there and then we'll set the value value of that to a known value so we can say something like john all right we'll do the same for the last name set the value to do then we'll do the email value john doe.com next we'll do the company and set the value to a known company in our case we can set the company one and finally we'll set a status to a known status so we can use status 2 just to mix things up a little bit all right and as you remember when we save something we actually get an event back so what we'll do is we'll create an atomic reference where we can capture that value that we get back from from the event so we'll do a atomic reference to a contact and we'll call this saved contact and we'll just instantiate the new atomic reference like this in this case we don't have a initial value all right then what we want to do is we want to add a listener on the form so we can capture that saved contact so we'll add a listener for the save event and the event then what it will do is it will take the saved contact and set the value to the contact that we get from the event like this so that way we're able to pull out the saved contact from there and that's exactly what we'll do so we'll have our contact we can call it saved and that will be equal to the save contact dot get so that way we now have a object here which has all the information of that saved contact and what we want to do then again using assert so that things are equal so we want to make sure that the john equals this the saved contact's first name do equals the last name john doe dot com equals the email then we'll do the same for the company in this case we'll use company 1 should equal to the company and finally the status i think we used status 2 should equal to the status like this all right so let's try this again we'll run this test and hopefully everything goes well okay so something did not pass let's take a look at what's going on here all right so cannot invoke uh get first name because saved is null all right that makes sense because i actually forgot a pretty important uh step here so we actually need to take the save button and actually click on it for that event to get triggered and for us to have a saved contact so let's save that let's rerun the test and sure enough it passes so now we've created two tests one making sure that when we pass in a contact the right fields in the ui will get populated the other one will start with an empty contact programmatically fill in the fields click on the save button and make sure that we get back what we expect now that we have a couple unit tests that test the form by itself let's create an integration test that tests the list view and making sure that the interaction between these two components that it comprises of actually works so create a new java class here and we're going to call this list view test and listview test will be slightly different because we're gonna use a runner here so we're gonna define run with and say that we're gonna use spring runner dot class so we're gonna use spring here so that we can use auto wiring and stuff that the view needs and we're also gonna add a spring boot test annotation here all right so with those in place we can now auto wire things here so we're gonna auto wire in the list view like this and then let's create a new test so for that a public void forum shown when contact selected so we want to make sure that the form is shown when the contact is selected and this will have a test annotation on it all right so you can see that this isn't working right now because there are no beans of type list view found so what we need to do to fix that is go here and add a component annotation and a prototype scope so add a scope proto type like that so that we always get a new version the reason we didn't need to have these uh earlier is that when we're navigating through bottom vinyl will make uh take care of actually uh making sure that everything gets auto wired but since we're not using wine right now we need to make sure that spring can find these on its own all right so we'll go back into our into our list view test and now you can see that the error is gone okay so what i want to do here is i want to find the first person in the grid select them and verify that the contact form shows that right person so for that we need a little bit of code here so first of all let's use the list view to get the grid and we can pull that into a variable and then we want to find the first contact so let's do a method a little helper for that so we can call get first item on grid and that's going to return the first item so we'll go ahead and create this method this will return a contact and take in the grid so the way we get the contact is by calling grid and getting the data provider that's kind of what's holding on to all those items and we're going to cast this into a list data provider of type contact like this and then we can call get items on this get the iterator and get the next contact from there and then we can return this so now we have a way of pulling in the first item from the grid all right and we will then pull this into a variable we're going to call this the first contact all right so now we know who is the first contact here then let's get the form so list view dot form pull that into a variable called form then we'll do some assertions so first we'll assert that the form is not visible so we can use insert again assert false and we want to assert that form dot is visible is true all right so so once we know the form is hidden by default we can take the grid a single select and set the value to the first contact so we essentially programmatically now select this first item then let's assert the form is visible and that we actually get the right person shown in the form so insert insert true form that is visible so the form should be visible then we'll insert equals that the first contact that we know we have that their first name is equal to the form first name field value like this okay so let's go ahead and run this and verify that everything works so one thing you notice here is that this is taking quite a bit longer than it did for the unit test that's because we now have to actually start up the spring di container so there's a little bit of a trade-off when you start doing this integration test where you need to involve spring but for the most part that's fine and it allows you to test the application integrations in a more realistic setting so we can see that this now works we've validated that the form is initially not shown when we select the first contact the form gets shown and the first name is valid so we can assume that the right person got shown there and we have the other unit tests that actually verify that the form itself works and then the final type of test that i want to write for this application is an end to end test so something that tests the application all the way from the browser to the database we can do that using the von testbench tool which again is part of the button pro tools so if you already started a trial with the charts the same trial will work for this as well so let's set this up by going into the test folder again and creating a new package under application called i t i t standing for integration tested the end to end tests are essentially a very wide type of integration test that tests the entire application there's a little bit of setup when we create a test bench test so let's go to the text version again and copy over this abstract test that we can use then to extend from so we'll paste this over our new package let's close some of these so we can see what we have here so the abstract test defines some constants here for the address and port and it takes in a route through its constructor then it turns off some logging in the apache http client so we don't get too much spam in the console and then it does some setup so before the class starts it starts a chrome driver and if something fails it grabs a screenshot and then the setup essentially gets the driver and opens up the url that we want to test so with that we can now start building our first test what i want to test is the login functionality so i should be able to log in with a valid username and i should be denied login with a invalid username so let's create a new java class for that call it login it the naming here is important because maven uses the it postfix to run these tests at the right build face so create the new login id and then we can start defining our test so first thing we need to do is extend from abstract test that we just created and it will require us to create the constructor we don't want to pass in a route but instead we're going to say that we're going to be testing the empty route so that takes care of the setup thanks to the abstract test now the next thing we want to do is create an actual test so we're going to create a public void login as valid user succeeds so this should validate that a login with a correct username and password succeeds annotate this with a test so it becomes runnable and the way this works is that we can use these element selectors to grab hold of references to ui components in the browser in this case i'm interested in getting the login form element and i want to get the first one that's visible on the page in our case it's the only one let's pull this into a variable form then let's set the values on the form so we'll call form dot get name field that's at value user then let's get the password field set the value to user pass and then finally we'll get the submit button and click on it and then what we want to assert is that we're no longer on the login page so what we can do here is insert assert false that a new newer element selector for the login form element that class exists so we want to make sure that it does not exist okay so let's save this and when we run these through the ide we want to make sure that the application is already up and running that way we can run these tests quicker because it doesn't need to start the application every time when you're running them through maven in the integration test phase it will start the server for you but that takes some extra time that we don't want to do while we're developing actively when we run these it's important that we run the entire class to make sure that those all those before class annotated setup things get run so we'll run the entire login it test here and then let's see what happens all right so something failed here um all right gonna take a wild guess that it's that this was made a protected method let's try to make it a public constructor just so it can get run properly let's run that again and yes okay so now it opens up chrome logs in and sure enough we get a green check mark here saying that everything went well all right so now we have one test that validates that you can log in successfully with the correct username to make sure somebody can't log in with an invalid password we could just copy paste this whole thing but something that you usually want to do is create these elements for your own views so that you can easily test different variations without having to copy paste too much code so i'm going to create a sub package here called elements and inside of it i'm going to create a login view element class what we're going to do here is define some attributes and we're going to say that the name here will be a class and it will contain login view so in our login view as you remember we added a css class login view and this will help us find it find the right one then we're gonna add an api here for a method for logging in so public uh boolean so we return whether or not that worked and login is the method name we'll take in two strings user name and string password then what we can do is essentially do what we did here earlier so let's copy this over move it here and instead of using these uh these hard-coded values we'll pass in the username pass in the password okay and the reason this is not working is that actually forgot to extend from a vertical layout element and when we make these uh elements it's really important that we have the same class structure so if you look at our login view you can see that it extends vertical layout and has this class name so we also extend from vertical layout and then we use the class name here to bind all right so now we pass in the username we're passing the password we click and then finally we're going to change the assertion so we're not going to do an assertion here instead we'll return the negation of a check of this login view element being visible so we'll do a login view element.class on page that exists all right so now we do the same and we validate that we no longer have the login view uh on the page we can go back to the test that we had here and we can simplify this so what we can do is we can do element selector for the login view element and get the first one of those pull that into a into a variable so login view and then we can assert that the login succeeds so we can assert the login view.log in with user and user pass works okay so let's validate that first of all continues to work so everything should work the exact same way as it did just a moment ago chrome starts up it logs in and the test passes so now we have a easier way to test that the opposite does not hold true so log in as as invalid user fails so we'll do the same but we type something else here and we assert that this would be pulse of course so now if we run this we should see two green check marks validating that this works all right and sure enough we have two green check marks so this is just a very quick introduction to bond testbench so you create a abstract test that you can use in as the base for just setting up all your tests and then you can create these elements for your views to kind of encapsulate some of the common things that you want to do to avoid having to repeat yourself too much and then finally you can just do normal junit assertations on on things that you expect to happen when you run the code now that we've created our application and tested it the last thing that remains to be done is to publish it somewhere where we can share the link to others before publishing the application we need to create a production build of the application we also don't want to use the in memory h2 database when we're running in production instead we want to use a postgres database so let's do a couple of changes to the code so that we can get ready for deployment first thing i want to do is go into the maven palm file here and go into the production profile so this is something that vaden uh maven plugin comes with that we can use to build a production uh ready application so it minifies some of the front-end assets it turns off unnecessary debugging and in general makes the application suitable for production so um i'm gonna do here is i'm gonna add some dependencies specifically for uh for postgres so that when we're running in when we're running in production we want to use postgres so we're going to use postgres sql from org postgresql like that then we need to go into our spring application properties and define some things here so i'm going to say spring jpa generate ddl is to true and i'm also going to say in this case spring jpa hibernate ddl auto to create drop so this will create and then destroy the schema at the end of the session now i want to warn you that don't do this with an actual application in a real life situation you don't want to create and drop the database every time you deploy but for our demo purposes that's perfect in a real life application you really want to use something like liquid base or flyway to handle your database migrations so that you don't lose data so keep that in mind all right so we now have everything that we need the next thing that we want to do is create a production optimized jar so i'm going to open up a terminal navigate to the desktop to the flow crm tutorial and then i'm gonna run the maven wrapper that comes with the project and i'm gonna run the clean and package package targets and use the production profile that we just configured and this will do a production build and the result of that will be a jar file that we can go and deploy now while that's doing its thing let's look at the deployment here in in the text version so we're going to deploy to heroku you can deploy modern apps on any cloud provider or pretty much any anything that runs a servlet but heroku is a really easy place to get started and it's free without requiring a credit card so it's a it's a nice place for us to deploy to what you need to do is create a heroku account and you need to follow the instructions for installing the cli all right so we now have the package built here and we can go ahead and start deploying it to heroku so the first step that you want to do is log into heroku with heroku login i've already done that so i don't need to do that once again the next step will be to run heroku plugins install java so plugins install java so enable java for this app all right then we're gonna create our application and we need to give it a name that's unique so let's call this button crm tutorial okay and then let's create a add-on to use postgres so roku add-ons create heroku post press ql and we need to pass in the app name which in our case is brought in crm tutorial all right that takes care of that so now we're ready to actually deploy this so we'll type in heroku deploy jar then we find our jar in the target so it'll be the crm tutorial snapshot jar then again we pass in the app name so bought in crm tutorial and then we wait for this to to complete it'll take a while when it sends over the application right you can see that we are now deployed to heroku at this address so we can go to our browser and navigate to the url the first time it starts it'll take a while for the app to actually boot up and one thing to note with heroku is that they do turn off their servers after a little while of inactivity and at least once at least once per day so this might not be the kind of perfect solution for a production deployment but it's really great for an easy way to get started so we have our app up and running so we'll type in user user pass login and sure enough here is our application running on the internet all right so there you have it we just built a full sec web application in java in just over two hours let me know what you thought of the course by reaching out to me on twitter and also help share the words so please share the video with any of your friends or co-workers who might benefit from it thanks for watching and i'll see you in the next one bye [Music] [Music] you
Info
Channel: vaadinofficial
Views: 883
Rating: 4.949367 out of 5
Keywords: Vaadin, vaadin tutorial, getting started with spring boot, introduction to spring boot, java, java spring boot, java tutorial, spring boot, spring boot example, spring boot for beginners, spring boot framework tutorial, spring boot full course, spring boot java, spring boot jpa, spring boot jpa tutorial for beginners, spring boot project, spring boot security, spring boot tutorial, spring boot tutorial for begineers, spring data jpa advanced, spring security tutorial, pwa
Id: bxy2JgqqKDU
Channel Id: undefined
Length: 127min 23sec (7643 seconds)
Published: Thu Sep 30 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.