'Presentation Layer'에 해당되는 글 1건

  1. 2007/08/03 iamyhs Flex(Cairngorm) + Spring + iBATIS 연동
Flex(Cairngorm) + Spring + iBATIS 연동

1)전체 아키텍처

    3-Tier 구조 : Presentation(혹은 UI) Layer,Business Layer,Persistence Layer 로 구성

    1.1 Presentation Layer : Flex
    1.2 Business Layer : Spring(부분)
    1.3 Persistence Layer : iBATIS

    Flex : adobe 사의 enterprise용 presentation tier 솔루션
    Cairngorm : Flex framework
    Spring : layered Java/J2EE application framework
    iBATIS : data mapper framework


2)환경 설정

    2.1 J2EE 설정 파일 : web.xml
    2.2 Flex 설정 파일 : remoting-config.xml, services-config.xml
    2.3 Spring 설정 파일 : applicationContext.xml
    2.4 iBATIS 설정 파일 : SqlMapConfig.xml 과 sqlmap.xml 파일들


    2.1 J2EE 설정 파일 web.xml 수정 사항
    //아래처럼 context-param, listener 태그를 추가한다.
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    2.2.1 Flex 설정 파일 remoting-config.xml 수정 사항
    //아래처럼 <factory>spring</factory> 태그를 추가하고, <source>contactService</source> 처럼 패키지 이름이 아니라,
    서비스 이름을 적어준다(applicationContext.xml 파일에 해당 서비스에 맞는 자바빈즈 설정을 해준다)

    <destination id="contactService">
        <properties>
            <factory>spring</factory>
            <source>contactService</source>
        </properties>
    </destination>
    //서비스 추가시 위 형식과 동일하게 계속 추가해준다.

    2.2.2 Flex 설정 파일 services-config.xml 수정 사항
    //아래처럼 factories 태그를 추가한다.
    //더불어, 관련 class 파일 두개를 패키지 경로에 맞게(flex.samples.factories) 넣어준다.
    // SpringFactory.class, SpringFactory$SpringFactoryInstance.class 이다.
    <factories>
        <factory id="spring" class="flex.samples.factories.SpringFactory"/>
    </factories>
        

    2.3 Spring 설정 파일 applicationContext.xml 수정 사항
    applicationContext.xml 파일을 참고한다,그 안의 내용을 요약하면,


    2.3.1 Application 설정
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location"><value>classpath:../application.properties</value></property>
    </bean>

    application.properties 는 jdbc 실제 정보를 입력한다.
    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost/ibatis?user=root&password=mysql
    jdbc.username=root
    jdbc.password=mysql

    
    2.3.2 DB Connection 설정    
    dataSource와 transactionManager 설정을 한다.
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
            <property name="url"><value>${jdbc.url}</value></property>
            <property name="username"><value>${jdbc.username}</value></property>
        <property name="password"><value>${jdbc.password}</value></property>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"><ref local="dataSource"/></property>
    </bean>
        

    2.3.3 iBATIS 설정
    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">       
        <property name="configLocation" value="classpath:../SqlMapConfig.xml" />
    </bean>


    2.3.4 DAO 설정
    Dao 인터페이스의 구현클래스 지정한다.
    <bean id="contactDao" class="com.appfoundation.flexibatis.dao.ibatis.ContactDaoImpl">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>

    <bean id="mycontactDao" class="com.appfoundation.flexibatis.dao.ibatis.MyContactDaoImpl">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>
    
    클래스가 추가되면 위와 같은 형식으로 추가한다.


    2.3.5 Flex 서비스 설정
    Service 인터페이스의 구현클래스 지정한다.
    <bean id="contactService" class="com.appfoundation.flexibatis.services.ContactServiceImpl">
        <property name="contactDao"><ref bean="contactDao"/></property>        
    </bean>

    <bean id="myContactService" class="com.appfoundation.flexibatis.services.MyContactServiceImpl">
        <property name="mycontactDao"><ref bean="mycontactDao"/></property>        
    </bean>    


    2.3.6 sqlmapconfig.xml    
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
        "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

    <sqlMapConfig>
      <settings useStatementNamespaces="true"/>
      <sqlMap resource="../sqlmaps/Contact.xml" />
      <sqlMap resource="../sqlmaps/MyContact.xml"/>
    </sqlMapConfig>


    2.3.7 Contact.xml
    
       <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE sqlMap
        PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
        "http://ibatis.apache.org/dtd/sql-map-2.dtd">

    <sqlMap namespace="Contact">
        <typeAlias alias="contact" type="com.appfoundation.flexibatis.domain.Contact"/>

        <resultMap id="contactResult" class="contact">
        <result property="objectIdentifier"    column="objectidentifier"/>
        <result property="name"                column="name" />
        <result property="businessPhone"      column="business_phone"/>
        <result property="mobilePhone"      column="mobile_phone" />
        <result property="homePhone"          column="home_phone"/>
        <result property="addressLine1"     column="address_line1" />
        <result property="addressLine2"     column="address_line2"/>
        <result property="addressLine3"     column="address_line3"/>
        <result property="city"              column="city"/>
        <result property="state"              column="state"/>     
        <result property="zip"              column="zip"/>
        <result property="email"          column="email"/>
        <result property="company"          column="company"/>
        <result property="title"          column="title"/>
        <result property="responsibility"    column="responsibility"/>
        <result property="image"      column="image"/>
        <result property="department"              column="department"/>
        <result property="phoneExtension"          column="phone_extension"/>
        <result property="fax"     column="fax"/>
        <result property="status"              column="status"/>
        <result property="refferedBy"              column="reffered_by"/>
        <result property="country"          column="country"/>
        <result property="webSite"          column="website"/>
        </resultMap>

        <sql id="contacts_table" >
        contacts
        </sql>

        <select id="getContacts" resultMap="contactResult">
        select *
          from <include refid="contacts_table" />
        order by name
        </select>

        <select id="getContact" resultMap="contactResult">
        select *
          from <include refid="contacts_table" />
         where objectidentifier = #value#
        </select>

        <insert id="insertContact" parameterClass="contact" >
        <selectKey resultClass="int" keyProperty="objectIdentifier">
            SELECT max(objectidentifier) from contacts
        </selectKey>
        insert into <include refid="contacts_table"/>(objectidentifier, name, business_phone,mobile_phone, home_phone, address_line1, address_line2, address_line3,city, state, zip, email, company, title, responsibility, image,department, phone_extension, fax, status, reffered_by, country, website)
                  values(#objectIdentifier#+1,
                     #name#,
                     #businessPhone#,
                     #mobilePhone#,
                     #homePhone#,
                     #addressLine1#,
                     #addressLine2#,
                     #addressLine2#,
                     #city#,
                     #state#,
                     #zip#,
                     #email#,
                     #company#,
                     #title#,
                     #responsibility#,
                     #image#,
                     #department#,
                     #phoneExtension#,
                     #fax#,
                     #status#,
                     #refferedBy#,
                     #country#,
                     #webSite#)
        </insert>

        <update id="updateContact" parameterClass="contact">
        update <include refid="contacts_table"/>
           set name             = #name#,
               business_phone     = #businessPhone#,
                   mobile_phone     = #mobilePhone#,
                   home_phone         = #homePhone#,
                   address_line1     = #addressLine1#,
                   address_line2    = #addressLine2#,
                   address_line3     = #addressLine3#,
                   city             = #city#,
                   state             = #state#,
                   zip                 = #zip#,
                   email             = #email#,
                   company             = #company#,
                   title             = #title#,
                   responsibility     = #responsibility#,
                   image             = #image#,
                   department         = #department#,
                   phone_extension     = #phoneExtension#,
                   fax                 = #fax#,
                   status             = #status#,
                   reffered_by         = #refferedBy#,
                   country             = #country#,
                   website             = #webSite#
        where objectidentifier     = #objectIdentifier#
        </update>

        <delete id="deleteContact" parameterClass="int">
        delete from <include refid="contacts_table"/> where objectidentifier = #value#
        </delete>
    </sqlMap>


    2.3.8 실제 자바 구현 클래스
    
    총 세 부분으로 나뉜다
    domain - flex에서의 vo 클래스라고 생각하면 된다.
    dao - dao 인터페이스와, 구현 클래스
    service - service 인터페이스와,구현 클래스
    


    Contact 클래스.
    --------------------------------------------------
    package com.appfoundation.flexibatis.domain;

    import java.io.Serializable;

    public class Contact implements Serializable {
        int objectIdentifier;
        String name;
        String businessPhone;
        String mobilePhone;
        String homePhone;
        String addressLine1;
        String addressLine2;
        String addressLine3;
        String city;
        String state;
        String zip;
        String email;
        String company;
        String title;
        String responsibility;
        String image;
        String department;
        String phoneExtension;
        String fax;
        String status;
        String refferedBy;
        String country;
        String webSite;

        ....
        셋터,겟터
//이 글 아래 참고 사이트에 가면 해당 클래스 다운받을수 있다.
    --------------------------------------------------    



    ContactDao 클래스.
    --------------------------------------------------
    package com.appfoundation.flexibatis.dao;

    import com.appfoundation.flexibatis.domain.Contact;
    import java.util.List;

    public interface ContactDao {
        
        public List getContacts();
        
        public int updateContact(Contact contact);

        public int deleteContact(int contactKey);

        public int insertContact(Contact contact);
    }
    --------------------------------------------------



    ContactDaoImpl 클래스.
    --------------------------------------------------
    package com.appfoundation.flexibatis.dao.ibatis;

    import java.util.List;

    import org.springframework.orm.ibatis.SqlMapClientTemplate;
    import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
    import org.springframework.dao.DataAccessException;

    import com.appfoundation.flexibatis.domain.Contact;
    import com.appfoundation.flexibatis.dao.ContactDao;

    public class ContactDaoImpl extends SqlMapClientDaoSupport implements ContactDao {

    //이 글 아래 주의 사항 꼭 참고!
    

        public List getContacts() throws DataAccessException {
        return getSqlMapClientTemplate().queryForList("Contact.getContacts");            
        }

        public int insertContact(Contact contact) throws DataAccessException {      
        return ((Integer)getSqlMapClientTemplate().insert("Contact.insertContact", contact)).intValue();
        }
            
        public int updateContact(Contact contact) throws DataAccessException {
        return ((Integer)getSqlMapClientTemplate().update("Contact.updateContact", contact)).intValue();
        }
            
        public int deleteContact(int contactKey) throws DataAccessException {
        return ((Integer)getSqlMapClientTemplate().delete("Contact.deleteContact", contactKey)).intValue();
        }

    }
    --------------------------------------------------



    ContactService 클래스.
    --------------------------------------------------
    package com.appfoundation.flexibatis.services;

    import com.appfoundation.flexibatis.domain.Contact;
    import java.util.List;

    public interface ContactService {
        
        public abstract List getContacts() throws Exception;
        
        public abstract int insertContact(Contact contact) throws Exception;

        public abstract int updateContact(Contact contact) throws Exception;
        
        public abstract int deleteContact(int contactKey) throws Exception;
    }
    --------------------------------------------------


    ContactServiceImpl 클래스.
    --------------------------------------------------
    package com.appfoundation.flexibatis.services;

    import com.appfoundation.flexibatis.domain.*;
    import com.appfoundation.flexibatis.dao.ContactDao;
    import java.util.List;
    import java.io.Serializable;

    public class ContactServiceImpl implements Serializable, ContactService {
        
        // injected by Spring
        ContactDao contactDao;
        
        public ContactDao getContactDao() {
            return contactDao;
        }
        
        public void setContactDao(ContactDao contactDao) {
            this.contactDao = contactDao;
        }
        
        public List getContacts() throws Exception {
            return contactDao.getContacts();        
        }
        
        public int insertContact(Contact contact) throws Exception{    
            return ((Integer)contactDao.insertContact(contact));
        }
    
        public int deleteContact(int contactKey) throws Exception {
           return ((Integer)contactDao.deleteContact(contactKey));
        }
    
        public int updateContact(Contact contact) throws Exception {
           return ((Integer)contactDao.updateContact(contact));
        }
        
    }
    --------------------------------------------------


    2.3.9 MySQL 테이블 구조
    # Host: localhost    Database: ibatis
    # ------------------------------------------------------
    # Server version 5.0.27-community-nt

    #
    # Table structure for table contacts
    #

    DROP TABLE IF EXISTS `contacts`;
    CREATE TABLE `contacts` (
      `objectidentifier` int(11) NOT NULL,
      `name` varchar(120) default NULL,
      `business_phone` varchar(16) default NULL,
      `mobile_phone` varchar(16) default NULL,
      `home_phone` varchar(16) default NULL,
      `address_line1` varchar(120) default NULL,
      `address_line2` varchar(120) default NULL,
      `city` varchar(45) default NULL,
      `state` varchar(25) default NULL,
      `zip` varchar(10) default NULL,
      `email` varchar(120) default NULL,
      `company` varchar(120) default NULL,
      `title` varchar(45) default NULL,
      `responsibility` varchar(45) default NULL,
      `image` varchar(45) default NULL,
      `department` varchar(45) default NULL,
      `phone_extension` varchar(16) default NULL,
      `fax` varchar(16) default NULL,
      `status` varchar(45) default NULL,
      `reffered_by` varchar(45) default NULL,
      `address_line3` varchar(120) default NULL,
      `country` varchar(60) default NULL,
      `website` varchar(120) default NULL,
      PRIMARY KEY  (`objectidentifier`)
    ) ENGINE=InnoDB DEFAULT CHARSET=euckr;

    #
    # Dumping data for table contacts
    #

    INSERT INTO `contacts` VALUES (0,'기본값',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'def@default.com',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
    INSERT INTO `contacts` VALUES (1,'양현석',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'iamyh@hitel.net',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
    INSERT INTO `contacts` VALUES (2,'jjong jj',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'jjong@offton.co.kr',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
    INSERT INTO `contacts` VALUES (3,'기본값',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'def@default.com',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
    INSERT INTO `contacts` VALUES (4,'test',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'test@hitel.net',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

    



        

3)테스트 환경

    Tomcat 5.0
    Flex 3.0b,Cairngorm 2.2
    Spring 2.0.6
    iBATIS 2.3.0.677
    MySQL 5.0


4)참고 사이트    
    Flex+Spring
    http://coenraets.org/flex-spring

    Flex+Cairngorm+Spring+iBATIS
    http://www.appfoundation.com/blogs/giametta/2007/05/09/flex-spring-ibatis-caringorm-bringing-it-all-together/
    

    바로 위 Chris Giametta가 구현한 자바 클래스 코딩을 좀 달리했다,난 SqlMapClientDaoSupport extend 해서 구현한거다.
    
    주의)    
    ContactDaoImpl 클래스를 코딩할때 아래처럼 Contact.getContacts,해줘야한다
    이분 블로그 처럼 getContacts 하고,다른 map 파일에서 똑같은 이름의 메소드가 있다면,아래 에러가 난다.
    이 에러때문에 한참 헤맸었다.
    //com.ibatis.sqlmap.client.SqlMapException: There is already a statement named getContacts in this SqlMap.

    위와 관련해서 sqlmapconfig.xml 에 아래의 태그를 추가해준다.

    <settings useStatementNamespaces="true"/>
    

    public List getContacts() throws DataAccessException {
        return getSqlMapClientTemplate().queryForList("Contact.getContacts");            
    }
    

    
3tier 각 부분별로 framework 을 적용해봤다.

그런데, 정말 중요한 질문은 이거다.

왜 Spring 을 쓰나?
왜 iBATIS 를 쓰나?
왜 Cairngorm 을 쓰나?
왜 Flex 를 쓰나?

명쾌한 자신만을 답을 가지고 있다면 이 조합이 꽤 쓸만할꺼다.

ps
지금까지 포스팅한글중에 가장 길고 정성들인것 같다.


2007/08/03 15:50 2007/08/03 15:50