Spring Boot Introduction

Antonios Barotsis
Feb 5 · 14 min read

A very surface level introductory presentation on Spring Boot for the First Year TU Delft Object Oriented Programming Project course.

Photo by Maximilian Weisbecker on Unsplash

What is this about / Who is this for

I was really interested in Spring Boot for some time and taught myself some basics over the last one month and a half or so. Keep that in mind alongside the fact that I am a first year student that has not taken OOPP yet. That being said, this page was created with the goal of introducing my colleagues to Spring Boot and giving out a very basic, purely backend toy application to hopefully help people get started with the course.

Why / What is Spring used for?

Spring is the most popular application development framework for enterprise Java. It is the expressjs equivalent of Java. It can be used to create both Web Services as well as Applications. It is often also used to create APIs which are then used by separate code bases that are possibly using a different programming language.

As an example, consider last year’s OOPP which was about creating an application that allowed you to book rooms as well as order food.

What is an API

An application programming interface (API) is a computing interface that defines interactions between multiple software intermediaries. It defines the kinds of calls or requests that can be made, how to make them, the data formats that should be used, the conventions to follow, etc. It can also provide extension mechanisms so that users can extend existing functionality in various ways and to varying degrees. An API can be entirely custom, specific to a component, or designed based on an industry-standard to ensure interoperability. Through information hiding, APIs enable modular programming, allowing users to use the interface independently of the implementation.

TL;DR:

What is an API Endpoint

In simple terms, an API endpoint is the point of entry in a communication channel when two systems are interacting. It refers to touchpoints of the communication between an API and a server. The endpoint can be viewed as the means from which the API can access the resources they need from a server to perform their task. An API endpoint is basically a fancy word for a URL of a server or service.

As an example, for those of you who made the web game, an endpoint is each url supported by your app (say / and /game or /play).

Chocolatey: A windows package manager

Make sure to run powershell with admin privileges if you want to install packages. The Choco installation executable can be found here.

What is Spring Boot

Spring Boot provides a good platform for Java developers to develop a stand-alone and production-grade Spring Application that you can just run. You can get started with minimum configurations without the need for an entire Spring configuration setup.

Requirements

For this project I will be using Java 15 which may differ from what will be used in the project

  • Install Gradle (choco install gradle)
  • Make sure the output of gradle -version (the JVM part) andjava -v point to the same Java version. If that is not the case try reinstalling the Java SDK (choco install opensdk)or updating your paths.
  • Make sure Intellij is using the proper Java SDK version for the project. Hit ctrl + shift + alt + s to open the Project Structure panel in Intellij (check this one we create the project).

In case you are using a different Java version make sure to edit the sourceCompatibility = ‘15’ attribute in build.gradle to whatever version of Java you have installed (for example change it to sourceCompatibility = ‘13’ if you are using Java 13).

Application Structure

The client will create REQUESTS to our server which will be handled by our API Layer or Controller in Spring terminology. This layer manages all our application’s endpoints and extracts data from the request before it passes it to the next layer.

The Service Layer is responsible for any business logic our application might have. As an example consider the scenario where you have a website and you want to allow users to create accounts but no two accounts should have the same username. The user will send a request to the server asking for an account creation along with his username (and credentials but that is not important here). The Controller will receive the request and destructure the username before calling the appropriate Service method and passing it the username. The Service is now responsible for checking whether the username already exists in the database or not. Note that the interaction with the database it performed in the next layer.

The Data Access layer or Repository is responsible for interacting with the database. At this point is where a typical response is generated and sent back to the user (exceptions could cause a response to be generated in any of the 3 layers). Dividing the application into layers is extremely important and has a lot of advantages.

  • It boosts development speed
  • It makes for cleaner code
  • Different teams could be working on different layers
  • It increases the application’s fault tolerance

On the far right you can see the Entity class that we will be implementing later, a Person class with an ID and a name.

File Structure

There are a few different ways one can structure such an application, the one I prefer is shown above. A different way of doing this would be to have a Person folder and inside live all the other classes which I will not be using as I believe it looks messier.

What is Gradle

What is Postman

Download

Spring Initializr is a web-based tool with which we can easily generate the structure of the Spring Boot Project.

Alternatively, there is a command line tool that does this for you!

choco install spring-boot-cli

spring init Copy
--build=gradle
-j 15
-d 'web,jpa,postgresql'
-a SpringPresentation
-n SpringPresentation
-g '.'

This command will create a project with:

  • Gradle as its build system (by default this is maven)
  • Java version 15
  • The dependencies mentioned previously (web, jpa and postgresql driver)
  • Artifact id of SpringPresentation
  • Project name of SpringPresentation
  • No package

In case you want to use this, run spring help init for documentation.

Both of the methods listed above create a zipped folder so make sure to unzip it before continuing.

mkdir SpringPresentation | tar -xf SpringPresentation.zip -C SpringPresentation

This creates a new folder SpringPresentation and extracts the zipped folder you just downloaded inside of it (assuming you are in the correct directory). You can also run

idea64.exe . to launch Intellij on your current directory.

Optional: If you want to have implement the entire project including a database make sure to have PostgtSQL installed (I installed it in Docker). To create the Database using docker run:

docker run --name springboottestdb -e POSTGRES_PASSWORD=password -d -p 5432:5432 postgres:alpineCopy
| docker exec -it 68627bf9417e bin/bash

Where 68627bf9417e is your container ID. I will not be going more in depth on this as it is outside the scope of this article.

Alternatively, you can use a very popular in-memory Java database engine called H2, instructions on that will follow shortly.

Dependencies

  • Spring Web: Allows the building of RESTful applications
  • JPA: It makes it easier to build Spring-powered applications that use data access technologies.
  • PostgreSQL driver

Coding

At this point, your empty project should look like this:

├── build.gradle
└── src
├── main
│ ├── java
│ │ └── SpringPresentation
│ │ └── SpringPresentationApplication.java
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── java
└── SpringPresentation
└── SpringPresentationApplicationTests.java

We will start by editing the src.main.resources.application.properties file to this:

  • spring.datasource.urlThe url of the database
  • spring.datasource.usernamePostgreSQL username
  • spring.datasource.passwordPostgreSQL password
  • spring.jpa.hibernate.ddl-autoSpecifies how to manipulate the database in set-up (create-drop clears the database whenever the application is ran, used for testing purposes)
  • spring.jpa.show-sqlLogs any SQL commands
  • spring.jpa.properties.hibernate.dialectTells jpa what flavour of SQL we are using
  • spring.jpa.properties.hibernate.format_sqlBeautifies the SQL outputs

This configuration works with my PostgreSQL database set up but in case you want to use an H2 database instead perform the following modifications in src.main.resources.application.properties:

  • Change spring.datasource.url to jdbc:h2:mem:springboottestdb
  • Change spring.datasource.username to sa (default profile) and leave the password empty
  • Change spring.jpa.properties.hibernate.dialect to org.hibernate.dialect.H2Dialect

And finally, go to the build.gradle file and replace runtimeOnly ‘org.postgresql:postgresql’ with runtimeOnly ‘com.h2database:h2’ (make sure to rebuild the project after this step)

Note that everything else mentioned in this article will work the same in either a proper PSQL database and an H2 database.

We will now create the following 4 packages under src.main.java.SpringPresentation:

  1. Api
  2. Models
  3. Repositories
  4. Service

Now let’s create src.main.java.SpringPresentation.Models.Person. Add a private field long id; as well as String name;. Create getters, setters an equals method, toString as well as 2 constructors:
public Person() and public Person(String name).

So far we have created a simple Java class, now let's turn this into a Spring Entity.
Before the public class Person add the following 2 annotations:

  • @Entity(name = “Person”)
  • @Table(name = “people”)

The first one tells Spring that the class is an Entity class and specifies its name. The name by default is the name of the class (so in our case this does not make a difference) however it is good practice to always specify the name.
The second one specifies the primary table for the annotated entity.

At this point you may notice that Intellij gives you an error when you hover over the Table name
Cannot resolve table 'people'. This is because we have yet to configure a datasource in Intellij. Press
ctrl + shift + a and search for create data source. Select PostgreSQL. Change the User, Password and Database to what was specified in our application.properties. Click apply and OK. At this point the error should change to
Cannot resolve table 'people', this is fine as the table does not and should not exist yet, it will be created automatically once we run the application. Note that if you are using the H2 database you can skip this step since the table will be created on runtime, the errors will still be visible. Do not worry about that; the table exists and it is working as intended.

You should see another error on the Person class: Persistent entity 'Person' should have primary key , since we told spring that this is a Database table it must have a primary key. Add the @Id annotation before the private long id;.

At this point you might have noticed something weird: We have not included the id parameter in any constructor, so how is it going to ever get a value? This is not a mistake, we want any IDs to be generated by the database, not by the user (imagine if everytime a user that wanted to create an account on a website for example had to include a unique id in his form; the user would have not way of knowing whether his id is unique or not). The conventional way of generating Database IDs is using a Sequence Generator.

We will now define our Sequence Generator and assign it to our id parameter. Add the following before the id declaration:

Let’s give Spring a few more details about our attributes. We can specify the name they will have in the Database (since they are collumns) and a few other stuff such as whether they can be updated or be nullable. Put the following 2 configurations before their respective attribute declarations.

If we now run the app and refresh the Intellij Datasource we should now see the following:

As we can see, our Database table has been created and the name errors have went away.

Next we will be creating the Repository interface. Create the file src.main.java.SpringPresentation.Repositories.PersonRepository. Make our interface extend from
JpaRepository<Person, Long>. The first parameter is the class our Repository is going to be working with and the second one specifies the ID type of that class. This interface provides us with a some basic CRUD (Create, Read, Update, Delete) operations. Let's add an updateNameById method that will update a person's name with a specified id.

We will not be implementing the method ourselves as the JpaRepository interface can do that for us. All we have to do is specify the query in an annotation above the method we just created.

The String we passed in the annotation is the name of this Repository which optional in our case. As we will see later it is necessary when we are dealing with multiple Repositories.

That is all we need in our Repository interface as the rest is handled by JPA.

On to our Service class. Create the file src.main.java.SpringPresentation.Services.PersonSerivce. As you might suspect by now, we will annotate it with @Service

Our Service class will have one attribute: The PersonRepository we created earlier. Go ahead and create a constructor. Time to annotate it. Add @Autowired above the constructor, this tells Spring it should use Dependency Injection. Finally, inside our constructor parameters add @Qualifier("PersonRepository"). This ensures that the Repository named PersonRepository is the one Injected.

We now have to implement all the methods our Controller has to be able to use. Since we have our Repository as an attribute here all of the simple methods we want are actually extremely easy to implement.

Keep in mind that our application is pretty simple. There is in fact 0 logic included in this layer. In a normal app this should end up being the most complicated layer.

Finally, let’s create the src.main.java.SpringPresentation.Api.PersonController controller. There's a few more annotations involved here. First of all, let's add the following above the class declaration:

@RestController // Tells Spring this is a REST controller
@RequestMapping("api/v1")

The second annotation makes it so we will be able to access our API at http://localhost:8080/api/v1/ instead of http://localhost:8080/. This is again good practice as it is often the case that real life projects end up hosting numerous versions of their API at once (due to backwards compatibility not being viable).

There are 4 annotations that we are going to be using based on what type of HTTP request we want our endpoint/method to support:

  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping

All of these have a path parameter which specifies the relative url to http://localhost:8080/api/v1. For example @GetMapping(path = "/example") will create a GET request handler for http://localhost:8080/api/v1/example.

But what about using data that was included in the request? @PathVariable, @RequestBody tell Spring to extract the variable from either the Path or the Request Body respectively. In the case of @PathVariable, the Mapping path should include the variable name enclosed in curly braces so Spring knows which one to use. This is done automatically for @RequestBody.

There is not much to talk about here. Keep in mind that @RequestBody will try to extract one object from the Request Body. That means that we can't for example have both id and person in our updateNameById method. Lastly remember that this will try to fit the data it finds to one of the defined constructors and we did have a public Person(String name) constructor.

At this point our application is basically done, time to test our endpoints using Postman!

Let's first check out what happens when we make a GET Request at http://localhost:8080/api/v1/

We get an empty array as expected since there are no objects in our database yet. Let’s add some! Remember that out POST mapping was at http://localhost:8080/api/v1/insert and we used @RequestBody to extract a Person from the request. Recall that Spring will automatically try to fit the request data into a Person constructor which means that if we send a payload containing an attribute called name that has any value of type String, Spring will create a Person object out of it.

It works! We even get the full object returned to us as expected and we can see that it automatically got assigned an Id of 1! Let’s try our previous GET endpoint again;

This time we get an array of one element which is the person that we just added! Since we now have an entity in the database, let’s see what happens when we make another GET at http://localhost:8080/api/v1/get/1

Remember that for this endpoint we used @PathParameter to get the id. Let's see what happens when we input an id that does not exist

We get null instead of an error which is nice. Remember that this method returned an Optional. Time to test our PUT mapping. For this we again need to specify a name, for the sake of the example let's set it to UPDATED and see what happens.

No response since our method was null but reusing our previous Request we can see that the update did go through.

We only have delete so time to test that as well. We just need to specify a path variable here and we are good to go.

Let’s reuse our first Request to make sure nothing is left in the database.

Lastly, let’s make sure our Sequence Generator works properly by adding another entity in the database.

As we can see, this has an id of 2 which means our Sequencer is working properly.

Congratulations! You just used postman instead of writing tests, see if that gets you anywhere…

My Learning Resources

If you made it this far then I want to thank you for reading and I hope you got something out of this :)

Again, do keep in mind that all this is written by a first year student that has not taken the course yet. Do not take anything from this as 100% correct or best practice or even as something you will definitely use during the course itself. I taught myself some Spring basics mostly using the following sources (the first 2 heavily influenced the example application) so be sure to look into all of them, especially the third one. The code for this has been posted on my github for which you can find the link below. Happy coding ;)

Last but not least, you can find the full code for this project here.

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To stay up to date on other topics, follow us on LinkedIn. https://www.linkedin.com/company/nerdfortech

Antonios Barotsis

Written by

Currently studying Computer Science and Engineering at TU Delft. Interested in backend software development, machine learning and data science.

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To stay up to date on other topics, follow us on LinkedIn. https://www.linkedin.com/company/nerdfortech

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store