달력

12

« 2024/12 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31


출처 : http://blog.daum.net/nyx21/7577691

 출처  - 자바 개발자를 위한 이클립스 바이블 제 2판 (피어슨에듀케이션코리아) p.287~288



목적확장점
오브젝트 레이블에 텍스트나 아이콘 장식 추가org.eclipse.ui.decorators
Window > Show View 메뉴 선택에 새로운 뷰 기여org.eclipse.ui.views
새로 만들기 마법사org.eclipse.ui.newWizards
표준 Export… 과 Import 메뉴 선택에 새로운 마법사 기여org.eclipse.ui.exportWizards
org.eclipse.ui.importWizards
표준 File > New 메뉴 선택에 새로운 마법사 기여org.eclipse.ui.newWizards
Window > Preferences 대화상자에 설정 페이지 기여org.eclipse.ui.preferencePages
오브젝트의 프로퍼티 대화상자에 페이지 기여org.eclipse.ui.propertyPages
리소스에 대한 새로운 편집기 정의
Open With 메뉴 분기에 선택으로 보인다.
org.eclipse.ui.editors
Window > Open Perspective 메뉴 선택에 대한 새로운 퍼스
펙티브 정의. 새로운 퍼스펙티브의 숏컷, 뷰 숏컷 그리고 기
존의 퍼스펙티브에 액션 집합 추가
org.eclipse.ui.perspectives
org.eclipse.ui.perspectiveExtentions
워크벤치 윈도우 메뉴 바 또는 툴바에 액션 기여org.eclipse.ui.actionSets
퍼스펙티브에서 지정된 뷰/편집기가 열려 있다면 웨크벤치
윈도우 메뉴 바 또는 툴바에 액션을 기여
org.eclipse.ui.actionSetPartAssociations
편집기의 툴바나 메뉴 선택에 액션 기여org.eclipse.ui.editorActions
편집기, 뷰 또는 객체의 콘텍스트 메뉴에 액션 기여org.eclipse.ui.popupMenus
뷰의 툴바나 풀다운 메뉴에 기여org.eclipse.ui.viewActions
Help > Help Contents 선택으로 활용 가능한 온라인 도움말
정의
org.eclipse.ui.help
org.eclipse.help.contentProducer
네비게이터 뷰의 Filter… 메뉴 선택에 대한 추가적인 필터
정의
org.eclipse.ui.ide.resourceFilters
기존의 리소스 또는 새로운 리소스 타입에 대해 자신만의
점진적인 빌드 과정 정의(Project > Rebuild Project).
프로젝트 기능을 향상
org.eclipse.core.resources.builders
org.eclipse.core.resources.natures
사용자 정보로 리소스에 태그를 붙임. 마커는 태스크 뷰나,
텍스트 편집기의 수직 표시자와 같은 뷰나 편집기와 아웃
라인 뷰에서 레이블 장식으로 표시될 수 있다.
org.eclipse.core.resources.markers
만들어져 있는 텍스트 편집기, JFace Text 는 사용자의 일관
된 편집 경험을 보장하기 위해 화장 가능하고 재사용 가능
한 텍스트 편집기를 제공한다. 그것을 알맞게 조정하여 표
시자에서 유일한 텍스트 주석에 대한 추가적인 요구, 라인
숫자, 구문 강조, 내용 돕기와 같은 추가적인 정보를 알려줄
수 있다.
org.eclipse.core.filebuffers.documentSetup
org.eclipse.ui.editors.templates
사용자의 행동에 기반하여 활용 가능한 옵션의 수 줄이기org.eclipse.ui.activities


:
Posted by 라면스프


출처 : http://knight76.tistory.com/entry/%EA%B5%AC%EA%B8%80-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C-%EB%B2%84%ED%8D%BC-Google-Protocl-Buffer


구글 프로토콜 버퍼 (Google Protocl Buffer)


PPT 작성 자료








* 배경
RPC와 쉽게 연동, Not RPC
하나의 개념으로 다양한 언어에서 쓸 수 있게 구글에서 다양한 언어별로 개발 하다 보니. 통신을 위한 단일 표준이 필요

  proto 파일 -> proto 컴파일러 -> 여러 언어로 변환 (java, python, c++)

Not socket
구글 에서 2008년 7월 발표
이슈 제시
- XML 문제
- Parsing, serialization  (debugging)
- Portable : IDL처럼 사용
- Heavy Optimization
- Language 지원 
짧은 데이터의 송수신 용도/긴 데이터 송수신이 목표가 아님

* XML 보다 좋은 점
Simple
3~10배 작음
20~100배 속도 빠름
모호하지 않음
바로 프로그램에 사용하기 쉬움

* 레퍼런스
Protocol Buffers: A new open source release
    http://www.youtube.com/watch?v=K-e8DDRwVUg

Home Page
   http://code.google.com/p/protobuf/

개발자 가이드
   http://code.google.com/intl/ko-KR/apis/protocolbuffers/docs/overview.html

Protocol Buffer Language Guide
    http://code.google.com/intl/ko-KR/apis/protocolbuffers/docs/proto.html

API
    http://code.google.com/intl/ko-KR/apis/protocolbuffers/docs/reference/java/index.html

PB 포맷
    http://wiki.openstreetmap.org/wiki/PBF_Format

비슷한 솔루션과 비교
    https://github.com/eishay/jvm-serializers/wiki


* 활용 
구글
- 원래 index server request/response protocol로 사용했었음
- 48,162 different message types
- 12,183 .proto files
다양한 회사
국내/외 게임 회사의 통신


* 장점
쓰기 편함
Stub 코드 자동 생성
- 통신에서 가져야 할 보편적 특성을 다 추가
- Serializing, Parsing 지원
코드 일치
- 클라이언트/서버 코드 동일
IDL 형태로 정의가 단순
- Portable
- 클래스 또는 struct 디자인
언어 지원
java, c++, python
3rd party lib (많은 언어 지원.http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns#RPC_Implementations)
배우기 쉬움
이클립스 플러그인 존재
Lite 버전 개발 가능
Good Document
BSD license
언어마다 특화되고 쓰기 편한 특징을 제공

* 단점
Output이 binary만 존재
- PB의 Reflection을 이용해서 json으로 전달 가능 
Map, set 지원 없음


* 개발환경 구성
Download proto compiler in google code
http://code.google.com/p/protobuf/downloads/list

(Option) eclipse plugin
http://protoclipse.googlecode.com/svn/trunk/site/


* proto 파일


// text.txt
package test;

message Request {
  required string command = 1;
  optional string param = 2;
}


 



/cygdrive/c/protocolbuffer
$ ./protoc.exe test.txt --java_out=.



Test폴더 생기고 TestTxt.java 생성됨
(17KB, Protocol buffer 내부 클래스 사용)

// c++ 로 하면
test.txt.pb.cc (12K)
test.txt.pb.h (8K)

// python으로 하면,
test/txt_pb2.py (2K)

* 생성된 자바 코드
Descriptor 지원
- internal_static_test_Request_descriptor
Reflection 지원
- Message / Message.Builder interfaces.
- Json 처럼 프로토콜로 변경 가능 (ajax 가능)
메시지 수정시 하위 호환 보장, 새로운 메시지로 변경되면 기존 코드에 대한 필드만 처리
파일이름을 디폴트로 해서 소스를 생성하지만, 내가 원하는 클래지 이름과 클래스 이름의 개별 지정이 가능
- option java_package = "com.example.foo.bar";
- option java_outer_classname = “ProtocolData";
PB의 Enum은 java의 enum으로 변경


* 크기 제한 
디폴트로 크기 제한 : 64 MB
속도를 최적화 또는 악의를 가진 사용자로부터 보호하기 위해서 크기를 제한할 수 있음
- CodedInputStream/CodedOutputStream (ZeroCopyInputStream/ZeroCopyOutputStream ) 
   SetTotalBytesLimit 메소드

* proto 파일 생성시 유의할 점
package 선언
클래스 파일 이름
운영을 위한 파일명 .proto
message 등록
- Protocol buffer language guide
Protoc.exe(컴파일러)에 의해 만들어진 java, python, c++ 코드는 고치지 말아야 한다.(immutable)
protoc에서 컴파일 되면, 자동으로 accessor가 붙는다.
- get/set/has…

* message 설명
package
Type
- Bool, int32, uint32, float, double, string, bytes,  ….
- Enum
Nested type
Default value
importing
Modifier
- required : 반드시 사용해야 할 필드. 미초기화된 상태 미초기화된 메시지를 빌드하면 RuntimeException, 초기화되지 않은 메시지를 파싱하면서 에러나면 IOException발생
- optional : option의 개념
     hasXXX() 로 확인
- repeated : 0을 포함하는 개수를 계속 넣을 수 있음
     자바에서는 List객체로 구현됨


* 필드에 번호를 반드시 주는 이유 
번호를 주지 않으면 protoc 에러 발생
Write/Read 할 때, serialization 순서를 주기 위함
필드 정보가 set되었는지 쉽게 알기 위함(내부적으로 bit 연산함)

* Versioning 정보가 없는 이유
새로운 필드를 언제든지 추가 될 수 있음
모든 정보를 볼 필요 없이 필요한 정보만 파싱할 수 있도록 함
But, java는 기본으로 존재하지 않지만, c++ 은 존재한다. 링킹 이슈. (GOOGLE_PROTOBUF_VERIFY_VERSION 매크로)
Incompatible한 버전 때문에 문제가 없도록 해야 함


* 데모 1

// text.txt
package test;

message Request {
  required string command = 1;
  optional string param = 2;
}


 



generated 자바 코드 로 컴파일


<Writer.java>

package com.example.test;

import java.io.FileOutputStream;
import test.Test.Request;

public class Writer {
    public static void main(String[] args) throws Exception {
        Request request = Request.newBuilder()
                                       .setCommand("commit")
                                       .setParam("every files")
                                       .build();
        FileOutputStream output = new FileOutputStream("r.os");
        request.writeTo(output);
        output.close();
    }
}




<Reader.java>
package com.example.test;

import java.io.FileInputStream;
import test.Test.Request;

public class Reader {
    public static void main(String[] args) throws Exception {
        Request request = Request.parseFrom(new FileInputStream("r.os"));
        System.out.println("command : " + request.getCommand());
        if (request.hasParam()) {
            System.out.println("params : " + request.getParam());
        } 
    }
}



 

<실행결과>
command : commit
params : every files


* 데모 2


<writer.cpp>

#include <iostream>
#include <fstream>
#include <string>
#include "test.pb.h"

using namespace std;

int main(int argc, char* argv[]) { 
 Request request;
   request.set_command("init");
 request.set_param("0");

           fstream out("streams", ios::out | ios::binary | ios::trunc); 
 request.SerializeToOstream(&out); 
 out.close();

 return 1;
}



 



<reader.cpp>
#include <iostream>
#include <fstream>
#include <string>
#include "test.pb.h"

using namespace std;

int main(int argc, char* argv[]) { 
    Request request;
    fstream in(“streams", ios::in | ios::binary); 
    if (!request.ParseFromIstream(&in)) { 
          cerr << "Failed to parse streams." << endl; 
          exit(1); 
    } 
    cout << “command: " << request.command() << endl; 
    if (request.has_param()) { 
         cout << “param: " << request.param() << endl; 
    }
}

 

* 데모 3


package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}



Posted by My Story '김용환'




:
Posted by 라면스프

출처 : http://cafe.naver.com/hermeneus/76


가이드 : http://wiki.eclipse.org/index.php/MemoryAnalyzer


자바 웹 개발자로서 듣기 가장 무서운 단어중에 하나는 out of memory 일 것이다.


메모리의 누수가 없도록 개발해야 하는 것이 정답이지만 실수 할 수 있는 가능성이 있는 만큼 대비 또한 중요하다고 생각한다.

시스템에서 out of memory가 발생했을 때 우리는 어떤 데이터를 가지고 어떻게 분석해야할지 고민해야 할 것이다.

out of memory에 대한 대비가 되어 있지 않으면 분석할 데이터가 존재하지 않는다.

따라서 할 수 있는 것은 시스템을 재시작하는 방법 뿐이다.

메모리는 계속 쌓여 갈 것이고 가까운 미래에 또다시 out of memory를 만날 것이다.

이러한 문제를 해결하기 위한 여러가지 분석 방법 중 하나가 out of memory가 발생할 때 힙덤프를 생성하는 것이다.

JAVA에서는 친절하게 옵션으로 제공하고 있다.

-XX:+HeapDumpOnOutOfMemoryError : out of memory가 발생시에 힙덤프를 현재 실행 디렉토리에 생성한다.

-XX:HeapDumpPath=힘덤프를 생성할 경로/힙덤프이름.hprof : 지정한 경로에 생성한다.

out of memory가 발생했다면 hprof 힙덤프 파일이라는 증거물을 자동으로 획득할 수 있다.

이제 힙덤프 파일을 어떻게 분석할까??

힙덤프를 분석해주는 툴이 있어 반갑다. 바로 Eclipse Memory Analyzer (MAT)  !!

1. 프로그램을 실행시키고 힙덤프 파일을 찾아서 열기(Open Heap Dump)한다.





2. 선택된 힙덤프를 바로 분석하여 파이형 그래프로 문제가 얼마나 있는지 한눈에 보여준다.





3. 이제 어디에 문제가 있는지 좀 더 분석해 보자.




메모리가 어느 부분에서 많이 쓰였는지 해당 인스턴스를 찾아서 나타내 준다.

Problem Suspect 1 한 부분만 봤을 때에도 문제의 원인을 대략적으로 알아낼 수 있었다.

바로 com.sun.mail.smtp.SMTPMessage[] 부분이었다.

SMTPMessage를 사용하는 곳만 찾아보아도 이미 반정도는 해결 된 문제다.


4. 좀 더 상세하게 분석해 보자.




트리 형태로 볼 수 있도록 트리 아이콘을 클릭한다.

트리는 메모리를 가장 많이 가지고 있는 쓰레드 순으로 정렬하여 보여주고 있다.

가장 문제가 큰 쓰레드를 열어보았다.

SMTPMessage 배열은 64개의 SMTPMessage 객체를 가지고 있다.

InternetAddress 배열도 64개의 InternetAddress 객체를 가지고 있다.

SenderInfoBean 클래스도 보인다.

메일을 발송하는 부분에서 사용되는 클래스가 대부분이었다.

이 세 항목으로 볼 때 메일 발송시 64개의 마임(MIME) 또는 그 이상을 생성하여 메모리에 가지고 있다가 

out of memory를 발생시킨 것이라는 결론을 내렸다.

이러한 힙덤프 분석으로 문제를 발견하고 수정하는데 많은 도움을 받을 수 있었다.

몇일, 몇주, 몇달이 지나도 out of memory가 발생했다는 문제는 지금까지 보고되지 않고 있다.


▼ 아래의 경로에서 Eclipse Memory Analyzer(MAT)에 대한 자세한 정보와 프로그램을 다운로드 받을 수 있다.

    ☞ 경로 : http://www.eclipse.org/mat/


:
Posted by 라면스프
2012. 7. 24. 09:40

synchronized : 동기화(Lock) Enjoy/JAVA2012. 7. 24. 09:40

출처 : http://blog.naver.com/sang_it/156495940


package com.thread;
/*
 * 동기화 : 쓰레드 Lock걸기,Synchronized를 걸면 동시 접속이 안된다 
하나의 자원(데이터)에 대해서 여러 스레드가 사용하려고 할때 
한 시점에서 하나의 스레드만 사용할 수 있도록 하는 것이다.
synchronized 식별자는 보통 메소드의 선언부에 쓰고 
이 키워드가 붙은 메소드는 한번에 하나의 스레드만 접근이 가능하며
메소드가 사용중일 때 다른 스레드가 메소드를 호출하면 앞의 스레드가 종료될때까지 기다려야 한다.
*/
class ATM implements Runnable{
 private long depositeMoney = 10000;


 @Override
 public void run() {
  synchronized (this) {
   for(int i=0; i<10 ; i++){
    try{
     Thread.sleep(100);
    }catch (Exception e) {
     e.printStackTrace();
    }
    //현재 디파짓을 반환
    if(getDepositMoney() <=0)
     break;
    whithDraw(100);
   }
  }  
 }


 private void whithDraw(int i) {
  if(0< depositeMoney)
   depositeMoney -= i;
  System.out.println(Thread.currentThread().getName()+ ","+depositeMoney);
 }


 private long getDepositMoney() {
  return depositeMoney;
 }

}

public class SynchronizedTest {
 public static void main(String[] args) { 
  ATM atm = new ATM();
  Thread t1 = new Thread(atm,"First");
  t1.start();
  
  Thread t2 = new Thread(atm,"Second");
  t2.start(); 


 }

}
==========결과 ====================

First,9900
First,9800
First,9700
First,9600
First,9500
First,9400
First,9300
First,9200
First,9100
First,9000
Second,8900
Second,8800
Second,8700
Second,8600
Second,8500
Second,8400
Second,8300
Second,8200
Second,8100
Second,8000

 

 

 

 

****첫번째로 들어온 쓰레드가 끝나면 다음 쓰레드 실행

:
Posted by 라면스프
2012. 7. 24. 09:34

[Java] replaceAll 로 공백 제거하기 Enjoy/JAVA2012. 7. 24. 09:34

출처 : http://vicki.tistory.com/583


정규식에서 공백은 정확하게 공백으로 인식을 못하는 것 같았습니다.
Pattern JavaDoc 에서 내용을 확인하였습니다.
http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html

POSIX character classes (US-ASCII only)
\p{Lower}A lower-case alphabetic character: [a-z]
\p{Upper}An upper-case alphabetic character:[A-Z]
\p{ASCII}All ASCII:[\x00-\x7F]
\p{Alpha}An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit}A decimal digit: [0-9]
\p{Alnum}An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct}Punctuation: One of !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph}A visible character: [\p{Alnum}\p{Punct}]
\p{Print}A printable character: [\p{Graph}\x20]
\p{Blank}A space or a tab: [ \t]
\p{Cntrl}A control character: [\x00-\x1F\x7F]
\p{XDigit}A hexadecimal digit: [0-9a-fA-F]
\p{Space}A whitespace character: [ \t\n\x0B\f\r]


그래서 아래와 같이 수정하였습니다.
  1. String str = "Vicki Yi";   
  2.   
  3. System.out.println(str + " : " + str.replaceAll("\\p{Space}"""));  
1.String str = "Vicki Yi";
2. 
3.System.out.println(str + " : " + str.replaceAll("\\p{Space}"""));


결과는~~~ 원하는 결과가 나왔습니다.
Vicki Yi : VickiYi

:
Posted by 라면스프
2012. 7. 24. 09:30

Java && Excel 연동 Enjoy/JAVA2012. 7. 24. 09:30

출처 : http://dualist.tistory.com/151


참조 : http://www.javapattern.info/

         http://www.okjsp.pe.kr/

 

자바로 엑셀을 핸들링 할 수 있는 방법은 크게 두가지로 나누어 진다.
1. Java Excel API    
    참조 : http://jexcelapi.sourceforge.net/
2. POI 
    참조 : http://jakarta.apache.org/poi/index.html

 

    흔히 POI를 엑셀을 핸들링 하기 위한 것으로만 오해하기 쉬운데,
    POI 프로젝트는 마이크로소프트 OLE 2 복합도큐먼트포맷형식의 파일을 순수 자바를 이용하여 핸들링하는 APIs로 구성되어있다.
    OLE 2 복합도큐먼트포맷형식의 파일은 마이크로소프트 엑셀 혹은 워드파일 등의 대부분의 오피스파일들을 나타낸다.

 

일반적으로 엑셀에 대한 핸들링만을 수행할 때에는 Jxl을 권장한다.
엑셀을 핸들링 할 때 엑셀에서 가장 작은 단위는 알고 있듯이 "셀"이다.
모든 작업은 이 셀을 중심으로 이루어진다.

 

주의할 점)
1) 엑셀 쉬트상에 "C15"라는 셀에 데이터가 있다고 가정하자.( 15행 C열을 나타낸다.)
이 때 Jxl에서는  A1( 1행 A열)부터  C15까지는 실제 데이터가 없을 경우에라도 null이 아닌 빈데이터가 있다고 인식한다.
즉 D열 이상이나, 16행 이상을 접근 할 때에 null로 인식한다.

하지만 POI에서는 C15 이내에 있다 하더라도 실제 데이터가 없을 때에는 null로 인식한다.

2) Jxl에서는 각 셀의 데이터 타입을 실제 엑셀 파일에서 지정된 셀의 타입을 따르고, 
   POI에서는 셀의 실제 데이터 형을 따른다. 
   예를 들어 특정 셀의 타입을 text 로 잡아놓고, 데이터를 1234로 입력하면
   Jxl에서는 "12345"로 인식하고, POI에서는 12345.00 이런식으로 인식한다.

 

EX ) Java Excel API를 이용한 Excel 읽기

import jxl.*;

// .. 중간생략

    Workbook workbook = null;
    Sheet sheet = null;
    Cell cell = null;

    try
    {
        //엑셀파일을 인식
        workbook = Workbook.getWorkbook( new File( szFileName));

        //엑셀파일에 포함된 sheet의 배열을 리턴한다.
        //workbook.getSheets();

        if( workbook != null)
        {
            //엑셀파일에서 첫번째 Sheet를 인식
            sheet = workbook.getSheet(0);

            if( sheet != null)
            {
                //셀인식 Cell a1 = sheet.getCell( 컬럼 Index, 열 Index);
                //셀 내용 String stringa1 = a1.getContents();

                //기록물철의 경우 실제 데이터가 시작되는 Row지정
                int nRowStartIndex = 5;
                //기록물철의 경우 실제 데이터가 끝 Row지정
                int nRowEndIndex   = sheet.getColumn( 2).length - 1;

                //기록물철의 경우 실제 데이터가 시작되는 Column지정
                int nColumnStartIndex = 2;
                //기록물철의 경우 실제 데이터가 끝나는 Column지정
                int nColumnEndIndex = sheet.getRow( 2).length - 1;

                String szValue = "";

                for( int nRow = nRowStartIndex; nRow <= nRowEndIndex; nRow++ )
                {
                    for( int nColumn = nColumnStartIndex; nColumn <= nColumnEndIndex ; nColumn++)
                    {
                        szValue = sheet.getCell( nColumn, nRow).getContents();

                        System.out.print( szValue);
                        System.out.print( "\t" );
                    }
                    System.out.println();
                }
            }
            else
            {
                System.out.println( "Sheet is null!!" );
            }
        }
        else
        {
            System.out.println( "WorkBook is null!!" );
        }
    }
    catch( Exception e)
    {
        e.printStackTrace();
    }
    finally
    {
        if( workbook != null)
        {
            workbook.close();
        }
    }

EX ) POI를 이용한 Excel 파일 읽기

import org.apache.poi.hssf.usermodel.*;

// .. 중간 생략

    HSSFWorkbook workbook = null;
    HSSFSheet sheet = null;
    HSSFRow row = null;
    HSSFCell cell = null;

    try
    {
        workbook = new HSSFWorkbook( new FileInputStream( new File( szFileName)));

        if( workbook != null)
        {
            sheet = workbook.getSheetAt( 0);

            if( sheet != null)
            {

                //기록물철의 경우 실제 데이터가 시작되는 Row지정
                int nRowStartIndex = 5;
                //기록물철의 경우 실제 데이터가 끝 Row지정
                int nRowEndIndex   = sheet.getLastRowNum();

                //기록물철의 경우 실제 데이터가 시작되는 Column지정
                int nColumnStartIndex = 2;
                //기록물철의 경우 실제 데이터가 끝나는 Column지정
                int nColumnEndIndex = sheet.getRow( 2).getLastCellNum();

                String szValue = "";

                for( int i = nRowStartIndex; i <= nRowEndIndex ; i++)
                {
                    row  = sheet.getRow( i);

                    for( int nColumn = nColumnStartIndex; nColumn <= nColumnEndIndex ; nColumn++)
                    {
                        cell = row.getCell(( short ) nColumn);
                        
                        if( cell == null)
                        {
                            continue;
                        }
                        if( cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC)
                        {
                            szValue = String.valueOf( cell.getNumericCellValue());
                        }
                        else
                        {
                            szValue = cell.getStringCellValue();
                        }

                        System.out.print( szValue);
                        System.out.print( "\t" );
                    }
                    System.out.println();
                }
            }
            else
            {
                System.out.println( "Sheet is null!!" );
            }
        }
        else
        {
            System.out.println( "WorkBook is null!!" );
        }

    }catch(Exception e){
        e.printStackTrace();
    }


EX ) Jxl을 이용하여 Excel에 데이터 저장하기

import jxl.*;

// .. 중간생략

    WritableWorkbook workbook = null;
 WritableSheet sheet = null;

 File excelFile = new File( szFileName);
 Label label = null;

 long start = 0;
   long end = 0;
   
    try
    { 
        for(int i = 0 ; i < 10; i++)
        {
            workbook = Workbook.createWorkbook( excelFile);
            workbook.createSheet("sheet1", 0);
            sheet = workbook.getSheet(0);
            for( int j = 0; j < 10000; j++){
                label = new Label( j, 0, "test cell");
                sheet.addCell( label);
            }

            kidsbook.write();
            kidsbook.close();
        }
    }
    catch( Exception e)
    {
    }

// .. 중간생략


EX ) POI를 이용한 브라우저에서 Excel에 데이터 저장하여 보여주기

import org.apache.poi.hssf.usermodel.*;

// ... 생략

public void writeStream( PTSEvaluation[] arrPTSEvaluation) throws Exception
{
    try
    {

        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet( "new sheet");
        HSSFRow row = null;
        HSSFCell cell = null;
        HSSFCellStyle style = null;

        ServletOutputStream excelOut = ServiceContext.getResponse().getOutputStream();
        ServiceContext.getResponse().setHeader( "Content-Disposition", "attachment;filename=EvaluationCompensationList.xls");
        ServiceContext.getResponse().setContentType( MimeType.getMimeType( "xls"));

        //로우 생성
        row = sheet.createRow( ( short)0);
        row.setHeightInPoints( 30);

        //셀에 적용한 스타일을 생성한다.
        style = PTSUtil.setExcelHeaderStyle( wb);

        // 셀 생성
        cell = row.createCell( (short)0);

        //한글 처리
        cell.setEncoding( HSSFCell.ENCODING_UTF_16); 

        //셀에 데이터 입력하기
        cell.setCellValue( "값");

        //셀에 스타일 적용하기
        cell.setCellStyle(style);

        //.. 중간생략 ( 이런 방식으로 로우와 셀을 증가 시키면서 작업을 수행하면 된다.

        wb.write( excelOut);
        excelOut.flush();
    }
    catch( Exception e)
    {
        e.printStackTrace();
        throw e;
    }
    finally
    {
        ServiceContext.getResponse().getOutputStream().close();
    }
}

// ... 생략


출처 : Tong - 퀴비님의 자바통


:
Posted by 라면스프
2012. 7. 20. 15:12

Java Stored Procedure 예제 Enjoy/JAVA2012. 7. 20. 15:12

출처 : http://do3ng.wordpress.com/2007/08/13/java-stored-procedure-%EB%A7%8C%EB%93%A4%EA%B8%B0/



Java Stored Procedure 예제

 

  Java Stored Procedure는 웹 개발시 배치잡(Batch Job) 형태의 작업이나, 많은 데이터의 작업이 필요한 경우 뛰어난 성능 향상을 가져 올 수 있습니다. 또한 PL/SQL로 구현하기 어려우나 Java로 구현이 편리할 경우(예를 들어 OS 파일 핸들링, 암호화..) 사용하면 성능 향상과 동시에 편리하게 사용 할 수 있다.

 

  생성 방법 요약

  1) Writing the JAva Classes

- JAVA 소스생성

  2) Load and Resolve the Java Classes

- loadjava를 이용하여 class를 DB에 Load

  3) Publish the Java Classes

- load된 자바클래스를 이용하여 오라클 프로시저/함수 만들기

  4) Call the Stored Procedure or Function

- 프로시저 또는 함수를 사용

 

  아래 예저는 OS 파일을 읽고, 이름을 변경할 수 있는 Java Stored Procedure 예제입니다.  PL/SQL에서 OS상의 파일에 대한 작업을 하려면 UTL_FILE패키지 이용 할 수 있지만 많은 불편함이 있습니다. Java Stored Procedure를 사용해서 작업하는 예제입니다.

 

① JAVA 소스생성

package com.oracleclub.odd.jsp;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class FileUtil {

    /**

     *파일을 읽어서 String으로 반환<br/>

     *@param fileDir  파일 경로와 파일명 String

     *@return 파일 데이터 byte[]

     */

    public static String readFile(String fileDir) {

        byte[] bytes = null;

        String data = "";

        try{

            FileInputStream fis = new FileInputStream(fileDir);

            bytes = new byte[fis.available()];

            fis.read(bytes);

            fis.close();

            data = new String(bytes);

        } catch(IOException ioe){

            System.out.println(" FileUtil.readFile error : "+ioe.getMessage());

        } finally {

        }

        return data;

    }

   

    /**

     *oldFileName을 newFileName 파일명으로 변경.<br/>

     *@param oldFileName String

     *@param newFileName String

     *@return boolean

     */

    public static void renameFile(String oldFileName, String newFileName) {

        try{

            if (File.separatorChar != ‘/’) {

                oldFileName = oldFileName.replace(File.separatorChar, ‘/’);

                newFileName = newFileName.replace(File.separatorChar, ‘/’);

            }

            File oldFile = new File(oldFileName);

            File newFile = new File(newFileName);

            if(!oldFile.exists())

                System.out.println("FileHndr.renameFile() Not Exist Source File : "+ oldFile);

            else

                oldFile.renameTo(newFile);

                System.out.println("파일명이 변경 되었습니다 ?>"+newFile);

        } catch(Exception e){

            System.out.println(" FileUtil.renameFile error : "+e.getMessage());

        }

    }

}

② loadjava를 이용하여 class를 DB에 Load

 E:\class directory>loadjava -u scott/tiger -v FileUtil.class

  -v : verbose모드 옵션

  -u : oracle 사용자

  -resolve : .class파일이 아닌 .java파일을 지정할때 컴파일 함

? 정상적으로 생성되었는지 확인

C:\>SQLPLUS scott/tiger

SQL>SELECT object_name

        FROM USER_OBJECTS

        WHERE object_type=’JAVA CLASS’;

③ load된 자바클래스를 이용하여 오라클 프로시저/함수 만들기

? 파일을 읽어 출력하는 함수 (Java 메소드에서 Return 값이 있으면 함수로 생성)

? NAME 키워드 뒤에 패키지.클래스.메소드 명을 입력 합니다.

CREATE OR REPLACE FUNCTION read_file(fileName VARCHAR2)

    RETURN VARCHAR2

    AS

    LANGUAGE JAVA

    NAME ‘com.oracleclub.odd.jsp.FileUtil.readFile(java.lang.String) return java.lang.String’;

/

? 파일명을 변경하는 프로시저 (Java 메소드에서 Return 값이 없으면 프로시저로 생성)

CREATE OR REPLACE PROCEDURE rename_file(oldName VARCHAR2, newName VARCHAR2)

    AS

    LANGUAGE JAVA

    NAME ‘com.oracleclub.odd.jsp.FileUtil.renameFile(java.lang.String, java.lang.String)’;

/

? 패키지로 생성해서 사용 할 수도 있습니다.

CREATE OR REPLACE PACKAGE file_util IS

    FUNCTION  read_file(fileName VARCHAR2) RETURN VARCHAR2;

    PROCEDURE rename_file(oldName VARCHAR2, newName VARCHAR2);

END file_util;

/

CREATE OR REPLACE PACKAGE BODY file_util IS

    FUNCTION read_file(fileName VARCHAR2) RETURN VARCHAR2

    AS

    LANGUAGE JAVA

    NAME ‘com.oracleclub.odd.jsp.FileUtil.readFile(java.lang.String) return java.lang.String’;

    PROCEDURE rename_file(oldName VARCHAR2, newName VARCHAR2)

    AS

    LANGUAGE JAVA

    NAME ‘com.oracleclub.odd.jsp.FileUtil.renameFile(java.lang.String, java.lang.String)’;

END file_util;

/

④ 프로시저 또는 함수를 사용.

? 파일을 읽고 쓸 수 있는 권한을 부여하기 위해 SYS 유저로 접속

SQL>CONN / AS SYSDBA

? 권한을 부여하지 않으면 "ERROR! Handling File: the Permission" 에러가 발생한다.

SQL> EXEC DBMS_JAVA.GRANT_PERMISSION( ‘SCOTT’, ‘SYS:java.io.FilePermission’,'<<ALL FILES>>’, ‘read ,write, execute, delete’ );

SQL> CONN SCOTT/TIGER

SQL> SET SERVEROUTPUT ON

? 자바출력은 트레이스파일로 쓰여지므로, 출력을 화면에 표시하도록 변경후 프로시저 호출

SQL> CALL DBMS_JAVA.SET_OUTPUT(1000);

 

? 파일을 읽는 함수 호출

SQL> SELECT READ_FILE(‘E:/test.txt’) FROM DUAL;

READ_FILE(‘E:/TEST.TXT’)

??????????????-

2006년 8월 26일 Oracle Developer Day

 

? 파일명을 바꾸는 프로시저 호출

SQL> EXEC RENAME_FILE(‘E:/test.txt’, ‘E:/new.txt’);

파일명이 변경 되었습니다 ?>E:\new.txt

PL/SQL 처리가 정상적으로 완료되었습니다.

?> 파일 이름이 변경되었는지 확인

 

? 바낀 파일을 패키지로 읽어 보겠습니다.

SQL> SELECT FILE_UTIL.READ_FILE(‘E:/new.txt’) FROM DUAL;

FILE_UTIL.READ_FILE(‘E:/NEW.TXT’)

????????????-

2006년 8월 26일 Oracle Developer Day

:
Posted by 라면스프

출처 : http://gurucode.egloos.com/1452887


OS: Microsoft Windows 2000 [Version 5.00.2195]

DBMS: Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production

작성자: 강명규

작성일: 2004-04-17


이 글은 Oracle and Java Stored Porcedures(www.developer.com/db/article.php/3337411)을 정리한 것임.

이 글에 나오는 예제또한 약간의 첨삭이 있지만, 원문에 충실히 할 것임.


오라클에서 stored procedure/function은 전통적으로 PL/SQL로 작성했었다.

사실, Native언어(C언어등 OS상에서 실행파일을 얻는)나 자바로도 가능하다.

특이하게 자바의 경우 오라클에서 VM을 제공하므로 별다른 복잡한 절자없이

PL/SQL처럼 손쉽게 스토어드 프로시저나 함수를 생성할 수 있다.


그럼, 왜 PL/SQL이 있는데 또 다른 언어를 지원하려는 것일까?

네이티브코드는 성능에 잇점이 있을 수 있다.

몇몇 글을 보면 네이티브코드의 경우, 오라클에 존재하는 PL/SQL로 작성된 패키지들을 전체를

네이티브코드로 변경해야 성능상의 이점을 볼 수 있다고 한다. PL/SQL과 섞어쓰면 성능이

오히려 떨어진다고 한다.


그럼 자바는?

실체 성능적인 부분을 측정해보지는 않았는데 PL/SQL과 혼합해서 써도 무방하다고 한다.


자바를 사용하면 좋은 점은?

어느 정도 데이터베이스와 독립적

PL/SQL을 별도로 배울 필요가 없음

개발팀에서 PL/SQL보다는 자바를 더 능숙하게 다루는 팀원이 많을 경우가 대개일 것임.


자바를 사용하면 찝찝한 점은?

성능이 아무래도 pl/sql로 작성한 것보다는 떨어진다.

오라클 SGA에 자바를 위한 메모리를 할당해줘야 한다.

즉, 성능과 리소스를 더 필요로 한다는 의미.


필자의 생각은?

PL/SQL로 작성하던 놈이라 별다른 것이 없다면 PL/SQL로 작성하고,

PL/SQL로 작성하기 어려우면 JAVA를 고려하는 것이 좋겠다.



들리는 소문에 의하면, 차후 오라클버전에서 PL/SQL을 없애고 자바로 대체한다는

믿거나 말거나 하는 얘기가 떠돈다. 사실 오라클사에서는 현재 PL/SQL은 현상유지 차원에서

계속 지원할 것이라고 하나, 자바쪽으로 비중이 옮겨가는 것은 사실인 것 같다.


결론은?

오라클 8i부터 자바로 stored procedure/function를 사용할 수 있다.

원래 pl/sql을 사용하던 사람은 계속 pl/sql을 쓰고, 처음하는 사람은 자바를 사용하도록 하자.

아무래도 둘이 섞어쓰면 찜찜할 것 같긴하다.

실제 자바소스가 변경되어, 오라클로 reload한후, 호출명세를 다시 설정해주지 않았더니 오라클이 맛가는 현상을 겪었다.

alter system kill session '';으로 어떻게 해보려고 했으나 감감 무소식.. shutdown abort밖에 없었다.



자, 이제 직관적으로 간단명료하게 진행하겠다.

우선 오라클에 테스트용 테이블을 생성한다.

SQL> create table test(id int, name varchar(10), salary float);


테이블이 생성되었습니다.


자바로 로직을 작성하고, loadjava를 이용하여 DB에 집어넣는다.

윈도   c:\oracle\ora92\bin\loadjava.bat

유닉스

[sky@gw1 sky]$ file $ORACLE_HOME/bin/loadjava

/u01/app/oracle/product/9.2.0/bin/loadjava: Bourne shell script text executable



[develope/load class]

D:\temp>type TestDML.java

import java.sql.*;

import oracle.jdbc.*;


public class TestDML

{

        // 리턴값이 없으면 오라클 Stored Procedure

        public static void addPerson(int id, String name, float salary)

        {

                System.out.println("새로운 사용자 등록");


                try

                {

                        Connection conn = DriverManager.getConnection("jdbc:default:connection:");

                        String sql = "insert into test values (?,?,?)";

                        PreparedStatement pstmt = conn.prepareStatement(sql);

                        pstmt.setInt(1,id);

                        pstmt.setString(2,name);

                        pstmt.setFloat(3,salary);

                        pstmt.executeUpdate();

                        pstmt.close();

                }

                catch(SQLException e)

                {

                        System.err.println("ERROR! Adding Employee: " + e.getMessage());

                }

        }


        // 리턴값이 있으면 오라클 Function

        public static float getSalary(int id)

        {

                float salary = 0;

                System.out.println(id + "의 급여");


                try

                {

                        ResultSet rs;

                        Connection conn = DriverManager.getConnection("jdbc:default:connection:");

                        String sql = "select salary from test where id=?";

                        PreparedStatement pstmt = conn.prepareStatement(sql);

                        pstmt.setInt(1,id);

                        rs = pstmt.executeQuery();


                        rs.next();

                        salary = rs.getFloat(1);


                        rs.close();

                        pstmt.close();

                }

                catch(SQLException e)

                {

                        System.err.println("ERROR! Adding Employee: " + e.getMessage());

                }


                return salary;

        }

}


-u : DB계정

-v : verbose feedback

-resolve : .class파일이 아닌 .java파일이므로 컴파일해주라.

D:\temp>loadjava -u kang/xxxxxx -v -resolve TestDML.java

arguments: '-u' 'kang/xxxxxx' '-v' '-resolve' 'TestDML.java'

created  : JAVA$CLASS$MD5$TABLE

creating : source TestDML

created  : CREATE$JAVA$LOB$TABLE

loading  : source TestDML

creating : TestDML

resolving: source TestDML


오라클 kang계정을 보면, 뭔가 생성된 것이 보일 것이다.

SQL> select * from tab;


TNAME                          TABTYPE  CLUSTERID

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

CREATE$JAVA$LOB$TABLE          TABLE

JAVA$CLASS$MD5$TABLE           TABLE

JAVA$OPTIONS                   TABLE

TEST                           TABLE


SQL> select object_name, object_type, status from user_objects

  2  where object_name='TestDML';


OBJECT_NAME     OBJECT_TYPE        STATUS

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

TestDML         JAVA CLASS         VALID

TestDML         JAVA SOURCE        VALID


SQL>


위에서 status필드가 VALID가 아니라면 user_errors를 조회해보라.

loadjava는 .sqlj .properties .ser .jar .zip을 인식한다.

만일, kang계정이외에 maddog계정도 이 놈을 사용하겠다고 하면 다음과 같이 한다.


D:\temp>loadjava -u kang/xxxxxx -resolve -resolver "((* KANG)(* MADDOG)(* PUBLIC))" TestDML.java




[publising classes]

SQL이나 PL/SQL에서 자바로 생성한 클래스파일을 호출하려면 publish를 해야 하는데,

자바 클래스는 호출명세(call specification, call spec 혹은 PL/SQL wrapper이라고 불리기도 함)

를 생성/컴파일함으로써 publish될 수 있다.

호출명세는 자바 메소드의 인자와 리턴형을 오라클 SQL타입과 매핑하는 역활을 한다.


SQL> create or replace procedure add_person(id number, name varchar2, salary number)

  2  as language java

  3  name 'TestDML.addPerson(int, java.lang.String, float)';

  4  /


프로시저가 생성되었습니다.


SQL> create or replace function get_salary(id number) return number 

  2  as language java

  3  name 'TestDML.getSalary(int) return int';

  4  /


함수가 생성되었습니다.



즉, 우리는 이제부터 add_person프로시저와 get_salary함수를 사용하면 되는 것이다.

자바출력은 트레이스파일로 쓰여지므로, 출력을 화면에 표시하도록 변경후 프로시저 호출

SQL> set serveroutput on

SQL> call dbms_java.set_output(2000);


호출이 완료되었습니다.


SQL> exec add_person(1,'강명규', 3000.01);

새로운 사용자 등록


PL/SQL 처리가 정상적으로 완료되었습니다.


SQL> select get_salary(1) from dual;


GET_SALARY(1)

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

      3000.01


함수는 다음과 같이 해도 된다.

SQL> var salary number;

SQL> call get_salary(1) into :salary;

1의 급여


호출이 완료되었습니다.


SQL> print salary;


    SALARY

----------

   3000.01



자바에서 PL/SQL을 호출하는 방법

CallableStatement cstmt = conn.prepareCall("{my_plsql_porc}");




[Usage Scenario]

오라클에서 OS상의 파일에 대한 작업을 하려면 UTL_FILE패키지를 이용해야 한다.

이것은 OS상의 파일에 접근할 수 있는 인터페이스를 제공하지만 여러가지로 불편하다.

이 경우 자바의 File I/O를 이용하면 더 효율적으로 작업할 수 있을 것이다.



D:\temp>type FileTest.java

import java.io.*;


class FileTest

{

        public static String readFile(String usrFile)

        {

                String fileStr = new String();

                String tmpStr = new String();

                try

                {

                        File file = new File(usrFile);

                        FileReader fr = new FileReader(usrFile);

                        LineNumberReader lnr = new LineNumberReader(fr);


                        do{

                                tmpStr = lnr.readLine();

                                fileStr += tmpStr;

                        } while(tmpStr != null);


                        lnr.close();

                        fr.close();


                }

                catch(Exception e)

                {

                        System.err.println("ERROR! Handling File: " + e.getMessage());

                }


                return fileStr;

        }

}



D:\temp>loadjava -u kang/xxxxxx -v -resolve FileTest.java

arguments: '-u' 'kang/xxxxxx' '-v' '-resolve' 'FileTest.java'

creating : source FileTest

loading  : source FileTest

creating : FileTest

resolving: source FileTest



SQL> create or replace package my_java_utils is

  2  function read_file(file varchar2) return varchar2;

  3  end my_java_utils

  4  ;

  5  /


패키지가 생성되었습니다.


SQL> create or replace package body my_java_utils is

  2  function read_file(file varchar2) return varchar2

  3  as language java

  4  name 'FileTest.readFile(java.lang.String) return java.lang.String';

  5  end my_java_utils;

  6  /


패키지 본문이 생성되었습니다.


SQL>



D:\temp>type hello

안녕!

나는 강명규라고 해!



SQL> conn system/xxxxxx

연결되었습니다.

SQL> exec dbms_java.grant_permission( 'KANG', 'SYS:java.io.FilePermission','d:\temp\hello', 'read' );


PL/SQL 처리가 정상적으로 완료되었습니다.


SQL> conn kang/xxxxxx

연결되었습니다.

SQL> set serveroutput on

SQL> call dbms_java.set_output(2000);


호출이 완료되었습니다.

SQL> select my_java_utils.read_file('d:\temp\hello') from dual;


MY_JAVA_UTILS.READ_FILE('D:\TEMP\HELLO')

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

안녕!나는 강명규라고 해!null


SQL>


사실 위에서는 hello라는 파일로 했지만, alert.log파일에 대한 처리로 하면 좀 더 현실적일 것이다.



[작업한 내용 제거]

SQL> conn system/xxxxxx

SQL> exec dbms_java.revoke_permission( 'KANG', 'SYS:java.io.FilePermission','d:\temp\hello', 'read');


PL/SQL 처리가 정상적으로 완료되었습니다.


SQL> connect kang/xxxxxx

연결되었습니다.

SQL> drop package my_java_utils;


패키지가 삭제되었습니다.


SQL> drop function get_salary;


함수가 삭제되었습니다.


SQL> drop procedure add_person;


프로시저가 삭제되었습니다.


D:\temp>dropjava -u kang/xxxxxx TestDML FileTest




This article comes from dbakorea.pe.kr (Leave this line as is)


:
Posted by 라면스프
2012. 7. 4. 15:52

eclipse Ganymede 64bit Enjoy/JAVA2012. 7. 4. 15:52




This build requires a 64-bit JVM, and will not run with a 32-bit JVM.

You can, for example, use the Sun 64-bit 1.5 JVM for AMD64.  Note

that the Sun 1.4.2 JVM for AMD64 is 32-bit and therefore cannot be

used to run this build.


http://archive.eclipse.org/eclipse/downloads/drops/R-3.4.2-200902111700/download.php?dropFile=eclipse-SDK-3.4.2-win32-x86_64.zip

:
Posted by 라면스프
출처 : http://www.ibm.com/developerworks/kr/library/os-javapdf/index.html


자바 애플리케이션에서 동적으로 PDF 파일 생성하기


많은 애플리케이션들이 PDF 문서의 동적 생성을 요구하고 있다. 이 같은 애플리케이션은 이메일 전달용 고객 일람표를 생성하는 은행부터, 책의 특정 챕터를 구매하여 이를 PDF 포맷으로 받는 리더기 까지 다양하다. 그 리스트는 끝이 없다. 이 글에서 iText 자바 라이브러리를 사용하여 PDF 문서를 만들 것이다. 여러분의 이해를 돕기 위해 샘플 애플리케이션도 제공한다.

iText와 친해지기

iText는 Lowagie.com(참고자료)에서 무료로 사용할 수 있는 자바 라이브러리이다. iText 라이브러리는 강력하고, HTML, RTF, XML 문서의 생성 뿐만 아니라 PDF 생성을 지원한다. 문서에 사용될 다양한 폰트를 선택할 수 있다. 또한 iText 구조에서는 같은 코드를 사용하여 앞서 언급한 유형의 문서를 만들 수 있다.

iText 라이브러리에는 다양한 폰트로 PDF 텍스트를 만들고, PDF 문서에 테이블을 생성하고, 워터마크를 페이지에 추가하는 클래스가 포함되어 있다. iText로 사용할 수 있는 더 많은 기능들이 있다. 하지만 그 모든 것을 이 글에서 다 설명하기는 불가능하다. PDF 생성에 필요한 기본적인 것만을 설명하겠다.

샘플 애플리케이션 개발에 Eclipse를 사용할 것이다. 오픈 소스 IDE인 Eclipse는 무료로 사용할 수 있고 매우 강력하다. 지금 Eclipse를 다운로드 하라. (참고자료)

iText API

com.lowagie.text.Document는 PDF 문서 생성을 위한 주 클래스이다. 인스턴스로 만들어질 첫 번째 클래스이다. 문서가 생성되면 라이터는 여기에 작성해야 한다. com.lowagie.text.pdf.PdfWriter는 PDF 라이터이다. 다음은 일반적으로 사용되는 클래스들이다.

  • com.lowagie.text.Paragraph -- 들여쓰기 단락을 나타내는 클래스이다.
  • com.lowagie.text.Chapter -- PDF 문서의 챕터이다. 타이틀로 Paragraph를 사용하고, 챕터 번호로 int를 사용한다.
  • com.lowagie.text.Font -- 폰트, 크기, 스타일, 컬러 같은 모든 폰트 스팩들이 포함되어 있다. 다양한 폰트들은 이 클래스에 정적 상수로서 선언된다.
  • com.lowagie.text.List -- 많은 ListItems를 포함하고 있는 리스트이다.
  • com.lowagie.text.Table -- 매트릭스에서 정렬된 셀들을 포함하고 있는 테이블이다.

Eclipse에서 iText 다운로드 및 설정하기

순수 자바 라이브러리인 아아텍스트는 JAR 파일의 형태로 되어 있다. (참고자료.) 라이브러리를 다운로드 하면(C:\temp) Eclipse 환경에서 iText 라이브러리를 설정한다.

  1. Eclipse에서 iText라는 이름의 새로운 자바 프로젝트를 만든다.
  2. Package Explorer 뷰에서 iText 프로젝트를 오른쪽 클릭하고 Properties를 선택한다.
  3. Java Build Path를 클릭한다. Libraries 탭에서, Add External JARs를 클릭한다.
  4. C:\temp 디렉토리를 검색하여 itext-1.3.jar를 선택한다.
  5. OK를 클릭한다.

iText가 설정되면 Eclipse는 동적인 PDF 문서를 생성하는 자바 애플리케이션을 구현할 준비를 갖춘 것이다.

샘플 애플리케이션

직접 샘플을 만드는 것 만큼 확실한 설명 방법은 없다. 필요한 툴(Eclipse IDE)과 라이브러리(iText 라이브러리)가 준비되었으니 샘플 프로그램을 디자인 및 개발해 보자.

평이한 텍스트, 특별 폰트로 색상을 입힌 텍스트, 테이블, 리스트, 챕터, 섹션 같은 기본적인 엘리먼트를 포함하고 있는 PDF 문서를 만들어 보자. 이 애플리케이션의 목적은 여러분이 iText 라이브러리를 사용하는 방법을 보다 잘 이해할 수 있도록 돕는 것이다. PDF 문서 생성과 관련되어 많은 일을 수행하는 많은 클래스들이 있다. 이 모든 클래스들을 다 다루기는 불가능하다. iText의 javadoc은 이러한 클래스들의 사용법을 잘 이해할 수 있는 좋은 자료이다. 코딩부터 시작해 보자.

첫 번째 단계는 문서를 만드는 것이다. 이 문서는 PDF 문서의 모든 엘리먼트용 컨테이너이다.


Listing 1. 문서 객체의 인스턴스화
				
Document document = new Document(PageSize.A4, 50, 50, 50, 50);

첫 번째 인자는 페이지 크기이다. 다음 인자들은 각각 왼쪽, 오른쪽, 상단, 하단 여백들이다. 이러한 유형의 문서는 아직 정의되지 않았다. 여러분이 만드는 라이터의 유형에 의존한다. 이 샘플에서 우리는 com.lowagie.text.pdf.PdfWriter를 선택했다. 기타 라이터로는 HtmlWriter, RtfWriter, XmlWriter 등이 있다. 이름만으로도 충분히 그 용도를 알 수 있다.


Listing 2. PdfWriter 객체의 생성
				
PdfWriter writer = PdfWriter.getInstance(document, \
new FileOutputStream("C:\\ITextTest.pdf"));
document.open();

첫 번째 인자는 문서 객체에 대한 참조이고, 두 번째 인자는 아웃풋이 작성될 파일의 고유 이름이다. 작성을 위해 문서를 연다.

이제, 문서의 첫 번째 페이지에 몇 가지 텍스트를 추가할 것이다. com.lowagie.text.Paragraph을 사용하여 어떤 텍스트라도 추가된다. 텍스트로 기본 단락을 만들고 폰트, 컬러, 크기 등 기본적인 설정을 할 수 있다. 각자의 고유 폰트를 사용해도 된다. 두 가지 옵션 모두를 살펴보자.


Listing 3. 단락 객체의 생성
				
document.add(new Paragraph("First page of the document."));
document.add(new Paragraph("Some more text on the \
first page with different color and font type.", 
FontFactory.getFont(FontFactory.COURIER, 14, Font.BOLD, new Color(255, 150, 200))));

아래 그림은 위 코드의 아웃풋이다. 위 코드 말미에 document.close();을 추가하여 문서를 마감한다.


그림 1. 아웃풋
Sample output of above code 

평이한 텍스트를 PDF 문서에 추가하는 방법을 배웠다. 복잡한 요소들도 문서에 추가해야 한다. 새로운 챕터를 만든다. 이 챕터는 특별 섹션으로서 새로운 페이지로 시작하고 기본적으로 디스플레이 된 숫자가 있다.


Listing 4. 챕터 객체의 생성 
				
Paragraph title1 = new Paragraph("Chapter 1", 
           FontFactory.getFont(FontFactory.HELVETICA, \
           18, Font.BOLDITALIC, new Color(0, 0, 255)));
Chapter chapter1 = new Chapter(title1, 1);
chapter1.setNumberDepth(0);

위 코드에서 chapter1 이라는 새로운 챕터 객체를 만들었다. 제목은 "This is Chapter 1."이다. 숫자 한계를 0으로 설정하면 페이지에 챕터 번호가 디스플레이 되지 않는다.

섹션은 챕터의 하위 요소이다. 다음 코드에서, "This is Section 1 in Chapter 1." 이라는 제목의 섹션을 만들었다. 이 섹션에 텍스트를 추가하기 위해 또 다른 단락 객체인 someSectionText를 만들고 이를 섹션 객체에 추가한다.


Listing 5. 섹션 객체의 생성 
				
Paragraph title11 = new Paragraph("This is Section 1 in Chapter 1", 
           FontFactory.getFont(FontFactory.HELVETICA, 16, \
           Font.BOLD, new Color(255, 0, 0)));
Section section1 = chapter1.addSection(title11);
Paragraph someSectionText = new Paragraph("This \
text comes as part of section 1 of chapter 1.");
section1.add(someSectionText);
someSectionText = new Paragraph("Following is a 3 X 2 table.");
section1.add(someSectionText);

테이블을 추가하기 전에 문서가 어떤 모습인지를 보자. 다음 두 줄을 추가하여 문서를 종료하고 프로그램을 컴파일 및 실행하여 PDF 문서를 만든다. document.add(chapter1);document.close();.


그림 2. 아웃풋
Sample output of chapter 

이제 테이블 객체를 만들어 보자. 테이블에는 열과 칼럼의 매트릭스가 포함된다. 한 열의 셀은 한 개 이상의 칼럼으로 확장될 수 있다. 마찬가지로, 한 칼럼에 있는 셀은 한 개 이상의 열로 확장될 수 있다. 따라서, 3 x 2 테이블은 정확히 6 개의 셀만 가질 필요가 없다.


Listing 6. 테이블 객체의 생성
				
Table t = new Table(3,2);
t.setBorderColor(new Color(220, 255, 100));
t.setPadding(5);
t.setSpacing(5);
t.setBorderWidth(1);
Cell c1 = new Cell("header1");
c1.setHeader(true);
t.addCell(c1);
c1 = new Cell("Header2");
t.addCell(c1);
c1 = new Cell("Header3");
t.addCell(c1);
t.endHeaders();
t.addCell("1.1");
t.addCell("1.2");
t.addCell("1.3");
section1.add(t);

위 코드에서, t라는 테이블 객체를 만들었다. 세 개의 칼럼과 두 개의 열을 갖고 있다. 테이블의 보더 색상을 설정했다. 패딩(padding)은 셀의 텍스트와 셀의 경계간 공간을 만드는데 사용된다. 스페이싱(spacing)은 인접하는 셀의 경계들간 공간이다. 그런 다음, 세 개의 셀 객체를 만든다. 각각 다른 텍스트를 갖고 있다. 이들을 계속해서 테이블에 추가한다. 첫 번째 칼럼에서 시작하여 같은 열의 다음 칼럼으로 이동한다. 열이 완성되면 다음 셀이 다음 열의 첫 번째 칼럼에 추가된다. 셀은 t.addCell("1.1"); 같은 셀의 텍스트를 제공하여 테이블에 추가될 수 있다. 마지막으로 테이블 객체가 섹션 객체에 추가된다.

마지막으로 PDF 문서에 리스트를 추가해 보자. 리스트에는 많은 ListItem들이 추가된다. 리스트에는 번호가 붙을 수도 있고 붙지 않을 수도 있다. 첫 번째 인자를 TRUE로 전달하면 번호가 붙은 리스트를 만들어야 한다.


Listing 7. 리스트 객체의 생성
				
List l = new List(true, false, 10);
l.add(new ListItem("First item of list"));
l.add(new ListItem("Second item of list"));
section1.add(l);

지금까지 chapter1 객체에 모든 것을 추가했다. chapter1에 추가될 더 이상의 객체가 없기 때문에, chapter1을 주 document에 추가해야 한다. 샘플 애플리케이션을 통해 한 개의 문서를 완성했다.


Listing 8. 주 document에 챕터 추가하기 
				
document.add(chapter1);
document.close();

샘플 애플리케이션 실행하기

  1. 샘플 애플리케이션, j-itextsample.jar(Download)을 다운로드 한다.
  2. 디렉토리에 j-itextsample.jar의 압축을 푼다. C:\temp에 추출하면, 소스와 클래스 파일은 C:\temp\com\itext\test에 배치된다.
  3. 명령어 프롬프트를 열고 디렉토리를 C:\temp로 변경한다.
  4. 명령어 프롬프트에 시스템의 classpath를 설정한다. 시스템의 classpath에 C:\temp\itext-1.3.jar를 포함시킨다. Windows®에서는, set classpath=C:\temp\itext-1.3.jar;%classpath%명령어를 실행한다.
  5. java com.itext.test.ITextTest 명령어로 애플리케이션을 실행한다.

이 프로그램은 C:\에 ITextTest.pdf 문서를 생성할 것이다. 아래 그림은 이 PDF 문서의 두 번째 페이지 모습이다.


그림 3. PDF 문서 모습
Screenshot of PDF document 

결론

지금까지 PDF 생성을 위한 기본 요소들을 살펴 보았다. iText의 장점은 같은 엘리먼트의 신택스가 다른 유형의 라이터에도 사용될 수 있다는 점이다. 또한, 이 라이터의 결과는 콘솔( XML과 HTML 라이터), 서블릿의 아웃풋 스트림 (PDF 문서의 웹 요청에 대한 응답), 또는 다른 유형의 OutputStream 으로 리다이렉션 된다. 또한 iText는 응답은 갖지만 PDF, RTF, HTML, XML 등 다양한 응답 유형을 보이는 상황에서 편리하게 사용할 수 있다. iText에서는 워터마크를 만들 수 있고 문서를 암호화 할 수 있으며 아웃풋도 정확하다.

:
Posted by 라면스프