اليوم رح نبدأ بالسلسلة لتطوير Backend باستخدام Spring Boot. بنهاية السلسلة رح نكون بنينا Employee Management System - نظام لإدارة الموظفين فيه أكثر من جدول بقاعدة البيانات.
السيستم رح يشمل موظفين، حسابات، أقسام، وطلبات إجازات. بس رح نبدأ بسيط وزيد التعقيد خطوة بخطوة.
بالسلسلة رح نمشي بالترتيب التالي:
بنفتح Spring Initializr ونختار الإعدادات التالية:
بالـ Dependencies لازم ننزّل ثلاث حاجات:
Spring WebSpring Data JPALombokبعد ما نفتح المشروع بالإديتر رح يكون عنا هالهيكل:
project/
├── .mvn/ # Maven wrapper
├── src/
│ ├── main/
│ │ ├── java/ # الكود الأساسي
│ │ └── resources/ # إعدادات التطبيق
│ └── test/ # كود الاختبارات
└── pom.xml # إدارة الـ Dependencies
الملف pom.xml هو المكان اللي بنضيف فيه الـ Dependencies مثل Lombok وغيرها.
بننشئ Package جديد اسمه entities جوا الباكيج الأساسي، وفيه بننشئ كلاس Employee مع هالخصائص:
public class Employee {
private UUID id;
private String firstName;
private String lastName;
private String email;
private String phoneNumber;
private LocalDate hireDate;
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
الكلاس هذا بحاجة لـ Getters وSetters وConstructor. بدون Lombok رح نحتاج كتابة كل هاد يدوياً - حوالي 90 سطر!
Lombok بيوفر علينا كتابة الـ Boilerplate Code عن طريق Annotations. بدل ما نكتب كل الـ Getters والSetters يدوياً، بنضيف:
@Getter
@Setter
@AllArgsConstructor
public class Employee {
private UUID id;
private String firstName;
private String lastName;
private String email;
private String phoneNumber;
private LocalDate hireDate;
private String position;
private UUID departmentId;
}وهيك الكلاس صار 21 سطر بدل 90!
@Getter - ينشئ Getter لكل خاصية تلقائياً عند الـ Compilation@Setter - ينشئ Setter لكل خاصية@AllArgsConstructor - ينشئ Constructor يأخذ كل الخصائص كـ Parametersللتأكد من أن Lombok شغالة، فوت على target/classes/entities/Employee.class وشوف إذا الكود المولّد موجود.
بننشئ Package جديد اسمه controllers وفيه كلاس EmployeeController. Spring Boot بيعرف إنو هذا الكلاس هو Controller عن طريق الـ Annotation:
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private ArrayList<Employee> employees = new ArrayList<>();
@GetMapping
public ArrayList<Employee> findAll() {
return employees;
}
}@RestController - بيحدد إن هذا الكلاس هو Controller يستلم HTTP Requests@RequestMapping("/employees") - بيحدد الـ Base URL للـ Controller@GetMapping - بيعرف Endpoint تستجيب لطلبات GETلما نشغّل التطبيق ونفتح http://localhost:8080/employees، رح يرجع لنا Array فاضي.
خلينا نضيف موظفين بالـ ArrayList لنتأكد من الشغل:
private ArrayList<Employee> employees = new ArrayList<>(List.of(
new Employee(UUID.randomUUID(), "John", "Smith", "john@example.com",
"0912345678", LocalDate.of(2022, 1, 15), "Developer", UUID.randomUUID()),
new Employee(UUID.randomUUID(), "Sara", "Jones", "sara@example.com",
"0987654321", LocalDate.of(2021, 6, 1), "Designer", UUID.randomUUID())
));بعد ما نعمل Run ونفتح localhost:8080/employees رح يرجع لنا:
[
{ "id": "...", "firstName": "John", "lastName": "Smith", ... },
{ "id": "...", "firstName": "Sara", "lastName": "Jones", ... }
]لنضيف Endpoint لجلب موظف واحد بالـ ID، بنستخدم Path Variable:
@GetMapping("/{employeeId}")
public Optional<Employee> findOne(@PathVariable UUID employeeId) {
return employees.stream()
.filter(emp -> emp.getId().equals(employeeId))
.findFirst();
}الـ {employeeId} جوا الـ Curly Brackets بيعني إنو هذا Dynamic Variable، يعني قيمة متغيرة في كل طلب.
@PathVariable بتأخذ القيمة من الـ URL وتحطها بالـ Parameterstream().filter() لنبحث بالـ List عن الموظف اللي عنده نفس الـ IDfindFirst() بترجع Optional لأنو ممكن ما نلاقي الموظفالـ Endpoint رح تكون: GET /employees/{id}
GET http://localhost:8080/employees/3fa85f64-5717-4562-b3fc-2c963f66afa6
وبترجع بيانات الموظف اللي عنده هالـ ID.
الفكرة الأساسية للـ Controller هي:
بالفيديو الجاي رح نضيف POST وPUT وDELETE Endpoints، ونشوف كيف نتعامل مع بيانات الطلب.