2. The Spring Boot Application

Our demo web application's functionality will be pretty simplistic indeed. It will be just narrowed to fetching and displaying a List of JPA entities from an in-memory H2 database, and persisting new ones through a plain HTML form.

This step isn't always necessary. Since we are deploying our Angular frontend to http://localhost:4200 and our Boot backend to http://localhost:8080, the browser would otherwise deny requests from one to the other.

Regarding the controller methods, getUser() fetches all the User entities from the database. Similarly, the addUser() method persists a new entity in the database, which is passed in the request body.

To keep things simple, we deliberately left out of the controller implementation triggering Spring Boot validation before persisting an entity. In production, however, we just can't trust user input, so server-side validation should be a mandatory feature.

2.5. Bootstrapping the Spring Boot Application

Finally, let's create a standard Spring Boot bootstrapping class and populate the database with a few User entities:

For obvious reasons, we'll not dive deep into learning TypeScript. Even so, let's notice that the file defines an AppComponent class, which declares a field title of type string (lower-cased). Definitively, it's typed JavaScript.

Additionally, the constructor initializes the field with a string value, which is pretty similar to what we do in Java.

The most relevant part is the @Component metadata marker or decorator, which defines three elements:

selector – the HTML selector used to bind the component to the HTML template file

templateUrl – the HTML template file associated with the component

styleUrls – one or more CSS files associated with the component

As expected, we can use the app.component.html and app.component.css files to define the HTML template and the CSS styles of the root component.

Finally, the selector element binds the whole component to the <app-root> selector included in the index.html file.

3.5. The app.component.html File

Since the app.component.html file allows us to define the root component's HTML template — the AppComponent class — we'll use it for creating a basic navigation bar with two buttons.

If we click the first button, Angular will display a table containing the list of User entities stored in the database. Similarly, if we click the second one, it will render an HTML form, which we can use for adding new entities to the database:

The bulk of the file is standard HTML, with a few caveats worth noting.

The first one is the {{ title }} expression. The double curly braces {{ variable-name }} is the placeholder that Angular uses for performing variable interpolation.

Let's keep in mind that the AppComponent class initialized the title field with the value Spring Boot – Angular Application. Thus, Angular will display the value of this field in the template. Likewise, changing the value in the constructor will be reflected in the template.

The second thing to note is the routerLink attribute.

Angular uses this attribute for routing requests through its routing module (more on this later). For now, it's sufficient to know that the module will dispatch a request to the /users path to a specific component and a request to /adduser to another component.

In each case, the HTML template associated with the matching component will be rendered within the <router-outlet></router-outlet> placeholder.

3.6. The User Class

Since our Angular application will fetch from and persist User entities in the database, let's implement a simple domain model with TypeScript.

Let's open a terminal console and create a model directory:

ng generate class user

Angular CLI will generate an empty User class. Let's populate it with a few fields:

export class User {
id: string;
name: string;
email: string;
}

3.7. The UserService Service

With our client-side domain User class already set, let's now implement a service class that performs GET and POST requests to the http://localhost:8080/users endpoint.

This will allow us to encapsulate access to the REST controller in a single class, which we can reuse throughout the entire application.

Let's open a console terminal, then create a service directory, and within that directory, issue the following command:

ng generate service user-service

Now, let's open the user.service.ts file that Angular CLI just created and refactor it:

We don't need a solid background on TypeScript to understand how the UserService class works. Simply put, it encapsulates within a reusable component all the functionality required to consume the REST controller API that we implemented before in Spring Boot.

3.8. The UserListComponent Component

In this case, the UserService class is the thin middle-tier between the REST service and the application's presentation layer. Therefore, we need to define a component responsible for rendering the list of User entities persisted in the database.

Let's open a terminal console, then create a user-list directory and generate a user list component:

ng generate component user-list

Angular CLI will generate an empty component class that implements the ngOnInit interface. The interface declares a hook ngOnInit() method, which Angular calls after it has finished instantiating the implementing class, and after calling its constructor, too.

Let's refactor the class so that it can take a UserService instance in the constructor:

The implementation of the UserListComponent class is pretty self-explanatory. It simply uses the UserService's findAll() method to fetch all the entities persisted in the database and stores them in the users field.

Additionally, we need to edit the component's HTML file, user-list.component.html, to create the table that displays the list of entities:

Notice the use of the *ngFor directive. The directive is called a repeater, and we can use it for iterating over the contents of a variable and iteratively rendering HTML elements. In this case, we used it for dynamically rendering the table's rows.

In addition, we used variable interpolation for showing the id,name, and email of each user.

3.9. The UserFormComponent Component

Similarly, we need to create a component that allows us to persist a new User object in the database.

Let's create a user-form directory and type the following:

ng generate component user-form

Next, let's open the user-form.component.ts file and add to the UserFormComponent class a method for saving a User object:

As we can see above, the Routes array instructs the router which component to display when a user clicks a link or specifies a URL into the browser address bar.

A route is composed of two parts:

Path – a string that matches the URL in the browser address bar

Component – the component to create when the route is active (navigated)

If the user clicks the List Users button, which links to the /users path, or enters the URL in the browser address bar, the router will render the UserListComponent component's template file in the <router-outlet> placeholder.

Likewise, if they click the Add User button, it will render the UserFormComponent component.

3.11. The app.module.ts File

Next, we need to edit the app.module.ts file, so Angular can import all the required modules, components, and services.

Additionally, we need to specify which provider we'll use for creating and injecting the UserService class. Otherwise, Angular won't be able to inject it into the component classes:

4. Running the Application

To accomplish this, let's first run the Spring Boot application, so the REST service is alive and listening for requests.

Once the Spring Boot application has been started, let's open a command console and type the following command:

ng serve --open

This will start Angular's live development server and also open the browser at http://localhost:4200.

We should see the navigation bar with the buttons for listing existing entities and for adding new ones. If we click the first button, we should see below the navigation bar a table with the list of entities persisted in the database:
Similarly, clicking the second button will display the HTML form for persisting a new entity:

5. Conclusion

In this tutorial, we learned how to build a basic web application with Spring Boot and Angular.

As usual, all the code samples shown in this tutorial are available over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

The reasoning is pure data classes in typescript do not have any runtime checking and interfaces offer equivalent type information at design time. Given that emitting the construction code during compiled is superfluous.

Hey Kitty,
Unfortunately, we can’t use an interface here, because we instantiate the User in our code.

0

Nils Breunese

1 year ago

“Also, let’s make sure to check the latest version of the H2 database on Maven Central.” Unless you have specific reasons to use the latest version, I would actually recommend not doing that and taking advantage of the fact that Spring Boot already manages the version of H2 for you: https://github.com/spring-projects/spring-boot/blob/v2.1.3.RELEASE/spring-boot-project/spring-boot-dependencies/pom.xml#L661-L665 Actually, the current version of Spring Boot will already give you H2 1.4.197: https://github.com/spring-projects/spring-boot/blob/v2.1.3.RELEASE/spring-boot-project/spring-boot-dependencies/pom.xml#L69 Not managing the H2 version yourself will also make sure that whenever you upgrade Spring Boot, your dependency will also get upgraded to a compatible version.

Thanks for pointing that out. As Loredana posted before, we usually add a link to the latest versions of the artifact(s). In this case, it’s of course recommended to let Spring Boot manage the dependencies for us, thus getting rid of this concern, Anyways, it’s useful that readers can check the latest versions while reading the article..

0

Ben

1 year ago

Thanks for the article. Any tips on debugging? It doesn’t seem straight-forward from the developer tools of a browser (which seems to load the compiled javascript code). From my research so far the options are: buy IntelliJ IDEA Ultimate, use one of two suspect Angular plug-ins for eclipse, or does it make sense to use a different IDE for Angular?

Hello Ben,
Thank you for your question!
In short, we don’t need any of those since ng serve supports SourceMap. It means that we can debug viewing the original source in the browser while it actually executes the compiled one.
Also, there’re free plugins to debug inside the IDE. For example, for VS Code here are some instructions: https://stackoverflow.com/questions/42881493/debugging-typescript-with-source-maps-and-webpack
Note that the exact process of debugging in the browser or IDE depends on the tools we use.
Cheers.