Kotlin CRUD Rest Api با استفاده از Spring Boot، Hibernate، Postgres، Docker و Docker Compose

بیایید یک CRUD Rest API در Kotlin ایجاد کنیم، با استفاده از:
- چکمه بهاره
- گریدل
- خواب زمستانی
- Postgres
- داکر
- Docker Compose
اگر نسخه ویدیویی را ترجیح می دهید:
https://www.youtube.com/watch?v=BbT1PCAOS2s
تمام کدها در مخزن GitHub موجود است (لینک در توضیحات ویدیو): https://youtube.com/live/BbT1PCAOS2s
🏁 معرفی
در اینجا طرحی از معماری برنامه ای که می خواهیم ایجاد کنیم آمده است:
ما 5 نقطه پایانی برای عملیات اصلی CRUD ایجاد خواهیم کرد:
- ايجاد كردن
- همه اش را بخوان
- یکی را بخوانید
- به روز رسانی
- حذف
در اینجا مراحلی است که ما طی می کنیم:
- با استفاده از Spring Initializr یک پروژه Spring Boot ایجاد کنید
- اتصال پایگاه داده را پیکربندی کنید
- User.kt، UserRepository.kt و UserService.kt را ایجاد کنید
- برنامه را داکر کنید
- برای اجرای پایگاه داده و برنامه، docker-compose.yml را ایجاد کنید
- برنامه را با Postman و Tableplus تست کنید
ما با یک راهنمای گام به گام همراه خواهیم بود، بنابراین شما می توانید با آن همراه باشید.
الزامات:
- Kotlin نصب شده است
- Docker نصب شده و در حال اجرا است
- (اختیاری): پستچی و Tableplus را دنبال کنید، اما هر ابزار آزمایشی کار خواهد کرد
اختیاری: کد VS با پسوندهای زیر:
- بسته برنامه افزودنی جاوا
- بسته الحاقی بوت بهار
🚀 یک پروژه جدید Kotlin ایجاد کنید
راه های زیادی برای ایجاد یک پروژه جدید Kotlin وجود دارد، اما من از Spring Initializr در VS Code استفاده خواهم کرد.
برای این کار باید بسته برنامه افزودنی جاوا و بسته برنامه افزودنی Spring Boot را نصب کرده باشید.
VS Code را باز کنید و روی دکمه “ایجاد پروژه جاوا” کلیک کنید:
با این کار یک درخواست در بالای صفحه باز می شود. به ترتیب روی موارد زیر کلیک کنید:
- چکمه بهاره
- گریدل
- 3.0.5 (ممکن است در آینده تغییر کند)
- کاتلین
- com.example (فقط روی enter کلیک کنید)
- دمو (فقط روی enter کلیک کنید)
- شیشه
- جاوا 17
با این کار یک اعلان دیگر باز می شود. به ترتیب روی موارد زیر کلیک کنید:
- Spring Web (وابستگی به ایجاد Rest API)
- Spring Data JPA (وابستگی به استفاده از Hibernate)
- درایور PostgreSQL (وابستگی به اتصال به Postgres)
سپس باید پوشه ای را که می خواهید پروژه را در آن ایجاد کنید انتخاب کنید.
یک پوشه را انتخاب کنید و روی «Generate into this folder» ساعت کنید.
اکنون روی دکمه سمت راست پایین صفحه کلیک کنید تا پروژه در یک پنجره جدید باز شود.
ما با ایجاد پروژه تمام شده است.
اکنون می توانیم برنامه نویسی را شروع کنیم.
👩💻 برنامه را کدگذاری کنید
دو مرحله برای کدنویسی برنامه وجود دارد:
- اتصال پایگاه داده را پیکربندی کنید
- موجودیت کاربر، UserRepository و UserService را ایجاد کنید
🔗 پیکربندی اتصال پایگاه داده
باز کن application.properties
فایل در src/main/resources
پوشه (باید خالی باشد).
مطالب زیر را اضافه کنید:
spring.datasource.url=${DB_URL}
spring.datasource.username=${PG_USER}
spring.datasource.password=${PG_PASSWORD}
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
توضیح:
-
spring.datasource.url
: آدرس پایگاه داده. -
spring.datasource.username
: نام کاربری پایگاه داده. -
spring.datasource.password
: رمز عبور پایگاه داده -
spring.jpa.hibernate.ddl-auto
: روشی که می خواهیم پایگاه داده را به روز کنیم. ما استفاده خواهیم کردupdate
برای ایجاد جداول در صورت عدم وجود، و به روز رسانی آنها در صورت وجود. -
spring.jpa.properties.hibernate.dialect
: گویش پایگاه داده. ما از PostgreSQL استفاده خواهیم کرد.
بعداً از متغیرهای محیطی استفاده خواهیم کرد (و کمی مشکل خواهد بود).
📁 ساختار منبع را ایجاد کنید
یک پوشه جدید به نام ایجاد کنید users
در demo
پوشه (یا هر نام دیگری که پروژه خود را نامگذاری کرده اید).
در این پوشه سه فایل ایجاد کنید:
User.kt
UserRepository.kt
UserController.kt
پوشه شما باید شبیه این باشد:
حالا بیایید فایل ها را پر کنیم.
User.kt
فایل User.kt حاوی موجودیت کاربر خواهد بود.
فایل را باز کنید و محتوای زیر را اضافه کنید (نام بسته را برای مطابقت با پروژه خود تغییر دهید):
package com.example.demo.users
import jakarta.persistence.*
@Entity
@Table(name = "users")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long,
val name: String,
val email: String
)
توضیح:
-
@Entity
: decorator به Hibernate بگوید که این کلاس یک موجودیت است. -
@Table
: decorator برای گفتن Hibernate نام جدول در پایگاه داده (“users in this case”). -
@Id
: دکوراتور به Hibernate بگوید که این فیلد کلید اصلی است. -
@GeneratedValue
: دکوراتور برای افزایش خودکار شناسه هر زمان که کاربر جدیدی ایجاد می کنیم.
یک کاربر سه فیلد خواهد داشت: id
، name
و email
.
UserRepository.kt
فایل UserRepository.kt شامل رابطی برای تعامل با پایگاه داده خواهد بود.
فایل را باز کنید UserRepository.kt
و محتوای زیر را اضافه کنید (اگر از بسته دیگری استفاده می کنید، نام بسته را تغییر دهید):
package com.example.demo.users
import org.springframework.data.repository.CrudRepository
interface UserRepository : CrudRepository<User, Long>
توضیح:
-
interface UserRepository
: رابطی که شامل متدهای تعامل با پایگاه داده است. از نوع خواهد بودCrudRepository
. این یک رابط عمومی است که شامل روش های اساسی برای تعامل با پایگاه داده است. یک نوع خواهد داشتUser
و یکInt
(نوع کلید اصلی).
UserController.kt
فایل UserController.kt حاوی Rest API خواهد بود.
فایل را باز کنید UserController.kt
و محتوای زیر را اضافه کنید (اگر از بسته دیگری استفاده می کنید، نام بسته را تغییر دهید):
package com.example.demo.users
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/api/users")
class UserController(@Autowired private val userRepository: UserRepository) {
@GetMapping("")
fun getAllUsers(): List<User> =
userRepository.findAll().toList()
@PostMapping("")
fun createUser(@RequestBody user: User): ResponseEntity<User> {
val createdUser = userRepository.save(user)
return ResponseEntity(createdUser, HttpStatus.CREATED)
}
@GetMapping("/{id}")
fun getUserById(@PathVariable("id") userId: Int): ResponseEntity<User> {
val user = userRepository.findById(userId).orElse(null)
return if (user != null) ResponseEntity(user, HttpStatus.OK)
else ResponseEntity(HttpStatus.NOT_FOUND)
}
@PutMapping("/{id}")
fun updateUserById(@PathVariable("id") userId: Int, @RequestBody user: User): ResponseEntity<User> {
val existingUser = userRepository.findById(userId).orElse(null)
if (existingUser == null) {
return ResponseEntity(HttpStatus.NOT_FOUND)
}
val updatedUser = existingUser.copy(name = user.name, email = user.email)
userRepository.save(updatedUser)
return ResponseEntity(updatedUser, HttpStatus.OK)
}
@DeleteMapping("/{id}")
fun deleteUserById(@PathVariable("id") userId: Int): ResponseEntity<User> {
if (!userRepository.existsById(userId)) {
return ResponseEntity(HttpStatus.NOT_FOUND)
}
userRepository.deleteById(userId)
return ResponseEntity(HttpStatus.NO_CONTENT)
}
}
توضیح:
-
@RestController
: دکوراتور برای بهار. -
@RequestMapping
: برای گفتن به Spring url پایه Rest API. در این صورت خواهد بود/api/users
. -
@Autowired
: به بهار بگویم که تزریق کندUserRepository
.
سپس ما پنج روش برای تعامل با پایگاه داده داریم:
-
getAllUsers
: برای دریافت همه کاربران. -
createUser
: برای ایجاد یک کاربر جدید. -
getUserById
: برای بدست آوردن کاربر با شناسه. -
updateUserById
: برای به روز رسانی یک کاربر با شناسه. -
deleteUserById
: برای حذف یک کاربر با شناسه.
Rest API ما برای Dockerized آماده است.
🐳 داکرسازی
اکنون بخش سرگرم کننده: Dockerization.
در این پروژه تصمیم گرفتم پروژه کاتلین را مستقیماً در داخل تصویر داکر بسازم.
گزینه دیگر این است که پروژه را به صورت محلی بسازید و سپس فایل jar را در تصویر داکر کپی کنید.
🐋 داکرفایل
یک فایل جدید به نام ایجاد کنید Dockerfile
در ریشه پروژه
مطالب زیر را اضافه کنید (توضیحات در نظرات موجود است):
# Start with a base image containing Java runtime
FROM amazoncorretto:17-alpine-jdk
# Create a directory
WORKDIR /app
# Copy all the files from the current directory to the image
COPY . .
# build the project avoiding tests
RUN ./gradlew clean build -x test
# Expose port 8080
EXPOSE 8080
# Run the jar file
CMD ["java", "-jar", "./build/libs/demo-0.0.1-SNAPSHOT.jar"]
⚠️ بخش غیرمعمول در اینجا خطوط ARG هستند. آنها برای ارسال آرگومان ها به تصویر Docker استفاده می شوند. آنها در تعریف شده اند docker-compose.yml
فایل.
🐙 docker-compose.yml
بیایید ایجاد کنیم docker-compose.yml
فایل در ریشه پروژه
مطالب زیر را اضافه کنید (توضیحات در نظرات موجود است):
version: '3.9'
services:
kotlinapp:
container_name: kotlinapp
build: # this is the build context: .
context: .
dockerfile: Dockerfile
args: # these are the arguments that are passed to the dockerfile
DB_URL: ${DB_URL}
PG_USER: ${PG_USER}
PG_PASSWORD: ${PG_PASSWORD}
ports: # port exposed to the host machine
- "8080:8080"
environment: # these are the environment variables that are passed to the dockerfile
DB_URL: jdbc:postgresql://db:5432/postgres
PG_USER: postgres
PG_PASSWORD: postgres
depends_on: # this is the dependency on the db service
- db
db:
container_name: db
image: postgres:12
environment: # environment variables for the Postgres container
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
ports: # port exposed to the host machine
- "5432:5432"
volumes: # volume used to persist data
- pgdata:/var/lib/postgresql/data
volumes: # volume creation
pgdata: {}
پروژه را بسازید و اجرا کنید
اکنون می توانیم پروژه را بسازیم و اجرا کنیم.
💽 پایگاه داده Postgres را اجرا کنید
ابتدا باید پایگاه داده Postgres را اجرا کنیم.
docker compose up -d db
برای بررسی اینکه آیا در حال اجرا است، می توانید از دستور زیر استفاده کنید:
docker compose logs
و
docker ps -a
اگر خروجی مانند خروجی زیر است، خوب است که بروید:
شما باید چنین چیزی را ببینید، شما خوب هستید که بروید.
به عنوان آزمایش اضافی، می توانید با استفاده از TablePlus (یا هر مشتری پایگاه داده دیگر) به پایگاه داده متصل شوید.
می توانید با استفاده از پارامترهای زیر یک اتصال جدید ایجاد کنید:
- میزبان: localhost
- بندر: 5432
- پایگاه داده: postgres
- کاربر: postgres
- رمز عبور: postgres
سپس بر روی آن کلیک کنید Test Connection
دکمه. پایگاه داده متصل است اما در حال حاضر خالی است.
🏗️ پروژه را بسازید
بیایید پروژه را در داخل تصویر داکر بسازیم.
docker compose build
و خروجی باید چیزی شبیه به این باشد:
🏃♂️ پروژه را اجرا کنید
اکنون می توانیم پروژه را اجرا کنیم.
docker compose up kotlinapp
و این باید خروجی باشد:
🧪 پروژه را تست کنید
اکنون می توانیم پروژه را آزمایش کنیم. ما از Postman استفاده خواهیم کرد، اما شما می توانید از هر ابزار دیگری استفاده کنید.
📝 یک کاربر ایجاد کنید
برای ایجاد یک کاربر جدید، a را ایجاد کنید POST request to localhost:8080/api/users
.
بدنه درخواست باید به این صورت باشد:
{
"name": "aaa",
"email": "aaa@mail"
}
خروجی باید چیزی شبیه به این باشد:
بیایید دو کاربر دیگر ایجاد کنیم، یک POST request to localhost:8080/api/users
.
{
"name": "bbb",
"email": "bbb@mail"
}
{
"name": "ccc",
"email": "ccc@mail"
}
📝 همه کاربران را دریافت کنید
برای دریافت همه کاربران، یک را بسازید GET request to localhost:8000/api/users
.
خروجی باید چیزی شبیه به این باشد:
📝 یک کاربر دریافت کنید
برای به دست آوردن یک کاربر، a GET request to localhost:8000/api/users/{id}
.
مثلا GET request to localhost:8000/api/users/1
.
خروجی باید چیزی شبیه به این باشد:
📝 یک کاربر را به روز کنید
برای به روز رسانی یک کاربر، یک را ایجاد کنید PUT request to localhost:8000/api/users/{id}
.
مثلا PUT request to localhost:8000/api/users/2
.
بدنه درخواست باید به این صورت باشد:
{
"name": "Francesco",
"email": "francesco@mail"
}
خروجی باید چیزی شبیه به این باشد:
📝 حذف یک کاربر
برای حذف یک کاربر، یک علامت بزنید DELETE request to localhost:8000/api/users/{id}
.
مثلا DELETE request to localhost:8000/api/users/1
.
در پستچی باید چیزی شبیه به آن را ببینید:
تست نهایی
به عنوان تست نهایی، می توانیم پایگاه داده را با استفاده از TablePlus بررسی کنیم.
🏁نتیجه گیری
ما ساختیمش! ما یک CRUD rest API در Kotlin ساختهایم که با استفاده از:
- چکمه بهاره
- گریدل
- خواب زمستانی
- Postgres
- داکر
- Docker Compose
اگر نسخه ویدیویی را ترجیح می دهید:
https://www.youtube.com/watch?v=BbT1PCAOS2s
تمام کدها در مخزن GitHub موجود است (لینک در توضیحات ویدیو): https://youtube.com/live/BbT1PCAOS2s
همین.
اگر سوالی دارید، در زیر نظر دهید.
فرانچسکو