Skip to content

12. [TD]: پیاده‌سازی لایه [DAO] از TD با استفاده از [Spring Data]

کلیدواژه‌ها: معماری چندلایه، اسپرینگ، تزریق وابستگی، API JPA (پایداری جاوا API)، اسپرینگ دیتا.

ما همان رویکرد قبلی را برای پیاده‌سازی لایه [DAO] از TD دنبال خواهیم کرد.

12.1. Support

  • در [1]، پوشه [support / chap-12] حاوی پروژه Eclipse برای این فصل است؛

12.2. پروژه اکلیپس

پروژه اکلیپس به شرح زیر خواهد بود:

  
  • [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] استثنای رسیدگی‌نشده‌ای است که در بخش ۴.۳ توضیح داده شده است.

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) {
        //بازیابی کنتکس بهار
        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 تنظیم کنید و مقدار 'eliminated' را روی 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 پروژه را تولید کنید.