JPA Jooq Marriage
This module demonstrates the usage of both JPA and JOOQ in a Spring Boot application for managing blog posts with comments and tags.
Technologies Used
Spring Boot
Spring Data JPA
JOOQ
PostgreSQL
OpenAPI (Swagger)
API Endpoints
Create Post
POST /api/users/{user_name}/posts/
Request Body:
{
"title": "Sample Post",
"content": "Post content here",
"published": true,
"publishedAt": "2024-01-20T10:00:00",
"comments": [
{
"title": "Comment Title",
"review": "Comment content",
"published": true,
"publishedAt": "2024-01-20T10:00:00"
}
],
"tags": [
{
"name": "tech",
"description": "Technology related posts"
}
]
}
Get Post
GET /api/users/{user_name}/posts/{title}
Response:
{
"title": "Sample Post",
"content": "Post content here",
"published": true,
"publishedAt": "2024-01-20T10:00:00",
"author": "user_name",
"createdAt": "2024-01-20T10:00:00",
"comments": [
{
"title": "Comment Title",
"content": "Comment content",
"published": true,
"publishedAt": "2024-01-20T10:00:00"
}
],
"tags": [
{
"name": "tech",
"description": "Technology related posts"
}
]
}
Sequence Diagrams
Post Creation Flow (JPA)
sequenceDiagram
participant Client
participant PostController
participant JPAPostService
participant PostRepository
participant Database
Client->>PostController: POST /api/posts/users/{user_name}
PostController->>JPAPostService: createPost(postRequest, userName)
JPAPostService->>PostRepository: existsByTitleIgnoreCase(title)
PostRepository->>Database: SELECT EXISTS(...)
Database-->>PostRepository: result
PostRepository-->>JPAPostService: boolean
alt Post exists
JPAPostService-->>PostController: throw PostAlreadyExistsException
PostController-->>Client: 409 Conflict
else Post doesn't exist
JPAPostService->>PostRepository: save(post)
PostRepository->>Database: INSERT
Database-->>PostRepository: saved post
PostRepository-->>JPAPostService: Post
JPAPostService-->>PostController: void
PostController-->>Client: 201 Created
end
Post Retrieval Flow (JOOQ)
sequenceDiagram
participant Client
participant PostController
participant JooqPostService
participant DSLContext
participant Database
Client->>PostController: GET /api/posts/users/{user_name}/{title}
PostController->>JooqPostService: fetchPostByUserNameAndTitle(userName, title)
JooqPostService->>DSLContext: select(...).from(POSTS)
DSLContext->>Database: SELECT with JOINs
Database-->>DSLContext: Result
alt Post found
DSLContext-->>JooqPostService: Records
JooqPostService-->>PostController: PostResponse
PostController-->>Client: 200 OK with PostResponse
else Post not found
JooqPostService-->>PostController: throw PostNotFoundException
PostController-->>Client: 404 Not Found
end
Validation Rules
Post title: Required, max 255 characters
Post content: Required, max 10000 characters
Comment title: Required, max 255 characters
Comment review: Required, max 10000 characters
Tag name: Required, 1-50 characters, alphanumeric with hyphens and underscores
Tag description: Optional, max 200 characters
Format code
This project uses Spotless to maintain consistent code formatting. Run the following command to format all files:
./mvnw spotless:apply
Run tests
./mvnw clean verify
Run locally
Ensure you have Docker and Maven installed. Then:
Start the required PostgreSQL database:
docker-compose -f docker/docker-compose.yml up -d
Run the application with the local profile (uses local database):
./mvnw spring-boot:run -Dspring-boot.run.profiles=local
Using Testcontainers at Development Time
Testcontainers provides isolated, throwaway instances of the PostgreSQL database for testing. This allows you to run the application without setting up a local database.
There are two ways to run the application with Testcontainers:
You can run TestJpaJooqApplication.java
from your IDE directly. Alternatively, use Maven:
./mvnw spring-boot:test-run
Useful Links
Swagger UI - API documentation and testing interface
Actuator Endpoints - Application monitoring and management
Last updated
Was this helpful?