Skip to content

7. [TD]: TD sınıfının [DAO] katmanının API ve JDBC ile uygulanması

Anahtar kelimeler: ilişkisel veritabanları, API, JDBC, SQLException.

Uygulamamızın katmanlı mimarisine tekrar göz atalım:

Seçim için gerekli veriler bir veritabanına kaydedilir MySQL [dbelections]

7.1. Support

[support / chap-07] [1] klasörü şunları içerir:

  • bu bölümün Eclipse projeleri [2];
  • SQL veritabanını oluşturan komut dosyası: MySQL, [dbelections], [3];

7.2. [dbelections] veritabanı


Yapılması gereken iş: 6.4.2. paragrafında izlenen prosedürü takip ederek MySQL ve [dblelections] veritabanlarını oluşturun.


[dbelections] veritabanı, iki tablo içeren bir MySQL veritabanıdır:

  

[conf] tablosu, seçimle ilgili yapılandırma bilgilerini içerir:

 
  • [id]: otomatik artan birincil anahtar;
  • [version]: kaydın sürüm numarası – burada göz ardı edilebilir;
  • [sap]: doldurulacak koltuk sayısı;
  • [seuilelectoral]: bir listenin elenmesi için alt sınır;

İçeriği şu şekildedir:

 

[listes] tablosu, seçim aday listelerini içerir:

 
  • [id]: otomatik artan birincil anahtar;
  • [version]: kaydın sürüm numarası – burada göz ardı edilebilir;
  • [nom]: listenin adı;
  • [voix]: listenin adı – ancak kullanıcı [présentation] katmanına giriş yaptıktan sonra bilinir;
  • [sieges]: kazanılan sandalye sayısı - yalnızca [métier] katmanının hesaplanmasından sonra bilinir;
  • [elimine]: liste elenmişse 1, aksi takdirde 0 - yalnızca [métier] katmanının hesaplanmasından sonra bilinir;

[listes] tablosunun içeriği şöyledir:

 

[dbelections] veritabanını oluşturmak için kullanılan SQL komut dosyası, [dbelections.sql] adını taşır ve sunucuda bulunur. Kod şöyledir:


-- phpMyAdmin SQL Dump
-- sürüm 4.0.4
-- http://www.phpmyadmin.net
--
-- İstemci: localhost
-- Oluşturulma tarihi: 11 Mart 2015 Çarşamba, 12:20
-- Sunucu sürümü: 5.6.12-log
-- PHP sürümü: 5.4.12

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Veritabanı: `dbelections`
--
CREATE DATABASE IF NOT EXISTS `dbelections` DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;
USE `dbelections`;

-- --------------------------------------------------------

--
-- `conf` tablosunun yapısı
--

CREATE TABLE IF NOT EXISTS `conf` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `version` int(11) NOT NULL DEFAULT '1',
  `sap` tinyint(4) NOT NULL,
  `seuilelectoral` double NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci AUTO_INCREMENT=2 ;

--
-- `conf` tablosunun içeriği
--

INSERT INTO `conf` (`id`, `version`, `sap`, `seuilelectoral`) VALUES
(1, 1, 6, 0.05);

-- --------------------------------------------------------

--
-- `listes` tablosunun yapısı
--

CREATE TABLE IF NOT EXISTS `listes` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `version` int(11) NOT NULL DEFAULT '1',
  `nom` varchar(20) COLLATE utf8_swedish_ci NOT NULL,
  `voix` int(11) NOT NULL,
  `sieges` int(11) NOT NULL,
  `elimine` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `nom` (`nom`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci AUTO_INCREMENT=8 ;

--
-- `listes` tablosunun içeriği
--

INSERT INTO `listes` (`id`, `version`, `nom`, `voix`, `sieges`, `elimine`) VALUES
(1, 21, 'A', 10, 1, 0),
(2, 22, 'B', 20, 2, 0),
(3, 21, 'C', 30, 3, 0),
(4, 13, 'D', 40, 3, 0),
(5, 17, 'E', 50, 6, 0),
(6, 18, 'F', 60, 1, 0),
(7, 19, 'G', 70, 2, 0);

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

7.3. Eclipse projesi

[DAO] katmanının Eclipse projesi şu şekilde olacaktır:

  
  • [elections.dao.entities] paketi, [DAO] katmanı tarafından işlenen nesneleri içerir;
  • [elections.dao.service] paketi, [DAO] katmanının uygulamasını içerir;
  • [elections.dao.config] paketi, [DAO] katmanının yapılandırmasını içerir;
  • [elections.dao.junit] paketi, projenin JUnit test sınıfını içerir;
  • [elections.dao.console] paketi, bir test çalıştırma sınıfı içerir;

7.4. Maven proje yapılandırması

 

Maven projesini yapılandıran [pom.xml] dosyası şöyledir:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-dao-jdbc-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <!-- Tomcat Jdbc -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>
        <!-- kütüphane jSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Testi -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Günlüğü -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
    </dependencies>

    <!-- eklentiler -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>config.AppConfig</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <!-- proje artefaktını yerel Maven deposuna yüklemek için -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>
</project>

Bu dosya, 6.5.1. paragrafında açıklanan dosyaya benzerdir. Dosyada aşağıdaki değişiklikler yapılmıştır:

  • 8-12. satırlar: Bir üst Maven projesi tanımlanmıştır. [spring-boot-starter-parent] projesi (10. satır), sürümleriyle birlikte çok sayıda bağımlılık tanımlamaktadır. Bunlardan birini kullandığımızda (19-57. satırlar), sürümünü belirtmeye gerek kalmaz; çünkü bu sürüm, üst Maven projesinde tanımlanmıştır;
  • satır 40-51: projenin test sınıfı için gerekli bağımlılıklar. Bu bağımlılıklar, [<scope>test</scope>] özniteliğine sahiptir; bu, bunların yalnızca [src / test / java] klasöründeki sınıflar için gerekli olduğu anlamına gelir. Bu bağımlılıklar, projenin nihai arşivine dahil edilmeyecektir;
  • 53-56. satırlar: [spring-boot-starter-logging] kütüphanesi, Spring tarafından ekrana günlük kaydı yapmak için kullanılacaktır;
  • 14-17. satırlar: Maven yapılandırma özellikleri:
    • 15. satır: kaynak dosyaların UTF-8 ile kodlandığını belirtir;
    • satır 16: kullanılacak derleyicinin 1.8 sürümü olması gerektiğini belirtir;

7.5. [DAO] katmanındaki varlıklar

  
  • [ElectionsConfig], [CONF] tablosundaki bir satıra ait nesne modelidir;
  • [ListeElectorale], [LISTES] tablosundaki bir satıra ait nesne modelidir;
  • [AbstactEntity], önceki iki sınıfın üst sınıfıdır. Bu sınıf, her iki sınıfa ortak olan [id, version] alanlarını bir araya getirir;
  • [ElectionsException] bir istisna sınıfıdır;

7.5.1. [ElectionsException] sınıfı

  

[ElectionsException] sınıfı 4.3. paragrafında açıklanmıştır. Kodunu tekrar veriyoruz:


package ...;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

// Elections uygulaması için istisna sınıfı
// istisna kontrolsüzdür

public class ElectionsException extends RuntimeException implements Serializable {

    // seri numarası ID
    private static final long serialVersionUID = 1L;

    // yerel alanlar
    private int code;
    private List<String> erreurs;

    // oluşturucular
    public ElectionsException() {
        super();
    }

    public ElectionsException(int code, Throwable e) {
        // üst
        super(e);
        // yerel
        this.code = code;
        this.erreurs = getErreursForException(e);
    }

    public ElectionsException(int code, String message, Throwable e) {
        // üst
        super(message,e);
        // yerel
        this.code = code;
        this.erreurs = getErreursForException(e);
    }

    public ElectionsException(int code, String message) {
        // üst
        super(message);
        // yerel
        this.code = code;
        List<String> erreurs = new ArrayList<>();
        erreurs.add(message);
        this.erreurs = erreurs;
    }

    public ElectionsException(int code, List<String> erreurs) {
        // üst
        super();
        // yerel
        this.code = code;
        this.erreurs = erreurs;
    }

    // bir istisnaya ait hata mesajları listesi
    private List<String> getErreursForException(Throwable th) {
        // istisnanın hata mesajları listesi alınır
        Throwable cause = th;
        List<String> erreurs = new ArrayList<>();
        while (cause != null) {
            // mesaj, yalnızca !=null ve boş değilse alınır
            String message = cause.getMessage();
            if (message != null) {
                message = message.trim();
                if (message.length() != 0) {
                    erreurs.add(message);
                }
            }
            // aşağıdaki neden
            cause = cause.getCause();
        }
        return erreurs;
    }

    // getter ve setter'lar
...
}

Bir [ElectionsException] nesnesi iki bilgiyle tanımlanır:

  • 16. satır: bir hata kodu;
  • 17. satır: meydana gelen istisna yığınıyla ilişkili hata mesajları listesi;
  • sınıfın 5 yapıcı işlevi vardır (satır 20, 24, 32, 40, 50);
  • satır 59-76: [getErreursForException] yöntemi, istisna yığınındaki hata mesajlarını almayı sağlar;

7.5.2. [AbstractEntity] sınıfı

  

[AbstractEntity] sınıfı şu şekildedir:


package elections.dao.entities;

import java.io.Serializable;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public abstract class AbstractEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    // alanlar
    protected Long id;
    protected Long version;

    // yapıcılar
    public AbstractEntity() {

    }

    public AbstractEntity(Long id, Long version) {
        this.id = id;
        this.version = version;
    }

    // imza
    public String toString() {
        try {
            return new ObjectMapper().writeValueAsString(this);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    // getter ve setter'lar
...
}

Bu sınıf, [ID, NOM] alanlarını [CONF] ve [LISTES] tablolarının satırlarından (8-9. satırlar) depolar.

  • 8. satır: Sınıf, örneklenemeyeceğini belirten [Abstract] özniteliğine sahiptir. Bu sınıf yalnızca türetilebilir;
  • 26-33. satırlar: nesnenin jSON imzası;
  • 28. satır: [this]'ten jSON dizesi döndürülür. Çalışma sırasında [this], [AbstactEntity]'ten türetilmiş bir nesneyi temsil ediyorsa, türetilmiş nesnenin jSON dizesi elde edilir. Böylece, türetilmiş sınıfların bir [toString] yöntemi tanımlamasına gerek kalmaz. Üst sınıftaki yöntem yeterlidir;

7.5.3. [ElectionsConfig] sınıfı

  

[ElectionsConfig] sınıfı şu şekildedir:


package elections.dao.entities;


public class ElectionsConfig extends AbstractEntity {

    private static final long serialVersionUID = 1L;
    // alanlar
    private int nbSiegesAPourvoir;
    private double seuilElectoral;

    // yapıcılar
    public ElectionsConfig() {
    }

    public ElectionsConfig(Long id, Long version, int nbSiegesAPourvoir, double seuilElectoral) {
        // üst sınıf
        super(id, version);
        // yerel alanlar
        this.nbSiegesAPourvoir = nbSiegesAPourvoir;
        this.seuilElectoral = seuilElectoral;
    }

    // getter ve setter'lar
...
}
  • 4. satır: sınıf, [AbstractEntity] sınıfını genişletir;
  • 8-9. satırlar: [CONF] tablosundaki [SAP, SEUILELECTORAL] sütunlarının bilgilerini depolar;

7.5.4. [ListeElectorale] sınıfı

  

[ListeElectorale] sınıfı şu şekildedir:


package elections.dao.entities;

public class ListeElectorale extends AbstractEntity {

    // alanlar
    private String nom;
    private int voix;
    private int sieges;
    private boolean elimine;

    // yapıcılar
    public ListeElectorale() {
    }

    public ListeElectorale(String nom, int voix, int sieges, boolean elimine) {
        // üst sınıf
        super();
        // yerel alanlar
        initNom(nom);
        initVoix(voix);
        initSieges(sieges);
        this.elimine=elimine;
    }

    public ListeElectorale(Long id, Long version, String nom, int voix, int sieges, boolean elimine) {
        // üst sınıf
        super(id, version);
        // yerel alanlar
        initNom(nom);
        initVoix(voix);
        initSieges(sieges);
        this.elimine=elimine;
    }

    // özel yöntemler
    private void initNom(String nom) {
        this.nom = nom.trim();
        if ("".equals(nom)) {
            throw new ElectionsException(10, "Le nom ne peut être vide");
        }
    }

    private void initVoix(int voix) {
        this.voix = voix;
        if (voix < 0) {
            throw new ElectionsException(11, "Le nombre de voix ne peut être <0");
        }
    }

    private void initSieges(int sieges) {
        this.sieges = sieges;
        if (sieges < 0) {
            throw new ElectionsException(12, "Le nombre de sièges ne peut être <0");
        }
    }

    // alıcı ve ayarlayıcılar

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        initNom(nom);
    }

    public int getVoix() {
        return voix;
    }

    public void setVoix(int voix) {
        initVoix(voix);
    }

    public int getSieges() {
        return sieges;
    }

    public void setSieges(int sieges) {
        initSieges(sieges);
    }

    public boolean isElimine() {
        return elimine;
    }

    public void setElimine(boolean elimine) {
        this.elimine = elimine;
    }

}
  • 3. satır: sınıf, [AbstractEntity] sınıfını genişletir;
  • 6-9. satırlar: sınıf, [LISTES] tablosunun [NOM, VOIX, SIEGES, ELIMINE] sütunlarını depolar;

7.6. [DAO] katmanının Spring yapılandırması

 

[AppConfig] sınıfı, veritabanına erişimi aşağıdaki şekilde yapılandıran bir Spring yapılandırma sınıfıdır:


package elections.dao.config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ComponentScan(basePackages = { "elections.dao.service" })
@EnableCaching
public class AppConfig {

    // sabitler
    public final static String URL = "jdbc:mysql://localhost:3306/dbelections";
    public final static String USER = "root";
    public final static String PASSWD = "";
    public final static String DRIVER_CLASSNAME = "com.mysql.jdbc.Driver";
    public final static String SELECT_LISTES = "SELECT ID, VERSION, NOM, VOIX, SIEGES, ELIMINE FROM LISTES";
    public final static String SELECT_CONF = "SELECT ID, VERSION, SAP, SEUILELECTORAL, SAP FROM CONF";
    public final static String UPDATE_LISTES = "UPDATE LISTES SET VOIX=?, SIEGES=?, ELIMINE=? WHERE ID=?";

    @Bean
    public DataSource dataSource() {
        // veri kaynağı TomcatJdbc
        DataSource dataSource = new DataSource();
        // erişim yapılandırması JDBC
        dataSource.setDriverClassName(DRIVER_CLASSNAME);
        dataSource.setUsername(USER);
        dataSource.setPassword(PASSWD);
        dataSource.setUrl(URL);
        // başlangıçta açık bir bağlantı
        dataSource.setInitialSize(1);
        // sonuç
        return dataSource;
    }

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("electionsConfig");
    }
}
  • 25-38. satırlar: BD'e erişim, [tomcat-jdbc] veri kaynağı aracılığıyla sağlanacaktır. Bu tür bir kaynak, 6.5. paragrafta kullanılmış ve açıklanmıştır;
  • 17-23. satırlar: projedeki tüm sınıflar tarafından erişilebilen bir dizi statik sabit;
  • 13. satır: [@Configuration] anotasyonu, [AppConfig] sınıfını bir Spring yapılandırma sınıfı haline getirir;
  • 11. satır: [@ComponentScan] anotasyonu, Spring nesnelerinin bulunabileceği paketleri belirtir. Burada, [dao] paketinde bir Spring nesnesi tanımlayacağız. [@ComponentScan] anotasyonu, sınıfı bir yapılandırma sınıfı haline getirir ve bu sayede [@Configuration] anotasyonunu eklememize gerek kalmaz;
  • 12. satır, önbellek yönetimini etkinleştirir. Prensip şöyledir:
    • M yöntemine [@Cacheable('nom_du_cache')] anotasyonu eklenir. 'önbellek_adı', 41. satırda kullanılan addır;
    • M yöntemi ilk kez çağrıldığında, sonuçları döndürülür ve aynı zamanda anotasyonla belirtilen önbelleğe kaydedilir;
    • M yöntemi, ilk seferkiyle aynı parametrelerle sonraki seferler çağrıldığında, yöntem çalıştırılmaz ve Spring sadece önbelleğe alınmış değerleri döndürür;

7.7. Günlüklerin yapılandırılması

Günlük kütüphaneleri, [pom.xml]'teki aşağıdaki bağımlılıkla tanımlanır:


        <!-- Spring Boot Günlüğü -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

Bu bağımlılık, aşağıdaki kütüphaneleri getirir:

  

Günlükleri sağlayacak olan kütüphane [logback]'tir. Bu kütüphane, iki dosya ile yapılandırılır:

  • [logback.xml], kodun ana dalı için;
  • [logback-test.xml], kodun test dalı için. Bu dosya yoksa, bir önceki dosya kullanılır;

Bu iki dosya, projenin [Classpath] dizininde bulunmalıdır. Bu nedenle, dosyalar şu klasöre yerleştirilmiştir:

  • [src / main / ressources], kodun ana dalı için;
  • [src / test / ressources], kodun test dalı için;

Dosyaların içeriği her ikisinde de aynıdır:


<configuration> 

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 
    <!-- kodlayıcılara varsayılan olarak tür atanır
         ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <!-- günlük seviyesi kontrolü -->
  <root level="info"> <!-- bilgi, hata ayıklama, uyarı -->
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Her şey 12. satırda gerçekleşir; burada istenen bilgi düzeyi belirlenir:

  • [debug]: en ayrıntılı seviye;
  • [off]: günlük yok;
  • [info]: normal günlük seviyesi;
  • [warn]: [info] seviyesiyle aynı, ayrıca uyarı mesajları (warning) da içerir. Bu mesajlar bir hata olasılığını gösterir;

Çalıştırma sırasında hatalar ortaya çıkar çıkmaz [debug] moduna geçin.

7.8. [DAO] katmanının uygulanması

  

[DAO] katmanının [IDao] arayüzü aşağıdaki gibidir:


package istia.st.elections.webapi.client.dao;

import istia.st.elections.webapi.client.entities.ElectionsConfig;
import istia.st.elections.webapi.client.entities.ListeElectorale;

public interface IDao {
    // seçim yapılandırması
    public ElectionsConfig getElectionsConfig();

    // yarışan listeler
    public ListeElectorale[] getListesElectorales();

    // seçim sonuçlarının kaydedilmesi
    public void setListesElectorales(ListeElectorale[] listesElectorales);

}

[dao] katmanını bir veritabanıyla uygulayan [ElectionsDaoJdbc] sınıfının iskeleti şu şekilde olacaktır:


package elections.dao.service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import elections.dao.entities.ElectionsConfig;
import elections.dao.entities.ElectionsException;
import elections.dao.entities.ListeElectorale;

@Component
@SuppressWarnings("unused")
public class ElectionDaoJdbc implements IElectionsDao {

    @Autowired
    private DataSource dataSource;

    @Cacheable("electionsConfig")
    // seçim yapılandırmasının alınması
    public ElectionsConfig getElectionsConfig() {
        throw new RuntimeException("[getElectionsConfig] not yet implemented");
    }

    // listelerin alınması
    public ListeElectorale[] getListesElectorales() {
        throw new RuntimeException("[getListesElectorales] not yet implemented");
    }

    // listelerin değiştirilmesi [voix, sieges, elimine]
    public void setListesElectorales(ListeElectorale[] listesElectorales) {
        throw new RuntimeException("[setListesElectorales] not yet implemented");
    }

    // -------------------- özel yöntemler

    // finally yönetimi
    private ElectionsException doFinally(int code, ResultSet rs, PreparedStatement ps, Connection connexion) {
        // kapanış ResultSet
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e1) {

            }
        }
        // kapatma [PreparedStatement]
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e2) {

            }
        }
        // bağlantıyı kapat
        if (connexion != null) {
            try {
                connexion.close();
            } catch (SQLException e3) {
                // bir [ElectionsException] döndürülür
                return new ElectionsException(code, e3);
            }
        }
        // istisna yok
        return null;
    }

    // yakalama yönetimi
    private ElectionsException doCatchException(int code1, int code2, Connection connexion, Throwable th) {
        // [ElectionsException] oluşturulur
        ElectionsException ex1 = new ElectionsException(code1, th);
        // işlem iptali
        try {
            if (connexion != null) {
                connexion.rollback();
            }
        } catch (SQLException e2) {
        }
        // istisna döndürülür
        return ex1;
    }
}
  • 24. satır: [@Cacheable] anotasyonu, [getElectionsConfig] yönteminin sonuçlarının bellekte saklanmasını ("cache") talep eden bir Spring anotasyonudur. [CONF] tablosunun içeriği hiçbir zaman değişmediği için bunu burada yapmak mümkündür. Bu anotasyonu [getListesElectorales] yöntemine eklemek mümkün olmazdı, çünkü [LISTES] tablosunun içeriği zamanla değişir;
  • [doCatchException] ve [doFinally] yöntemleri, [ElectionsException] türünde bir değer döndürür. [doFinally] yöntemi, kaynakların serbest bırakılması hatasız gerçekleştiyse bir null işaretçisi döndürür;

Yapılacak çalışma: 6.5.2. paragrafında incelenen [IntroJdbc02] sınıfından esinlenerek [ElectionDaoJdbc] sınıfını yazınız.


7.9. [Main] test sınıfı

  

[Main] sınıfı şu şekildedir:


package elections.dao.console;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import elections.dao.config.AppConfig;
import elections.dao.entities.ElectionsConfig;
import elections.dao.entities.ElectionsException;
import elections.dao.entities.ListeElectorale;
import elections.dao.service.IElectionsDao;

public class Main {

    // veri kaynağı
    private static IElectionsDao dao;

    public static void main(String[] args) {
        // Spring bağlamı oluşturulduktan sonra [DAO] katman referansı alınır
        try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class)) {
            // veri kaynağının alınması
            dao = ctx.getBean(IElectionsDao.class);
        } catch (Exception e) {
            System.out.println("Les erreurs suivantes se sont produites lors de l'initialisation du contexte Spring -------");
            for (String erreur : getErreursForThrowable(e)) {
                System.out.println(erreur);
            }
            // son
            return;
        }
        // BD'in okunması
        ElectionsConfig electionsConfig = null;
        ListeElectorale[] listes;
        try {
            // iki tablonun içeriği
            electionsConfig = dao.getElectionsConfig();
            listes = dao.getListesElectorales();
        } catch (ElectionsException e) {
            System.out.println("Les erreurs suivantes se sont produites lors de la lecture des tables ----------");
            for (String erreur : e.getErreurs()) {
                System.out.println(erreur);
            }
            // son
            return;
        }
        // her şey yolunda gitti - görüntüleme
        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);
        }
    }

    // özel yöntemler ------------------
    private static List<String> getErreursForThrowable(Throwable th) {
        // istisnanın hata mesajları listesi alınır
        Throwable cause = th;
        List<String> erreurs = new ArrayList<>();
        while (cause != null) {
            // mesajı yalnızca !=null ve boş değilse alıyoruz
            String message = cause.getMessage();
            if (message != null) {
                message = message.trim();
                if (message.length() != 0) {
                    erreurs.add(message);
                }
            }
            // sonraki neden
            cause = cause.getCause();
        }
        return erreurs;
    }

}
  • 21-31. satırlar: [DAO] katmanından bir referans alınır;
  • 21. satır: try_with_resources adlı bir sözdizimi kullanılır. Sözdizimi şöyledir:

try (T ressource=expression) {
            // kaynak kullanımı
...
}
  • (devam)
    • 1. satırdaki T türü, [java.lang.AutoCloseable] arayüzünü uygulamalıdır;
    • 1-4. satırlardan oluşan bloğun çıkışında, istisna olsun ya da olmasın, [java.lang.AutoCloseable] türündeki kaynak otomatik olarak serbest bırakılır. C# dilini bilenler, burada using (T kaynak=ifade) cümlesinin sözdizimsel ve işlevsel bir benzerini fark edeceklerdir;
  • 40-49. satırlar: [DAO] katmanının kullanılmasıyla [CONF] ve [LISTES] tablolarının içeriğinin alınması;
  • 41-47. satırlar: [electionsconfig] önbelleği test ediliyor. Bu önbellek iki yerde tanımlanmıştır:
    • [ElectionsDaoJdbc] sınıfında:

  @Cacheable("electionsConfig")
  public ElectionsConfig getElectionsConfig() {
  • (devamı)
    • [AppConfig] yapılandırma sınıfında:

@EnableCaching
public class AppConfig {
...
  @Bean
  public CacheManager cacheManager() {
    return new ConcurrentMapCacheManager("electionsConfig");
  }
}
  • 59. satır: Spring bağlamının kapatılması;
  • 62-67. satırlar: elde edilen bilgilerin görüntülenmesi;

[DAO] katmanı uygulandığında elde edilen sonuçlar şunlardır:

...
début requête 1 : 11:09:29:752
fin requête 1 et début requête 2: 11:09:30:132
fin requête 2 : 11:09:30:133
...
Nombre de sièges à pourvoir : 6
Seuil électoral :  0,05
Listes candidates----------------
{"id":1,"version":9,"nom":"A","voix":32000,"sieges":2,"elimine":false}
{"id":2,"version":13,"nom":"B","voix":25000,"sieges":2,"elimine":false}
{"id":3,"version":14,"nom":"C","voix":16000,"sieges":1,"elimine":false}
{"id":4,"version":13,"nom":"D","voix":12000,"sieges":1,"elimine":false}
{"id":5,"version":14,"nom":"E","voix":8000,"sieges":0,"elimine":false}
{"id":6,"version":13,"nom":"F","voix":4500,"sieges":0,"elimine":true}
{"id":7,"version":13,"nom":"G","voix":2500,"sieges":0,"elimine":true}
  • 2-4. satırlar: önbelleğin etkisini gösterir:
    • 1. istek 80 milisaniye sürer;
    • 2. sorgu 1 milisaniye sürer;

Veritabanı devre dışı bırakıldığında şu sonuçlar elde edilir:

1
2
3
4
5
Les erreurs suivantes se sont produites lors de la lecture des tables ----------
Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
Connection refused: connect

7.10. [ElectionsDaoJdbc] sınıfının JUnit testleri

  

[Test01] sınıfı, [JUnit] sınıfının bir sonraki test sınıfıdır:


package elections.dao.junit;

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 elections.dao.config.AppConfig;
import elections.dao.entities.ElectionsConfig;
import elections.dao.entities.ListeElectorale;
import elections.dao.service.IElectionsDao;


@SpringApplicationConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class Test01 {

    // [DAO] katmanı
    @Autowired
    private IElectionsDao electionsDao;

    @Before
    public void init() {
        // [LISTES] tablosu temizlenir
        // yarışan listeler
        ListeElectorale[] listes = electionsDao.getListesElectorales();
        // oy ve koltuk sayılarını 0'a sıfırlayıp false olarak siliniyor
        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] katmanı sayesinde bu verileri kalıcı hale getiriyoruz
        electionsDao.setListesElectorales(listes);
    }

    @Test
    public void testElections01() {
        ...
    }
}
  • 17. satır: [RunWith] açıklaması, [JUnit] (6. satır) açıklamasının bir parçasıdır ve [SpringJUnit4ClassRunner] sınıfı aracılığıyla Spring ile entegrasyonu sağlar;
  • 16. satır: [SpringApplicationConfiguration] anotasyonu, [Spring] anotasyonunun (8. satır) bir örneğidir ve JUnit test yapılandırma sınıflarını belirlemeye olanak tanır. Burada, projeyi yapılandırmak için kullanılan [AppConfig] sınıfı belirtilmektedir. Böylece, bu yapılandırma sınıfı tarafından tanımlanan tüm Spring nesnelerine erişilebilir hale gelir. Bu sayede, 21-22. satırlarda test edilecek olan [DAO] katmanına bir referans enjekte edilebilir;
  • 25. satır: [Before] anotasyonu, her testten önce yürütülmesi gereken bir yöntemi belirtir;
  • 26-41. satırlar: [init] yöntemi, [LISTES] tablosundaki listelerin oy ve koltuk sayılarını sıfıra, [elimine] boole değerini ise [false]'e ayarlar;

Tek test yöntemi şöyledir:


@Test
    public void testElections01() {
        System.out.println("testElections01-------------------------------------");
        // seçim yapılandırmasının alınması
        ElectionsConfig electionsConfig = electionsDao.getElectionsConfig();
        int nbSiegesAPourvoir = electionsConfig.getNbSiegesAPourvoir();
        double seuilElectoral = electionsConfig.getSeuilElectoral();
        Assert.assertEquals(6, nbSiegesAPourvoir);
        Assert.assertEquals(0.05, seuilElectoral, 1E-6);

        // yarışan listeler
        ListeElectorale[] listes = electionsDao.getListesElectorales();
        // okunan değerlerin görüntülenmesi
        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]);
        }

        // listelere oy ve sandalye tahsis ediliyor
        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;
        }

        // bu veriler [dao] katmanı aracılığıyla kalıcı hale getirilir
        electionsDao.setListesElectorales(listes);

        // veriler yeniden okunur
        ListeElectorale[] listesElectorales2 = electionsDao.getListesElectorales();
        // okunan veriler kontrol edilir
        Assert.assertEquals(7, listesElectorales2.length);
        voix = 0;
        sièges = 0;
        elimine = false;
        for (ListeElectorale liste : listesElectorales2) {
            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]);
        }
    }
  • 5-9. satırlar: [CONF] tablosunun içeriğinin alınabildiğinden emin olunur;
  • 11-19. satırlar: [LISTES] tablosunun içeriği görüntülenir. Burada test yapılmaz, sadece görsel kontrol yapılır;
  • 21-35. satırlar: Veritabanındaki [LISTES] tablosunu, listelere [voix, sieges, elimine] alanları için değerler atayarak değiştiriyoruz;
  • satır 37-51: [LISTES] tablosu yeniden okunur ve elde edilen sonucun girilen değerlerle tam olarak eşleştiği kontrol edilir;
  • satır 52-55: görsel kontrol;

[DAO] katmanı uygulandığında elde edilen konsol sonuçları şunlardır:

mars 11, 2015 4:50:00 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames
INFOS: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
mars 11, 2015 4:50:00 PM org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
INFOS: Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
mars 11, 2015 4:50:00 PM org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
INFOS: Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
mars 11, 2015 4:50:00 PM org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
INFOS: Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
mars 11, 2015 4:50:00 PM org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners
INFOS: Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@483bf400, org.springframework.test.context.support.DirtiesContextTestExecutionListener@21a06946]

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.2.2.RELEASE)

[2015-03-11 16:50:01.272] - 11696 INFOS [main] --- org.eclipse.jdt.internal.junit.runner.RemoteTestRunner: Starting RemoteTestRunner on Gportpers3 with PID 11696 (started by ST in D:\data\istia-1415\eclipse\intro-jdbc\elections-jdbc-01)
[2015-03-11 16:50:01.317] - 11696 INFOS [main] --- org.springframework.context.annotation.AnnotationConfigApplicationContext: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@74ad1f1f: startup date [Wed Mar 11 16:50:01 CET 2015]; root of context hierarchy
mars 11, 2015 4:50:01 PM org.eclipse.jdt.internal.junit.runner.RemoteTestRunner logStarted
INFOS: Started RemoteTestRunner in 0.775 seconds (JVM running for 1.433)
testElections01-------------------------------------
Nombre de sièges à pourvoir : 6
Seuil électoral : 0.05
Listes en compétition ---------------------
{"id":1,"version":21,"nom":"A","voix":0,"sieges":0,"elimine":false}
{"id":2,"version":22,"nom":"B","voix":0,"sieges":0,"elimine":false}
{"id":3,"version":21,"nom":"C","voix":0,"sieges":0,"elimine":false}
{"id":4,"version":13,"nom":"D","voix":0,"sieges":0,"elimine":false}
{"id":5,"version":17,"nom":"E","voix":0,"sieges":0,"elimine":false}
{"id":6,"version":18,"nom":"F","voix":0,"sieges":0,"elimine":false}
{"id":7,"version":19,"nom":"G","voix":0,"sieges":0,"elimine":false}
Listes en compétition ---------------------
{"id":1,"version":21,"nom":"A","voix":0,"sieges":0,"elimine":false}
{"id":2,"version":22,"nom":"B","voix":10,"sieges":1,"elimine":true}
{"id":3,"version":21,"nom":"C","voix":20,"sieges":2,"elimine":false}
{"id":4,"version":13,"nom":"D","voix":30,"sieges":3,"elimine":true}
{"id":5,"version":17,"nom":"E","voix":40,"sieges":4,"elimine":false}
{"id":6,"version":18,"nom":"F","voix":50,"sieges":5,"elimine":true}
{"id":7,"version":19,"nom":"G","voix":60,"sieges":6,"elimine":false}
  • satır 1-23: Spring Test günlükleri;
  • satır 25-26: [CONF] tablosunun içeriği;
  • satır 27-34: [LISTES] tablosunun başlangıç içeriği;
  • satır 35-42: [voix, sieges, elimine] alanlarına değerler atandıktan sonra [LISTES] tablosunun içeriği;

Ayrıca, JUnit testi başarılı oldu:

 

7.11. [dao] katmanından [with-dependencies] arşivinin oluşturulması

Nihai projenin mimarisi şu şekildedir:

Projenin Maven yapılandırmasını hatırlayalım:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-dao-jdbc-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.7.RELEASE</version>
    </parent>

    <dependencies>
        <!-- MySQL -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <!-- Tomcat Jdbc -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jdbc</artifactId>
        </dependency>
        <!-- jSON kütüphanesi -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Testi -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot Günlüğü -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
    </dependencies>

    <!-- eklentiler -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>config.AppConfig</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
            <!-- proje artefaktını yerel Maven deposuna yüklemek için -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
            </plugin>
        </plugins>
    </build>
</project>
  

Yukarıdaki tüm jar dosyalarındaki sınıfları ve [DAO] katman projesindeki sınıfları içeren tek bir jar dosyası oluşturacağız. Bu, [pom.xml] dosyasında yapılacak bir değişiklikle gerçekleştirilir:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>istia.st.elections</groupId>
    <artifactId>elections-jdbc-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.2.RELEASE</version>
    </parent>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        ...
    </dependencies>

    <!-- eklentiler -->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>console.Main</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 25-37. satırlar: jar dosyasını oluşturmak için bir Maven eklentisi yapılandırır;
  • 15. satır: derleme için kullanılacak Java sürümünü belirtir;

Bu değişiklik yapıldıktan sonra, jar dosyası şu şekilde oluşturulabilir: [1-10]:

  • [5]'te, [6] düğmesini kullanarak proje klasörünü seçin;
  • [7]'te, çalıştırma yapılandırmasına bir ad verin;
  • [8] dosyasında, çalıştırılacak Maven hedeflerinin listesini girin:
    • [clean]: Oluşturulan jar dosyasının yerleştirileceği projenin [target] klasörünü boşaltır;
    • [compile]: projeyi derler;
    • [assembly:single]: projenin ve bağımlılıklarının tüm sınıflarını içeren tek bir jar dosyası oluşturur;
  • [9-10] komutunda, JDK (Java Development Kit) dosyasının bulunduğundan emin olun; JRE (Java Runtime Environment) dosyası olmamalıdır. Aradaki fark, JDK'te derleyici bulunurken JRE'te bulunmamasıdır. JDK sürümüne sahip değilseniz, [10] sürümüne [11] sürümünü eklemeniz gerekir. Bunun için 3.1. paragrafında açıklanan prosedürü izleyin;
  • [17]'te, yürütme yapılandırmasını gerçekleştirin;
  • [13]'e, oluşturulan arşivi;

Bu arşivi bir açma programı ile açabilirsiniz:

 

7.12. [DAO] katman arşivini test etme

Standart bir Eclipse projesi (Maven değil) [1] oluşturalım:

[elections-dao-jdbc-01] projesindeki [dao.console] paketini [elections-dao-jdbc-02] ve [2] projelerine kopyalayıp yapıştıralım. [Main] sınıfı, kendi [Classpath]'inde bulunmayan sınıflara referans verdiği için birçok hata ortaya çıkıyor. Bunu değiştireceğiz.

Öncelikle yeni projede [2-8] adlı bir klasör oluşturuyoruz:

[9]'te, önceki adımda oluşturulan arşivi [lib] klasörüne yerleştiriyoruz ve ardından projenin Build Path'ini değiştiriyoruz:

  • olarak değiştiriyoruz; daha önce oluşturulan [DAO] katman arşivini içe aktardık;
  • [19] dosyasında, projede artık hata bulunmamaktadır;

Böylece [Main] sınıfını çalıştırabiliriz. Daha önce elde edilen sonuçların aynısı elde edilir.