12. [TD]: تنفيذ الطبقة [DAO] من TD باستخدام [Spring Data]
الكلمات الرئيسية: بنية متعددة الطبقات، Spring، حقن التبعيات، API JPA (Java Persistence API)، Spring Data.
سنتبع نفس النهج السابق لتنفيذ الطبقة [DAO] من TD.
12.1. Support
![]() |
- في [1]، يحتوي المجلد [support / chap-12] على مشروع Eclipse الخاص بهذا الفصل؛
12.2. مشروع Eclipse
سيكون مشروع Eclipse كما يلي:
![]() |
- [elections.dao.config]: يحتوي على فئة تكوين مشروع Spring؛
- [elections.dao.entities]: يحتوي على الكيانات JPA بالإضافة إلى فئة الاستثناءات الخاصة بالمشروع؛
- [elections.dao.repositories]: يحتوي على واجهات [CrudRepository] للجداول [CONF] و [LISTES]؛
- [elections.dao.service]: تحتوي على تنفيذ الطبقة [DAO]. هذه هي الطبقة التي يتعين علينا كتابتها؛
- [elections.dao.console]: يحتوي على فئة اختبار من النوع [console]؛
- [pom.xml]: ملف تكوين مشروع Maven؛
يُنفذ هذا المشروع البنية التالية:
![]() |
لا ترى الطبقة [DAO] سوى الطبقة التي تنفذها [Spring Data].
12.3. تكوين Maven
المهمة المطلوبة: قم بإنشاء ملف [pom.xml] للمشروع.
12.4. كيانات الطبقة [JPA]
![]() |
![]() |
- [ElectionsConfig] هو نموذج الكائن المرتبط بصف في الجدول [CONF]؛
- [ListeElectorale] هو نموذج الكائن المرتبط بصف في الجدول [LISTES]؛
- [AbstactEntity] هي الفئة الأم للفئتين السابقتين. وهي تعمم الحقول [id, version] المشتركة بين الفئتين؛
- [ElectionsException] هي فئة الاستثناءات للمشروع؛
12.4.1. الفئة [ElectionsException]
![]() |
الفئة [ElectionsException] هي الاستثناء غير المتحكم فيه الموصوف في الفقرة 4.3.
12.4.2. فئة [AbstractEntity]
![]() |
الفئة [AbstractEntity] هي التالية:
package elections.dao.entities;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@MappedSuperclass
public abstract class AbstractEntity implements Serializable{
private static final long serialVersionUID = 1L;
// الخصائص
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
protected Long id;
@Version
@Column(name = "VERSION")
protected Long version;
// المنشئات
public AbstractEntity() {
}
public AbstractEntity(Long id, Long version) {
this.id = id;
this.version = version;
}
// إعادة تعريف [equals] و [hashcode]
@Override
public int hashCode() {
return (id != null ? id.hashCode() : 0);
}
@Override
public boolean equals(Object entity) {
if (!(entity instanceof AbstractEntity)) {
return false;
}
String class1 = this.getClass().getName();
String class2 = entity.getClass().getName();
if (!class2.equals(class1)) {
return false;
}
AbstractEntity other = (AbstractEntity) entity;
return id != null && this.id == other.id;
}
// التوقيع jSON
public String toString() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
// المُستردات والمُعيّنات
...
}
هذه هي الفئة الموصوفة في الفقرة 11.3.5.2، بدون المرشحات jSON. هنا، في الواقع، لا ترتبط الجداول [CONF] و [LISTES] بعلاقة مفتاح أجنبي. ومع ذلك، فإن وجود مثل هذه العلاقة مع الوضع [lazy loading] هو ما يستلزم وجود المرشحات jSON.
12.4.3. الفئة [ElectionsConfig]
![]() |
الفئة [ElectionsConfig] هي الكيان JPA المرتبط بالجدول [CONF]؛
المهمة المطلوبة: قم بإنشاء الفئة [ElectionsConfig].
12.4.4. الفئة [ListeElectorale]
![]() |
الفئة [ListeElectorale] هي الكيان JPA المرتبط بالجدول [LISTES]؛
المهمة المطلوبة: قم بإنشاء الفئة [ListeElectorale].
12.5. الطبقة [Spring Data]
![]() |
المهمة المطلوبة: اكتب واجهتي [Spring Data] لإدارة الجدولين [CONF] و [LISTES]؛
12.6. الطبقة [DAO]
![]() |
واجهة [IElectionsDao] للطبقة [DAO] هي كما يلي:
package dao.service;
import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;
public interface IElectionsDao {
// تكوين الانتخابات
public ElectionsConfig getElectionsConfig();
// قوائم المرشحين
public ListeElectorale[] getListesElectorales();
// تحديث قوائم المرشحين
public void setListesElectorales(ListeElectorale[] listesElectorales);
}
المهمة المطلوبة: اكتب تنفيذ [ElectionsDaoJpa] للواجهة [IElectionsDao].
12.7. تكوين مشروع Spring
تقوم الفئة [DaoConfig] بتكوين مشروع Spring.
المهمة المطلوبة: اكتب الفئة [DaoConfig]
12.8. الطبقة [console]
![]() |
![]() |
الطبقة [Main] هي الطبقة القابلة للتنفيذ التالية:
package dao.console;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import dao.config.AppConfig;
import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;
import dao.service.IElectionsDao;
public class Main {
// مصدر البيانات
private static IElectionsDao dao;
public static void main(String[] args) {
// استرداد سياق Spring
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// استرداد مصدر البيانات
dao = ctx.getBean(IElectionsDao.class);
// محتوى الجدولين
ElectionsConfig electionsConfig = dao.getElectionsConfig();
ListeElectorale[] listes = dao.getListesElectorales();
// العرض
System.out.println(String.format("Nombre de sièges à pourvoir : %d", electionsConfig.getNbSiegesAPourvoir()));
System.out.println(String.format("Seuil électoral : %5.2f", electionsConfig.getSeuilElectoral()));
System.out.println("Listes candidates----------------");
for (ListeElectorale liste : listes) {
System.out.println(liste);
}
// إغلاق سياق Spring
ctx.close();
}
}
الفئة [Test01] هي اختبار JUnit:
package dao.tests;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import dao.config.AppConfig;
import dao.entities.ElectionsConfig;
import dao.entities.ListeElectorale;
import dao.service.IElectionsDao;
@SpringApplicationConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {
// الطبقة [DAO]
@Autowired
private IElectionsDao electionsDao;
@Before
public void init() {
// تنظيف الجدول [LISTES]
// القوائم المتنافسة
ListeElectorale[] listes = electionsDao.getListesElectorales();
// يتم تعيين الأصوات والمقاعد على 0 وإزالة القيمة false
int voix = 0;
int sièges = 0;
boolean elimine = false;
for (ListeElectorale liste : listes) {
liste.setVoix(voix);
liste.setSieges(sièges);
liste.setElimine(elimine);
}
// جعل هذه البيانات دائمة بفضل الطبقة [dao]
electionsDao.setListesElectorales(listes);
}
@Test
public void testElections01() {
System.out.println("testElections01-------------------------------------");
// استرداد تكوين الانتخابات
ElectionsConfig electionsConfig = electionsDao.getElectionsConfig();
int nbSiegesAPourvoir = electionsConfig.getNbSiegesAPourvoir();
double seuilElectoral = electionsConfig.getSeuilElectoral();
Assert.assertEquals(6, nbSiegesAPourvoir);
Assert.assertEquals(0.05, seuilElectoral, 1E-6);
// القوائم المتنافسة
ListeElectorale[] listes = electionsDao.getListesElectorales();
// عرض القيم المقروءة
System.out.println("Nombre de sièges à pourvoir : " + nbSiegesAPourvoir);
System.out.println("Seuil électoral : " + seuilElectoral);
System.out.println("Listes en compétition ---------------------");
for (int i = 0; i < listes.length; i++) {
System.out.println(listes[i]);
}
// تخصيص الأصوات والمقاعد للقوائم
int voix = 0;
int sièges = 0;
boolean elimine = false;
for (ListeElectorale liste : listes) {
liste.setVoix(voix);
liste.setSieges(sièges);
liste.setElimine(elimine);
voix += 10;
sièges += 1;
elimine = !elimine;
}
// جعل هذه البيانات دائمة بفضل الطبقة [dao]
electionsDao.setListesElectorales(listes);
// إعادة قراءة البيانات
ListeElectorale[] listesElectorales2 = electionsDao.getListesElectorales();
// يتم التحقق من البيانات التي تمت قراءتها
Assert.assertEquals(7, listesElectorales2.length);
voix = 0;
sièges = 0;
elimine = false;
for (ListeElectorale liste : listes) {
Assert.assertEquals(voix, liste.getVoix());
Assert.assertEquals(sièges, liste.getSieges());
Assert.assertEquals(elimine, liste.isElimine());
voix += 10;
sièges += 1;
elimine = !elimine;
}
System.out.println("Listes en compétition ---------------------");
for (int i = 0; i < listes.length; i++) {
System.out.println(listes[i]);
}
}
}
المهمة المطلوبة: قم بإجراء الاختبارات [console] و [JUnit] على الطبقة [DAO] الخاصة بك.
12.9. إنشاء أرشيف Maven للمشروع
باتباع المثال الوارد في الفقرة 11.3.12، قم بإنشاء أرشيف Maven للمشروع.












