Skip to content

Latest commit

 

History

23 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AddressBook

A small full-stack Spring Boot application built to practice the standard Java web stack end to end: JPA entities and relationships, a JSON REST API, a server-rendered Thymeleaf UI with AJAX, automated tests, and a CI/CD pipeline that builds and deploys the app. It manages address books, each holding a list of buddies (name, phone, address), through both the REST API and the web UI.

Tech stack

  • Language: Java 21 (maven.compiler.release in pom.xml; CI uses Microsoft Build of OpenJDK 21)
  • Framework: Spring Boot 3.3.3 (spring-boot-starter-parent)
  • Persistence: Spring Data JPA (spring-boot-starter-data-jpa), with spring-boot-starter-data-rest also on the classpath
  • Database: H2 (com.h2database:h2, runtime scope), no application.properties/.yml is present, so Spring Boot's default in-memory H2 auto-configuration is used
  • View layer: Thymeleaf (spring-boot-starter-thymeleaf) for HTML templates, plain JavaScript (fetch) for AJAX calls from the browser
  • Test frameworks: JUnit 4 (junit:junit:4.13.2) for the model unit tests, JUnit 5/Jupiter and Spring Boot Test (spring-boot-starter-test) for the integration test, TestRestTemplate for HTTP calls in tests
  • Build tool: Maven, with maven-compiler-plugin 3.11.0, maven-surefire-plugin 3.2.5, spring-boot-maven-plugin (repackaging), and maven-assembly-plugin 3.6.0 (builds an additional jar-with-dependencies, see Testing/CI notes below)
  • CI/CD: GitHub Actions (.github/workflows/maven.yml), building on windows-latest, running mvn -B -ntp clean verify, then deploying to Azure App Service (see CI/CD section)

Architecture

flowchart TD
    Browser["Browser<br/>(HTML + fetch AJAX)"]
    Curl["REST client<br/>(curl / API consumer)"]

    ViewController["AddressBookViewController<br/>(@Controller)"]
    RestController["AddressBookController<br/>(@RestController, /addressbook)"]
    PingController["PingController<br/>(@RestController, /ping)"]

    AddressBookRepo["AddressBookRepository"]
    BuddyInfoRepo["BuddyInfoRepository"]

    DB[("H2, in-memory")]

    Thymeleaf["Thymeleaf templates<br/>addressbooks.html / addressbook.html"]

    Browser -- "GET/POST /view/..." --> ViewController
    Browser -- "fetch: POST /addressbook/..." --> RestController
    Curl -- "JSON over HTTP" --> RestController
    Curl --> PingController

    ViewController --> Thymeleaf
    ViewController --> AddressBookRepo
    ViewController --> BuddyInfoRepo
    RestController --> AddressBookRepo
    RestController --> BuddyInfoRepo

    AddressBookRepo --> DB
    BuddyInfoRepo --> DB

    AddressBookRepo -. "AddressBook 1 --- * BuddyInfo" .- BuddyInfoRepo
Loading
  • BuddyInfo (org.example.model): JPA entity for a single contact (name, phone, address). setPhone strips a leading + or 0 from the input before storing it. Holds a @ManyToOne back-reference to its owning AddressBook (@JsonBackReference, so it is not re-serialized inside a buddy's JSON).
  • AddressBook (org.example.model): JPA entity with a @OneToMany list of BuddyInfo (mappedBy = "addressBook", cascade ALL, orphanRemoval = true). addBuddy/removeBuddy keep both sides of the relationship in sync. The list is serialized to JSON (@JsonManagedReference).
  • Repositories (org.example.repo): AddressBookRepository and BuddyInfoRepository are CrudRepository interfaces (Spring Data JPA). BuddyInfoRepository adds findByName and findByPhone query-derivation methods.
  • AddressBookController (org.example.api, @RestController, base path /addressbook): JSON REST endpoints for creating/listing/fetching/deleting address books and adding/removing buddies.
  • AddressBookViewController (org.example.api, @Controller): serves the Thymeleaf HTML pages and handles the classic form-post routes used by the browser UI.
  • PingController (org.example.api, @RestController): a simple /ping health-check endpoint returning a Ping record (id, ping, status, timestamp).
  • AddressBookApplication: the @SpringBootApplication entry point. It also defines a CommandLineRunner bean that seeds one address book with two buddies (Nina, Alex) on every startup and prints them to the console.

REST API

All endpoints below are implemented in AddressBookController (base path /addressbook) and PingController.

Method Path Request body Response
POST /addressbook/newbook none, or a JSON AddressBook (optional) 200 OK with the created AddressBook JSON
GET /addressbook none 200 OK with a JSON array of all AddressBooks
GET /addressbook/{id} none 200 OK with the AddressBook JSON, or 404 Not Found if it does not exist
DELETE /addressbook/{id}/delete none 204 No Content, or 404 Not Found if it does not exist
POST /addressbook/{id}/add JSON BuddyInfo (name, phone, address) 200 OK with the updated AddressBook JSON, or 404 Not Found if the book does not exist
DELETE /addressbook/{id}/remove/{buddyId} none 200 OK with the updated AddressBook JSON, or 404 Not Found if the book or buddy does not exist
GET /ping none 200 OK with a JSON Ping (id, ping: "pong", status: "ok", timestamp)

HTML view routes (AddressBookViewController, server-rendered Thymeleaf, not JSON):

  • GET /, GET /view, GET /view/addressbooks - list all address books (addressbooks.html)
  • POST /view/addressbook/create - create a new address book, then redirect to its detail view
  • GET /view/addressbook/{id}/view - show one address book and its buddies (addressbook.html)
  • POST /view/addressbook/{id}/addbuddy - add a buddy from an HTML form (name, phone, address as form fields), then redirect back to the detail view

Example: create a book and add a buddy via curl.

# Create a new address book
curl -s -X POST http://localhost:8080/addressbook/newbook

# Add a buddy to book with id 1
curl -s -X POST http://localhost:8080/addressbook/1/add \
  -H "Content-Type: application/json" \
  -d '{"name":"Nina","phone":"+15559990100","address":"123 Maple St"}'

Running locally

Prerequisites: JDK 21 and Maven.

Build:

mvn clean package

Run:

mvn spring-boot:run

or run the packaged jar:

java -jar target/testJava-1.0-SNAPSHOT.jar

Open http://localhost:8080/ for the HTML UI, or call the JSON API directly (for example http://localhost:8080/addressbook).

The database is H2, in-memory (no application.properties/.yml overrides Spring Boot's default). Data does not persist across restarts, and the CommandLineRunner in AddressBookApplication re-seeds one address book with two buddies (Nina, Alex) every time the app starts.

Testing

Run the tests with:

mvn test

or as part of a full build with:

mvn verify
  • BuddyInfoTest (JUnit 4): unit tests for BuddyInfo, covering field initialization to null, setName, and the phone-cleaning logic in setPhone (leading + or 0, null input, empty input, no prefix).
  • AddressBookTest (JUnit 4): unit tests for AddressBook, covering addBuddy, removeBuddy (including removing a middle element), get, size, and getBuddies.
  • AddressBookApiIT (JUnit 5 / Spring Boot Test, @SpringBootTest with a random port and TestRestTemplate): an end-to-end HTTP test that creates a book via POST /addressbook/newbook, adds a buddy via POST /addressbook/{id}/add, then fetches the book via GET /addressbook/{id} and asserts the buddy is present with the expected phone and address.

CI/CD

.github/workflows/maven.yml runs on every push to master (and can also be triggered manually via workflow_dispatch):

  1. Build job (windows-latest): checks out the code, sets up Microsoft Build of OpenJDK 21, runs mvn -B -ntp clean verify, lists the contents of target, and uploads target\*.jar (plus an optional web.config) as a build artifact.
  2. Deploy job: downloads that artifact and deploys it to Azure App Service (azure/webapps-deploy@v3, app name Addressbookwebapp, using a publish profile stored in the AZURE_WEBAPP_PUBLISH_PROFILE secret).

The app was deployed to Azure App Service through this workflow; the hosting subscription has since ended.

About

Spring Boot address book app: JPA, REST API, Thymeleaf + AJAX UI, JUnit tests, and a GitHub Actions CI/CD pipeline.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages