Java 3 - 2026

Week 1

Lesson 1 - Setup Pet Clinic App. Deployment using Docker.
Lesson 2 - Create, Read, Update, Delete (CRUD) functionality.
Lesson 3 - Homepage with content from the database. Custom not found and error pages.
Lesson 4 - Users, roles, and permissions setup from Java 2. User Registration.
Lesson 5 - Login and logout. Cookies. User permission access.

Lesson 6 - Edit and delete user profile. Password reset.
Lesson 7 - Pagination. Filtering and limiting records by category.
Lesson 8 - Web Sockets.
Lesson 9 - Internationalization. Date and currency formatting.
Lesson 10 - Email and SMS messaging. Failed login attempts.
Lesson 11 - Shopping Cart. Payment processing.

Course Plan

  • Modify the Pet Clinic application based on the user stories and personas you created in Java 2.
  • Derive an entity-relationship diagram and SQL queries for the data you will collect.
  • Create user interface drawings and wireframes for all web layouts.
  • Write use case narratives and build diagrams for each feature you add.
  • Write unit tests as necessary.

Expectations

  • Clone the Spring Pet Clinic project using IntelliJ.
  • Open it as a Gradle project.
  • Close the README.md file.
  • Open src/main/java/.../PetClinicApplication.java
  • A yellow bar will display asking you to install JDK 17.
  • Use Microsoft OpenJDK locally since we will deploy to Azure

Pet Clinic Project

  • Wait while the JDK downloads.

This is correct setup      This is not

Possible solutions if not correct

  • Close and re-open the project.
  • If this warning displays, click "Install required toolchain".
  • Press the Reload Gradle icon if it displays in the upper-right corner.

Run the app

  • Ignore any messages in the bottom-right corner.
  • Click the run button.
  • The Terminal should say that
    Tomcat started on port 8080

View and interact with the app

application-mysql.properties

  • Stop the program.
  • By default, PetClinic uses an in-memory H2 database.
  • You need to tell it to use your external MySQL database instead.
  • In IntelliJ, open the file:
    src/main/resources/application-mysql.properties
  • Replace the default settings with your web-based database details from Java 2.
# database init, supports mysql too
database=mysql
full.jdbc.connectionstring=jdbc:mysql://YOUR_WEB_DB_HOST:3306/YOUR_DB_NAME?user=YOUR_DB_USERNAME&password=YOUR_DB_PASSWORD&sslmode=disabled
spring.datasource.url=jdbc:mysql://YOUR_WEB_DB_HOST8:3306/YOUR_DB_NAME?useSSL=true
spring.datasource.username=YOUR_DB_USERNAME
spring.datasource.password=YOUR_DB_PASSWORD
# SQL is written to be idempotent so this is safe
spring.sql.init.mode=always

MySQL Database

application-mysql.properties

  • Add the following to the application-mysql.properties file.
# This tells Spring to run the scripts found in the db folder
spring.sql.init.schema-locations=classpath:db/mysql/schema.sql
spring.sql.init.data-locations=classpath:db/mysql/data.sql

# JPA / Hibernate settings
spring.jpa.hibernate.ddl-auto=none
  • Because you set spring.sql.init.mode=always, Spring Boot will attempt to run schema.sql and data.sql (located in src/main/resources/db/mysql) when the app starts.
  • Edit the Run configurations.
  •  

application-mysql.properties

  • Edit the Run configurations.
  • Add a Spring Boot configuration with the following settings.
  • Run the app and visit localhost:8080
  • Refresh the database to see the new tables.

Containerize the Application

  • To deploy to all the clouds you listed (Azure, AWS, GCP, etc.), the universal standard is Docker.
  • Create a file named Dockerfile in the root of your project. Add the following.
  • By default, Gradle might generate two jars (a "plain" jar and a "boot" jar). Adding -x jar ensures only the executable "boot" jar is created, so the COPY command doesn't get confused by multiple files.
# Stage 1: Build the application
# We use the full JDK image to compile the code
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build
WORKDIR /app
COPY . .
# Gradle build command (skipping tests and plain jar creation)
RUN ./gradlew clean bootJar -x test -x jar

# Stage 2: Run the application
# Microsoft provides a lightweight runtime for deployment
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-Dspring.profiles.active=mysql", "-jar", "app.jar"]

Build and Run the Image

  • Ensure that your Docker Desktop application is running by looking for the icon in your system tray (near the clock). 
  • Login to DockerHub. https://hub.docker.com/
  • Run this command to login via the terminal
    docker login
  • Go to https://login.docker.com/activate and enter the code shown in the terminal.
  • Run this command in the Terminal to build the Docker image:
    docker build -t dockerhub-username/image-name:version-name .
    for example, I could write this...
    docker build -t mlhaus/petclinic:v1 .
  • Open the Docker Desktop application and click the "Images" tab to confirm it was built. 
  • The -t tags the build. In Docker, a "tag" is like a sticky note on a specific version of your built files.

Build and Run the Image

  • Run the image with this command to map port 8099 on our host machine to port 8080 in the Docker container.
  • docker run -p 8099:8080 image-name
  • Visit http://localhost:8099/ to confirm that the application is running.
  • Press Ctrl + C to terminate the app.

STOP!

  • Our passwords are currently written inside application-mysql.properties. If you push that image to Docker Hub, anyone can download your image and see your passwords.

  • We must remove the secrets from your code, rebuild the image, and then provide the secrets only when the container runs.

  • Open src/main/resources/application-mysql.properties.

  • Replace your hardcoded real passwords with Spring Boot placeholders.

spring.datasource.url=${MYSQL_URL}
spring.datasource.username=${MYSQL_USER}
spring.datasource.password=${MYSQL_PASS}

IntelliJ Environment Variables

  • When running the program the app will look for environment variables with those names. If it doesn't find one, it will fail.

  • Open the Edit Configurations window. Click "Modify options" and choose "Environment Variables".

  • Click the "Edit Environment Variables" button. Enter these variables and your values.
    MYSQL_URL
    MYSQL_USER
    MYSQL_PASS

  • Run the program and visit http://localhost:8080

Rebuild and Rerun

  • Run this command in the Terminal to rebuild the Docker image:
    docker build -t dockerhub-username/image-name:version-name .
  • Run the image locally with this command. You use the -e flag to inject the values for the placeholders
    docker run -p 8099:8080 `
      -e MYSQL_URL="jdbc:mysql://your-db-host:3306/your-db-name?useSSL=true" `
      -e MYSQL_USER="your-db-username" `
      -e MYSQL_PASS="your-db-password `

    dockerhub-username/image-name:version-name
  • The backticks are for multi-line commands in PowerShell.
  • Run this command to push to DockerHub
    docker push dockerhub-username/image-name:version-name
  • Find your image online: https://hub.docker.com/repositories​

Containerize the Application

  • Run this command to see all of the images built and tagged:
    docker images
  • While you are testing, overwriting v1 over and over is fine. But for real deployments, it is better to increment the number so you can "roll back" if something breaks.
    • Build 1: docker build -t mlhaus/petclinic:v1 .

    • Build 2: docker build -t mlhaus/petclinic:v2 .

    • Build 3: docker build -t mlhaus/petclinic:v3 .

  • This way, if v3 has a bug, you can instantly tell your cloud provider to run v2 instead.

Microsoft Azure Student

Microsoft Azure Free Plans

  • Azure does offer a Free F1 web app plan.
    https://azure.microsoft.com/en-us/pricing/details/app-service/linux/
  • Read FAQs about Container App free pricing.
    https://azure.microsoft.com/en-us/pricing/details/container-apps/#faq
  • For a free deployment of your custom Docker image, you should choose Azure Container Apps.
    • The "F1" free tier only supports code deployments, not Docker images. To run a container, you typically need the paid "Basic" tier.
    • Azure Container Apps use a consumption model. You get a monthly free allowance of 180,000 vCPU-seconds and 360,000 GiB-seconds, which is enough for a low-traffic test app. You can scale it to zero to pause your app when no one is using it to save money.

Create Resource Group

  • Create a Resource Group. Think of this as a folder for your project. Replace project-name as you continue.
    az group create --name project-name-rg --location eastus

Create Container App Environment

Create/Deploy Container App

  • This command pulls your image from Docker Hub and launches it as an Azure Container App. Replace dockerhub-username and your actual DB details below. Read the next page before running.
    az containerapp create \
      --name project-name-app \
      --resource-group project-name-rg \
      --environment project-name-env \
      --image dockerhub-username/image-name:v1 \
      --target-port 8080 \
      --ingress 'external' \
      --min-replicas 1 \
      --env-vars MYSQL_URL="jdbc:mysql://your-db-host:3306/your-db-name?useSSL=true" MYSQL_USER="your-db-user" MYSQL_PASS="your-db-password"

Create/Deploy Container App

  • --env-vars: We need to pass the environment variables so your app can connect to your MySQL database.
  • --ingress 'external': Makes your app accessible via a public URL.

  • --target-port 8080: Tells Azure your container listens on port 8080 (standard for Spring Boot).

  • --min-replicas 1: Keeps at least one instance running (so it doesn't "sleep" and take 20 seconds to wake up). If you want to be purely free and don't mind the "cold start" delay, change this to 0.

  • After running the command, yellow text will display in the terminal with a URL like this:
     https://project-name-app.redpond-578f1b00.eastus.azurecontainerapps.io/

  • You can deploy other petclinic apps from the Spring Community.

Container Status

  • Run this command to see the status of the container:
    az containerapp replica list \
      --name project-name-app \
      --resource-group project-name-rg

  • If RunningState is "Running", you are good to go!

Live Log Stream

  • Run this command to view the live log stream directly from your terminal.
    az containerapp logs show \
      --name project-name-app \
      --resource-group project-name-rg \
      --follow

  • You might see a prompt to install the containerapp extension if it’s not already there. Type Y and press Enter.
  • After a few seconds, you will see the scrolling logs of your Spring Boot application. Look for any errors or warnings.
  • If the logs command returns an error about "Log Analytics," it means the quick-start command didn't auto-link a workspace for streaming.
  • Press Ctrl + C to stop the stream and return to your command prompt.

Cloud Services

  • You can now move on to deploying this same image to Google Cloud Run or AWS App Runner to compare the experience.
  • Here is the cheat sheet for popular cloud services:

Cloud Provider Service to Use Deployment Strategy
Microsoft Azure Azure Spring Apps Native Spring support. It can build the source directly or run your Docker image.
Google Cloud Cloud Run Serverless. Push image to Google Artifact Registry, then gcloud run deploy.
AWS AWS App Runner Easiest for single containers. Point it to your Docker Hub image, and it handles load balancing/SSL.
Heroku Dynos Use the Heroku CLI: heroku container:push web then heroku container:release web.
Digital Ocean App Platform Connect your GitHub repo; it detects the Dockerfile and deploys automatically.
Red Hat OpenShift OpenShift Deployment Use oc new-app pointing to your Docker image or Source-to-Image (S2I).

Java 3 - Week 1

By Marc Hauschildt

Java 3 - Week 1

  • 34