A comprehensive RESTful API for managing webtoons, allowing users to handle comics, chapters, and content (images) easily. Built with Spring Boot and Java 21, the application includes secure authentication with JWT, file uploads to Cloudinary, and robust input validation.
- π JWT Authentication
- π CRUD Operations for Comics
- π CRUD Operations for Chapters
- πΌοΈ CRUD Operations for Content (Image Pages)
- βοΈ Upload Images to Cloudinary
- π Pagination and Sorting
- π‘οΈ Input Validation
- π¦ Consistent JSON Response Wrapper
- π« Dockerfile and Docker Compose
- π Ready Production
- Java 21
- Spring Boot
- MySQL
- Cloudinary
- Lombok
- Jakarta Bean Validation
- Java 21
- Maven 3+
- MySQL 8+
- Cloudinary Account
git clone https://github.com/nurmanhadi/webtoon-java-springboot-with-cloud-storage-cloudinary.git
cd webtoon-java-springboot-with-cloud-storage-cloudinaryEdit the file at src/main/resources/application.properties:
spring.threads.virtual.enabled=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/your-database
spring.datasource.username=your-username
spring.datasource.password=your-password
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
cloudinary.cloud-name=your-cloud-name
cloudinary.api-key=your-api-key
cloudinary.api-secret=your-api-secretCreate the required tables using the schema provided in the database/ folder.
./mvnw spring-boot:run| User | Path | Header | Required |
|---|---|---|---|
| Admin | api/admin | Authorization: Bearer JWT | β |
| Anonim | api/public | None | β |
POST /api/auth/register
{
"username": "your_username",
"password": "your_password"
}POST /api/auth/login
{
"username": "your_username",
"password": "your_password"
}POST /api/admin/comics
Form Data:
| Key | Type | Required |
|---|---|---|
| cover | file | β |
| title | text | β |
| synopsis | text | β |
| author | text | β |
| artist | text | β |
| type | text | β |
PUT /api/admin/comics/{comicId}
GET /api/public/comics?page=1&size=10
GET /api/public/comics/{comicId}
GET /api/public/comics/search?keyword={keyword}&page={page}&size={size}
GET /api/public/comics/type?type={type}&page={page}&size={size}
DELETE /api/admin/comics/{comicId}
POST /api/admin/comics/{comicId}/chapters
{
"number": 1
}PUT /api/admin/comics/{comicId}/chapters/{chapterId}
{
"number": 2
}GET /api/public/comics/{comicId}/chapters
GET /api/public/comics/{comicId}/chapters/{chapterId}
DELETE /api/admin/comics/{comicId}/chapters/{chapterId}
POST /api/admin/comics/{comicId}/chapters/{chapterId}/contents
Form Data:
| Key | Type | Required |
|---|---|---|
| content | file | β |
PUT /api/admin/comics/{comicId}/chapters/{chapterId}/contents/{contentId}
GET /api/public/comics/{comicId}/chapters/{chapterNumber}/contents
DELETE /api/admin/comics/{comicId}/chapters/{chapterId}/contents/{contentId}
POST /api/admin/categories
{
"name": "harem"
}PUT /api/admin/categories/{categoryId}
{
"name": "action"
}GET /api/public/categories
POST /api/admin/comic-categories
{
"comicId": 7,
"categoryId": 3
}GET /api/admin/comic-categories/categories/{categoryId}?page={page}&size={size}
DELETE /api/admin/comic-categories/{comicCategoryId}
{
"data": "OK",
"error": null
}{
"data": null,
"error": "resource not found"
}- All
/api/admin/**endpoints require a valid JWT token. - File uploads are stored in Cloudinary and accessible via returned URLs.
- Spring's validation handles input validation via Jakarta Bean Validation.
- The project uses consistent response wrapping to standardize API output.
This project is licensed under the Apache License 2.0. You are free to use, modify, and distribute this project under the terms of that license.