Modernize project foundation and configuration

This commit is contained in:
2026-08-19 21:17:18 +08:00
parent 1c12977744
commit 053afab44d
8 changed files with 164 additions and 71 deletions

38
.gitignore vendored
View File

@@ -1,33 +1,9 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.idea/
.vscode/
*.iml
*.log
.env
.env.*
!.env.example
data/

View File

@@ -1,2 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

84
pom.xml
View File

@@ -1,67 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
<version>3.5.16</version>
<relativePath/>
</parent>
<groupId>com.hoelee</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<artifactId>springboot-jsonplaceholder-demo</artifactId>
<version>1.0.0</version>
<name>springboot-jsonplaceholder-demo</name>
<description>A production-minded Spring Boot REST API showcase.</description>
<properties>
<java.version>1.8</java.version>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Additional add-on by Hoelee -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<type>jar</type>
<version>20200518</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<type>jar</type>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@@ -73,5 +80,4 @@
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,23 @@
package com.hoelee.jsonplaceholder;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
/**
* @version v1, 2024-10-21 08:05:00PM
* @author hoelee
* Learning note: configuration scanning and JPA auditing keep cross-cutting setup explicit and compact.
*/
@SpringBootApplication
@ConfigurationPropertiesScan
@EnableJpaAuditing
public class ShowcaseApplication {
public static void main(String[] args) {
SpringApplication.run(ShowcaseApplication.class, args);
}
}
//~ v1, 2024-10-21 08:05:00PM - Last edited by hoelee

View File

@@ -0,0 +1,23 @@
package com.hoelee.jsonplaceholder.config;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
/**
* @version v1, 2024-10-21 09:05:00PM
* @author hoelee
* Learning note: typed, validated properties make operational settings discoverable and fail fast.
*/
@Validated
@ConfigurationProperties(prefix = "app.api")
public record ApiProperties(
@NotBlank String jsonPlaceholderBaseUrl,
Duration requestTimeout,
@Min(1) @Max(100) int importLimit) {
}
//~ v1, 2024-10-21 09:05:00PM - Last edited by hoelee

View File

@@ -0,0 +1,19 @@
package com.hoelee.jsonplaceholder.config;
import jakarta.validation.constraints.NotBlank;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
/**
* @version v1, 2024-10-21 10:05:00PM
* @author hoelee
* Learning note: credentials are externalized so a repository never needs a real environment secret.
*/
@Validated
@ConfigurationProperties(prefix = "app.security")
public record SecurityProperties(
@NotBlank String editorUsername,
@NotBlank String editorPassword) {
}
//~ v1, 2024-10-21 10:05:00PM - Last edited by hoelee

View File

@@ -0,0 +1,35 @@
spring:
application:
name: jsonplaceholder-showcase
datasource:
url: jdbc:h2:mem:postshowcase;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password:
jpa:
open-in-view: false
hibernate:
ddl-auto: update
cache:
caffeine:
spec: maximumSize=500,expireAfterWrite=10m
mvc:
problemdetails:
enabled: true
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: never
app:
api:
json-placeholder-base-url: https://jsonplaceholder.typicode.com
request-timeout: 2s
import-limit: 20
security:
editor-username: ${APP_EDITOR_USERNAME:demo-editor}
editor-password: ${APP_EDITOR_PASSWORD:changeit}

View File

@@ -0,0 +1,11 @@
spring:
datasource:
url: jdbc:h2:mem:postshowcase-test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
jpa:
hibernate:
ddl-auto: create-drop
app:
security:
editor-username: test-editor
editor-password: test-password