반응형

Commons Lang


 

I. Commons Lang란?


Commons-Lang은 java.lang에 있는 클래스처럼 기능적으로 필요한 유틸리티들을 모아놓은 클래스들의 집합입니다. 아마도 여러분들 역시 직접 유틸리티 클래스들을 만들어 사용하고 있을겁니다. 즉 코딩을 하다보면 이렇거 있었으면 좋겠다 싶은것들이 Commons Lang에 다 있다고 생각하시면 됩니다 ^^



II. 다운로드 및 설치


http://jakarta.apache.org/site/downloads/downloads_commons-lang.cgi 에서 다운받자!

설치는 각 어플리케이션의 클래스 패스에 복사합니다.



III. org.apache.commons.lang.SystemUtils


SystemUtils는 java.lang.System 클래스 처럼 시스템에 관련된 기능을 쉽게 이용 할 수 있도록 하는 시스템 관련 유틸리티입니다.

시스템 변수들을 가져올 때 매번 System.getProperty("JAVA_HOME")를 하기보다 SystemUtils.JAVA_HOME하면 간단하기 때문에 SystemUtils가 쓸만합니다.

SystemUtils의 변수들은 모두 static 변수이기 때문에 SystemUtils 객체생성 없이 SystemUtils.XXX로 바로 사용할 수 있습니다.


예) System.out.println("SystemUtils.FILE_ENCODING : "+SystemUtils.FILE_ENCODING);


반환값 변수명 설명
String SystemUtils.FILE_ENCODING System.getProperty("file.encoding")
String SystemUtils.FILE_SEPARATOR System.getProperty("file.separator")
String SystemUtils.JAVA_CLASS_PATH System.getProperty("java.class.path")
String SystemUtils.JAVA_CLASS_VERSION System.getProperty("java.class.version")
String SystemUtils.JAVA_COMPILER System.getProperty("java.compiler")
String SystemUtils.JAVA_EXT_DIRS System.getProperty("java.ext.dirs")
String SystemUtils.JAVA_HOME System.getProperty("java.home")
String SystemUtils.JAVA_IO_TMPDIR System.getProperty("java.io.tmpdir")
String SystemUtils.JAVA_LIBRARY_PATH System.getProperty("java.library.path")
String SystemUtils.JAVA_RUNTIME_NAME System.getProperty("java.runtime.name")
String SystemUtils.JAVA_RUNTIME_VERSION System.getProperty("java.runtime.version")
String SystemUtils.JAVA_SPECIFICATION_NAME System.getProperty("java.specification.name")
String SystemUtils.JAVA_SPECIFICATION_VENDOR System.getProperty("java.specification.vendor")
String SystemUtils.JAVA_SPECIFICATION_VERSION System.getProperty("java.specification.version")
String SystemUtils.JAVA_VENDOR System.getProperty("java.vendor")
String SystemUtils.JAVA_VENDOR_URL System.getProperty("java.vendor.url")
String SystemUtils.JAVA_VERSION System.getProperty("java.version")
String SystemUtils.JAVA_VM_INFO System.getProperty("java.vm.info")
String SystemUtils.JAVA_VM_NAME System.getProperty("java.vm.name")
String SystemUtils.JAVA_VM_SPECIFICATION_NAME System.getProperty("java.vm.specification.name")
String SystemUtils.JAVA_VM_SPECIFICATION_VENDOR System.getProperty("java.vm.specification.vendor")
String SystemUtils.JAVA_VM_SPECIFICATION_VERSION System.getProperty("java.vm.specification.version")
String SystemUtils.JAVA_VM_VENDOR System.getProperty("java.vm.vendor")
String SystemUtils.JAVA_VM_VERSION System.getProperty("java.vm.version")
String SystemUtils.LINE_SEPARATOR System.getProperty("line.separator")
String SystemUtils.OS_ARCH System.getProperty("os.arch")
String SystemUtils.OS_NAME System.getProperty("os.name")
String SystemUtils.OS_VERSION System.getProperty("os.version")
String SystemUtils.PATH_SEPARATOR System.getProperty("path.separator")
String SystemUtils.USER_COUNTRY System.getProperty("user.country") != null ? System.getProperty("user.country") : System.getProperty("user.region")
String SystemUtils.USER_DIR System.getProperty("user.dir")
String SystemUtils.USER_HOME System.getProperty("user.home")
String SystemUtils.USER_LANGUAGE System.getProperty("user.language")
String SystemUtils.USER_NAME System.getProperty("user.name")
float JAVA_VERSION_FLOAT 자바 버젼을 float형으로
int JAVA_VERSION_INT 자바 버젼을 int형으로
boolean IS_JAVA_1_1 자바버젼이 1.1인가?
boolean IS_JAVA_1_2 자바버젼이 1.2인가?
boolean IS_JAVA_1_3 자바버젼이 1.3인가?
boolean IS_JAVA_1_4 자바버젼이 1.4인가?
boolean IS_JAVA_1_5 자바버젼이 1.5인가?
boolean IS_OS_AIX 운영체제가 AIX인가?
boolean IS_OS_HP_UX 운영체제가 HP Unix인가?
boolean IS_OS_IRIX 운영체제가 IRIX인가?
boolean IS_OS_LINUX 운영체제가 LINUX인가?
boolean IS_OS_MAC 운영체제가 MAC인가?
boolean IS_OS_MAC_OSX 운영체제가 MAC OSX인가?
boolean IS_OS_OS2 운영체제가 OS2인가?
boolean IS_OS_SOLARIS 운영체제가 SOLARIS인가?
boolean IS_OS_SUN_OS 운영체제가 SUN인가?
boolean IS_OS_WINDOWS 운영체제가 WINDOW인가?
boolean IS_OS_WINDOWS_2000 운영체제가 WINDOW 2k인가?
boolean IS_OS_WINDOWS_95 운영체제가 WINDOW 95인가?
boolean IS_OS_WINDOWS_98 운영체제가 WINDOW 98인가?
boolean IS_OS_WINDOWS_ME 운영체제가 WINDOW ME인가?
boolean IS_OS_WINDOWS_NT 운영체제가 WINDOW NT인가?
boolean IS_OS_WINDOWS_XP 운영체제가 WINDOW XP인가?

이를 바탕으로 제 컴(win2k)에서 출력한 결과입니다.


변수명 출력결과
SystemUtils.FILE_ENCODING MS949
SystemUtils.FILE_SEPARATOR \
SystemUtils.JAVA_CLASS_PATH C:\Tomcat 4.1\bin\bootstrap.jar
SystemUtils.JAVA_CLASS_VERSION 48.0
SystemUtils.JAVA_COMPILER null
SystemUtils.JAVA_EXT_DIRS C:\j2sdk1.4.2_06\jre\lib\ext
SystemUtils.JAVA_HOME C:\j2sdk1.4.2_06\jre
SystemUtils.JAVA_IO_TMPDIR C:\DOCUME~1\kitty1\LOCALS~1\Temp\
SystemUtils.JAVA_LIBRARY_PATH C:\j2sdk1.4.2_06\bin;.;C:\WINNT\system32;C:\WINNT;
SystemUtils.JAVA_RUNTIME_NAME Java(TM) 2 Runtime Environment, Standard Edition
SystemUtils.JAVA_RUNTIME_VERSION 1.4.2_06-b03
SystemUtils.JAVA_SPECIFICATION_NAME Java Platform API Specification
SystemUtils.JAVA_SPECIFICATION_VENDOR Sun Microsystems Inc.
SystemUtils.JAVA_SPECIFICATION_VERSION 1.4
SystemUtils.JAVA_VENDOR Sun Microsystems Inc.
SystemUtils.JAVA_VENDOR_URL http://java.sun.com/
SystemUtils.JAVA_VERSION 1.4.2_06
SystemUtils.JAVA_VM_INFO mixed mode
SystemUtils.JAVA_VM_NAME Java HotSpot(TM) Client VM
SystemUtils.JAVA_VM_SPECIFICATION_NAME Java Virtual Machine Specification
SystemUtils.JAVA_VM_SPECIFICATION_VENDOR Sun Microsystems Inc.
SystemUtils.JAVA_VM_SPECIFICATION_VERSION 1.0
SystemUtils.JAVA_VM_VENDOR Sun Microsystems Inc.
SystemUtils.JAVA_VM_VERSION 1.4.2_06-b03
SystemUtils.LINE_SEPARATOR  
SystemUtils.OS_ARCH x86
SystemUtils.OS_NAME Windows 2000
SystemUtils.OS_VERSION 5.0
SystemUtils.PATH_SEPARATOR ;
SystemUtils.USER_COUNTRY KR
SystemUtils.USER_DIR C:\Tomcat 4.1
SystemUtils.USER_HOME C:\Documents and Settings\kitty1
SystemUtils.USER_LANGUAGE ko
SystemUtils.USER_NAME kitty1
JAVA_VERSION_FLOAT 1.42
JAVA_VERSION_INT 142
IS_JAVA_1_1 false
IS_JAVA_1_2 false
IS_JAVA_1_3 false
IS_JAVA_1_4 true
IS_JAVA_1_5 false
IS_OS_AIX false
IS_OS_HP_UX false
IS_OS_IRIX false
IS_OS_LINUX false
IS_OS_MAC false
IS_OS_MAC_OSX false
IS_OS_OS2 false
IS_OS_SOLARIS false
IS_OS_SUN_OS false
IS_OS_WINDOWS true
IS_OS_WINDOWS_2000 true
IS_OS_WINDOWS_95 false
IS_OS_WINDOWS_98 false
IS_OS_WINDOWS_ME false
IS_OS_WINDOWS_NT false
IS_OS_WINDOWS_XP false

위의 결과값을 보니 너무 유용하게 사용되겠죠? ^^


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

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

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

저자 : GoodBug (unicorn@jakartaproject.com)

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

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

Posted by 1010
반응형

Jakarta POI



VII. 엑셀 쓰기예제


쓰기도 역시 읽기와 비슷합니다.

엑셀 워크북을 생성합니다. 행과 셀을 생성하려면 당연한 절차겠죠?

HSSFWorkbook workbook = new HSSFWorkbook();


시트를 생성합니다.

시트명을 파라미터로 바로 생성 합니다.

HSSFSheet sheet = workbook.createSheet("sheet name");


만약 한글로 시트명을 만들려면 다음과 같이 인코딩이 필요합니다.

HSSFSheet sheet = workbook.createSheet();

workbook.setSheetName( 0 , "한글" , HSSFWorkbook.ENCODING_UTF_16 );


셀에 사용할 스타일을 미리 생성해 둡니다.

HSSFCellStyle style = wb.createCellStyle();
style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
style.setBottomBorderColor(HSSFColor.BLACK.index);
style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
style.setLeftBorderColor(HSSFColor.GREEN.index);
style.setBorderRight(HSSFCellStyle.BORDER_THIN);
style.setRightBorderColor(HSSFColor.BLUE.index);
style.setBorderTop(HSSFCellStyle.BORDER_MEDIUM_DASHED);
style.setTopBorderColor(HSSFColor.BLACK.index);

등 여러가지 스타일을 만들 수 있습니다.


스타일은 다음 주소를 참고하세요

http://jakarta.apache.org/poi/apidocs/org/apache/poi/hssf/usermodel/HSSFCellStyle.html


로우를 하나 생성합니다.

HSSFRow row = sheet.createRow(0);


셀츨 하나 생성하여 스타일을 주고 값을 입력합니다.

HSSFCell cell = row.createCell((short)0);

cell.setCellStyle(style);

cell.setCellValue("jakarta project!");


만약 한글을 입력한다면 인코딩 해야 하며 값 세팅전에 해야 합니다.

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

cell.setCellStyle(style);

cell.setCellValue("자카드타 프로젝트!");


모든 셀이 다 입력되었으면 파일을 만듭니다.

FileOutputStream fs = new FileOutputStream("excelfile.xls");
workbook.write(fs);
fs.close();



VIII. 쓰기샘플 소스


<%@ page language="java" contentType="text/html;charset=euc-kr" %>
<%@ page import="java.io.*" %>
<%@ page import="org.apache.poi.poifs.dev.*" %>
<%@ page import="org.apache.poi.hssf.record.*" %>
<%@ page import="org.apache.poi.hssf.record.formula.*" %>
<%@ page import="org.apache.poi.hssf.model.*" %>
<%@ page import="org.apache.poi.hssf.usermodel.*" %>
<%@ page import="org.apache.poi.hssf.util.*" %>


<html>
<body>

<%

    String filepath = "C:\\Tomcat 5.0\\webapps\\ROOT\\write.xls";


    try {

        String[] cell_value = {"자카르타","프로젝트","www.jakartaproject.com"};


        HSSFWorkbook workbook = new HSSFWorkbook();


        HSSFSheet sheet = workbook.createSheet();
        workbook.setSheetName(0 , "한글명" ,HSSFWorkbook.ENCODING_UTF_16);


        HSSFCellStyle style = workbook.createCellStyle();
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        style.setLeftBorderColor(HSSFColor.GREEN.index);
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        style.setRightBorderColor(HSSFColor.BLUE.index);
        style.setBorderTop(HSSFCellStyle.BORDER_MEDIUM_DASHED);
        style.setTopBorderColor(HSSFColor.BLACK.index);           


        HSSFRow row = sheet.createRow(0);
        for (int i = 0 ; i < cell_value.length; i++){
            HSSFCell cell = row.createCell((short)i);
            cell.setEncoding(HSSFCell.ENCODING_UTF_16);
            cell.setCellStyle(style);
            cell.setCellValue(cell_value[i]);
        }
           
        FileOutputStream fs = null;
        try {
            fs = new FileOutputStream(filepath);
            workbook.write(fs);
        } catch (Exception e) {
        } finally {
            if (fs != null) fs.close();
        }
       
    } catch (Exception e) {
%>
        Error occurred:  <%= e.getMessage() %>
<%  
        e.printStackTrace();
    }   
   
%>

</body>
</html>



자 결과화면 입니다.





성공!


위의 소스를 기본으로 한다면 그리 어렵지 않을겁니다 ^^


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

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

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

저자 : GoodBug (unicorn@jakartaproject.com)

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

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

Posted by 1010
반응형

Jakarta POI


 

I. POI 란?


일반적으로 POI가 엑셀파일을 쓰는 컴퍼넌트로 알려져 있으나 POI는 프로젝트 이름입니다.
즉 POI는 Microsoft Format File을 액세스 할 수 있는 API를 제공합니다. (한마디로 자바에서 MS파일을 읽고 쓸수있도록 지원합니다.)


POI안에는 여러 컴퍼넌트들이 있습니다.

POIFS
Microsoft의 OLE2 포맷 형식의 문서를 자바로 읽고 쓸수 있는 컴퍼넌트입니다
기본적으로 POI의 모든 컴퍼넌트들이 POIFS를 사용합니다.
HSSF
Microsoft의 엑셀파일을 읽고 쓸수 있도록 지원하는 컴퍼넌트입니다.
HWPF
Microsoft의 워드파일을 읽고 쓸수 있도록 지원하는 컴퍼넌트입니다.
이 컴퍼넌트는 디자인 초기단계입니다.
HPSF
Microsoft의 OLE2 포맷 형식의 문서 속성을 어플리케이션에서 사용 할수 있도록 지원하는 컴퍼넌트입니다.
현재 읽기 기능만 제공합니다


워드파일을 핸들링 하는 HWPF는 초기단계라 사용을 못하지만 기대는 되는군요 ^^


ps. 영어사전을 찾아보니 poi는 하와이의 토란 요리를 뜻하더군요.

우리나라말로 하니 자카르타 토란 프로젝트 쯤 될라나? ㅎㅎ



II. 다운로드 및 설치


다운로드 받으러 갑시다~!

http://jakarta.apache.org/site/downloads/downloads_poi.cgi

현재 2.5.1버젼입니다.

다운받은 파일을 압축을 풀면 *.jar 파일들이 있을겁니다 이 파일들을 자신의 어플리케이션 /lib/에 복사합시다


POI API http://jakarta.apache.org/poi/apidocs/index.html

Quick Guide http://jakarta.apache.org/poi/hssf/quick-guide.html



III. Formula(수식) 지원에 관해..


엑셀을 읽고 쓸때 수식을 지원합니다.
org.apache.poi.hssf.usermodel.HSSFCell의 setCellFormula("formulaString") 메쏘드는 스프레드시트에 수식을 추가하는데 사용되며 getCellFormula() 메쏘드는 수식을 대표하는 문자열을 해석하는데 사용됩니다. 하지만 엑셀에서 사용하는 수식을 모두 사용 할 수는 없습니다.


지원되는 부분
-. 셀 참조, 시트참조, 지역참조
-. 상대적 혹은 절대적 참조
-. 수연산 및 논리연산
-. 시트 혹은 매크로 함수

-. 수식 결과값 반환


부분적 지원
문자열을 포함하는 수식을 해석할 수는 있지만 문자열값을 반환하는 수식은 아직 지원하지 않습니다.

지원되지 않는 부분

-. 배열 수식
-. 1진법 수식
-. 3D 참조
-. 에러 값 (cells containing #REF's or #VALUE's)


 

IV. 기본객체


가장 기본이되는 객체가 다음 4가지 입니다

이름에서 무엇을 뜻하는지 대강 짐작 할 수 있겠죵?


HSSFWorkbook - 엑셀 워크북을 말합니다.
HSSFSheet - 엑셀 쉬트를 나타냅니다.
HSSFRow - 엑셀에서 특정 행입니다.
HSSFCell - 엑셀에서 특정 행에대한 특정 셀입니다


위 4가지 객체는 앞으로 계속 나올겁니다. 눈여겨 미리 봐 둡시다. @.@



V. 엑셀 읽기 예제


POSFS을 이용하여 엑셀 워크북을 생성합니다.


POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream("excelfile.xls"));
HSSFWorkbook workbook = new HSSFWorkbook(fs);



생성된 워크북을 이용하여 시트 수만큼 돌면서 엑셀 시트 하나씩을 생성합니다.


int sheetNum = workbook.getNumberOfSheets();

for (int k = 0; k < sheetNum; k++) {
   System.out.println("Sheet Number : "+k);

   System.out.println(Sheet Name : " + workbook.getSheetName(k));
   HSSFSheet sheet = workbook.getSheetAt(k);

}



생성된 시트를 이용하여 그 행의 수만큼 돌면서 행을 하나씩 생성합니다.


int rows = sheet.getPhysicalNumberOfRows();

for (int r = 0; r < rows; r++) {
   HSSFRow row   = sheet.getRow(r);

   System.out.println("Row : "+row.getRowNum());

}



역시나 생성된 행을 이용하여 그 셀의 수만큼 돌면서 셀을 하나씩 생성합니다.


int cells = row.getPhysicalNumberOfCells();

for (short c = 0; c < cells; c++) {              <--!! short 형입니다. 255개가 max!
    HSSFCell cell  = row.getCell(c);

    int celltype = cell.getCellType();

    ...

}

셀을 생성하여 셀 타입에 따라 처리를 해주면 끝~


주의사항

만약 엑셀에서 A열에 아무런 값이 없으면 그 행은 읽지 못합니다.

행을 읽지 못하니 셀또한 처리 할 수 없습니다



VI. 엑셀읽기 샘플소스


샘플 데이터








A열은 B열에 대한 셀 타입을 나타내며 C열은 D열에대한 셀 타입을 나타냅니다.

즉 B:1 의 123456의 셀 타입은 A:1 일반 이라는 것이며 마찬가지로

D:1의 2005-02-09의 셀타입은 C:1 사용자정의로 세팅하였다는 겁니다


이 엑셀의 데이터를 다음 소스로 읽어 보겠습니다.


<%@ page
language="java"
contentType="text/html;charset=euc-kr"
import="java.io.*,
 org.apache.poi.poifs.filesystem.POIFSFileSystem,
 org.apache.poi.hssf.record.*,
 org.apache.poi.hssf.model.*,
 org.apache.poi.hssf.usermodel.*,
 org.apache.poi.hssf.util.*" %>


<html>
<head><title>Read example</title></head>
<body>

<%

  String excelfile = "C:\\Tomcat 5.0\\webapps\\ROOT\\example.xls";

  try {
       POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(excelfile));


       //워크북을 생성!               

       HSSFWorkbook workbook = new HSSFWorkbook(fs);

       int sheetNum = workbook.getNumberOfSheets();


       for (int k = 0; k < sheetNum; k++) {


            //시트 이름과 시트번호를 추출
%>

            <br><br>
            Sheet Number <%= k %> <br>
            Sheet Name <%= workbook.getSheetName(k) %><br>
<%
            HSSFSheet sheet = workbook.getSheetAt(k);
            int rows = sheet.getPhysicalNumberOfRows();


            for (int r = 0; r < rows; r++) {


                // 시트에 대한 행을 하나씩 추출
                HSSFRow row   = sheet.getRow(r);
                if (row != null) {
                     int cells = row.getPhysicalNumberOfCells();
%>
                     ROW  <%= row.getRowNum() %> <%=cells%></b><br>
<%

                     for (short c = 0; c < cells; c++) {


                         // 행에대한 셀을 하나씩 추출하여 셀 타입에 따라 처리
                         HSSFCell cell  = row.getCell(c);
                         if (cell != null) {
                              String value = null;

                              switch (cell.getCellType()) {

                                   case HSSFCell.CELL_TYPE_FORMULA :
                                       value = "FORMULA value=" + cell.getCellFormula();
                                        break;
                                   case HSSFCell.CELL_TYPE_NUMERIC :
                                       value = "NUMERIC value=" + cell.getNumericCellValue(); //double
                                       break;
                                  case HSSFCell.CELL_TYPE_STRING :
                                       value = "STRING value=" + cell.getStringCellValue(); //String
                                       break;
                                  case HSSFCell.CELL_TYPE_BLANK :
                                      value = null;
                                     break;
                                 case HSSFCell.CELL_TYPE_BOOLEAN :
                                     value = "BOOLEAN value=" + cell.getBooleanCellValue(); //boolean
                                    break;
                                case HSSFCell.CELL_TYPE_ERROR :
                                     value = "ERROR value=" + cell.getErrorCellValue(); // byte
                                     break;
                                default :
                             }
%>        
                          <%= "CELL col=" + cell.getCellNum() + " VALUE=" + value %> <br>
<%
                        }
                    }
                }
            }
       }
   } catch (Exception e) {
%>
       Error occurred:  <%= e.getMessage() %>
<%  
       e.printStackTrace();
    }

%>


</body>
</html>


위 소스의 결과입니다.


Sheet Number 0
Sheet Name 한글
ROW 0 4
CELL col=0 VALUE=STRING value=일반
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=사용자정의
CELL col=3 VALUE=NUMERIC value=38392.0
ROW 1 4
CELL col=0 VALUE=STRING value=숫자
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yy-m-d h:mm)
CELL col=3 VALUE=NUMERIC value=38393.0
ROW 2 4
CELL col=0 VALUE=STRING value=통화
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yy年 mm月 dd日)
CELL col=3 VALUE=NUMERIC value=38394.0
ROW 3 4
CELL col=0 VALUE=STRING value=텍스트
CELL col=1 VALUE=NUMERIC value=123456.0
CELL col=2 VALUE=STRING value=날짜 (yyyy년 mm월 dd일)
CELL col=3 VALUE=NUMERIC value=38395.0


 

결과를 보니 사용자가 지정한 셀 타입에 관계없이

숫자관련 셀은 POI에서 모두 숫자 타입으로 인식해 버렸습니다.

날짜 역시 지정한 셀 타입에 관계없이 모두 숫자 타입으로 인식해 버리는군요!

그럼 어떻게 날짜를 제대로 표현할까요?

날짜 타입을 제대로 나타내기 위해서는 날짜 Cell에는 getDateCellValue()를 사용하면

정상적으로 처리 할 수 있습니다.

SimpleDateformat sdf = new SimpleDateformat("yyyy-MM-dd hh:mm");
String date = sdf.format(cell.getDateCellValue());

등을 이용하면 나타내고자 하는 알짜를 표현 하기 더 쉽겠지요

나머지 수식을 가져 올때도 마찬가지입니다. 이런 사항을 도표로 나타내보았습니다.


org.apache.poi.hssf.usermodel.HSSFCell 에는 모두 6가지의 Cell Type이 있는데,

cell.getCellType()을 하면 그 셀의 반환값을 알 수 있으며 그에 상응하는 static 필드타입은 다음과 같습니다.


셀타입 필드타입

함수

함수반환값
0 CELL_TYPE_NUMERIC

getNumericCellValue()

-> 숫자 타입일때

getDateCellValue()

-> 날짜 타입일때

double


Date


1 CELL_TYPE_STRING

getStringCellValue()

String
2 CELL_TYPE_FORMULA

getCellFormula()

-> 수식자체를 가져올때

getNumericCellValue()

-> 수식 반환값이 숫자일때

getStringCellValue()

-> 수식 반환값이 문자일때

String


double


String

3 CELL_TYPE_BLANK

4 CELL_TYPE_BOOLEAN

getBooleanCellValue()

boolean
5 CELL_TYPE_ERROR

getErrorCellvalue()

byte

이번시간에는 POI 프로젝트를 이용하여 엑셀 파일을 읽어보았습니다.

다음 시간에는 엑셀파일에 쓰는 핸드링을 해 보도록 하지요~


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

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

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

저자 : GoodBug (unicorn@jakartaproject.com)

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

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

Posted by 1010
반응형

Commons-Fileupload

 


I. Commons-fileupload 란?

 

커먼스의 파일 업로드 패키지는 사용법이 쉬우며 쓸만한 함수들을 많이 지원합니다.

SmartUpload, MultipartRequest, Commons fileupload등을 모두 사용해 보았지만 개인적으로 가장 애착이 가는 파일 업로드입니다.

아쉬운점은 Commons-fileupload는 지난 2003년 6월 1.0버젼으로 정식 릴리즈 되었지만 그 이후로 이렇다 할 패치나 보안이 전혀 안되었다는 것입니다. 이말은 파일 업로드 자체가 그리 복잡한 패키지가 아니며 첫 정식 버젼이 그만큼 완벽하다는 것을 반증하는 말이기도 하겠지요 ^^



II. 다운로드 및 설치

 

자 다운로드 받으러 갑시다.

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

설치는 역시나 /WEB-INF/lib/ 폴더에 복사합니다.



III. 파일 업로드 처리 단계

 

먼저 파일 업로드된 아이쳄을 처리하기 전에 유효한 Request인지 확인해야 합니다.

boolean isMultipart = FileUpload.isMultipartContent(request);

이 코드는 현재 request가 multipart/form-data로 데이터를 전송했는지 유무를 true/false로 반환합니다.


업로드된 아이템이 매우 작다면 메모리에서 처리합니다.


큰 아이템이라면 임시 파일을 만들어 디스크에 저장하여 처리합니다.


너무 큰 아이템이라면 당연히 거부해야 합니다.


그렇지 않고 디폴트로 설정한 메모리, 최대값의 범위를 초과하지 않는다면 업로드를 시작합니다.

② ~ ⑤ 까지를 다음과 같이 간단히 할 수 있습니다.

// 파일 업로드 핸들러를 생성
DiskFileUpload upload = new DiskFileUpload();

// 한번에 메모리에 저장할 사이즈 설정

upload.setSizeThreshold(yourMaxMemorySize);

// 파일 업로드 최대 사이즈를 설정

upload.setSizeMax(yourMaxRequestSize);

// 파일 업로드 경로를 설정
upload.setRepositoryPath(yourTempDirectory);

이제 전송된 request를 parsing하여 아이템들을 추출합니다.

List /* FileItem */ items = upload.parseRequest(request);

위에서 설정한 값들을 request parsing단위로 따로 설정 할 수 있습니다.

List /* FileItem */ items = upload.parseRequest(request,
        yourMaxMemorySize, yourMaxRequestSize, yourTempDirectory);


이렇게 추출된 items를 이제 폼필드 타입에 따라 적절히 처리 합니다.

Iterator iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = (FileItem) iter.next();

    // 파일 타입이 아닌 다른 폼필드라면
    if (item.isFormField()) {
        processFormField(item);


    // 파일 타입 폼필드라면
    } else {
        processUploadedFile(item);
    }
}


폼필드에 따른 처리

만약 폼필드가 파일 이외의 파라미터라면 다음과 같이 처리하면 됩니다.

if (item.isFormField()) {
   //파라미터 이름

    String name = item.getFieldName();          

   //파라미터 값

    String value = item.getString();              
    ...
}


만약 폼필드가 파일 파라미터라면 다음과 같이 처리하면 됩니다.

if (!item.isFormField()) {

    // 파라미터 이름
    String fieldName = item.getFieldName();

    // 파일 이름 (경로포함)
    String fileName = item.getName();
    String contentType = item.getContentType();

    // 업로드한 파일이 메모리에 저장된 상태면 true, 거렇지 않고 임시 파일로 저장된 경우 false를 리턴
    boolean isInMemory = item.isInMemory();

    // 파일사이즈
    long sizeInBytes = item.getSize();
    ...


   // 파일 객체를 하나 만들어 업로드 완료!

   File uploadedFile = new File(...);

   item.write(uploadedFile);
}


파일 업로드 방식

파일 업로드 방식에는 모두 3가지가 존재합니다.

-. FileItem.write(File file);

-. FileItem.getInputStream();

-. FileItem.get()


write 는 직접적으로 업로드한 파일을 저장하는 가장 일반적이고 간단한 방식입니다.

나머지 두 방식은 스트림을 사용하여 업로드한 파일이 어떤 특별한 처리를 할 때 사용합니다.  혹은 데이터베이스에 바로 저장 할 경우에도 사용될 수 있습니다. 특히 get()은 메모리에 모두 할당하여 작업을 하니 주의를 요합니다.



VI. 샘플코드


import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;


public class UploadServlet extends HttpServlet {


   String upload = null;


   public void init(ServletConfig config) throws ServletException {
      super.init(config);  
      upload = config.getServletContext().getRealPath("/upload/")
   }
 
   public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

      try {
 
         if (FileUpload.isMultipartContent(request)) {

            DiskFileUpload fileUload = new DiskFileUpload();
            fileUpload.setRepositoryPath(upload);
            fileUpload.setSizeMax(100*1024*1024);
            fileUpload.setSizeThreshold(1024*50);
   
            List items = fileUpload.parseRequest(request);


            Iterator iterator = items.iterator();
            while (iterator.hasNext()) {


                FileItem item = (FileItem) iterator.next();

                if (!item.isFormField()) {
                    if (fileItem.getSize() > 0) {
                        //파일 이름을 가져온다      
                        String filename = fileItem.getName().substring(fileItem.getName().lastIndexOf("\\")+1);
       
                         try {
                              File file = new File(upload+filename);
                              fileItem.write(file);
                              } catch (IOException e) {
                                   System.out.println(e);
                              }      
                         }
                    }
               }
          }

      } catch (org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException e) {

          // 파일 사이즈 초과시 발생하는 익셉션
          System.out.println("파일 사이즈가 100메가 보다 더 초과되었습니다");
      } catch (Exception e) {
          System.out.println("업로드시 예기치 못한 오류가 발생하였습니다");
      }
   }
}


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

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

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

저자 : GoodBug (unicorn@jakartaproject.com)

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

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

Posted by 1010
반응형

Apache JMeter



VI. 테스트 구성단위

 

앞의 예제에서 대강의 테스팅 흐름을 살펴보았습니다. 이제 각각의 요소별로 자세히 알아봅시다.


크게 보면 다음 7가지 요소들로 나누어집니다.

1. 쓰레드 그룹 (Thread Group)

쓰레드 그룹은 테스팅에 있어 시작점이 되며 모든 요소들은 최소한 하나의 쓰레드 그룹에 속해야 합니다.


쓰레드 프러퍼티부분이 가장 중요하며 테스팅의 효과를 어떻게 얻을 것인지 결정하게 됩니다. 쓰레드 프러퍼티는 다음과 같이 생각할 수 있습니다.

① 쓰레드 갯수 : 몇명으로 테스트할 것인가?

② 램업 주기 : 얼마나 빨리 테스트 할 것인가?

③ 반복 수 : 얼마나 많이 테스트 할 것인가?


만약 쓰래드 갯수를 20개, 랩업 주기를 100초, 반복 수를 2로 하였다면 전체 테스트 수는 40(20x2 )번이 테스팅 되며, 한 쓰레드가 실행 후 다음 쓰레드 실행 까지는 5(100/20)초가 걸리며 총 수행 시간은 100초 입니다.

쉽죵?

만약 무한반복을 하고자 한다면 forever에 체크하세요


1.9버젼부터는 스케쥴 기능이 추가되었습니다. 시작시간과 종료시간을 입력하면 메뉴에서 RUN하지 않아도 시작시간에 맞춰 실행하게 됩니다.


2. 컨트롤러 (Controller)

컨트롤러란 서버에 테스트 요청을 전달 할 때 무엇을 언제 보낼지를 지시합니다.

샘플러(Sampler, 무엇을)와 로직(Logic Controller, 언제) 두가지 타입이 있습니다.


2-1. 샘플러(Sampler)

샘플러는 테스트 서버에게 HTTP 요청을 보내고 싶으면 HTTP 요청 샘플러를, FTP 요청을 보내고 싶으면 FTP 요청 샘플러를 추가하면 됩니다.


좌측의 그림은 샘플러 종류를 나타냅니다.

정말 다양한 요청이 지원되고 있습니다.


만약 서버에 같은 타입의 요청을 다중으로 보내고자 한다면 Config Element의 디폴트 요소를 사용하는것이 편리합니다. (예: HTTP Request Default)










2-2. 로직 컨트롤러(Logic Controller)

로직 컨트롤러는 언제 요청을 전달해야 하는지 결정합니다. 다음 예를봅시다.

  • Test Plan
    • Thread Group
      • Once Only Controller
        • Login Request (an HTTP Request)
      • Load Search Page (HTTP Sampler)
      • Interleave Controller
        • Search "A" (HTTP Sampler)
        • Search "B" (HTTP Sampler)
        • HTTP default request (Configuration Element)
      • HTTP default request (Configuration Element)
      • Cookie Manager (Configuration Element)

    HTTP default request와 Cookie Manager가 Thread Group에 추가되어 있다는 것을 유의깊게 봅시다. 그리고 Interleave Controller에도 HTTP default request가 있습니다.

    ① Once Only 컨크롤러에 의해 로그인 요청은 딱 한번 요청이 됩니다. 이후의 반복작업에서는 이 작업이 스킵이 되게 됩니다.

    ② 그다음 검색 페이지를 요청합니다. 이 요청은 어떠한 컨트롤러도 개입이 되어있지 않습니다.

    ③ 검색페이지에서 "A"를 검색합니다. Interleave 컨트롤러의해 다음 반복 작업때에는 "B"를 검색합니다. 즉 순서를 돌아가며 실행 된다는 것입니다.


    이처럼 로직 컨트롤러는 다양한 구성요소의 조합을 가능 하게 해 줍니다.


    좌측 그림은 컨트롤러의 종류를 보여줍니다.


    대부분 이름만으로 짐작 가능한 컨트롤러이니 그리 어렵지는 않을 겁니다 ^^
















    3. 리스너(Listener)

    리스너는 테스팅한 결과의 정보를 나타내는데 사용됩니다. 즉 결과를 레포팅 해주는 것이죠

    어떤 위치든지 추가될 수 있으며 그 요소에 해당하는 데이터나 그 이하 노드에 해당하는 데이터들만 수집하게 됩니다.

    가장 간단한 Graph Result 리스너는 응답시간을 그래프에 뿌려줍니다.


    좌측 그림은 리스너의 종류들입니다.













    4. 타이머(Timer)

    기본적으로 JMeter는 요청들을 쉴틈없이 테스트 서버로 보내게 되는데 만약 아주 짧은 시간에 상당한 양의 요청들을 보낸다면 서버가 뻗어 버릴지도 모릅니다.

    타이머는 쓰레드가 만들어 내는 각 요청들 사이에 특정 시간만큼 딜레이를 주는 역할을 합니다.








    5. 어서션 (Assertions)

    어서션은 테스트 요청에 대한 응답이 제대로 된 응답인지 그 유효성을 검증해줍니다.

    예를들어 테스트 요청에 대한 응답이 어느 특정 텍스트를 포함하고 있는지를 확인 해 볼 수 있다는 것입니다.

    어서션의 결과를 볼려면 어서션 리스너를 추가해야 한답니다.


    좌측 그림은 어서션의 종류를 나타냅니다.









    이상 JMeter의 구성요소들에 대해 간략히 살펴보았습니다.


    다음 레퍼런스 사이트를 참조 하면서 테스트 계획을 구성, 실행한다면 상당히 괜찮은 테스트 시나리오를 만들 수 있습니다.

    http://jakarta.apache.org/jmeter/usermanual/component_reference.html


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

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

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

    저자 : GoodBug (unicorn@jakartaproject.com)

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

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

  • Posted by 1010
    반응형

    Apache JMeter



    I. Apache JMeter

     

    Apache JMeter는 100% 순수 자바로 만든 퍼포먼스 테스팅 도구 입니다.

    기본적으로는 Web Application을 테스팅 하는데 디자인 되었지만 다른 기능들도 테스트 할 수 있도록 확장되었답니다


    그럼 Apache JMeter로 무엇을 할 수 있을까요?

    JMeter는 정적인 것 뿐만 아니라 동적인 자원 (files, Servlet, Perl, Java Object, DataBase 와 Queries, FTP Servers 등) 둘다 성능을 테스트 하는데 사용됩니다. 즉 서버나 네트웍 혹은 Object에 스트레스를 가하여 다양한 형태의 상태에서 성능을 전반적으로 분석 할 수 있도록 도와준다는 겁니다.


    그럼 JMeter의 특징을 간단히 살펴보죵.

    -. HTTP나 FTP서버 뿐만 아니라 임의의 데이터베이스 쿼리도 성능을 테스트 할 수 있습니다.

    -. 100% 순수 자바로 구현되었기 때문에 기종에 상관없이 실행 할 수 있습니다.

    -. Swing 기반의 Componet를 지원합니다.

    -. Multithreading 기능을 이용하여 동시에 많은 Thread를 발생 시킬수도 있으며 혹은 독립된 Thread를 연속적으로 발생시켜 테스팅 할 수도 있습니다

    -. GUI 환경으로 빠른 작업을 정확하게 할 수 있답니다.

    -. 캐싱된 결과를 분석하고 재현 할 수 있습니다.

    -. 높은 확장성이 있습니다.


    II. 다운로드


    다운 로드는 요기서..

    http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi



    III. 설치 및 실행

     

    설치전 요구사항을 알아봅시다

    먼저 jdk 1.4 이상이어야 합니다. jdk 1.4.1 이하버젼에서는 GUI elements가 잘 작동하지 않는 다는 bug가 레포팅 되었습니다. 운영체제는  unix (solaris, linux) 및  Widnows 계열 모두 잘 작동합니다.


    그럼 다운 받은 파일의 압축을 풀어봅시다. 제가 받은 파일은 2.0.2버젼이군요


    잠깐 디렉토리 구조를 보지요.

    /bin 에는 실행관련 파일들이 들어있습니다.

    /docs 와 /printable_docs에는 사용자 매뉴얼과 데모가 들어있습니다.

    /extras 는 JMeter를 ant로 바로 실행할수 있도록 하는 설명이 들어있고요

    /lib에는 JMeter를 실행하면서 로딩해야할 다른 서드 파티 jar파일을 넣으면 됩니다 만약 JDBC 테스팅을 한다면 해당하는 벤더의 JDBC를 넣으면 되겠네요


    ㅈ ㅏ ~ 그럼 실행해 봅시다 /bin/jmeter.bat 을 따블클릭 합니다.


     

    IV. 테스트 계획 수립

     

    테스트 시작 전 먼저 계획을 수립해봅시다 어떻게 해야 할까요?

    그냥 쉽게 일반적으로 생각해 봅시다

    1) 테스트 인원 및 몇번을 반복할 지 결정한다
    2) 첫화면을 간다
    3) 로그인 페이지로 간다
    4) 500ms 정도 쉰다 (로그인 아이디, 패스워드 입력시간)
    5) 로그인을 한다
    6) 메뉴를 하나씩 클릭한다
    7) 특별한 메뉴는 반복적으로 클릭한다.
    8) 또한 어떤 메뉴는 딱 한번만 클릭해야 한다.
    9) 또한 다른 메뉴는 랜덤하게 클릭한다.
    등의 정도가 되겠지요..

    그럼 이러한 작업들이 모두 JMeter로 가능한가? YES!!



    V. 초간단 테스트 예제

     

    자 그럼 먼저 간단한 예제를 한번 만들어 봅시다.



    먼저 JMeter를 실행하면 다음과 같은 화면이 나올겁니다.

    많이 보고 얼렁 익숙해 집시다.













    왼쪽편에 'Test Plan'이라는 노드가 보이는데 이 노드는 테스트 계획을 나타낼 일련의 실행 코드 집합 이라고 보면 됩니다 (말이 좀 어렵낭?-_-?)


    중간에 User Defined Variables 라고 나오는데 이건 뭔지 저도 잘 모루겠습니다 -_-;

    암튼 분명한건 여기서 정의한 변수 및 값은 테스트 플랜 이하 노드에서 모두 상속받아 사용한다는 겁니다.


    다음에 체크박스 두개가 있는데 첫번째 'Run each Thread..' 요놈은 Thread를 순차적으로 실행 하겠냐 아니면 동시에 실행하겠냐의 여부를 묻는데 체크하지 않으면 동시에 실행 하는걸로 되어 있습니다. 여기서 Thread란 조금 후에 설명 하겠습니다. 두번째 체크박스는 각 요청에대한 서버의 응답 데이터를 파일에 기록할 것인지 여부를 말하는 것인데 이걸 체크하면 성능이 확~ 떨어지니 왠만함 하지 말라고 되어있습니다.


    자 이제 본격적으로 시작해 봅시다. 'Test Plan'을 오른쪽 마우스로 클릭해 봅시다



















    Thread Group 이란 테스트 계획을 수행할 수행 단위 그룹이라 보면 될것 같습니다. 이 Thread Group을 여러개 추가 할 수도 있으며 그럴 경우 위에서 언급한 체크박스로 동시에 실행 할 것인지 순차적으로 실행 할 것인지 결정 해야 합니다.



















    그럼 이름을 뭘로 할까요? 'Jakarta Project'라 하지요 -_-;

    ㅈ ㅏ 이름을 'Jakarta Project'라 하였습니다 멋집니다 ;;


    가운데 체크박스 3개가 있네요

    이건 만약 테스트 수행도중 에러(테스트 대상의 에러)가 발생 한 경우 계속할 것인지 Thread만 멈출 것인지 아니면 테스트 자체를 멈출것인지를 선택합니다 여기선 그냥 'Continue'로 하지요


    그다음 항목이 가장 중요하므로 잘 숙지해야 합니다.

    Number Of Threads 란 이 Thread Group이 생성할 Thread갯수를 말하는데, 쉽게 말하면 이 그룹에서는 몇 사람으로 테스트 할 것이냐 라고 생각하면 됩니다.

    Ramp-Up Period (in seconds)는 한 Thread가 시작 된 후 다음 Thread가 시작 될 때까지의 대기 시간을 의미합니다 예를 들어 보자면 10개의 Thread가 사용되고 Ramp-up Period가 50이라면 총 10개의 Thread가 모두 실행되려면 50초가 걸린다는 겁니다. 즉 평균적으로 보자면 한 Thread가 실행 후 다름 Thread까지 5(50/10)초정도 후에 실행 되다는 거지요 (휴 어렵다 =3)

    Loop Count는 실행 횟수를 말합니다. forever에 체크하면 무한 루프를 돕니다. 이때는 사용자가 수동으로 STOP 시켜줘야 합니다.


    이제 'Jakarta Project'에 마우스를 오른쪽으로 클릭 후 'Add -> Config Element -> HTTP Request Defaults'를 선택합니다.

















    이 'HTTP Request Defaults'는 HTTP request를 설정함에 있어서 이 노드 이하의 HTTP request는 모두 HTTP Request Defaults에서 설정한 값을 디폴트로 상속 받아 사용하겠다는 겁니다.


    반드시 추가해야 할 필수 요소는 아닙니다만 이후의 추가해야 할 HTTP Request노드가 많다면 일일이 다 다음과 같이 세팅해야 함으로 이를 추가해 놓는 편이 좋습니다.


    Protocol에는 당연히 웹이니 HTTP를 써야겠고 Server name or ip에는 연결할 서버의 이름이나 ip를 적습니다. 주의할것은 주소까지 모두 여기에 적으면 안됩니다. 나머지 부분은 path 부분에 적어야 합니다.


    예를들어 naver에서 jsp를 입력하여 찾기하면 다음 주소가 생기는데 이 예를 들어보도록 하지요 http://search.naver.com/search.naver?where=nexearch&query=jsp&frm=t1

    protocol : http

    servarname or ip : search.naver.com

    path : search.naver

    parameter name : where, query, frm

    parameter value : nexearch, jsp, t1

    을 입력하면 OK~


    하지만 위의 설정값 세팅으로 완료된 것이 아닙니다. 이제부터 테스트 실행을 하기 위한

    실질적인 노드를 추가해야 합니다.

    'Jakarta Project'를 오른쪽 마우스로 클릭하여 'Add -> Sampler -> HTTP Request'를 선택합니다.


















    HTTP Request는 HTTP요청을 웹서버에 전송하여 그 결과를 받아오는 Sampler입니다.

    우리는 좀전에 세팅한 HTTP Request Default의 값을 모두 상속하여 사용할 것이기 때문에 여기서 특별히 세팅할 것이 없습니다.


    이제 request에 대한 준비는 되었고.. 이제 그에 대한 응답을 어떻게 분석 할 것인지에 대해 준비를 해 봅시다.


    'Jakarta Project'를 역시나 오른쪽 마우스로 클릭하여 'Add -> Listener -> View Results Tree와 Graph Results'를 추가합니다


    모든게 ㄷ ㅏ ~ 준비되었습니다. 이제 실행해 보도록 하지요!

    이제 상위 메뉴중 'RUN -> START'를 클릭해봅시다.

    그러면 우측 상단에 있던 아주 자그마한 네모박스가 연두색 으로 표시됩니다. 이 표시가 현재 테스트중이라는 표시입니다. Thrad Group에 세팅된 정보에 의해 딱 10번 request가 가게 될 것입니다.



















    먼저 View Result Tree부터 테스트 실행 결과를 봅시다.

    각 HTTP Request 에 대해 여러 정보들을 표시해 주는군요!


    첫번째 탭인 'Sampler result'에는 load time, response code, response header, server, content-type, length등의 정보가 표시된니다.


    두번째 탭인 'Request'에는 request형태가 표시 되는군요

    세번째 텝인 'Response data'에는 응답받은 Html 코드를 보여주며 또한 이를 Render해서 보여줍니다.



















    'Graph Result'를 봅시다. 이 그림은 Thread Group에서 loop count를 forever해서 나타낸 그림입니다. 비쥬얼 하죠?


















    간단하죠? 여기서 배운것을 바탕으로 응용하면 어떠한 테스트 계획이든지 실행 가능 하답니다. 자 다음 시간에는 JMeter의 고급사용법을 알아보도록 하겠습니다.


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

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

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

    저자 : GoodBug (unicorn@jakartaproject.com)

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

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

    Posted by 1010
    반응형
    jakarta commons DbUtils 간단한 사용법

    Commons DbUtils : 데이터베이스 사용에 있어서 단순노가다로 이루어지던 많은 작업을 편리하게 해준다. 그동안 "이거 귀찮은데 유틸로 뽑아놓을까?" 아니면 "우씨~ 이런 노가다" 하던 부분이 한방에 해결됐다. 단순한 유틸 패키지이기에 사용법도 간단하고 편리하다.


    //1. JDBC 드라이버 로딩을 간략화(로딩 성공시 true 반환)

            if (!DbUtils.loadDriver("com.mysql.jdbc.Driver")) {

                System.out.println("Failed Loading JDBC Driver!");
                System.exit(0);

            }


    //2. Connection, ResultSet, Statement 등의 close를 간단하게

    (null 확인 - > 예외처리의 과정을 간단하게)
            DbUtils.closeQuietly(connection);


    //3. QueryRunner - 쿼리문 수행

    - SELECT

    query(Connection conn, String sql, ResultSetHandler rsh)

    query(Connection conn, String sql, Object param, ResultSetHandler rsh)

    query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) 등

    param은 PreparedStatement의 ?에 해당 .. 2개 이상은 배열을 만들어서 전달


    - INSERT, UPDATE, DELETE의

    int update(Connection conn, String sql)

    int update(Conneciton conn, String sql, Object param) 등

    executeUpdate()와 사용법 동일


    //4. ResultSetHandler - 빈이나 맵을 만들어서 ResultRet에서 읽어들여 넣어주는 노가다여 안녕~!

    BeanHandler, BeanListHandler, MapHandler, MapListHandler


    예)

    String query = "SELECT * FROM user WHERE name = ?";

    User user = null;

    ResultSetHandler rsh = new BeanHandler(User.class);

    QueryRunner runner = new QueryRunner();

    user = (User) runner.query(conn, query, "홍길동", rsh);


    -----------

    import java.sql.*;
    import org.apache.commons.dbutils.DbUtils;


    public class CommonsDBUtilExample {
        public static void main(String[] args) {
            Connection connection = null;
            String url = "jdbc:mysql://localhost/mysql";
            String user = "root";
            String password = "";

            if (!DbUtils.loadDriver("com.mysql.jdbc.Driver")) {
               System.out.println("Failed Loading JDBC Driver!");
               System.exit(0);
            }

            try {
                connection = DriverManager.getConnection(url, user, password);
                System.out.println("Connection successful!!");
                Statement select = connection.createStatement();
       ResultSet rs = select.executeQuery("select * from user");
       while (rs.next()) {
        System.out.println(rs.getString(1));
       }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                DbUtils.closeQuietly(connection);
            }
        }

    Posted by 1010
    반응형
    개발을 하다보면 간단한 화면 1~2개만 독립적으로 돌아가는 웹어플리케이션을 만들 때도 있습니다. 예를 들면 로그조회 프로그램 같은 것들이죠.

    그런 곳에는 Hibernate나 iBatis를 쓰기에는 너무 거창하다는 느낌이 들기도 합니다. 그렇다고 JDBC로 날코딩하기는 성가실때, 이럴 때는 apache commons DbUtils를 써볼만 합니다.


    JDBC에서 Connection, Statement,ResultSet의 close 글에 나온 것처럼 Connection을 닫는 번거로운 처리가 DbUtils.closeQuietly(con);로 끝나는 것만 해도 상당히 편합니다.


    아래 예제는  DBUtils + JSTL로 간단한 조회화면을 만들어 본 것입니다.

    <%@ page language="java" contentType="text/html; charset=EUC-KR"
        pageEncoding="EUC-KR"%>
    <%@ page import = "java.sql.*" %>
    <%@ page import = "java.util.Properties" %>
    <%@ page import = "org.apache.commons.dbutils.DbUtils" %>
    <%@ page import = "org.apache.commons.dbutils.QueryRunner" %>
    <%@ page import = " org.apache.commons.dbutils.handlers.MapListHandler" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%!
      private static final String SELECT_STMT =
                      "SELECT id, name, email, cell_phone_number FROM quiz_user";
    %>
    <%
     String url = "jdbc:hsqldb:hsql://localhost/sampledb";
     Properties prop = new Properties();
     prop.put("user","sa");  
     prop.put("password","");
     Connection con =  null;
     try{
      Class.forName ("org.hsqldb.jdbcDriver");
      con = DriverManager.getConnection(url,prop);
            QueryRunner runner = new QueryRunner();
            Object resultList = runner.query(con,SELECT_STMT, new MapListHandler());
            request.setAttribute("list",resultList);          
       } catch (SQLException ex) {

          throw new RuntimeException(ex);
       } finally {
         DbUtils.closeQuietly(con);
       }
     %>  
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
    <title>사용자</title>
    </head>
    <body>
      <h1>사용자  조회</h1>
      <h2>사용자  목록</h2>
      <table class="list">
       <tr>
        <th>id</th><th>이름</th><th>전화번호</th> <th>이메일</th>   
     </tr>
        <c:forEach var="item" items="${list}" varStatus="status">
     <tr>
      <td>${item.id}</td>
      <td align="center">${item.name}</td>
      <td>${item.cell_phone_number}</td>  
      <td align="center">${item.email}</td>
     </tr>
     </c:forEach>
      </table>
    </body>
    </html>


      몇 년전에 DbUtils와 비슷한 클래스를 만든 적이 있었는데, 그때도 좀 찾아볼 걸 그랬나봅니다. 그러고 보면 저도 apache commons에 이미 있는 것을 많이도 만들어본 삽질의 시간들을 겪었었습니다.  신입 때 commons beanutils하고 commons io에 포함된 것 비슷한 유틸리티 만들어 놓고 혼자서 뿌듯해 했었죠 -_-;


    참고자료

    Commons-DbUtils

    dbutils 활용방법



    출처 : http://benelog.egloos.com/1978345

    Posted by 1010
    반응형
    Spring 프레임워크 참고문서
    Spring 프레임워크 강의
    Spring 프레임워크 기반의 테스트
    Spring 프레임워크 Batch
    Acegi Security 문서
    Spring 프레임워크 워크북
    Spring 프레임워크 워크북 관련 문서 및 자료들
    Spring 프레임워크 워크북 추가 문서

    Spring 프레임워크는 상당히 방대한 기능을 제공하고 있으며, 빠른 속도로 발전하고 있다. 따라서 한권의 책에서 Spring 프레임워크가 가지고 있는 모든 기능을 다루기는 힘든 것이 사실이다. 따라서 이 위키를 통하여 Spring 프레임워크 워크북에서 다루지 못한 내용들을 하나씩 채워나갈 생각이다.

    독자들 중 Spring 프레임워크의 기능 중 책에서 다루지 않고 있는 기능에 대하여 알고 싶은 부분이 있다면 게시판을 통하여 제안을 해주기 바란다. 시간이 허락하는 한도내에서 문서를 작성하고 정보를 제공할 예정이다.

    Spring 프레임워크 워크북 부연설명
    • 4장-예제 4-12 applicationContext.xml 부연설명 : 4장 Spring JDBC p.244에 있는 (예제 4-12)applicationContext.xml에 대한 부연설명
    • Spring MVC를 활용한 정적인 페이지 개발 : 6장의 Spring MVC를 단계적으로 추가적인 설명과 처음 Spring MVC를 이용하여 구현하고자 하는 개발자에게 도움이 될 만한 내용이 추가된다. 또한 책에서는 메인페이지를 처음으로 구현하고 있는데, 실제 예제소스에서는 이미 완성된 소스를 보이고 있음으로 단계적으로 개발하기에 부족함이 있는 듯 하여 직접 하나씩 구현해 보면서 예제소스를 만들어 가는 것으로 한다.
    Spring 프레임워크 참고자료
    • Spring 프레임워크 참고 문서 : Spring 프레임워크를 공부하기 위한 참고문서를 정리해 놓은 페이지
    • unitils : Spring, Hiberate 프레임워크, Easymock 프레임워크를 Annotation 기반으로 테스트가 가능하도록 지원하는 프레임워크이다.
    Posted by 1010
    반응형
    2006년 한빛 미디어 강의 (Spring Framework)
    2007년 두번째 한빛 미디어 강의 (Spring Framework)
    2007년 한빛 미디어 강의 문서 (Spring Framework)
    2008년 한빛 교육 센터 강의 자료 (Spring Framework)
    4장-예제 4-12 applicationContext.xml 부연설명 (Spring Framework)
    Acegi Security 분석 - Acl (Spring Framework)
    Acegi Security 분석 - Authentication 기본 (Spring Framework)
    Acegi Security 분석 - Authentication과 Authorization에 대한 기본 개념 (Spring Framework)
    Acegi Security 분석 - Authorization 기본 (Spring Framework)
    Acegi Security 분석 - Domain object instance Authorization (Spring Framework)
    Acegi Security 분석 - Servlet Filter 설정 및 기본 메커니즘 (Spring Framework)
    Acegi Security 분석 - Web URL Authorization (Spring Framework)
    N사 신입 사원 교육을 위한 Spring 프레임워크 강의 (Spring Framework)
    ReloadableResourceBundleMessageSource 클래스를 이용하여 MessageSource 자동 로딩하기 (Spring Framework)
    Spring MVC에 HandlerInterceptor 사용하기 (Spring Framework)
    Spring 프레임워크 기반하에서 컴포넌트 관리 전략 (Spring Framework)
    Spring 프레임워크 빈 설정 파일에 대한 기본적인 설명 (Spring Framework)
    Spring 프레임워크 샘플 애플리케이션 (Spring Framework)
    Spring 프레임워크 워크북 2장 1강 - Spring IoC (Spring Framework)
    Spring 프레임워크 워크북 2장 2강 - Spring IoC (Spring Framework)
    Spring 프레임워크 워크북 2장 3강 - Spring IoC (Spring Framework)
    Spring 프레임워크 워크북 2장 4강 - Spring IoC (Spring Framework)
    Spring 프레임워크 워크북 2장 5강 - Spring IoC (Spring Framework)
    Spring 프레임워크 워크북 3장 1강 - Spring AOP (Spring Framework)
    Spring 프레임워크 워크북 3장 2강 - Spring AOP (Spring Framework)
    Spring 프레임워크 워크북 3장 3강 - Spring AOP (Spring Framework)
    Spring 프레임워크 워크북 3장 4강 - Spring AOP (Spring Framework)
    Spring 프레임워크 워크북 6장 1강 - Spring MVC (Spring Framework)
    Spring 프레임워크 워크북 6장 2강 - Spring MVC (Spring Framework)
    Spring 프레임워크 워크북 원고 준비문서 (Spring Framework)
    Spring 프레임워크 워크북을 위한 로드맵 (Spring Framework)
    Spring 프레임워크 워크북을 위한 참고문서 (Spring Framework)
    Spring 프레임워크 참고 문서 (Spring Framework)
    Unitils를 이용한 단위 테스트 (Spring Framework)
    샘플 예제를 위한 환경 세팅시 참고사항 (Spring Framework)
    자바지기 Spring 프레임워크 강의 (Spring Framework)
    Posted by 1010
    반응형
    출처 : http://www.jakartaproject.com/

    Spring 설치- 서론 spring 설치

    서론...

    작년에 한 것도 없고 요즘 재미도 없고 해서

    올해는 spring을 알아보려 합니다.

    아는 것도 없는데 저의 취미생활로 하니까 돌은 던지기 말아주시면 감사합니다. ^^*

    얼마 전에 회사에서 Spring in action 이라는 책을 신청해서 나와서

    책보면서 작성해 보려 합니다.


    spring 설치


    전 myeclipse를 사용합니다.

     Visit http://www.myeclipseide.com/

    여기서 받으시면 됩니다.

    이 툴을 사용하는 이유는 플러그가 자동으로 설치되고

    spring 개발을 쉽게 도와주기 때문입니다.


     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    그림에서 Add Spring Capabilities… 클릭하시면

    (주의 : 반드시 프로젝트를 하나 만들고 해야 합니다.)






































    그림이 나타나고 finish 하죠


    그런 다음 http://www.springframework.org 에서 spring 최신 버젼을 받습니다.

    책에서는 1.2.7 기준이라고 하는데  홈페이지에서는 벌써

    2.0.2 이네요 걍~~~ 2.0.2로 하려 합니다.

    다운을 하려고 보면 파일이 두 입니다.














    파일은 큰것으로 보아 서드파티 라이브러리가 포함된것이고 아래는 코아만 들어 있다고 하네요

    윗것으로 다운 받습니다

    물론 myeclipse에서 1.2 버전 지원하는데 2.0 다운 받아 수동으로 라이브러리 추가하려고 합니다.

    근데 아마도 책은 1.2 버전 기준이기때문에 나중 2.0 사용하지 않을까 하네요 ^^*



    Spring 라이브러리


    Jar 파일

    용도

    의존대상

    Spring-core.jar

    스프링 핵심 컨테이너와 유틸리티

    커먼스 로깅, 선택사항:Log4J

    Spring-aop.jar

    스프링 aop 프레임워크 메타데이터 지원

    Spring-core.jar, AOP 연맹

    선택사항:cglib, 커먼스 어트리뷰츠

    Spring-context.jar

    애플리케이션 컨텍스트, 유효성 검증 프레임워크, 템를릿 지원

    (벨로시티, 프리마커), 리모팅(jax-rpc, hessian, burlap), EJB 지원,

    스케쥴링

    Spring-core.jar

    선택사항:벨로시티,프리마커,javamail,

    Ejb,jax-rpc,hessian, burlap,쿼츠

    Spring-dao.jar

    Jdbc dao 지원 , 트랜잭션 기반구조

    Spring-core.jar

    선택사항:spring-aop.jar, jta

    Spring-orm.jar

    하이버네이트, jdo, 아이바티스를 포함한 orm 프레임워크 지원

    Spring-core.jar

    선택사항:하이버네이트,jdo,아이바티스

    Spring-web.jar

    애플리케이션 컨텍스트 유틸리티, 멀티파트 파일 업로드지원

    Spring-cotext.jar, 서블릿

    선택사항:커먼스 파일업로드,cos

    Spring-webmvc.jar

    스프링 mvc 프레이워크

    Spring-web.jar

    선택사항:jsp,jstl,타일즈,itext, poi

    Spring.jar

    다른 jar 파일들을 포함한 스프링 프레임워크 전체

    위의 모든 사항들을 포함


    사실 나도 모르는 용어들이 많다 사용해본 것도 개정도 있다.

    앞으로 알아가면 재미(?) 같다. ㅎㅎㅎㅎㅎ


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


    Spring 로드존슨이 만든 오픈소스 프레임 워크이며, 그의 책인 Expert one-on-one : j2ee design and development 처음 소개 되었다 한다. 어라... 이책 봤는데..왜 몰랐지…

    책에서 스프링의 원래 이름은 interface21 었다.


    스프링에 대한 감을 잡기 위한 설명은…


    1.경량

    크기와 부하의 측면에서 경량이고 1MB 크기의 jar파일로 배포된다. 그리고 스프링은 침입적이지 않다고 한다. 무슨말인지.. 스프링을 도입한 애플리케이션의 객체가 보통의 경우 스프링의 특정 클래스에 대한 의존성을 갖지 않는다는 의미라고 한다. 그냥 ejb 비해 의존성이 없다는 얘기로 이해하고 넘어가야 겠다


    2.제어역행

    제어역행(IoC, Inversion of Control)이라는 기술을 통해 애플리케이션의 느슨한 결합을 도모한다.

    말은 기본개념은 객체를 생성하거나 찾는 대신, 구현되는 방법을 기술하는 것이다. 컴포넌트와 서비스들을 코드에 직접 연결하지는 않지만, 설정 파일에서 어떤 컴포넌트가 어떤 서비스를 요구하는지를 기술한다. 컨테이너(이 경우, Spring 프레임웍, IOC 컨테이너)는 이 모든 것을 연결한다.


    3.관점지향

    관점지향 프로그래밍(AOP, Aspect-Oriented Programming) 위한 풍부한 지원을 한다. 여기서 관점지향 프로그래밍이란 비즈니스 로직을 프로그램밍하게만 한다는 것이다. 트랜잭션과 시스템 감시같은 것은  관련 모듈을 이용하면 된다.

    http://aopalliance.soureforge.net 참고하면 된다.


    4.컨네이너

    어플리케이션 객체의 생명주기와 설정을 포함하고 관리한다는 점에서 스프링은 일종의 컨테이너이고, 빈을 생성, 빈의 연관 설정등 있다고 한다.


    5.프레임워크

    스프링에서는 파일내에 선언적으로 구성하여 애플리케이션 객체를 생성하며 어플리케이션 로직 개발은 개발자에게 맡기고 이외는 기능은 모듈로서 제공한다.


























    Spring 프레임웍을 구성하는 각 모듈(또는 컴포넌트)은 독립적이거나, 다른 모듈들과 함께 구현된다. 각 컴포넌트의 기능은 다음과 같다.

    • 코어 컨테이너(core container): Spring 프레임웍의 핵심 기능을 제공한다. 코어 컨테이너의 주요 컴포넌트는 BeanFactory(Factory 패턴의 구현)이다. BeanFactoryInversion of Control (IOC) 패턴을 사용하여 애플리케이션의 설정 및 의존성 스팩을 실제 애플리케이션 코드에서 분리시킨다.
    • Spring 컨텍스트(Spring context): Spring 프레임웍에 컨텍스트 정보를 제공하는 설정 파일이다. Spring 컨텍스트에는 JNDI, EJB, 국제화, 밸리데이션, 스케줄링 같은 엔터프라이즈 서비스들이 포함된다.
    • Spring AOP 모듈(Spring AOP): 설정 관리 기능을 통해 aspect 지향 프로그래밍 기능을 Spring 프레임웍과 직접 통합시킨다. 따라서 Spring 프레임웍에서 관리되는 모든 객체에서 AOP가 가능하다. Spring AOP 모듈은 Spring 기반 애플리케이션에서 객체에 트랜잭션 관리 서비스를 제공한다. Spring AOP에서는 EJB 컴포넌트에 의존하지 않고도 선언적 트랜잭션 관리를 애플리케이션과 결합할 수 있다.
    • Spring DAO: Spring JDBC DAO 추상 레이어는 다른 데이터베이스 벤더들의 예외 핸들링과 오류 메시지를 관리하는 중요한 예외 계층을 제공한다. 이 예외 계층은 오류 핸들링을 간소화하고, 예외 코드의 양도 줄여준다. Spring DAO의 JDBC 예외는 일반 DAO 예외 계층에 순응한다.
    • Spring ORM: 프레임웍은 여러 ORM 프레임웍에 플러그인 되어, Object Relational 툴 (JDO, Hibernate, iBatis SQL Map)을 제공한다. 이 모든 것은 Spring의 일반 트랜잭션과 DAO 예외 계층에 순응한다.
    • Spring Web module: 웹 컨텍스트 모듈은 애플리케이션 컨텍스트 모듈의 상단에 구현되어, 웹 기반 애플리케이션에 컨텍스트를 제공한다. Spring 프레임웍은 Jakarta Struts와의 통합을 지원한다. 웹 모듈은 다중 요청을 핸들링하고, 요청 매개변수를 도메인 객체로 바인딩하는 작업을 수월하게 한다.
    • Spring MVC framework: MVC 프레임웍은 완전한 기능을 갖춘 MVC 구현이다. MVC 프레임웍은 전략 인터페이스를 통해 설정할 수 있으며, JSP, Velocity, Tiles, iText, POI 같은 다양한 뷰 기술을 허용한다.

    Pasted from <http://www-128.ibm.com/developerworks/kr/library/wa-spring1/>



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


    먼저 Hello World 라는 예제를 한번 해본다.



    GreetingService.java
    인터페이스

     : 여기에서 인터페이스로 만들어서 구현하는 이유는 특별히 없다.


























    GreeringServiceImpl.java

    : 인터페이스를 구현한 인사말을 출력하는 클래스이다.

    여기서 주목할것은 setGreeting() 있다는 것이다. 소스를 보게되면 setGreeting() 누가 호출했는지 자세히 알아보는것이다 이것이 spring 힘이 아닐까 한다.


















    applicationContext.xml

    : 파일은 spring 컨테이너에게 클래스에 대한 정보와 설정방법을 알려준다.

    <bean> </beam> 내용은  아래의 코드와 같다.


    GreetingServiceImpl greetingService = new GreetingServiceImpl();

    greetingService.setGreeting("Buenos Dias!");





     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    HelloApp.java 메인 클래스

    : BeanFactory 클래스가 스프링 컨테이너이다.












    그림은 출력물이다.


    아주 간단한 예제 프로그램이다. 생각은 spring 힘은 ejb에서 lookup으로 찾아서 실행하는 것이 아니라

    Xml 이용하여 빈들을 실행하고 제어 , 컨트롤을 하는 것이다. 이것이 역행제어를 말하는 같다.

    Ejb보다는 쉽게(?) 있고 Ejb에서 트랜잭션을 보장 해주는 것을 spring에서도 해주고 비즈니스 로직만 프로그래밍하면 이외 기능은 기타의 모듈로서 해결할 있을 거라 생각한다.


    그럼 앞으로 알아야 것은 빈들을 어떻게 컨트롤하는가 spring 다른 기능의 모듈과 어떻게 연결하는가만

    배우면 같다.



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


    Spring EJB에서 구현되는 것을 좀더 쉽게 구현 있다.(spring 다른 것과 결합하여) 제어 역행이라는 개념을 이용하여 인터페이스를 통해 서로 협업하는 간단한 자바 객체들() 사용해 엔터프라이즈 애플리케이션을 개발할 있다. 이들 빈은 런타임에 spring 컨테이너에 의해 함께 묶인다.

    결국 spring 적은 비용으로 느슨하게 결합된 코드를 유지할 있게 해준다.


    spring 제어 역행의 상부에 AOP 제공한다. AOP 애플리케이션 전체에  걸쳐 흩어져 있는 코드를 한곳(aspect) 위치하도록 준다. 런타임에 빈들이 함께 묶이면 애스펙트들이 그에 엮임으로써, 빈은 새로운 작동을 하게 된다.


    엔터프라이즈 개발을 지원하다는 명목하에, spring 다양한 퍼시스턴스 기술과 통합할 있다. JDBC, 하이버네이트, JDO, 어떤 것을 사용하든, 스프링의 DAO 프레임워크는 퍼시스턴스 프레임워크에 있어서 에러 처리와 자원관리를 위한 일관된 모델을 제공함으로써 개발 편의성을 도모한다.


    퍼시스턴스 기술과의 동합을 보와하는것은 spring 트랜잭션 지원 기능이다. EJB 사용하지 않고도 AOP 통해 애플리케이션에 선언적으로 트랜잭션 지원을 추가할수 있다.또한 분산 트랜잭션을 위한 JTA 트랜잭션과의 통합을 포함하여 다양한 트랜잭션을 지원한다.


    Spring 여러지원 가능한 기능으로 메일,EJB, 서비스, JNDI 다양한 J2EE 서비스와의 통합기능도 제공한다. 제어역행을 통해 이들 서비스를 쉽게 설정하며, 애플리케이션 객체에 단순한 인터페이스를 제공한다.


    Spring 프리젠테이션 계층을 우해 다중 뷰기술을 지원한다. 벨로시티나 JSP 같은 프리젠테이션 기술뿐만 아니라 마이크로소프트 엑셀, PDF 파일을 생성할 있다. 프리젠테이션의 상부에는 내장된 MVC 프레임워크가 존재하고 스트럿츠나 웹워크(webwork) 같은 다른 웹프레임워크의 대안을 제시하며, spring 모든 서비스와 좀더 쉽게 통합 있다.


    생각을 덧붙이자면,

    Spring CBD 개발된 컴포넌트인 같다. spring 트랜잭션을 지원하기 위해 AOP 컴포넌트를 붙이고, 데이터 베이스와의 연결은 JDBC, 하이버네이트, JDO 등의 컴포넌트로 사용하면 되고, 프리젠테이션은 태피스트리나 벨로시티 컴포넌트를 이용하면 같다.

    , 내가 구현 가능한 기능이 있으면 가져다가 spring 붙이고 사용하면 가능하다는 뜻이다.

    근데 그러기 위해서는 많은 컴포넌트를 알아야 하고 spring 붙이기 위해서는 붙이는 방법 등을 학습해야 한다. 알고 나면 쉬운 것이지만 처음부터 알기란 매우 힘들 같다.

    만약 이것을 학습하고 있는데 다른 좋은 무엇가가 나타나면 어떻게 되는 것일까…..




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


    Spring에서는 어떤 컴포넌트가 다른 컴포넌트와의 연관관계를 관리할 책임이 없다.

    어떤 컴포넌트에서 다른 컴포넌트를 호출하는 것을 말하는 같다.

    대신, 컨테이너에 의해 컴포넌트 간의 협업을 위한 참조가 주어진다.

    이렇듯  애플리케이션 컴포넌트 간의 연관관계를 만드는 행위를 묶기(wiring)라고 하며, 이번 장에서 다룰 주제이다.

    Spring 묶기는 단순히 객체간의 연관관계를 성립시키는 작업 이상의 것이다.

    또한 spring 사용해 빈의 특성을 설정하는 방법, 별도 파일로 배치(deployment) 설정을 외부화 하는 방법, 빈의 생명주기를 관리하는 방법 등을 알게 된다.

    비즈니스를 묶는 것과 관련된 내용이 spring 핵심이 아닐까 한다.


    Spring 프레임워크를 사용하기 위해 빈을 설정 때에는, 항상 spring 컨테이너에 어떤 지시사항을 기술해야 한다. 따라서 컨테이너를 알면, 빈이 어떻게 관리되는지를 이해하는데 도움이 되기때문에 컨테이너를 알아보자.

     컨테이너는 spring 프레임워크의 핵심이다. Spring 컨테이너는 제어역행(IOC) 사용해 애플리케이션을 구성하는 컴포넌트를 관리한다. 여기서 협력하는 컴포넌트간의 연관관계를 생성하는 것을 포함한다. 이는 객체는 좀더 명확하게 이행 있고, 재사용이 가능해지며, 단위 테스트가 쉬워진다고 한다.


    Spring 기본 컨테이너 2

       org.springframework.beans.factory.BeanFactory 인터네이스로 정의된 빈팩토리

       : 기본적인 의존성 주입 지원

      org.springframework.context.ApplicationContext 인터네이스로 정의되는 애플리케이션 컨텍스트

       : 프로퍼티 파일의 텍스트 메시지 해석, 애플리케이션 프레임워크 서비스 제공


    외에 다수 존재한다. 그리고 빈팩토리와 애플리케이션 컨텍스트를 모두 컨테이너 용어 한다.


    1. 팩토리

     - 빈을 생성하고 분배하는 책임을 지는 클래스이고 팩토리 디자인 패턴을 구현한 것이다.

        ( 팩토리 패턴은 객체를 생성하고 분배하는 패턴이고 자세한것은 스스로…^^)

     

       빈팩토리는 애플리케이션내의 많은 객체에 대해 알고 있기 때문에 객체들을 인스턴스화할때 협업하는 객체 간의 연관관계를 생성시키는 것이 가능하다.( 말은 객체들간의 관계를 정의하는 무엇가가 필요하는 말이다.)

      이렇게 하는 이유는 자신과 빈의 클라이언트로부터 설정이라는 작업이  없다. 그로 인하여 빈팩토리가 객체를 분배하는 시점에서는 객체들이 완전히 설정된 상태이며, 협업하는 객체들끼리 인식하고 있고 곧바로  사용할 있는 상태인 것이다.  빈팩토리는 커스텀 초기화 메소드와 소멸 메소드를 호출함으로써 빈의 생명주기에 개입할 있다.


    Spring 다양한 BeanFactory 구현 클래스 가장 유용한 것은 org.springframework.beans.factory.xml.XmlBeanFactory 로서 xml 파일에 기술되어 있는 정의를 바탕으로 빈을 로딩한다.


     BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));


    코드는 팩토리에게 XML 파일로부터 빈에 대한 정의를 읽어오라고 알려준다. 그러나 팩토리가 빈을 인스턴스화하는 것은 아니다. 빈은 팩토리에 "늦게 로딩"(lazy loading)되는데, 말은 팩토리가 빈의 정의(빈과 특성에 대한 설명) 즉시 로딩하는 반면, 자체가 필요하기 되기 전까지는 인스턴스화하지 않는다는 의미다.

      팩토리로부터 빈을 언어오기 위해서는 아래와 같다.


      MyBean myBean = (MyBean) factory.getBean("myBean");


    getBean(); 호출되면, 팩토리는 의존성 주입을 이용해 빈을 인스턴스화하고 빈의 특성(빈의 set 메소드) 설정하기 시작한다. 이렇게 해서 스프링컨테이너 안에서의 빈의 일생이 시작된다.


     

    2. 애플리케이션 컨텍스트

     

     표면적으로는 ApplicationContext BeanFactory 상당히 비슷하다. 빈을 로딩하고 빈들을 묶어주며, 요청에 따라 빈을 분배한다. , ApplicationContext 인터페이스가 BeanFactory 인터페이스를 확장한 것이다. 또한 getBean() 메소드를 사용해 ApplicationContext 로부터 빈을 얻을 있다.

    차이점은 팩토리는 모든 빈을 늦게 로딩(lazy loading)하는데, 애플리케이션 컨텍스트는  컨텍스트를 시작시킬때 모든 싱클톤 빈을 미리 로딩(preloading)함으로써 빈이 필요할때 즉시 사용될수 있도록 보장해 준다. , 빈이 생성되기를 기다릴 필요가 없다는 것이다.

    하지만 모든 객체를 싱클톤으로 생성해 놓는다지만 객체가 많아지면 무거울꺼라는 생각이 든다. 해보지 않아서 추측임.

    (싱클톤은 디자인패턴의 일종이다 스스로…. ^^)

     

     ApplicationContext 다음과 같은 추가기능을 제공한다.

     -.국제화(I18N) 지원을 포함해 텍스트 메시지를 해석하는 수단 제공

     -.이미지 등과 같은 자원을 로딩하는 범용적인 방법 제공

     -.리스너로 등록되어있는 빈에 이벤트를 발생할 있음.


     BeanFactory 자원이 제약이 따르는 이동통신기기 같은 상황이 아니면 ApplicationContext 사용한다고 한다.

     

    ApplicationContext 다양한 구현 클래스 일반적인

     -.ClasspathXmlApplicationContext : 클래스 패스에 있는 XML 파일로부터 컨텍스트 정의를 로딩하며, 컨텍스트 정의를 클래스 패스에 있는 자원으로 취급한다.

     -.FileSystemXmlApplicationContext : 파일 시스템에 있는 XML 파일로부터 컨텍스트 정의를 로딩한다.

     -.XmlWebApplicationContext : 애플리케이션에 포함되어있는 XML 파일로부터 컨텍스트 정의를 로딩한다.


    ) ApplicationContext context = new FileSystemXmlApplicationContext("c:/foo.xml");

        : 특정한 위치에서 foo.xml 찾음.

         ApplicationContext context = new ClassPathXmlApplicationContext("c:/foo.xml");

        : 클래스 패스에 있는 foo.xml 찾음.




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


      1. 빈의 일생

      전통적인 자바 애플리케이션에서의 빈의 생명주기는 new 키워드를 통해 인스턴스화 되거나 역직렬화(deserializatino) 되며, 사용할 있는 상태가 된다.




      여기서 잠깐

      직렬화는 객체의 현재 상태(attribute value)를 네트웍상의 다른곳(remote)또는 local의 file등에

      전달/보존하기 위해 byte stream으로 내보내는 작업(상태 copy)을 말합니다.

      예제)

      public class Person implements java.io.Serializable{

          

            public String name = "홍길동";

            public int    age  = "20";

            public static String address = "서울시";

            transient String post ="111";

      }


      위의 예제의 Person이라는 class의 인스턴스가 현재의 상태 를 네트웍으로 전송하기 위해 상태값을 직렬화 하면

      이 직렬화된 데이터는 네트웍으로 전송될것이고, 전달받는 상태를 복원하는 작업을 역직렬화
      (deserialized)라고

      합니다. 물론 전달받는 곳에는 Person이라는 class가 존재해야 합니다.

      그래서 역직렬화하는 과정에서 Person인스턴스가 생성되면서 전달받은 데이터로 상태를 복원합니다.


      RMI(Remote Method Invocation)기술을 사용할 경우 이 직렬화/역직렬화를 통해 remote간에 객체의

      상태를 전달받습니다.


      네트웍 전달뿐 아니라 파일에도 객체의 상태를 저장하기 위해 직렬화와 역직렬화를 사용합니다.

      직렬화는 ObjectOuputStream의 writeObject() 메소드를 사용하며, 역직렬화는 ObjectInputStream의

      readObject()를 사용합니다.


      그리고 직렬화 대상 class는 java.io.Serializable interface를 implements해야 합니다.

      Serializable interface내부는 비어져 있습니다.


      출처 : http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=1117764219&p=3&s=t



      Spring 빈의 생성방법을 커스터마이징 있는 기회를 제공하기 때문에 spring 컨테이너에서의 빈의 생명주기를 이해하는 것이 중요하다.


      다음 그림은 spring 애플리케이션 컨텍스트 안에서의 빈의 생명주기이다.




      빈의 생성


      a. 컨테이너는 빈의 정의(빈에 대한 정보를 어딘가에 있겠죠) 알아낸 다음, 빈을 인스턴스화 한다.

      b. 의존성 주입을 이용해 빈의 정의에 지정되어 있는 모든 특성에 값을 채운다.

      c. 빈이 BeanNameAware 인터페이스를 구현한다면, 팩토리는 빈의 ID setBeanName() 전달하여 호출한다.

      d. 빈이 BeanFactoryAware 인터페이스를 구현한다면, 팩토리는 자신의 인스턴스를 setBeanFactory() 전달하여 호출한다.

      e. 빈이 ApplicationContextAware 인터페이스를 구현했다면 setApplicationContext() 메소드가 호출된다.

      f. 빈과 연관되어 있는 하나 이상의 BeanPostProcessor 존재한다면, 각각의 모든 postProcessBeforeInitialization() 메소드가 호출된다.

      g. 빈이 재정되어 있는 init-method 있으면 호출된다.

      h. 마지막으로 빈과 연관되어 있는 하나 이상의 BeanPostProcessor 존재하다면, 모든 postProcessAfterInitialization()메소드가 호출된다.
      i.
      빈은 애플리케이션에 의해 즉시 사용 있는 상태이며, 이상 필요하지 않을때까지 팩토리 안에 남아 있게 된다.


      빈의 소멸


      a. 빈이 DisposableBean 인터페이스를 구현하고 있다면, destroy() 메소드가 호출된다.

      b. 커스텀 destroy-method 지정되어 있다면 메소드가 호출된다.




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


    Spring 컨테이너 안에서 빈들(컴포넌트)끼리 사용하거나 사용되어지는 것을 묶기라고 한다. 빈을 묶을 에는 어떤 빈들이 사용 지와 빈들을 묶기 위해서 어떻게 의존성 주입을 사용할지를 컨테이너에게 알려줘야 한다. 이때 컨테이너에게 알려 때는 xml 이용하여 알려준다.


    간단한 샘플을 보면서 진행해 보자

    여러분이 스프링 트레이닝 주식회사라는 기술교육단체와 계약된 상태라고 가정하자 스프링 트레이닝사는 수강생이 온라인으로 교과 과정을 등록할 있도록 하는 애플리케이션을 만들어 달라고 요청했다.

    먼저 애플리케이션의 서비스 계층부터 만들어 보자

    아래의 그림은 스프링 트레이닝 애플리케이션에서 서비스 계층을 구성하는 계층을 보여준다.

     


     

    서비스 계층에는 수강생 서비스(Student Service) 교과과정 서비스 (Course Service) 라는 개의 서비스 컴포넌트가 있다.

     -.수강생 서비스(Student Service) : 수강생과 관련된 모든 것을 처리

     -.교과과정 서비스 (Course Service) : 교과과정과 관련된 모든 기능을 처리


    지금은 어떻게 구현되어 있는지 코드를 구현 부분만 살펴보고 나중에

    완전한 소스를 알아보자 궁금하면 www.acornpub.co.kr 에서 소스를 다운 받아 확인해 보세요

     

     

    Student Service.java

     

    public interface StudentService {

      public Student getStudent(String login);

      public void registerStudent(Student student);

      public java.util.Set getCompletedCourses(Student student);

      public String getCurrentUserId();

    }




    CourseService.java

     

     

    public interface CourseService {

      public Course getCourse(int id);

      public Course getCourse(Integer id);

      public void saveCourse(Course course);

      public java.util.Set getAllCourses();

      public void enrollStudentInCourse(Course course, Student student) throws CourseException;

      public void sendCourseEnrollmentReport();

    }



    StudentServiceImpl


     

    public class StudentServiceImpl implements StudentService {

      Logger LOGGER = Logger.getLogger(StudentServiceImpl.class);

     

      private StudentDao studentDao;

     

      // 생성자에 의한 주입

      public StudentServiceImpl(StudentDao dao) {

        studentDao = dao;

      }

      // setter 의한 주입

      // 참고: 소스에는 없다. 다만, 원리를 설명하기 위함.

      public setStudentDao(StudentDao dao) {

        studentDao = dao;

      }



      public Student getStudent(String login) {

        return studentDao.findById(login);

      }


      public void registerStudent(Student student) {

        HashSet authorities = new HashSet();

        authorities.add(new Authority("ROLE_STUDENT"));

        authorities.add(new Authority("ROLE_USER"));

        student.setAuthorities(authorities);


        studentDao.create(student);

      }


      public java.util.Set getCompletedCourses(Student student) {

        return studentDao.getCompletedCourses(student);

      }

     

      /*

       * TODO - This could be used more generically for Instructors as well.

       * But since it's only used for Students right now and because it would

       * be silly to create a UserService for this simple method, we'll just

       * put it here for now.

       */

      public String getCurrentUserId() {

        return ((SecureContext)ContextHolder.getContext()).getAuthentication().getPrincipal().toString();

      }

    }



    StudentServiceImpl 학생을 찾고, 생성하고 수강하는 작업등을 StudentDao 위임하여 StudentDao 데이터베이스와 상호작용하여 처리한다. StudentDao 객체의 실제 구현내용은 나중에 알아보기로 한다.

    그리고 StudentDao 구현한 클래스는 StudentDaoImpl 클래스이다.

    StudentDaoImpl 위의 소스에서 것과 같이 생성자와 setStudentDao() 메소드를 이용하여 StudentDao 대한 참조를 얻을 있다.


    CourseServiceImpl.java

     

     

     

    public class CourseServiceImpl implements CourseService {

     

      private static Logger LOGGER = Logger.getLogger(CourseServiceImpl.class);

      // 생성자 주입을 통한 CourseDao 설정

      public CourseServiceImpl(CourseDao dao) {

        this.courseDao = dao;

      }



      public Course getCourse(int id) {

        return getCourse(new Integer(id));

      }

     

      public Course getCourse(Integer id) {

        return courseDao.findById(id);

      }


      public void saveCourse(Course course) {

        courseDao.save(course);

      }


      public void enrollStudentInCourse(Course course,

          Student student) throws CourseException {


        // TODO:    enforcePrerequisites(course, student);


        // TODO:    Check for schedule conflicts


        course.getStudents().add(student);

        courseDao.save(course);

      }

     

      public Set getAllCourses() {

        return courseDao.findAll();

      }


      public void sendCourseEnrollmentReport() {

        Set courseList = courseDao.findAll();


        SimpleMailMessage message =

            new SimpleMailMessage(this.mailMessage);


        StringBuffer messageText = new StringBuffer();

        messageText.append("Current enrollment data is as follows:\n\n");

       

        for(Iterator iter = courseList.iterator(); iter.hasNext(); ) {

          Course course = (Course) iter.next();

          messageText.append(course.getId() + "    ");

          messageText.append(course.getName() + "    ");

          int enrollment = courseDao.getEnrollment(course);

          messageText.append(enrollment);

        }


        message.setText(messageText.toString());


        try {

          mailSender.send(message);

        } catch (MailException e) {

          LOGGER.error(e.getMessage());

        }

      }

     

      private void enforcePrerequisites(Course course,

          Student student) throws CourseException {

       

        Set completed = studentService.getCompletedCourses(student);


        // Check for prerequesites

        Set prereqs = course.getPrerequisites();

        for(Iterator iter = prereqs.iterator(); iter.hasNext(); ) {

          if(!completed.contains(iter.next())) {

            throw new CourseException("Prerequisites are not met.");

          }

        }

       

        // Check for scheduling clash

        for(Iterator iter = completed.iterator(); iter.hasNext(); ) {

          Course completedCourse = (Course) iter.next();

         

        }

      }

     

      // COLLABORATORS

      private CourseDao courseDao;

      public void setCourseDao(CourseDao courseDao) {

        this.courseDao = courseDao;

      }

     

      private StudentService studentService;

      public void setStudentService(StudentService service) {

        this.studentService = service;

      }


      private MailSender mailSender;

      public void setMailSender(MailSender mailSender) {

        this.mailSender = mailSender;

      }

     

      private SimpleMailMessage mailMessage;

      public void setMailMessage(SimpleMailMessage mailMessage) {

        this.mailMessage = mailMessage;

      }

    }



    CourseServiceImpl 생성자를 통해 CourseDao 참조를 있다. enrollStudentInCourse() 메소드는 수강생을 교과과정에 추가하기 전에 enforcePrerequisites() 먼저 호출한다. 만약 수강생이 선수과목을 이수하지 않았다면 enforcePrerequisites() CourseException 던질 것이며, 이를 다시 enrollStudentInCourse() 던질 것이다.

    enforcePrerequisites() StudentService 참조를 사용해 수강생이 수료한 모든 과목을 얻어온다. 이는 선수과목이라는 비즈니스 요구사항을 충목시키기 위해 CourseDao 뿐만 아니라, CourseServiceImpl과도 참조한다는 의미다.

    CourseServiceImpl CourseDao 생성자를 통해 얻는 것과 달리, StudentService 참조는 setStudentService() 메소드를 통해 얻는다. 이런 이유는 courseDao 이용하여 과목을 찾는데 사용되기 되고,  속성 값을 설정하지 않으면 인스턴스를 생성할수 없기때문에  private CourseDao courseDao 속성을 설정했다.

    다음은 xml 빈을 묶는 것에 대해 알아 보자


    Posted by 1010