반응형

from http://www.javaservice.net/~java/bbs/read.cgi?m=resource&b=qna2&c=r_p&n=1131692449&p=1&s=t

 

제목 : POI로 엑셀파일 읽을때, Invalid header signature 에러
글쓴이: 손님(guest) 2005/11/11 11:37:30 조회수:20 줄수:44
poi를 이용하여 클라이언트의 엑셀문서를 서버에 업로드후 읽어내는 작업을 하려합니다.
작업의 목적은 화면상에 입력필드가 너무 많아서(대략 240여개 정도 됩니다),
일일이 입력하기에 불편함이 초래되어,엑셀로 다운받은 다음에 해당 입력값들을 엑셀에서 입력후,
입력한 값을 다시 화면상에 뿌려주려는 것입니다.

업로드 완료후 엑셀파일을 읽을때,

Error occurred : Invalid header signature; read 5789751444030890300, expected -2226271756974174256
java.io.IOException: Invalid header signature; read 5789751444030890300, expected -2226271756974174256
        at org.apache.poi.poifs.storage.HeaderBlockReader.<init>(HeaderBlockReader.java:88)
        at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:83).......

 

위와 같은 에러가 발생합니다.해당 라인을 쫓아가보면,

POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(filePath + fileName));

이부분입니다.

읽으려 하는 엑셀은 jsp내에서,

response.setContentType("application/vnd.ms-excel;charset=euc-kr"); 
response.setHeader("Content-Disposition", "attachment; filename="+jspName+".xls"); 
response.setHeader("Content-Description", "JSP Generated Data"); 

을 이용해서 생성한것입니다.해당 엑셀파일을 일반 텍스트 에디터에서 열어보면,

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/html; charset=ks_c_5601-1987">
<meta name=ProgId content=Excel.Sheet>
(이하 생략)

meta 태그내의 'content="text/html;' 부분이 의심이 갑니다만.
엑셀을 생성하는 jsp내의 meta 태그부분을 삭제해도,생성된 엑셀을 보면 해당부분이 들어가있는데요.

다시 처음으로 와서,content='text/html' 부분때문에 Invalid header signature...의 오류가 발생하는것인지요?
jsp에서 생성된 엑셀이 아닌 일반 엑셀문서로 테스트 해봤을때는 이상없이 제대로 실행됩니다.
제가 의심한 부분이 맞는것이라면, 해결책은 어떤것이 있을런지 조언 부탁드립니다.
제목 : Re: 실제 엑셀파일이 아니라서 그런거 같습니다.
글쓴이: 손님(guest) 2005/11/11 16:00:49 조회수:7 줄수:16
 Invalid Header라는 에러메시지의 의미가

 파일 헤더가 엑셀타입이 아니라서 그런거 같습니다.

 POI가 해석하는 엑셀파일은 MS OLE Compound로 생성된 파일포맷일 경우에만

 해당됩니다..html의 header를 excel이라 조작해서 생성된 엑셀파일은

 실제론 텍스트파일일뿐 OLE 타입이 아니라서요.

 서버에서 생성시 jsp로 생성하지 말고 poi를 이용해서 서버측에 실제

 엑셀파일을 생성한 후 클라이언트로 스트리밍을 통해 다운로드 해주는 방식을

 택해야할 것같네요.
제목 : Re: 답변 고맙습니다.
글쓴이: 손님(guest) 2005/11/11 16:31:58 조회수:2 줄수:5
그렇군요.
실제로 jsp내에서 생성되는 엑셀을 다른이름으로 저장해서 'Micrisoft Excel 통합문서' 형식으로 저장하니,
정상적으로 실행이 되는군요.
충고해주신데로, poi를 이용해서 엑셀을 생성하는 쪽으로 다시 해봐야겠습니다.
답변 고맙습니다.좋은 주말 되세요.

Posted by 1010
반응형

JSP에서 원하는 Appender 선택하여 쓰기


만약 log4j 가 처음이라면 다음 링크를 먼저 필독하세요


log4j 웹에서 사용하기

http://www.jakartaproject.com/article/jakarta/1110438405982

log4j 고급스럽게 사용하기

http://www.jakartaproject.com/article/jakarta/1113816023183


 

I. 먼저 log4j 프로퍼티 파일입니다

log4j.properties

log4j.rootLogger=INFO, stdout1, stdout2


log4j.logger.jsp1=INFO, stdout1
log4j.additivity.jsp1=false


log4j.logger.jsp2=INFO, stdout2
log4j.additivity.jsp2=false


log4j.appender.stdout1=org.apache.log4j.ConsoleAppender
log4j.appender.stdout1.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout1.layout.ConversionPattern=jsp1 appender log %d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n


log4j.appender.stdout2=org.apache.log4j.ConsoleAppender
log4j.appender.stdout2.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout2.layout.ConversionPattern=jsp2 appender log %d %-5p [%t] %-17c{2} (%13F:%L) %3x - %m%n


log4j.logger.jsp1=INFO, stdout1
log4j.logger.jsp2=INFO, stdout2
jsp1과 jsp2의 두개의 logger를 정의합니다

jsp1 logger는 appender로 stdout1을 사용하며, jsp2 logger는 appender로 stdout2로 사용한다는 의미입니다


log4j.additivity.jsp1=false

additivity 속성은 jsp1 logger를 상위 로거(root logger)의 속성을 삭송받지 않겠다는 의미입니다

만약 이 속성이 없으면 동일한 메세지가 여러번 로깅될 것입니다

이하 속성은

http://www.jakartaproject.com/article/jakarta/1110438405982 을 참고하세요


II. JSP 샘플 소스

test_jsp1_appender.jsp

<%@ page contentType="text/html;charset=MS949"
 import="org.apache.log4j.Logger" %>

<%!
 static Logger logger1 = Logger.getLogger("jsp1");
%>

<%
logger1.warn("warn");
%>

로깅 메세지

jsp1 appender log 2005-11-07 13:05:23,687 WARN  [http-8080-Processor5] jsp1 (test_jsp1_appender_jsp.java:48)     - warn


test_jsp2_appender.jsp

<%@ page contentType="text/html;charset=MS949"
 import="org.apache.log4j.Logger" %>

<%!
 static Logger logger2 = Logger.getLogger("jsp2");
%>

<%
logger2.warn("warn");
%>

로깅 메세지

jsp2 appender log 2005-11-07 13:05:58,031 WARN  [http-8080-Processor4] jsp2 (test_jsp2_appender_jsp.java:48)     - warn


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형

Jakarta Commons Email


I. Commons-Email

2005년 9월 27일 드디어 Commons-Email이 version 1.0이 배포되었습니다

Commons-Email은 Java Mail API를 근간으로 좀더 심플하게 메일을 보내는 방안을 제시합니다.

기능상으로는 첨부파일 뿐만 아니라 HTML Email도 쉽게 보낼수 있는 API를 제공합니다


II. Download!

Commons-Email을 사용하기 위해서는 JavaMail의 mail.jar와 JAF의 activation.jar 가 필요합니다

Commons-Email download

http://jakarta.apache.org/site/downloads/downloads_commons-email.cgi

JavaMail 1.3

http://java.sun.com/products/javamail/downloads/index.html

JAF 1.0.2

http://java.sun.com/products/javabeans/glasgow/jaf.html


Commons-Email

http://jakarta.apache.org/commons/email/index.html

Commons-Email API

http://jakarta.apache.org/commons/email/apidocs/index.html



III. Install




다운 받은 3개의 파일을 $tomcat_home/webapps/ROOT/WEB-INF/lib/ 밑에 복사합니다



IV. 샘플 소스


간단히 텍스트만 보내기

SimpleEmail email = new SimpleEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test message");
email.setMsg("This is a simple test of commons-email");
email.send();

org.apache.commons.mail.SimpleEmail 은 가장 중심이 되는 org.apache.commons.mail.Email을 상속받아 setMsg(java.lang.String msg)만을 구현한 가장 기본적인 클래스입니다.

setHostName(java.lang.String aHostName)으로 SMTP 서버를 지정하고,

addTo(java.lang.String email) or addTo(java.lang.String email, java.lang.String name)으로 받는 사람의 메일주소를, setFrom(java.lang.String email) or setFrom(java.lang.String email, java.lang.String name)으로 보내는 사람의 메일을 설정합니다

물론 addTo 함수의 추가로 여러 사람에게 메일을 보낼 수 있습니다.

가장 기본적인 setSubject(java.lang.String subject)와 setMsg(java.lang.String msg)로 메일 제목과 내용을 입력한 후 send() 함수로 전송합니다


파일 첨부하기

// 첨부할 attachment 정보를 생성합니다
EmailAttachment attachment = new EmailAttachment();
attachment.setPath("mypictures/john.jpg");
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Picture of John");
attachment.setName("John");

// 기본 메일 정보를 생성합니다

MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The picture");
email.setMsg("Here is the picture you wanted");

// 생성한 attachment를 추가합니다
email.attach(attachment);

// 메일을 전송합니다
email.send();

첨부파일과 같이 보낼려면 EmailAttachment 를 생성하여 파일 정보를 입력해 줍니다

파일경로와 파일형태, 파일 설명등을 추가하며 마지막으로 setName(java.lang.String name)을 통해 첨부되는 파일명을 설정합니다

그 후 MultiPartEmail 을 통해 SimpleEmail 처럼 기본 메일정보를 설정합니다

마지막으로 MultiPartEmail의 attach() 함수를 통해 첨부 파일을 추가하여 전송합니다

만약 첨부파일이 두개 이상이라면 EmailAttachment 를 여러개 생성하여 파일 정보를 설정 한 후 attach()를 통해 추가해 주기만 하면 됩니다


URL을 통해 첨부하기

// 첨부할 URL정보 및 파일 기본 정보를 설정합니다
EmailAttachment attachment = new EmailAttachment();
attachment.setURL(new URL("http://www.apache.org/images/asf_logo_wide.gif"));
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Apache logo");
attachment.setName("Apache logo");

// 기본 메일 정보를 생성합니다
MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The logo");
email.setMsg("Here is Apache's logo");

// attachment를 추가합니다
email.attach(attachment);

// 메일을 전송합니다
email.send();

파일 경로 정보를 setURL(java.net.URL) 으로 설정할 뿐 위의 첨부파일과 동일합니다


HTML 이메일 보내기

// 기본 메일 정보를 생성합니다
HtmlEmail email = new HtmlEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test email with inline image");

// 삽입할 이미지와 그 Content Id를 설정합니다
URL url = new URL("http://www.apache.org/images/asf_logo_wide.gif");
String cid = email.embed(url, "Apache logo");

// HTML 메세지를 설정합니다

email.setHtmlMsg("<html>The apache logo - <img src=\"cid:"+cid+"\"></html>");

// HTML 이메일을 지원하지 않는 클라이언트라면 다음 메세지를 뿌려웁니다
email.setTextMsg("Your email client does not support HTML messages");

// 메일을 전송합니다
email.send();

HtmlEmail 클래스는 setHtmlMsg()로 작성된 html을 보낼 수 있습니다

이미지 처리가 조금 까탈스럽네요



V. 인증처리

만약 SMTP 서버가 인증을 요구한다면 org.apache.commons.mail.Email 의 setAuthentication(java.lang.String username, java.lang.String password)를 통해 해결할 수 있습니다

이 함수는 JavaMail API의 DefaultAuthenticator 클래스를 생성하여 사용합니다



=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형

Jakarta POI

 


X. 이미지


POI 3.0 부터 드디어 이미지를 지원하는군요.

아직 알파버젼이구요 http://www.apache.org/dyn/closer.cgi/jakarta/poi/ 에서 최신버젼을 다운 받을 수 있습니다


최신링크

http://mirror.apache.or.kr/jakarta/poi/dev/bin/poi-bin-3.0-alpha1-20050704.zip


아래 소스는 OKJSP의 "이루"님이 작성한 소스입니다

from http://www.okjsp.pe.kr/bbs?act=VIEW&seq=60543&bbs=bbs4&keyfield=content&keyword=&pg=0


import java.util.*;
import java.io.*;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem.*;
import org.apache.poi.poifs.eventfilesystem.*;


public class InsertImage {
    public static void main(String[] args) throws IOException {
        POIFSFileSystem fs      = new POIFSFileSystem(new FileInputStream("/xxx/test.xls")); // 원본엑셀파일
        HSSFWorkbook    wb      = new HSSFWorkbook(fs);
        HSSFSheet       sheet   = wb.getSheetAt(0);

        drawSheet5( sheet, wb );

        // Write the file out.
        FileOutputStream fileOut = new FileOutputStream("/xxx/img_work.xls"); // 이미지 삽입된 엑셀파일
        wb.write(fileOut);
        fileOut.close();
    }


    private static void drawSheet5( HSSFSheet sheet, HSSFWorkbook wb ) throws IOException {
        // Create the drawing patriarch.  This is the top level container for
        // all shapes. This will clear out any existing shapes for that sheet.
        HSSFPatriarch patriarch = sheet.createDrawingPatriarch();

        HSSFClientAnchor anchor;
        anchor = new HSSFClientAnchor(0,0,0,255,(short)1,4,(short)2,4); // 이미지 크기조절은 여기서..
        anchor.setAnchorType( 2 );
        patriarch.createPicture(anchor, loadPicture( "/xxx/okjsp.jpg", wb )); // 삽입 할 이미지
    }


    private static int loadPicture( String path, HSSFWorkbook wb ) throws IOException {
        int pictureIndex;
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;

        try {
            fis = new FileInputStream( path);
            bos = new ByteArrayOutputStream( );
            int c;
            while ( (c = fis.read()) != -1) {
                bos.write( c );
            }
            pictureIndex = wb.addPicture( bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_JPEG  );
        } finally {
            if (fis != null) fis.close();
            if (bos != null) bos.close();
        }
        return pictureIndex;
    }
}


Posted by 1010
반응형

Jakarta Ant


-. 이번 강좌에서는 지난 시간에 이어 ant 사용에 필수적인 task들에 대해 알아보고

   예제를 통해 한번더 알아보도록 하겠습니다.

   만약 지난 강좌를 아직 보지 않았다면 다음 링크를 참조하세요

   http://www.jakartaproject.com/article/jakarta/1114617006525



I. 집합 태그


1. <fileset>

개요

-. fileset이란 말 그대로 파일의 집합을 말하며 특정 태스크에서 파일을 포함하여야 할때

손쉽게 특정 파일이나 집합을 지정해 주는데 사용된다

주로 클래스패스나, 압축, 파일 카피등의 task에서 사용되어진다


예제

사용예제-1


<fileset dir="${server.src}" casesensitive="yes">
  <include name="**/*.java"/>
  <exclude name="**/*Test*"/>
</fileset>
<fileset dir="${server.src}" casesensitive="yes">
  <filename name="**/*.java"/>
  <filename name="**/*Test*" negate="true"/>
</fileset>
<fileset dir="${server.src}" casesensitive="yes"> <filename name="**/*.java"/> <not> <filename name="**/*Test*"/> </not> </fileset>

모든 디렉토리의 java파일을 포함시키면서 파일이름중 Test가 들어가는 파일은 제외하는 fileset을 나타낸다

위 세가지 fileset은 같은 의미이다


사용예제-2


<fileset dir="${server.src}" casesensitive="yes">
  <include name="**/*.java, **/*.properties"/>
</fileset>
<fileset dir="${server.src}" casesensitive="yes">
  <include name="**/*.java"/>
<include name="**/*.properties"/>
</fileset>

","를 사용하여 나타낼 수도 있고 다로 분리하여 tag를 사용할 수도 있다

위 두 fileset은 같은 의미이다


속성

속성 설명 필수여부
dir 파일집합의 최상위 디렉토리 (루트 디렉토리) dir나 file둘중 하나는 필수
file 특정 하나의 파일을 지정할때 사용
defaultexcludes default excludes 에 명시된 파일 및 디렉토리를 자동적으로 제외하는 속성이며 이기능을 사용하려면 생략한다. 혹은 yes/no 로 값을 준다 No
includes 컴마나 스페이스로 구분된 파일의 패턴을 포함하는 속성이며 모든 파일을 사용하려면 생략한다 No
includesfile 특정 각각의 파일을 포함할때 사용하는 속성 No
excludes 컴마나 스페이스로 구분된 파일의 패턴을 제외하는 속성이며 생략하면 default excludes를 제외하고 어떠한 파일도 제외하지 않는다 No
excludesfile 특정 각각의 파일을 제외할때 사용하는 속성 No
casesensitive 패턴의 대소문자를 구분할지 여부를 나타내는 속성으로 기본값은 true이다 No
followsymlinks symbolic links를 허용할지 여부를 나타내며 기본값은 true이다 No


default excludes

excludes를 사용하지 않아도 기본적으로 제외되는 파일 및 디렉토리

     **/*~
     **/#*#
     **/.#*
     **/%*%
     **/._*
     **/CVS
     **/CVS/**
     **/.cvsignore
     **/SCCS
     **/SCCS/**
     **/vssver.scc
     **/.svn
     **/.svn/**
     **/.DS_Store

자 이정도면 fileset은 이제 빠~삭해 지셨겠죠?



2. <dirset>

개요

-. fileset이 파일 집합을 나타냈다면 dirset task는 디렉토리의 집합을 나타낸다. 기본적인 속성은 fileset과 동일하다

차이점은 defaultexcludes가 없다


사용예제


<dirset dir="${build.dir}"> <include name="apps/**/classes"/> <exclude name="apps/**/*Test*"/> </dirset>

apps 이하 디렉토리중 classes 디렉토리를 포함하고 apps 이하 디렉토리중 디렉토리 이름중 Test가 들어가는 디렉토리는 제외한 dirset을 의미한다


속성

속성 설명 필수여부
dir 파일집합의 최상위 디렉토리 (루트 디렉토리) YES
includes 컴마나 스페이스로 구분된 디렉토리의 패턴을 포함하는 속성이며 모든 파일을 사용하려면 생략한다 No
includesfile 특정 각각의 디렉토리를 포함할때 사용하는 속성 No
excludes 컴마나 스페이스로 구분된 디렉토리의 패턴을 제외하는 속성이며 생략하면 어떠한 디렉토리도 제외하지 않는다 No
excludesfile 특정 각각의 디렉토리를 제외할때 사용하는 속성 No
casesensitive 패턴의 대소문자를 구분할지 여부를 나타내는 속성으로 기본값은 true이다 No
followsymlinks symbolic links를 허용할지 여부를 나타내며 기본값은 true이다 No



3. <patternset>

개요

-. 여러 파일이나 디렉토리를 미리 그룹핑해 놓고 이를 특정 아이디를 통해 사용하는 방식을 제공한다. 즉 워드의 매크로 같은 기능이라 보면 쉽게 이해가 갑니다


사용예제

<patternset id="non.test.sources">
  <include name="**/*.java"/>
  <exclude name="**/*Test*"/>
</patternset>
...
<fileset dir="${server.src}">
<patternset refid="non.test.sources"/>
</fileset>
...
<fileset dir="${server.src}">
<patternset refid="non.test.sources">
<include name="**/*.java"/>
</patternset>
</fileset>

예제를 보는바와 같이 patternset은 여러곳에서 동일한 패턴을 사용할때 이를 미리 정의해 놓고 지정한 id의 값을 refid를 통해 재사용 할 수 있다

paternset을 사용하면 코딩양을 줄일 수 있고 변동사항이 있으면 손쉽게 변동 할 수 있다는 점이다


속성

속성 설명 필수여부
includes 컴마나 스페이스로 구분된 디렉토리의 패턴을 포함하는 속성이며 모든 파일을 사용하려면 생략한다 No
includesfile 특정 각각의 디렉토리를 포함할때 사용하는 속성 No
excludes 컴마나 스페이스로 구분된 디렉토리의 패턴을 제외하는 속성이며 생략하면 어떠한 디렉토리도 제외하지 않는다 No
excludesfile 특정 각각의 디렉토리를 제외할때 사용하는 속성 No



4. <path>

개요

-. 파일과 디렉토리를 함께 나타낼 수 있는 집합. 클래스패스에는 경로뿐만 아니라 *.jar 같은 파일이 같이 사용되듯이 이 path task는 주로 클래스패스로 자주 이용된다

fileset, dirset과 비슷하지만 파일과 디렉토리를 함께 나타낼 수 있다는 점에서 틀리다

path tag역시 patternset과 같이 지정된 id 값을 이용하여 여러 곳에서 재사용 할 수 있다.


사용예제

아래 예제는 ${basedir}/lib/struts.jar, ${base.dir}/lib/log4j.jar 그리고 ${base.dir}/classes 에 클래스패스를 잡는 예제이다.

<path id="base.path">
<pathelement path="lib/struts.jar;lib/log4j.jar"/> <pathelement location="classes"/> </path> ...
<classpath refid="base.path"/>
...

path에 대한 정의를 해놓고 base.path라는 아이디를 이용하여 여러 곳에서 사용할 수 있다


location 속성은 single 파일이나 탐색할 하나의 디렉토리만을 설정할수 있는 반면에,

path는 ";"나 ":"를 사용하여 여러 파일들이나 디렉토리를 설정할 수 있다


II. 파일 태그


1. <copy>

개요

-. 소스 파일을 타겟으로 파일을 복사하는데 사용한다


사용예제

파일 하나 복사

<copy file="myfile.txt" tofile="mycopy.txt"/>


파일 하나를 디렉토리에 복사

<copy file="myfile.txt" todir="../some/other/dir"/>

 

디렉토리를 다른 디렉토리로 복사 

<copy todir="../new/dir">
    <fileset dir="src_dir"/>
</copy>

 

파일 집합을 디렉토리에 복사

<copy todir="../dest/dir">
    <fileset dir="src_dir">
      <exclude name="**/*.java"/>
    </fileset>
</copy>

<copy todir="../dest/dir">
    <fileset dir="src_dir" excludes="**/*.java"/>
</copy>

 

파일 집합을 디렉토리에 복사하며 파일명 끝에 .bak을 추가하여 복사

<copy todir="../backup/dir">
    <fileset dir="src_dir"/>
    <globmapper from="*" to="*.bak"/>
</copy>

 

파일집합을 디렉토리에 복사하며 파일집합중 TITLE 이란 STRING을 Foo Bar로 대체하며 복사

<copy todir="../backup/dir">
    <fileset dir="src_dir"/>
    <filterset>
      <filter token="TITLE" value="Foo Bar"/>
    </filterset>
</copy>


속성

속성 설명 필수여부
file 복사할 파일 fileset tag를 사용하지 않는다면 필수
preservelastmodified

소스와 타겟의 최종 수정날짜 파일을 유지하며 복사한다

기본값은 false

No
tofile 복사할 소스파일 fileset tag와 함께 소스 및 타겟을 지정할수있다
todir 복사할 소스 디렉토리
overwrite 타겟의 파일이 최근의 파일이라도 덮어쓸지 여부를 나타내며 기본값은 false No
filtering

복사하는동안 filter를 사용할것인지 여부를 나타내며 기본값은 false

단 이 값이 false일지라도 nested 하게 <filterset>을 사용할수 있다

No
flatten

소스 디렉토리의 구조를 무시하고 특정 디렉토리 한곳에 모든 파일을 복사할지 여부를 나타내며 기본값은 false

No
includeEmptyDirs

<fileset>을 지정하여 복사될 디렉토리중에 파일이 없는 비어있는 디렉토리까지 복사할지 여부를 나타내며 기본값을 true

No
failonerror

복사중 에러가 발생할때 false이면 warning 메세지 로그를, 그렇지 않으면 build시 중지한다

기본값은 true

No
verbose 복사되고 있는 파일의 로그 여부를 나타내며 기본값은 false No
encoding

필터 복사중 사용할 encoding을 나타내며 기본값은 JVM 기본 encoding을 따른다 (ant 1.5 이후)

No
outputencoding

파일기록에 사용할 encoding을 나타낸다

(ant 1.6이후)

No
enablemultiplemappings

true면 주어진 소스 path에대해 모든 mapping 처리를 하며 false이면 첫번째 파일이나 디렉토리에 대해서만 mapping 처리를 한다

이 속성은 <mapper> subelement가 있을때만 관련있다

기본값은 false

(ant 1.6이후)

No
granularity

최근 수정된 시간을 기준으로 파일을 비교 복사시 기준이 되는 시간으로부터 여유분 시간을 나타낸다

즉 소스 파일 서버와 타겟 파일 서버가 다른경우 두 머신간에 시간차이가 있을 수 있기 때문에 이를 사용한다

(ant 1.6.2 이후)

 


2. <delete>

개요

-. 하나의 파일, 하나의 디렉토리 혹은 fileset으로 지정한 특정한 파일들을 삭제할수 있다


사용예제

하나의 파일을 삭제
<delete file="/lib/ant.jar"/>


하나의 디렉토리를 삭제 (이하 디렉토리 및 파일 모두 삭제됨)
<delete dir="lib"/>


현재 디렉토리로 부터 모든 파일중 .bak 파일은 모두 삭제
<delete>
    <fileset dir="." includes="**/*.bak"/>
</delete>


하나의 디렉토리를 삭제하며 빈 디렉토리라도 모두 삭제 (build 자신의 디렉토리도 삭제)
<delete includeEmptyDirs="true">
    <fileset dir="build"/>
</delete>


build 이하 모든 파일을 삭제하며 빈 디렉토리라도 모두 삭제 (build 자신의 디렉토리는 삭제되지 않음)
<delete includeemptydirs="true">
    <fileset dir="build" includes="**/*"/>
</delete>


 


속성

속성 설명 필수사항
file

삭제할 파일

(상대경로나 절대경로나 상관없음)

<fileset>을 사용하지 않는다면 file혹은 dir둘중 하나는 사용하여야 한다
dir

삭제할 디렉토리

verbose

각 삭제되는 파일의 이름을 보져줄 것인지 여부를 나타내며 기본값은 false

No
quiet

시스템이 사용하고 있어 삭제할수 없는 파일이거나

존재하지 않는 파일, 디렉토리등의 메세지를 나태낼지 여부를 나타내며 기본값은 false

No
failonerror

파일 삭제시 에러가 발생하면 build를 중단 하고 현재 사항을 레포팅해줄지 여부를 나타내며 기본값은 true

No
includeemptydirs fileset을 사용할 때 빈 디렉토리empty directory)를 삭제할 것인지 여부를 나타내며 기본값은 false No
includes Deprecated. Use <fileset>. No
includesfile Deprecated. Use <fileset>. No
excludes Deprecated. Use <fileset>. No
excludesfile Deprecated. Use <fileset>. No
defaultexcludes

Deprecated. Use <fileset>.

기본값은 true

No
deleteonexit

파일 삭제시 실패했을때 JVM이 종료될 때 이 파일을 지우도록 할것인지 여부를 나타내며 기본값은 false

(ant 1.6.2 이후)

No


3. <mkdir>

설명

-. 디렉토리를 생성


사용예제

"${dist}" 디렉토리를 생성한다

<mkdir dir="${dist}"/>


"${dist}/lib" 디렉토리를 생성한다

<mkdir dir="${dist}/lib"/>


속성

속성 설명 필수여부
dir 생성할 디렉토리 Yes


4. <move>

설명

-. 파일 혹은 디렉토리를 타겟으로 이동시킵니다 디폴트로 타겟에 이미 파일이 존재하면 덮어씁니다.


사용예제

하나의 파일을 이동시킵니다 (rename과 동일)
<move file="file.orig" tofile="file.moved"/>


하나의 파일을 디렉토리로 이동시킵니다
<move file="file.orig" todir="dir/to/move/to"/>


디렉토리를 새로운 디렉토리로 이동시킵니다
<move todir="new/dir/to/move/to">
    <fileset dir="src/dir"/>
</move>


위의 task와 동일하며 ant 1.6.3부터 지원합니다
<move file="src/dir" tofile="new/dir/to/move/to"/>


파일집합을 새로운 디렉토리로 이동시킵니다
<move todir="some/new/dir">
    <fileset dir="my/src/dir">
      <include name="**/*.jar"/>
      <exclude name="**/ant.jar"/>
    </fileset>
</move>


.bak을 제외한 모든 파일에 .bak을 추가시키며 이동시킵니다
<move todir="my/src/dir" includeemptydirs="false">
    <fileset dir="my/src/dir">
      <exclude name="**/*.bak"/>
    </fileset>
    <mapper type="glob" from="*" to="*.bak"/>
</move>



속성

-. delete 속성과 동일합니다



III. java 태그


1. <javac>

설명

-. 자바소스를 컴파일 하는 tag입니다

기본적으로 타겟에 특정 .java에 대해 .class 파일이 없거나 오래된 .class 파일이면 컴파일 대상입니다


사용예제

<path id="compile.classpath">

    <pathelement location="${catalina.home}/common/classes"/>
    <fileset dir="${web.home}/WEB-INF/lib">
      <include name="*.jar"/>
    </fileset>
</path>


가장 일반직인 컴파일 태그 compile.classpath 는 앞의 path 태그에서 정의됨

<javac srcdir="${src}"

          destdir="${build}">

     <classpath refid="compile.classpath"/>

</javac>


include, exclude, debug등을 포함한 컴파일 태그

<javac srcdir="${src}"
          destdir="${build}"
          includes="mypackage/p1/**,mypackage/p2/**"
          excludes="mypackage/p1/testpackage/**"
          classpath="xyz.jar"
          debug="on"
/>


srcdir 대신 <scr> 태그를 이용한 컴파일 태그

<javac destdir="${build}"
         classpath="xyz.jar"
         debug="on">
    <src path="${src}"/>
    <src path="${src2}"/>
    <include name="mypackage/p1/**"/>
    <include name="mypackage/p2/**"/>
    <exclude name="mypackage/p1/testpackage/**"/>
</javac>



속성

width=20%>속성 설명 필수여부
srcdir 자바 소스가 위치한 디렉토리

Yes

<src>가 존재하면NO

destdir 컴파일된 클래스파일이 위치할 디렉토리 No
includes 컴마나 스페이스로 구분된 파일집합의 패턴을 포함하여 컴파일하며 모든 파일을 사용하려면 생략한다 No
includesfile 각각 개개의 파일을 포함하여 컴파일 No
excludes 컴마나 스페이스로 구분된 파일의 패턴을 제외하하여 컴파일하며 생략하면 어떠한 디렉토리도 제외하지 않는다 No
excludesfile 각각 개개의 파일을 제외하여 컴파일 No
classpath 사용할 클래스 패스 No
sourcepath

사용할 소스패스이며 기본값은 srcdir 값이다

No
bootclasspath bootstrap 클래스 패스 No
classpathref 참조를 통해 사용할 클래스 패스 (refid를 이용한 path 태그) No
sourcepathref 참조를 통해 사용할 소스 패스 No
bootclasspathref 참조를 통해 사용할 bootstrap 패스 No
extdirs 사용할 extednsion이 위치한 경로 (${java_home}/lib/ext/를 말하는것 같음) No
encoding 소스파일에 사용할 encoding (javac의 -encoding과 동일) No
nowarn

컴파일시 -nowarn 옵션을 을 줄지 여부를 나타내며 기본값은 off

반대값은 on

No
debug 컴파일시 debug 모드로 컴파일 하며 기본값은 off No
optimize 컴파일시 optimize 옵션을 사용한다 기본값은 off No
deprecation 컴파일시 deprecation 옵션을 사용한다 기본값은 off No
target 특정 VM 버젼으로 컴파일 할수 있도록 한다 No
verbose

컴파일시 그 내용을 화면에 출력한다

기본값은 no

No
depend

이를 지원하는 컴파일러는 dependecy-tracking를 가능하게 한다

No
includeAntRuntime

ant run time library를 포함하여 컴파일하며 기본값은 yes

No
includeJavaRuntime

VM이 실행될때의 run time library를 포함하여 컴파일하며 기본값은 no

No
fork 외부의 JDK를 사용하여 컴파일 하며 기본값은 no No
executable

fork를 yes로 하였을경우 javac가 실행될 경로를 나타내며 기본값으로는 ant에서 현재 사용중인 java version의 컴파일러를 나타낸다

No
memoryInitialSize

VM내에서 초기 메모리 사이즈를 설정하며 기본값은 VM에 설정된 기본값을 사용한다

No
memoryMaximumSize VM내에서 최대 메모리 사이즈를 설정 No
failonerror

컴파일시 에러가 발생하였을 경우 계속 진행할지 여부를 나타내며 기본값은 true

No
source -source 옵션을 이용하여 컴파일 한다 No
compiler

사용할 컴파일러 설정 list

No
listfiles

컴파일 되는 소스파일들을 list할지 여부를 나타내며 기본값은 no

No
tempdir

ant가 사용하는 임시디렉토리

기본값은 java.io.tmpdir

(ant 1.6이후)

No


2. <javadoc>

개요

-. 자바 소스 파일로 부터 javadoc API 문서를 생성한다


사용예제

간단한 사용예

<javadoc sourcepath="${src.home}"
               destdir="${dist.home}/docs/api"
               packagenames="*">
       <classpath refid="compile.classpath"/>
</javadoc>


아래 3가지 사용예는 동일한 의미이다

<javadoc

           packagenames="com.dummy.test.*"
           sourcepath="src"
           excludepackagenames="com.dummy.test.doc-files.*"
           defaultexcludes="yes"
           destdir="docs/api"
           author="true"
           version="true"
           use="true"
           windowtitle="Test API">
    <doctitle><![CDATA[<h1>Test</h1>]]></doctitle>
    <bottom><![CDATA[<i>Copyright &#169; 2000 Dummy Corp. All Rights Reserved.</i>]]></bottom>
    <tag name="todo" scope="all" description="To do:"/>
    <group title="Group 1 Packages" packages="com.dummy.test.a*"/>
    <group title="Group 2 Packages" packages="com.dummy.test.b*:com.dummy.test.c*"/>
    <link offline="true" href="http://java.sun.com/products/jdk/1.2/docs/api/" packagelistLoc="C:\tmp"/>
    <link href="http://developer.java.sun.com/developer/products/xml/docs/api/"/>
</javadoc>


<javadoc
           destdir="docs/api"
           author="true"
           version="true"
           use="true"
           windowtitle="Test API">

    <packageset dir="src" defaultexcludes="yes">
      <include name="com/dummy/test/**"/>
      <exclude name="com/dummy/test/doc-files/**"/>
    </packageset>

    <doctitle><![CDATA[<h1>Test</h1>]]></doctitle>
    <bottom><![CDATA[<i>Copyright &#169; 2000 Dummy Corp. All Rights Reserved.</i>]]></bottom>
    <tag name="todo" scope="all" description="To do:"/>
    <group title="Group 1 Packages" packages="com.dummy.test.a*"/>
    <group title="Group 2 Packages" packages="com.dummy.test.b*:com.dummy.test.c*"/>
    <link offline="true" href="http://java.sun.com/products/jdk/1.2/docs/api/" packagelistLoc="C:\tmp"/>
    <link href="http://developer.java.sun.com/developer/products/xml/docs/api/"/>
</javadoc>


<javadoc
           destdir="docs/api"
           author="true"
           version="true"
           use="true"
           windowtitle="Test API">

    <fileset dir="src" defaultexcludes="yes">
      <include name="com/dummy/test/**"/>
      <exclude name="com/dummy/test/doc-files/**"/>
    </fileset>

    <doctitle><![CDATA[<h1>Test</h1>]]></doctitle>
    <bottom><![CDATA[<i>Copyright &#169; 2000 Dummy Corp. All Rights Reserved.</i>]]></bottom>
    <tag name="todo" scope="all" description="To do:"/>
    <group title="Group 1 Packages" packages="com.dummy.test.a*"/>
    <group title="Group 2 Packages" packages="com.dummy.test.b*:com.dummy.test.c*"/>
    <link offline="true" href="http://java.sun.com/products/jdk/1.2/docs/api/" packagelistLoc="C:\tmp"/>
    <link href="http://developer.java.sun.com/developer/products/xml/docs/api/"/>
</javadoc>


속성

속성 설명 사용범위 필수여부
sourcepath 자바 소스 위치 all At least one of the three or nested <sourcepath>, <fileset> or <packageset>
sourcepathref 참조된 경로 아이디를 사용하여 소스위치를 지정 (path 의 refid를 사용) all
sourcefiles 컴마로 구분하여 소스 파일을 지정 all
destdir 결과물(java docs) 디렉토리를 지정 all Yes, unless a doclet has been specified.
maxmemory

javadoc VM에 할당할 최대 메모리 사이즈

all No
packagenames

컴마로 구분된 패키지 파일 목록

("*"로 끝나면 하위 패키지까지 모두 javadoc으로 처리한다)

all No
packageList 처리할 패키지를 포함하고있는 파일명 all No
classpath 사용할 클래스 패스 all No
Bootclasspath

사용할 bootstrap 클래스 패스

all No
classpathref 참조된 경로 아이디를 사용하여 클래스 패스를 지정 (path 의 refid) all No
bootclasspathref 참조된 경로 아이디를 사용하여  bootstrap classpath를 지정 all No
Extdirs 설치된 extension 위치 all No
Overview

HTML 문서로부터 overview 문서를 읽어온다

all No
access

Access mode를 지정한다

public, protected, package, private 중 하나의 값을 가지며 기본값은 protected이다

all No
Public 생성된 문서에 public 클래스와 멤버만 보여준다 all No
Protected 생성된 문서에 protected/public 클래스와 멤버만 보여준다 all No
Package 생성된 문서에 package/protected/public 클래스와 멤버만 보여준다 all No
Private 생성된 문서에 모든 클래스와 멤버를 보여준다 all No
Old jdk 1.1 버젼으로 문서를 생성한다 1.2 No
Verbose javadoc을 생성하는동안 메세지를 화면에 출력한다 all No
Locale

사용할 Locale 을 지정한다

(en_US, en_US_WIN, ko_KR)

all No
Encoding 소스파일 encoding 이름 all No
Version @version 단락을 포함한다 all No
Use 클래스와 패키지 사용법에 대한 페이지를 생성한다 all No
Author @author 단락을 포함한다 all No
Splitindex Split index into one file per letter all No
Windowtitle 생성된 문서의 브라우져 타이트을 지정한다 (텍스트) all No
Doctitle

패키지 인덱스 페이지에 대한 타이틀을 지정한다 (html 코드)

all No
Header

각페이지에대한 헤더부분을 지정한다 (html 코드)

all No
Footer 각페이지에대한 푸터부분을 지정한다 (html 코드) all No
bottom 각페이지에대한 버텀부분을 지정한다 (html 코드) all No
link

주어진 URL로 javadoc 출력물에 link를 생성한다

all No
linkoffline Link to docs at <url> using package list at <url2> - separate the URLs by using a space character -- see also the nested link element. all No
group 특정 패키지들에 대한 overview 페이지를 생성한다 all No
nodeprecated @deprecated 정보를 포함하지 않는다 all No
nodeprecatedlist deprecated 목록을 생성하지 않는다 all No
notree 클래스 하이라키를 생성하지 않는다 all No
noindex 인덱스를 생성하지 않는다 all No
nohelp 도움말 link를 생성하지 않는다 all No
nonavbar 네비게이션 바를 생성하지 않는다 all No
serialwarn @serial tag 대한 warning을 생성한다 all No
helpfile help 파일로 사용될 HTML 파일을 지정한다 all No
stylesheetfile CSS 로 사용할 파일을 지정한다 all No
charset 문서를 생성할때 사용될 charset을 지정한다 all No
docencoding 결과 파일(문서)에 사용될 encoding을 지정한다 all No
doclet

doclet을 시작하는 클래스 파일을 지정한다

all No
docletpath

doclet 클래스 패스를 지정한다

all No
docletpathref 참조 아이디값을 이용해 docletpath를 지정한다 all No
additionalparam

javadoc 명령에서 추가적인 파라미터를 추가하도록 한다

all No
failonerror

에러 발생시 build 중단할지 여부를 나타낸다

all No
excludepackagenames 문서를 생성하지 않을 패키지를 컴마로 구분하여 지정한다ment. all No
defaultexcludes

기본적으로 제외되는 목록을 사용할 것인지 여부를 나타낸다

all No
useexternalfile

명령줄을 간단히하기위해 임시파일에 기록된 소스파일명을 지정한다

기본값은 No

all No
source

j2se 1.4 소스코드에 나타난 주장을 처리하도록 javadoc에서 설정한다

1.4+ No
linksource

소스파일에 hyperlinks 생성한다

기본값은 No

(ant 1.6이후)

1.4+ No
breakiterator

새로운 breakiterator 알고리즘을 사용한다 기본값은 No

(ant 1.6이후)

1.4+ No
noqualifier

-noqualifier 옵션을 설정한다

(ant 1.6이후)

1.4+ No
includenosourcepackages

"true"이면 자바소스가 아닌 패키지된 html을 가지고 문서 생성이 한다

(ant 1.6.3이후)

all No (default is false)
executable

실행될 javadoc 위치를 지정한다

(ant 1.6이후)

all No


3. <war>

개요

-. 웹 어플리케이션 배포 파일인 war 파일을 생성해 준다


사용예제


thirdparty/libs/jdbc1.jar
thirdparty/libs/jdbc2.jar
build/main/com/myco/myapp/Servlet.class
src/metadata/myapp.xml
src/html/myapp/index.html
src/jsp/myapp/front.jsp
src/graphics/images/gifs/small/logo.gif
src/graphics/images/gifs/large/logo.gif


위의 파일을 WAR로 구성해 보자


<war destfile="myapp.war" webxml="src/metadata/myapp.xml">
  <fileset dir="src/html/myapp"/>
  <fileset dir="src/jsp/myapp"/>
  <lib dir="thirdparty/libs">
    <exclude name="jdbc1.jar"/>
  </lib>
  <classes dir="build/main"/>
  <zipfileset dir="src/graphics/images/gifs"
              prefix="images"/>
</war>


WAR task 후 다음과 같이 구성된다


WEB-INF/web.xml
WEB-INF/lib/jdbc2.jar
WEB-INF/classes/com/myco/myapp/Servlet.class
META-INF/MANIFEST.MF
index.html
front.jsp
images/small/logo.gif
images/large/logo.gif



속성

속성 설명 필수여부
destfile 생성될 WAR 파일 지정 둘중 하나는 필수
warfile Deprecated
webxml 사용할 deployment descriptor (WEB-INF/web.xml)를 지정 Yes
basedir jar파일로 압축할 디렉토리를 지정한다 No
compress

data를 압축할지 여부를 나타내며 기본값은  true이다

keepcompression 속성을 false로 했을지라도 이는 적용된다

No
keepcompression

이미 존재하는 파일 묶음에 대해 compress을 계속 유지할 것인지 여부를 나타내며 기본값은 fale 이다

(ant 1.6이후)

No
encoding

압축될 파일명에 사용할 encoding을 지정한다

기본값은 UTF8

No
filesonly

Store only file entries

기본값은 false

No
includes 지정된 컴마나 스페이스로 구분된 파일 패턴을 WAR에 포함하며 생략하면 모든 파일을 WAR한다 No
includesfile 지정된 개개의 파일을 WAR에 포함한다 No
excludes 지정된 컴마나 스페이스로 구분된 파일 패턴을 WAR에서 제외시키며 생략하면 어떠한 파일로 제외하지 않는다 No
excludesfile 지정된 개개의 파일을 WAR에서 제외시킨다 No
defaultexcludes 기본적으로 제외시키는 기능을 사용할것인지 여부를 나타낸다 No
manifest 사용할 manifest 파일을 지정한다 No
update 이미 존재하는 파일이라면 업데이트할지 덮어쓸지를 결정하며 기본값은 false이다 No
duplicate

중복된 파일이 나타났을 때 "add"할지 "preserve"할지 혹은 "fail"할지를 지정하며 기본값은 "add"이다

No
roundup

파일 시간 비교시 파일 변경 시간을 다음 짝수 횟수의 초(seconds)에 반올림 할지 혹은 내림할지 여부를 나타낸다

기본값은 true
(ant 1.6.2 이후)

No


from http://ant.apache.org/manual/index.html


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형



 

I. Welcom to Lucene !


  Lucene 은 자바로 구현된 고성능의 풀텍스트 검색엔진입니다

  Lucene 이 제공하는 API를 사용하여 강력하고 유연한 검색기능을 어플리케이션에 손쉽게 추가할 수 있습니다

  Lucene은 2005년 2월에 Apache top-level 로 등급이 상승하였고

  서브 프로젝트인 Nutch 또한 2005년 6월에 Apache Incubator를 졸업하였습니다


  Lucene는 다음 3가지 software를 포함하고 있습니다

  Lucene java : Lucene의 핵심 부분으로 indexing 과 search 구현 영역입니다

  Nutch : web search application을 지원합니다 (이슈!)

                 mp3, pdf, ms 등 다양한 문서를 검색할수 있도록 제공해 주지만

                 아직까지는 0.6 버젼이네요

  Lucene4c :  Lucene의 C 기반의 검색엔진입니다 아직까진 Incubator에 있군요


  이번 강좌에서는 Lucene java 함 뒤벼보고 웹에다 Lucene을 달아봅시다 ^^


  강좌 진행 순서는 "데모I 프로그램(어플리 케이션) -> 데모II 프로그램(웹 어플리케이션) -> 데모II 프로그램 수정" 순으로 갑니다


  ps. 한글검색이 가능하지만 한글 형태소 분석을 아직까지는 지원하지 않기 때문에

       한글은 단순검색으로 만족해야 합니다.

       하지만 영문은 기똥차게 잘됩니다



II. Download


  lucene 다운로드

  http://www.apache.org/dyn/closer.cgi/jakarta/lucene/binaries/


  참고 사이트

  http://lucene.apache.org/

  http://lucene.apache.org/java/docs/api/index.html

  http://lucene.apache.org/java/docs/index.html

  http://today.java.net/pub/a/today/2003/11/07/QueryParserRules.html

  http://www-128.ibm.com/developerworks/library/j-lucene/

  http://www.onjava.com/pub/a/onjava/2003/03/05/lucene.html




III. 설치


  그럼 이제 Lucene에 한번 빠져 봅시다~!

  다운받은 lucene-1.4.3.zip 파일을 C:\에 압축을 풉니다




  압축을 풀면 lucene-1.4.3.jarlucene-demos-1.4.3.jar 파일을 클래스 패스에 겁니다



C:\Documents and Settings\Administrator>cd c:\

C:\>cd lu*

C:\lucene-1.4.3>set classpath=C:\lucene-1.4.3\lucene-1.4.3.jar;C:\lucene-1.4.3\lucene-demos-1.4.3.jar


C:\lucene-1.4.3>set
ALLUSERSPROFILE=C:\Documents and Settings\All Users
ANT_HOME=C:\java\Jeus42\lib\etc\ant
APPDATA=C:\Documents and Settings\Administrator\Application Data
CLASSPATH=C:\lucene-1.4.3\lucene-1.4.3.jar;C:\lucene-1.4.3\lucene-demos-1.4.3.jar

...



  "set" 명령으로 확인합니다

  설치 끝 ~



IV. 데모I 실행하기


  Lucene 데모에는 두가지 데모가 있습니다

  하나는 일반적인 인덱싱, 및 검색이고 다른 하나는 웹에서 사용하기 위한 인덱싱 및 웹검색입니다


1) 데모I 실행


먼저 네이버나 야후같은 웹 검색엔진을 생각해 봅시다
수도없이 많은 문서들이 어떻게 해서 그렇게 빠릴 검색될까요?
바로 검색 전처리 작업을 하기 때문입니다
예를들어 간단하게 보자면 "love"라는 단어는 A문서, B문서, C문서에 포함되어 있다라는 정보를 미리 만들어 두는 것입니다
즉 인덱스를 만들어 두는 것이지요
그리고 웹로봇들이 문서를 수집해오면 추가된 문서들에 대해 하루에 몇번씩 배치작업으로 인덱스를 추가해 주겠지요
결과적으로 "love" 검색시 인덱스 정보를 뒤져서 A문서, B문서, C문서의 결과를 보여주는 겁니다


lucene도 마찬가지 입니다 인덱스를 먼저 만들어 주어야 합니다
먼저 일단 데모프로그램을 이용하여 인덱스를 만들어 보고 이를 이용하여 검색해 봅시다
내부 코딩은 일단 실행 이후에 살펴봅시다 ^_^ (눈에 먼저 보여야 멀 해도 잘되죵)


C:\lucene-1.4.3\src\ 는 데모을 위한 자바소스 파일입니다


 

인덱스 생성하기
다음 명령으로 인덱스를 생성해 봅시다
인덱스 생성 어플리케이션은 IndexFiles.java 이며 파라미터는 인덱스를 만들 소스파일들(검색대상파일들) 입니다
여기서는 lucene의 document를 index 처리해 보겠습니다


C:\lucene-1.4.3>
C:\lucene-1.4.3>java org.apache.lucene.demo.IndexFiles C:\lucene-1.4.3\docs
adding C:\lucene-1.4.3\docs\api\allclasses-frame.html
adding C:\lucene-1.4.3\docs\api\allclasses-noframe.html
adding C:\lucene-1.4.3\docs\api\constant-values.html
adding C:\lucene-1.4.3\docs\api\deprecated-list.html
adding C:\lucene-1.4.3\docs\api\help-doc.html
adding C:\lucene-1.4.3\docs\api\index-all.html
adding C:\lucene-1.4.3\docs\api\index.html
adding C:\lucene-1.4.3\docs\api\org\apache\lucene\analysis\Analyzer.html
...
18500 total milliseconds
C:\lucene-1.4.3>


야호~ 인덱스가 생성되었습니다



C:\lucene-1.4.3\index 풀더를보면 다음 파일들이 생성된 것을 알수있습니다


검색하기
검색 어플리케이션은 SearchFiles.java 이며 실행 후 Query: 에 검색할 단어를 입력해 봅시다

C:\lucene-1.4.3>
C:\lucene-1.4.3>java org.apache.lucene.demo.SearchFiles
Query: lucene
Searching for: lucene
324 total matching documents
0. C:\lucene-1.4.3\docs\api\allclasses-frame.html
1. C:\lucene-1.4.3\docs\api\allclasses-noframe.html
2. C:\lucene-1.4.3\docs\api\index-all.html
3. C:\lucene-1.4.3\docs\api\overview-frame.html
4. C:\lucene-1.4.3\docs\api\overview-tree.html
5. C:\lucene-1.4.3\docs\api\org\apache\lucene\queryParser\MultiFieldQueryParser.html
6. C:\lucene-1.4.3\docs\lucene-sandbox\index.html
7. C:\lucene-1.4.3\docs\resources.html
8. C:\lucene-1.4.3\docs\api\org\apache\lucene\search\class-use\Query.html
9. C:\lucene-1.4.3\docs\api\org\apache\lucene\index\class-use\Term.html
more (y/n) ?


와~ 성공! 엄청 빠릅니다!!

검색결과가 10개씩 리스팅되며 다음 리스트는 y버튼을 클릭하여 조회 할수 있습니다



2) 데모I 인덱싱 코드 분석

이 데모 프로그램은 가장 기본이 되는 프로그램으로 핵심 코딩만 되어 있으니 lucene을 사용하기 위해서는 꼭 알아 두어야 합니다


Analyzer 선택

Analyer 는 문서를 인덱싱 하거나 검색할때 핵심이 되는 요소로서, 텍스트를 파싱할 때 사용합니다 Analyzer의 종류에는 다음 몇가지 들이 있습니다


SimpleAnalyzer

  non-letters 를 기준으로 문자를 파싱합니다
  non-letters는 java.lang.Character.isLetter()에 의해 정의된 것을 사용합니다
  이 Analyzer는 대부분의 유럽권 언어에 적당하며 아시아권 언어에는 terrible 이라고 되어 있군요 -_-;
  대소문자 구분 안합니다


StopAnalyzer

  기본적으로 SimpleAnalyzer와 같으나 StopFilter를 두어 StopWord를 제거한 후 분석합니다
  StopWord란 일반적으로 검색시 유용하지 않는 단어들을 말합니다
  (a,an,and,are,as,at,be,but,by,for,if,in,into,is,it,no,not,of,on,or,s,such,t,that,the,their,then,there,these,they,this,to,was,will,with) 역시나 대소문자 구분 안합니다


StandardAnalyzer 

  대부분 유렵권 언어들에 최적화 되어있는 Analyzer 입니다
  StopFilter를 사용하며 대소문자 구분 안합니다


WhitespaceAnalyzer 

  whitespace, 즉 공백문자를 가지고 text를 나누는 방식입니다
  가장 기본적이면서도 무식한 방식입니다
  불행히도 한글검색은 이 WhitespaceAnalyzer 만 가능하며 대소문자 구분 합니다

  (왜 이것만 대소문자 구분 하냥 -_-)


이밖에도 GermanAnalyzer, PerFieldAnalyzerWrapper, RussianAnalyzer등이 있으며
이름에서도 알수있듯이 그다지 한글과 친하지 않은듯 합니다 -.-;;


IndexWriter 생성
자 이제 Analyer를 선택했으면 IndexWriter를 생성하여 Index를 만들어봅시다


IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);


첫번째 파라미터는 index가 생성될 위치를 말하며
두번째 파라미터는 선택한 Analyzer를,
세번째 파라미터는 index를 초기화 하여 다시 생성할것인지 말것인지를 말합니다
즉 추가/삭제만 할 것인지(false) 새로 만들것인지(true)를 나타냅니다
문서가 많을경우 매번 새로 만들수 없으며,
또한 만약 몇개의 문서만 변경되었는데 모두 다시 인덱스를 만들수는 없기 때문입니다 (시간 상당히 걸림 --)


Index에 document 추가
다음으로 소스 디렉토리(검색대상 문서들)의 파일들을 읽어가며 Analyzer에 의해 파싱된 문서 정보를 인덱스에 추가합니다


writer.addDocument(FileDocument.Document(file));


index optimize
마지막으로 인덱싱한 정보를 하나의 파일로 merge 합니다
즉 검색에 적합하도록 파일을 하나로 합치는 겁니다


writer.optimize();


index close

사용후 받드시 close 합시다!


writer.close();


끝~ 간단하죠?

이제 전체 소스를 살펴봅시다

소스는 C:\lucene-1.4.3\src\demo\org\apache\lucene\demo 에 있습니다


org.apache.lucene.demo.IndexFiles.java


class IndexFiles {


  public static void main(String[] args) throws IOException {

    String usage = "java " + IndexFiles.class + " <root_directory>";
   
    // 파라미터(소스디렉토리)를 입력하지 않았다면 사용법을 출력해 줍니다
    if (args.length == 0) {
      System.err.println("Usage: " + usage);
      System.exit(1);
    }

    Date start = new Date();
    try {
   
      // 선택한 Analyzer를 이용하여 IndexWriter를 생성합니다
      IndexWriter writer = new IndexWriter("index", new StandardAnalyzer(), true);
     
      // 소스디렉토리를 디비가며 문서를 파싱하여 인덱스에 추가하는 재귀함수
      indexDocs(writer, new File(args[0]));

      // 인덱싱한 여러 segment들을 검색에 알맞도록 하나로 합치는 작업
      writer.optimize();
     
      // 반드시 close()
      writer.close();

      Date end = new Date();

      // 인덱싱 처리시간 출력
      System.out.print(end.getTime() - start.getTime());
      System.out.println(" total milliseconds");

    } catch (IOException e) {
      System.out.println(" caught a " + e.getClass() +
       "\n with message: " + e.getMessage());
    }
  }


  // 소스 파일들을 읽어가며 파싱하여 인덱스에 추가하는 재귀함수
  public static void indexDocs(IndexWriter writer, File file)
    throws IOException {


    if (file.canRead()) {
      if (file.isDirectory()) {
        String[] files = file.list();


        if (files != null) {
          for (int i = 0; i < files.length; i++) {
            // 자기자신을 호출
            indexDocs(writer, new File(file, files[i]));
          }
        }
      } else {
        System.out.println("adding " + file);
        try {
          // 문서를 인덱스에 추가

          // FileDocument는 해당 file의 정보를 파싱해줌
          writer.addDocument(FileDocument.Document(file));
        }
       
        // 윈도에서 temporary filese등이 access denied로  exception이 발생할 수 있음
        catch (FileNotFoundException fnfe) {
          ;
        }
      }
    }
  }
}



3) 데모I 검색 코드분석
검색은 인덱스를 만드는 코드보다 훨씬 쉽습니다


IndexSearcher 생성
실질적으로 검색을 담당할 IndexSearcher를 생성해 봅시다
파라미터로는 index가 생성되어있는 위치를 입력합니다


Searcher searcher = new IndexSearcher("index");


Query 생성
Query는 질의 문자열을 파싱해 줍니다 (즉 AND,OR,NOT,!,-등의 논리연산이나 와일드카드 *,?등을 파싱합니다)


Query query = QueryParser.parse(line, "contents", analyzer);


첫번째 파라미터는 질의를,
두번째 파라미터는 검색 필드를,
세번째 파라미터는 인덱스를 만든 Analyzer와 동일한 Analyzer를 입력해 줘야 합니다


검색 및 검색한 결과 저장

파싱된 쿼리를 가지고 검색하여 그 결과값을 반환 받습니다


Hits hits = searcher.search(query);


반환된 Hits 클래스는 순위가 매겨진 문서들로 검색결과를 저장하고 유지합니다


IndexSearcher close
검색이 끝났으면 닫아줍시다


searcher.close();


전체 소스를 살펴봅시다


org.apache.lucene.demo.SearchFiles.java

class SearchFiles {


  public static void main(String[] args) {
    try {


      // index 폴더를 파라미터로 넘겨 IndexSearcher를 생성합니다
      Searcher searcher = new IndexSearcher("index");
     
      // 생성된 index와 동일한 Analyzer를 생성하여 넘겨줍니다
      Analyzer analyzer = new StandardAnalyzer();


      // 검색어를 입력받기 위한 reader 입니다
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));


      while (true) {
        System.out.print("Query: ");
        String line = in.readLine();
       
        if (line.length() == -1)
          break;


        // 입력받은 질의를 파싱합니다
        Query query = QueryParser.parse(line, "contents", analyzer);
        System.out.println("Searching for: " + query.toString("contents"));


        // 팡싱된 질의로 검색을 합니다       
        Hits hits = searcher.search(query);
        System.out.println(hits.length() + " total matching documents");
       
        // 검색 결과 목록을 10개씩 보여줍니다
        final int HITS_PER_PAGE = 10;
        for (int start = 0; start < hits.length(); start += HITS_PER_PAGE) {
          int end = Math.min(hits.length(), start + HITS_PER_PAGE);
          for (int i = start; i < end; i++) {


            // 검색 결과로 부터 문서를 가져옵니다
            Document doc = hits.doc(i);

            // 문서정보를 출력합니다

            String path = doc.get("path");
            if (path != null) {
                  System.out.println(i + ". " + path);
            } else {
                  String url = doc.get("url");
              if (url != null) {
                System.out.println(i + ". " + url);
                System.out.println("   - " + doc.get("title"));
              } else {
                System.out.println(i + ". " + "No path nor URL for this document");
              }
            }
          }


          if (hits.length() > end) {
            System.out.print("more (y/n) ? ");
            line = in.readLine();
            if (line.length() == 0 || line.charAt(0) == 'n')
              break;
          }
        }
      }
     
      searcher.close();
       
    } catch (Exception e) {
      System.out.println(" caught a " + e.getClass() +
         "\n with message: " + e.getMessage());
    }
  }
}



V. 질의 문법

질의 문법에 대해 알아봅시다


A AND B

    A와 B가 모두 포함된 문서를 검색한다

A OR B

    A혹은 B가 포함된 문서를 검색한다

A NOT B

    A는 포함되고 B는 포함되지 않는 문서를 검색한다

    A ! B, A - B와 동일하다

+A OR B

    A OR B에서 A는 받드시 포함된 문서를 검색한다

A*

    A로 시작하는 단어가 있는 문서를 검색한다

A?

    A로 시작하는 두글자의 단어가 있는 문서를 검색한다

A~

    A와 스펠링이 비슷한 글자를 지닌 단어가 있는 문서를 검색한다

(A OR B) AND C

    논리연산의 그루핑 또한 지원한다


AND, OR, NOT등은 반드시 대문자로 입력해야 인식됩니다


다음 시간에는 두번째 데모 프로그램을 실행시켜 보고 lucene을 웹 어플리케이션에 달아 봅시다~


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형

Jakarta Ant


I. Ant 야 놀자~

Ant 란 "Java 기반의 빌드 도구입니다" 라고들 많이 나와있습니다
근데 이게 대체 무순 뜻이란 말인가 ㅡ.ㅡ;


쉽게 예기해서 환경에 구애받지 않고 간단히 java 소스를 컴파일 하고 필요한 파일이 있다면
그 파일들을 복사나 삭제하며 또한 javadoc 이나 war 같은 배포용 파일까지 생성해 주며
필요하다면 서버에 까지 바로 적용할 수 있도록 도와주는 도구입니다.


또한 여러팀원들이 프로젝트를 진행할 때 새로운 팀원이 참가하더라도
Ant 설정파일을 공유함으로써 손쉽게 참여가 가능하다는 것입니다


아직 사용해 보지 않았다면 얼렁 익혀서 사용해봅시다 무~지 편하답니다



II. 설치해보자
다운로드
Ant

http://ant.apache.org/bindownload.cgi

Ant manual

http://ant.apache.org/manual/index.html

http://ant.apache-korea.org/manual/index.html


다운받은 파일의 압축을 풀고 환경변수 및 패스를 잡아줍니다
set ANT_HOME=c:\ant
set JAVA_HOME=c:\jdk1.4.2
set PATH=%PATH%;%ANT_HOME%\bin



III. 간단한 Ant 예제

Ant를 이용하여 web application을 구성할 때 다음의 구조를 유지하기를 권장합니다


build : src, web, docs에서 결과적으로 만들어진 산출물 디렉토리
dist : build를 배포하기 위한 배포 디렉토리
docs : 배포판에 배포할 정적인 문서를 관리할 디렉토리
src : /WEB-INF/classes 에 위치할 java 소스 디렉토리
web : HTML, JSP, 이미지등의 컨텐트 디렉토리 (WEB-INF의 서브디렉토리 포함)
build.properties : build.xml에서 사용할 properties
build.xml : ant 명령으로 실행될 설정파일


src에 하나이상의 java 소스를 테스트로 넣어 놓으세요

자 이렇게 디렉토리를 설정하고 build.xml 을 다음 step에 따라 따라 해 BOA요 ^^&


STEP 1. build.xml 의 기본구조

xml을 기본적인 내용을 안다면 이해하기 쉽습니다

<project name="My Project" default="compile" basedir=".">

 <target name="clean">

   여러 작업

  </target>


  <target name="prepare" depends="clean">

   여러 작업

   </target>


   <target name="compile" depends="prepare">

    여러 작업

    </target>

</project>

하나의 build 파일은 하나의 project로 구성되며 이는 다시 여러 target으로 구성됩니다

target 이란 빌드 과정중 수행해야 할 task들을 모아놓은 job 단위 라고 보면 됩니다

compile target이라 한다면 compile에 관련된 작업들을 모아놓은 그룹이라 생각하면 쉽게 이해 될겁니다


STEP 2. 시~작 Ant 맛보기~
① build.xml에 다음을 입력한 후 저장 합니다

<project name="Unicorn Project" default="clear" basedir=".">
  <description>Simple Test</description>
 
  <property file="${basedir}/build.properties"/>
 
  <echo message="${catalina.home}"/>


   <target name="clear"/>
   
</project>

-. project

    project는 하나 이상의 target을 정의 합니다 또한 하나의 target은 task의 집합입니다

    ant를 실행할 시에 어느 타겟을 실행할 것인지 지정할 수가 있으며 (예: \ant clear)

    지정하지 않았을 경우 디폴트로 설정된 값이 사용됩니다 이부분이 default="clear"입니다

-. property

    전역변수 설정 혹은 그렇게 사용할 build.properties를 정의 합니다

    build.properties에 catalina.home을 정의하였으며 여러 환경이 변하더라도 이 값만

    변경해주면 build.xml을 수정없이 바로 실행 가능합니다

-. echo

    message 내용을 출력 합니다

-. target

    target 이란 task의 집합으로 실질적으로 실행될 코드들의 묶음입니다

    여기서는 아무 task도 없습니다


② build.properties에 다음을 입력 후 저장합니다

catalina.home=C:\Tomcat 5.0

catalina.home 은 변수로 사용할 것이며 그 값은 C:\Tomcat 5.0입니다


③ 실행

해당 디렉토리로 이동하여 도스창에서 ant 라고 칩니다

c:\예제\ant

Buildfile : build.xml

      [echo] c:\Tomcat 5.0


clear :


BUILD SUCCESSFUL

Total time : 0 seconds


STEP 3. 사전작업 하기~

이번 단계에서는 컴파일 하기전 전역변수 선언이나 컴파일 시 클래스 패스 설정을 해봅시다


① build.xml

<project name="Unicorn Project" default="prepare" basedir=".">
  <description>Simple Test</description>

  <property file="${basedir}/build.properties"/>


  <property name="app.name"      value="unicorn"/>
  <property name="app.path"       value="/${app.name}"/>
  <property name="app.version"   value="0.1-dev"/>

  <property name="build.home"    value="${basedir}/build"/>
  <property name="dist.home"     value="${basedir}/dist"/>
  <property name="docs.home"   value="${basedir}/docs"/>
  <property name="src.home"      value="${basedir}/src"/>
  <property name="web.home"     value="${basedir}/web"/>  


  <path id="compile.classpath">

    <pathelement location="${catalina.home}/common/classes"/>
    <fileset dir="${catalina.home}/common/endorsed">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${catalina.home}/common/lib">
      <include name="*.jar"/>
    </fileset>
    <pathelement location="${catalina.home}/shared/classes"/>
    <fileset dir="${catalina.home}/shared/lib">
      <include name="*.jar"/>
    </fileset>
    <fileset dir="${web.home}/WEB-INF/lib">
      <include name="*.jar"/>
    </fileset>
  </path>


  <target name="clean"
   description="Delete old build and dist directories">
    <delete dir="${build.home}"/>
    <delete dir="${dist.home}"/>
  </target>
 
  <target name="prepare" depends="clean">

    <mkdir dir="${build.home}"/>
    <mkdir  dir="${build.home}/WEB-INF"/>
    <mkdir  dir="${build.home}/WEB-INF/classes"/>
    <mkdir  dir="${build.home}/WEB-INF/lib"/>
   
    <copy todir="${build.home}">
       <fileset dir="${web.home}">
         <include name="**/*.jsp"/>
         <include name="**/*.css"/>
         <include name="**/*.html"/>
         <include name="**/*.js"/>
         <include name="**/*.jpg"/>
         <include name="**/*.gif"/>
         <include name="**/*.swf"/>
         <include name="**/*.xml"/>
         <include name="**/*.tld"/>
         <include name="**/*.jar"/>

       </fileset>
     </copy>

   </target>  

   
</project>

-. project

    이번에는 default 값을 prepare로 하였습니다 고로 target은 prepare가 실행될 것입니다

-. property

    역시나 build.properties를 정의하였고 여러 전역변수를 설정하였습니다

    build.home 이란 변수에는 ${basedir}/build 값이 정의되었으며

    build.home은 ${build.home}으로 사용할수 있습니다

    궁금하면 <echo message="${build.home}"/> 등으로 출력해 봅시다~

-. path

    ${catalina.home} 은 build.properties에서 정의하였다는것을 기역하실겁니다

    fileset은 파일들의 집합을 나타내는데 어떤 특정파일만 포함 할수 있거나 혹은 어느 특정파일만 제외할 수 있습니다

    특정파일만 포함하는것은 include 태그이며 그 반대는 exclude 입니다

    <fileset dir="${web.home}/WEB-INF/lib">
      <include name="*.jar"/>
    </fileset>

    이부분은 ${web.home}/WEB-INF/lib 에서 *.jar 파일만 클래스패스로 잡겠다는 의미입니다

-. target

   드디어 실질적으로 실행될 target 입니다.

   project 속성의 default가 prepare이므로 prepare target으로 실행하기 위해 가보니  depend 속성으로 "clean"이 설정되어 있습니다

  이것은 "clean" target을 먼저 실행 후 prepare를 실행하라는 말입니다

   즉 prepare는 clean이 실행조건 입니다

   clean target은 delete 태그를 이용하여 배포할 dist 디렉토리와 산출물 디렉토리인 build를 삭제하는 작업입니다
   prepare target으로 다시 와보면 mkdir 는 당연히 디렉토리를 만들라는 뜻입니다

   copy는 todir에 다음 web.home의 모든 fileset을 copy 하라는 의미입니다 여기서도 역시나 include, exclude가 사용될 수 있겠지요

   <include name="**/*.jsp"/> 는 모든디렉토리의 *.jsp 를 카피하라는 의미입니다

    즉 web 디렉토리의 모든 실행 가능할 파일을 build로 옮기는 작업입니다


② 실행

c:\예제\ant

Buildfile : build.xml


clean :

     [delete] : Deleting directory c:\예제\build

     [delete] : Deleting directory c:\예제\dist


prepare :

     [mkdir] Created dir : c:\예제\build\WEB-INF

     [mkdir] Created dir : c:\예제\build\WEB-INF\classes

     [mkdir] Created dir : c:\예제\build\WEB-INF\lib

     [copy] Copying 2 files to Deleting directory c:\예제\build


BUILD SUCCESSFUL

Total time : 1 seconds


STEP 4. 컴파일 하기

이제 컴파일할 모든 준비가 되었습니다

STEP2의 소스에 다음 target을 추가하고 project의 default 값을 compile로 수정한 후 실행해 봅시다


 <target name="compile" depends="prepare"
   description="Compile Java sources">


    <!-- Compile Java classes as necessary -->
    <javac srcdir="${src.home}"
          destdir="${build.home}/WEB-INF/classes">
        <classpath refid="compile.classpath"/>
    </javac>


    <!-- Copy application resources -->
    <copy  todir="${build.home}/WEB-INF/classes">
      <fileset dir="${src.home}" excludes="**/*.java"/>
    </copy>
   
 </target>

-. target

   depends가 prepare이므로 실행 순서는 clean, prepare, compile 입니다

   javac 태스크는 srcdir 인 소스디렉토리에 있는 자바소스를 desdir 쪽으로 컴파일 합니다

   classpath는 위에서 이미 설정한 compile.classpath를 사용합니다

   그 후 properties등 같은 기타 resource 들을 /WEB-INF/classes에 복사합니다

② 실행

c:\예제\ant

Buildfile : build.xml


clean :

     [delete] : Deleting directory c:\예제\build

     [delete] : Deleting directory c:\예제\dist


prepare :

     [mkdir] Created dir : c:\예제\build\WEB-INF

     [mkdir] Created dir : c:\예제\build\WEB-INF\classes

     [mkdir] Created dir : c:\예제\build\WEB-INF\lib

     [copy] Copying 2 files to Deleting directory c:\예제\build


compile :

     [javac] Compileing 1 source file to c:\예제\build\WEB-INF\classes

     [copy] Copying 1 file to c:\예제\build\WEB-INF\classes


BUILD SUCCESSFUL

Total time : 1 seconds


STEP 5. Javadoc 을 이용해 API를 만들어 보고 배포파일도 생성해 보자

이제 컴파일도 했으니 javadoc도 만들어 보고 war 같은 배포파일도 생성해 봅시다

STEP 3.까지의 build.xml에 아래 target을 더 추가하고 project의 default 값에 dist로 설정합니다

① build.xml

 <target name="javadoc" depends="compile"
    description="Create Javadoc API documentation">

     <mkdir dir="${dist.home}/docs/api"/>
     <javadoc sourcepath="${src.home}"
                  destdir="${dist.home}/docs/api"
                   packagenames="*">
       <classpath refid="compile.classpath"/>
     </javadoc>

   </target>


 <target name="dist" depends="compile,javadoc"
   description="Create binary distribution">

    <mkdir dir="${dist.home}/docs"/>

    <copy  todir="${dist.home}/docs">
      <fileset dir="${docs.home}"/>
    </copy>


    <jar jarfile="${dist.home}/${app.name}-${app.version}.war"
         basedir="${build.home}"/>

  </target>

-. target

   target의 실행순서는 clean, prpare, compile, javadoc, dist가 될겁니다

   javadoc target의 javadoc 태스트를 보면 java 소스가 있는 소스디렉토리와

   API를 생성할 타겟 디렉토리를 정해주면 알아서 API를 생성해 줍니다

   만들어진 API는 배포버젼의 dist디렉토리로 해주면 더 좋겠지요


   dist target은 배포파일인 war를 만듭니다

   필요한 문서가 있으면 docs 디렉토리를 만들어 로 복사도 하도록 합시다

   jar 태스크는 위의 방식과 같이 사용합니다


② 실행

c:\예제\ant

Buildfile : build.xml


clean :

     [delete] : Deleting directory c:\예제\build

     [delete] : Deleting directory c:\예제\dist


prepare :

     [mkdir] Created dir : c:\예제\build\WEB-INF

     [mkdir] Created dir : c:\예제\build\WEB-INF\classes

     [mkdir] Created dir : c:\예제\build\WEB-INF\lib

     [copy] Copying 2 files to Deleting directory c:\예제\build


compile :

     [javac] Compileing 1 source file to c:\예제\build\WEB-INF\classes

     [copy] Copying 1 file to c:\예제\build\WEB-INF\classes


javadoc :

     [mkdir] Created dir : c:\예제\dist\docs\api

     [javadoc] Generating Javadoc

     [javadoc] Javadoc execution

     [javadoc] Loading source files for package com.jakartaproject.db...

     [javadoc] Constructing Javadoc information...

     [javadoc] Standard Doclet version 1.4.1

     [javadoc] Building tree for all the packages and classes...

     [javadoc] Building index for all the packaes and classes...

     [javadoc] Building index for all classes...


dist :

     [jar] Building jar :Created dir : c:\예제\dist\unicorn-0.1-dev.war


BUILD SUCCESSFUL

Total time : 3 seconds



VI. Ant 실행

C:\예제\ant -help

ant [options] [target [target2 [target3] ...]]


Options :
  -help                    이 메세지의 표시
  -projecthelp           프로젝트 도움 정보의 출력
  -version                버전 정보의 출력과 종료
  -diagnostics           diagnose 나 report 문제에  도움이 되는 정보의 출력.
  -quiet, -q              한층 더 메세지를 적게
  -verbose, -v          한층 더 메세지를 많게
  -debug                 디버그 정보의 출력
  -emacs                 adornments 없이 로그 정보의 생성(produce)
  -logfile <file>         로그를 지정 파일에 출력
    -l     <file>                ''
  -logger <classname>    로그 생성을 실행하기 위한 클래스
  -listener <classname>  프로젝트 청취자(listener) 역할의 class의 인스턴스를 추가
  -buildfile <file>            지정된 빌드 파일의 사용
    -file    <file>              ''
    -f       <file>              ''
  -D<property>=<value> 지정된 프로퍼티의 값의 사용
  -propertyfile <name>    모든 프로퍼티를 파일로부터 로드  (-D프로퍼티보다 전에)
  -inputhandler <class>  입력 요청(requests)를 취급하는 클래스
  -find <file>                 파일시스템의 루트로 향해 빌드파일을  검색하고 그것을 사용


C:\예제\ant

현재 디렉토리에 있는 build.xml 파일을 이용해, 디폴트 타겟으로 Ant 를 실행합니다.


C:\예제\ant compile

현재 디렉토리에 있는 build.xml이 실행되며 파라미터로 compile을 지정하면 project의 default 값을 무시하고 compile target을 실행합니다 물론 depends 가 있다면 먼저 실행합니다

 

C:\예제\ant -buildfile test.xml

현재 디렉토리에 있는 test.xml 파일을 이용해, 디폴트 타겟으로 Ant 를 실행합니다.


C:\예제\ant -buildfile test.xml dist

현재 디렉토리에 있는 test.xml 파일을 이용해, dist 라는 이름의 타겟으로 Ant 를 실행합니다.


C:\예제\ant -buildfile test.xml -Dbuild=build/classes dist

현재 디렉토리에 있는 test.xml 파일을 이용해, dist 라는 이름의 타겟으로, build 프로퍼티에 build/classes 값을 설정해 Ant 를 실행합니다.


VII. 기본 프로퍼티

Ant는 다음과 같은 프로퍼티를 기본으로 제공합니다

basedir : 기본 디렉토리 경로를 나타내며 project 태그의 basedir에 명시되어 있습니다

ant.file : 빌드 파일의 절대 경로입니다

ant.version : Ant 버젼을 나타냅니다

ant.project.name : project 태그의 name에 명시되어있습니다

ant.java.version : 자바 버젼을 나타냅니다

자바 시스템 프로퍼티를 사용 가능 합니다

   예) ${os.name} 참고 http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#getProperties()


<echo message="${ant.file}"/> 으로 한번 출력해 보면 이해가 쉽습니다


다음 시간에는 각 타스크의 종류와 상세 설정에 관해 알아봅시다


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형

Commons net


I. Commons net

Jakarta Commons의 net은 network utility collection입니다.

인터넷 프로토콜을 대부분지원하는 강력한 유틸리티로 사용이 쉽고 간결합니다.


클라이언트측의 기본적인 Internet protocol을 구현함으로서 고차원적인 abstract가 아닌 기본적인 프로토콜 access가 목적이기 때문에 부분적으로 object-orient 규칙에 위배되는 사항이 있다는것을 참고적으로 알자


Commons net이 지원하는 프로토콜은 다음과 같다

  • FTP
  • NNTP
  • SMTP
  • POP3
  • Telnet
  • TFTP
  • Finger
  • Whois
  • rexec/rcmd/rlogin
  • Time (rdate) and Daytime
  • Echo
  • Discard
  • NTP/SNTP

FTP의 경우 이전에는 sun 패키지의 FtpClient를 사용했지만 이제는 Commons net의 FTP를 사용해 봅시다


II. 준비물~

Commons net은 자체적으로 ORO를 사용합니다

Jakarta ORO란 파일이름의 치환, 분할, 필터링 등을 수행하기 위한 Perl5 호환 정규식, AWK와 같은 정규식, glob 표현, 그리고 유틸리티 클래스들을 제공하는 텍스트 처리 자바 클래스들입니다

 

Commons net http://jakarta.apache.org/site/downloads/downloads_commons-net.cgi

Jakarta ORO http://jakarta.apache.org/site/downloads/downloads_oro.cgi


참고자료

Commons net API http://jakarta.apache.org/commons/net/apidocs/index.html

Commons net http://jakarta.apache.org/commons/net/


III. org.apache.commons.net.ftp 의 흐름

sun 패키지의 FTPClient처럼 FTP여러 동작을 Commons net의 FTPClient로 구현해 보자


다음 ① ~ ⑦까지 목록은 필수항목으로 구현되어야 합니다.

논리적으로 보면 간단합니다

FTPClient 생성

먼저 가장 중심적인 역할을 하는 FTPClient를 생성합니다

FTPClient ftpClient = new FTPClient();


FTPServer에 Connect

서버에 연결을 합니다

ftpClient.connect(server);


응답이 정상적인지 확인 합니다

응답을 받아와서

int reply = ftpClient.getReplyCode();


정상적인지 확인해 봅니다
if (!FTPReply.isPositiveCompletion(reply)) {

    정상적이지 않으면 연결을 끊고 종료 합니다

    ftpClient.disconnect();


    System.out.println("FTP server refused connection.");

}  else {

    정상적이면 계속 진행 합니다
    System.out.println("Connect successful");

    ..

}


FTP Server 로그인

ftpClient.login(username, password);


여러가지 작업을 합니다

list, get, put...


FTP Server 로그아웃

ftpClient.logout();


FTP Server disconnect

ftpClient.disconnect();


IV. 사용예제 - 목록보기

본격적으로 FTP에 접속하여 목록을 가져오는 소스를 봅시다

FTPClient ftpClient = null;

try {

    ftpClient = new FTPClient();

    ftpClient.setControlEncoding("euc-kr");  // 한글파일명 때문에 디폴트 인코딩을 euc-kr로 합니다

    ftpClient.connect("user.chollian.net");  // 천리안 FTP에 접속합니다


   int reply = ftpClient.getReplyCode(); // 응답코드가 비정상이면 종료합니다
   if (!FTPReply.isPositiveCompletion(reply)) {
       ftpClient.disconnect();
       System.out.println("FTP server refused connection.");    

   } else {


       System.out.print(ftpClient.getReplyString());  // 응답 메세지를 찍어봅시다


       ftpClient.setSoTimeout(10000);  // 현재 커넥션 timeout을 millisecond 값으로 입력합니다
       ftpClient.login(username, password); // 로그인 유저명과 비밀번호를 입력 합니다

       // 목록보기 구현

       FTPFile[] ftpfiles = ftpClient.listFiles("/public");  // public 폴더의 모든 파일을 list 합니다
       if (ftpfiles != null) {
           for (int i = 0; i < ftpfiles.length; i++) {
               FTPFile file = ftpfiles[i];
               System.out.println(file.toString());  // file.getName(), file.getSize() 등등..

           }
       }

       ftpClient.logout();
   }

} catch (Exception e) {
   System.out.println(e);
   e.printStackTrace();
} finally {
   if (ftpClient != null && ftpClient.isConnected()) {
    try {
         ftpClient.disconnect();
    } catch (IOException ioe) {
         ioe.printStackTrace();
    }
}


목록보기 방법에는 한가지 방법이 더 있습니다

위의 코드는 해당 디렉토리내의 모든 파일을 가져오는 방법이며 다음 방법은 해당 디렉토리의 모든 파일을 정해진 수로 짤라 가져오는 방법이 있습니다.

위의 빨간색 코드대신 다음 코드가 들어갈 수 있습니다.


    int page = 1;
    FTPListParseEngine engine = ftpClient.initiateListParsing("/public"); // 목록을 나타낼 디렉토리
    while (engine.hasNext()) {
        FTPFile[] ftpfiles = engine.getNext(10); // 10개 단위로 끊어서 가져온다


        System.out.println("------------------------ "+page+" ------------------------");    

        if (ftpfiles != null) {
            for (int i = 0; i < ftpfiles.length; i++) {
                 FTPFile file = ftpfiles[i];
                 System.out.println(file.toString());
           }
        }
        System.out.println("------------------------ "+(page++)+" -------------------------");
    }


V. 사용예제 - get (파일 다운로드)

서버의 /public/테스트.txt 파일을 클라이언트의 C:\\Test\\테스트.txt 에 다운받는 예제

    File get_file = new File("C:\\Test\\테스트.txt");  
    OutputStream outputStream = new FileOutputStream(get_file);
    boolean result = ftpClient.retrieveFile("/public/테스트.txt", outputStream);

    outputStream.close();


VI. 사용예제 - put(파일 업로드)

클라이언트의 C:\\Test\\보내자.txt 파일을 서버의 /public/보내자.txt 에 업로드하는 예제

만일 서버에 이미 /public/보내자.txt 파일이 있다면 덮어쓰게 된다

    File put_file = new File("C:\\Test\\보내자.txt");
    inputStream = new FileInputStream(put_file);
    boolean result = ftpClient.storeFile("/public/보내자.txt", inputStream);
    inputStream.close();


VII. 사용예제 - append (파일업로드)

위의 예제와 같은 기능을 하지만 이미 파일에 동일한 파일이 있으면 false를 반환하면서 실행하지 않는다

    File append_file = new File("C:\\Test\\더해라.txt");
    inputStream = new FileInputStream(append_file);
    boolean result = ftpClient.appendFile("/public/더해라.txt", inputStream);
    inputStream.close();


VIII. 사용예제 - rename (파일 이름변경)

변경전 파일명과 변경할 파일명을 파라미터로 준다

     boolean result = ftpClient.rename("/public/바꾸기전파일.txt", "/public/바꾼후파일.txt");


IX. 사용예제 - delete (파일삭제)

삭제할 파일을 선택한다    

     boolean result = ftpClient.deleteFile("/public/test.txt");


X. 사용예제 - directory 생성

/public 에 oops 디렉토리를 생성한다

     boolean result = ftpClient.makeDirectory("/public/oops");


XI. 사용예제 - OS 커맨드 입력하기

/public 에 oops 디렉토리를 생성한다

ftpClient.sendCommand(FTPCommand.MAKE_DIRECTORY, "/public/oops");


sendCommand 함수에 FTPCommand의 실행할 OS명령을 static 멤버변수를 넘겨준다


XII. 사용예제 - 작업디렉토리 설정하기

작업디렉토리를 /public 설정한 후 oops 디렉토리를 설정한다 (위의 예제와 비교해보라!)

ftpClient.changeWorkingDirectory("/public");

boolean result = ftpClient.makeDirectory("oops"); // /public/oops 절대경로를 적지 않아도 된다


XIII. 사용예제 - 파일 및 전송형태 설정

파일 형태 설정

ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

파일 타입

FTP.BINARY_FILE_TYPE, FTP.ASCII_FILE_TYPE, FTP.EBCDIC_FILE_TYPE, FTP.IMAGE_FILE_TYPE , FTP.LOCAL_FILE_TYPE

이 값을 설정하지 않으면 디폴트는 ASCII 이다


전송 형태 설정

ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);

전송 타입

FTP.BLOCK_TRANSFER_MODE, FTP.COMPRESSED_TRANSFER_MODE  

이값을 설정하지 않으면 디폴트는 FTP.STREAM_TRANSFER_MODE 이다



XIV. FTP접속시 글목록이 보이지 않는경우 아래 URL을 참고하세요


Jakarta Commons Net 에서 FTP 사용시 목록이 안보일 경우

http://www.jakartaproject.com/article/jakarta/1132032615162


목록이 안보일 경우 해결기 I탄

http://www.jakartaproject.com/article/jakarta/1135307924491


테스트한 파일을 첨부합니다 ^^


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================



Posted by 1010
반응형

Commons-Lang


VI. org.apache.commons.lang.builder.ToStringBuilder

toString()은 현 객체의 값을 문자열로 변환하여 반환 해주는 메소드로써 직접 구현할려면 노가다성 코드입니다.

하지만 Commons의 ToStringBuilder를 사용하면 는 말 그대로 클래스의 toString()을 쉽게 만들 수 있습니다.

웹에서는 빈클래스등에 toString을 구현하면 쉽게 디벙깅을 할 수 있습니다.



예제

ToStringTest.java

public class ToStringTest {


    public static void main(String args[]) {

        TestClass test = new TestClass();
        System.out.println(test.toString());
    }

}


TestClass.java

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;


public class TestClass {


    private String boardId;
    private int boardNo;


    public TestClass() {}


    public String toString() {
        return ToStringBuilder.reflectionToString(this);

    }


}


(1) refrectionToString 함수


public String toString() {
    return ToStringBuilder.reflectionToString(this);

}


reflectionToString은 static함수로써 위와같이 사용하며 파라미터로 스타일을 지정할 수 있습니다. 아래 코드를 봅시다

방법 ①

public String toString() {

    return ToStringBuilder.reflectionToString(this);

}


출력 결과

TestClass@1cd2e5f[boardId=<null>,boardNo=0]


방법 ②

public String toString() {

    return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);

}


출력 결과

TestClass@1cd2e5f[boardId=<null>,boardNo=0]


방법 ③

public String toString() {

    return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);

}


출력 결과

TestClass@1cd2e5f[
  boardId=<null>
  boardNo=0
]


방법 ④

public String toString() {

    return ToStringBuilder.reflectionToString(this, ToStringStyle.NO_FIELD_NAMES_STYLE);

}


출력 결과

TestClass@1cd2e5f[<null>,0]


방법 ⑤

public String toString() {

    return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);

}


출력 결과

<null>,0


(2) append 함수

append 메소드는 static이 아니며 다음과 같은 형식으로 사용 가능합니다.


public String toString() {

    return new ToStringBuilder(this).append("boardId", boardId).append("boardNo", boardNo).toString();

}


출력 결과

TestClass@1cd2e5f[boardId=<null>,boardNo=0]


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

=============================================

Posted by 1010
반응형

Commons-Digester


I. Digester ?

digester는 XML파일로 저장된 정보를 java 객체에 매핑해 주는 API입니다. 하지만 그 반대기능은 되지 않습니다.

보통은 XML파일을 parsing할때 SAX와 DOM을 이용하였지만 DOM은 성능이 좀 느리고, SAX는 DOM보다는 빠르지만 코드가 난잡해 집니다. digester는 SAX기반이지만 pattern 매칭으로 아주 쉽고 빠르게 XML 파일을 parsing합니다


원래 digester는 struts의 struts-config.xml 정보를 로딩하기위해 개발되어 struts의 한 부분이었는데 독립적으로 commons project로 분리되었습니다.


II. 준비물

digester를 사용하기 위해서는 다음 4가지 준비물이 필요합니다

commons-digester http://jakarta.apache.org/site/downloads/downloads_commons-digester.cgi

commons-beanutils http://jakarta.apache.org/site/downloads/downloads_commons-beanutils.cgi

commons-collections http://jakarta.apache.org/site/downloads/downloads_commons-collections.cgi

commons-logging http://jakarta.apache.org/site/downloads/downloads_commons-logging.cgi

만약 digester는 SAX API를 사용하기 때문에 jdk1.4 이상의 버젼이 아니라면 Xerces같은 XML parser가 필요합니다


아래예제를 실행하려면 dbcp 관련 파일도 필요하며 이는 Commons-dbcp 편을 참조하세요~


참고 사이트

commons-digester API http://jakarta.apache.org/commons/digester/commons-digester-1.6/docs/api/index.html

commons-digester Guide http://jakarta.apache.org/commons/digester/apidocs/org/apache/commons/digester/package-summary.html


III. 시작하기 전에..

보통 digester는 여러 설정값들을 xml에 정의해 놓고 이를 어플리케이션에서 로드하는 방식으로 많이 이용됩니다. 이 강좌에서도 데이터베이스 정보를 xml에 정의해 놓고 이를 로딩하여 데이터베이스에 연결하는 예제를 강의할 것입니다.

시작하기 전에 XML에 대한 어느정도 기본 지식이 필요합니다.


주요함수

다른 함수들도 많이만 가장 많이 사용되는 다음 4가지만 딱 눈으로 익히고 갑시다


-. addObjectCreate(element 경로, 자바빈크래스) : 어떤 element 경로를 자바빈클래스로 매칭?

-. addSetProperties(element 속성명, 자바빈프로퍼티명) : 어떤 element 속성을 자바빈 변수에 설정?

-. addBeanPropertySetter(element 경로, 자바빈프로퍼티명) : 어떤 element 경로를 자바빈 변수에 설정?

-. addSetNext(element 경로, 자바빈함수) : 어떤 element 경로를 자바빈 함수에?

대강은 이런 뜻으로 알고 넘어 갑쉬다~!

그럼 element 경로가 먼가요? 다음에 나옵니다


Element Matching Pattern

XML에 element들의 path를 pattern으로 인식하는 방법만 익힙시다.


<a>                 -- Matches pattern "a"
    <b>             -- Matches pattern "a/b"
        <c/>        -- Matches pattern "a/b/c"
        <c/>        -- Matches pattern "a/b/c"
    </b>
    <b>             -- Matches pattern "a/b"
        <c/>        -- Matches pattern "a/b/c"
        <c/>        -- Matches pattern "a/b/c"
        <c/>        -- Matches pattern "a/b/c"
    </b>
</a>


위 XML을 보면 element a가 최상위 루트 element 입니다.

이것은 "a"로 매칭되며 그다음 a의 서브 element b는 "a/b" 로 매칭합니다

그다음은 .. "a/b/c".. 

쉽죠?

즉 최상위만 "/"가 붙지 않으며 그 이하는 트리구조처럼 "/"를 붙여주면 됩니다


자 그럼 좀전에 보았던 함수들과 연관지어 보면..

...

digester.addObjectCreate("a/b", B.class);

digester.addBeanPropertySetter("a/b/c", "c");

...

요렇게 쓰입니다.


IV. Digester를 이용하여 데이터베이스 커넥션 정보를 DBCP로 멀티 설정하여 웹에서 사용해 보자!

자 이제 실질적인 예제를 봅시다~


무엇을 하려고 하려면 mysql과 oracle jdbc정보를 xml 파일에 기록해 두고 이를 딱 한번만 읽어서 이정보를 데이터베이스 커넥션풀인 dbcp에 설정할 것입니다


 XML 파일

다음과 같은 XML 파일이 있습니다. 이 파일은 mysql과 oracle을 연결하는 커넥션 정보를 가지고 있습니다

이 파일이름은 C:\Tomcat 5.0\webapps\ROOT\WEB-INF\classes\config.xml입니다

mysql과 oracle 두개의 jdbc pool을 dbcp로 설정할 것입니다.

이 파일은 제가 임의로 정해서 만든겁니다.


<?xml version="1.0" encoding="EUC-KR"?>


<connection-sources>
   <description>This script is a connection description</description>


   <JDBCConnectionPool name="mysql">
      <description>Mysql Connection Source</description>
      <defaultAutoCommit>true</defaultAutoCommit>
      <defaultReadOnly>false</defaultReadOnly>
      <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
      <maxActive>10</maxActive>
      <maxIdle>10</maxIdle>
      <maxWait>10000</maxWait>
      <username>unicorn</username>
      <password>iloveyou</password>
      <url>jdbc:mysql://localhost/unicorn</url>
   </JDBCConnectionPool>


   <JDBCConnectionPool name="oracle">
      <description>Oracle Connection Source</description>
      <defaultAutoCommit>true</defaultAutoCommit>
      <defaultReadOnly>false</defaultReadOnly>
      <driverClassName>oracle.jdbc.driver.OracleDriver</driverClassName>
      <maxActive>10</maxActive>
      <maxIdle>10</maxIdle>
      <maxWait>10000</maxWait>
      <username>unicorn</username>
      <password>iloveyoutoo</password>
      <url>jdbc:oracle:thin:@localhost:1521:unicorn</url>
   </JDBCConnectionPool>


</connection-sources>


web.xml

웹 배치파일에 의해 db.ConnectionInitialize.java를 초기 서블릿 컨테이너 로딩시 실행하여 XML정보를 DBCP로 세팅할 것입니다

config.xml 파일경로를 config 파라미터에 설정합니다


<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

  <servlet>
     <servlet-name>connectioninitialize</servlet-name>
     <servlet-class>db.ConnectionInitialize</servlet-class>
     <init-param>
        <param-name>config</param-name>
        <param-value>C:\Tomcat 5.0\webapps\ROOT\WEB-INF\classes\config.xml</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
  </servlet>
   
</web-app>


db.jdbc.ConnectionSources.java

XML 파일에서도 보면 알수있듯이 connection-sources 서브요소인 description과 JDBCConnectionPool을 저장하는 객체입니다. 변수를 눈여겨 봅시다


package db.jdbc;

import java.util.HashMap;

public class ConnectionSources {

	private String description;
	private HashMap source = new HashMap();
	
	public void setDescription(String description) {
		this.description = description;
	}
	
	public void addSource(JDBCConnectionPool source) {
		this.source.put(source.getName(), source);
	}
	
	public String getDescription() {
		return this.description;
	}
	
	public JDBCConnectionPool getSource(String name) {
		return (JDBCConnectionPool)this.source.get(name);
	}
}

addSource 함수는 여러 JDBCConnectionPool 정보를 ConnectionSourcec 의 source에 저장합니다. 이 함수는 밑에서 다시 나오니 눈여겨 봅시다

 

db.jdbc.JDBCConnectionPool.java

변수에 대해 단순히 setter, getter로 이루어져 있습니다.

XML 파일을 보면JDBCConnectionPool 의 서브 element들을 저장하는 객체이며 XML파일과  이 java 변수명들과 매칭되는것을 알수 있을겁니다.

대강 감이 오나요? ㅡ.ㅡ? 감좌봐쓰~?


package db.jdbc;

public class JDBCConnectionPool {

	private String name;
	private String description;
	private boolean defaultAutoCommit;
	private boolean defaultReadOnly;
	private String driverClassName;
	private int maxActive;
	private int maxIdle;
	private int maxWait;
	private String username;
	private String password;
	private String url;
	
//for debug public void print() { String toString = "name : "+name+"\n"+ "description : "+description+"\n"+ "defaultAutoCommit : "+defaultAutoCommit+"\n"+ "defaultReadOnly : "+defaultReadOnly+"\n"+ "driverClassName : "+driverClassName+"\n"+ "maxActive : "+maxActive+"\n"+ "maxIdle : "+maxIdle+"\n"+ "maxWait : "+maxWait+"\n"+ "username : "+username+"\n"+ "password : "+password+"\n"+ "url : "+url; System.out.println(toString); } public void setName(String name) { this.name = name; } public void setDescription(String description) { this.description = description; } public void setDefaultAutoCommit(boolean defaultAutoCommit) { this.defaultAutoCommit = defaultAutoCommit; } public void setDefaultReadOnly(boolean defaultReadOnly) { this.defaultReadOnly = defaultReadOnly; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public void setUrl(String url) { this.url = url; } public String getName() { return this.name; } public String getDescription() { return this.description; } public boolean getDefaultAutoCommit() { return this.defaultAutoCommit; } public boolean getDefaultReadOnly() { return this.defaultReadOnly; } public String getDriverClassName() { return this.driverClassName; } public int getMaxActive() { return this.maxActive; } public int getMaxIdle() { return this.maxIdle; } public int getMaxWait() { return this.maxWait; } public String getUsername() { return this.username; } public String getPassword() { return this.password; } public String getUrl() { return this.url; } }

db.ConnectionInitialize.java

자 이제 여기가 핵심 클래스입니다. 위부분이 모두이해가 되었으면 다음 소스코드를 살펴봅시다

web.xml에서 정의한 config.xml을 로딩하여 파싱하고 그 정보를 DBCP에 설정합니다

mysql과 oracle 두개의 jdbc를 설정하도록 xml에 정의하였었습니다.


package db;

import java.sql.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;

import org.apache.commons.digester.Digester;
import java.io.*;
import org.xml.sax.SAXException;

import db.jdbc.ConnectionSources;
import db.jdbc.JDBCConnectionPool;

public class ConnectionInitialize extends HttpServlet {

	public void init() throws ServletException {

		String config = null;
		// web.xml의 배치스크립트의 파라미터이름을 가져온다
		Enumeration names = getServletConfig().getInitParameterNames();
		do {
			if(!names.hasMoreElements())
			break;
			String name = (String)names.nextElement();
			String value = getServletConfig().getInitParameter(name).trim();

			System.out.println(name+" : "+value);

			// config에 정의된 XML 파일을 가져온다
			if (name.startsWith("config"))
 				config = value;
		} while(true);

		//Digester를 생성하고
		Digester digester = new Digester();
		//XML 유효성을 검증할것인가?
		digester.setValidating(false);

		//connection-sources 요소를 ConnectionSources.class 객체에 저장하겠다
		digester.addObjectCreate("connection-sources",
		                          ConnectionSources.class);

		//connection-sources/description 요소를
		//ConnectionSources.class의 description 변수에 저장하겠다
		digester.addBeanPropertySetter("connection-sources/description",
						"description");

		//connection-sources/JDBCConnectionPool 요소를 JDBCConnectionPool.class 객체에저장하겠다
		digester.addObjectCreate("connection-sources/JDBCConnectionPool",
		                         db.jdbc.JDBCConnectionPool.class);

		//connection-sources/JDBCConnectionPool 요소의 name 속성을
		//JDBCConnectionPool.class의 name 변수에 저장하겠다
		digester.addSetProperties("connection-sources/JDBCConnectionPool", "name", "name");

		//connection-sources/JDBCConnectionPool/description 을
		//JDBCConnectionPool.class 객에의 description 변수에 저장하겠다
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/description",
                                       "description");

		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/defaultAutoCommit",
                                       "defaultAutoCommit");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/defaultReadOnly",
                                       "defaultReadOnly");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/driverClassName",
                                       "driverClassName");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/maxActive",
                                       "maxActive");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/maxIdle",
                                       "maxIdle");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/maxWait",
                                       "maxWait");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/username",
                                       "username");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/password",
                                       "password");
		digester.addBeanPropertySetter("connection-sources/JDBCConnectionPool/url", "url");

		//connection-sources/JDBCConnectionPool을
		//ConnectionResources.class의 addSource를 이용하여 반복적으로 추가하겠다
		digester.addSetNext("connection-sources/JDBCConnectionPool", "addSource");

		try {
			File file = new File(config);
			//digester 파싱 및 결과 리턴
			ConnectionSources connectionSources =
                                                             (ConnectionSources)digester.parse(file);

			System.out.println(connectionSources.getDescription());
			JDBCConnectionPool mysql = connectionSources.getSource("mysql");
			mysql.print(); //디버깅
			JDBCConnectionPool oracle = connectionSources.getSource("oracle");
			oracle.print(); //디버깅

			//이부분 이하는 Commons-dbcp 부분을 참조하기 바란다
			setupDriver(mysql.getName(),
				mysql.getDriverClassName(),
				mysql.getUrl(),
				mysql.getUsername(),
				mysql.getPassword(),
				mysql.getDefaultAutoCommit(),
				mysql.getDefaultReadOnly(),
				mysql.getMaxActive(),
				mysql.getMaxIdle(),
				mysql.getMaxWait());

			setupDriver(oracle.getName(),
				oracle.getDriverClassName(),
				oracle.getUrl(),
				oracle.getUsername(),
				oracle.getPassword(),
				oracle.getDefaultAutoCommit(),
				oracle.getDefaultReadOnly(),
				oracle.getMaxActive(),
				oracle.getMaxIdle(),
				oracle.getMaxWait());

		} catch (FileNotFoundException filenotfoundexception) {
			System.out.println("Config file not found");
			filenotfoundexception.printStackTrace();
		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}

	public void setupDriver(String poolName,
			String driverClassName,
			String url,
			String username,
			String password,
			boolean defaultAutoCommit,
			boolean defaultReadOnly,
			int maxActive,
			int maxIdle,
			long maxWait) throws Exception {
		try {
		    Class.forName(driverClassName);
		} catch (ClassNotFoundException classnotfoundexception) {
			System.out.println(driverClassName+" is not found");
		    classnotfoundexception.printStackTrace();
		    throw classnotfoundexception;
		}
		
		GenericObjectPool connectionPool = new GenericObjectPool(null);
		connectionPool.setMaxActive(maxActive);
		connectionPool.setMaxIdle(maxIdle);
		connectionPool.setMaxWait(maxWait);
		
		ConnectionFactory connectionFactory
			= new DriverManagerConnectionFactory(url, username, password);
		
		PoolableConnectionFactory poolableConnectionFactory
			= new PoolableConnectionFactory(connectionFactory,
		                                   connectionPool,
		                                   null,
		                                   null,
		                                   defaultReadOnly,
		                                   defaultAutoCommit);
		
		Class.forName("org.apache.commons.dbcp.PoolingDriver");
		PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
		
		driver.registerPool(poolName,connectionPool);    
	}
}

그럼 이렇게 설정한 DBCP는 어떻게 사용할까요?

이전강좌에서 보았던 ConnectionContext.java와 ConnectionResource.java를 다시 사용해봅시다

package db;

public interface ConnectionContext {
	public java.sql.Connection getConnection();
	public void rollback();
	public void commit();
	public void release();
}

ConectionContext를 구현한 ConnectionResource는 풀이름을 받아 처리하는것으로 수정하였습니다

package db;

import java.sql.Connection;
import java.sql.DriverManager;
import javax.sql.DataSource;

public class ConnectionResource implements ConnectionContext {
	private Connection connection = null;
	private boolean transaction = false;

    public ConnectionResource(String poolName) throws Exception {
    	init(false, poolName);	
    }
    
    public ConnectionResource(boolean transaction, String poolName) throws Exception {
    	init(transaction, poolName);
    }
    
    public void init(boolean transaction, String poolName) throws Exception {
    	this.transaction = transaction;
    	connection = DriverManager.getConnection("jdbc:apache:commons:dbcp:"+poolName);
if (transaction) connection.setAutoCommit(false); if (connection == null) throw new Exception("fail to get connection"); } public Connection getConnection() { return connection; } public void rollback() { if (transaction) { if (connection != null) try { connection.rollback(); } catch (Exception e) {} } } public void commit() { if (transaction) { if (connection != null) try { connection.commit(); } catch (Exception e) {} } } public void release() { { if (connection != null) { if (transaction) { try { connection.setAutoCommit(true); } catch (Exception e) {} } try { connection.close(); } catch (Exception e) {} }    } }

jsp 파일

마지막으로 ConnectionContext는 풀이름과 함께 사용하면 되겠네요

<%@ page contentType="text/html;charset=EUC_KR" %>
<%@ page import="java.sql.*,db.*" %>

<%

ConnectionContext mysqlContext = new ConnectionResource("mysql");
// 혹은 ConnectionContext oracleContext = new ConnectionResource("oracle");


Connection connection = null;


try {


    connection = mysqlContext.getConnection();
    out.println(connection);


} catch (Exception exception) {
    exception.printStackTrace();
} finally {
    if (connection != null) try { mysqlContext.release(); } catch (Exception exception) {}
}

%>


DBCP 부분은 이전 강좌인 Commons-dbcp (http://www.jakartaproject.com/article/jakarta/1111890409958 )부분을 참조하세요~


ps. 휴 =3 다썼당 ^_^

     흠.. 쉽게쓴다고 이리 저리 하루종일 썼는데 설명이 많이 부족한것 같네요

     그밖에 사항은 알아서 찾아보기~!

     digester II탄에서는 xml 설정파일로부터 규칙을 읽어 xml을 파싱하는 방법을 알아보겠습니다~


=============================================

본문서는 자유롭게 배포/복사 할수 있지만

이문서의 저자에 대한 언급을 삭제하시면 안됩니다

저자 : GoodBug (unicorn@jakartaproject.com)

최초 : http://www.jakartaproject.com 

Posted by 1010