반응형

1. 왜 이걸 썼을까?
   bean에서 하드코딩된 값을 property 파일에 넣고 쓸려면 "key=value" 형태 밖에 안됩니다.
   좀더 복잡한 구조를 효율적으로 관리하고자 한다면 xml을 이용해야 하는데
   xml를 쉽게 처리할 수 있는게 뭐 없을까 찾아보니 digester라는 아파치 오픈소스가
   눈에 띄었습니다.
   그냥 따라하기 식으로 환경구성하고 테스트 만들어 보니 한 30분 즘...
   정말 쉽게 구현이 되었습니다.
  
2. 필요한건 뭘까?
   url : http://jakarta.apache.org/commons/digester/
   아래 보면 digester를 이용하기 위해 관련된걸 보면 commons의 logging 1.1.x, BeanUtils 1.x, Collections 2.x/3.x 등이 필요합니다.
   다 다운받으세요^^  

사용자 삽입 이미지
  digester : http://jakarta.apache.org/site/downloads/downloads_commons-digester.cgi
  logging : http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi
  BeanUtils : http://jakarta.apache.org/site/downloads/downloads_commons-beanutils.cgi
  Collections :  http://jakarta.apache.org/site/downloads/downloads_commons-collections.cgi


3. 만들어 보기
    일단 간단한 형태로 구조를 잡았습니다.
[code]
<?xml version="1.0"?>
<config description="kkaok">
<database part="oracle">
<driverclassname>oracle.jdbc.driver.OracleDriver</driverclassname>
<url>oracle ......</url>
<maxactive>10</maxactive>
<maxwait>100</maxwait>
<defaultautocommit>true</defaultautocommit>
<defaultreadonly>false</defaultreadonly>
<defaulttransactionisolation>2</defaulttransactionisolation>
<username>oid</username>
<password>opwd</password>
</database>
<database part="cubrid">
<driverclassname>cubrid.jdbc.driver.CUBRIDDriver</driverclassname>
<url>jdbc:CUBRID:localhost:33000:demodb:::</url>
<maxactive>10</maxactive>
<maxwait>100</maxwait>
<defaultautocommit>true</defaultautocommit>
<defaultreadonly>false</defaultreadonly>
<defaulttransactionisolation>2</defaulttransactionisolation>
<username>cid</username>
<password>cpwd</password>
</database>
</config>
[/code]
config 라는 거 아래 database라는 노드가 반복이 되고
database 아래에는 part, driverclassname,url,maxactive ... 등이 있습니다.

xml을 매핑할 객체를 만들어 보겠습니다.
[code]
public class ConfigInfo {
    private List databaseinfo; // database가 반복되는 bean
    public ConfigInfo(){
        databaseinfo  = new ArrayList();
    }
    public void AddDatavaseInfo(DatabaseInfo dbinfo){ // database 빈에 추가하는 메소드
        databaseinfo.add(dbinfo);
    }
}
[/code]
반복이 되는 패턴 등은 따로 클래스로 뽑고 그냥 값은 property로 만드시면 됩니다.
[code]
public class DatabaseInfo {
    private String part;
    private String driverclassname;
    private String url;
    private int maxactive;
    private long maxwait;
    private boolean defaultautocommit;
    private boolean defaultreadonly;
    private String username;
    private String password;
    private int defaulttransactionisolation;
    public int getDefaulttransactionisolation() {
        return defaulttransactionisolation;
    }
    public void setDefaulttransactionisolation(int defaulttransactionisolation) {
        this.defaulttransactionisolation = defaulttransactionisolation;
    }
    public boolean isDefaultautocommit() {
        return defaultautocommit;
    }
    public void setDefaultautocommit(boolean defaultautocommit) {
        this.defaultautocommit = defaultautocommit;
    }
    public boolean isDefaultreadonly() {
        return defaultreadonly;
    }
    public void setDefaultreadonly(boolean defaultreadonly) {
        this.defaultreadonly = defaultreadonly;
    }
    public String getDriverclassname() {
        return driverclassname;
    }
    public void setDriverclassname(String driverclassname) {
        this.driverclassname = driverclassname;
    }
    public int getMaxactive() {
        return maxactive;
    }
    public void setMaxactive(int maxactive) {
        this.maxactive = maxactive;
    }
    public long getMaxwait() {
        return maxwait;
    }
    public void setMaxwait(long maxwait) {
        this.maxwait = maxwait;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPart() {
        return part;
    }
    public void setPart(String part) {
        this.part = part;
    }
}
[/code]

[code]
public class ReadConfig {
    public static void main(String[] args){
        try {
            Digester digester = new Digester();
            digester.setValidating(false);
             // 최상위 노드를 생성합니다. 객체는 addObjectCreate
            // addObjectCreate(xml 경로와노드명, 객체 타입)
            digester.addObjectCreate("config", ConfigInfo.class);
            // DatabaseInfo를 생성합니다.
            digester.addObjectCreate("config/database", DatabaseInfo.class);
            // DatabaseInfo의 part 지정
            //attributes는 addSetProperties(경로, attribute name, bean 매핑할 property) 메소드로 등록합니다.
            digester.addSetProperties("config/database", "part", "part");
            // node 추가, addBeanPropertySetter(경로와이름, 객체필드명)
            digester.addBeanPropertySetter("config/database/driverclassname",
                    "driverclassname");
            digester.addBeanPropertySetter("config/database/url", "url");
            digester.addBeanPropertySetter("config/database/maxactive",
                    "maxactive");
            digester
                    .addBeanPropertySetter("config/database/maxwait", "maxwait");
            digester.addBeanPropertySetter("config/database/defaultautocommit",
                    "defaultautocommit");
            digester.addBeanPropertySetter("config/database/defaultreadonly",
            "defaultreadonly");
            digester.addBeanPropertySetter("config/database/defaulttransactionisolation",
            "defaulttransactionisolation");
            digester.addBeanPropertySetter("config/database/username",
                    "username");
            digester.addBeanPropertySetter("config/database/password",
                    "password");
            // set하기
            // addSetNext(경로와이름, 추가할 메소드명);
            digester.addSetNext("config/database", "AddDatavaseInfo");

            File input = new File(xml파일);
            config = (ConfigInfo) digester.parse(input);

            // config에 xml값이 이제 다 담겼습니다. 이제 입맛대로 사용하시면 됩니다.

        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }
}
[/code]

4. 결과
    work flow
    1.  xml 구조 및 파일 생성
    2. 매핑할 객체 생성
    3. digester로 매핑하기
    4. 사용

    xml로 만들걸 객체로 생성하거나 객체로 구조 잡고 xml로 만들 수 있다면 나머진 digester가 알아서 해줍니다.
    약간의 규칙을 알아야 하는데 해당 사이트에 가보시면 문서가 잘 만들어 져 있으니 사용하는데 크게 어렵진 않을거 같습니다.
    소스를 보시면 알겠지만 기존 xml을 다루는 거와 비교해보면 월등히 간결합니다.
    기존 xml과 관련된 많은 것들이 보이지도 않습니다.
    한 30분 노력해서 앞으로 몇년을 써먹을 수 있다면 충분히 가치가 있다고 생각합니다.
    try it~~~~

Posted by 1010