1. Exercise: Spring Boot Introduction

By the end of this exercise, you should be able to:
  • Start a project using http://start.spring.io

  • to open the project in IntelliJ

  • Describe the contents of

    • the Maven pom

    • the spring-boot-starters in the Maven pom

  • Start the Tomcat server

Pre-requisites
  • Know how to start a Java app in IntelliJ

1.1. Run Introducing Spring Boot

Action: go to start.spring.io and start the project based on the instructions above

StartSpringIo
Figure 1. Start.spring.io

1.2. Testing

The server should be running on port 8080

1.3. Takeaway

In this exercise, you have started your first Spring Boot application

2. Exercise: Hello world!

By the end of this exercise, you should be able to:
  • Run a Hello world controller to smoke test the application

2.1. Steps: Hello world!

Step 1: Code
  • Copy the code from the demo (in the slides) into your project

Step 2: Testing

2.2. Takeaway

In this exercise, we smoke tested our app to get started.

3. Exercise: Hitting the Database

By the end of this exercise, you should be able to:
  • Implement the connection from a Spring Boot application to a database in general and espcially for MySQL

Pre-requisites
  • Know how to start a container

  • Know how to bash into a container

  • Know how to stop a container

3.1. Exercise Steps: Hitting the Database

Step 1: Start a Docker container
docker container run -d -it --name my-local-mysql-server -e MYSQL_ROOT_PASSWORD=... -p 3306:3306 mysql
Remember the root password for later
Step 2: Connect to the docker container
mysql -h localhost -P 3306 --protocol=tcp -u root -p
Step 2 (Alternative): If you do not have MySQL client installed locally
docker container exec -it my-local-mysql-server bash
mysql -h localhost -P 3306 --protocol=tcp -u root -p
Step 3: Create a Database as root
create database carDb;
Below fill in a username and password on the 'username' and 'password' locations
Step 4: Create a user when logged in as root on MySQL container
create user 'username'@'%' identified by 'password';
grant all privileges on carDb.* to 'username'@'%';
flush privileges;
exit;
Below again, fill in the username and password as the value (after the '=' sign)
Step 5: create an application.properties file for MySQL in src/main/resources
spring.datasource.url=jdbc:mysql://localhost:3306/carDb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=theUsername
spring.datasource.password=thePassword

# Recreate or updte the database after stopping and starting ??? =>
## options for spring.jpa.hibernate.ddl-auto: none, validate, update, create, create-drop
spring.jpa.hibernate.ddl-auto=update

# log sql queries to console or not
spring.jpa.show-sql=true

3.2. Testing

If all is well you should be able to run the server without errors during started and you should see the following part of the log

Validate some like this
...  o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
...  com.acme.cars.CarsApplication          : Started CarsApplication in 4.018 seconds (JVM running for 4.464)

3.3. Takeaway

In this exercise, you learned how to make connection to a MySQL database in your Spring Boot application

4. Exercise: JPA

By the end of this exercise, you should be able to:
  • Create an entity

  • Use and describe the annotations @Entity, @Id and @GeneratedValue

4.1. Steps: JPA

Step 1: Create entity Car
  • Create entity Car with properties

    • licensePlate: String

    • mileage: int

    • brand: String

    • id: long (mandatory)

  • Generate getters and setters for all but leave out the setter for id

An entity must have a no-arg constructor.
Step 2: Annotate the id field
  • @Id

  • @GeneratedValue(strategy=GenerationType.IDENTITY)

Step 3: Testing
  • Start the server

    • Validate there is no error in the Spring Boot logging

  • Validate that there is now a table car in the carDb with columns 'id, license_plate, mileage and brand'

JPA will change the camelcase to snake_case e.g. licensePlate in the entity goes to license_plate in the database

4.2. Takeaway

In this exercise, you set up the first entity for our project and learned some basic regarding JPA

5. Exercise: Dependency Injection I

By the end of this exercise, you should be able to:
  • Describe and know the @Component and specialities of it

Exercise component 101
  • Open the @Component class

  • Browse through the subtypes. Which are?

  • Know that this will become more fine grainer during the upcoming modules Repository and RestController

6. Exercise: Repository

By the end of this exercise, you should be able to:
  • Describe and Use the CrudRepository and JPARepository to persist to the database

  • Describe the differences between these two

  • Have the server running without errors

6.1. Steps: Repository

Step 1: Create a repository
  • Create interface CarRepository

    • extends JpaRepository

    • set the correct Generic Type

Step 2: Testing
  • Start the server

  • The server should start without error messages

We will be using this repo in the next module RestController

6.2. Takeaway

In this exercise, you created the repository for saving objects of type Car

7. Exercise: RestController

By the end of this exercise, you should be able to:
  • Create and describe the semantics of the RestControllers and the REST principles and ..Identify the various annotations related to RestControler in Spring Boot

  • @RestController

  • @RequestMapping(method=…​) or shorter

    • @GetMapping for getting a List or an instance

      • Omitting - or using the {id} path variable e.g. * @GetMapping("{id}")

    • @PostMapping for creating

    • @PutMapping for updating

    • @DeleteMapping for deleting

  • @RequestBody for reading an object from the request

  • @PathVariable for reading a scalar from the url of the request

Other annotations
  • @CrossOrigin for setting the REST controller open to specific or all visitors

7.1. Steps: RestController

Step 1: Create a class RestController
  • Create a class RestController for the Car entity alike the BeerController shown in the slides

Step 2: Testing
  • After starting the server

  • Use Postman to get an empty list, which is rendered as [] using GET:http://localhost:8080/api/cars

  • Use Postman to post a Car using POST:http://localhost:8080/api/cars

  • Use Postman to update a Car using PUT:http://localhost:8080/api/cars/{id}

  • Use Postman to delete some car

7.2. Takeaway

In this exercise, you created the RestController with the injected Repository and used the GET,POST,PUT and DELETE request for crudding Cars

8. Exercise: Rest with Statuscodes

By the end of this exercise, you should be able to:
  • Describe and implement the statuscodes of the REST responses

8.1. Steps: Rest with Statuscodes

Step 1: Modify CarController
  • Implement your in the previous exercise created CarController to use HTTP Status code alike the in the slides shown BeerController

Step 2: Testing
  • After starting the server successfully

  • Use Postman to create a new Car which should result in 200 OK

  • Use Postman to read an existing Car by id which should result in 200 OK

  • Use Postman to delete an existing Car by id which should result in 204 No Content

  • Use Postman to delete a NON existing Car by id which should result in 404 Not found

8.2. Bonus Exercise

Formally, when creating an entity, we should return a 201 status code. Please build that in! Use the API of the ResponseEntity class for that and use a bit your imagination - or ask the trainer. Be aware that Postman shows the created URL in the Location header of the Response. See the links in this module under 'Further Reading' for more clarification

8.3. Takeaway

In this exercise, you learned working with some most important HTTP status codes and rendered them using Spring Boot

9. Exercise: Service

By the end of this exercise, you should be able to:
  • Implement a Service for the Car

9.1. Steps: Service

Step 1: Create a Service class
  • Create a class CarService

  • Annotate with @Service

Step 2: Wire in the Service between the RestController and the Repository
  • Move the repository from the controller to the service

  • Use the intellij Refactor ⇒ Delegate methods to have the methods from the repo in the service

  • Inject the service into the RestController

9.2. Testing

Step 1: Redo with Postman
  • Do all the steps for the Repository again with Postman

9.3. Takeaway

In this exercise, you set up a basic service

10. Exercise: Dependency Injection II

By the end of this exercise, you should be able to:
  • Implement a Spring Bean using the following annotations

    • @Configuration

    • @Bean

10.1. Steps: Dependency Injection II

Step 1: Based on the code in the demo and the previous exercise (RestTemplate) refactor your code
  • Create a Bean of the created RestTemplate in the CountryService

Step 2: Validate using Postman
  • Validate that the CountryService still works

11. Exercise: Transactions

By the end of this exercise, you should be able to:
  • For starters, describe and implement transactions using the @Transactional annotation

  • Validate that a transaction is rolled back when the server crashes during a saving

Definitions
  • There are two types of saving in this context

    • In the Service

    • In the DB

    • The difference is that while in the service the data is NOT persisted yet but a new id might be set to an about-to-be-saved Car!

11.1. Steps: Transactions

Step 1: Add Transactional behaviour
  • Add @Transactional annotation to methods which are imperative e.g. save and update

Step 2: Modify the save method to create an exception during saving
public class CarService {
@Transactional
    public Car save(Car car) {
        Car savedCar = this.carRepository.save(car);

        // this is to demo the consequences of rolling back a Transaction
        if ("rollback".equals(savedCar.getBrand())) {
            System.out.println(3 / 0); // results in an ArithmeticException

            // The car should not be saved/updated now!!!
        }

        return savedCar;
    }
}
Step 3: Start the server
  • Start the server in debug mode

  • Add breakpoints on the above location on the line with the if statement

Step 4: Invoke succesful and unsuccesful savings
  • Run Postman and start to create a Car using POST and check the flow using the breakpoints

    • The first one with brand:'BMW' which should be saved successfully in the Service::save method

    • The second one with brand:'rollback' which should be saved in the Service::save method before the division by zero

      • Validate that the car while being saved gets an id from the underlying database

Step 5: Validate using Postman
  • Validate that the car with an other brand (so not 'rollback') is sucessfully saved to the database

  • Validate that the in step four saved car with brand:'rollback' is NOT saved in the DB ⇒ the Transaction is rolled back

  • Inspect the id of a successfully saved car after a rolledback saving. What happened to the failed id?

Remember this: Be sure that saving here is saving in the Spring Boot service::save method. Be clear that saving here to the DB is really done after the save method is committed and NOT rolled back

11.2. Takeaway

In this exercise, you implemented and tested the usage of the @Transactional annotation

12. Exercise: Query methods

By the end of this exercise, you should be able to:
  • Describe and Implement query methods in our Repository

  • Have a good understanding of the syntax of the query methods

12.1. Steps: Query methods

Step 1: Add query methods to the CarRepository
  • find the car with a specific licensePlate

  • find all cars with a specific brand

  • find all cars with a mileage > 10000

Use the link in the topic to make the query methods
Step 2: Testing - and that might be after every query method you added in Step 1.
  • Use Postman to validate the result

12.2. Takeaway

In this exercise, you should have learned how to create your own query methods and use them with Postman

12.3. Bonus Exercise

Add a query method for
  • find all cars from a specific and order them by mileage

13. Exercise: Named queries

By the end of this exercise, you should be able to:
  • Create Named queries

    • JPQL Queries

    • Native queries using native SQL

13.1. Steps: Named queries

Step 1: Refactor the previous @Query to a native SQL query method
  • Make the previous @Query method native by supplying a native SQL statement

  • Cryptic ⇒ See the other attribute of @Query - change the value so that a native query is executed

Step 2: Testing
  • Again, use Postman to validate your results

13.2. Bonus Exercise

Step 1: Create a JPQL named query for validating the licensePlate(s) of Cars
  • Create a query which finds all cars with an invalid licensePlate - which contain an invalid character (see the KentekenValidator as a hint in the code below)

class KentekenValidator {

    private static final String REGEXP_KENTEKEN_FORMAT;

    // so NOT the characters mentioned below (^ = NOT in regexp in a range)
    private static final String VALID_LETTERS = "[^AaEeIiOoCcQqUu0-9]";

    // A valid licensePlate in the NL matches the following regular expression
    static {
        REGEXP_KENTEKEN_FORMAT = String.format("\\d-%1$s{2}-\\d{3}|\\d-%1$s{3}-\\d{2}|"
        + "\\d{2}-\\d{2}-%1$s{2}|\\d{2}-%1$s{2}-\\d{2}|\\d{2}-%1$s{2}-%1$s{2}|\\d{2}-%1$s{3}-\\d|"
        + "\\d{3}-%1$s{2}-\\d|%1$s-\\d{2}-%1$s{3}|%1$s-\\d{3}-%1$s{2}|%1$s{2}-\\d{2}-\\d{2}|%1$s{2}-\\d{2}-%1$s{2}|"
        + "%1$s{2}-\\d{3}-%1$s|%1$s{2}-%1$s{2}-\\d{2}|%1$s{3}-\\d{2}-%1$s", VALID_LETTERS);
    }
}
Step 2: Testing
  • Again, use Postman to validate your results

13.3. Takeaway

In this exercise, you learned to make JPQL named queries

14. Exercise: Profiles and Properties

By the end of this exercise, you should be able to:
  • Have a full understanding of creating and using a profile

14.1. Roadmap: Profiles and Properties

Roadmap
  • Create a Profile development and move the dataSource properties from application.properties therein

  • Start your app with the profile development

14.2. Steps: Profiles and Properties

Step 1: Create profile
  • Add a file application-development.properties

Step 2: Start the app
  • Open CarsApplication

  • IntelliJ: Run as ⇒ Edit configuration ⇒ Set environment variables 'spring.profiles.active=development'

  • Run the application

Step 3: Testing
  • Validate that your application.properties file does NOT CONTAIN DB specific keys as url, username and password!

  • After starting use Postman and validate that the data is still persisted in the same database as before

14.3. Takeaway

In this exercise, you set up a newly development profile and started the Spring Boot application using that profile

14.4. (Optional) Uninstalling Profiles and Properties

If you do not like working with the newly created development profile you migh move back to the original application.properties file

15. Exercise: Minor fixes

Fix the name of the CarsApplicationTests
  • Symptom: The CarApplicationTests is now an @SpringBootTest which is during the test phase. That should be during integration-test phase

  • Cause: The test should end with IT

  • Solution: Rename the CarsApplicationTests class to CarsApplicationIT

  • Testing: During mvn clean test the test is NOT executed

Add the maven-failsafe-plugin
  • Symptom: After the change above the test will not run during mvn clean verify

  • Cause: The maven-failsafe-plugin is NOT added to the pom.xml

  • Solution: Add the maven-failsafe-plugin as plugin in the build section of the pom.xml (see below)

  • Testing: During mvn clean verify the test is executed

Add this dependency in the build section
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
</plugin>
The version of the maven-failsafe-plugin can be omitted since that is already settled for us in the Spring Boot parent project
Set the version from 0.0.1-SNAPSHOT to 0.1.0-SNAPSHOT
  • Symtom: the version is 0.0.1.-SNAPSHOT which indicated that we are creating a bugfix for the 0.0 version

  • Cause: The version number is strange

  • Solution: Bump it to 0.1.0-SNAPSHOT

Action
mvn versions:set -DgenerateBackupPoms=false -DnewVersion=0.1.0-SNAPSHOT
Testing
  • During mvn clean test the version 0.1.0-SNAPSHOT is printed

16. Exercise: Testing

By the end of this exercise, you should be able to:
  • Describe and implement Unittests and Integration test

  • Learn how to make use of the Junit5 library and the Spring Boot Testing library

16.1. Setup Testing

This topic has an other, remote site
There is also a handy referal github repo for this on this Github repo

16.2. Steps: Testing

Step 1: Do the exercises on the site of testing
This site is used before and may contains some error. I omitted to fix the errors since at this point they might be fixable for yourself at this moment during this training.
Step 2: Testing

When time permits

Exercise: Bean Validation

By the end of this exercise, you should be able to:
  • Install and use bean validation for your Spring Boot application

Steps: Bean Validation

Use the text from the demo and implement the validation on your app

Testing

You might write some integration testing for it! In fact that is a very good practise!

Takeaway

In this exercise, you set up validation and have learned how to add validation to your app

Exercise: RestTemplate

By the end of this exercise, you should be able to:
  • Invoke a REST api using a Spring Boot app

  • Return the values of the REST api

Setup RestTemplate

We will be using the countries REST api for this exercise

Especially this endpoint as an example for Germany which returns all cities in a country

Steps: RestTemplate

Step 1: Implement a CountryController
Step 2: Testing

Takeaway

In this exercise, you learned how to invoke a REST api from within your Spring Boot app using RestTemplate

Exercise: JDBC Template

By the end of this exercise, you should be able to:
  • Have a little understanding of the JDBC Template

Setup JDBC Template

Code the code from the slides, Customer and SpringBootJdbcApplication to your workspace

Steps: JDBC Template

Step 1: Code it
  • After adding the code from the step above (Setup)

  • Run the code

Step 2: Testing
  • There should be printed that Customers are created and changed

Takeaway

In this exercise, you learned some very basic regarding JDBC Templating

Future

Exercise: WebFlux

By the end of this exercise, you should be able to:
  • Run an async app with Spring Boot and verify that you have seen async result in the browser window

Setup WebFlux

Step 1: Start a mongo db container
docker container run -dit --name some-mongo -p 27017:27017 mongo:latest
Step 2: Open the project

Steps: WebFlux

Step 1: Go to the instructions
  • On this tutorial

  • Browse to '5: Demo' on that article

Step 2: Execute the instructions
  • Open the link above in What and How and run the POST, PUT and GET methods on http://localhost:8080

    • The POST and PUT with Postman

    • The GET with some Internet Browser which should show that the response is getting asynchronously

Testing

Be sure that you have seen the responses of the users asynchronousely in the final part of the exercise which validates that the app is asynchronousely responding

Bonus Exercise

Introduction
  • WebClient is the future asynchronous and perhaps replacement of RestTemplate

When time permit
  • Follow this tutorial from Baeldung for introducing the future WebClient

(Optional) Uninstalling WebFlux

You might remove the project or keep the project if you like, that is entirely up to you!