<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ spring-boot - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ spring-boot - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 27 Jun 2026 11:23:06 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/spring-boot/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Database Version Control with Liquibase and Spring Boot ]]>
                </title>
                <description>
                    <![CDATA[ Picture this familiar scenario: you're working on a new feature that requires a new database column. You open your local database client, write an ALTER TABLE statement, and execute it. Your code work ]]>
                </description>
                <link>https://www.freecodecamp.org/news/database-version-control-with-liquibase-and-spring-boot/</link>
                <guid isPermaLink="false">6a277a781aef44b8099e978b</guid>
                
                    <category>
                        <![CDATA[ Databases ]]>
                    </category>
                
                    <category>
                        <![CDATA[ version control ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ashutosh Krishna ]]>
                </dc:creator>
                <pubDate>Tue, 09 Jun 2026 02:29:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/dbadec79-8248-4ef4-aa9c-126250db7a64.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Picture this familiar scenario: you're working on a new feature that requires a new database column. You open your local database client, write an <code>ALTER TABLE</code> statement, and execute it. Your code works perfectly. You commit the Java code, push it to the repository, and go grab a coffee.</p>
<p>A few hours later, a teammate pulls your branch, runs the application, and everything crashes.</p>
<p>"Hey," they ask across the room (or in a Slack channel), "did you change the database?"</p>
<p>You quickly realize you forgot to share the SQL script. You paste it into the chat. They run it. Everything works. Then, a week later, the deployment to the staging environment fails for the exact same reason. By the time this code reaches production, everyone is asking a variation of the same terrified question: "Which SQL script should I run?"</p>
<p>This situation is called schema drift. It happens when the state of your database diverges across different environments. Staging has one schema, production has another, and every developer's local machine is a unique snowflake of untested database modifications.</p>
<p>Managing database changes manually is a recipe for deployment headaches and team collaboration challenges. Application code is stateless and easy to replace. Databases are stateful. Databases have surprisingly good memories, and they rarely forget a bad migration.</p>
<p>Liquibase solves this problem by bringing version-control discipline to your database changes. Instead of passing around SQL files and hoping people remember to run them, you define your database changes in code. These changes travel with your application repository and execute automatically.</p>
<p>Here is a high-level look at how this architecture works:</p>
<img src="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/41202410-4d42-4343-98df-912420dbfb15.png" alt="Architecture diagram showing code flowing from a developer to a database via Git, Spring Boot, and Liquibase." style="display:block;margin:0 auto" width="482" height="771" loading="lazy">

<p>Think about the journey of a single database change. A developer commits their database migration alongside their Java code into Git. When the CI/CD pipeline (or a teammate) pulls that code, the Spring Boot application starts. But before the app fully boots up and accepts web traffic, Liquibase intercepts the process. It acts as a gatekeeper, connecting to the database and applying the required schema changes. This ensures the database exactly matches the code's expectations before a single user makes a request.</p>
<h2 id="heading-why-database-version-control-matters">Why Database Version Control Matters</h2>
<p>If you've spent any time working on team-based applications, you've probably seen a folder structure that looks exactly like this:</p>
<pre><code class="language-plaintext">project-sql-scripts/
├── create_employee_table.sql
├── create_employee_table_final.sql
├── create_employee_table_final_v2.sql
├── add_email_column.sql
├── latest.sql
└── definitely_latest_use_this_one.sql
</code></pre>
<p>The phrase "just run this SQL script manually" has launched many memorable incidents.</p>
<p>When you rely on manual database updates, you guarantee failure at scale. Onboarding a new developer becomes an archeological expedition to figure out how to build the local schema. Deployments become stressful events requiring a checklist of manual queries that must be run in a highly specific order.</p>
<p>Version-controlled database changes treat your schema as code. When your database changes live alongside your application logic, you gain several immediate benefits:</p>
<ul>
<li><p><strong>Consistency:</strong> Every environment (local, staging, production) applies the exact same changes in the exact same order.</p>
</li>
<li><p><strong>Safety:</strong> You eliminate the human error of skipping a script or running an outdated query.</p>
</li>
<li><p><strong>Visibility:</strong> You can look at a Git commit and see exactly how the Java code and the database schema changed together to support a new feature.</p>
</li>
</ul>
<p>Git solved version control for code. Liquibase helps prevent databases from becoming the rebellious sibling.</p>
<h2 id="heading-what-is-liquibase">What is Liquibase?</h2>
<p>At its core, Liquibase is a database migration tool that tracks and applies schema changes in a predictable and repeatable way.</p>
<p>Instead of writing loose SQL scripts, you write "migrations" (also called changeSets). Liquibase reads these files, compares them against a tracking table inside your actual database, and figures out exactly what needs to be executed to bring the database up to date.</p>
<p>To use Liquibase effectively, you only need to understand a few conceptual terms:</p>
<ul>
<li><p><strong>changeLog:</strong> The master file. This is essentially a list that tells Liquibase which migration files to execute and in what order.</p>
</li>
<li><p><strong>changeSet:</strong> A single, atomic change to your database. Creating a table is one changeSet. Adding a column is another.</p>
</li>
<li><p><strong>Migration History:</strong> A table Liquibase automatically creates in your database (called <code>DATABASECHANGELOG</code>) to remember which changeSets have already been executed.</p>
</li>
<li><p><strong>Checksums:</strong> A unique hash generated for every changeSet. Liquibase uses this to detect if someone secretly modified a file after it was already executed.</p>
</li>
</ul>
<p>When you integrate Liquibase with Spring Boot, the migration process happens completely automatically during the application startup phase.</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/410e7bdb-da2f-4c48-a5b2-20a45fb20956.png" alt="Sequence diagram of Spring Boot startup where Liquibase checks the tracking table, locks the database, runs migrations, and releases the lock before allowing HTTP traffic." style="display:block;margin:0 auto" width="645" height="528" loading="lazy">

<p>During startup, Liquibase takes control before your web server is allowed to receive HTTP traffic. It reaches into the database and checks the tracking table to see which migrations have already run. If it finds new migrations in your local files, it locks the database to prevent concurrent updates, executes the changes, records the new history, and finally releases the lock. Only after this entire process completes does Spring Boot finish booting up.</p>
<p>Because Liquibase runs before Spring Boot fully initializes the web server, your application will never serve traffic with an outdated database schema. If a migration fails, the application fails to start, protecting your system from entering a broken state.</p>
<h2 id="heading-project-setup">Project Setup</h2>
<p>Now that you understand the theory, let's build something real. We're going to build the database layer for an Employee Management API.</p>
<p>For this project we'll use:</p>
<ul>
<li><p>Java 17+</p>
</li>
<li><p>Spring Boot 3.x</p>
</li>
<li><p>Maven</p>
</li>
<li><p>Liquibase</p>
</li>
<li><p>H2 Database</p>
</li>
</ul>
<p>We're using H2 because it's an in-memory database that requires zero installation. You can run this project immediately without configuring Docker containers or installing database servers. But everything you learn here applies exactly the same way to PostgreSQL, MySQL, SQL Server, or Oracle.</p>
<p>If you're generating this project via <a href="https://start.spring.io/">Spring Initializr</a>, select the following dependencies: Spring Web, Spring Data JPA, Liquibase Migration, and H2 Database.</p>
<p>In your <code>pom.xml</code>, you'll see the critical dependencies that make this work:</p>
<pre><code class="language-xml">&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;com.h2database&lt;/groupId&gt;
        &lt;artifactId&gt;h2&lt;/artifactId&gt;
        &lt;scope&gt;runtime&lt;/scope&gt;
    &lt;/dependency&gt;

    &lt;dependency&gt;
        &lt;groupId&gt;org.liquibase&lt;/groupId&gt;
        &lt;artifactId&gt;liquibase-core&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<p>Next, configure Spring Boot to talk to H2 and find your Liquibase files. Open your <code>src/main/resources/application.properties</code> file and add the following:</p>
<pre><code class="language-plaintext"># H2 Database Configuration
spring.datasource.url=jdbc:h2:file:./data/employeedb;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

# Enable H2 Console to inspect the database in your browser
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# Liquibase Configuration
spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml
</code></pre>
<p>That last line is the most important. It tells Spring Boot exactly where to find the "master list" of your database changes.</p>
<p>Note: We're using a file-based H2 database instead of an in-memory database. The problem with an in-memory database is that it completely wipes itself clean every time you restart Spring Boot.</p>
<p>While Liquibase will happily rebuild the schema from scratch on every boot, a <strong>file-based</strong> database is much better for this tutorial (and for real-world local development). With a file-based database, your data, and more importantly, your Liquibase history, will actually persist between application restarts.</p>
<h2 id="heading-understanding-core-liquibase-concepts">Understanding Core Liquibase Concepts</h2>
<p>Before we write our first table, we need to understand how Liquibase organizes files. Liquibase uses a hierarchical structure.</p>
<p>Think of it like a book. The <code>changeLog</code> is the table of contents, and the <code>changeSets</code> are the actual chapters.</p>
<ol>
<li><p><strong>The Master ChangeLog:</strong> This is the entry point. It rarely contains actual database changes. Instead, its only job is to include other files in a specific order.</p>
</li>
<li><p><strong>Child ChangeLogs:</strong> These group related changes together.</p>
</li>
<li><p><strong>ChangeSets:</strong> These are the actual, atomic database commands (like creating a table or adding a column).</p>
</li>
</ol>
<p>Here's a visual breakdown of how this hierarchy works in a real Spring Boot project:</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/2cbd3054-d0e4-4129-b0a4-015b08c7258c.png" alt="File structure diagram showing a master changelog XML file pointing to three child migration files in strict chronological order." style="display:block;margin:0 auto" width="993" height="259" loading="lazy">

<p>Liquibase organizes migrations hierarchically. You maintain a single master file that acts as a table of contents. This master file rarely holds actual SQL commands. Instead, it explicitly includes child XML files in a strict execution order. Each of those child files (like <code>01-create-employees.xml</code>) contains one or more individual database commands, which Liquibase calls changeSets.</p>
<p>A <code>changeSet</code> is uniquely identified by three things:</p>
<ul>
<li><p><strong>id:</strong> A unique string (often a number or a Jira ticket ID).</p>
</li>
<li><p><strong>author:</strong> The person who wrote the migration.</p>
</li>
<li><p><strong>file path:</strong> Where the file is located.</p>
</li>
</ul>
<p>When Liquibase runs, it looks at a <code>changeSet</code>, calculates a cryptographic hash of its contents (a checksum), and records the id, author, and checksum in the database. If it sees that exact combination of id, author, and file path in the database again on the next startup, it skips it.</p>
<h2 id="heading-create-the-initial-employee-schema-version-1">Create the Initial Employee Schema (Version 1)</h2>
<p>Let's write our first version. We need a table to store employees.</p>
<p>First, create the master file at <code>src/main/resources/db/changelog/db.changelog-master.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;include file="db/changelog/changes/01-create-employees.xml"/&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Next, create the actual migration file at <code>src/main/resources/db/changelog/changes/01-create-employees.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="1" author="ashutoshkrris"&gt;
        &lt;createTable tableName="employees"&gt;
            &lt;column name="id" type="BIGINT" autoIncrement="true"&gt;
                &lt;constraints primaryKey="true" nullable="false"/&gt;
            &lt;/column&gt;
            &lt;column name="first_name" type="VARCHAR(50)"&gt;
                &lt;constraints nullable="false"/&gt;
            &lt;/column&gt;
            &lt;column name="last_name" type="VARCHAR(50)"&gt;
                &lt;constraints nullable="false"/&gt;
            &lt;/column&gt;
        &lt;/createTable&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Let's look at what we just did. We defined a <code>changeSet</code> with an <code>id</code> of "1" and an <code>author</code> of "ashutoshkrris". Inside, we used Liquibase's XML syntax to define a table.</p>
<p>Why use XML instead of plain SQL? Because Liquibase is database-agnostic. This exact XML will generate the correct auto-increment syntax for PostgreSQL (<code>SERIAL</code>), MySQL (<code>AUTO_INCREMENT</code>), or Oracle (<code>IDENTITY</code>). You define the structure, and Liquibase translates it to the specific database dialect.</p>
<p>Now, run your Spring Boot application. Watch your terminal output. You'll see logs similar to this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/69171f93-d54b-487b-a09a-9fd49cad6b6a.png" alt="Terminal Logs for Liquibase Startup" style="display:block;margin:0 auto" width="1810" height="518" loading="lazy">

<p>Liquibase realized the database was empty. It automatically created its tracking table (<code>DATABASECHANGELOG</code>), read our <code>changeSet</code>, executed the table creation, and recorded the event.</p>
<p>If you restart the application right now, Liquibase will run again. But this time, it'll check the <code>DATABASECHANGELOG</code> table, see that <code>id="1"</code> and <code>author="ashutoshkrris"</code> has already been executed, and silently skip it. Your database is now safely version-controlled.</p>
<h2 id="heading-what-just-happened">What Just Happened?</h2>
<p>Up to this point, Liquibase might feel a bit like magic. You dropped an XML file into a folder, started Spring Boot, and your database schema transformed.</p>
<p>But understanding how Liquibase actually works under the hood is critical. If you understand the startup sequence, you'll know exactly how to debug deployments when things eventually go wrong.</p>
<p>When your Spring Boot application starts, it doesn't immediately begin accepting web requests. First, it initializes its internal components. When it creates the Liquibase component, the migration process begins.</p>
<p>Here's exactly what happens during that startup phase:</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/4625b403-3f12-4015-9f46-2d0966c35e30.png" alt="Detailed sequence diagram showing Liquibase checking the lock table, acquiring the lock, running unexecuted migrations, and releasing the lock before Tomcat starts." style="display:block;margin:0 auto" width="832" height="766" loading="lazy">

<p>Let's trace the exact sequence. When Spring Boot initializes Liquibase, the very first thing the tool does is query the lock table to ensure no other application instance is currently migrating the database. If the coast is clear, it claims the lock. It then calculates cryptographic checksums for your local XML files, compares them against the database history, executes any missing changes, and logs them. Finally, it releases the lock so the Tomcat web server can safely start.</p>
<p>This sequence guarantees that your application will never serve a user request before the database schema is completely ready to handle it.</p>
<h2 id="heading-inspecting-the-database-liquibase-metadata-tables">Inspecting the Database: Liquibase Metadata Tables</h2>
<p>Let's look at what this history and locking actually looks like inside the database itself. Since we configured the H2 Console earlier, we can inspect the raw tables.</p>
<p>While your Spring Boot application is running, open your browser and navigate to <code>http://localhost:8080/h2-console</code>. Connect using the JDBC URL <code>jdbc:h2:file:./data/employeedb</code> with the username <code>sa</code> and a blank password.</p>
<p>Inside, you'll see your <code>employees</code> table. You'll also see two extra tables created automatically by Liquibase: <code>DATABASECHANGELOG</code> and <code>DATABASECHANGELOGLOCK</code>.</p>
<h3 id="heading-the-databasechangelog-table">The <code>DATABASECHANGELOG</code> Table</h3>
<p>This table is the brain of your migration strategy. It acts as the permanent ledger of every database change ever applied to this environment.</p>
<p>If you run <code>SELECT * FROM DATABASECHANGELOG;</code>, you'll see output that looks like this:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>AUTHOR</th>
<th>FILENAME</th>
<th>DATEEXECUTED</th>
<th>ORDEREXECUTED</th>
<th>EXECTYPE</th>
<th>MD5SUM</th>
<th>DESCRIPTION</th>
<th>COMMENTS</th>
<th>TAG</th>
<th>LIQUIBASE</th>
<th>CONTEXTS</th>
<th>LABELS</th>
<th>DEPLOYMENT_ID</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>ashutoshkrris</td>
<td>db/changelog/changes/01-create-employees.xml</td>
<td>2026-05-30 13:11:35.937919</td>
<td>1</td>
<td>EXECUTED</td>
<td>9:66e7dcffb2b1902a4e9f01670cb5f192</td>
<td>createTable tableName=employees</td>
<td></td>
<td><em>null</em></td>
<td>4.31.1</td>
<td><em>null</em></td>
<td><em>null</em></td>
<td>0126894849</td>
</tr>
</tbody></table>
<p>Let's break down the most important columns:</p>
<ul>
<li><p><strong>ID, AUTHOR, FILENAME:</strong> These three columns form a composite key. Together, they uniquely identify a single migration.</p>
</li>
<li><p><strong>DATEEXECUTED &amp; ORDEREXECUTED:</strong> Tells you exactly when a script ran and in what sequence.</p>
</li>
<li><p><strong>MD5SUM:</strong> This is the cryptographic hash of your XML file. When Liquibase starts, it hashes your local XML file and compares it to this column. If you secretly edit a file after it's been executed, this hash won't match, and Liquibase will crash the startup to protect your database.</p>
</li>
<li><p><strong>EXECTYPE:</strong> Most of the time, this simply says <code>EXECUTED</code>. But it provides a crucial audit trail: if you use Liquibase commands to intentionally skip a migration but record it as finished, you'll see <code>MARK_RAN</code>. If a migration was skipped because its preconditions failed, you'll see <code>SKIPPED</code>.</p>
</li>
<li><p><strong>TAG:</strong> Think of this as a Git tag for your database schema. Before a major, high-risk deployment, you can configure Liquibase to "tag" the current state of the database (for example, <code>v1.4.0</code>). If the deployment fails catastrophically, you can trigger a rollback command telling Liquibase to undo every change applied after the <code>v1.4.0</code> tag.</p>
</li>
<li><p><strong>CONTEXTS:</strong> This is how you manage environment-specific changes. By adding a context attribute to your changeSet (for example, <code>&lt;changeSet id="7" author="ashutoshkrris" context="dev, qa"&gt;</code>), that migration will only execute if Spring Boot passes "dev" or "qa" to Liquibase on startup. Production will safely ignore it.</p>
</li>
<li><p><strong>LABELS:</strong> While Contexts target environments, Labels target categories of work. You can label a changeSet with a Jira ticket number (<code>issue-842</code>) or a release train (<code>Q3-release</code>). This allows advanced teams to selectively execute or roll back specific subsets of features without affecting the rest of the database.</p>
</li>
</ul>
<h3 id="heading-the-databasechangeloglock-table">The <code>DATABASECHANGELOGLOCK</code> Table</h3>
<p>This table is tiny, but it plays a massive role in modern deployments.</p>
<p>If you run <code>SELECT * FROM DATABASECHANGELOGLOCK;</code>, you'll see a single row:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>LOCKED</th>
<th>LOCKGRANTED</th>
<th>LOCKEDBY</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>FALSE</td>
<td><em>null</em></td>
<td><em>null</em></td>
</tr>
</tbody></table>
<p>Imagine you're deploying your Spring Boot application to a Kubernetes cluster. You tell Kubernetes to spin up three identical instances simultaneously. All three instances connect to the exact same database.</p>
<p>If all three instances try to run the <code>CREATE TABLE</code> migration at the exact same millisecond, your database will throw concurrency errors. The lock table prevents this. The very first instance to reach the database sets <code>LOCKED</code> to <code>TRUE</code>. The other two instances check the table, see the lock, and politely wait.</p>
<p><strong>Practical Troubleshooting Tip:</strong> Sometimes, a deployment fails catastrophically mid-migration (perhaps the server lost power). When this happens, Liquibase might die before it can set <code>LOCKED</code> back to <code>FALSE</code>.</p>
<p>The next time you start the application, the logs will hang indefinitely, repeating: <code>Waiting for changelog lock....</code></p>
<p>If you're absolutely certain no other applications are currently running migrations, you can manually fix this by running a simple SQL command in your database client:</p>
<pre><code class="language-sql">UPDATE DATABASECHANGELOGLOCK SET LOCKED = FALSE;
</code></pre>
<p>This forces the lock open, allowing your application to resume.</p>
<h2 id="heading-evolving-the-employee-api">Evolving the Employee API</h2>
<p>Software is never finished. Two weeks after your successful Version 1 deployment, the business team comes back with new requirements.</p>
<p>Because you now understand how Liquibase tracks history, evolving the database is simple. You just append new files to your master list.</p>
<h3 id="heading-version-2-adding-an-email-field">Version 2: Adding an Email Field</h3>
<p>The HR team needs to contact employees. You need an email column.</p>
<p>Create a new file at <code>src/main/resources/db/changelog/changes/02-add-employee-email.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="2" author="ashutoshkrris"&gt;
        &lt;addColumn tableName="employees"&gt;
            &lt;column name="email" type="VARCHAR(100)"&gt;
                &lt;constraints nullable="false" unique="true"/&gt;
            &lt;/column&gt;
        &lt;/addColumn&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Add this to your <code>db.changelog-master.xml</code> file immediately below your first include:</p>
<pre><code class="language-xml">&lt;include file="db/changelog/changes/02-add-employee-email.xml"/&gt;
</code></pre>
<p>When you restart the application, Liquibase checks the <code>DATABASECHANGELOG</code> table. It sees that <code>id="1"</code> is already there, so it skips it. It sees <code>id="2"</code> is missing, so it executes it and adds a new row to the tracking table.</p>
<h3 id="heading-version-3-adding-departments-support">Version 3: Adding Departments Support</h3>
<p>The company is growing. Employees now belong to departments. You need a <code>departments</code> table and a foreign key constraint linking the two.</p>
<p>Create <code>03-add-departments.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="3" author="ashutoshkrris"&gt;
        &lt;createTable tableName="departments"&gt;
            &lt;column name="id" type="BIGINT" autoIncrement="true"&gt;
                &lt;constraints primaryKey="true" nullable="false"/&gt;
            &lt;/column&gt;
            &lt;column name="name" type="VARCHAR(50)"&gt;
                &lt;constraints nullable="false" unique="true"/&gt;
            &lt;/column&gt;
        &lt;/createTable&gt;
    &lt;/changeSet&gt;

    &lt;changeSet id="4" author="ashutoshkrris"&gt;
        &lt;addColumn tableName="employees"&gt;
            &lt;column name="department_id" type="BIGINT"/&gt;
        &lt;/addColumn&gt;
        &lt;addForeignKeyConstraint baseTableName="employees"
                                 baseColumnNames="department_id"
                                 constraintName="fk_employee_department"
                                 referencedTableName="departments"
                                 referencedColumnNames="id"/&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Notice that we used two separate changeSets in one file. This is a best practice. Each changeSet represents one logical operation. If the foreign key creation (id="4") fails, the department table creation (id="3") will still be recorded as successful, and only id="4" will roll back.</p>
<h3 id="heading-version-4-amp-5-employee-status-and-performance-indexes">Version 4 &amp; 5: Employee Status and Performance Indexes</h3>
<p>Finally, HR wants to track active versus inactive staff, and the database team noticed that searching by last name is getting slow.</p>
<p>Create <code>04-status-and-indexes.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="3" author="ashutoshkrris"&gt;
        &lt;createTable tableName="departments"&gt;
            &lt;column name="id" type="BIGINT" autoIncrement="true"&gt;
                &lt;constraints primaryKey="true" nullable="false"/&gt;
            &lt;/column&gt;
            &lt;column name="name" type="VARCHAR(50)"&gt;
                &lt;constraints nullable="false" unique="true"/&gt;
            &lt;/column&gt;
        &lt;/createTable&gt;
    &lt;/changeSet&gt;

    &lt;changeSet id="4" author="ashutoshkrris"&gt;
        &lt;addColumn tableName="employees"&gt;
            &lt;column name="department_id" type="BIGINT"/&gt;
        &lt;/addColumn&gt;
        &lt;addForeignKeyConstraint baseTableName="employees"
                                 baseColumnNames="department_id"
                                 constraintName="fk_employee_department"
                                 referencedTableName="departments"
                                 referencedColumnNames="id"/&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Remember to add all new files to your <code>db.changelog-master.xml</code>. The order of your include statements is the exact order Liquibase will execute them.</p>
<h2 id="heading-the-golden-rule-never-modify-executed-changesets">The Golden Rule: Never Modify Executed ChangeSets</h2>
<p>Eventually, a developer on your team will look at your <code>01-create-employees.xml</code> file and notice a mistake. Perhaps they spot a typo in a column name, or perhaps they realize a column is missing a strict non-null constraint.</p>
<p>Their instinct, based on years of writing standard Java code, will be to open that XML file, fix the mistake, save the file, and restart the application.</p>
<p>Let's actually do this and see what happens.</p>
<p>Open your <code>src/main/resources/db/changelog/changes/01-create-employees.xml</code> file. Change the <code>first_name</code> column to <code>given_name</code>:</p>
<pre><code class="language-xml">&lt;column name="given_name" type="VARCHAR(50)"&gt;
    &lt;constraints nullable="false"/&gt;
&lt;/column&gt;
</code></pre>
<p>Save the file and restart your Spring Boot application.</p>
<p>Instead of a smooth startup, your application will instantly crash, and your terminal will vomit a massive stack trace. Look closely at the top of the error logs. You should see this exact message:</p>
<pre><code class="language-shell">Caused by: liquibase.exception.ValidationFailedException: Validation Failed:
     1 changesets check sum
          db/changelog/changes/01-create-employees.xml::1::ashutoshkrris was: 9:66e7dcffb2b1902a4e9f01670cb5f192 but is now: 9:2bd3ef21343d3b5c9448cc50bc35deef
</code></pre>
<p>Here's why this happens. Once a changeSet runs against an environment, it becomes immutable history. You can't change the past.</p>
<p>When Liquibase starts up, it calculates a cryptographic hash (an MD5 checksum) of your local XML file. It then queries the <code>DATABASECHANGELOG</code> table and compares the freshly calculated hash against the hash that was recorded when the file originally executed.</p>
<p>If you change even a single character in a file that has already been executed, the hash changes. Liquibase detects the tampering and refuses to start. It does this to protect your data. If your XML code says a column is named <code>first_name</code> but the database was originally built using <code>fist_name</code>, your Spring Data JPA repositories are going to fail anyway.</p>
<h3 id="heading-how-to-fix-it-the-right-way">How to Fix It (The Right Way)</h3>
<p>If you made this mistake locally, you might be tempted to go into your database, delete the row from the <code>DATABASECHANGELOG</code> table, and try again. Don't do this. If this code reaches staging or production, you can't manually delete rows on production servers.</p>
<p>The correct way to fix a schema mistake is to <strong>roll forward</strong>.</p>
<p>First, undo your change in <code>01-create-employees.xml</code> so the hash matches the database again. Then, write a brand new changeSet to apply the fix:</p>
<pre><code class="language-xml">&lt;changeSet id="7" author="ashutosh"&gt;
    &lt;renameColumn tableName="employees" 
                  oldColumnName="first_name" 
                  newColumnName="given_name" 
                  columnDataType="VARCHAR(50)"/&gt;
&lt;/changeSet&gt;
</code></pre>
<p>Include it in your master changelog, restart the application, and the database will safely evolve to the correct state.</p>
<h2 id="heading-working-with-seed-data">Working with Seed Data</h2>
<p>Sometimes, a schema change requires initial data to be useful.</p>
<p>For example, in Version 3, we created a <code>departments</code> table. Right now, that table is completely empty. When a new developer clones the repository and spins up the project locally, they have to manually write SQL <code>INSERT</code> statements just to test the API.</p>
<p>We can automate this by making baseline data insertion part of our migration strategy.</p>
<p>Create a new file at <code>src/main/resources/db/changelog/changes/05-seed-departments.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="8" author="ashutoshkrris"&gt;
        &lt;insert tableName="departments"&gt;
            &lt;column name="name" value="Engineering"/&gt;
        &lt;/insert&gt;
        &lt;insert tableName="departments"&gt;
            &lt;column name="name" value="Human Resources"/&gt;
        &lt;/insert&gt;
        &lt;insert tableName="departments"&gt;
            &lt;column name="name" value="Finance"/&gt;
        &lt;/insert&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Add the include statement to your <code>db.changelog-master.xml</code> file. When you restart the application, Liquibase will insert these rows. Your API is now instantly usable out of the box.</p>
<h3 id="heading-the-danger-of-data-migrations">The Danger of Data Migrations</h3>
<p>While seeding data is powerful, it requires discipline. Here is a practical engineering rule of thumb:</p>
<p><strong>Do use Liquibase for:</strong></p>
<ul>
<li><p>Static lookup tables (status codes, country lists, default departments).</p>
</li>
<li><p>System configuration flags required for the application to boot.</p>
</li>
</ul>
<p><strong>Do NOT use Liquibase for:</strong></p>
<ul>
<li><p>Generating thousands of fake users for testing.</p>
</li>
<li><p>Migrating massive amounts of transactional data (for example, moving 5 million records from one table to another).</p>
</li>
</ul>
<p>Large data migrations can lock up database tables for hours. If you lock a core table during a deployment, your application will experience a massive outage. Keep your changeSets focused on schema structure and essential baseline data. Use dedicated scripts or background jobs for heavy data manipulation.</p>
<h2 id="heading-rollbacks">Rollbacks</h2>
<p>In a perfect world, code always works. In reality, you'll eventually deploy a database change that breaks a critical production query or corrupts data. When this happens, you need a way to hit the undo button.</p>
<p>Liquibase supports rollbacks, but you have to understand how it interprets them.</p>
<h3 id="heading-automatic-vs-explicit-rollbacks">Automatic vs. Explicit Rollbacks</h3>
<p>Many Liquibase commands are automatically reversible. For example, if you write a changeSet to <code>&lt;createTable&gt;</code> or <code>&lt;addColumn&gt;</code>, Liquibase implicitly knows that the opposite of adding a column is dropping a column. You don't have to tell it how to undo these actions.</p>
<p>But some operations are inherently destructive or ambiguous. If you use custom <code>&lt;sql&gt;</code> tags, or if you use <code>&lt;dropTable&gt;</code>, Liquibase has no idea how to put the data back. In these cases, you must provide explicit rollback instructions.</p>
<p>Let's simulate a scenario where we add a temporary access code column, but we want to ensure we know exactly how to remove it safely.</p>
<p>Create <code>06-temporary-access.xml</code>:</p>
<pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
        http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd"&gt;

    &lt;changeSet id="9" author="ashutosh"&gt;
        &lt;addColumn tableName="employees"&gt;
            &lt;column name="temp_access_code" type="VARCHAR(10)"/&gt;
        &lt;/addColumn&gt;
        
        &lt;rollback&gt;
            &lt;dropColumn tableName="employees" columnName="temp_access_code"/&gt;
        &lt;/rollback&gt;
    &lt;/changeSet&gt;

&lt;/databaseChangeLog&gt;
</code></pre>
<p>Add this to your master file and run the application. The column is added.</p>
<p>If you were deploying this via a CI/CD pipeline and the deployment failed, you could trigger a Liquibase Maven command to roll back by a specific number of steps (for example, <code>mvn liquibase:rollback -Dliquibase.rollbackCount=1</code>), or roll back to a specific tag we discussed earlier.</p>
<h3 id="heading-the-reality-check-on-rollbacks">The Reality Check on Rollbacks</h3>
<p>While it's important to know how rollbacks work, here's a practical reality from the trenches of backend engineering: <strong>Rollbacks are often discussed but rarely executed cleanly in production.</strong></p>
<p>Dropping a column is mathematically easy. Recovering the customer data that was written to that column during the 15 minutes the bad code was live is incredibly difficult.</p>
<p>Because of this, modern engineering teams often prefer a "roll forward" strategy. If a migration causes an issue, instead of running a scary database rollback command, they quickly write a new changeSet that fixes the issue (for example, adding a missing index or relaxing a constraint) and deploy the application again.</p>
<p>It's highly recommended to design your database changes to be additive and non-destructive to avoid needing complex rollbacks in the first place.</p>
<h2 id="heading-common-beginner-mistakes">Common Beginner Mistakes</h2>
<p>Adopting database version control is a massive step forward for any engineering team, but it comes with a learning curve. When developers transition from writing loose SQL scripts to using Liquibase, they tend to fall into a few predictable traps.</p>
<p>Here are the most common beginner mistakes and exactly how to avoid them.</p>
<h3 id="heading-1-the-mega-changeset">1. The "Mega" ChangeSet</h3>
<p>When starting out, it's tempting to dump your entire initial schema into a single XML file under a single <code>changeSet</code>. You might put 15 <code>createTable</code> statements and 20 <code>addForeignKeyConstraint</code> statements into <code>id="1"</code>.</p>
<p>This is a terrible idea for one simple reason: transaction failure.</p>
<p>If your database engine fails on table number 14 (perhaps due to a syntax error), what happens to the first 13 tables? Some database engines support transactional DDL (Data Definition Language), meaning it will roll back all 13 tables automatically. But many databases do not.</p>
<p>If it fails halfway through, your database is now in a fractured state. Liquibase didn't record <code>id="1"</code> as successful, so the next time you start the app, it will try to create all 15 tables again. It will immediately crash because table 1 already exists.</p>
<p><strong>The Fix:</strong> Stick to the rule of "one logical operation per changeSet." If you're creating three tables, write three separate changeSets. If one fails, the successful ones are permanently recorded, and you only have to fix the broken one.</p>
<h3 id="heading-2-manual-database-tweaking-the-phantom-menace">2. Manual Database Tweaking (The Phantom Menace)</h3>
<p>This is the most dangerous habit to break. A developer spots a missing index in production. Instead of writing a Liquibase migration, going through code review, and deploying, they log directly into the production database and run <code>CREATE INDEX</code> manually to save time.</p>
<p>A week later, another developer writes a proper Liquibase migration to create that exact same index and deploys it. The application crashes on startup. Liquibase tries to execute the <code>CREATE INDEX</code> command, but the database throws an error saying the index already exists.</p>
<p>When you adopt Liquibase, you must accept a fundamental rule: <strong>Liquibase is the absolute source of truth for your schema.</strong> Human hands should never touch the database structure directly.</p>
<p><strong>The Fix:</strong> If someone accidentally does this, you have two options to fix the deployment pipeline. You can manually drop the index from the database so Liquibase can recreate it properly, or you can use the <code>&lt;preConditions&gt;</code> tag in Liquibase to check if the index exists before trying to create it.</p>
<h3 id="heading-3-ignoring-the-from-scratch-build">3. Ignoring the "From Scratch" Build</h3>
<p>When you work on a project for months, your local database accumulates a lot of history. You write migrations assuming certain tables or test data already exist.</p>
<p>Then, a new developer joins the team. They pull the code, spin up an empty database, start Spring Boot, and the migrations crash halfway through.</p>
<p>This happens because the migrations rely on an assumed state (like expecting a specific row to exist before creating a foreign key) rather than a guaranteed state.</p>
<p><strong>The Fix:</strong> You should regularly test your migrations against a completely blank database. If you're using Docker, tear down your database container and rebuild it. If you're using a file-based H2 database like we set up earlier, simply delete the <code>./data/employeedb.mv.db</code> file from your project folder and restart Spring Boot. If the application can't boot successfully from a completely empty state, your migration history is broken.</p>
<h3 id="heading-4-hardcoding-environment-details">4. Hardcoding Environment Details</h3>
<p>Beginners sometimes hardcode environment-specific details directly into their XML files. For example, they might hardcode a specific schema name (schemaName="dev_schema") or grant permissions to a specific local user (GRANT ALL ON employees TO my_local_user).</p>
<p>When this code goes to staging, the staging database uses a different schema name, and the deployment fails.</p>
<p>The Fix: Keep your migrations abstract. Let Spring Boot handle the connection details via application.properties. If you absolutely must use dynamic values inside your Liquibase files, use property substitution. You can define variables in Liquibase and pass them in from Spring Boot during startup.</p>
<h3 id="heading-5-messing-up-migration-ordering">5. Messing Up Migration Ordering</h3>
<p>Liquibase executes files in the exact order they're listed in your <code>db.changelog-master.xml</code> file.</p>
<p>If developer A creates the <code>departments</code> table in a branch, and developer B creates a foreign key linking to <code>departments</code> in another branch, whoever merges their code first dictates the order. If developer B's code gets included in the master file <em>before</em> developer A's code, Liquibase will try to create the foreign key before the target table exists.</p>
<p><strong>The Fix:</strong> The master changelog is the ultimate chokepoint for database changes. During code reviews, always verify that the <code>&lt;include&gt;</code> statements are ordered chronologically and that dependencies make sense.</p>
<h2 id="heading-liquibase-vs-flyway-vs-manual-sql-scripts">Liquibase vs Flyway vs Manual SQL Scripts</h2>
<p>When you decide to implement database version control, you'll immediately face a choice. Liquibase isn't the only tool in the Java ecosystem. The three most common approaches to managing schema evolution are Liquibase, Flyway, and manual SQL scripts.</p>
<p>You should understand the practical tradeoffs of each so you can choose the right tool for your specific team and project.</p>
<h3 id="heading-1-manual-sql-scripts-the-baseline">1. Manual SQL Scripts (The Baseline)</h3>
<p>This is the default approach for most beginners. You write a script.sql file and execute it directly against the database using a tool like DBeaver, pgAdmin, or DataGrip.</p>
<ul>
<li><p><strong>Strengths:</strong> There is zero setup required. You have total control over the exact syntax, and every backend developer already knows how to write SQL.</p>
</li>
<li><p><strong>Weaknesses:</strong> There's absolutely no execution tracking. This approach practically guarantees schema drift across environments. Deployments become stressful because they rely on humans remembering to execute the right scripts in the exact right order.</p>
</li>
<li><p><strong>The Verdict:</strong> Manual scripts are perfectly fine for solo weekend projects or rapid prototyping where you don't care if the database gets destroyed. But they become a massive liability the moment a second developer joins the team or a staging environment is created.</p>
</li>
</ul>
<h3 id="heading-2-flyway-the-sql-purist">2. Flyway (The SQL Purist)</h3>
<p>Flyway is the most popular alternative to Liquibase. Instead of using XML or YAML abstractions, Flyway embraces raw SQL. You write pure SQL files with a strict naming convention (for example, V1__Create_employee_table.sql).</p>
<ul>
<li><p><strong>Strengths:</strong> There's no new syntax to learn. If you know SQL, you already know how to use Flyway. It's incredibly fast to set up, highly opinionated, and integrates flawlessly with Spring Boot.</p>
</li>
<li><p><strong>Weaknesses:</strong> Because you write raw SQL, your migrations are intimately tied to your specific database dialect. If you write Flyway scripts for MySQL and later decide to migrate the project to PostgreSQL, you have to manually rewrite your migration history. Furthermore, seamless automated rollbacks are a paid feature in Flyway's commercial tier.</p>
</li>
<li><p><strong>The Verdict:</strong> Flyway is excellent for teams that are highly skilled in SQL, are permanently committed to a single database vendor, and prefer strict conventions over flexible configurations.</p>
</li>
</ul>
<h3 id="heading-3-liquibase-the-abstraction-layer">3. Liquibase (The Abstraction Layer)</h3>
<p>As we have seen throughout this tutorial, Liquibase takes a different approach by abstracting database changes into XML, YAML, or JSON.</p>
<ol>
<li><p><strong>Strengths:</strong> It's truly database-agnostic. You define the logical structure, and Liquibase automatically translates that into the correct SQL dialect for H2, PostgreSQL, or Oracle. It supports powerful automatic rollbacks, preconditions, contexts, and deployment labels out of the box for free.</p>
</li>
<li><p><strong>Weaknesses:</strong> It has a steeper learning curve than Flyway. The XML syntax is undeniably verbose and can feel heavy for very simple, single-table applications.</p>
</li>
<li><p><strong>The Verdict:</strong> Liquibase shines in complex applications, multi-tenant systems, projects that support multiple database vendors, and enterprise environments that require fine-grained control over CI/CD deployment pipelines.</p>
</li>
</ol>
<h2 id="heading-liquibase-best-practices">Liquibase Best Practices</h2>
<p>Now that you understand the mechanics of Liquibase, you need to know how to use it in a professional environment. Writing a migration that works on your local machine is only half the battle. Writing a migration that your entire team can safely deploy to production requires discipline.</p>
<p>Here are the engineering best practices you should adopt when managing database changes.</p>
<h3 id="heading-1-one-logical-change-per-changeset-the-atomic-rule">1. One Logical Change Per ChangeSet (The Atomic Rule)</h3>
<p>We discussed this in the common mistakes section, but it's important enough to repeat. Never bundle a table creation, an index creation, and a data insertion into a single changeSet.</p>
<p>If you're adding a salary column and an idx_employee_salary index, put them in two separate changeSets within the same file. This ensures that if the index creation fails, the column creation is still safely recorded, and you don't end up in a fractured database state.</p>
<h3 id="heading-2-meaningful-file-organization-and-naming">2. Meaningful File Organization and Naming</h3>
<p>Don't name your files <code>update1.xml</code> or <code>new_changes.xml</code>. Your file names should tell a story about how your database evolved.</p>
<p>Adopt a strict prefix system. In our project, we used <code>01-create-employees.xml</code> and <code>02-add-employee-email.xml</code>. In a real team, you might use Jira ticket numbers or release versions (for example, <code>v1.2.0_ticket-482_add_email.xml</code>). Whatever convention you choose, enforce it rigorously during code reviews.</p>
<h3 id="heading-3-treat-database-changes-like-application-code">3. Treat Database Changes Like Application Code</h3>
<p>Database migrations belong in source control right next to your Java code. They should be reviewed with the exact same level of scrutiny.</p>
<p>When reviewing a pull request that includes a Liquibase file, engineers should ask:</p>
<ul>
<li><p>Does this column need an index?</p>
</li>
<li><p>Is this a destructive change (like renaming a column) that will break the currently running application?</p>
</li>
<li><p>Did the author include explicit rollback instructions for custom SQL?</p>
</li>
</ul>
<h3 id="heading-4-integrate-migrations-into-cicd">4. Integrate Migrations into CI/CD</h3>
<p>Human hands should never run database migrations against a production server. Your deployment pipeline should handle this automatically.</p>
<p>When you merge code into your main branch, your CI/CD pipeline (like GitHub Actions or GitLab CI) should build your Spring Boot application and deploy it. Because we bundled Liquibase into our Spring Boot startup sequence, the application will automatically migrate the production database before it starts accepting web traffic.</p>
<p>Here's what a safe, automated deployment pipeline looks like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/61c1acb4a90dea775da8262b/7a9323e6-c44a-4ee5-8307-3ee8a696c3a9.png" alt="CI/CD pipeline architecture showing code moving from Git to testing, deploying to a staging environment where Liquibase runs, and then promoting to production." style="display:block;margin:0 auto" width="677" height="657" loading="lazy">

<p>In a mature deployment pipeline, human hands never touch the production database. When you merge a pull request, the CI/CD pipeline builds the code and runs unit tests. It deploys the Spring Boot application to a staging environment, where Liquibase automatically acquires a lock and runs the migrations during startup. Once validated, that exact same artifact is promoted to production, triggering the identical automated migration process.</p>
<h3 id="heading-5-never-fix-forward-by-deleting-history">5. Never Fix Forward by Deleting History</h3>
<p>If a migration fails in an upper environment (like staging or production), never log into the database to delete the <code>DATABASECHANGELOG</code> row so you can try again.</p>
<p>You must respect the immutability of the changelog. If you made a mistake, write a new changeSet that drops the broken table or fixes the data type, and push it through your Git workflow just like you would a Java bug fix.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Managing database schema changes doesn't have to be a source of anxiety.</p>
<p>By treating your database schema as code, you eliminate the chaos of manual SQL scripts. You prevent the dreaded "schema drift" where every developer's local machine behaves differently. Most importantly, you make your deployments predictable and boring (which is exactly what you want deployments to be).</p>
<p>In this tutorial, you built a practical Spring Boot application from scratch. You learned how Liquibase intercepts the application startup, locks the database, calculates cryptographic checksums, and safely applies incremental changes. You evolved a single table into a relational schema, added seed data, and learned how to avoid the most common traps beginners fall into.</p>
<p>The next time you start a Spring Boot project, don't reach for a manual SQL client. Add the Liquibase dependency, create your master changelog, and start version controlling your database from day one. Your future self (and your team) will thank you.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ OpenFeign vs WebClient: How to Choose a REST Client for Your Spring Boot Project ]]>
                </title>
                <description>
                    <![CDATA[ When building microservices with Spring Boot, you’ll have to decide how the services will communicate with one another. The basic choices in terms of protocols are Messaging and REST. In this article we’ll discuss tools based on REST, which is a comm... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/best-choice-openfeign-or-webclient/</link>
                <guid isPermaLink="false">6841f2c63a801418642db429</guid>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Microservices ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mario Casari ]]>
                </dc:creator>
                <pubDate>Thu, 05 Jun 2025 19:40:54 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749152217156/dc3e8896-b084-4bec-a549-b51a821f7d69.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building microservices with Spring Boot, you’ll have to decide how the services will communicate with one another. The basic choices in terms of protocols are Messaging and <a target="_blank" href="https://www.freecodecamp.org/news/tag/rest-api/">REST</a>. In this article we’ll discuss tools based on REST, which is a common protocol for microservices. Two well-known tools are <a target="_blank" href="https://codingstrain.com/rest-clients-with-openfeign-how-to-implement-them/"><strong>OpenFeign</strong></a> and <a target="_blank" href="https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html"><strong>WebClient</strong></a>.</p>
<p>You’ll learn how they differ in their approaches, use cases, and design. You’ll then have the necessary information to make a proper choice.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-introduction-to-openfeign">Introduction to OpenFeign</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-introduction-to-webclient">Introduction to WebClient</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-main-differences">Main Differences</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-considerations">Performance Considerations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-use-cases">Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-introduction-to-openfeign">Introduction to OpenFeign</h2>
<p>OpenFeign is an HTTP client tool developed originally by Netflix and now maintained as an open-source community project. In the Spring Cloud ecosystem, OpenFeign allows you to define REST clients using annotated Java interfaces, reducing boilerplate code.</p>
<p>A basic OpenFeign client looks like this:</p>
<pre><code class="lang-java"><span class="hljs-meta">@FeignClient(name = "book-service")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BookClient</span> </span>{
    <span class="hljs-meta">@GetMapping("/books/{id}")</span>
    <span class="hljs-function">User <span class="hljs-title">getBookById</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable("id")</span> Long id)</span></span>;
}
</code></pre>
<p>You can then inject <code>BookClient</code> like any Spring Bean:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookService</span> </span>{
    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">private</span> BookClient bookClient;

    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">getBook</span><span class="hljs-params">(Long id)</span> </span>{
        <span class="hljs-keyword">return</span> bookClient.getBookById(id);
    }
}
</code></pre>
<p>OpenFeign is well integrated with Spring Cloud Discovery Service (Eureka), Spring Cloud Config, and Spring Cloud LoadBalancer. This makes it perfect for service-to-service calls in a microservice architecture based on Spring Cloud. It has several important features.</p>
<ul>
<li><p>Declarative syntax: It uses interfaces and annotations to define HTTP clients, avoiding manual request implementation.</p>
</li>
<li><p>Spring Cloud integration: It integrates well with the components of Spring Cloud, like Service Discovery (Eureka), Spring Config, and Load Balancer.</p>
</li>
<li><p>Retry and fallback mechanisms: It can be easily integrated with Spring Cloud Circuit Breaker or Resilience4j.</p>
</li>
<li><p>Custom configurations: You can customize many aspects, like headers, interceptors, logging, timeouts, and encoders/decoders.</p>
</li>
</ul>
<h2 id="heading-introduction-to-webclient">Introduction to WebClient</h2>
<p>WebClient is a reactive HTTP client, and it’s part of the <a target="_blank" href="https://medium.com/@bolot.89/an-introduction-to-spring-webflux-reactive-programming-made-easy-f70050f4c6c6"><strong>Spring WebFlux</strong></a> module. It is mainly based on non-blocking asynchronous HTTP communication, but it can also deal with synchronous calls.</p>
<p>While OpenFeign follows a declarative design, WebClient offers an imperative, fluent API.</p>
<p>Here’s a basic example of using WebClient synchronously:</p>
<pre><code class="lang-java">WebClient client = WebClient.create(<span class="hljs-string">"http://book-service"</span>);

User user = client.get()
        .uri(<span class="hljs-string">"/books/{id}"</span>, <span class="hljs-number">1L</span>)
        .retrieve()
        .bodyToMono(Book.class)
        .block(); <span class="hljs-comment">// synchronous</span>
</code></pre>
<p>Or asynchronously:</p>
<pre><code class="lang-java">Mono&lt;User&gt; bookMono = client.get()
        .uri(<span class="hljs-string">"/books/{id}"</span>, <span class="hljs-number">1L</span>)
        .retrieve()
        .bodyToMono(Book.class);
</code></pre>
<p>Being designed to be non-blocking and reactive, WebClient gives its best with high-throughput, I/O intensive operations. This is particularly true if the entire stack is reactive.</p>
<h2 id="heading-main-differences">Main Differences</h2>
<h3 id="heading-programming-model">Programming Model</h3>
<ul>
<li><p><strong>OpenFeign</strong>: Declarative. You just have to define interfaces. The framework will provide implementations of those interfaces.</p>
</li>
<li><p><strong>WebClient</strong>: Programmatic. You use an imperative, fluent API to implement HTTP calls.</p>
</li>
</ul>
<h3 id="heading-synchronousasynchronous-calls">Synchronous/Asynchronous Calls</h3>
<ul>
<li><p><strong>OpenFeign</strong>: Based on synchronous calls. You require customization or third-party extensions to implement asynchronous behavior.</p>
</li>
<li><p><strong>WebClient</strong>: Asynchronous and non-blocking. It fits well with systems based on a reactive stack.</p>
</li>
</ul>
<h3 id="heading-integration-with-spring-cloud">Integration with Spring Cloud</h3>
<ul>
<li><p><strong>OpenFeign</strong>: It integrates well with the Spring Cloud stack, such as service discovery (Eureka), client-side load balancing, and circuit breakers.</p>
</li>
<li><p><strong>WebClient</strong>: It integrates with Spring Cloud, but additional configuration is required for some features, like load balancing.</p>
</li>
</ul>
<h3 id="heading-boilerplate-code">Boilerplate Code</h3>
<ul>
<li><p><strong>OpenFeign</strong>: You have to define only the endpoint with Interfaces, and the rest is implemented automatically by the framework.</p>
</li>
<li><p><strong>WebClient</strong>: You have a little more code to write and more explicit configuration.</p>
</li>
</ul>
<h3 id="heading-error-handling">Error Handling</h3>
<ul>
<li><p><strong>OpenFeign</strong>: You require custom error handling or fallbacks by <a target="_blank" href="https://stackoverflow.com/questions/39349591/what-is-hystrix-in-spring">Hystrix</a> or <a target="_blank" href="https://codingstrain.com/how-to-implement-circuit-breaker-pattern-with-spring-cloud/">Resilience4j</a>.</p>
</li>
<li><p><strong>WebClient</strong>: Error handling is more flexible with operators like onStatus() and exception mapping.</p>
</li>
</ul>
<h2 id="heading-performance-considerations">Performance Considerations</h2>
<p>When high throughput is not the main concern, OpenFeign is a better choice, since it is well-suited for traditional, blocking applications where simplicity and developer productivity are more important than maximum throughput.</p>
<p>When you have a large number of concurrent requests, such as hundreds or thousands per second, with OpenFeign, you can encounter thread exhaustion problems unless you significantly increase the thread pool sizes. This results in higher memory consumption and increased CPU overhead. For a monolithic application with blocking operations, OpenFeign is better, because mixing blocking and non-blocking models is discouraged.</p>
<p>WebClient is more suitable if your application is I/O bound and has to handle heavy loads. Its non-blocking, reactive nature is excellent for those scenarios, because it can handle more concurrent requests with fewer threads. WebClient does not block a thread while waiting for a response, it releases it immediately to be reused for other work. It also provides a reactive feature called backpressure, used to control the data flow rate. This is useful when dealing with large data streams or when the speed at which clients consume data is too low. It's suited for applications that need to manage thousands of concurrent requests. It is more complex, though, and has a steeper learning curve.</p>
<h2 id="heading-use-cases">Use Cases</h2>
<p><strong>Use OpenFeign When:</strong></p>
<ul>
<li><p>You need to call other services in a Spring Cloud microservice architecture, with tight integration with Service Discovery and Spring Cloud LoadBalancer.</p>
</li>
<li><p>You prefer productivity and simplicity.</p>
</li>
<li><p>You’re bound to a synchronous, blocking model.</p>
</li>
</ul>
<p><strong>Use WebClient When:</strong></p>
<ul>
<li><p>You're using Spring WebFlux to develop the application.</p>
</li>
<li><p>You need full control over request/response handling.</p>
</li>
<li><p>You require high-performance, non-blocking communication.</p>
</li>
<li><p>You want more control over error handling and retry logic.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The architecture and performance requirements of your system guide the choice between OpenFeign and WebClient.</p>
<p>OpenFeign is ideal for synchronous REST calls in a Spring Cloud stack and helps in reducing boilerplate code. WebClient, on the other hand, gives its best for reactive and high-performance applications and is more flexible.</p>
<p>If you're building a traditional microservices system using Spring Boot and Spring Cloud, OpenFeign is most likely to be the obvious choice. If you're in the context of reactive programming or you have to handle thousands of concurrent connections, then WebClient would be a better choice.</p>
<p>Understanding both tools, their pros and cons, is important to make the proper choice.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop a CRUD App with Spring Boot, Neon Postgres, and Azure App Service ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and Neon Postgres. We'll also deploy the application on Azure App Service and make it production-ready by setting up features like autos... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-crud-app-spring-boot-neon-postgres/</link>
                <guid isPermaLink="false">66c3762340438b5931fe0a0b</guid>
                
                    <category>
                        <![CDATA[ Azure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Abhinav Pandey ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jul 2024 19:14:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/neon-banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we'll explore how to develop a CRUD (Create, Read, Update, Delete) application using Spring Boot and <a target="_blank" href="https://neon.tech/">Neon Postgres</a>.</p>
<p>We'll also deploy the application on <a target="_blank" href="https://azure.microsoft.com/en-us/products/app-service">Azure App Service</a> and make it production-ready by setting up features like autoscaling and multiple environments.</p>
<p>You'll learn how Neon Postgres can make your development and deployment processes easier along the way.</p>
<h2 id="heading-heres-what-well-cover">Here's what we'll cover:</h2>
<ul>
<li>Setting up a Neon Postgres database and exploring its features</li>
<li>Building a CRUD application using Spring Boot and deploying the application on Azure App Service</li>
<li>Why Neon is a good fit for infrastructure that auto-scales</li>
<li>Database branching in Neon Postgres and how it can ease the development workflow</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li>Working knowledge of Java, Maven, and Spring Boot</li>
<li>Basics of SQL databases</li>
<li>Understanding of serverless and cloud services</li>
<li>Familiarity with testing and deployment processes</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-neon-postgres">What is Neon Postgres?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-database">How to Set Up the Database</a><ul>
<li><a class="post-section-overview" href="#heading-create-the-database">Create the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</a><ul>
<li><a class="post-section-overview" href="#heading-create-an-entity-class">Create an Entity Class</a></li>
<li><a class="post-section-overview" href="#heading-create-a-repository">Create a Repository</a></li>
<li><a class="post-section-overview" href="#heading-create-a-rest-controller">Create a REST Controller</a></li>
<li><a class="post-section-overview" href="#heading-configure-the-database">Configure the Database</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</a><ul>
<li><a class="post-section-overview" href="#heading-create-a-new-web-app">Create a New Web App</a></li>
<li><a class="post-section-overview" href="#heading-deploy-the-application">Deploy the Application</a></li>
<li><a class="post-section-overview" href="#heading-access-the-application">Access the Application</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</a><ul>
<li><a class="post-section-overview" href="#heading-autoscaling-in-azure">Autoscaling in Azure</a></li>
<li><a class="post-section-overview" href="#heading-autoscaling-in-neon">Autoscaling in Neon</a></li>
</ul>
</li>
<li><a class="post-section-overview" href="#heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</a></li>
<li><a class="post-section-overview" href="#heading-summary">Summary</a></li>
</ul>
<h2 id="heading-what-is-neon-postgres">What is Neon Postgres?</h2>
<p>Neon is a fully managed serverless Postgres database platform. It offers features such as high availability, automatic backups, and scaling options to handle varying traffic levels.</p>
<p>Neon is designed to be cost-efficient and developer-friendly, and it focuses on providing a seamless experience for developers.</p>
<p>In addition to the standard Postgres features, it provides capabilities like database branching, allowing you to create Git-like branches of the database for different purposes.</p>
<h2 id="heading-how-to-set-up-the-database">How to Set Up the Database</h2>
<p>To begin with, let's explore how you can set up a Neon database for your application.</p>
<p>Firstly, you'll need to <a target="_blank" href="https://console.neon.tech/signup">create an account</a> on the Neon website. It doesn't require a credit card to sign up, and you're automatically set up with the free tier to get started.</p>
<p>Here's a <a target="_blank" href="https://neon.tech/pricing">pricing and features comparison</a> of Neon plans:</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Finxumg46sf92ffre6l2q.png" alt="A screenshot of pricing plans in Neon listing down free and paid features" width="800" height="400" loading="lazy">
<em>Neon pricing plans</em></p>
<p>In the free tier, we get 0.5 GB of storage with basic computing which is enough for playing around with the database and building small applications.</p>
<h3 id="heading-create-the-database">Create the Database</h3>
<p>Once you've signed up, you can access the dashboard and create a new project.</p>
<p>Star by filling in the project name, region, and Postgres version options. In addition to this, we can choose two additional options:</p>
<ul>
<li><strong>compute size</strong> – You can choose a min and max compute size for the database. This is useful for autoscaling the database based on the load.</li>
<li><strong>suspend time</strong> – You can set a time after which the database will be suspended if not being used. This is useful for saving costs when the database is not being used.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggwuvqtb8ydl3mxd1dak.png" alt="Form with specifications required when creating a database" width="800" height="662" loading="lazy">
<em>Creating a database project in Neon</em></p>
<p>Once you submit the form, Neon will create the database and provide the connection details.</p>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwe2x5d81euphg2owgxhd.png" alt="Neon Dashboard showing the project is ready. Also shows connection details." width="800" height="400" loading="lazy">
<em>Neon Dashboard</em></p>
<p>As you can see, the database was set up in 3.3 seconds (compared to hours of installing and setting up your own infrastructure). You can choose multiple ways to connect to the database. For this tutorial, select Java as your programming language and get the JDBC connection string.</p>
<h2 id="heading-how-to-build-the-spring-boot-crud-app">How to Build the Spring Boot CRUD App</h2>
<p>Next, let's set up our CRUD application. We'll use Spring Boot, as it provides easy bootstrapping and configuration for building web applications.</p>
<p>We can use the <a target="_blank" href="https://start.spring.io/">Spring Initializr</a> to generate a new Spring Boot project with the necessary dependencies:</p>
<ul>
<li>Spring Web – for building web applications</li>
<li>Spring Data JPA – for working with databases using JPA</li>
<li>PostGres Driver – for connecting to the Postgres database</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffifv17tc5d3swothe3zf.png" alt="Spring Initializer website form to select spring boot project specifications and dependencies" width="800" height="400" loading="lazy">
<em>Creating a Spring Boot project using Spring Initializer</em></p>
<p>You can generate, download, and import the project into your favorite IDE.</p>
<h3 id="heading-create-an-entity-class">Create an Entity Class</h3>
<p>Let's create an entity class to represent the data in the application. First, create a <code>User</code> class:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Entity(name = "users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{
    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.IDENTITY)</span>
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String email;

    <span class="hljs-comment">// Constructors, Getters and Setters</span>
}
</code></pre>
<p>The entity name <code>users</code> is the name of the table you want to use in your database.</p>
<h3 id="heading-create-a-repository">Create a Repository</h3>
<p>Next, create a repository interface to interact with the database. You'll extend the <code>JpaRepository</code> interface provided by Spring Data JPA:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Repository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">Long</span>&gt; </span>{
}
</code></pre>
<p>You need to annotate the interface with <code>@Repository</code> to mark it as a Spring bean. The <code>JpaRepository</code> interface provides methods for CRUD operations like <code>save</code>, <code>findAll</code>, <code>findById</code>, <code>delete</code>, and so on, so you don't need to write the queries manually.</p>
<p>You'll provide your entity class <code>User</code> and the type of the primary key <code>Long</code> as type arguments to the <code>JpaRepository</code> interface.</p>
<h3 id="heading-create-a-rest-controller">Create a REST Controller</h3>
<p>Finally, create a REST controller to handle the CRUD operations. You'll inject the <code>UserRepository</code> into the controller and implement the necessary endpoints:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/users")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserController</span><span class="hljs-params">(UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-meta">@GetMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">getUsers</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findAll();
    }

    <span class="hljs-meta">@PostMapping</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">createUser</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@PutMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">updateUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id, <span class="hljs-meta">@RequestBody</span> User user)</span> </span>{
        user.setId(id);
        <span class="hljs-keyword">return</span> userRepository.save(user);
    }

    <span class="hljs-meta">@DeleteMapping("/{id}")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteUser</span><span class="hljs-params">(<span class="hljs-meta">@PathVariable</span> Long id)</span> </span>{
        userRepository.deleteById(id);
    }
}
</code></pre>
<p>Here are a few things to note:</p>
<ul>
<li>You're using the <code>@RestController</code> annotation to mark the class as a controller that handles REST requests.</li>
<li>The <code>@RequestMapping</code> annotation specifies the base URL for the endpoints.</li>
<li>You're injecting the <code>UserRepository</code> into the controller using constructor injection.</li>
<li>Finally, you're implementing your API endpoints for CRUD operations using the <code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>, and <code>@DeleteMapping</code> annotations.</li>
</ul>
<h3 id="heading-configure-the-database">Configure the Database</h3>
<p>To connect your Spring Boot application to the Neon Postgres database, you need to configure the database URL, username, and password in the <code>application.properties</code> file:</p>
<pre><code>spring.datasource.url=jdbc:postgresql:<span class="hljs-comment">//&lt;db-url&gt;/&lt;db-name&gt;?sslmode=require</span>
spring.datasource.username=&lt;username&gt;
spring.datasource.password=&lt;password&gt;
spring.jpa.hibernate.ddl-auto=update
</code></pre><p>Here, you configured the database URL, username, and password provided by Neon when you created the database. The <code>spring.jpa.hibernate.ddl-auto=update</code> property tells Spring Boot to automatically create the necessary tables or columns based on the entity classes when the application starts.</p>
<h2 id="heading-how-to-deploy-on-azure-app-service">How to Deploy on Azure App Service</h2>
<p>Now that your Spring Boot application is ready, it's time to deploy it on Azure App Service.</p>
<h3 id="heading-create-a-new-web-app">Create a New Web App</h3>
<p>To deploy your Spring Boot application on Azure App Service, you'll first create a new <code>Web App</code>. You can do this through the Azure portal by following these steps:</p>
<ul>
<li>Log in to the <a target="_blank" href="https://portal.azure.com/">Azure portal</a>.</li>
<li>Click on the <code>Create a resource</code> button.</li>
<li>Search for <code>Web App</code> and select the <code>Create</code> option.</li>
<li>Fill in the necessary details like resource group, app name, runtime stack, and region.</li>
<li>Click the <code>Review + create</code> button.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flf2kmh12t8eucd1qa1pg.png" alt="Form for creating a web app in Azure" width="800" height="400" loading="lazy">
<em>Creating a Web App in Azure</em></p>
<h3 id="heading-deploy-the-application">Deploy the Application</h3>
<p>The Web App takes a couple of minutes to create. Once done, you can deploy your Spring Boot application to Azure App Service.</p>
<p>One of the easiest ways to deploy is to package your Spring Boot application as a JAR file and deploy it to Azure App Service using the Azure CLI.</p>
<p>To do this, run the below commands:</p>
<pre><code>mvn package
az webapp deploy --src-path neon-demo<span class="hljs-number">-0.0</span><span class="hljs-number">.1</span>-SNAPSHOT.jar --resource-group learn-ba1a439c<span class="hljs-number">-71</span>ca<span class="hljs-number">-4</span>cab<span class="hljs-number">-9</span>bb1-f5b1331bab04 --name neon-app
</code></pre><p>Here, you're packaging your Spring Boot application using Maven and deploying the JAR file to Azure App Service using the Azure CLI. You've provided the path to the JAR file, the resource group, and the app name you previously configured.</p>
<h3 id="heading-access-the-application">Access the Application</h3>
<p>Once the deployment is complete, you can access your Spring Boot application on Azure App Service by navigating to the URL of the Web App. Your app is available at neon-app.azurewebsites.net</p>
<p>Let's use _curl _to test the endpoints.</p>
<h4 id="heading-create-a-user">Create a User</h4>
<pre><code>curl -X POST -d <span class="hljs-string">'{"name":"John Doe","email":"john@gmail.com"}'</span> https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><p>Here you provide user data in JSON format to create a new user.</p>
<h4 id="heading-get-users">Get Users</h4>
<p>You can also can test that the user was created by fetching all users:</p>
<pre><code>curl -X GET https:<span class="hljs-comment">//neon-app.azurewebsites.net/users</span>
</code></pre><h2 id="heading-how-to-set-up-autoscaling">How to Set Up Autoscaling</h2>
<p>A production application may experience varying levels of traffic, and it's important to scale the application dynamically based on the load.</p>
<p>Let's explore how you can autoscale your application when needed.</p>
<h3 id="heading-autoscaling-in-azure">Autoscaling in Azure</h3>
<p>Azure App Service provides <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal#plan-and-sku-settings">autoscaling options</a> that let you automatically adjust the number of instances as needed.</p>
<p>You can configure autoscaling rules in the Azure portal by following these steps:</p>
<ul>
<li>Navigate to the Web App in the Azure portal.</li>
<li>Click the <code>Scale out (App Service Plan)</code> option from the left menu.</li>
<li>Configure the autoscaling rules – you can choose predefined rules like traffic or create custom rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
<li>Save.</li>
</ul>
<p>Azure will automatically scale the application based on the configured rules.</p>
<h3 id="heading-autoscaling-in-neon">Autoscaling in Neon</h3>
<p>Since your application is automatically scaled based on the load, you'll want to ensure that the database can handle the increased traffic.</p>
<p>Neon provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">autoscaling options</a> to scale the database dynamically based on the load. You can configure autoscaling rules in the Neon dashboard to ensure the database can handle the increased load.</p>
<p>Follow the below steps to configure autoscaling in Neon:</p>
<ol>
<li>Navigate to the Neon dashboard and select the database. Then select the branch to configure autoscaling.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6s84pqhk2avflpjbgrf.png" alt="Neon project dashboard with branches section highlighted " width="800" height="400" loading="lazy">
<em>Selecting a branch from Neon project dashboard</em></p>
<ol start="2">
<li>Click on the <code>Edit</code> button next to the <code>Compute</code> section. Configure the autoscaling rules based on metrics like CPU usage, memory usage, or custom metrics.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkn11nop1zz9xxbfamsr.png" alt="Branch details view in Neon with edit button in the computes section highlighted" width="800" height="400" loading="lazy">
<em>Branch details view in Neon</em></p>
<ol start="3">
<li>Configure the min-max compute size and Save. Neon will automatically scale the database based on the configured rules when needed.</li>
</ol>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmuow8zvndz0dibv2kxt.png" alt="Form to enable autoscaling and select min and max size of the compute" width="800" height="400" loading="lazy">
<em>Setting up autoscaling for compute</em></p>
<p>Ensuring that both the application and the database can scale dynamically based on the load will help you handle varying levels of traffic efficiently.</p>
<h2 id="heading-how-to-configure-database-branches-in-neon">How to Configure Database Branches in Neon</h2>
<p>In a typical development workflow, multiple databases may be used for different purposes like development, testing, and production.</p>
<p>Neon Postgres provides <a target="_blank" href="https://neon.tech/docs/introduction/autoscaling">database branching</a> to create multiple branches for different purposes. Each branch is an instance of the database that you can use independently.</p>
<p>This Git-like feature helps set up a copy of the database for different environments like development, staging, and production. It also helps preserve data for different versions of the application.</p>
<p>Let's explore how you can create and manage branches in Neon Postgres:</p>
<ul>
<li>Navigate to the Neon dashboard and select the database.</li>
<li>In the <code>Branches</code> section, click on the <code>View All</code> button.</li>
<li>You can create a new branch from an existing one by clicking on the <code>Create Branch</code> button. You'll need to provide the branch name and what data to copy from the parent branch.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ncdgdrj32etd3gbqurf.png" alt="Branches view with Create branch option visible " width="800" height="400" loading="lazy">
<em>Create branch option</em></p>
<ul>
<li>You can either copy all the data or copy until a point in time or a specific record. This is useful for multiple purposes like restoring data, creating a new environment, or testing new features.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7gchucru5qw294icqw3.png" alt="Creating a new branch from an existing branch" width="800" height="400" loading="lazy">
<em>Creating a new branch</em></p>
<ul>
<li>Neon will create a new branch of the database that can be used independently. You can find the URL, username, and password for the new branch in the dashboard. And this happens in real time without any downtime and delays.</li>
</ul>
<p><img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji79akuf193gtv94yaag.png" alt="Branch-specific connection details " width="800" height="400" loading="lazy">
<em>Branch-specific connection details</em></p>
<p>Now you can use your <code>dev</code> branch for local development and testing, and the <code>main</code> branch for production. This helps in keeping the data separate and ensures that changes in one branch do not affect the other branches.</p>
<h2 id="heading-summary">Summary</h2>
<p>In this article, we built a CRUD application using Spring Boot, Neon Postgres, and Azure App Service.</p>
<p>We explored how to set up the Neon Postgres database, build a basic CRUD application using Spring Boot, deploy the application on Azure App Service, and configure autoscaling for the application and the database.</p>
<p>We also learned about how the database branching feature in Neon Postgres helps you create branches of the database for different environments and purposes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform Load Testing in Spring Boot with Gatling ]]>
                </title>
                <description>
                    <![CDATA[ To evaluate the performance of a system, you need a tool that can simulate its behavior in production.  For this purpose, you can use a software tool based on Scala called Gatling. This article will teach you how to integrate it into a Spring Boot ap... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-integrate-spring-boot-with-gatling/</link>
                <guid isPermaLink="false">66bb4548cd114247c2941f32</guid>
                
                    <category>
                        <![CDATA[ Gatling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mario Casari ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jul 2024 19:46:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/06/pexels-markusspiske-177598.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>To evaluate the performance of a system, you need a tool that can simulate its behavior in production. </p>
<p>For this purpose, you can use a software tool based on <a target="_blank" href="https://www.scala-lang.org/">Scala</a> called <a target="_blank" href="https://gatling.io/">Gatling</a>. This article will teach you how to integrate it into a <a target="_blank" href="https://spring.io/projects/spring-boot">Spring Boot</a> application and perform a load test.</p>
<h2 id="heading-main-concepts">Main Concepts</h2>
<p>Gatling is a tool you can use to execute load and performance tests. It can be used as a standalone application or integrated into a Maven or Gradle-based project.</p>
<p>Gatling is based on Scala, the <a target="_blank" href="https://en.wikipedia.org/wiki/Netty_(software)">Netty</a> framework, and the <a target="_blank" href="https://doc.akka.io/docs/akka/current/typed/guide/index.html">Akka</a> toolkit. It has an asynchronous, non-blocking architecture, which allows for high performance with minimum wasting of resources.</p>
<p>You can define tests by Gatling's flexible domain-specific language. You can also use its recorder function with a Graphical User Interface to capture user interactions in the browser and generate Scala scripts that can be modified and launched to perform a simulation.</p>
<p>In this article, you will learn how to integrate Gatling in a Spring Boot web application based on Maven. You will define a load test by its DSL, and then run it using the Gatling Maven plugin.</p>
<p>With Gatling, you can perform performance tests in a variety of ways. For instance, you can implement:</p>
<ul><li><b>Load Testing</b>: to see how a system performs under a specific load</li><li><b>Stress Testing</b>: to find the breaking point of a system, raising the load progressively</li><li><b>Soak Testing</b>: running the system with a steady load for a long time to find its pitfalls</li><li><b>Spike Testing</b>: to see how the system performs when swiftly raising the load to a peak and then going down</li></ul>

<p>The basic components by which Gatling implements the features described above are:</p>
<ul><li><b>Scenarios</b>: a series of steps performed by a virtual user</li><li><b>Feeders</b>: how data is provided to feed the scenarios</li><li><b>Injection</b>: a sort of a blueprint that states how the test is performed, in terms of number of virtual users, how they change in time, and so on</li></ul>

<h2 id="heading-spring-boot-gatling-integration">Spring Boot Gatling Integration</h2>
<p>In this article, you will start with a simple Spring Boot web application and implement and run a load test over it. You can find the source code of this sample application on <a target="_blank" href="https://github.com/mcasari/codingstrain/tree/main/spring-cloud-sample-libraryapp/libraryapp-testing-gatling-test">GitHub</a>.</p>
<p>Imagine you have a library and want to insert new books by their title. You can implement this minimal requirement using JPA by defining a Book entity, a repository class, a service class, and a controller with a <a target="_blank" href="https://codingstrain.com/spring-boot-for-cloud-rest-api-development/">REST</a> service mapping.</p>
<p>The REST service is defined as a POST call to a /book endpoint that saves a new book object. You can see the implementation in the code below:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping("/library")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookController</span> </span>{

    Logger logger = LoggerFactory.getLogger(BookController.class);

    <span class="hljs-meta">@Autowired</span>
    BookService bookService;

    <span class="hljs-meta">@PostMapping(value = "/book", consumes = "application/json", produces = "application/json")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Book <span class="hljs-title">createPerson</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> Book book)</span> </span>{
        <span class="hljs-keyword">return</span> bookService.save(book);
    }

}
</code></pre>
<p>To perform a load test on the above REST endpoint, you need to integrate Gatling. You can do this by setting some Maven dependencies first:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.gatling<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>gatling-app<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.7.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>


<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.gatling.highcharts<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>gatling-charts-highcharts<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.7.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>    

<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.github.javafaker<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>javafaker<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.15<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>Then you also need a Maven plugin to execute the test:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.gatling<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>gatling-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>4.2.9<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">simulationClass</span>&gt;</span>com.codingstrain.springcloud.sample.libraryapp.books.BookSaveSimulation<span class="hljs-tag">&lt;/<span class="hljs-name">simulationClass</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
</code></pre>
<h2 id="heading-load-test-implementation">Load Test Implementation</h2>
<p>To implement a test, you need to extend the <code>io.gatling.javaapi.core.Simulation</code> class, as in the <code>BookSaveSimulation</code> class below:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.core.CoreDsl.StringBody;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.core.CoreDsl.global;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.core.CoreDsl.rampUsersPerSec;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> io.gatling.javaapi.http.HttpDsl.http;

<span class="hljs-keyword">import</span> java.time.Duration;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Iterator;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-keyword">import</span> java.util.stream.Stream;

<span class="hljs-keyword">import</span> com.github.javafaker.Faker;

<span class="hljs-keyword">import</span> io.gatling.javaapi.core.CoreDsl;
<span class="hljs-keyword">import</span> io.gatling.javaapi.core.OpenInjectionStep.RampRate.RampRateOpenInjectionStep;
<span class="hljs-keyword">import</span> io.gatling.javaapi.core.ScenarioBuilder;
<span class="hljs-keyword">import</span> io.gatling.javaapi.core.Simulation;
<span class="hljs-keyword">import</span> io.gatling.javaapi.http.HttpDsl;
<span class="hljs-keyword">import</span> io.gatling.javaapi.http.HttpProtocolBuilder;


<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BookSaveSimulation</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Simulation</span> </span>{


    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BookSaveSimulation</span><span class="hljs-params">()</span> </span>{

        setUp(buildPostScenario()
            .injectOpen(injection())
            .protocols(setupProtocol())).assertions(global().responseTime()
          .max()
          .lte(<span class="hljs-number">10000</span>), global().successfulRequests()
          .percent()
          .gt(<span class="hljs-number">90d</span>));
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> ScenarioBuilder <span class="hljs-title">buildPostScenario</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> CoreDsl.scenario(<span class="hljs-string">"Load POST Test"</span>)
            .feed(feedData())
            .exec(http(<span class="hljs-string">"create-book"</span>).post(<span class="hljs-string">"/library/book"</span>)
            .header(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"application/json"</span>)
                .body(StringBody(<span class="hljs-string">"{ \"title\": \"${title}\" }"</span>)));
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Iterator &amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; feedData() {
        Faker faker = <span class="hljs-keyword">new</span> Faker();
        Iterator&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; iterator;
        iterator = Stream.generate(() -&amp;gt; {
              Map&amp;lt;String, Objectglt; stringObjectMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
            stringObjectMap.put(<span class="hljs-string">"title"</span>, faker.book()
                .title());
              <span class="hljs-keyword">return</span> stringObjectMap;
          })
          .iterator();
        <span class="hljs-keyword">return</span> iterator;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> HttpProtocolBuilder <span class="hljs-title">setupProtocol</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> HttpDsl.http.baseUrl(<span class="hljs-string">"http://localhost:8080"</span>)
          .acceptHeader(<span class="hljs-string">"application/json"</span>)
          .maxConnectionsPerHost(<span class="hljs-number">10</span>)
            .userAgentHeader(<span class="hljs-string">"Performance Test"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> RampRateOpenInjectionStep <span class="hljs-title">injection</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">int</span> totalUsers = <span class="hljs-number">100</span>;
        <span class="hljs-keyword">double</span> userRampUpPerInterval = <span class="hljs-number">10</span>;
        <span class="hljs-keyword">double</span> rampUpIntervalInSeconds = <span class="hljs-number">30</span>;

        <span class="hljs-keyword">int</span> rampUptimeSeconds = <span class="hljs-number">300</span>;
        <span class="hljs-keyword">int</span> duration = <span class="hljs-number">300</span>;
        <span class="hljs-keyword">return</span> rampUsersPerSec(userRampUpPerInterval / (rampUpIntervalInSeconds)).to(totalUsers)
            .during(Duration.ofSeconds(rampUptimeSeconds + duration));
    }
}
</code></pre>
<p>The <code>BoookSaveSimulation</code> class uses its constructor to do all the settings using the parent class <code>setUp</code> method. It first implements a scenario. Since the test's purpose is to simulate a real situation in production, the scenario represents the steps performed by a configured number of virtual users interacting with the system.</p>
<p>The scenario in the example executes a POST call to the /library/book endpoint, sending a single title parameter in the payload. The invoked service will save a new book by the passed title value. A class named <code>com.github.javafaker.Faker</code> produces title values automatically and implements the feeder component described earlier in the <code>Main Concepts</code> section.</p>
<p>Then the <code>injectOpen</code> method defines how the virtual users are added to the simulation. The injectOpen method implements the injection part using the so-called open mode. There are two different models of injection, <code>open</code> and <code>closed</code>.</p>
<p>The open model simulates a scenario in which new users can be added constantly and independently from the execution state of the others. This is the model used in this article's example. On the other hand, in the closed model, new users can be added only when all the others have terminated their tasks. This helps simulate a steady load on the system.</p>
<p>The open injection configuration in the example sets a total number of 100 users that are added progressively 10 at a time, every 30 seconds. Once all users have been added, the execution continues for 300 seconds.</p>
<p>The protocols method sets up the base URL, the data type expected in the response, the maximum number of connections per host, and the User-Agent header.</p>
<p>The last part of this set-up phase defines a couple of assertions to consider the test passed: a maximum response time lower than 10 seconds and a percentage of successful requests greater than 90%.</p>
<h2 id="heading-how-to-run-the-test">How to Run the Test</h2>
<p>To run the test, you first have to start the Spring Boot web application. You can do this, for instance, by going to the project base directory and execute the following command: <code>mvn spring-boot:run</code>. </p>
<p>Once the application is started, you can run the Gatling simulation by executing <code>mvn gatling:test</code>.</p>
<h2 id="heading-how-to-see-the-results">How to See the Results</h2>
<p>Once the test is terminated, you will find an index.html in the /target/gatling directory with all the measurements and several graphs.</p>
<p>The figure below displays all the results. It shows a list of the assertions and their outcome. Then, you can see the total number of requests, and how many requests have a positive or negative result. You have useful information about the response time: minimum, maximum, average, and standard deviation, and you also have the 50th, 75th, 95th, and 99th percentiles.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Summary.png" alt="Image" width="600" height="400" loading="lazy">
<em>Summary of the test results</em></p>
<p>A chart shows the number of requests, with positive and negative outcomes, in a particular response time range, as in the following figure.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/GlobalInfo.png" alt="Image" width="600" height="400" loading="lazy">
<em>Number of requests in particular response time ranges</em></p>
<p>Another graph shows the number of requests per second and how it changes depending on the number of active users.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/RequestsPerSecond.png" alt="Image" width="600" height="400" loading="lazy">
<em>Number of request per second and active users over time</em></p>
<p>You can also see in the next figure how the percentiles change over time, and with the number of active users at each point in time.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/06/Percentiles.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Evaluating the performance of a system is a complex task. Gatling makes things easy enough to integrate this kind of task with continuous integration. It gives you a comprehensive view and allows you to tweak the tests to find weaknesses and suggest solutions.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Implement an OAuth2 Resource Server with Spring Security ]]>
                </title>
                <description>
                    <![CDATA[ Hey everyone! Imagine you are building an awesome application, with lots of cool features. Picture a backend server at its core that hosts a majority of the business logic and exposes functionality through APIs. Once you have planned out your APIs, t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/oauth2-resourceserver-with-spring-security/</link>
                <guid isPermaLink="false">66d8516039c4dccc43d4d4c3</guid>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kunal Nalawade ]]>
                </dc:creator>
                <pubDate>Wed, 08 May 2024 15:39:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/05/article-cover.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hey everyone! Imagine you are building an awesome application, with lots of cool features. Picture a backend server at its core that hosts a majority of the business logic and exposes functionality through APIs.</p>
<p>Once you have planned out your APIs, there's one crucial step you need to take care of: securing your APIs. You don't want your APIs exposed to anyone on the internet (unless you are building for open source).</p>
<p>Authentication ensures that your APIs can only be accessed by authenticated users of your application. A user can be authenticated with username and password, or via access token.</p>
<p>In this post, we are going to see how to secure your APIs using OAuth2 and access tokens. I am assuming you have a basic knowledge of Java and Spring Boot. If not, then you can <a target="_blank" href="https://www.freecodecamp.org/news/learn-app-development-with-spring-boot-3/">check out this course on freeCodeCamp's YouTube channel</a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-oauth2">What is OAuth2?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-the-spring-boot-application">How to Set Up the Spring Boot Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#configuration">Web Security Configuration</a></p>
</li>
<li><p><a class="post-section-overview" href="#write-apis-in-controller-class">Public and Private APIs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-testing-the-apis">Testing APIs with and without Access Token</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-get-the-users-details-from-the-access-token">How to Get the User's Details From the Access Token</a></p>
</li>
</ol>
<h2 id="heading-what-is-oauth2">What is OAuth2?</h2>
<p>OAuth2 is a framework that lets third-party applications access your service on behalf of an end user. It is widely used for authentication and authorization in modern applications.</p>
<p>There are four components in the OAuth2 framework:</p>
<ul>
<li><p><strong>Resource Owner</strong>: The end-user of your application.</p>
</li>
<li><p><strong>Authorization Server</strong>: The third-party application that authenticates the user and issues an access token after successful authentication.</p>
</li>
<li><p><strong>Client</strong>: The user interface through which the user wants to access your resources. The client could be a mobile app, web app, or a desktop app. The client requires an access token to access your APIs.</p>
</li>
<li><p><strong>Resource Server</strong>: The server hosting the protected resources. It validates the access token and grants access to the resources if authentication is successful.</p>
</li>
</ul>
<p>The user, through the client, requests an access token from the authorization server. If authentication is successful, the client uses this token to access the protected APIs exposed by the resource server.</p>
<p>In this post, we are only going to focus on implementing the resource server.</p>
<h2 id="heading-how-to-set-up-the-spring-boot-application">How to Set Up the Spring Boot Application</h2>
<p>To set up your application, navigate to <a target="_blank" href="https://start.spring.io/">Spring Initializr</a>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/image-44.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Spring Initializr</em></p>
<p>Choose <em>Gradle</em> or <em>Maven</em> for the project, the Spring Boot version, and the name of the project. Add the following dependencies: <em>spring-boot-starter-web</em> and <em>oauth2-resource-server</em>.</p>
<p>Click on <em>Generate</em> to download the Spring Boot application and once downloaded, extract the zip file. You should now have a running Spring Boot application with the dependencies fully loaded. Open IntelliJ (or any IDE of your choice) and select this project to start working.</p>
<p>You can find the complete code for this tutorial on <a target="_blank" href="https://github.com/KunalN25/my-tutorials/tree/main/java-springboot/oauth2-resource-server-tutorial">GitHub</a>.</p>
<h2 id="heading-web-security-configuration">Web Security Configuration</h2>
<p>First, open <code>application.properties</code> and add the following property:</p>
<pre><code class="lang-python">spring.security.oauth2.resourceserver.jwt.issuer-uri: ${JWT_ISSUER_URI}
</code></pre>
<p>You can find the <em>issuer-uri</em> in the open-id configuration of the OAuth2 service that you are using. For instance, check out the <a target="_blank" href="https://accounts.google.com/.well-known/openid-configuration">Google OAuth2</a> config.</p>
<p>Next, let's configure Spring Security.</p>
<p>To implement the resource server, you need to have Spring Security as one of your dependencies. Here, we don't need to add it separately since the <em>oauth2-resource-server</em> uses Spring Security.</p>
<p>When you add Spring Security in your dependencies, Spring Boot enables authentication for each API you expose. The default one is username and password-based authentication.</p>
<p>This happens because Spring Security has its own <code>SecurityAutoConfiguration</code> class that contains the default security configuration. But, we haven't added Spring Security in our dependencies.</p>
<p>Since we do not want username and password-based authentication, we need to disable the auto configuration. Go to the main class and add the following exclusion:</p>
<pre><code class="lang-java"><span class="hljs-meta">@SpringBootApplication(exclude = { SecurityAutoConfiguration.class})</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Oauth2ResourceServerTutorialApplication</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        SpringApplication.run(Oauth2ResourceServerTutorialApplication.class, args);
    }
}
</code></pre>
<p>If you run the application now, it throws an error.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/image-45.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Error without configuration</em></p>
<p>Let's add our own configuration now. Create a new Java class <code>SecurityConfig</code> with the following annotations:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSecurity</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityConfig</span> </span>{
    <span class="hljs-comment">// Beans here</span>
}
</code></pre>
<p><code>@Configuration</code> indicates that this is a configuration class that contains several Bean methods, that are responsible for creating beans. <a target="_blank" href="https://www.baeldung.com/spring-bean">Beans</a> are simply objects that form the building blocks of a Spring Boot application. <code>@EnableWebSecurity</code> tells Spring Boot to enable Web Security with your configurations.</p>
<p>Create a method that returns a bean of type <code>SecurityFilterChain</code>. The security filter chain bean intercepts incoming requests and applies custom filters to them. This is where you can apply different kinds of authorization to different requests.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Bean</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> SecurityFilterChain <span class="hljs-title">filterChain</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        http
                .authorizeHttpRequests((authz) -&gt; authz
                        .requestMatchers(<span class="hljs-string">"/public/**"</span>).permitAll()
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2 -&gt; oauth2.jwt(Customizer.withDefaults()));
        <span class="hljs-keyword">return</span> http.build();
    }
</code></pre>
<p>Let's understand the key parts of this code:</p>
<ul>
<li><p>The <code>filterChain()</code> method takes an <code>HttpSecurity</code> object as an argument. This class from Spring Security allows you to configure requests.</p>
</li>
<li><p>The method <code>authorizeHttpRequests()</code> takes an object that we have represented as a lambda expression.</p>
</li>
<li><p>We have used the <code>requestMatchers()</code> method to match a route that will be accessible without authentication. In our case, any route starting from <code>/public</code> will be accessible to anyone. Requests to any other route will need authentication.</p>
</li>
<li><p>The <code>oauth2ResourceServer()</code> method sets up our application as an OAuth2 resource server. Here, we specify that JWT authentication will be used with default customizers.</p>
</li>
<li><p>Lastly, <code>http.build()</code> builds the <code>HttpSecurity</code> object and returns it.</p>
</li>
</ul>
<p>In this project, we have configured web security in the above manner. But if you have any other requirements you may need a different configuration. For example, if you have privileged roles like admin in your application, you can specify which routes each role can access, and so on.</p>
<p>Visit the <a target="_blank" href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html">JWT resource server</a> docs to understand different ways you can customize web security.</p>
<h2 id="heading-write-apis-in-the-controller-class">Write APIs in the Controller Class</h2>
<p>Let's write two simple APIs. Create a class <code>MainController</code> that will expose these APIs:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainController</span> </span>{

    <span class="hljs-meta">@GetMapping("/public")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">homePage</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello from Spring boot app"</span>;
    }

    <span class="hljs-meta">@GetMapping("/private")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">privateRoute</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"Private Route"</span>;
    }
}
</code></pre>
<p>The <code>@RestController</code> indicates that this class will handle HTTP requests and return the data to the client, typically in JSON format. We have written a public and a private API.</p>
<p>Save the file and run the application.</p>
<h2 id="heading-testing-the-apis">Testing the APIs</h2>
<p>Let's test the above APIs using Postman, without an authorization header.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/image-9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>/public route</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/image-10.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>/private route</em></p>
<p>In the above two API calls, the <code>/public</code> route returned a response, while the <code>/private</code> route threw an error with a status of <code>401 Unauthorized</code>.</p>
<p>This is because, in our configuration, we have made all routes starting with <code>/public</code> accessible without authentication. All the other routes would need some form of authentication. In our case, we need a Bearer Token to access the private route.</p>
<p>Let's include an authorization header in the request to the <code>/private</code> endpoint.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/05/image-11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>/private route request with access token</em></p>
<p>When we include an authorization header with the access token, the private route returns a response. For this, and any other routes not starting with <code>/public</code>, we need to pass an access token in the header.</p>
<p>We are not going to see how to obtain an access token, since we are only focussing on the resource server. The OAuth2 Client is responsible for obtaining an access token. I'll cover that in a future post.</p>
<h2 id="heading-how-to-get-the-users-details-from-the-access-token">How to Get the User's Details From the Access Token</h2>
<p>When you make a request to a private route, the security filter intercepts this request and looks for a Bearer Token. If a token exists, it decodes the token and extracts the authentication information from the token. You can understand this whole process in detail from the <a target="_blank" href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html">OAuth2 Resource Server</a> docs.</p>
<p>If the token is valid and authentication is successful, the authentication data is set on the <a target="_blank" href="https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-securitycontextholder">SecurityContextHolder</a> class. The <code>SecurityContextHolder</code> contains the details of the authenticated user. We use this class to extract the user's information such as name, email, and so on.</p>
<p>Let's see how we can get these user details. First, we get an <a target="_blank" href="https://docs.spring.io/spring-security/reference/servlet/authentication/architecture.html#servlet-authentication-authentication">Authentication</a> object from the <code>SecurityContextHolder</code>:</p>
<pre><code class="lang-java">Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
</code></pre>
<p>Then, we use the <code>getPrincipal()</code> that returns an object:</p>
<pre><code class="lang-java">Object principal = authentication.getPrincipal();
</code></pre>
<p>Since we are using JWT Authentication, the above object can be type-casted into an object of type <a target="_blank" href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/jwt/Jwt.html">Jwt</a>. The object contains the following fields:</p>
<pre><code class="lang-python">{
    <span class="hljs-string">"tokenValue"</span>: token_value,
    <span class="hljs-string">"issuedAt"</span>: <span class="hljs-string">""</span>,
    <span class="hljs-string">"expiresAt"</span>: <span class="hljs-string">""</span>,
    <span class="hljs-string">"headers"</span>: {...},
    <span class="hljs-string">"claims"</span>: {        
        <span class="hljs-string">"name"</span>: full_name,
        <span class="hljs-string">"email"</span>: user_email,
        <span class="hljs-string">"given_name"</span>: first_name,
        <span class="hljs-string">"family_name"</span>: last_name,
        <span class="hljs-string">"picture"</span>: picture_link,
        ...other fields
    },
    <span class="hljs-string">"subject"</span>: <span class="hljs-string">""</span>,
    <span class="hljs-string">"id"</span>: null,
    <span class="hljs-string">"issuer"</span>: issuer_link,
    <span class="hljs-string">"audience"</span>: [...],
    <span class="hljs-string">"notBefore"</span>: null
}
</code></pre>
<p>Here, we can get the user data from the <code>claims</code> field:</p>
<pre><code class="lang-java">Map&lt;String, Object&gt; claims = ((Jwt) principal).getClaims();
</code></pre>
<p>Using the above map, we can get the user's information using the corresponding key value. Let's write this logic in a separate class <code>CurrentAuthContext</code>:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CurrentAuthContext</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Map&lt;String, Object&gt; <span class="hljs-title">extractClaim</span><span class="hljs-params">()</span> </span>{
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object principal = authentication.getPrincipal();
        Map&lt;String, Object&gt; claims = ((Jwt) principal).getClaims();
        <span class="hljs-keyword">return</span> claims;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">getUserEmail</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> (String) extractClaim().get(<span class="hljs-string">"email"</span>);
    }
}
</code></pre>
<p>You can add more methods to get the details you need. To get the user email anywhere in the application, just call <code>CurrentAuthContext.getUserEmail()</code> or any other method returning the value you need.</p>
<p>I haven't implemented custom error handling here. You can reach out to me with different ways to implement custom error handling.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>OAuth2 provides a robust framework for securing your APIs while providing access to authorized users. In this post, we started with understanding OAuth2 and its components.</p>
<p>Spring Security is a fundamental part of the Spring OAuth2 Resource Server. We learned how to implement security configurations as per our requirements. Then, we defined public and private APIs and tested them with and without an access token.</p>
<p>A private API can only be accessed with an access token passed through the authorization header. We also implemented some logic to extract the user's information from the access token with the <code>SecurityContextHolder</code> class.</p>
<p>I attached reference links to docs at various places for further understanding of these concepts. That's all for today. I hope this helps in your future projects.</p>
<p>If you are unable to understand the content or find the explanation unsatisfactory, reach out to me. New ideas are always appreciated! Feel free to connect with me on Twitter. Till then, Goodbye!!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn App Development with Spring Boot 3 ]]>
                </title>
                <description>
                    <![CDATA[ Spring Boot 3 is an advanced framework that simplifies the development of new Spring applications through convention over configuration, providing a range of out-of-the-box functionalities for building enterprise-grade applications efficiently. We ju... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-app-development-with-spring-boot-3/</link>
                <guid isPermaLink="false">66b203f4a8b92c9329236480</guid>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 19 Mar 2024 14:57:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/javaspringboot.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Spring Boot 3 is an advanced framework that simplifies the development of new Spring applications through convention over configuration, providing a range of out-of-the-box functionalities for building enterprise-grade applications efficiently.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will teach you how to develop apps with Spring Boot and Java. Dan Vega developed this course. Dan is a spring developer advocate, course creator, and speaker.</p>
<p>The course is designed to guide beginners through the nuances of web application development using Spring Boot 3, the cornerstone framework for Java applications. It's a blend of theory and practical application, where you start from the grassroots and ascend to creating sophisticated web applications.</p>
<h2 id="heading-module-breakdown">Module Breakdown</h2>
<p>Here is a description of each module in this course.</p>
<h3 id="heading-module-1-course-introduction">Module 1: Course Introduction</h3>
<p>Dive into the world of Spring Boot 3, starting with an overview of the course structure and objectives. Understand the prerequisites, including Java fundamentals and the necessary development tools like JDK 17+ and your preferred IDE or text editor. This module sets the stage, ensuring you're well-equipped to embark on this learning journey.</p>
<h3 id="heading-module-2-create-your-project">Module 2: Create Your Project</h3>
<p>Kickstart your project with a detailed exploration of how to use start.spring.io for project initialization. This module covers the essentials of Java Build Tools, Maven and Gradle, and best practices for organizing your code, including where to place your code files and the importance of avoiding the default package. Learn the nuances of running your application through an IDE or Maven, and get acquainted with Spring Boot DevTools.</p>
<h3 id="heading-module-3-rest-api">Module 3: REST API</h3>
<p>Delve into creating a REST API, where you'll learn to construct a web application that communicates effectively with clients. Explore the various components of Spring, like @Component, Controller, RestController, Service, and Repository, and understand their roles in your application. This module also covers the basics of CRUD operations in an in-memory setting and introduces you to the principles of dependency injection and data validation.</p>
<h3 id="heading-module-4-working-with-databases">Module 4: Working with Databases</h3>
<p>This module introduces you to integrating and manipulating databases within your Spring Boot application. You'll start with the H2 Database, progressing to more complex interactions using the JDBC Client. Additionally, you'll learn how to elevate your application with Docker Compose and PostgreSQL, ensuring your app can scale and interact with more sophisticated data storage solutions.</p>
<h3 id="heading-module-5-rest-clients">Module 5: Rest Clients</h3>
<p>Explore the construction and utilization of REST clients, crucial for enabling your application to communicate with other web services. This module will guide you through setting up and configuring rest clients to interact with external APIs, enhancing the capability and reach of your application.</p>
<h3 id="heading-module-6-testing">Module 6: Testing</h3>
<p>Ensure your application's reliability and stability by mastering testing with the Spring Boot Testing Toolkit. This module emphasizes the importance of testing in the development lifecycle, teaching you how to create and implement a comprehensive testing suite to validate your application's functionality and performance.</p>
<h2 id="heading-embark-on-your-development-journey">Embark on Your Development Journey</h2>
<p>This course is more than just a learning experience; it's a gateway to the vast world of web application development, offering you the tools and knowledge to build your own web applications with confidence. Whether you're starting from scratch or looking to refine your skills, this course is designed to provide a structured, engaging, and informative path to mastering Spring Boot 3.</p>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/31KTdfRH6nY">the freeCodeCamp.org YouTube channel</a> (3.5 hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/31KTdfRH6nY" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Spring Boot and Spring Data JPA ]]>
                </title>
                <description>
                    <![CDATA[ By mastering Spring Boot and Spring Data JPA, you'll be equipped to build efficient, scalable, and secure applications with ease, making you a valuable asset in the job market and a more effective developer. We just published a comprehensive video co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-spring-boot-and-spring-data-jpa/</link>
                <guid isPermaLink="false">66b2050d39b555ffda8bfea8</guid>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring data ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 06 Feb 2024 16:05:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/springboot.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By mastering Spring Boot and Spring Data JPA, you'll be equipped to build efficient, scalable, and secure applications with ease, making you a valuable asset in the job market and a more effective developer.</p>
<p>We just published a comprehensive video course on the freeCodeCamp.org YouTube channel that teaches Spring Boot and Spring Data JPA, two pivotal technologies in the Java ecosystem. Bouali Ali created this course. Bouali is an experienced developer and teacher.</p>
<p>Spring Boot is an open-source, micro-framework from the larger Spring Framework, designed to simplify the bootstrapping and development of new Spring applications. Its primary goal is to ease the development process by offering a range of out-of-the-box features for configuration, along with embedded servers to facilitate a straightforward setup of web applications. Spring Boot's convention over configuration approach significantly reduces the amount of manual configuration required, making it a preferred choice for developers aiming to deploy applications quickly.</p>
<p>Spring Data JPA, on the other hand, is a part of the larger Spring Data family, aiming to simplify data access within SQL databases. It abstracts boilerplate CRUD operations, providing a more straightforward way to interact with databases through the Java Persistence API (JPA). Spring Data JPA integrates seamlessly with Spring Boot, offering an intuitive approach to handling database operations, reducing the complexity and the amount of code developers need to write.</p>
<p>This course is designed for both beginners and experienced developers who wish to deepen their understanding of Spring Boot and Spring Data JPA.  Here's an overview of the key topics covered in the course:</p>
<h4 id="heading-introduction-to-spring-framework-and-spring-boot">Introduction to Spring Framework and Spring Boot</h4>
<ul>
<li>Overview of Spring Framework</li>
<li>Introduction to Spring Boot</li>
<li>Setting up a Spring Boot project</li>
<li>Understanding Spring Boot auto-configuration</li>
</ul>
<h4 id="heading-spring-boot-basics">Spring Boot Basics</h4>
<ul>
<li>Building RESTful web services with Spring Boot</li>
<li>Spring Boot application properties</li>
<li>Logging with Spring Boot</li>
<li>Building a CRUD API</li>
</ul>
<h4 id="heading-database-access-with-spring-data-jpa">Database Access with Spring Data JPA</h4>
<ul>
<li>Configuring a data source in Spring Boot</li>
<li>Introduction to Spring Data JPA</li>
<li>Implementing repositories</li>
<li>Entity relationships and cascading</li>
<li>Transactions and locking</li>
</ul>
<h4 id="heading-advanced-spring-boot-features">Advanced Spring Boot Features</h4>
<ul>
<li>Securing Spring Boot applications with Spring Security</li>
<li>Token-based authentication</li>
<li>Spring Boot with OAuth2</li>
<li>Microservices with Spring Boot</li>
<li>Deploying Spring Boot applications</li>
</ul>
<h4 id="heading-testing">Testing</h4>
<ul>
<li>Writing unit tests for Spring Boot applications</li>
<li>Integration testing with Spring Boot</li>
</ul>
<h4 id="heading-spring-boot-best-practices">Spring Boot Best Practices</h4>
<ul>
<li>Effective logging practices</li>
<li>Exception handling</li>
<li>Application monitoring with Actuator</li>
<li>Tips for production-ready applications</li>
</ul>
<p>With a blend of theoretical concepts and practical demonstrations, the course aims to equip you with the knowledge and skills required to build robust, efficient applications. Watch the full course <a target="_blank" href="https://www.youtube.com/watch?v=5rNk7m_zlAg">on the freeCodeCamp.org YouTube channel</a> (13-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/5rNk7m_zlAg" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Monitor Python APIs using Pyctuator and SpringBootAdmin ]]>
                </title>
                <description>
                    <![CDATA[ Actuator endpoints help us monitor our services. By using actuators, we can gain a lot of information about what’s going on. SpringBoot has a number of in-built actuators, and it also allows us to create our own Actuator Endpoint. For frameworks writ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-monitor-python-apis-using-pyctuator-and-springbootadmin/</link>
                <guid isPermaLink="false">66d460f03dce891ac3a96810</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sameer Shukla ]]>
                </dc:creator>
                <pubDate>Fri, 02 Sep 2022 15:02:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/09/Screen-Shot-2022-09-01-at-12.18.52-AM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Actuator endpoints help us monitor our services. By using actuators, we can gain a lot of information about what’s going on.</p>
<p>SpringBoot has a number of in-built actuators, and it also allows us to create our own Actuator Endpoint.</p>
<p>For frameworks written in Python like Flask or FastAPI, we can incorporate actuators by integrating a library called Pyctuator.</p>
<p>In this article I am going to explain how to monitor applications written in FastAPI using the Pyctuator library. I'll also show you how to manage the actuator endpoints using the SpringBootAdmin server.</p>
<h2 id="heading-what-are-actuators">What are Actuators?</h2>
<p>We use actuators for monitoring and managing application usage in production. This usage information gets exposed to us via REST endpoints.</p>
<p>For example, we can access the application logs in production, environment details, and HTTP traces. And if something has gone wrong within the application, we can even access the applications “threaddump” for debugging purposes.</p>
<p>Here are some examples of few important actuator endpoints:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-16.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Actuators</em></p>
<h2 id="heading-what-is-pyctuator">What is Pyctuator?</h2>
<p>Actuators become popular because of SpringBoot, but you can implement them in frameworks like FastAPI or Flask by integrating a module called Pyctuator.</p>
<p>Pyctuator is a Python Module, which is a partial implementation of SpringBoot Actuators. Pyctuator is managed by SolarEdge.</p>
<p>Some of the actuators supported by Pyctuators are:</p>
<ul>
<li><p>/health: This endpoint in Pyctuator has built-in monitoring for Redis and MySQL</p>
</li>
<li><p>/env</p>
</li>
<li><p>/metrics</p>
</li>
<li><p>/logfile</p>
</li>
<li><p>/threaddump</p>
</li>
<li><p>/httptrace</p>
</li>
<li><p>/loggers</p>
</li>
</ul>
<h2 id="heading-what-is-springbootadmin">What is SpringBootAdmin?</h2>
<p>Imagine a service having all these actuators for checking metrics, httptrace, threaddump and so on. It would be pretty tedious to invoke each one of them individually to check what’s going on within the service. And if we have many services and each one of them has its own actuator endpoints, this makes monitoring even more difficult.</p>
<p>That’s where you can use SpringBootAdmin to manage and monitor applications.</p>
<p>In a nutshell, SpringBootAdmin provides a nice dashboard for all the actuator endpoints in one place.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-30.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Admin Dashboard</em></p>
<h2 id="heading-use-case-for-pyctuator">Use-Case for Pyctuator</h2>
<p>The use-case is straightforward: we are going to develop a RESTful service using FastAPI framework and configure the actuators in the service using the Pyctuator module.</p>
<p>The service has 3 endpoints as shown in the API-Docs (Swagger) below</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-31.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>API-Docs</em></p>
<ul>
<li><p>GET /users: Return all the users that exists in the system.</p>
</li>
<li><p>POST /users: Create user</p>
</li>
<li><p>GET /users/{id}: Return a user with a given id</p>
</li>
</ul>
<p>You can find the code <a target="_blank" href="https://github.com/sameershukla/fastapi-pyctuator">here</a>.</p>
<p>In the User-Service we are going to enable the actuators using Pyctuator and monitor them using SpringBootAdmin dashboard. We are also going to explore how we can enhance the /health actuator for monitoring Redis.</p>
<p>For configuring the Actuators, first we need to install “pyctuator”. You can do that using the command “pip install pyctuator”.</p>
<p>After installation, simply instantiating the Pyctuator object is the entry point for seeing in-built actuators within a web-framework.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-47.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Pyctuator Constructor</em></p>
<p>Before instantiating Pyctuator, if you access the /pyctuator endpoint you will get the “Not Found” message:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-91.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Without Pyctuator Configuration</em></p>
<p>After instantiation, on accessing the /pyctuator endpoint you will see all the actuators enabled by default. This is because we have defined "pyactuator_endpoint_url" within Pyctuator.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-93.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>After Pyctuator Configuration</em></p>
<p>I strongly recommend going through the Pyctuator object as it explains what the mandatory and optional arguments are that we need to provide.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-114.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Understanding Constructor parameters</em></p>
<p>The mandatory parameters are:</p>
<ul>
<li><p>app – instance of FastAPI or Flask</p>
</li>
<li><p>the application name – displayed in the info section in SpringBootAdmin</p>
</li>
<li><p>“pyctuator_endpoint_url” – what we have seen which returns all the actuator endpoints</p>
</li>
<li><p>“registration_url” – you will understand this one shortly.</p>
</li>
</ul>
<h2 id="heading-how-to-enhance-the-health-endpoint">How to Enhance the /health Endpoint</h2>
<p>You can enhance the /health endpoint in Pyctuator to monitor Redis or MySQL databases. Say you are using Redis in your application – then we need to use RedisHealthProvider and pass the redis instance to it.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-174.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Redis Health</em></p>
<h2 id="heading-how-to-start-the-springbootadmin-server">How to Start the SpringBootAdmin Server</h2>
<p>To run the SpringBootAdmin server on local, we have two options: first, we can do it by creating SpringBootAdmin manually by going to start.spring.io and adding libraries.</p>
<p>Spring Web &amp; Spring Boot Admin (Server):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-175.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Creating SpringBootAdmin</em></p>
<p>The second option is to run a Docker image:</p>
<pre><code class="lang-docker">docker <span class="hljs-keyword">run</span><span class="bash"> --rm --name spring-boot-admin -p 8080:8080 michayaak/spring-boot-admin:2.2.3-1</span>
</code></pre>
<p>Once the admin server is up, we need to provide the “registration_url” to the Pyctuator Constructor as discussed earlier.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-178.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>URL registration in SpringBootAdmin</em></p>
<p>The Admin Server is running on localhost:8080 and this should register our application to SpringBootAdmin. We can access all the actuator endpoints in one place:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-181.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Dashboard</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-182.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>All Configured Actuator Endpoints</em></p>
<p>I executed the /users endpoint few times and now HTTP Traces on the Admin side showcases all the Request-Response exchange details.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/09/image-191.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>HTTP Traces</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Actuators are extremely helpful in monitoring and debugging applications in production. By accessing endpoints we can get details on thread dumps, heap dumps, HTTP Traces and so on.</p>
<p>Pyctuator simplifies having actuators in Python APIs to a great extent. By simply importing the library and defining an object, all the actuators are ready for us within our application.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform Integration Testing using JUnit 5 and TestContainers with SpringBoot ]]>
                </title>
                <description>
                    <![CDATA[ TestContainers is a library that helps you run module-specific Docker containers to simplify Integration Testing. These Docker containers are lightweight, and once the tests are finished the containers get destroyed. In the article we are going to un... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integration-testing-using-junit-5-testcontainers-with-springboot-example/</link>
                <guid isPermaLink="false">66d460f437bd2215d1e245c9</guid>
                
                    <category>
                        <![CDATA[ Docker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sameer Shukla ]]>
                </dc:creator>
                <pubDate>Fri, 26 Aug 2022 15:46:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/testcontainers-logo.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>TestContainers is a library that helps you run module-specific Docker containers to simplify Integration Testing.</p>
<p>These Docker containers are lightweight, and once the tests are finished the containers get destroyed.</p>
<p>In the article we are going to understand what the TestContainers is and how it helps you write more reliable Tests.</p>
<p>We are also going to understand the important components (Annotations and Methods) of the library which help you write the Tests.</p>
<p>Finally, we will also learn to write a proper Integration Test in SpringBoot using the TestContainers library and its components.</p>
<h2 id="heading-limitations-of-testing-with-an-h2-in-memory-database">Limitations of Testing with an H2 In-Memory Database</h2>
<p>The most common approach to Integration Testing today is to use an H2 in-memory database. But there are certain limitations to this method.</p>
<p>First of all, say we are using version 8.0 of MySQL in production, but our integration tests are using H2. We can never execute our tests for the database version running on Production.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-303.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>SpringBoot app with MySQL DB and H2</em></p>
<p>‌Secondly, the test cases are less reliable because in production we are using an altogether different database and the tests are pointing to H2. The application may run into issues in production, but the integration tests may succeed.</p>
<p>I was trying to access my RESTful service on local and faced this error:</p>
<p>“<strong>Caused by: org.postgresql.util.PSQLException: FATAL: database "example_db" does not exist</strong>”.</p>
<p>It happened because of a permission issue, but the tests on local worked fine.</p>
<p>And finally, as documented <a target="_blank" href="http://h2database.com/html/features.html#compatibility">here</a>, H2 is compatible with other databases only up to a certain point. There are few areas where H2 is incompatible. If you need to use “nativeQueries” in a SpringBoot application, for example, then using H2 may cause problems.</p>
<h2 id="heading-enter-the-testcontainers-library">Enter the TestContainers Library</h2>
<p>By using TestContainers we can overcome the limitations of H2.</p>
<ul>
<li><p>Integration tests will point to the same version of the database as it’s in production. So we can tie our TestContainer Database Image to the same version running on production.</p>
</li>
<li><p>Integration tests are lot more reliable because both application and tests are using the same database type and version and there won't be any compatibility issues in Testcases.</p>
</li>
</ul>
<h2 id="heading-what-is-testcontainers">What is TestContainers?</h2>
<p>The TestContainers library is a wrapper API over Docker. When we write code to create a container behind the scenes it may be translated to some Docker command, for example‌:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-283.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>MySQLContainer Creation</em></p>
<p>This code may be translated to something like the following:</p>
<pre><code class="lang-docker">docker <span class="hljs-keyword">run</span><span class="bash"> -d --env MYSQL_DATABASE=example_db --env MYSQL_USER=<span class="hljs-built_in">test</span> --env MYSQL_PASSWORD=<span class="hljs-built_in">test</span> ‘mysql:latest’</span>
</code></pre>
<p>TestContainers has a method name “withCommand”. You use it to set the command that should be run inside the Docker container which confirms that TestContainers is a wrapper API over Docker.</p>
<p>TestContainers downloads the MySQL, Postgres, Kafka, Redis images and runs in a container. The MySQLContainer will run a MySQL Database in a container and the Testcases can connect to it on the local machine. Once the execution is over the Database will be gone – it just deletes it from the machine. In the Testcases we can start as many container images as we want.</p>
<p>TestContainers supports JUnit 4, JUnit 5 and Spock. If you go to the TestContainers.org website, just visit the QuickStart section that explains how to use it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-284.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers.org how to start with Test Framework</em></p>
<p>TestContainers supports almost every Database from MySQL and Postgres to CockroachDB. You can find more info about this on the TestContainers.org website under the Modules section:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-285.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers support for Database Modules</em></p>
<p>‌TestContainers also supports Cloud Modules like GCloud Module and Azure Module as well. If your application is running on Google Cloud, then TestContainers has support for Cloud Spanner, Firestore, Datastore and so on.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-286.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers support for GCloud Module</em></p>
<p>In the article so far, we have discussed only about Databases, but TestContainers supports various other components like Kafka, SOLR, Redis, and more.</p>
<h2 id="heading-how-to-use-the-testcontainers-library">How to Use the TestContainers Library</h2>
<p>In this article we are going to explore TestContainers with JUnit 5. To implement TestContainers we need to understand a few important TestContainers annotations, methods, and the libraries that we need to implement in our project.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-288.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>TestContainers libraries</em></p>
<h3 id="heading-annotations-in-testcontainers">Annotations in TestContainers</h3>
<p>Two important annotations are required in our Tests for TestContainers to work: @TestContainers and @Container.</p>
<p>@TestContainer is JUnit-Jupiter extension which automatically starts and stops the containers that are used in the tests. This annotation finds the fields that are marked with @Container and calls the specific Container life-cycle methods. Here, MySQLContainer life-cycle methods will be invoked.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-289.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>MySQLContainer</em></p>
<p>The MySQLContainer is declared as static because if we declare Container as static then a single container is started and it will be shared across all the test methods.</p>
<p>If it’s an instance variable, then a new container is created for each test method.</p>
<h2 id="heading-testcontainers-library-methods">TestContainers Library Methods</h2>
<p>There are few important methods in TestContainers library that you'll use in the tests. They're good to know before using the library.</p>
<ul>
<li><p><strong>withInitScript</strong>: Using ‘withInitScript’ we can execute the .SQL to define the schema, tables, and plus add the data into the database. In short, this method is used to run the .SQL to populate the database.</p>
</li>
<li><p><strong>withReuse</strong> (true): Using “withReuse” method we can enable the reuse of containers. This method works well in conjunction with enabling the “testcontainers.reuse.enable:true” property in the “.testcontainers.properties” file.</p>
</li>
<li><p><strong>start</strong>: we use this to start the container.</p>
</li>
<li><p><strong>withClasspathResourceMapping</strong>: This maps a resource (file or directory) on the classpath to a path inside the container. This will only work if you are running your tests outside a Docker container.</p>
</li>
<li><p><strong>withCommand</strong>: Set the command that should be run inside the Docker container.</p>
</li>
<li><p><strong>withExposedPorts</strong>: Used to set the port that the container listens on.</p>
</li>
<li><p><strong>withFileSystemBind</strong>: Used to map a file / directory from the local filesystem into the container.</p>
</li>
</ul>
<h2 id="heading-testcontainers-use-case">TestContainers Use Case</h2>
<p>In the example we'll look at now, the application will communicate only with the database and write the integration tests for it using TestContainers. Then we'll extend the use-case by implementing Redis in between.</p>
<p>If the data exists in the Redis cache it will be returned, otherwise it'll dip into the database for saving and retrieval based on the Key.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-308.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Use-Case</em></p>
<p>The service is simple. It has 2 endpoints – the first one is to create a user and the second one is to find a user by email. If the user is found it is returned, otherwise we get a 404. The service class code looks something like this:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-291.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Service Component</em></p>
<p>We are going to write tests for this class. You can find the entire codebase <a target="_blank" href="https://github.com/sameershukla/testcontainers_demo">here</a>:‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-292.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test Class</em></p>
<p>The test class is marked with @TestContainers annotation which starts/stops the container. We use the @Container annotation to call the specific container's life-cycle methods.</p>
<p>Also, the “MySQLContainer” is declared as static because then a single container is started. Then it gets shared across all the test methods (we have already discussed the importance of these annotations).</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-293.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>BeforeAll</em></p>
<p>Next we need to write a setup method marked with @BeforeAll, where we have enabled the “withReuse” method. This helps us reuse the existing containers. We are using the “withInitScript” method to execute the “.sql” file and then starting the container.‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-294.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Overwriting Properties</em></p>
<p>‌@DynamicPropertySource helps us override the properties declared in the properties file. We write this method to allow TestContainers to create the URL, username, and password on its own – otherwise we may face errors.</p>
<p>For example on removing username and password we may face an ‘Access denied’ error which may confuse us. So it’s better to allow TestContainer to assign these properties dynamically on its own.</p>
<p>That’s it – we are ready to run the Testcases:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-295.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Test Cases</em></p>
<p>Execute @AfterAll to stop the container, otherwise it may keep running on your local machine if you don't explicitly stop it. ‌</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-296.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-use-genericcontainer">How to Use GenericContainer</h2>
<p>‌‌GenericContainer is the most flexible container. It makes it easy to run any container images within GenericContainer.</p>
<p>Now we have Redis in place, all we need to do in our Testcase is to spin up a GenericContainer with the Redis image.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-297.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>GenericContainer for Redis</em></p>
<p>Then we start the Generic Redis container in @BeforeAll and stop it with the @AfterAll tear down method.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-298.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Starting Containers</em></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/08/image-299.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Stopping Containers</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>It's extremely easy to use TestContainers in our application to write better tests. The learning curve is not too steep and it has support for various different modules from a variety of databases like Kafka, Redis and others.</p>
<p>Writing tests using TestContainers makes our tests lot more reliable. The only flip side is that the tests are slow compared to H2. This is because H2 is in memory and TestContainers takes time to download the image, run the container, and execute the entire setup we have discussed in this article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Spring Boot Tutorial – How to Build Fast and Modern Java Apps ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç In this article I am going to walk you through building a prototype with Spring Boot. Think of it like building a project for a hackathon or a prototype for your startup in limited time.  In other words, we are not trying to buil... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/spring-boot-tutorial-build-fast-modern-java-app/</link>
                <guid isPermaLink="false">66d45e4b182810487e0ce161</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 20 Sep 2021 19:43:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/09/pexels-ramdas-ware-102896.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>In this article I am going to walk you through building a prototype with Spring Boot. Think of it like building a project for a hackathon or a prototype for your startup in limited time. </p>
<p>In other words, we are not trying to build something perfect – but rather something that works.</p>
<p>If you get stuck in any part of this tutorial or if I have forgotten to mention something, you can check out the GitHub repository I have included in the <strong>Conclusion</strong>.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>Foundations of Java and OOP</li>
<li>Basic knowledge of relational databases (one-to-many, many-to-many, and so on)</li>
<li>Fundamentals of Spring would be helpful</li>
<li>Basic level HTML</li>
</ul>
<p>Also make sure you have the following:</p>
<ul>
<li><a target="_blank" href="https://www.oracle.com/java/technologies/javase-downloads.html">JDK (Java Development Kit)</a> latest</li>
<li><a target="_blank" href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a> or some other Java IDE</li>
</ul>
<h2 id="heading-what-are-we-building">What are we building?</h2>
<p>We will build an amenity reservation system where users will log in and reserve a time to use a service such as fitness center, pool, or sauna. </p>
<p>Each amenity will have a certain capacity (number of people that can use the service at the same time) so that people can make use of the amenities safely during the Covid-19 pandemic.</p>
<h3 id="heading-list-of-features-for-the-app">List of Features for the App</h3>
<p>We can think of our app as the reservation system for an apartment complex. </p>
<ul>
<li>Users should be able to log in.</li>
<li>We will assume that the accounts of residents are pre-created and there will be no sign-up feature.</li>
<li>Users should be able to view their reservations. </li>
<li>Users should be able to create new reservations by selecting the amenity type, date, and time.</li>
<li><strong>Only logged-in</strong> <strong>users</strong> should be able to see the reservations page and create reservations.</li>
<li>We should check the capacity and only create new reservations if the current number of reservations does not exceed the capacity.</li>
</ul>
<h3 id="heading-technologies-well-use">Technologies We'll Use</h3>
<p>We will learn about a lot of useful technologies that will make you more efficient as a Spring Boot developer. I will briefly mention what they are and what they are good for and then we will see them in action.</p>
<ul>
<li>Bootify</li>
<li>Hibernate</li>
<li>Spring Boot</li>
<li>Maven</li>
<li>JPA</li>
<li>Swagger</li>
<li>H2 In-Memory Database</li>
<li>Thymeleaf</li>
<li>Bootstrap</li>
<li>Spring Security</li>
</ul>
<h2 id="heading-why-spring-boot">Why Spring Boot?</h2>
<p>The Spring framework is generally used for enterprise level/large scale jobs. It is not usually the first option that comes to mind for smaller projects – but I will argue that it can be quite fast for prototyping. </p>
<p>It has the following advantages:</p>
<ul>
<li>Annotation-based development generates a lot of code for you behind the scenes. And especially with the availability of libraries like Lombok, it has became a lot easier to focus on the business logic.</li>
<li>It has nice in-memory database support, so that we don't need to create a real database and connect to it. (H2)</li>
<li>It has a mature ecosystem so you can readily find answers to most questions.</li>
<li>Almost "no configuration" is required. With the help of Spring Boot, we get rid of ugly XML configurations on the Spring side of things and configuring your application is really easy.</li>
<li>There's a lot happening behind the scenes. Spring provides so much magic and does so many things to get things going. So you don't usually need to care about that stuff and can just let the framework handle things.</li>
<li>We have <a target="_blank" href="https://github.com/spring-projects/spring-security">Spring Security.</a> Having one of the most comprehensive, battle-tested security frameworks on your side gives you more confidence in the security of your application. It also takes care of a good share of the hard work for you.</li>
</ul>
<h2 id="heading-how-to-create-the-project-with-bootify">How to Create the Project with Bootify</h2>
<p>To create the project, you will use <a target="_blank" href="https://bootify.io/"><strong>Bootify</strong></a>. It's a freemium service that makes Spring Boot development faster by generating a lot of boilerplate code for you and letting you focus on business logic instead.</p>
<p><strong>Bootify</strong> allows us to specify our preferences and automatically imports the dependencies similar to <strong>Spring Initializr</strong>. </p>
<p>But there is more than that. You can also specify your entities and it will generate the corresponding model and DTO classes. It can even generate the service and controller level code for common <strong>CRUD</strong> operations.</p>
<p>I believe it is a more convenient tool for API development than it is for MVC apps since it generates REST API code by default. But it will still make our lives easier even with a Spring Boot MVC application that contains views. We will just need to make some adjustments to the generated code.</p>
<p>Let's open the <strong>Bootify</strong> website and click the "Start Project" button at the top right corner.</p>
<p>You should select:</p>
<ul>
<li><strong>Maven</strong> as the build type</li>
<li>Java version: 14</li>
<li>Tick enable <strong>Lombok</strong></li>
<li>DBMS: <strong>H2</strong> database</li>
<li>Tick <strong>add</strong> <strong>dateCreated/lastUpdated</strong> to entities</li>
<li>Packages: Technical</li>
<li>Enable <strong>OpenAPI/Swagger UI</strong></li>
<li>Add <strong>org.springframework.boot:spring-boot-devtools</strong> to further dependencies</li>
</ul>
<p>After you are done, you should see this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-bootify-io-app-8U9U2BBTLEAX-2021-04-09-16_06_29-1024x754.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now let's specify our entities. Start by clicking the <strong>Entities</strong> tab on the left menu.</p>
<p>We will have the following entities and relations:</p>
<ol>
<li><strong>Reservation</strong> that contains the data related to each reservation such as reservation date, reservation starting time, ending time, and the user who owns this reservation.</li>
<li>The <strong>User</strong> entity that contains our user model and will have relations with <strong>Reservation</strong>.</li>
<li>The <strong>Amenity</strong> entity to hold the type of Amenity and its capacity (maximum number of reservations for a certain time, for example 2 people can use and reserve the Sauna for the same time).</li>
</ol>
<p>Let's define our <strong>Reservation</strong> entity as follows and keep "Add REST endpoints" checked (even though we will modify the output). Then click the Save button.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-1-1024x577.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will specify the relations later, so the only field that our user entity has is the id field.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-1024x445.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We could create an entity for Amenities to store the data of the amenity name and its capacity and then we could reference it from the <strong>Reservation</strong>. But the relationship between Amenity and Reservation would be one-to-one. </p>
<p>So instead, for the sake of simplicity, we will create an enum called <strong>AmenityType</strong> and store the <strong>AmenityType</strong> inside <strong>Reservation</strong>.</p>
<p>Now let's create a relationship between the <strong>User</strong> and <strong>Reservation</strong> entities by clicking the + button next to the <strong>Relations</strong> menu.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Menu to create relations</em></p>
<p>It will be a <strong>Many-to-one</strong> relationship since a user can have many reservations but a reservation must have one and only one user. We will make sure this is the case by checking the required box.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-3-1024x507.png" alt="Image" width="600" height="400" loading="lazy">
<em>User-Reservation Relation</em></p>
<p>We click "Save Changes" and we are done. Your final model should look like this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-4-1024x481.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now click the download button on the left menu to download the generated project code so we can start working on it. You can see the first commit on the project repository to compare with yours if you have any problems.</p>
<p>After you download the project, open it in an IDE – I'll use <strong>IntelliJ IDEA</strong>. Your file structure should look like this:</p>
<pre><code>├── amenity-reservation-system.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   └── main
│       ├── java
│       │   └── com
│       │       └── amenity_reservation_system
│       │           ├── AmenityReservationSystemApplication.java
│       │           ├── HomeController.java
│       │           ├── config
│       │           │   ├── DomainConfig.java
│       │           │   ├── JacksonConfig.java
│       │           │   └── RestExceptionHandler.java
│       │           ├── domain
│       │           │   ├── Reservation.java
│       │           │   └── User.java
│       │           ├── model
│       │           │   ├── ErrorResponse.java
│       │           │   ├── FieldError.java
│       │           │   ├── ReservationDTO.java
│       │           │   └── UserDTO.java
│       │           ├── repos
│       │           │   ├── ReservationRepository.java
│       │           │   └── UserRepository.java
│       │           ├── rest
│       │           │   ├── ReservationController.java
│       │           │   └── UserController.java
│       │           └── service
│       │               ├── ReservationService.java
│       │               └── UserService.java
│       └── resources
│           └── application.yml
└── target
    ├── classes
    │   ├── application.yml
    │   └── com
    │       └── amenity_reservation_system
    │           ├── AmenityReservationSystemApplication.class
    │           ├── HomeController.class
    │           ├── config
    │           │   ├── DomainConfig.class
    │           │   ├── JacksonConfig.class
    │           │   └── RestExceptionHandler.class
    │           ├── domain
    │           │   ├── Reservation.class
    │           │   └── User.class
    │           ├── model
    │           │   ├── ErrorResponse.class
    │           │   ├── FieldError.class
    │           │   ├── ReservationDTO.class
    │           │   └── UserDTO.class
    │           ├── repos
    │           │   ├── ReservationRepository.class
    │           │   └── UserRepository.class
    │           ├── rest
    │           │   ├── ReservationController.class
    │           │   └── UserController.class
    │           └── service
    │               ├── ReservationService.class
    │               └── UserService.class
    └── generated-sources
        └── annotations
</code></pre><h2 id="heading-how-to-test-and-explore-the-generated-code">How to Test and Explore the Generated Code</h2>
<p>Let's take our time to experiment with the generated code and understand it layer by layer.</p>
<p>The <strong>Repos</strong> folder contains the code for the data access layer, namely our repositories. We will use <strong>JPA</strong> methods to retrieve our data, which are pre-made query methods you can use by defining them inside the repository interface. </p>
<p>Notice that our repository classes extend the <strong>JpaRepository</strong> interface. This is the interface that allows us to use the mentioned methods. </p>
<p>JPA queries follow a certain convention, and when we create the method that obeys the conventions, it will automatically know what data you want to retrieve, behind the scenes. If you don't yet get it, do not worry, we will see examples.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-5-1024x719.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example keywords, sample phrases and their corresponding JPQL snippets (queries)</em></p>
<p>The <strong>Model</strong> classes present our data model, and which classes will have which fields. </p>
<p>Each model class corresponds to a database table with the same name and the fields in the model class will be columns in the corresponding table. </p>
<p>Notice the annotation <strong>@Entity</strong> on top of our model classes. This annotation is handled by <a target="_blank" href="https://hibernate.org/"><strong>Hibernate</strong></a> and whenever Hibernate sees <strong>@Entity</strong>, it will create a table using the name of our class as table name. </p>
<p>If you are wondering, "What is Hibernate anyways?", it is an <strong>object-relational-mapping</strong> (ORM) tool for Java that allows us to map the <strong>POJOs</strong> (Plain Old Java Object) to database tables. It can also provide features such as data validation constraints, but we will not go deep into Hibernate in this post since it is a vast topic on its own. </p>
<p>An awesome feature of Hibernate is that it handles all table creation and deletion operations so you don't have to use additional <strong>SQL</strong> scripts.</p>
<p>We also represent the relationships between objects in model classes. To see an example, take a look at our <strong>User</strong> class:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@OneToMany(mappedBy = "user")</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; userReservations;
</code></pre>
<p>It has a <strong>userReservations</strong> object that holds a set of references that resembles the reservations of this particular user. In the <strong>Reservation</strong> class we have the reverse-relation as:</p>
<pre><code class="lang-java"><span class="hljs-meta">@ManyToOne(fetch = FetchType.LAZY)</span>
<span class="hljs-meta">@JoinColumn(name = "user_id", nullable = false)</span>
<span class="hljs-keyword">private</span> User user;
</code></pre>
<p>Having references on both sides makes it possible to access the other side of the relationship (user object to reservation and vice versa).</p>
<p><strong>Controllers</strong> will handle the requests that are passed to this controller by the request handler and return the corresponding views, in this case. </p>
<p>The controllers that were generated by Bootify are configured to return JSON responses, and we will modify them in the next section to return our views.</p>
<p><strong>Services</strong> will hold the logic of our application. The best practice is to keep controllers thin by keeping the business logic in a separate place, the service classes. </p>
<p>Controllers should not interact with the repositories directly, but instead call the service which will interact with the repository, perform any additional operation, and return the result to the controller.</p>
<h3 id="heading-lets-try-out-the-api">Let's Try Out the API</h3>
<p>Now, let's get to the fun part and try our API to see it on action. Run the Spring application on your favorite IDE. Open your browser and go to this address:</p>
<pre><code>http:<span class="hljs-comment">//localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/</span>
</code></pre><p>Swagger automatically documents our code and allows you to send requests easily. You should be seeing this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-localhost-8080-swagger-ui-index-html-2021-04-17-21_27_48-1024x914.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Let's first create a user by sending a <strong>POST</strong> request to <strong>UserController</strong>. We will do that by clicking the last box (the green one) under user-controller list.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/Screen-Shot-2021-04-17-at-21.30.41-1024x565.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Swagger</strong> shows us the parameters that this endpoint expects – only the id for now – and also the responses that the API returns. </p>
<p>Click the "Try it out" button at the top right corner. It asks you to enter an id. I know it is nonsense and the code will not even use this id you enter, but we will fix that in the next section (it is just a problem with the generated code). </p>
<p>For the sake of experimenting, enter any number, like 1 for the id, and click the execute button.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/screencapture-localhost-8080-swagger-ui-index-html-2021-04-17-21_39_32-547x1024.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The response body contains the id of the created object. We can confirm that it is created on the database by checking the H2 console. </p>
<p>But before doing that, we need to make a minor adjustment to the <strong>application.yml</strong> file which contains the application settings and configuration. Open your <strong>application.yml</strong> file and paste in the following code:</p>
<pre><code>spring:
  datasource:
    url: ${<span class="hljs-attr">JDBC_DATABASE_URL</span>:jdbc:h2:mem:amenity-reservation-system}
    <span class="hljs-attr">username</span>: ${<span class="hljs-attr">JDBC_DATABASE_USERNAME</span>:sa}
    <span class="hljs-attr">password</span>: ${<span class="hljs-attr">JDBC_DATABASE_PASSWORD</span>:}
  <span class="hljs-attr">dbcp2</span>:
    max-wait-millis: <span class="hljs-number">30000</span>
    validation-query: <span class="hljs-string">"SELECT 1"</span>
    validation-query-timeout: <span class="hljs-number">30</span>
  <span class="hljs-attr">jpa</span>:
    hibernate:
      ddl-auto: update
    open-<span class="hljs-keyword">in</span>-view: <span class="hljs-literal">false</span>
    <span class="hljs-attr">properties</span>:
      hibernate:
        jdbc:
          lob:
            non_contextual_creation: <span class="hljs-literal">true</span>
        <span class="hljs-attr">id</span>:
          new_generator_mappings: <span class="hljs-literal">true</span>
<span class="hljs-attr">springdoc</span>:
  pathsToMatch: <span class="hljs-regexp">/api/</span>**
</code></pre><p>Then we should be able to access the H2 console by going to this address:</p>
<pre><code>http:<span class="hljs-comment">//localhost:8080/h2-console/</span>
</code></pre><p><img src="https://erinc.io/wp-content/uploads/2021/04/image-6-1024x724.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here you need to check that the username is "sa" and click the Connect button.</p>
<p>Click the USER table on the left menu and the console will write the select all query for you.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-7-1024x573.png" alt="Image" width="600" height="400" loading="lazy">
<em>H2 Admin Panel</em></p>
<p>Let's click the <strong>Run</strong> button that is above the query.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-8-1024x466.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We can see that the <strong>User</strong> object is indeed created – great!</p>
<p>We already have a working API at this point and we have not written a single line of code.</p>
<h3 id="heading-how-to-adjust-the-code-for-our-use-case">How to Adjust the Code for our Use Case</h3>
<p>As I mentioned earlier, the generated code does not fully suit our use case and we need to make some adjustments to it. </p>
<p>Let's remove the model folder which contains DTOs and stuff that we will not use. We will show the data inside views instead.</p>
<pre><code>cd src/main/java/com/amenity_reservation_system/ 
rm -rf model
</code></pre><p>We will have a lot of errors now since the code uses the DTO classes, but we will get rid of most of it after removing the controller classes. </p>
<p>We will delete the controllers because we do not want to expose the functionality of modifying our data anymore. Our users should be able to do that by interacting with our UI, and we will create new controllers to return the view components in the next section.</p>
<pre><code>rm -rf rest
</code></pre><p>Finally, we need to do some refactoring to our service classes since the DTO classes are not present anymore:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> org.springframework.web.server.ResponseStatusException;


<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserService</span><span class="hljs-params">(<span class="hljs-keyword">final</span> UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;User&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findAll();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> User user)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.save(user).getId();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id, <span class="hljs-keyword">final</span> User user)</span> </span>{
        <span class="hljs-keyword">final</span> User existingUser = userRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));

        userRepository.save(user);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        userRepository.deleteById(id);
    }
}
</code></pre>
<p>We basically removed the DTO-related code from the <strong>UserService</strong> class and replaced the return types with <strong>User</strong>. Let's do the same for <strong>ReservationService</strong>.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> org.springframework.web.server.ResponseStatusException;


<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReservationService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ReservationRepository reservationRepository;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReservationService</span><span class="hljs-params">(<span class="hljs-keyword">final</span> ReservationRepository reservationRepository,
            <span class="hljs-keyword">final</span> UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.reservationRepository = reservationRepository;
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Reservation&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.findAll();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Reservation <span class="hljs-title">get</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id, <span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">final</span> Reservation existingReservation = reservationRepository.findById(id)
                .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> ResponseStatusException(HttpStatus.NOT_FOUND));
        reservationRepository.save(reservation);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Long id)</span> </span>{
        reservationRepository.deleteById(id);
    }

}
</code></pre>
<p>Let's also remove the config classes:</p>
<pre><code>rm -rf config
</code></pre><p>And rename the domain folder to model. If you are using an IDE, I strongly advise that you use your IDE's rename functionality to rename this folder since it will automatically rename the imports to match the new package name.</p>
<pre><code>mv domain model
</code></pre><p>Also, make sure that your model classes (<strong>User</strong> and <strong>Reservation</strong>) have the right package name after this operation. The first line of these two files should be:</p>
<pre><code>package com.amenity_reservation_system.model;
</code></pre><p>If it stays as domain package, you may have errors.</p>
<p>At this point, you should be able to compile and run the project without any problems.</p>
<h2 id="heading-how-to-create-the-controllers-and-view-files-to-show-data">How to Create the Controllers and View Files to Show Data</h2>
<p><strong>Thymeleaf</strong> is a template engine for Spring that allows us to create UIs and display our model data to the users. </p>
<p>We can access the Java objects inside the Thymeleaf template, and we can also use plain old HTML, CSS and JavaScript. If you know about JSPs, this is JSP on steroids.</p>
<p>Let's create some Thymeleaf templates that will not do anything but show the data for now. We will style them in the next section. We will also create the controllers that will return these views.</p>
<p>Before getting started with the Thymeleaf templates, we need to add a Maven dependency for Spring Boot Thymeleaf. Your dependencies should look like this in your <strong>pom.xml</strong> file:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
        <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">parent</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.4.4<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span> /&gt;</span><span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>amenity-reservation-system<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>amenity-reservation-system<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>14<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-validation<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.h2database<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>h2<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springdoc<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>springdoc-openapi-ui<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.5.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-devtools<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.projectlombok<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>lombok<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.18.20<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>provided<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-thymeleaf<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

    <span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span>
</code></pre>
<p>You can just copy and paste the inner content of the dependencies tag. Now let's tell Maven to install the dependencies:</p>
<pre><code>mvn clean install
</code></pre><p>We are now ready to create our views. Let's create a directory under resources to hold our view template files like this:</p>
<pre><code>cd ../../../resources
mkdir templates
</code></pre><p>And create a view file:</p>
<pre><code>cd templates
touch index.html
</code></pre><p>Copy and paste the following snippet into it. This file will be our home page in the future.</p>
<pre><code>&lt;!DOCTYPE HTML&gt;
<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Amenities Reservation App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
hello world!
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></span>
</code></pre><p>We also need to create a controller that will return us this view so we can see it in the browser.</p>
<pre><code>cd ../java/com/amenity_reservation_system
mkdir controller &amp;&amp; cd controller
touch HomeController
</code></pre><p>Paste this code into the HomeController:</p>
<pre><code>package com.amenity_reservation_system.controller;

<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.ui.Model;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;


@Controller
public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeController</span> </span>{

    @GetMapping(<span class="hljs-string">"/"</span>)
    public <span class="hljs-built_in">String</span> index(Model model) {

        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;
    }
}
</code></pre><p>Notice how we annotate our method with <strong>@Controller</strong> instead of <strong>@RestController</strong> this time. The @RestController annotation implies that the controller will return a REST response whereas a <strong>@Controller</strong> can return pre-rendered (SSR) views/HTML.</p>
<p>When a request arrives in our application, Spring will automatically run this controller method. Then it will find the <strong>index.html</strong> file we previously created under the resources and send that file to the client.</p>
<p>Let's confirm that it is working by sending a request to our application. Do not forget to restart first, then send this request:</p>
<pre><code>GET localhost:<span class="hljs-number">8080</span>
</code></pre><p>You should be able to see the Hello World message on the browser.</p>
<h2 id="heading-how-to-define-different-types-of-amenities">How to Define Different Types of Amenities</h2>
<p>We have the <strong>Reservation</strong> class but we have not created a way to specify which type of amenity is getting reserved (the pool, sauna, or gym).</p>
<p>There are multiple ways to do this. One of them would be to create an entity called Amenity to store shared data among entities. Then we'd create <strong>PoolAmenity</strong>, <strong>SaunaAmenity</strong>, and <strong>GymAmenity</strong> classes which would then extend the Amenity class. </p>
<p>This is a nice and extendable solution but it feels a bit like overkill for our simple application, since we do not have much data specific to the amenity type. We are only going to have a capacity for each amenity type.</p>
<p>To keep things simple and not to bother ourselves with table inheritance and other complicated stuff, let's just create an enum to indicate the amenity type as a String and let each reservation have one of these.</p>
<p>Let's switch to the model directory from the controller directory and create the enum for <strong>AmenityType</strong>:</p>
<pre><code>cd ../model
touch AmenityType.java
</code></pre><pre><code>public enum AmenityType {
    POOL(<span class="hljs-string">"POOL"</span>), SAUNA(<span class="hljs-string">"SAUNA"</span>), GYM(<span class="hljs-string">"GYM"</span>);

    private final <span class="hljs-built_in">String</span> name;

    private AmenityType(<span class="hljs-built_in">String</span> value) {
        name = value;
    }

    @Override
    public <span class="hljs-built_in">String</span> toString() {
        <span class="hljs-keyword">return</span> name;
    }
}
</code></pre><p>In this enum, we define a name variable to hold the name of the enum and create a private constructor to only allow a limited set of types. Notice that the type declarations call the constructor from within the class with their name values.</p>
<p>Now we need to modify the Reservation class to hold a reference to <strong>AmenityType</strong>:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Enumerated(EnumType.STRING)</span>
<span class="hljs-meta">@Column(nullable = false)</span>
<span class="hljs-keyword">private</span> AmenityType amenityType;
</code></pre>
<p>We use the <strong>@Enumerated</strong> annotation to describe how we want to store the enum in our database. We'll also make it not nullable because every <strong>Reservation</strong> must have an <strong>AmenityType</strong>.</p>
<h2 id="heading-how-to-show-a-users-reservations">How to Show a User's Reservations</h2>
<p>What is the most crucial feature for our app? Creating reservations and showing a user's reservations. </p>
<p>We do not have a way to authenticate users yet, so we can't really ask the user to login and then show their reservations. But we still want to implement and test the functionality to reserve an amenity and show reservations.</p>
<p>For that purpose, we can ask Spring to put some initial data into our database whenever the application runs. Then we can query that data to test if our queries actually work. We can then proceed to call these services from our <strong>Views</strong> and add authentication to our application in the next sections.</p>
<p>We will use a <strong>CommandLineRunner</strong> bean to run the initial code. Whenever Spring Container finds a bean of type CommandLineRunner it will run the code inside it. Before that step, let's add a few methods to our model classes to make object creation easier and less verbose.</p>
<p>Take a look at the model classes' annotations and you should see annotations like <strong>@Getter</strong> and <strong>@Setter</strong>. These are <strong>Lombok</strong> annotations.</p>
<p>Lombok is an annotation processor we can use to make our coding experience better by letting it generate code for us. When we annotate a class with <strong>@Getter</strong> and <strong>@Setter</strong>, it generates the getters and setters for each field of this class. </p>
<p>Spring uses getter and setter methods for many trivial operations behind the scenes so these are almost always required. And creating them for every entity easily becomes a hassle without the help of Lombok. </p>
<p>Lombok can do more than that though. We will also add the following annotations to our <strong>Reservation</strong> and <strong>User</strong> classes:</p>
<pre><code>@Builder
@NoArgsConstructor
@AllArgsConstructor
</code></pre><p>With these annotations, Lombok implements the builder creational pattern for this class and also creates 2 constructors: One with no arguments (default constructor) and another one with all arguments. I think it is awesome that we can do so much by adding just a few annotations. </p>
<p>We are now ready to add some initial data. Go to your main class (<strong>AmenityReservationSystemApplication.java</strong>) and add this method:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;


<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        SpringApplication.run(AmenityReservationSystemApplication.class, args);
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(UserRepository userRepository,
                                      ReservationRepository reservationRepository)</span> </span>{
        <span class="hljs-keyword">return</span> (args) -&gt; {
            User user = userRepository.save(<span class="hljs-keyword">new</span> User());
            DateFormat dateFormat = <span class="hljs-keyword">new</span> SimpleDateFormat(<span class="hljs-string">"dd/MM/yyyy HH:mm:ss"</span>);
            Date date = <span class="hljs-keyword">new</span> Date();
            LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            Reservation reservation = Reservation.builder()
                    .reservationDate(localDate)
                    .startTime(LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">00</span>))
                    .endTime(LocalTime.of(<span class="hljs-number">13</span>, <span class="hljs-number">00</span>))
                    .user(user)
                    .amenityType(AmenityType.POOL)
                    .build();

            reservationRepository.save(reservation);
        };
    }
}
</code></pre>
<p>If you get an error about saving operations such as "Inferred type 'S' for parameter ... does not match", it's because we renamed the domain directory to model. Go to the repository classes and fix the paths of imports to <strong>model.User</strong> and <strong>model.Reservation</strong>.</p>
<p>Notice how we used the <strong>builder pattern</strong> to create the reservation object easily. When the object creation gets complex and a constructor requires so many parameters, it's easy to forget the order of parameters or just mess up the order. </p>
<p>Without the builder pattern, we would either need to call a constructor with so many parameters or call the default constructor and write #properties code to call the setters.</p>
<p>After you are done, run your application again to insert the initial data and connect to <strong>H2 console</strong> as we learned before to confirm that our date is indeed inserted. If you do not have any errors, you should be able to see that the user and the reservation are inserted successfully.</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/04/image-9-1024x325.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We have inserted a reservation to be able to test the functionality to list the reservations but our views currently do not have a way to show the reservations and add reservations. We need to create the UI for that. </p>
<p>We do not have an authentication or sign-up mechanism yet, so act like the user with ID 10001 is logged in. Later we will improve on that by dynamically checking who is logged in and showing a different page if the user is not logged in.</p>
<h3 id="heading-how-to-create-views-with-thymeleaf">How to Create Views with Thymeleaf</h3>
<p>Let's get started by creating a simple home page and a navbar for ourselves. We will use Thymeleaf fragments for the navbar code. </p>
<p>Thymeleaf fragments allow us to create reusable component-like structures similar to React/Vue components if you are familiar with them. Let's create a folder for our fragments under templates and call it fragments.</p>
<pre><code>mkdir fragments
touch nav.html
</code></pre><p>We will put our navbar inside <strong>nav.html</strong> file. Copy and paste the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"nav"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar navbar-expand navbar-dark bg-primary"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav w-100"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Amenities Reservation System<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It is not doing much in its current state, but we may add a login button or some links in the future. </p>
<p>Now let's create a simple home page that will serve the users that are not logged in. We will have our navbar fragment on top and have a login button to ask the user to log in before using the app.</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">HTML</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Amenities Reservation App<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"text-light"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"background-image: url('https://source.unsplash.com/1920x1080/?nature');
                                   position: absolute;
                                   left: 0;
                                   top: 0;
                                   opacity: 0.6;
                                   z-index: -1;
                                   min-height: 100vh;
                                   min-width: 100vw;"</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 20vh; display: flex; flex-direction: column; align-items: center;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"display-3"</span>&gt;</span>Reservation management made easy.<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"lead"</span>&gt;</span>Lorem, ipsum dolor sit amet consectetur adipisicing elit.
            Numquam in quia natus magnam ducimus quas molestias velit vero maiores.
            Eaque sunt laudantium voluptas. Fugiat molestiae ipsa delectus iusto vel quod.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/reservations"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-success btn-lg my-2"</span>&gt;</span>Reserve an Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>It should look like this:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/05/image-1024x533.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We will create another page to show if the user is already logged in. To keep it simple we will also treat it as a home page, and if the user is logged in, they will be able to see their reservations on the home page. </p>
<p>It is also good in terms of practicality for the user since it decreases the steps they need to take to view their reservations. </p>
<p>We will now create this page as another endpoint. But after adding the login to our application we will show this previous page if the user is not logged in and the next page if they are logged in, dynamically.</p>
<p>Before we start working on our new page, let's add another mapping to <strong>HomeController</strong> that will return our new page. We will later merge these two controllers:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.domain.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.service.UserService;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.ui.Model;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ResponseBody;


<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HomeController</span> </span>{

    <span class="hljs-keyword">final</span> UserService userService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HomeController</span><span class="hljs-params">(UserService userService)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
    }

    <span class="hljs-meta">@GetMapping("/")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">index</span><span class="hljs-params">(Model model)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;
    }

    <span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        model.addAttribute(<span class="hljs-string">"user"</span>, user);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
}
</code></pre>
<p>If a request is received at "/reservations", this code will call our userService and ask for the user with id 10000L. Then it will add this user to the <strong>Model</strong>. </p>
<p>View will access this model and present the information about this user's reservations. We have also autowired the user service to use it.</p>
<p>Navigate to the templates folder if you are not already there and create another file called "reservations.html":</p>
<pre><code>touch reservations.html
</code></pre><p>Copy and paste the following code:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">HTML</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>/&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Reservations<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>/&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 10vh; display: flex; flex-direction: column; align-items: center;"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Start Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>End Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">th:each</span>=<span class="hljs-string">"reservation : ${user.getReservations()}"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getAmenityType()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getReservationDate()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getStartTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getEndTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>In this <strong>Thymeleaf</strong> template, we import <strong>Bootstrap</strong> and <strong>Thymeleaf</strong> as before and we access the user variable that was added to the model in our controller by using the ${} syntax. </p>
<p>To access data, Thymeleaf uses the getter methods of the object and we can print that information by using the <code>th:text</code> attribute. Thymeleaf also supports loops. In the <code>tbody</code> we have a <code>th:each</code> loop, which we can think of as a foreach loop over a user's reservations. So we loop over the reservations and display them in a table.</p>
<p>You may have an error that says something like "Could not initialize proxy, ... lazy loading". This is caused by the view trying to access the reservations object while it does not yet exist. To get rid of that we can modify the following lines in <strong>User.java</strong>:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; reservations = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();
</code></pre>
<p>We add a statement to tell Java to fetch this object eagerly.</p>
<p>Now you should be able to view the reservations page:</p>
<p><img src="https://erinc.io/wp-content/uploads/2021/05/image-1-1024x488.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-create-a-reservation">How to Create a Reservation</h3>
<p>We also need a way to create new reservations, so let's build that mechanism for our pre-created user like we did with showing the reservations. Then we can alter it to show the reservations of the currently logged-in user.</p>
<p>Before going forward, we need to update the date formats in our <strong>Reservation.java</strong> file to avoid any format mismatch problems. Make sure your formats for these variables are the same:</p>
<pre><code class="lang-java">    <span class="hljs-meta">@DateTimeFormat(pattern = "yyyy-MM-dd")</span>
    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> LocalDate reservationDate;

    <span class="hljs-meta">@DateTimeFormat(pattern = "HH:mm")</span>
    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> LocalTime startTime;

    <span class="hljs-meta">@DateTimeFormat(pattern = "HH:mm")</span>
    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> LocalTime endTime;
</code></pre>
<p>In the previous section, we created our <strong>reservations</strong> controller. Now we need to modify it a little bit to add another attribute to the model. </p>
<p>We learned how we can access the objects that are added to the model by using the ${} syntax. Now we are going to do something similar:</p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        session.setAttribute(<span class="hljs-string">"user"</span>, user);
        Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
        model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
</code></pre>
<p>We are updating our reservations controller to move the user object to the session because we want that to be accessible from another controller method and not only from a template. </p>
<p>Think of it like this: once a user is logged in, this user's account will be responsible for every action that's taken after that point. You can think of Session as a global variable that is accessible from everywhere. </p>
<p>We also create a <strong>Reservation</strong> object and add it to the model. <strong>Thymeleaf</strong> will access this newly created object in our view template using this model and it will call the setters to set its fields.</p>
<p>Now let's create the view for creating the reservation. We are going to use <a target="_blank" href="https://getbootstrap.com/docs/4.0/components/modal/">Bootstrap Modal</a> to display a form modal after a button is clicked.</p>
<p>We can first handle the code to call the modal we are going to create in the next step, move to the reservations.html file, and add this snippet after the table tag we added before:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
  <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>
  <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"modal"</span>
  <span class="hljs-attr">data-target</span>=<span class="hljs-string">"#createReservationModal"</span>
&gt;</span>
  Create Reservation
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Modal --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span>
  <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/modal :: modal"</span>
  <span class="hljs-attr">th:with</span>=<span class="hljs-string">"reservation=${reservation}"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This button will trigger our modal. In the div, we insert this modal that we are going to create and we use the <code>th:with</code> tag to pass the reservation object that was put in the model in our controller. If we do not do this, the fragment will not know about the reservation object.</p>
<p>We also need to change how we access the user to print their name because we no longer store it in the modal but in session:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${session.user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
</code></pre>
<p>So your final <strong>reservations.html</strong> file should be looking like this:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Reservations<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">link</span>
      <span class="hljs-attr">th:rel</span>=<span class="hljs-string">"stylesheet"</span>
      <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "</span>
    /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/nav :: nav"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
        <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>
        <span class="hljs-attr">style</span>=<span class="hljs-string">"padding-top: 10vh; display: flex; flex-direction: column; align-items: center;"</span>
      &gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h3</span>&gt;</span>Welcome <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">" ${session.user.getFullName()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h3</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>Start Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"col"</span>&gt;</span>End Time<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">tr</span> <span class="hljs-attr">th:each</span>=<span class="hljs-string">"reservation : ${session.user.getReservations()}"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getAmenityType()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getReservationDate()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getStartTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">td</span> <span class="hljs-attr">th:text</span>=<span class="hljs-string">"${reservation.getEndTime()}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>

        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>
          <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"modal"</span>
          <span class="hljs-attr">data-target</span>=<span class="hljs-string">"#createReservationModal"</span>
        &gt;</span>
          Create Reservation
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- Modal --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
          <span class="hljs-attr">th:insert</span>=<span class="hljs-string">"fragments/modal :: modal"</span>
          <span class="hljs-attr">th:with</span>=<span class="hljs-string">"reservation=${reservation}"</span>
        &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/jquery/3.0.0/jquery.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/popper.js/1.12.9-1/umd/popper.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">th:src</span>=<span class="hljs-string">"@{/webjars/bootstrap/4.0.0-2/js/bootstrap.min.js}"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>We are now ready to create the modal fragment. We can create a fragment for the modal just like we did with the nav:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">pwd</span>
/src/main/resources
<span class="hljs-built_in">cd</span> templates/fragments
touch modal.html
</code></pre>
<p>And paste in the following template code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
      <span class="hljs-attr">class</span>=<span class="hljs-string">"modal fade"</span>
      <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"modal"</span>
      <span class="hljs-attr">id</span>=<span class="hljs-string">"createReservationModal"</span>
      <span class="hljs-attr">tabindex</span>=<span class="hljs-string">"-1"</span>
      <span class="hljs-attr">role</span>=<span class="hljs-string">"dialog"</span>
      <span class="hljs-attr">aria-labelledby</span>=<span class="hljs-string">"createReservationModalTitle"</span>
      <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>
    &gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-dialog"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"document"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-content"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-header"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-title"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"createReservationModalTitle"</span>&gt;</span>
              Create Reservation
            <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
              <span class="hljs-attr">class</span>=<span class="hljs-string">"close"</span>
              <span class="hljs-attr">data-dismiss</span>=<span class="hljs-string">"modal"</span>
              <span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Close"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">aria-hidden</span>=<span class="hljs-string">"true"</span>&gt;</span><span class="hljs-symbol">&amp;times;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-body"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span>
              <span class="hljs-attr">action</span>=<span class="hljs-string">"#"</span>
              <span class="hljs-attr">th:action</span>=<span class="hljs-string">"@{/reservations-submit}"</span>
              <span class="hljs-attr">th:object</span>=<span class="hljs-string">"${reservation}"</span>
              <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"type-select"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>Amenity<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">select</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"type-select"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{amenityType}"</span>
                  &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"POOL"</span>&gt;</span>POOL<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"SAUNA"</span>&gt;</span>SAUNA<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">option</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"GYM"</span>&gt;</span>GYM<span class="hljs-tag">&lt;/<span class="hljs-name">option</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"start-date"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>Date<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"start-date"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"trip-start"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{reservationDate}"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">"2018-07-22"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"2021-05-01"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"2021-12-31"</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"start-time"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>
                  &gt;</span>From<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>
                &gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"start-time"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{startTime}"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"08:00"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"19:30"</span>
                    <span class="hljs-attr">required</span>
                  /&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-group row"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"end-time"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-2 col-form-label"</span>&gt;</span>To<span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"col-10"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">id</span>=<span class="hljs-string">"end-time"</span>
                    <span class="hljs-attr">name</span>=<span class="hljs-string">"time"</span>
                    <span class="hljs-attr">th:field</span>=<span class="hljs-string">"*{endTime}"</span>
                    <span class="hljs-attr">min</span>=<span class="hljs-string">"08:30"</span>
                    <span class="hljs-attr">max</span>=<span class="hljs-string">"20:00"</span>
                    <span class="hljs-attr">required</span>
                  /&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">small</span>&gt;</span>Amenities are available from 8 am to 8 pm<span class="hljs-tag">&lt;/<span class="hljs-name">small</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"modal-footer"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                  <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-secondary"</span>
                  <span class="hljs-attr">data-dismiss</span>=<span class="hljs-string">"modal"</span>
                &gt;</span>
                  Close
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Submit"</span>&gt;</span>
                  Save changes
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>There are a few important points that you need to take note of here.</p>
<p>Notice how we access the reservation object in the form tag:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span>
  <span class="hljs-attr">action</span>=<span class="hljs-string">"#"</span>
  <span class="hljs-attr">th:action</span>=<span class="hljs-string">"@{/reservations-submit}"</span>
  <span class="hljs-attr">th:object</span>=<span class="hljs-string">"${reservation}"</span>
  <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span>
&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
</code></pre>
<p>The <strong><code>th:object</code></strong> tag associates this form with the reservation object that we have created before. <strong><code>th:action</code></strong> determines where this object will be sent when the form is submitted, and our submission method will be <strong>POST</strong>. We will create this controller with the mapping to <strong>/reservations-submit</strong> after this step.</p>
<p>We use the <strong><code>th:field</code></strong> tag to bind the inputs to our reservation object's fields. Thymeleaf calls the setters of the reservation object whenever that input field's value changes.</p>
<p>Now let's create the controller that will receive this form. Go to <strong>HomeController</strong> and add the following method:</p>
<pre><code class="lang-java"><span class="hljs-meta">@PostMapping("/reservations-submit")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservationsSubmit</span><span class="hljs-params">(<span class="hljs-meta">@ModelAttribute</span> Reservation reservation,
                                     <span class="hljs-meta">@SessionAttribute("user")</span> User user)</span> </span>{

        <span class="hljs-comment">// Save to DB after updating</span>
        <span class="hljs-keyword">assert</span> user != <span class="hljs-keyword">null</span>;
        reservation.setUser(user);
        reservationService.create(reservation);
        Set&lt;Reservation&gt; userReservations = user.getReservations();
        userReservations.add(reservation);
        user.setReservations(userReservations);
        userService.update(user.getId(), user);
        <span class="hljs-keyword">return</span> <span class="hljs-string">"redirect:/reservations"</span>;
    }
</code></pre>
<p>And also add the <strong>ReservationService</strong> to our dependencies:</p>
<pre><code class="lang-java">    <span class="hljs-keyword">final</span> UserService userService;
    <span class="hljs-keyword">final</span> ReservationService reservationService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HomeController</span><span class="hljs-params">(UserService userService, ReservationService reservationService)</span> </span>{
        <span class="hljs-keyword">this</span>.userService = userService;
        <span class="hljs-keyword">this</span>.reservationService = reservationService;
    }
</code></pre>
<p>After our modal fragment posts the reservation object to this controller, that object will be bound with the <strong>@ModelAttribute</strong> annotation. We also need the user so we use <strong>@SessionAttribute</strong> to get a reference to it.</p>
<p>The fields of the reservation object should be all set by the form. Now we just need to save it to the database. </p>
<p>We do that by calling the <strong>create</strong> method. Then we add the new Reservation to the user's list of reservations and update the user to reflect these changes. We then redirect the user to the reservations page to show the updated reservations list.</p>
<p>Your reservations page should look like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/LFJE0Ad---Imgur.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>And when you click the button, the create reservation modal should pop up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/image-42.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-add-authentication-and-authorization-to-the-app">How to Add Authentication and Authorization to the App</h2>
<p>We will use <strong>Spring Security</strong> to add authentication and authorization to our application. We want to make sure that nobody can see each other's reservations and that the users must be logged in to create reservations. </p>
<p>If you want to learn more about it, I wrote an article that provides an overview of <a target="_blank" href="https://auth0.com/blog/spring-security-overview/">Spring Security</a>. </p>
<p>We will keep it simple and mostly use the defaults because this is a difficult topic on its own. If you want to learn how to properly set up Spring Security Auth, you can check out my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/">article</a> on that. </p>
<p>We need to add "Spring Security" and "Thymeleaf Spring Security" to our dependencies, so open your pom.xml and add the following to your list of dependencies:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.thymeleaf.extras<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>thymeleaf-extras-springsecurity5<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>3.0.4.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>Now, by default, Spring Security makes all the endpoints protected, so we need to configure it to allow viewing the home page. </p>
<p>Let's create a config folder to contain our <strong>WebSecurityConfig</strong> file. Assuming you are on the root folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /src/main/java/com/amenity_reservation_system
mkdir config &amp;&amp; <span class="hljs-built_in">cd</span> config
touch WebSecurityConfig.java
</code></pre>
<p>This should be the content of your config file:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.config;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.service.UserDetailsServiceImpl;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
<span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-meta">@EnableWebSecurity</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WebSecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">WebSecurityConfigurerAdapter</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> UserDetailsServiceImpl userDetailsService;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BCryptPasswordEncoder bCryptPasswordEncoder;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">WebSecurityConfig</span><span class="hljs-params">(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder)</span> </span>{
        <span class="hljs-keyword">this</span>.userDetailsService = userDetailsService;
        <span class="hljs-keyword">this</span>.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        http
                .authorizeRequests()
                .antMatchers(<span class="hljs-string">"/"</span>, <span class="hljs-string">"/webjars/**"</span>).permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .logoutSuccessUrl(<span class="hljs-string">"/"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>{
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

}
</code></pre>
<p>I will not go into the details, but here's a summary of what happened here: </p>
<ul>
<li>we configured Spring Security to permit all requests made to the home page ("/")</li>
<li>we configured our styles ("/webjars/**")</li>
<li>we asked it to provide us with login and logout forms </li>
<li>and we asked it to permit the requests to them as well and redirect to the home page after logout is successful</li>
</ul>
<p>Isn't it amazing what you can achieve with just a few statements?</p>
<p>We also configured our <strong>AuthenticationManagerBuilder</strong> to use bCryptPasswordEncoder and userDetailsService. But wait, we don't have neither of them yet, and your IDE may already be complaining about that. So let's create them.</p>
<p>Before we go on, it may be a good idea to add <strong>username</strong> and passwordHash fields to our <strong>User</strong> class. We'll use them to authenticate the user instead of using their full name. Then we'll add it to the constructor.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.model;

<span class="hljs-keyword">import</span> java.time.OffsetDateTime;
<span class="hljs-keyword">import</span> java.util.HashSet;
<span class="hljs-keyword">import</span> java.util.Set;
<span class="hljs-keyword">import</span> javax.persistence.*;

<span class="hljs-keyword">import</span> lombok.AllArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Getter;
<span class="hljs-keyword">import</span> lombok.NoArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Setter;


<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Getter</span>
<span class="hljs-meta">@Setter</span>
<span class="hljs-meta">@AllArgsConstructor</span>
<span class="hljs-meta">@NoArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{

    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-meta">@SequenceGenerator(
            name = "primary_sequence",
            sequenceName = "primary_sequence",
            allocationSize = 1,
            initialValue = 10000
    )</span>
    <span class="hljs-meta">@GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "primary_sequence"
    )</span>
    <span class="hljs-keyword">private</span> Long id;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-keyword">private</span> String fullName;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-keyword">private</span> String username;

    <span class="hljs-meta">@Column</span>
    <span class="hljs-keyword">private</span> String passwordHash;

    <span class="hljs-meta">@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)</span>
    <span class="hljs-keyword">private</span> Set&lt;Reservation&gt; reservations = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();

    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-keyword">private</span> OffsetDateTime dateCreated;

    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> OffsetDateTime lastUpdated;

    <span class="hljs-meta">@PrePersist</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">prePersist</span><span class="hljs-params">()</span> </span>{
        dateCreated = OffsetDateTime.now();
        lastUpdated = dateCreated;
    }

    <span class="hljs-meta">@PreUpdate</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preUpdate</span><span class="hljs-params">()</span> </span>{
        lastUpdated = OffsetDateTime.now();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">User</span><span class="hljs-params">(String fullName, String username, String passwordHash)</span> </span>{
        <span class="hljs-keyword">this</span>.fullName = fullName;
        <span class="hljs-keyword">this</span>.username = username;
        <span class="hljs-keyword">this</span>.passwordHash = passwordHash;
    }
}
</code></pre>
<p>Create a file called <strong>UserDetailsServiceImpl</strong> under the services folder:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> service
touch UserDetailsServiceImpl.java
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.service;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetails;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UsernameNotFoundException;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">UserDetailsService</span> </span>{

    <span class="hljs-keyword">private</span> UserRepository userRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">UserDetailsServiceImpl</span><span class="hljs-params">(UserRepository userRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.userRepository = userRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> UserDetails <span class="hljs-title">loadUserByUsername</span><span class="hljs-params">(String username)</span> <span class="hljs-keyword">throws</span> UsernameNotFoundException </span>{
        <span class="hljs-keyword">final</span> User user = userRepository.findUserByUsername(username);

        <span class="hljs-keyword">if</span> (user == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> UsernameNotFoundException(username);
        }

        UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(
                user.getUsername()).password(user.getPwHash()).roles(<span class="hljs-string">"USER"</span>).build();

        <span class="hljs-keyword">return</span> userDetails;
    }
}
</code></pre>
<p>This basically tells Spring Security that we want to use the <strong>User</strong> entity we created earlier by getting the <strong>User</strong> object from our database and using the JPA method on our repository. But again, we do not have the <strong>findUserByUsername</strong> method on our <strong>UserRepository</strong>. You can try fixing this on your own as a challenge, it is really simple.</p>
<p>Remember, we do not need to write queries. It is sufficient to provide the signature and let JPA do the work.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.repos;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> org.springframework.data.jpa.repository.JpaRepository;


<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">Long</span>&gt; </span>{

    <span class="hljs-function">User <span class="hljs-title">findUserByUsername</span><span class="hljs-params">(String username)</span></span>;
}
</code></pre>
<p>We also need a <strong>BCryptPasswordEncoder</strong> bean to satisfy that dependency in <strong>WebSecurityConfig</strong> and to make it work. Let's modify our main class to add a bean and change the constructor parameters to give our predefined <strong>User</strong> a username.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;


<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        SpringApplication.run(AmenityReservationSystemApplication.class, args);
    }


    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(UserRepository userRepository,
                                      ReservationRepository reservationRepository)</span> </span>{
    <span class="hljs-keyword">return</span> (args) -&gt; {
      User user =
          userRepository.save(
              <span class="hljs-keyword">new</span> User(<span class="hljs-string">"Yigit Kemal Erinc"</span>,
                      <span class="hljs-string">"yigiterinc"</span>,
                      bCryptPasswordEncoder().encode(<span class="hljs-string">"12345"</span>)));
      DateFormat dateFormat = <span class="hljs-keyword">new</span> SimpleDateFormat(<span class="hljs-string">"dd/MM/yyyy HH:mm:ss"</span>);
      Date date = <span class="hljs-keyword">new</span> Date();
      LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
      Reservation reservation =
          Reservation.builder()
              .reservationDate(localDate)
              .startTime(LocalTime.of(<span class="hljs-number">12</span>, <span class="hljs-number">00</span>))
              .endTime(LocalTime.of(<span class="hljs-number">13</span>, <span class="hljs-number">00</span>))
              .user(user)
              .amenityType(AmenityType.POOL)
              .build();

      reservationRepository.save(reservation);
    };
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();
    }
}
</code></pre>
<p>Your application should be ready to compile now and it should already be redirecting you to the login page if you send a request to "/reservations". </p>
<p>It would be nice to have buttons for log-in and log-out on the navbar, and we want to show login if user is not authenticated and logout otherwise. We can do it this way in <strong>nav.html</strong>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span> <span class="hljs-attr">xmlns:th</span>=<span class="hljs-string">"http://www.thymeleaf.org"</span> <span class="hljs-attr">xmlns:sec</span>=<span class="hljs-string">"http://www.w3.org/1999/xhtml"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">th:fragment</span>=<span class="hljs-string">"nav"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar navbar-expand navbar-dark bg-primary"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-nav w-100"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>&gt;</span>Amenities Reservation System<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">sec:authorize</span>=<span class="hljs-string">"isAnonymous()"</span>
           <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/login}"</span>&gt;</span>Log in<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">sec:authorize</span>=<span class="hljs-string">"isAuthenticated()"</span>
               <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand text-color"</span> <span class="hljs-attr">th:href</span>=<span class="hljs-string">"@{/logout}"</span>&gt;</span>Log out<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>The log in link should now be visible on the navbar.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/09/Screen-Shot-2021-09-10-at-02.19.09.png" alt="Image" width="600" height="400" loading="lazy">
<em>Home page when you are not logged in</em></p>
<h2 id="heading-how-to-show-a-logged-in-users-reservations">How to Show a Logged-in User's Reservations</h2>
<p>Our Reservations page is currently displaying the reservations of one hard-coded user and not the reservations of the logged-in user. </p>
<pre><code class="lang-java">    <span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        User user = userService.get(<span class="hljs-number">10000L</span>);
        session.setAttribute(<span class="hljs-string">"user"</span>, user);
        Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
        model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

        <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
    }
</code></pre>
<p>We need to show the reservations of the currently logged-in user. To achieve that, we should use some Spring Security.</p>
<p>Go to the <strong>HomeController</strong> (I know, that name is a bit problematic right now) class and change it with the following code:</p>
<pre><code class="lang-java"><span class="hljs-meta">@GetMapping("/reservations")</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">reservations</span><span class="hljs-params">(Model model, HttpSession session)</span> </span>{
        UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String name = principal.getUsername();
        User user = userService.getUserByUsername(name);

        <span class="hljs-comment">// This should always be the case </span>
        <span class="hljs-keyword">if</span> (user != <span class="hljs-keyword">null</span>) {
            session.setAttribute(<span class="hljs-string">"user"</span>, user);

            <span class="hljs-comment">// Empty reservation object in case the user creates a new reservation</span>
            Reservation reservation = <span class="hljs-keyword">new</span> Reservation();
            model.addAttribute(<span class="hljs-string">"reservation"</span>, reservation);

            <span class="hljs-keyword">return</span> <span class="hljs-string">"reservations"</span>;
        }

        <span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;    
        }
</code></pre>
<p>Since we have added Spring Security to the project, it automatically creates the <strong>Authentication</strong> object behind the scenes – we are getting that from <strong>SecurityContextHolder</strong>. </p>
<p>We are grabbing the <strong><a target="_blank" href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/UserDetails.html#:~:text=Interface%20UserDetails&amp;text=Provides%20core%20user%20information.,later%20encapsulated%20into%20Authentication%20objects.">UserDetails</a></strong> object which stores the info related to user. Then we check if the user object is null. This should always be the case since <em>reservations</em> is a protected endpoint and the user must be logged in to see that page – but it is always good to make sure everything is as expected.</p>
<p>Then we call the <strong>UserService</strong> class to get the <strong>User</strong> object which has this username – but we have not added the <strong>getUserByUsername</strong> method yet. So let's move to the <strong>UserService</strong> and add this simple method.</p>
<pre><code class="lang-java">    <span class="hljs-function"><span class="hljs-keyword">public</span> User <span class="hljs-title">getUserByUsername</span><span class="hljs-params">(String username)</span> </span>{
        <span class="hljs-keyword">return</span> userRepository.findUserByUsername(username);
    }
</code></pre>
<p>Now you should be able to see the logged-in user's reservations. You can try that by adding another user and creating reservations for that user as well. </p>
<h3 id="heading-how-to-check-the-capacity">How to Check the Capacity</h3>
<p>We currently don't have a mechanism to store the Capacity of each amenity type. We need to store those somehow and also check that there is enough capacity before we approve a reservation. </p>
<p>For that purpose, let's create a class called <strong>Capacity</strong> under our model folder.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.model;

<span class="hljs-keyword">import</span> lombok.AllArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Getter;
<span class="hljs-keyword">import</span> lombok.NoArgsConstructor;
<span class="hljs-keyword">import</span> lombok.Setter;

<span class="hljs-keyword">import</span> javax.persistence.*;

<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Getter</span>
<span class="hljs-meta">@Setter</span>
<span class="hljs-meta">@AllArgsConstructor</span>
<span class="hljs-meta">@NoArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Capacity</span> </span>{

    <span class="hljs-meta">@Id</span>
    <span class="hljs-meta">@Column(nullable = false, updatable = false)</span>
    <span class="hljs-meta">@SequenceGenerator(
            name = "primary_sequence",
            sequenceName = "primary_sequence",
            allocationSize = 1,
            initialValue = 10000
    )</span>
    <span class="hljs-meta">@GeneratedValue(
            strategy = GenerationType.SEQUENCE,
            generator = "primary_sequence"
    )</span>
    <span class="hljs-keyword">private</span> Long id;

    <span class="hljs-meta">@Column(nullable = false, unique = true)</span>
    <span class="hljs-meta">@Enumerated(EnumType.STRING)</span>
    <span class="hljs-keyword">private</span> AmenityType amenityType;

    <span class="hljs-meta">@Column(nullable = false)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> capacity;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Capacity</span><span class="hljs-params">(AmenityType amenityType, <span class="hljs-keyword">int</span> capacity)</span> </span>{
        <span class="hljs-keyword">this</span>.amenityType = amenityType;
        <span class="hljs-keyword">this</span>.capacity = capacity;
    }
}
</code></pre>
<p>This is the entity that will represent our logical construct to be stored in our database. It is basically a map entry with an AmenityType and its corresponding capacity.</p>
<p>We also need a repository to store the <strong>Capacity</strong> entries, so let's create the CapacityRepository under the <strong>repos</strong> folder.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.repos;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Capacity;
<span class="hljs-keyword">import</span> org.springframework.data.jpa.repository.JpaRepository;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">CapacityRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">Capacity</span>, <span class="hljs-title">Long</span>&gt; </span>{
}
</code></pre>
<p>We need to populate this new table with the initial capacities. We could read the initial capacities from a config file or something, but let's keep it simple and hardcode it using loadData in our main method.</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system;

<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.AmenityType;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Capacity;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.Reservation;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.model.User;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.CapacityRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.ReservationRepository;
<span class="hljs-keyword">import</span> com.amenity_reservation_system.repos.UserRepository;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

<span class="hljs-keyword">import</span> java.text.DateFormat;
<span class="hljs-keyword">import</span> java.text.SimpleDateFormat;
<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.time.LocalTime;
<span class="hljs-keyword">import</span> java.time.ZoneId;
<span class="hljs-keyword">import</span> java.util.Date;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;

<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AmenityReservationSystemApplication</span> </span>{

  <span class="hljs-keyword">private</span> Map&lt;AmenityType, Integer&gt; initialCapacities =
      <span class="hljs-keyword">new</span> HashMap&lt;&gt;() {
        {
          put(AmenityType.GYM, <span class="hljs-number">20</span>);
          put(AmenityType.POOL, <span class="hljs-number">4</span>);
          put(AmenityType.SAUNA, <span class="hljs-number">1</span>);
        }
      };

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
    SpringApplication.run(AmenityReservationSystemApplication.class, args);
  }

  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> CommandLineRunner <span class="hljs-title">loadData</span><span class="hljs-params">(
      UserRepository userRepository,
      CapacityRepository capacityRepository)</span> </span>{
    <span class="hljs-keyword">return</span> (args) -&gt; {
      userRepository.save(
          <span class="hljs-keyword">new</span> User(<span class="hljs-string">"Yigit Kemal Erinc"</span>, <span class="hljs-string">"yigiterinc"</span>, bCryptPasswordEncoder().encode(<span class="hljs-string">"12345"</span>)));

      <span class="hljs-keyword">for</span> (AmenityType amenityType : initialCapacities.keySet()) {
        capacityRepository.save(<span class="hljs-keyword">new</span> Capacity(amenityType, initialCapacities.get(amenityType)));
      }
    };
  }

  <span class="hljs-meta">@Bean</span>
  <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder();
  }
}
</code></pre>
<p>I just added the capacities inside the <strong>initialCapacities</strong> map then saved those to the <strong>CapacityRepository</strong> inside the <strong>loadData</strong> method.</p>
<p>We can now check if the number of reservations in the requested time exceeds the capacity and reject the reservation request if it does.</p>
<p>So here is the logic: We need to fetch the number of reservations that are on the same day and overlap with this current request. Then we need to fetch the capacity for this amenity type, and if the capacity is exceeded we can throw an exception. </p>
<p>Therefore we need a query to get the number of potentially overlapping reservations. It is not the easiest query to write, but JPA is very convenient and we can access that query inside our <strong>ReservationRepository</strong> without needing to write any SQL or HQL (Hibernate Query Language). </p>
<p>I encourage you to try it yourself before moving forward, because this is like the sole reason why I have included this concept of capacity in this tutorial (to show an example of a more advanced JPA query).</p>
<p>So this is how the <strong>ReservationService</strong>'s create method looks. You need to replace the 0 with a call to reservationRepository to get the number of overlapping reservations. </p>
<p>If the current number of overlapping reservations is equal to the capacity, it means that the next one will exceed it so we throw the exception.</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">int</span> capacity = capacityRepository.findByAmenityType(reservation.getAmenityType()).getCapacity();
        <span class="hljs-keyword">int</span> overlappingReservations = <span class="hljs-number">0</span>; <span class="hljs-comment">// TODO</span>

        <span class="hljs-keyword">if</span> (overlappingReservations &gt;= capacity) {
            <span class="hljs-comment">// Throw a custom exception</span>
        }

        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }
</code></pre>
<p>To find the overlapping reservations there are a few conditions we need to check:</p>
<p>First of all, the reservation date should be the same as the date in the request.</p>
<ol>
<li>Start time can be before the startTime of a new request. In that case, the end time should be later than our request, in order to overlap. (startTimeBeforeAndEndTimeAfter)</li>
<li>Or, endTime can be after but the startTime can actually be between the startTime and endTime of the request. (endTimeAfterOrStartTimeBetween)</li>
</ol>
<p>So our final query should return all reservations which match any of these 2 possibilities.</p>
<p>We can express it like this: </p>
<pre><code class="lang-java"><span class="hljs-function">List&lt;Reservation&gt; <span class="hljs-title">findReservationsByReservationDateAndStartTimeBeforeAndEndTimeAfterOrStartTimeBetween</span>
            <span class="hljs-params">(LocalDate reservationDate, LocalTime startTime, LocalTime endTime, LocalTime betweenStart, LocalTime betweenEnd)</span></span>;
</code></pre>
<p>And the final create method looks like this:</p>
<pre><code class="lang-java"> <span class="hljs-function"><span class="hljs-keyword">public</span> Long <span class="hljs-title">create</span><span class="hljs-params">(<span class="hljs-keyword">final</span> Reservation reservation)</span> </span>{
        <span class="hljs-keyword">int</span> capacity = capacityRepository.findByAmenityType(reservation.getAmenityType()).getCapacity();
        <span class="hljs-keyword">int</span> overlappingReservations = reservationRepository
                .findReservationsByReservationDateAndStartTimeBeforeAndEndTimeAfterOrStartTimeBetween(
                        reservation.getReservationDate(),
                        reservation.getStartTime(), reservation.getEndTime(),
                        reservation.getStartTime(), reservation.getEndTime()).size();

        <span class="hljs-keyword">if</span> (overlappingReservations &gt;= capacity) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> CapacityFullException(<span class="hljs-string">"This amenity's capacity is full at desired time"</span>);
        }

        <span class="hljs-keyword">return</span> reservationRepository.save(reservation).getId();
    }
</code></pre>
<p>You don't need to worry about the custom exception, but if you are interested in that, here is the code:</p>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.amenity_reservation_system.exception;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CapacityFullException</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RuntimeException</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CapacityFullException</span><span class="hljs-params">(String message)</span> </span>{
        <span class="hljs-keyword">super</span>(message);
    }
}
</code></pre>
<p>We should normally show an error modal if the capacity is exceeded but I will skip that to avoid repetitive UI stuff. You can try that as a challenge if you wish.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, we have learned about so many technologies that make development with Spring Boot easier and faster. </p>
<p>I believe many people underestimate the framework in terms of development speed and the quality of the resulting work. </p>
<p>Assuming you are fluent with the technology, I would argue that Spring Boot is not any slower (in development) than any other backend framework if you do everything in the modern fashion. </p>
<p>You can find the whole code in this repository:</p>
<p><a target="_blank" href="https://github.com/yigiterinc/amenity-reservation-system.git">https://github.com/yigiterinc/amenity-reservation-system.git</a></p>
<p>If you are interested in reading more content like this, feel free to subscribe to my blog at <a target="_blank" href="https://erinc.io/">https://erinc.io</a> to get notified about my new posts.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Generate an Excel Report in a Spring Boot REST API with Apache POI and Kotlin ]]>
                </title>
                <description>
                    <![CDATA[ By Piotr Wolak In this article, I would like to show you how to generate Excel reports in the .xls and .xlsx formats (also known as Open XML) in a Spring Boot REST API with Apache POI and Kotlin. After finishing this guide, you will have a fundamenta... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/generate-excel-report-in-spring-rest-api/</link>
                <guid isPermaLink="false">66d46089677cb8c6c15f3167</guid>
                
                    <category>
                        <![CDATA[ excel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Kotlin ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 08 Dec 2020 01:54:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/share-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Piotr Wolak</p>
<p>In this article, I would like to show you how to generate Excel reports in the <strong>.xls</strong> and <strong>.xlsx</strong> formats (also known as Open XML) in a <strong>Spring Boot REST API</strong> with <strong>Apache POI and Kotlin</strong>.</p>
<p>After finishing this guide, you will have a fundamental understanding of how to create custom cells formats, styles, and fonts. In the end, I will show you how to create Spring Boot REST endpoints so you can easily download generated files.</p>
<p>To better visualize what we'll learn, check out the preview of the resulting file:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/12/result_file_preview.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-step-1-add-the-necessary-imports">Step 1: Add the Necessary Imports</h2>
<p>As the first step, let's create a Spring Boot project (I highly recommend using the <a target="_blank" href="https://start.spring.io/">Spring Initializr</a> page) and add the following imports:</p>
<pre><code class="lang-groovy">implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.apache.poi:poi:4.1.2")
implementation("org.apache.poi:poi-ooxml:4.1.2")
</code></pre>
<p>Let me explain the purpose of each library: </p>
<ul>
<li>The <strong>Spring Boot Starter Web</strong> is necessary to create the REST API in our application.</li>
<li>The <strong>Apache POI</strong> is a complex Java library for working with Excel files. If we would like to work only with the .xls format, then the <em>poi</em> import would be enough. In our case, we would like to add the support for the <strong>.xlsx</strong> format, so the <em>poi-ooxml</em> component is necessary as well.</li>
</ul>
<h2 id="heading-step-2-create-the-models">Step 2: Create the Models</h2>
<p>As the next step, let's create an enum class called <strong>CustomCellStyle</strong> with 4 constants: </p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">enum</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomCellStyle</span> </span>{
    GREY_CENTERED_BOLD_ARIAL_WITH_BORDER,
    RIGHT_ALIGNED,
    RED_BOLD_ARIAL_WITH_BORDER,
    RIGHT_ALIGNED_DATE_FORMAT
}
</code></pre>
<p>Although the purpose of this enum class might seem a bit enigmatic at the moment, it will all become clear in the next sections.</p>
<h2 id="heading-step-3-prepare-cells-styles">Step 3: Prepare Cells Styles</h2>
<p>The Apache POI library comes with the <strong>CellStyle</strong> interface, which we can use to define custom styling and formatting within rows, columns, and cells.</p>
<p>Let's create a <strong>StylesGenerator</strong> component, which will be responsible for preparing a map containing our custom styles:</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Component</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StylesGenerator</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">prepareStyles</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: Map&lt;CustomCellStyle, CellStyle&gt; {
        <span class="hljs-keyword">val</span> boldArial = createBoldArialFont(wb)
        <span class="hljs-keyword">val</span> redBoldArial = createRedBoldArialFont(wb)

        <span class="hljs-keyword">val</span> rightAlignedStyle = createRightAlignedStyle(wb)
        <span class="hljs-keyword">val</span> greyCenteredBoldArialWithBorderStyle =
            createGreyCenteredBoldArialWithBorderStyle(wb, boldArial)
        <span class="hljs-keyword">val</span> redBoldArialWithBorderStyle =
            createRedBoldArialWithBorderStyle(wb, redBoldArial)
        <span class="hljs-keyword">val</span> rightAlignedDateFormatStyle =
            createRightAlignedDateFormatStyle(wb)

        <span class="hljs-keyword">return</span> mapOf(
            CustomCellStyle.RIGHT_ALIGNED to rightAlignedStyle,
            CustomCellStyle.GREY_CENTERED_BOLD_ARIAL_WITH_BORDER to greyCenteredBoldArialWithBorderStyle,
            CustomCellStyle.RED_BOLD_ARIAL_WITH_BORDER to redBoldArialWithBorderStyle,
            CustomCellStyle.RIGHT_ALIGNED_DATE_FORMAT to rightAlignedDateFormatStyle
        )
    }
}
</code></pre>
<p>As you can see, with this approach, we create each style once and put it inside a map so that we will be able to refer to it later. </p>
<p>There are plenty of design techniques which we could use here, but I believe using a map and enum constants is one of the best ways to keep the code cleaner and easier to modify.</p>
<p>With that being said, let's add some missing functions inside the generator class. Let's start with custom fonts first:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createBoldArialFont</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: Font {
    <span class="hljs-keyword">val</span> font = wb.createFont()
    font.fontName = <span class="hljs-string">"Arial"</span>
    font.bold = <span class="hljs-literal">true</span>
    <span class="hljs-keyword">return</span> font
}
</code></pre>
<p>The <strong>createBoldArialFont</strong> function creates a new bold Arial Font instance, which we will use later. </p>
<p>Similarly, let's implement a <strong>createRedBoldArialFont</strong> function and set the font color to red: </p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRedBoldArialFont</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: Font {
    <span class="hljs-keyword">val</span> font = wb.createFont()
    font.fontName = <span class="hljs-string">"Arial"</span>
    font.bold = <span class="hljs-literal">true</span>
    font.color = IndexedColors.RED.index
    <span class="hljs-keyword">return</span> font
}
</code></pre>
<p>After that, we can add other functions responsible for creating individual <strong>CellStyle</strong> instances: </p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRightAlignedStyle</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: CellStyle {
    <span class="hljs-keyword">val</span> style: CellStyle = wb.createCellStyle()
    style.alignment = HorizontalAlignment.RIGHT
    <span class="hljs-keyword">return</span> style
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createBorderedStyle</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: CellStyle {
    <span class="hljs-keyword">val</span> thin = BorderStyle.THIN
    <span class="hljs-keyword">val</span> black = IndexedColors.BLACK.getIndex()
    <span class="hljs-keyword">val</span> style = wb.createCellStyle()
    style.borderRight = thin
    style.rightBorderColor = black
    style.borderBottom = thin
    style.bottomBorderColor = black
    style.borderLeft = thin
    style.leftBorderColor = black
    style.borderTop = thin
    style.topBorderColor = black
    <span class="hljs-keyword">return</span> style
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createGreyCenteredBoldArialWithBorderStyle</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>, boldArial: <span class="hljs-type">Font</span>)</span></span>: CellStyle {
    <span class="hljs-keyword">val</span> style = createBorderedStyle(wb)
    style.alignment = HorizontalAlignment.CENTER
    style.setFont(boldArial)
    style.fillForegroundColor = IndexedColors.GREY_25_PERCENT.getIndex();
    style.fillPattern = FillPatternType.SOLID_FOREGROUND;
    <span class="hljs-keyword">return</span> style
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRedBoldArialWithBorderStyle</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>, redBoldArial: <span class="hljs-type">Font</span>)</span></span>: CellStyle {
    <span class="hljs-keyword">val</span> style = createBorderedStyle(wb)
    style.setFont(redBoldArial)
    <span class="hljs-keyword">return</span> style
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRightAlignedDateFormatStyle</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: CellStyle {
    <span class="hljs-keyword">val</span> style = wb.createCellStyle()
    style.alignment = HorizontalAlignment.RIGHT
    style.dataFormat = <span class="hljs-number">14</span>
    <span class="hljs-keyword">return</span> style
}
</code></pre>
<p>Please keep in mind that the above examples represent only a small part of <strong>CellStyle's</strong> possibilities. If you would like to see the full list, please refer to the official documentation <a target="_blank" href="https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/CellStyle.html">here</a>.</p>
<h2 id="heading-step-4-create-the-reportservice-class"><strong>Step 4: Create the ReportService Class</strong></h2>
<p>As the next step, let's implement a <strong>ReportService</strong> class responsible for creating .xlsx and <strong>.xls</strong> files and returning them as ByteArray instances:</p>
<pre><code class="lang-kotlin"><span class="hljs-meta">@Service</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReportService</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> stylesGenerator: StylesGenerator
) {
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateXlsxReport</span><span class="hljs-params">()</span></span>: ByteArray {
        <span class="hljs-keyword">val</span> wb = XSSFWorkbook()

        <span class="hljs-keyword">return</span> generateReport(wb)
    }

    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateXlsReport</span><span class="hljs-params">()</span></span>: ByteArray {
        <span class="hljs-keyword">val</span> wb = HSSFWorkbook()

        <span class="hljs-keyword">return</span> generateReport(wb)
    }
 }
</code></pre>
<p>As you can see, the only difference between these two formats' generation is the type of <strong>Workbook</strong> implementation we've. used. For the .xlsx format we will use the <strong>XSSFWorkbook</strong> class, and for the .xls we will use <strong>HSSFWorkbook</strong><em>.</em></p>
<p>Let's add the rest of the code to the <strong>ReportService</strong>:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateReport</span><span class="hljs-params">(wb: <span class="hljs-type">Workbook</span>)</span></span>: ByteArray {
    <span class="hljs-keyword">val</span> styles = stylesGenerator.prepareStyles(wb)
    <span class="hljs-keyword">val</span> sheet: Sheet = wb.createSheet(<span class="hljs-string">"Example sheet name"</span>)

    setColumnsWidth(sheet)

    createHeaderRow(sheet, styles)
    createStringsRow(sheet, styles)
    createDoublesRow(sheet, styles)
    createDatesRow(sheet, styles)

    <span class="hljs-keyword">val</span> <span class="hljs-keyword">out</span> = ByteArrayOutputStream()
    wb.write(<span class="hljs-keyword">out</span>)

    <span class="hljs-keyword">out</span>.close()
    wb.close()

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">out</span>.toByteArray()
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setColumnsWidth</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>)</span></span> {
    sheet.setColumnWidth(<span class="hljs-number">0</span>, <span class="hljs-number">256</span> * <span class="hljs-number">20</span>)

    <span class="hljs-keyword">for</span> (columnIndex <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        sheet.setColumnWidth(columnIndex, <span class="hljs-number">256</span> * <span class="hljs-number">15</span>)
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createHeaderRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">0</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(<span class="hljs-string">"Column <span class="hljs-variable">$columnNumber</span>"</span>)
        cell.cellStyle = styles[CustomCellStyle.GREY_CENTERED_BOLD_ARIAL_WITH_BORDER]
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRowLabelCell</span><span class="hljs-params">(row: <span class="hljs-type">Row</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;, label: <span class="hljs-type">String</span>)</span></span> {
    <span class="hljs-keyword">val</span> rowLabel = row.createCell(<span class="hljs-number">0</span>)
    rowLabel.setCellValue(label)
    rowLabel.cellStyle = styles[CustomCellStyle.RED_BOLD_ARIAL_WITH_BORDER]
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createStringsRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">1</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Strings row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(<span class="hljs-string">"String <span class="hljs-variable">$columnNumber</span>"</span>)
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED]
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createDoublesRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">2</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Doubles row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(BigDecimal(<span class="hljs-string">"<span class="hljs-subst">${columnNumber}</span>.99"</span>).toDouble())
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED]
    }
}

<span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createDatesRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">3</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Dates row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue((LocalDate.now()))
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED_DATE_FORMAT]
    }
}
</code></pre>
<p>As you can see, the first thing the <strong>generateReport</strong> function does is that it styles the initialization. We pass the <strong>Workbook</strong> instance to the <strong>StylesGenerator</strong> and in return, we get a map, which we will use later to obtain appropriate CellStyles. </p>
<p>After that, it creates a new sheet within our workbook and passes a name for it. </p>
<p>Then, it invokes functions responsible for setting the columns' widths and operating on our sheet row by row. </p>
<p>Finally, it writes out our workbook to a ByteArrayOutputStream.</p>
<p>Let's take a minute and analyze what exactly each function does:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setColumnsWidth</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>)</span></span> {
    sheet.setColumnWidth(<span class="hljs-number">0</span>, <span class="hljs-number">256</span> * <span class="hljs-number">20</span>)

    <span class="hljs-keyword">for</span> (columnIndex <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        sheet.setColumnWidth(columnIndex, <span class="hljs-number">256</span> * <span class="hljs-number">15</span>)
    }
}
</code></pre>
<p>As the name suggests, <strong>setColumnsWidth</strong> is responsible for setting widths of columns in our sheet. The first parameter passed to the <strong>setColumnWidth</strong> indicates the columnIndex, whereas the second one sets the width (in units of 1/256th of a character width). </p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createRowLabelCell</span><span class="hljs-params">(row: <span class="hljs-type">Row</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;, label: <span class="hljs-type">String</span>)</span></span> {
    <span class="hljs-keyword">val</span> rowLabel = row.createCell(<span class="hljs-number">0</span>)
    rowLabel.setCellValue(label)
    rowLabel.cellStyle = styles[CustomCellStyle.RED_BOLD_ARIAL_WITH_BORDER]
}
</code></pre>
<p>The <strong>createRowLabelCell</strong> function is responsible for adding a cell in the first column of the passed row, alongside setting its value to the specified label and setting the style. I've decided to add this function to slightly reduce the code's redundancy.</p>
<p>All of the below functions are pretty similar. Their purpose is to create a new row, invoking the <strong>createRowLabelCell</strong> function (except for <strong>createHeaderRow</strong>) and adding five columns with data to our sheet.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createHeaderRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">0</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(<span class="hljs-string">"Column <span class="hljs-variable">$columnNumber</span>"</span>)
        cell.cellStyle = styles[CustomCellStyle.GREY_CENTERED_BOLD_ARIAL_WITH_BORDER]
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createStringsRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">1</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Strings row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(<span class="hljs-string">"String <span class="hljs-variable">$columnNumber</span>"</span>)
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED]
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createDoublesRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">2</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Doubles row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue(BigDecimal(<span class="hljs-string">"<span class="hljs-subst">${columnNumber}</span>.99"</span>).toDouble())
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED]
    }
}
</code></pre>
<pre><code class="lang-kotlin"><span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createDatesRow</span><span class="hljs-params">(sheet: <span class="hljs-type">Sheet</span>, styles: <span class="hljs-type">Map</span>&lt;<span class="hljs-type">CustomCellStyle</span>, CellStyle&gt;)</span></span> {
    <span class="hljs-keyword">val</span> row = sheet.createRow(<span class="hljs-number">3</span>)
    createRowLabelCell(row, styles, <span class="hljs-string">"Dates row"</span>)

    <span class="hljs-keyword">for</span> (columnNumber <span class="hljs-keyword">in</span> <span class="hljs-number">1</span> until <span class="hljs-number">5</span>) {
        <span class="hljs-keyword">val</span> cell = row.createCell(columnNumber)

        cell.setCellValue((LocalDate.now()))
        cell.cellStyle = styles[CustomCellStyle.RIGHT_ALIGNED_DATE_FORMAT]
    }
}
</code></pre>
<h2 id="heading-step-5-implement-the-rest-reportcontroller"><strong>Step 5: Implement the REST ReportController</strong></h2>
<p>As the last step, we will implement a class named <strong>ReportController</strong>. It will be responsible for handling POST requests coming to our two REST endpoints:</p>
<ul>
<li><em>/api/report/xlsx -</em> creating a report in a <em>.xlsx</em> format </li>
<li><em>/api/report/xls</em> - same as above, but in a .xls format</li>
</ul>
<pre><code class="lang-kotlin"><span class="hljs-meta">@RestController</span>
<span class="hljs-meta">@RequestMapping(<span class="hljs-meta-string">"/api/report"</span>)</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ReportController</span></span>(
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> reportService: ReportService
) {

    <span class="hljs-meta">@PostMapping(<span class="hljs-meta-string">"/xlsx"</span>)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateXlsxReport</span><span class="hljs-params">()</span></span>: ResponseEntity&lt;ByteArray&gt; {
        <span class="hljs-keyword">val</span> report = reportService.generateXlsxReport()

        <span class="hljs-keyword">return</span> createResponseEntity(report, <span class="hljs-string">"report.xlsx"</span>)
    }

    <span class="hljs-meta">@PostMapping(<span class="hljs-meta-string">"/xls"</span>)</span>
    <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">generateXlsReport</span><span class="hljs-params">()</span></span>: ResponseEntity&lt;ByteArray&gt; {
        <span class="hljs-keyword">val</span> report = reportService.generateXlsReport()

        <span class="hljs-keyword">return</span> createResponseEntity(report, <span class="hljs-string">"report.xls"</span>)
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">createResponseEntity</span><span class="hljs-params">(
        report: <span class="hljs-type">ByteArray</span>,
        fileName: <span class="hljs-type">String</span>
    )</span></span>: ResponseEntity&lt;ByteArray&gt; =
        ResponseEntity.ok()
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .header(HttpHeaders.CONTENT_DISPOSITION, <span class="hljs-string">"attachment; filename=\"<span class="hljs-variable">$fileName</span>\""</span>)
            .body(report)

}
</code></pre>
<p>The most interesting part of the above code is the <strong>createResponseEntity</strong> function, which sets the passed ByteArray with its generated report as a response body. </p>
<p>Additionally, we set the <strong>Content-Type</strong> header of the response as the <strong>application/octet-stream</strong>, and the Content-Disposition as the <strong>attachment; filename=</strong>.</p>
<h2 id="heading-step-6-test-everything-with-postman"><strong>Step 6: Test Everything With Postman</strong></h2>
<p>Finally, we can run and test our Spring Boot application, for instance with the <code>gradlew</code> command:</p>
<pre><code>./gradlew bootRun
</code></pre><p>By default, the Spring Boot application will be running on port 8080, so let's open up <a target="_blank" href="https://www.postman.com/">Postman</a> (or any other tool), specify the <strong>POST</strong> request to <strong>localhost:8080/api/report/xls</strong> and hit <strong>Send and Download</strong> button: </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/12/POST_xls.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>If everything went well, we should see a window allowing us to save the <strong>.xls</strong> file. </p>
<p>Similarly, let's test the second endpoint:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/12/POST_xlsx.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This time, the file extension should be .xlsx.</p>
<h2 id="heading-summary"><strong>Summary</strong></h2>
<p>That's all for this article! We've covered the process of generating Excel reports in a Spring Boot REST API with Apache POI and Kotlin.</p>
<p>If you enjoyed it and would like to learn other topics through similar articles, please visit my blog, <a target="_blank" href="https://codersee.com/"><strong>Codersee</strong></a>.</p>
<p>And the last thing: for the source code of a fully working project, please refer to <a target="_blank" href="https://github.com/codersee-blog/freecodecamp-spring-boot-kotlin-excel">this GitHub repository</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ COM Interface API Tutorial: Java Spring Boot + JACOB Library ]]>
                </title>
                <description>
                    <![CDATA[ By Serhii Povisenko In this article, I will show you how to embed the JACOB library into your Spring Boot application. This will help you call a COM interface API via the DLL library in your web application. Also, for illustrative purposes, I will pr... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/interface-in-java-tutorial-how-to-call-the-com-interface-spring-boot-jacob-library/</link>
                <guid isPermaLink="false">66d4608bd1ffc3d3eb89de36</guid>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Libraries ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 30 Sep 2020 05:07:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/Screenshot-2020-09-29-at-15.49.33.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Serhii Povisenko</p>
<p>In this article, I will show you how to embed the <a target="_blank" href="https://sourceforge.net/projects/jacob-project/">JACOB library</a> into your <a target="_blank" href="https://spring.io/projects/spring-boot">Spring Boot</a> application. This will help you call a <a target="_blank" href="https://en.wikipedia.org/wiki/Component_Object_Model">COM interface API</a> via the <a target="_blank" href="https://en.wikipedia.org/wiki/Dynamic-link_library">DLL</a> library in your web application.</p>
<p>Also, for illustrative purposes, I will provide a description of a COM API so you can build your application on top of it. You can find all the code snippets in this <a target="_blank" href="https://github.com/povisenko/jacob-within-spring-boot-2">GitHub repo</a>.</p>
<p>But first, a quick note: at <a target="_blank" href="https://cthesigns.co.uk">C the Signs</a> we deployed this solution that allowed us to integrate with <a target="_blank" href="https://www.emishealth.com">EMIS Health</a>. It is an electronic patient record system used in primary care in the United Kingdom. For integration we used their provided DLL library.</p>
<p>The approach that I'll show you here (sanitised to avoid leaking any sensitive information) rolled out to production more than two years ago, and has since proven its durability.</p>
<p>Since we recently employed a brand new approach to integrating with EMIS, the old system is going to be shut down in a month or two. So this tutorial is its swan song. Sleep, my little prince.</p>
<h2 id="heading-what-is-the-dll-api">What is the DLL API?</h2>
<p>First, let's start with a clear description of the DLL library. To do this, I prepared a short mock-up of the original technical documentation.</p>
<p>Let's take a look through it to see what the three methods of a COM interface are.</p>
<h3 id="heading-initialisewithid-method">InitialiseWithID Method</h3>
<p>This method is a security feature required on-site that lets us obtain a connection to an API server that we want to integrate with the library.</p>
<p>It requires the <code>AccountID</code> (GUID) of the current API user (to access the server) and some other initialization arguments that are listed below.</p>
<p>This function also supports an auto-login feature. If a client has a logged-in version of the running system (the library is a part of that system) and calls the method on the same host, the API will automatically complete the login under that user's account. Then it'll return the <code>SessionID</code> for subsequent API calls. </p>
<p>Otherwise, the client needs to continue with the <code>Logon</code> function (see the next part) using the returned <code>LoginID</code>.</p>
<p>To call the function, use the name <code>InitialiseWithID</code> with the following arguments:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Name</td><td>In/out</td><td>Type</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>address</td><td>In</td><td>String</td><td>provided integration server IP</td></tr>
<tr>
<td>AccountID</td><td>In</td><td>String</td><td>provided unique GUID string</td></tr>
<tr>
<td>LoginID</td><td>Out</td><td>String</td><td>GUID string used for Logon API call</td></tr>
<tr>
<td>Error</td><td>Out</td><td>String</td><td>Error description</td></tr>
<tr>
<td>Outcome</td><td>Out</td><td>Integer</td><td>-1 = Refer to error<br>1 = Successful initialise awaiting logon<br>2 = Unable to connect to server due to absent server, or incorrect details<br>3 = Unmatched AccountID<br>4 = Autologon successful</td></tr>
<tr>
<td>SessionID</td><td>Out</td><td>String</td><td>GUID used for subsequent interactions (if auto log in successful)</td></tr>
</tbody>
</table>
</div><h3 id="heading-logon-method">Logon Method</h3>
<p>This method determines the authority of the user. The username here is the ID used to log in to the system. The password is the API password set for that username. </p>
<p>In the success scenario, the call returns a <code>SessionID</code> string (GUID) that must be passed into other subsequent calls to authenticate them.</p>
<p>To call the function, use the name <code>Logon</code> with the following arguments:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Name</td><td>In/out</td><td>Type</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>LoginID</td><td>In</td><td>String</td><td>The login id returned by the initialization method Initialise with ID</td></tr>
<tr>
<td>username</td><td>In</td><td>String</td><td>provided API username</td></tr>
<tr>
<td>password</td><td>In</td><td>String</td><td>provided API password</td></tr>
<tr>
<td>SessionID</td><td>Out</td><td>String</td><td>GUID used for subsequent interactions (if logon successful)</td></tr>
<tr>
<td>Error</td><td>Out</td><td>String</td><td>Error description</td></tr>
<tr>
<td>Outcome</td><td>Out</td><td>Integer</td><td>-1 = Technical error<br>1 = Successful<br>2 = Expired<br>3 = Unsuccessful<br>4 = Invalid login ID or login ID does not have access to this product</td></tr>
</tbody>
</table>
</div><h3 id="heading-getmatchedusers-method">getMatchedUsers Method</h3>
<p>This call lets you find user data records that match specific criteria. The search term can only refer to one field at a time such as last name, first name, or date of birth. </p>
<p>A successful call returns an XML string with the data in it.</p>
<p>To call the function, use the name <code>getMatchedUsers</code> with the following arguments:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Name</td><td>In/out</td><td>Type</td><td>Description</td></tr>
</thead>
<tbody>
<tr>
<td>SessionID</td><td>In</td><td>String</td><td>The session id returned by the logon  method</td></tr>
<tr>
<td>MatchTerm</td><td>In</td><td>String</td><td>Search term</td></tr>
<tr>
<td>MatchedList</td><td>Out</td><td>String</td><td>XML conforming to provided corresponding XSD scheme</td></tr>
<tr>
<td>SessionID</td><td>Out</td><td>String</td><td>GUID used for subsequent interactions (if logon successful)</td></tr>
<tr>
<td>Error</td><td>Out</td><td>String</td><td>Error description</td></tr>
<tr>
<td>Outcome</td><td>Out</td><td>Integer</td><td>-1 = Technical error<br>1 =  Users found<br>2 = Access denied<br>3 = No users</td></tr>
</tbody>
</table>
</div><h2 id="heading-dll-library-application-flow">DLL Library Application Flow</h2>
<p>To make it easier to grasp what we want to implement, I decided to create a simple flow diagram. </p>
<p>It describes a step-by-step scenario of how a web client can interact with our server-based application using its API. It encapsulates interaction with the DLL Library and allows us to get hypothetical users with the provided match term (search criteria):</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/JACOB_DLL_FLOW-5.png" alt="Image" width="600" height="400" loading="lazy">
<em>Application Flow Diagram</em></p>
<h2 id="heading-registering-com">Registering COM</h2>
<p>Now let's learn how we can access the DLL library. To be able to interact with a 3rd party COM interface, it <a target="_blank" href="https://docs.microsoft.com/en-us/windows/win32/com/registering-com-applications">needs to be added to the registry</a>. </p>
<p>Here's what the docs say:</p>
<blockquote>
<p>The registry is a system database that contains information about the configuration of system hardware and software as well as about users of the system. Any Windows-based program can add information to the registry and read information back from the registry. Clients search the registry for interesting components to use.  </p>
<p>The registry maintains information about all the COM objects installed in the system. Whenever an application creates an instance of a COM component, the registry is consulted to resolve either the CLSID or ProgID of the component into the pathname of the server DLL or EXE that contains it.  </p>
<p>After determining the component's server, Windows either loads the server into the process space of the client application (in-process components) or starts the server in its own process space (local and remote servers).  </p>
<p>The server creates an instance of the component and returns to the client a reference to one of the component's interfaces.</p>
</blockquote>
<p>To learn how to do that, the official Microsoft documentation <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/framework/interop/registering-assemblies-with-com">says</a>:</p>
<blockquote>
<p>You can run a command-line tool called the <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/framework/tools/regasm-exe-assembly-registration-tool">Assembly Registration Tool (Regasm.exe)</a> to register or unregister an assembly for use with COM.  </p>
<p>Regasm.exe adds information about the class to the system registry so COM clients can use the .NET Framework class transparently.  </p>
<p>The <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.registrationservices">RegistrationServices</a> class provides the equivalent functionality. A managed component must be registered in the Windows registry before it can be activated from a COM client</p>
</blockquote>
<p>Make sure that your host machine has installed the required <code>.NET Framework</code> components. After that, you can execute the following CLI command:</p>
<pre><code class="lang-shell">C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe {PATH_TO_YOUR_DLL_FILE} /codebase
</code></pre>
<p>A message will display indicating whether the file was successfully registered. Now we're ready for the next step.</p>
<h2 id="heading-defining-the-backbone-of-the-application">Defining the Backbone of the Application</h2>
<h3 id="heading-dllapiservice">DllApiService</h3>
<p>First of all, let's define the interface that describes our DLL library as it is:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">DllApiService</span> </span>{

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> accountId identifier for which we trigger initialisation
     * <span class="hljs-doctag">@return</span> Tuple3 from values of Outcome, SessionID/LoginID, error
     * where by the first argument you can understand what is the result of the API call
     */</span>
    Mono&lt;Tuple3&lt;Integer, String, String&gt;&gt; initialiseWithID(String accountId);

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> loginId  is retrieved before using {<span class="hljs-doctag">@link</span> DllApiService#initialiseWithID(String)} call
     * <span class="hljs-doctag">@param</span> username
     * <span class="hljs-doctag">@param</span> password
     * <span class="hljs-doctag">@return</span> Tuple3 from values of Outcome, SessionID, Error
     * where by the first argument you can understand what is the result of the API call
     */</span>
    Mono&lt;Tuple3&lt;Integer, String, String&gt;&gt; logon(String loginId, String username, String password);

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> sessionId is retrieved before using either
     *                  {<span class="hljs-doctag">@link</span> DllApiService#initialiseWithID(String)} or
     *                  {<span class="hljs-doctag">@link</span> DllApiService#logon(String, String, String)} calls
     * <span class="hljs-doctag">@param</span> matchTerm
     * <span class="hljs-doctag">@return</span> Tuple3 from values of Outcome, MatchedList, Error
     * where by the first argument you can understand what is the result of the API call
     */</span>
    Mono&lt;Tuple3&lt;Integer, String, String&gt;&gt; getMatchedUsers(String sessionId, String matchTerm);

    <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">COM_API_Method</span> </span>{
        InitialiseWithID, Logon, getMatchedUsers
    }
}
</code></pre>
<p>As you might have noticed, all the methods map with the definition of the COM Interface described above, except for the <code>initialiseWithID</code> function.</p>
<p>I decided to omit the <code>address</code> variable in the signature (the IP of the integration server) and inject it as an environment variable which we will be implementing.</p>
<h3 id="heading-sessionidservice-explained">SessionIDService Explained</h3>
<p>To be able to retrieve any data using the library, first we need to get the <code>SessionID</code>. </p>
<p>According to the flow diagram above, this involves calling the <code>initialiseWithID</code> method first. After that, depending on the result, we will get either the SessionID or <code>LoginID</code> to use in subsequent <code>Logon</code> calls. </p>
<p>So basically this is a two-step process behind the scenes. Now, let's create the interface, and after that, the implementation:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">SessionIDService</span> </span>{

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> accountId identifier for which we retrieve SessionID
     * <span class="hljs-doctag">@param</span> username
     * <span class="hljs-doctag">@param</span> password
     * <span class="hljs-doctag">@return</span> Tuple3 containing the following values:
     * result ( Boolean), sessionId (String) and status (HTTP Status depending on the result)
     */</span>
    Mono&lt;Tuple3&lt;Boolean, String, HttpStatus&gt;&gt; getSessionId(String accountId, String username, String password);
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-meta">@Service</span>
<span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SessionIDServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">SessionIDService</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> DllApiService dll;

    <span class="hljs-meta">@Override</span>
    <span class="hljs-keyword">public</span> Mono&lt;Tuple3&lt;Boolean, String, HttpStatus&gt;&gt; getSessionId(String accountId, String username, String password) {
        <span class="hljs-keyword">return</span> dll.initialiseWithID(accountId)
                  .flatMap(t4 -&gt; {
                      <span class="hljs-keyword">switch</span> (t4.getT1()) {
                          <span class="hljs-keyword">case</span> -<span class="hljs-number">1</span>:
                              <span class="hljs-keyword">return</span> just(of(<span class="hljs-keyword">false</span>, t4.getT3(), SERVICE_UNAVAILABLE));

                          <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>: {

                              <span class="hljs-keyword">return</span> dll.logon(t4.getT2(), username, password)
                                        .map(t3 -&gt; {
                                            <span class="hljs-keyword">switch</span> (t3.getT1()) {
                                                <span class="hljs-keyword">case</span> -<span class="hljs-number">1</span>:
                                                    <span class="hljs-keyword">return</span> of(<span class="hljs-keyword">false</span>, t3.getT3(), SERVICE_UNAVAILABLE);
                                                <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
                                                    <span class="hljs-keyword">return</span> of(<span class="hljs-keyword">true</span>, t3.getT2(), OK);
                                                <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
                                                <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:
                                                    <span class="hljs-keyword">return</span> of(<span class="hljs-keyword">false</span>, t3.getT3(), FORBIDDEN);
                                                <span class="hljs-keyword">default</span>:
                                                    <span class="hljs-keyword">return</span> of(<span class="hljs-keyword">false</span>, t3.getT3(), BAD_REQUEST);

                                            }
                                        });

                          }

                          <span class="hljs-keyword">case</span> <span class="hljs-number">4</span>:
                              <span class="hljs-keyword">return</span> just(of(<span class="hljs-keyword">true</span>, t4.getT2(), OK));

                          <span class="hljs-keyword">default</span>:
                              <span class="hljs-keyword">return</span> just(of(<span class="hljs-keyword">false</span>, t4.getT3(), BAD_REQUEST));
                      }
                  });

    }
}
</code></pre>
<h3 id="heading-api-facade">API Facade</h3>
<p>The next step is to design our web application API. It should represent and encapsulate our interaction with the COM Interface API:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DllApiRouter</span> </span>{

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> RouterFunction&lt;ServerResponse&gt; <span class="hljs-title">dllApiRoute</span><span class="hljs-params">(DllApiRouterHandler handler)</span> </span>{
        <span class="hljs-keyword">return</span> RouterFunctions.route(GET(<span class="hljs-string">"/api/sessions/{accountId}"</span>), handler::sessionId)
                              .andRoute(GET(<span class="hljs-string">"/api/users/{matchTerm}"</span>), handler::matchedUsers);
    }
}
</code></pre>
<p>Besides the <code>Router</code> class, let's define an implementation of its handler with logic for retrieving the SessionID and the user records data. </p>
<p>For the second scenario, to be able to make a DLL <code>getMatchedUsers</code> API call according to the design, let's use the mandatory header <code>X-SESSION-ID</code>:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Slf4j</span>
<span class="hljs-meta">@Component</span>
<span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DllApiRouterHandler</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String SESSION_ID_HDR = <span class="hljs-string">"X-SESSION-ID"</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> DllApiService service;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> AccountRepo accountRepo;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> SessionIDService sessionService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">sessionId</span><span class="hljs-params">(ServerRequest request)</span> </span>{
        <span class="hljs-keyword">final</span> String accountId = request.pathVariable(<span class="hljs-string">"accountId"</span>);

        <span class="hljs-keyword">return</span> accountRepo.findById(accountId)
                          .flatMap(acc -&gt; sessionService.getSessionId(accountId, acc.getApiUsername(), acc.getApiPassword()))
                          .doOnEach(logNext(t3 -&gt; {
                              <span class="hljs-keyword">if</span> (t3.getT1()) {
                                  log.info(format(<span class="hljs-string">"SessionId to return %s"</span>, t3.getT2()));
                              } <span class="hljs-keyword">else</span> {
                                  log.warn(format(<span class="hljs-string">"Session Id could not be retrieved. Cause: %s"</span>, t3.getT2()));
                              }
                          }))
                          .flatMap(t3 -&gt; status(t3.getT3()).contentType(APPLICATION_JSON)
                                                           .bodyValue(t3.getT1() ? t3.getT2() : Response.error(t3.getT2())))

                          .switchIfEmpty(Mono.just(<span class="hljs-string">"Account could not be found with provided ID "</span> + accountId)
                                             .doOnEach(logNext(log::info))
                                             .flatMap(msg -&gt; badRequest().bodyValue(Response.error(msg))));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">matchedUsers</span><span class="hljs-params">(ServerRequest request)</span> </span>{

        <span class="hljs-keyword">return</span> sessionIdHeader(request).map(sId -&gt; Tuples.of(sId, request.queryParam(<span class="hljs-string">"matchTerm"</span>)
                                                                         .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> IllegalArgumentException(
                                                                                 <span class="hljs-string">"matchTerm query param should be specified"</span>))))
                                       .flatMap(t2 -&gt; service.getMatchedUsers(t2.getT1(), t2.getT2()))
                                       .flatMap(<span class="hljs-keyword">this</span>::handleT3)
                                       .onErrorResume(IllegalArgumentException.class, <span class="hljs-keyword">this</span>::handleIllegalArgumentException);

    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Mono&lt;String&gt; <span class="hljs-title">sessionIdHeader</span><span class="hljs-params">(ServerRequest request)</span> </span>{
        <span class="hljs-keyword">return</span> Mono.justOrEmpty(request.headers()
                                       .header(SESSION_ID_HDR)
                                       .stream()
                                       .findFirst()
                                       .orElseThrow(() -&gt; <span class="hljs-keyword">new</span> IllegalArgumentException(SESSION_ID_HDR + <span class="hljs-string">" header is mandatory"</span>)));
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">handleT3</span><span class="hljs-params">(Tuple3&lt;Integer, String, String&gt; t3)</span> </span>{
        <span class="hljs-keyword">switch</span> (t3.getT1()) {
            <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
                <span class="hljs-keyword">return</span> ok().contentType(APPLICATION_JSON)
                           .bodyValue(t3.getT2());
            <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
                <span class="hljs-keyword">return</span> status(FORBIDDEN).contentType(APPLICATION_JSON)
                                        .bodyValue(Response.error(t3.getT3()));
            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">return</span> badRequest().contentType(APPLICATION_JSON)
                                   .bodyValue(Response.error(t3.getT3()));
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">handleIllegalArgumentException</span><span class="hljs-params">(IllegalArgumentException e)</span> </span>{
        <span class="hljs-keyword">return</span> Mono.just(Response.error(e.getMessage()))
                   .doOnEach(logNext(res -&gt; log.info(String.join(<span class="hljs-string">","</span>, res.getErrors()))))
                   .flatMap(res -&gt; badRequest().contentType(MediaType.APPLICATION_JSON)
                                               .bodyValue(res));
    }

    <span class="hljs-meta">@Getter</span>
    <span class="hljs-meta">@Setter</span>
    <span class="hljs-meta">@NoArgsConstructor</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Response</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Serializable</span> </span>{

        <span class="hljs-keyword">private</span> String message;

        <span class="hljs-keyword">private</span> Set&lt;String&gt; errors;

        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">Response</span><span class="hljs-params">(Set&lt;String&gt; errors)</span> </span>{
            <span class="hljs-keyword">this</span>.errors = errors;
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Response <span class="hljs-title">error</span><span class="hljs-params">(String error)</span> </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Response(singleton(error));
        }
    }
}
</code></pre>
<h3 id="heading-account-entity">Account Entity</h3>
<p>As you might have noticed, we've imported <code>AccountRepo</code> in the router's handler to find the entity in a database by the provided <code>accountId</code>. This lets us get the corresponding API user credentials and use all three in the DLL <code>Logon</code> API call. </p>
<p>To get a clearer picture, let's define the managed <code>Account</code> entity as well:</p>
<pre><code class="lang-java"><span class="hljs-meta">@TypeAlias("Account")</span>
<span class="hljs-meta">@Document(collection = "accounts")</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Account</span> </span>{

    <span class="hljs-meta">@Version</span>
    <span class="hljs-keyword">private</span> Long version;

    <span class="hljs-comment">/**
     * unique account ID for API, provided by supplier
     * defines restriction for data domain visibility
     * i.e. data from one account is not visible for another
     */</span>
    <span class="hljs-meta">@Id</span>
    <span class="hljs-keyword">private</span> String accountId;

    <span class="hljs-comment">/**
     * COM API username, provided by supplier
     */</span>
    <span class="hljs-keyword">private</span> String apiUsername;

    <span class="hljs-comment">/**
     * COM API password, provided by supplier
     */</span>
    <span class="hljs-keyword">private</span> String apiPassword;


    <span class="hljs-meta">@CreatedDate</span>
    <span class="hljs-keyword">private</span> Date createdAt;

    <span class="hljs-meta">@LastModifiedDate</span>
    <span class="hljs-keyword">private</span> Date updatedOn;
}
</code></pre>
<h2 id="heading-the-jacob-library-setup">The JACOB Library Setup</h2>
<p>All parts of our application are ready now except the core – the configuration and use of the JACOB library. Let's start with setting up the library.</p>
<p>The library is distributed via <a target="_blank" href="https://sourceforge.net/projects/jacob-project/">sourceforge.net</a>. I did not find it available anywhere on either the Central Maven Repo or any other repositories online. So I decided to import it manually into our project as a local package. </p>
<p>To do that, I downloaded it and put it in the root folder under <code>/libs/jacob-1.19</code>. </p>
<p>After that, put the following <a target="_blank" href="https://maven.apache.org/plugins/maven-install-plugin/">maven-install-plugin</a> configuration into <code>pom.xml</code>. This will add the library to the local repository during Maven's <code>install</code> build phase:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">plugin</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>maven-install-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">executions</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">execution</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>install-jacob<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">phase</span>&gt;</span>validate<span class="hljs-tag">&lt;/<span class="hljs-name">phase</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">configuration</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">file</span>&gt;</span>${basedir}/libs/jacob-1.19/jacob.jar<span class="hljs-tag">&lt;/<span class="hljs-name">file</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">repositoryLayout</span>&gt;</span>default<span class="hljs-tag">&lt;/<span class="hljs-name">repositoryLayout</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>net.sf.jacob-project<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jacob<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.19<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>jar<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">generatePom</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">generatePom</span>&gt;</span>
         <span class="hljs-tag">&lt;/<span class="hljs-name">configuration</span>&gt;</span>
         <span class="hljs-tag">&lt;<span class="hljs-name">goals</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">goal</span>&gt;</span>install-file<span class="hljs-tag">&lt;/<span class="hljs-name">goal</span>&gt;</span>
         <span class="hljs-tag">&lt;/<span class="hljs-name">goals</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">execution</span>&gt;</span>
   <span class="hljs-tag">&lt;/<span class="hljs-name">executions</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
</code></pre>
<p>That will let you easily add the dependency as usual:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>net.sf.jacob-project<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jacob<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
   <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.19<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>The library import is finished. Now let's get it ready to use it.</p>
<p>To interact with the COM component, JACOB provides a wrapper called an <code>ActiveXComponent</code> class (as I mentioned before). </p>
<p>It has a method called <code>invoke(String function, Variant... args)</code> that lets us make exactly what we want. </p>
<p>Generally speaking, our library is set up to create the <code>ActiveXComponent</code> bean so we can use it anywhere we want in the app (and we want it in the implementation of <code>DllApiService</code>). </p>
<p>So let's define a separate Spring <code>@Configuration</code> with all the essential preparations:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Slf4j</span>
<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">JacobCOMConfiguration</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String COM_INTERFACE_NAME = <span class="hljs-string">"NAME_OF_COM_INTERFACE_AS_IN_REGISTRY"</span>;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String JACOB_LIB_PATH = System.getProperty(<span class="hljs-string">"user.dir"</span>) + <span class="hljs-string">"\\libs\\jacob-1.19"</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String LIB_FILE = System.getProperty(<span class="hljs-string">"os.arch"</span>)
                                                 .equals(<span class="hljs-string">"amd64"</span>) ? <span class="hljs-string">"\\jacob-1.19-x64.dll"</span> : <span class="hljs-string">"\\jacob-1.19-x86.dll"</span>;

    <span class="hljs-keyword">private</span> File temporaryDll;

    <span class="hljs-keyword">static</span> {
        log.info(<span class="hljs-string">"JACOB lib path: {}"</span>, JACOB_LIB_PATH);
        log.info(<span class="hljs-string">"JACOB file lib path: {}"</span>, JACOB_LIB_PATH + LIB_FILE);
        System.setProperty(<span class="hljs-string">"java.library.path"</span>, JACOB_LIB_PATH);
        System.setProperty(<span class="hljs-string">"com.jacob.debug"</span>, <span class="hljs-string">"true"</span>);
    }

    <span class="hljs-meta">@PostConstruct</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> IOException </span>{
        InputStream inputStream = <span class="hljs-keyword">new</span> FileInputStream(JACOB_LIB_PATH + LIB_FILE);

        temporaryDll = File.createTempFile(<span class="hljs-string">"jacob"</span>, <span class="hljs-string">".dll"</span>);
        FileOutputStream outputStream = <span class="hljs-keyword">new</span> FileOutputStream(temporaryDll);
        <span class="hljs-keyword">byte</span>[] array = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">8192</span>];
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = inputStream.read(array); i != -<span class="hljs-number">1</span>; i = inputStream.read(array)) {
            outputStream.write(array, <span class="hljs-number">0</span>, i);
        }
        outputStream.close();

        System.setProperty(LibraryLoader.JACOB_DLL_PATH, temporaryDll.getAbsolutePath());
        LibraryLoader.loadJacobLibrary();
        log.info(<span class="hljs-string">"JACOB library is loaded and ready to use"</span>);
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> ActiveXComponent <span class="hljs-title">dllAPI</span><span class="hljs-params">()</span> </span>{
        ActiveXComponent activeXComponent = <span class="hljs-keyword">new</span> ActiveXComponent(COM_INTERFACE_NAME);
        log.info(<span class="hljs-string">"API COM interface {} wrapped into ActiveXComponent is created and ready to use"</span>, COM_INTERFACE_NAME);
        <span class="hljs-keyword">return</span> activeXComponent;
    }

    <span class="hljs-meta">@PreDestroy</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">clean</span><span class="hljs-params">()</span> </span>{
        temporaryDll.deleteOnExit();
        log.info(<span class="hljs-string">"Temporary DLL API library is cleaned on exit"</span>);
    }
}
</code></pre>
<p>It's worth mentioning that, besides defining the bean, we initialize the library components based on the host machine's ISA (instruction set architecture).</p>
<p>Also, we follow some common recommendations to make a copy of the corresponding library's file. This avoids any potential corruption of the original file during runtime. We also need to cleanup all allocated resources when the applications terminates.</p>
<p>Now the library is set up and ready to use. Finally, we can implement our last main component that helps us interact with the DLL API:  <code>DllApiServiceImpl</code>.</p>
<h2 id="heading-how-to-implement-a-dll-library-api-service">How to Implement a DLL Library API Service</h2>
<p>As all COM API calls are going to be cooked using a common approach, let's implement <code>InitialiseWithID</code> first. After that, all other methods can be implemented easily in a similar way.</p>
<p>As I mentioned before, to interact with the COM interface, JACOB provides us with the <code>ActiveXComponent</code> class that has the <code>invoke(String function, Variant... args)</code> method. </p>
<p>If you want to know more about the <code>Variant</code> class, the JACOB documentation says the following (you can find it in the <a target="_blank" href="https://sourceforge.net/projects/jacob-project/">archive</a> or under <code>/libs/jacob-1.19</code> in the <a target="_blank" href="https://github.com/povisenko/jacob-within-spring-boot-2">project</a>):</p>
<blockquote>
<p>The multi-format data type used for all call backs and most communications between Java and COM. It provides a single class that can handle all data types.</p>
</blockquote>
<p>This means that all arguments defined in the <code>InitialiseWithID</code> signature should be wrapped with <code>new Variant(java.lang.Object in)</code> and passed to the <code>invoke</code> method. Use the same order as specified in the interface description at the beginning of this article.</p>
<p>The only other important thing we haven't touched on yet is how to distinguish <code>in</code> and <code>out</code> type arguments. </p>
<p>For that purpose, <code>Variant</code> provides a constructor that accepts the data object and information about whether this is by reference or not. This means that after <code>invoke</code> is called, all variants that were initialized as references can be accessed after the call. So we can extract the results from <code>out</code> arguments. </p>
<p>To do that, just pass an extra boolean variable to the constructor as the second parameter: <code>new Variant(java.lang.Object pValueObject, boolean fByRef)</code>. </p>
<p>Initializing the <code>Variant</code> object as reference puts an additional requirement on the client to decide when to release the value (so it can be scrapped by the garbage collector). </p>
<p>For that purpose, you have the <code>safeRelease()</code> method that is supposed to be called when the value is taken from the corresponding <code>Variant</code> object.  </p>
<p>Putting all the pieces together gives us the following service's implementation:</p>
<pre><code class="lang-java"><span class="hljs-meta">@RequiredArgsConstructor</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DllApiServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">DllApiService</span> </span>{

    <span class="hljs-meta">@Value("${DLL_API_ADDRESS}")</span>
    <span class="hljs-keyword">private</span> String address;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ActiveXComponent dll;

    <span class="hljs-meta">@Override</span>
    <span class="hljs-keyword">public</span> Mono&lt;Tuple3&lt;Integer, String, String&gt;&gt; initialiseWithID(<span class="hljs-keyword">final</span> String accountId) {

        <span class="hljs-keyword">return</span> Mono.just(format(<span class="hljs-string">"Calling %s(%s, %s, %s, %s, %s, %s)"</span>,<span class="hljs-comment">//</span>
                                InitialiseWithID, address, accountId, <span class="hljs-string">"loginId/out"</span>, <span class="hljs-string">"error/out"</span>, <span class="hljs-string">"outcome/out"</span>, <span class="hljs-string">"sessionId/out"</span>))
                   .doOnEach(logNext(log::info))
                   <span class="hljs-comment">//invoke COM interface method and extract the result mapping it onto corresponding *Out inner class</span>
                   .map(msg -&gt; invoke(InitialiseWithID, vars -&gt; InitialiseWithIDOut.builder()
                                                                                   .loginId(vars[<span class="hljs-number">3</span>].toString())
                                                                                   .error(vars[<span class="hljs-number">4</span>].toString())
                                                                                   .outcome(valueOf(vars[<span class="hljs-number">5</span>].toString()))
                                                                                   .sessionId(vars[<span class="hljs-number">6</span>].toString())
                                                                                   .build(), <span class="hljs-comment">//</span>
                                      <span class="hljs-keyword">new</span> Variant(address), <span class="hljs-keyword">new</span> Variant(accountId), initRef(), initRef(), initRef(), initRef()))
                   <span class="hljs-comment">//Handle the response according to the documentation</span>
                   .map(out -&gt; {

                       <span class="hljs-keyword">final</span> String errorVal;

                       <span class="hljs-keyword">switch</span> (out.outcome) {
                           <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
                               errorVal = <span class="hljs-string">"InitialiseWithID method call failed. DLL API request outcome (response code from server via DLL) = 2 "</span> +<span class="hljs-comment">//</span>
                                       <span class="hljs-string">"(Unable to connect to server due to absent server, or incorrect details)"</span>;
                               <span class="hljs-keyword">break</span>;
                           <span class="hljs-keyword">case</span> <span class="hljs-number">3</span>:
                               errorVal = <span class="hljs-string">"InitialiseWithID method call failed. DLL API request outcome (response code from server via DLLe) = 3 (Unmatched AccountID)"</span>;
                               <span class="hljs-keyword">break</span>;
                           <span class="hljs-keyword">default</span>:
                               errorVal = handleOutcome(out.outcome, out.error, InitialiseWithID);
                       }

                       <span class="hljs-keyword">return</span> of(out, errorVal);
                   })
                   .doOnEach(logNext(t2 -&gt; {
                       InitialiseWithIDOut out = t2.getT1();
                       log.info(<span class="hljs-string">"{} API call result:\noutcome: {}\nsessionId: {}\nerror: {}\nloginId: {}"</span>,<span class="hljs-comment">//</span>
                                InitialiseWithID, out.outcome, out.sessionId, t2.getT2(), out.loginId);
                   }))
                   .map(t2 -&gt; {
                       InitialiseWithIDOut out = t2.getT1();
                       <span class="hljs-comment">//out.outcome == 4 auto-login successful, SessionID is retrieved</span>
                       <span class="hljs-keyword">return</span> of(out.outcome, out.outcome == <span class="hljs-number">4</span> ? out.sessionId : out.loginId, t2.getT2());
                   });
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Variant <span class="hljs-title">initRef</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Variant(<span class="hljs-string">""</span>, <span class="hljs-keyword">true</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">handleOutcome</span><span class="hljs-params">(Integer outcome, String error, COM_API_Method method)</span> </span>{
        <span class="hljs-keyword">switch</span> (outcome) {
            <span class="hljs-keyword">case</span> <span class="hljs-number">1</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-string">"no error"</span>;
            <span class="hljs-keyword">case</span> <span class="hljs-number">2</span>:
                <span class="hljs-keyword">return</span> format(<span class="hljs-string">"%s method call failed. DLL API request outcome (response code from server via DLL) = 2 (Access denied)"</span>, method);
            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">return</span> format(<span class="hljs-string">"%s method call failed. DLL API request outcome (response code from server via DLL) = %s (server technical error). "</span> + <span class="hljs-comment">//</span>
                                      <span class="hljs-string">"DLL API is temporary unavailable (server behind is down), %s"</span>, method, outcome, error);
        }

    }

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> method     to be called in COM interface
     * <span class="hljs-doctag">@param</span> returnFunc maps Variants (references) array onto result object that is to be returned by the method
     * <span class="hljs-doctag">@param</span> vars       arguments required for calling COM interface method
     * <span class="hljs-doctag">@param</span> &lt;T&gt;        type of the result object that is to be returned by the method
     * <span class="hljs-doctag">@return</span> result of the COM API method invocation in defined format
     */</span>
    <span class="hljs-keyword">private</span> &lt;T extends Out&gt; <span class="hljs-function">T <span class="hljs-title">invoke</span><span class="hljs-params">(COM_API_Method method, Function&lt;Variant[], T&gt; returnFunc, Variant... vars)</span> </span>{
        dll.invoke(method.name(), vars);
        T res = returnFunc.apply(vars);
        asList(vars).forEach(Variant::safeRelease);
        <span class="hljs-keyword">return</span> res;
    }

    <span class="hljs-meta">@SuperBuilder</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Out</span> </span>{
        <span class="hljs-keyword">final</span> Integer outcome;
        <span class="hljs-keyword">final</span> String error;
    }

    <span class="hljs-meta">@SuperBuilder</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InitialiseWithIDOut</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Out</span> </span>{
        <span class="hljs-keyword">final</span> String loginId;
        <span class="hljs-keyword">final</span> String sessionId;
}
</code></pre>
<p>Two other methods, <code>Logon</code> and <code>getMatchedUsers</code>, are implemented accordingly. You can refer to my <a target="_blank" href="https://github.com/povisenko/jacob-within-spring-boot-2/blob/master/src/main/java/me/povisenko/jacob_within_spring_boot_2/services/impl/DllApiServiceImpl.java">GitHub</a> repo for a complete version of the service if you want to check it out.</p>
<h2 id="heading-congratulations-youve-learned-a-few-things">Congratulations – You've Learned a Few Things</h2>
<p>We've gone through a step by step scenario that showed us how a hypothetical COM API could be distributed and called in Java. </p>
<p>We also learned how the JACOB library can be configured and effectively used to interact with a DDL library within your Spring Boot 2 application.</p>
<p>A small improvement would be to cache the retrieved SessionID which could improve the general flow. But that's a bit outside the scope of this article. </p>
<p>If you want to investigate further, you can find that on GitHub where it's implemented using Spring's caching mechanism.</p>
<p>Hope you enjoyed going through everything with me and found this tutorial helpful!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Java Spring Boot JWT Authorization and Authentication ]]>
                </title>
                <description>
                    <![CDATA[ By Yiğit Kemal Erinç In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring.  In this post, I will try to explain what I have ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/</link>
                <guid isPermaLink="false">66d45e44182810487e0ce155</guid>
                
                    <category>
                        <![CDATA[ authentication ]]>
                    </category>
                
                    <category>
                        <![CDATA[ authorization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JSON Web Tokens ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JWT ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ spring security ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 12 Aug 2020 20:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/jwt.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Yiğit Kemal Erinç</p>
<p>In the past month, I had a chance to implement JWT auth for a side project. I have previously worked with JWT in Ruby on Rails, but this was my first time in Spring. </p>
<p>In this post, I will try to explain what I have learned and applied in my project to share my experience and hopefully help some people. </p>
<p>We will start by taking a quick look at the theory behind JWT and how it works. Then we will look at how to implement it in a Spring Boot application.</p>
<h2 id="heading-jwt-basics">JWT Basics</h2>
<p>JWT, or JSON Web Tokens (<a target="_blank" href="https://tools.ietf.org/html/rfc7519">RFC 7519</a>), is a standard that is mostly used for securing REST APIs. Despite being a relatively new technology, it is gaining rapid popularity.</p>
<p>In the JWT auth process, the front end (client) firstly sends some credentials to authenticate itself (username and password in our case, since we're working on a web application). </p>
<p>The server (the Spring app in our case) then checks those credentials, and if they are valid, it generates a JWT and returns it. </p>
<p>After this step client has to provide this token in the request’s <strong>Authorization</strong> header in the “Bearer TOKEN” form. The back end will check the validity of this token and authorize or reject requests. The token may also store user roles and authorize the requests based on the given authorities.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/1.jpg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-implementation">Implementation</h2>
<p>Now let’s see how we can implement the JWT login and save mechanism in a real Spring application.</p>
<h3 id="heading-dependencies">Dependencies</h3>
<p>You can see the list of Maven dependencies that our example code uses below. Note that the core dependencies like Spring Boot and Hibernate are not included in this screenshot.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/2-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-saving-users">Saving Users</h3>
<p>We will start by creating controllers to save users securely and authenticate them based on username and password.</p>
<p>We have a model entity called User. It is a simple entity class that maps to the <strong>USER</strong> table. You can use whatever properties you need depending on your application.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/3-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We also have a simple <strong>UserRepository</strong> class to save users. We need to override the <strong>findByUsername</strong> method since we will use it in authentication.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserRepository</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">JpaRepository</span>&lt;<span class="hljs-title">User</span>, <span class="hljs-title">String</span>&gt;</span>{ 
    <span class="hljs-function">User <span class="hljs-title">findByUsername</span><span class="hljs-params">(String username)</span></span>; 
}
</code></pre>
<p>We should never store plaintext passwords in the database because many users tend to use the same password for multiple sites. </p>
<p>There are many different hashing algorithms, but the most commonly used one is <strong>BCrypt</strong> and it is a recommended method of secure hashing. You can check out <a target="_blank" href="https://security.blogoverflow.com/2013/09/about-secure-password-hashing/#:~:text=Passwords%20should%20be%20hashed%20with,providing%20most%20security%20is%20bcrypt.">this</a> article for more information on the topic.</p>
<p>To hash the password, we will define a <strong>BCrypt</strong> bean in <strong>@SpringBootApplication</strong> and annotate the main class as follows:</p>
<pre><code class="lang-java"><span class="hljs-meta">@Bean</span> <span class="hljs-function"><span class="hljs-keyword">public</span> BCryptPasswordEncoder <span class="hljs-title">bCryptPasswordEncoder</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> BCryptPasswordEncoder(); 
}
</code></pre>
<p>We will call the methods on this bean when we need to hash a password.</p>
<p>We also need a UserController to save users. We create the controller, annotate it with <strong>@RestController,</strong> and define the corresponding mapping. </p>
<p>In our application, we save the user based on a DTO object that is passed from the front end. You can also pass a User object in <strong>@RequestBody</strong>.</p>
<p>After we pass the DTO object, we encrypt the password field using the <strong>BCrypt</strong> bean we created earlier. You could also do this in the controller, but it is a better practice to put this logic in the service class.</p>
<pre><code class="lang-java"><span class="hljs-meta">@Transactional(rollbackFor = Exception.class)</span> 
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">saveDto</span><span class="hljs-params">(UserDto userDto)</span> </span>{ 
    userDto.setPassword(bCryptPasswordEncoder
           .encode(userDto.getPassword())); 
    <span class="hljs-keyword">return</span> save(<span class="hljs-keyword">new</span> User(userDto)).getId(); 
}
</code></pre>
<h3 id="heading-authentication-filter">Authentication Filter</h3>
<p>We need authentication to make sure that the user is really who they claim to be. We will be using the classic username/password pair to accomplish this.</p>
<p>Here are the steps to implement authentication:</p>
<ol>
<li>Create our Authentication Filter that extends <strong>UsernamePasswordAuthenticationFilter</strong></li>
<li>Create a security configuration class that extends <strong>WebSecurityConfigurerAdapter</strong> and apply the filter</li>
</ol>
<p>Here is the code for our Authentication Filter – as you might know, filters are the backbone of Spring Security.</p>


<p>Let’s go over this code step by step.</p>
<p>This class extends <strong>UsernamePasswordAuthenticationFilter</strong> which is the default class for password authentication in Spring Security. We extend it to define our custom authentication logic.</p>
<p>We make a call to the <strong>setFilterProcessesUrl</strong> method in our constructor. This method sets the default login URL to the provided parameter. </p>
<p>If you remove this line, Spring Security creates the <strong>“/login”</strong> endpoint by default. It defines the login endpoint for us, which is why we will not define a login endpoint in our controller explicitly. </p>
<p>After this line our login endpoint will be <strong>/api/services/controller/user/login</strong>. You can use this function to stay consistent with your endpoints.</p>
<p>We override the <strong>attemptAuthentication</strong> and <strong>successfulAuthentication</strong> methods of the <strong>UsernameAuthenticationFilter</strong> class.</p>
<p>The <strong>attemptAuthentication</strong> function runs when the user tries to log in to our application. It reads the credentials, creates a user POJO from them, and then checks the credentials to authenticate. </p>
<p>We pass the username, password, and an empty list. The empty list represents the authorities (roles), and we leave it as is since we do not have any roles in our application yet.</p>
<p>If the authentication is successful, the <strong>successfulAuthentication</strong> method runs. The parameters of this method are passed by Spring Security behind the scenes. </p>
<p>The <strong>attemptAuthentication</strong> method returns an <strong>Authentication</strong> object that contains the authorities we passed while attempting. </p>
<p>We want to return a token to user after authentication is successful, so we create the token using username, secret, and expiration date. We need to define the <strong>SECRET</strong> and <strong>EXPIRATION_DATE</strong> now.</p>


<p>We create a class to be a container for our constants. You can set the secret to whatever you want, but the best practice is making the secret key as long as your hash. We use the <strong>HS256</strong> algorithm in this example, so our secret key is 256 bits/32 chars.</p>
<p>The expiration time is set to 15 minutes, because it is the best practice against secret key brute-forcing attacks. The time is in milliseconds.</p>
<p>We have prepared our Authentication filter, but it is not active yet. We also need an Authorization filter, and then we will apply them both through a configuration class. </p>
<p>This filter will check the existence and validity of the access token on the Authorization header. We will specify which endpoints will be subject to this filter in our configuration class.</p>
<h3 id="heading-authorization-filter">Authorization Filter</h3>


<p>The <strong>doFilterInternal</strong> method intercepts the requests then checks the Authorization header. If the header is not present or doesn’t start with “BEARER”, it proceeds to the filter chain. </p>
<p>If the header is present, the <strong>getAuthentication</strong> method is invoked. <strong>getAuthentication</strong> verifies the JWT, and if the token is valid, it returns an access token which Spring will use internally. </p>
<p>This new token is then saved to SecurityContext. You can also pass in Authorities to this token if you need for role-based authorization.</p>
<p>Our filters are ready, and now we need to put them into action with the help of a configuration class.</p>
<h3 id="heading-configuration">Configuration</h3>


<p>We annotate this class with <strong>@EnableWebSecurity</strong> and extend <strong>WebSecurityConfigureAdapter</strong> to implement our custom security logic. </p>
<p>We autowire the BCrypt bean that we defined earlier. We also autowire the <strong>UserDetailsService</strong> to find the user’s account. </p>
<p>The most important method is the one which accepts an <strong>HttpSecurity</strong> object. Here we specify the secure endpoints and filters that we want to apply. We configure CORS, and then we permit all post requests to our sign up URL that we defined in the constants class. </p>
<p>You can add other ant matchers to filter based on URL patterns and roles, and you can <a target="_blank" href="https://stackoverflow.com/questions/44067650/spring-security-role-based-access">check</a> this StackOverflow question for examples regarding that. The other method configures the <strong>AuthenticationManager</strong> to use our encoder object as its password encoder while checking the credentials.</p>
<h3 id="heading-testing">Testing</h3>
<p>Let’s send a few requests to test if it works properly.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/4.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Here we send a GET request to access a protected resource. Our server responds with a 403 code. This is the expected behavior because we haven’t provided a token in the header. Now let’s create a user:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/5.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>To create a user, we send a post request with our User DTO data. We will use this user to login and get an access token.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/6.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Great! We got the token. After this point, we will use this token to access protected resources.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/7.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We provide the token in the Authorization header and we are now allowed access to our protected endpoint.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial I have walked you through the steps I took when implementing JWT authorization and password authentication in Spring. We also learned how to save a user securely. </p>
<p>Thank you for reading – I hope it was helpful to you. If you are interested in reading more content like this, feel free to subscribe to my blog at <a target="_blank" href="https://erinc.io">https://erinc.io</a>. :)</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Use Spring Boot and Java to create a Rest API (Tutorial) ]]>
                </title>
                <description>
                    <![CDATA[ Rest APIs are used all over the place. If you are learning the Spring Boot Java-based framework, you will need to know how to create one. We've released a full video course that will teach you how to create a Rest API using Spring Boot. This course f... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/use-spring-boot-and-java-to-create-a-rest-api-tutorial/</link>
                <guid isPermaLink="false">66b206e6a2135cc2539a21f6</guid>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 15 Jul 2020 15:07:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/springapi.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Rest APIs are used all over the place. If you are learning the Spring Boot Java-based framework, you will need to know how to create one. We've released a full video course that will teach you how to create a Rest API using Spring Boot.</p>
<p>This course from Pair Learning will also demonstrate how to use PostgreSQL as the relational database and Spring JdbcTemplate for interacting with that. You will learn how to add authentication using JWT (JSON Web Tokens).</p>
<p>Here are the sections in this course:</p>
<ul>
<li>Project Setup &amp; Creating Database Objects</li>
<li>Persisting User Information on Register</li>
<li>Login and Hashing Password</li>
<li>JWT Authentication</li>
<li>Adding New Categories</li>
<li>Category - Find &amp; Update Functionality</li>
<li>Adding Category Transactions</li>
<li>Transaction - Find and Update</li>
<li>Deleting - Category &amp; Transactions</li>
<li>CORS &amp; Testing from Web Client</li>
<li>Summary and Code</li>
</ul>
<p>You can watch the full course on <a target="_blank" href="https://youtu.be/5VUjP1wMqoE">the freeCodeCamp.org YouTube channel</a> (2 hour watch).</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Spring Boot Tutorial - Learn the popular Java framework ]]>
                </title>
                <description>
                    <![CDATA[ Learn Spring Boot in this full course for beginners from Amigoscode. Spring Boot is an amazing framework for building Java applications. It makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". This ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/spring-boot-tutorial/</link>
                <guid isPermaLink="false">66b2067639b555ffda8bfeb6</guid>
                
                    <category>
                        <![CDATA[ spring-boot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Fri, 06 Sep 2019 14:53:10 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/springboot.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Learn Spring Boot in this full course for beginners from Amigoscode. Spring Boot is an amazing framework for building Java applications. It makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".</p>
<p>This course covers:</p>
<ul>
<li>HTTP: GET, POST, PUT &amp; DELETE</li>
<li>Build an in-memory database</li>
<li>How to structure applications using N Tier Architecture</li>
<li>Auto wire beans with dependency injections</li>
<li>Program to interfaces</li>
<li>Run .jar file so that you can deploy to any server</li>
<li>Use Postman REST Client</li>
<li>and more!</li>
</ul>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/vtPkZShrvXQ" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>You can watch the <a target="_blank" href="https://www.youtube.com/watch?v=vtPkZShrvXQ">full video on the freeCodeCamp.org YouTube channel</a> (2 hour watch).</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
