Skip to content

18. اپلیکیشن وب MVC در معماری سه‌لایه – مثال ۴، پست‌گرس

18.1. پایگاه داده Postgres

در این نسخه، فهرست افراد را در یک جدول پایگاه داده Postgres به نام 8.x [http://www.postgres.org] ذخیره خواهیم کرد. اسکرین‌شات‌های زیر از کلاینت EMS PostgreSQL Manager Lite [http://www.sqlmanager.net/fr/products/postgresql/manager]، یک کلاینت مدیریتی رایگان برای SGBD Postgres، گرفته شده‌اند.

این پایگاه داده [dbpersonnes] نام دارد. این پایگاه داده شامل جدولی به نام [PERSONNES] است:

Image

جدول [PERSONNES] شامل فهرست افرادی است که توسط وب‌اپلیکیشن مدیریت می‌شوند. این جدول با استفاده از دستورات زیر SQL ایجاد شده است:

CREATE TABLE "public"."PERSONNES" (
  "ID" INTEGER NOT NULL, 
  "VERSION" INTEGER NOT NULL, 
  "NOM" VARCHAR(30) NOT NULL, 
  "PRENOM" VARCHAR(30) NOT NULL, 
  "DATENAISSANCE" DATE NOT NULL, 
  "MARIE" BOOLEAN NOT NULL, 
  "NBENFANTS" INTEGER NOT NULL, 
  CONSTRAINT "PERSONNES_pkey" PRIMARY KEY("ID"), 
  CONSTRAINT "PERSONNES_chk_NBENFANTS" CHECK ("NBENFANTS" >= 0), 
  CONSTRAINT "PERSONNES_chk_NOM" CHECK (("NOM")::text <> ''::text), 
  CONSTRAINT "PERSONNES_chk_PRENOM" CHECK (("PRENOM")::text <> ''::text)
) WITH OIDS;

ما در مورد این جدول توضیح بیشتری نمی‌دهیم، زیرا مشابه جدول نوع Firebird به نام [PERSONNES] است که قبلاً در مورد آن بحث شد. با این حال، باید توجه داشت که نام‌های ستون و جدول در گیومه قرار دارند. علاوه بر این، این نام‌ها به حروف بزرگ و کوچک حساس هستند. ممکن است این رفتار Postgres 8.x قابل پیکربندی باشد. من بیشتر در این مورد تحقیق نکرده‌ام.

جدول [PERSONNES] ممکن است محتوای زیر را داشته باشد:

Image

علاوه بر جدول [PERSONNES]، پایگاه داده [dbpersonnes] حاوی ابجکتی به نام [SEQ_ID] است که به آن «ترتیب» (sequence) گفته می‌شود. این تولیدکننده اعداد صحیح متوالی را تولید می‌کند که از آن‌ها برای تخصیص مقدار به کلید اصلی [ID] از کلاس [PERSONNES] استفاده خواهیم کرد. بیایید یک مثال بزنیم تا نحوه کار آن را نشان دهیم:

می‌توانیم ببینیم که مقدار [Next value] در دنباله [SEQ_ID] تغییر کرده است (برای تازه‌سازی روی آن دوبار کلیک کنید + F5):

 

سفارش SQL

SELECT nextval('"SEQ_ID"')

بنابراین مقدار زیر را برای دنباله [SEQ_ID] برمی‌گرداند. ما از این مقدار در فایل [personnes-postgres.xml] استفاده خواهیم کرد، که سفارش‌های SQL صادر شده بر روی SGBD را گردآوری می‌کند.

18.2. پروژهٔ Eclipse برای لایه‌های [dao] و [service]

برای توسعه لایه‌های [dao] و [service] اپلیکیشن خود با استفاده از پایگاه داده Postgres 8.x، از پروژه Eclipse زیر [spring-mvc-39] استفاده خواهیم کرد:

Image

این پروژه یک پروژه ساده جاوا است، نه یک پروژه وب تامکت.


پوشه [src]


این پوشه حاوی کد منبع لایه‌های [dao] و [service] است:

Image

هر فایلی که در نامش «[postgres]» باشد ممکن است نسبت به نسخه Firebird تغییر کرده باشد یا نکرده باشد. در ادامه، فایل‌های تغییرشده را توضیح می‌دهیم.


پوشه [database]


این پوشه حاوی اسکریپت ایجاد پایگاه داده Postgres افراد است:

Image

-- EMS PostgreSQL مدیر لایت ۳.۱.۰.۱
-- ---------------------------------------
-- میزبا    ن : localhost
-- پایگاه داده: dbpersonnes



--
-- تعریف برای تابع plpgsql_call_handler (OID = 17230): 
--
...
--
--ساختار جدول PERSONNES (OID = 17254): 
--
CREATE TABLE "PERSONNES" (
    "ID" integer NOT NULL,
    "VERSION" integer NOT NULL,
    "NOM" varchar(30) NOT NULL,
    "PRENOM" varchar(30) NOT NULL,
    "DATENAISSANCE" date NOT NULL,
    "MARIE" boolean NOT NULL,
    "NBENFANTS" integer NOT NULL,
    CONSTRAINT "PERSONNES_chk_NBENFANTS" CHECK (("NBENFANTS" >= 0)),
    CONSTRAINT "PERSONNES_chk_NOM" CHECK ((("NOM")::text <> ''::text)),
    CONSTRAINT "PERSONNES_chk_PRENOM" CHECK ((("PRENOM")::text <> ''::text))
);
--
-- تعریف برای توالی SEQ_ID (OID = 17261): 
--
CREATE SEQUENCE "SEQ_ID"
    INCREMENT BY 1
    NO MAXVALUE
    NO MINVALUE
    CACHE 1;
--
--داده‌ها برای بلوب‌ها (OID = 17254) (LIMIT 0,3)
--
INSERT INTO "PERSONNES" ("ID", "VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES (1, 1, 'Major', 'Joachim', '1984-11-13', true, 2);
INSERT INTO "PERSONNES" ("ID", "VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES (2, 1, 'Humbort', 'Mélanie', '1985-01-12', false, 1);
INSERT INTO "PERSONNES" ("ID", "VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES (3, 1, 'Lemarchand', 'Charles', '1986-01-01', false, 0);
--
-- تعریف برای نمایه PERSONNES_pkey (OID = 17256): 
--
ALTER TABLE ONLY "PERSONNES"
    ADD CONSTRAINT "PERSONNES_pkey" PRIMARY KEY ("ID");
--
--داده‌ها برای توالی عمومی "SEQ_ID" (OID = 17261)
--
SELECT pg_catalog.setval('"SEQ_ID"', 37, true);
--
-- توضیحات
--
COMMENT ON SCHEMA public IS 'Standard public schema';

پوشه [lib]


این پوشه شامل آرشیوهای مورد نیاز برنامه است:

توجه داشته باشید که درایور JDBC Postgres 8.x با نام SGBD نیز گنجانده شده است. تمام این آرشیوها بخشی از پروژه Eclipse با نام Classpath را تشکیل می‌دهند.

18.3. لایه [dao]

لایه [dao] به شرح زیر است:

Image

ما تنها تغییرات را نسبت به نسخه [Firebird] برجسته می‌کنیم.

فایل نگاشت [personne-postgres.xml] به شرح زیر است:


<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap
    PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-2.dtd">

<!-- لطفاً توجه داشته باشید – PostgreSQL 8 نیاز دارد که نام ستون‌ها دقیقاً نوشته شوند
     et des tables ainsi que des guillemets autour de ces noms -->

    <sqlMap>
        <!-- نام مستعار کلاس [Personne] -->
        <typeAlias alias="Personne.classe" 
            type="istia.st.mvc.personnes.entites.Personne"/>
        <!-- جدول نگاشت [PERSONNES] - شیء [Personne] -->
        <resultMap id="Personne.map" 
            class="istia.st.mvc.personnes.entites.Personne">
            <result property="id" column="ID" />
            <result property="version" column="VERSION" />
            <result property="nom" column="NOM"/>
            <result property="prenom" column="PRENOM"/>
            <result property="dateNaissance" column="DATENAISSANCE"/>
            <result property="marie" column="MARIE"/>
            <result property="nbEnfants" column="NBENFANTS"/>
        </resultMap>
        <!-- فهرست همه افراد -->
        <select id="Personne.getAll" resultMap="Personne.map" > select "ID", 
            "VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM 
            "PERSONNES"</select>
        <!--بازیابی یک شخص خاص -->
        <select id="Personne.getOne" resultMap="Personne.map" >select "ID", 
            "VERSION", "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS" FROM 
            "PERSONNES" WHERE "ID"=#مقدار#</select>
        <!-- افزودن یک شخص -->
        <insert id="Personne.insertOne" parameterClass="Personne.classe"> 
            <selectKey keyProperty="id">
                SELECT nextval('"SEQ_ID"') as value
            </selectKey> 
            insert into "PERSONNES"("ID", "VERSION", 
            "NOM", "PRENOM", "DATENAISSANCE", "MARIE", "NBENFANTS") VALUES(#شناسه#, 
             #نسخه#, #نام خانوادگی#, #نام#, #dateNaissance#, #نام خانوادگی پس از ازدواج#, #nbEnfants#) 
            </insert>
        <!-- به‌روزرسانی یک شخص -->
        <update id="Personne.updateOne" parameterClass="Personne.classe"> update 
            "PERSONNES" set "VERSION"=#نسخه#+1, "NOM"=#نام خانوادگی#, "PRENOM"=#نام#, 
            "DATENAISSANCE"=#dateNaissance#, "MARIE"=#ماري#, "NBENFANTS"=#nbEnfants# 
            WHERE "ID"=#id# و "VERSION"=#version#</update>
        <!-- حذف یک شخص -->
        <delete id="Personne.deleteOne" parameterClass="int"> delete FROM 
            "PERSONNES" WHERE "ID"=#value# </delete>
    </sqlMap>

محتوا همانند [personnes-firebird.xml] است، با تفاوت‌های جزئی زیر:

  • نام ستون‌ها و جدول‌ها در گیومه قرار دارند و نسبت به حروف بزرگ و کوچک حساس هستند
  • ترتیب SQL " Personne.insertOne " در خطوط 34–41 تغییر کرده است. روش تولید کلید اصلی با Postgres با روشی که در Firebird استفاده می‌شود متفاوت است:
    • خط ۳۶: توالی SQL [SELECT nextval('"SEQ_ID"')] کلید اصلی را فراهم می‌کند. سینتکس [as value] الزامی است. [value] نمایانگر کلید حاصل است. این مقدار به فیلد شیء [Personne] که توسط ویژگی [keyProperty] (خط ۳۵) مشخص شده است، اختصاص داده می‌شود؛ در این مورد، فیلد [id].
    • دستورهای SQL درون تگ <insert> به ترتیبی که با آن‌ها برخورد می‌شود اجرا می‌گردند. بنابراین، SELECT قبل از INSERT اجرا می‌شود. در زمان عملیات درج، فیلد [id] از شیء [Personne] بنابراین توسط دستور SQL SELECT به‌روزرسانی شده خواهد بود.
    • خطوط ۳۸–۴۰: درج شیء [Personne]

کلاس پیاده‌سازی [DaoImplCommon] از لایه [dao] همان است که در نسخه [Firebird] بررسی شده است.

پیکربندی لایه [dao] برای SGBD و [Postgres] تطبیق داده شده است. در نتیجه، فایل پیکربندی [spring-config-test-dao-postgres.xml] به شرح زیر است:


<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <!-- منبع داده DBCP -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName">
            <value>org.postgresql.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:postgresql:dbpersonnes</value>
        </property>
        <property name="username">
            <value>postgres</value>
        </property>
        <property name="password">
            <value>postgres</value>
        </property>
    </bean>
    <!-- SqlMapCllient -->
    <bean id="sqlMapClient" 
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="configLocation">
            <value>classpath:sql-map-config-postgres.xml</value>
        </property>
    </bean>
    <!-- دسترسی کلاس‌ها برای لایه [dao] -->
    <bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
        <property name="sqlMapClient">
            <ref local="sqlMapClient"/>
        </property>
    </bean>
</beans>
  • خطوط ۵–۱۹: بیان [dataSource] اکنون به پایگاه داده [Postgres] [dbpersonnes] اشاره می‌کند که مدیر آن [postgres] با رمز عبور [postgres] است. خواننده باید این پیکربندی را برای مطابقت با محیط خود تغییر دهد.
  • خط ۳۱: کلاس [DaoImplCommon] کلاس پیاده‌سازی برای لایه [dao] است

پس از اعمال این تغییرات، می‌توانیم به مرحلهٔ تست برویم.

18.4. آزمایش‌ها برای لایه‌های [dao] و [service]

تست‌های لایه‌های [dao] و [service] مشابه نسخه [Firebird] هستند. بیایید نمونه Postgres با شناسه SGBD را اجرا کرده و سپس تست‌های Eclipse را اجرا کنیم. نتایج حاصل به شرح زیر است:

می‌توانیم ببینیم که تست‌ها با پیاده‌سازی [DaoImplCommon] با موفقیت پاس شده‌اند. ما نیازی به مشتق‌سازی این کلاس نخواهیم داشت، همانطور که در مورد SGBD و [Firebird] ضروری بود.

18.5. آزمون اپلیکیشن [web]

برای تست اپلیکیشن وب با SGBD و [Postgres]، ما یک پروژه Eclipse به نام [mvc-personnes-04B] را به روشی مشابه با روشی که برای ساخت پروژه [mvc-personnes-03B] با پایگاه داده Firebird استفاده شد، ایجاد می‌کنیم (به بخش 17.7 مراجعه کنید). با این حال، ما نیازی به بازسازی آرشیوهای [personnes-dao.jar] و [personnes-service.jar] نداریم. این به این دلیل است که ما هیچ کلاسی را در ارتباط با پروژه [mvc-personnes-03B] تغییر نداده‌ایم. صرفاً آرشیو [personnes-dao.jar] حاوی کلاس [DaoImplFirebird] است که اکنون بلااستفاده شده است.

Image

ما در حال استقرار پروژه وب [mvc-personnes-04B] در Tomcat هستیم:

ما اکنون برای تست آماده‌ایم . محتویات جدول [PERSONNES] به شرح زیر است:

Image

تام‌کت در حال اجرا است. با استفاده از یک مرورگر وب، به آدرس [http://localhost:8080/mvc-personnes-04B] دسترسی پیدا می‌کنیم:

Image

ما اضافه می‌کنیم یک فرد جدید را از طریق لینک [Ajout] اضافه می‌کنیم:

ما افزودن را در پایگاه داده بررسی می‌کنیم:

Image

از خواننده دعوت می‌شود تا آزمایش‌های بیشتری را انجام دهد: [modification, suppression].