diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..b9ef8baf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +# Stage 1: Build the Angular app +FROM node:22-alpine AS angular-build + +WORKDIR /angular-app + +COPY ./booklore-ui/package.json ./booklore-ui/package-lock.json ./ +RUN npm install +COPY ./booklore-ui /angular-app/ + +RUN npm run build --prod + +# Stage 2: Build the Spring Boot app with Gradle +FROM gradle:jdk21-alpine AS springboot-build + +WORKDIR /springboot-app + +COPY ./booklore-api/gradlew ./booklore-api/gradle/ /springboot-app/ +COPY ./booklore-api/build.gradle ./booklore-api/settings.gradle /springboot-app/ +COPY ./booklore-api/gradle /springboot-app/gradle +COPY ./booklore-api/src /springboot-app/src + +RUN ./gradlew clean build + +# Stage 3: Final image combining everything +FROM eclipse-temurin:21-jdk-alpine + +RUN apk update && apk add nginx + +COPY ./nginx.conf /etc/nginx/nginx.conf +COPY --from=angular-build /angular-app/dist/booklore/browser /usr/share/nginx/html +COPY --from=springboot-build /springboot-app/build/libs/booklore-api-0.0.1-SNAPSHOT.jar /app/app.jar + +EXPOSE 8080 80 + +CMD /usr/sbin/nginx -g "daemon off;" & \ + java -jar /app/app.jar \ No newline at end of file diff --git a/booklore-api/build.gradle b/booklore-api/build.gradle index 22fde50d..3f69563c 100644 --- a/booklore-api/build.gradle +++ b/booklore-api/build.gradle @@ -3,7 +3,6 @@ plugins { id 'org.springframework.boot' version '3.4.0' id 'io.spring.dependency-management' version '1.1.6' id 'org.hibernate.orm' version '6.6.2.Final' - id 'org.graalvm.buildtools.native' version '0.10.3' } group = 'com.adityachandel' @@ -33,11 +32,11 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-websocket' implementation 'org.springframework.boot:spring-boot-starter-quartz' implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-configuration-processor' // Lombok compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' - annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' // Database & Flyway implementation 'com.h2database:h2' diff --git a/booklore-api/src/main/resources/application-local.yaml b/booklore-api/src/main/resources/application-local.yaml index c322fafc..b183a889 100644 --- a/booklore-api/src/main/resources/application-local.yaml +++ b/booklore-api/src/main/resources/application-local.yaml @@ -15,7 +15,7 @@ spring: name: booklore-api datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:tcp://localhost:9092/~/my-library-temp/config/db/booklore + url: jdbc:h2:~/my-library-temp/config/db/booklore username: sa password: password jpa: diff --git a/booklore-api/src/main/resources/application.yaml b/booklore-api/src/main/resources/application.yaml index c322fafc..af9ef25a 100644 --- a/booklore-api/src/main/resources/application.yaml +++ b/booklore-api/src/main/resources/application.yaml @@ -1,6 +1,6 @@ app: - path-book: '/Users/aditya.chandel/my-library-temp/books' - path-config: '/Users/aditya.chandel/my-library-temp/config' + path-book: '/app/books' + path-config: '/app/config' spring: servlet: @@ -15,7 +15,7 @@ spring: name: booklore-api datasource: driver-class-name: org.h2.Driver - url: jdbc:h2:tcp://localhost:9092/~/my-library-temp/config/db/booklore + url: 'jdbc:h2:/app/config/db/booklore' username: sa password: password jpa: diff --git a/booklore-api/src/test/java/com/adityachandel/booklore/BookloreApplicationTests.java b/booklore-api/src/test/java/com/adityachandel/booklore/BookloreApplicationTests.java deleted file mode 100644 index 8ec2a1a2..00000000 --- a/booklore-api/src/test/java/com/adityachandel/booklore/BookloreApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.adityachandel.booklore; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class BookloreApplicationTests { - - @Test - void contextLoads() { - } - -} diff --git a/booklore-ui/.dockerignore b/booklore-ui/.dockerignore new file mode 100644 index 00000000..8e0032b7 --- /dev/null +++ b/booklore-ui/.dockerignore @@ -0,0 +1,7 @@ +node_modules +npm-debug.log +dist +.vscode +.idea +.angular +.editorconfig diff --git a/booklore-ui/angular.json b/booklore-ui/angular.json index e2228b6a..d875fdc3 100644 --- a/booklore-ui/angular.json +++ b/booklore-ui/angular.json @@ -56,7 +56,7 @@ { "type": "initial", "maximumWarning": "500kB", - "maximumError": "1MB" + "maximumError": "3MB" }, { "type": "anyComponentStyle", diff --git a/booklore-ui/src/app/book/components/book-browser/book-browser.component.ts b/booklore-ui/src/app/book/components/book-browser/book-browser.component.ts index 5f849bd6..9a2acbe7 100644 --- a/booklore-ui/src/app/book/components/book-browser/book-browser.component.ts +++ b/booklore-ui/src/app/book/components/book-browser/book-browser.component.ts @@ -19,7 +19,7 @@ import {BookTableComponent} from './book-table/book-table.component'; import {animate, state, style, transition, trigger} from '@angular/animations'; import {MetadataFetchOptionsComponent} from '../../../metadata/metadata-options-dialog/metadata-fetch-options/metadata-fetch-options.component'; import {MetadataRefreshType} from '../../../metadata/model/request/metadata-refresh-type.enum'; -import {Button, ButtonDirective, ButtonIcon} from 'primeng/button'; +import {Button} from 'primeng/button'; import {AsyncPipe, NgClass, NgForOf, NgIf} from '@angular/common'; import {VirtualScrollerModule} from '@iharbeck/ngx-virtual-scroller'; import {BookCardComponent} from './book-card/book-card.component'; @@ -30,8 +30,6 @@ import {InputText} from 'primeng/inputtext'; import {FormsModule} from '@angular/forms'; import {BookFilterComponent} from './book-filter/book-filter.component'; import {Tooltip} from 'primeng/tooltip'; -import {WindowMaximizeIcon} from 'primeng/icons'; -import {Ripple} from 'primeng/ripple'; export enum EntityType { LIBRARY = 'Library', @@ -44,7 +42,7 @@ export enum EntityType { standalone: true, templateUrl: './book-browser.component.html', styleUrls: ['./book-browser.component.scss'], - imports: [Button, NgIf, VirtualScrollerModule, BookCardComponent, AsyncPipe, ProgressSpinner, Select, Menu, NgForOf, InputText, FormsModule, BookTableComponent, BookFilterComponent, Tooltip, ButtonDirective, WindowMaximizeIcon, ButtonIcon, Ripple, NgClass], + imports: [Button, NgIf, VirtualScrollerModule, BookCardComponent, AsyncPipe, ProgressSpinner, Select, Menu, NgForOf, InputText, FormsModule, BookTableComponent, BookFilterComponent, Tooltip, NgClass], animations: [ trigger('slideInOut', [ state('void', style({ diff --git a/build-docker.sh b/build-docker.sh new file mode 100644 index 00000000..fb05792b --- /dev/null +++ b/build-docker.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Define variables +PROJECT_ROOT=$(pwd) +UI_DIR="$PROJECT_ROOT/booklore-ui" +API_DIR="$PROJECT_ROOT/booklore-api" +H2_JAR="$PROJECT_ROOT/h2-2.3.232.jar" +DOCKER_IMAGE_NAME="booklore-app" + +# Step 1: Build Angular frontend +echo "Building Angular frontend..." +cd "$UI_DIR" || exit +npm install +npm run build --prod || { echo "Angular build failed"; exit 1; } +echo "Angular build completed." + +# Step 2: Package Spring Boot API +echo "Packaging Spring Boot API..." +cd "$API_DIR" || exit +mvn clean package -DskipTests || { echo "Spring Boot build failed"; exit 1; } +API_JAR=$(find target -name "*.jar" | head -n 1) +echo "Spring Boot API packaged: $API_JAR" + +# Step 3: Build Docker image +cd "$PROJECT_ROOT" || exit +echo "Building Docker image..." +docker build -t "$DOCKER_IMAGE_NAME" . || { echo "Docker build failed"; exit 1; } +echo "Docker image built: $DOCKER_IMAGE_NAME" + +# Step 4: Clean up (optional) +echo "Cleaning up intermediate files..." +rm -rf "$UI_DIR/node_modules" + +echo "Build process completed successfully!" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..03db79e3 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3.8' +services: + booklore-app: + container_name: booklore + image: localhost:5000/booklore-app:v12 + ports: + - "8081:8080" + - "4201:80" + volumes: + - /Users/aditya.chandel/my-library-temp/config:/app/config + - /Users/aditya.chandel/my-library-temp/books:/app/books \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 00000000..bd3cc2b3 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,27 @@ +# the events block is required +events{} + +http { + # include the default mime.types to map file extensions to MIME types + include /etc/nginx/mime.types; + + server { + # set the root directory for the server (we need to copy our + # application files here) + root /usr/share/nginx/html; + + # set the default index file for the server (Angular generates the + # index.html file for us and it will be in the above directory) + index index.html; + + # specify the configuration for the '/' location + location / { + # try to serve the requested URI. if that fails then try to + # serve the URI with a trailing slash. if that fails, then + # serve the index.html file; this is needed in order to serve + # Angular routes--e.g.,'localhost:8080/customer' will serve + # the index.html file + try_files $uri $uri/ /index.html; + } + } +}