finally it seems to work

This commit is contained in:
Stepan Usatiuk
2023-12-30 22:52:04 +01:00
parent 65e50d9e02
commit 52f26c15db
10 changed files with 112 additions and 8 deletions

29
Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM node:20-bullseye as client
WORKDIR /usr/src/app/client
COPY ./client/package*.json ./
RUN npm i
COPY ./client/. .
RUN npm run build
FROM azul/prime:17 as server
WORKDIR /usr/src/app/server
COPY ./server/. .
RUN ./gradlew clean build && bash -c "rm build/libs/*-plain.jar && mv build/libs/*.jar server.jar"
FROM azul/prime:17
WORKDIR /usr/src/app
COPY --from=server /usr/src/app/server/server.jar .
RUN mkdir -p client/dist
COPY --from=client /usr/src/app/client/dist ./client/dist
ENV spring_profiles_active=prod
COPY ./dockerentry.sh .
RUN ["chmod", "+x", "./dockerentry.sh"]
CMD [ "./dockerentry.sh" ]

3
client/.dockerignore Normal file
View File

@@ -0,0 +1,3 @@
.parcel-cache
dist
node_modules

View File

@@ -5,10 +5,9 @@
"author": "Stepan Usatiuk", "author": "Stepan Usatiuk",
"source": "src/index.html", "source": "src/index.html",
"scripts": { "scripts": {
"start": "parcel", "start": "parcel --public-url /app",
"build": "parcel build" "build": "parcel build --public-url /app"
}, },
"publicUrl": "/app",
"browserslist": "> 0.5%, last 2 versions, not dead", "browserslist": "> 0.5%, last 2 versions, not dead",
"dependencies": { "dependencies": {
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",

View File

@@ -10,7 +10,7 @@ declare const process: {
}; };
const apiRoot: string = const apiRoot: string =
process.env.NODE_ENV == "production" ? "/" : "http://localhost:8080"; process.env.NODE_ENV == "production" ? "" : "http://localhost:8080";
let token: string | null; let token: string | null;

View File

@@ -0,0 +1,37 @@
version: "3.8"
services:
yapp:
build: ./
restart: unless-stopped
ports:
- "8080:8080"
environment:
- jwt_secret=secretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecretsecret
- spring_datasource_url=jdbc:mariadb://db:3306/yapp
- spring_datasource_username=yapp
- spring_datasource_password=yappyapp
depends_on:
db:
condition: service_healthy
db:
image: mariadb
restart: unless-stopped
environment:
- MYSQL_RANDOM_ROOT_PASSWORD=true
- MYSQL_USER=yapp
- MYSQL_PASSWORD=yappyapp
- MYSQL_DATABASE=yapp
- MYSQL_CHARSET=utf8mb4
- MYSQL_COLLATION=utf8mb4_general_ci
volumes:
- ymariadb:/var/lib/mysql
healthcheck:
test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ]
start_period: 30s
start_interval: 10s
interval: 5s
timeout: 5s
retries: 3
volumes:
ymariadb:

3
dockerentry.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
java -jar server.jar

2
server/.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
build
.gradle

View File

@@ -44,3 +44,11 @@ dependencies {
tasks.named('test') { tasks.named('test') {
useJUnitPlatform() useJUnitPlatform()
} }
jar {
manifest {
attributes(
'Main-Class': 'com.usatiuk.tjv.y.server.ServerApplication'
)
}
}

View File

@@ -2,9 +2,13 @@ package com.usatiuk.tjv.y.server;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.CacheControl; import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
@@ -12,6 +16,9 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.ResourceResolver; import org.springframework.web.servlet.resource.ResourceResolver;
import org.springframework.web.servlet.resource.ResourceResolverChain; import org.springframework.web.servlet.resource.ResourceResolverChain;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
@@ -21,9 +28,9 @@ public class WebConfig implements WebMvcConfigurer {
static class AppResourceResolver implements ResourceResolver { static class AppResourceResolver implements ResourceResolver {
@Override @Override
public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) { public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) {
ClassPathResource res = new ClassPathResource("/app/" + requestPath); FileSystemResource res = new FileSystemResource("/usr/src/app/client/dist/" + requestPath);
if (res.exists()) return res; if (res.exists()) return res;
ClassPathResource indexRes = new ClassPathResource("/app/index.html"); FileSystemResource indexRes = new FileSystemResource("/usr/src/app/client/dist/index.html");
if (indexRes.exists()) return indexRes; if (indexRes.exists()) return indexRes;
return null; return null;
} }
@@ -34,9 +41,24 @@ public class WebConfig implements WebMvcConfigurer {
} }
} }
@RestController
@RequestMapping(value = "/app", produces = MediaType.TEXT_HTML_VALUE)
static class AppRootContoller {
@GetMapping
public String get() throws IOException {
return Files.readString(Path.of("/usr/src/app/client/dist/index.html"));
}
@GetMapping("/")
public String getSlash() throws IOException {
return Files.readString(Path.of("/usr/src/app/client/dist/index.html"));
}
}
@Override @Override
public void addViewControllers(ViewControllerRegistry registry) { public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/app/", "/app/index.html"); registry.addRedirectViewController("/", "/app");
} }
@Override @Override

View File

@@ -63,6 +63,7 @@ public class WebSecurityConfig {
.requestMatchers(mvc.pattern("/swagger-ui*/**")).permitAll() .requestMatchers(mvc.pattern("/swagger-ui*/**")).permitAll()
.requestMatchers(mvc.pattern("/v3/**")).permitAll() .requestMatchers(mvc.pattern("/v3/**")).permitAll()
.requestMatchers(mvc.pattern("/error")).permitAll() .requestMatchers(mvc.pattern("/error")).permitAll()
.requestMatchers(mvc.pattern("/")).permitAll()
.anyRequest().hasAuthority(UserRoles.ROLE_USER.name())) .anyRequest().hasAuthority(UserRoles.ROLE_USER.name()))
.sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)