2009년 3월 5일 목요일

beanutils를 이용한 excel import

excel파일을 받아서 특정 bean array로 만들어 처리해야 하는 경우...

 

1. excel를 읽어오는 library가 필요 : 아래 2개를 찾아 냄

 - apache의 poi 

 - Java Excel API

 

2. 읽어온 data를 특정 객체에 넣기

 - apache commons의 beanutils를 이용함

 

[먼저]

I. apache POI는 MS Office에서 제공하는 가능한 모든 포멧을 java에서 읽거나 쓰기 위해 만든 프로젝트이다. 그중 HSSF+XSSF는 엑셀에 관해 처리하는 부분이며 이게 관한 api를 제공하고 있다.

참고로 HSSF는 97~2003까지 xls 확장자를 다루며, XSSF는 2007버젼의 xlsx 확장자를 다룬다.

POI는 office 전반을 controll하기 때문에 무겁고 광대하며 자세하다.

II. java excel api는 sourceforge에 등록된 excel controll을 목적으로 한 오픈소스 프로젝트로, 가볍고 간단하다는 장점이 있다. (과거 유명한 jxl프로젝트와 무슨 관계인지 jxl.jar로 배포하고 있다)

 

[내용]

POI와 JXL을 선택적으로 사용해야 할 수도 있기에, interface를 제공하고 factory로 처리하고 했다.

 

=== Interface ===

public interface Importer {
 
 public void process() throws Exception ;

 public Object getResult();
}

 

=== POIInporter ===

import  org.apache.poi.hssf.usermodel.*;
import  org.apache.poi.hssf.model.Workbook;
import  org.apache.poi.hssf.model.Sheet;
import  org.apache.poi.hssf.*;
import  org.apache.poi.hssf.util.*;
import  org.apache.poi.poifs.filesystem.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
import java.util.ArrayList;


public class ExcelImporter implements Importer {

 POIFSFileSystem fs = null;
 FileOutputStream fileOut = null;

 String fileName  = "";
 int processCount = 0;
 
 HSSFWorkbook wb = null;
 HSSFSheet sheet = null;

 List resultObj = null;
 

 public ExcelImporter(String fn) {
  this.fileName = fn;
 }
 
 public void process() throws Exception {
  FileInputStream fi = new FileInputStream(fileName);
  try{

   fs  = new POIFSFileSystem(fi);
   //if(fs  != null) System.out.println("file name_______ =>"+fileName);
   //if(fs  != null) System.out.println("fs _______ =>"+fs);


   wb = new HSSFWorkbook(fs);
   System.out.println("WB =>"+wb);
   
   sheet = wb.getSheetAt(0);
   int totalRowNum = sheet.getPhysicalNumberOfRows();
   //int  totalRowNum = sheet.getLastRowNum();
   int rowIndex= 0;

   
   HSSFRow row = null;
   short cellSize = 0;
   HSSFCell[] cells = null ;
   HSSFCell cell = null ;
   

   resultObj = new ArrayList();
   
   //System.out.println("*** totalRowNum=>"+totalRowNum);
   
   Object[] obj = null;
   for(int k=0; k<totalRowNum; k++) {
    row = sheet.getRow(k);            
    if(row == null) continue;
    if(k==0) cellSize = row.getLastCellNum();
   
    obj = new Object[cellSize];
    //System.out.println("*** cellSize=>"+cellSize);
    cells = new HSSFCell[cellSize];  
    for(int i=0; i<cellSize; i++) {
     cells[i] = row.getCell(i);
     obj[i] = new Object();
     //System.out.println("cells[i].getStringCellValue()=>"+cells[i].getStringCellValue());    
     obj[i] = cells[i].getStringCellValue();
    }
    resultObj.add(obj);
   }

  }catch(Exception ex) {
   throw ex;
  }finally{
   if(fi != null) try{ fi.close(); } catch(Exception ex2) { }
  }
 
 }

 public Object getResult() {
  return resultObj;
 }

 

}

 

 

=== JXLInporter ===

 

import jxl.*;
import java.io.File;
import java.util.List;
import java.util.ArrayList;

public class JExcelImporter implements Importer {

 String fileName = "";
 int processCount = 0;

 Workbook workbook = null;
 Sheet sheet = null;
 List resultObj = null;
 
 public JExcelImporter(String fn) {
  this.fileName = fn;
 }
 
 public void process() throws Exception {
 
  try{  
   workbook = Workbook.getWorkbook(new File(fileName));

   sheet = workbook.getSheet(0);
   
   int totalRowNum = sheet.getRows();
   int cellSize = sheet.getColumns();
 
   //System.out.println("***************************** totalRowNum=>"+totalRowNum);    
   //System.out.println("***************************** cellSize=>"+cellSize);    
   
   int rowIndex= 0;
   
   Cell[] cells = null ;
   Cell cell = null ;
   
   resultObj = new ArrayList();
     
   Object[] obj = null;
   for(int k=0; k<totalRowNum; k++) {
    cells = sheet.getRow(k);

    if(cells  == null ) continue;
   
   
    obj = new Object[cellSize];
   
    for(int i=0; i<cellSize; i++) {    
     obj[i] = new Object();    
     obj[i] = cells[i].getContents();
    }
    resultObj.add(obj);
   }

  }catch(Exception ex) {
   throw ex;
  }finally{
   if(workbook != null) try{ workbook.close(); } catch(Exception ex2) { }
  }
 
 }

 public Object getResult() {
  return resultObj;
 }

}

 

=== Excel Util ===

 

/**
 * 엑셀(xls)파일을 읽어서 Bean Array에 넣는 Util
 * @FileName  : ExcelUtil.java
 * @Project   : nurien
 * @Date      : 2009. 03. 01
 * @Auther    : sunjin.kim
 * @History   :
 * @Comment   :
 *  Caption : xlsx(office 2007)파일 지원 안함. 저장시 97~2003통합문서로 저장.
 *  Usage : 1. xls 최상단에 컬럼명을 넣는다
 *    2. new ExcelUtil(파일경로, 클래스명, data가 시작되는 row)
 *    3. 클래스명 : package를 포함한 class명
 */

import org.apache.commons.beanutils.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import com.nurien.base.util.importer.*;

public class ExcelUtil {
 private String fileName;
 private String beanClassName;
 private int dataRow;
 
 public ExcelUtil(String fn, String bc, int dr){
  this.fileName = fn;
  this.beanClassName = bc;
  this.dataRow = dr;
 }
 
 public List getImportObject(){
  Importer importer = ImporterFactory.getInstance(fileName, ImporterFactory.JEXCEL);
  List list = null;
  try{
   importer.process();
   list = (List)importer.getResult();
  }catch(Exception ex) {
   ex.printStackTrace();
  }
  return list;
 }
 
 public String[] getHeaderInfo(List list) {
  Object[] obj = (Object[])list.get(0);
  String hs[] = null;
  if(obj != null) {
   hs = new String[obj.length];
   for(int i=0; i<obj.length; i++) {
    hs[i] = (String)obj[i];
    hs[i] = hs[i].toLowerCase().trim();
   }
  }
  return hs;
 }
 
 public List getImportData() {

  List importObj = getImportObject();
  if(importObj == null) return null;
 
  String[] heads = null;

  heads = getHeaderInfo(importObj);
  if(heads == null) return null;
 
  List list = new ArrayList();
  Map map = new HashMap();
 
  try{  
   heads = getHeaderInfo(importObj);
   for(int k=dataRow; k<importObj.size(); k++) { //dataRow번째 행부터 data로 인식

    Object[] objImportValues = (Object[])importObj.get(k);
    Object obj = Class.forName(beanClassName).newInstance();
    for(int i=0; i<heads.length; i++) {
     Object typeObj = PropertyUtils.getProperty(obj,heads[i]);
     if(typeObj.getClass().getName().equals("java.lang.String")) {
      map.put(heads[i],(String)objImportValues[i]);      
     }else {
      map.put(heads[i],new Integer((String)objImportValues[i]));
     }
    }
    PropertyUtils.copyProperties(obj,map);
    list.add(obj);
    map.clear();
   }

  }catch(Exception ex) {
   ex.printStackTrace(System.err);
   return null;
  }

  return list;
 }
 
 public static void main(String[] args){
  /*
  if(args.length < 2){
   System.out.println("Please insert Excel File Name and Data Row Number");
   System.exit(0);
  }
  String fileName = args[0];
  int dataRow = Integer.parseInt(args[1]);
  String className = "com.textcube.babyp.product";
  ExcelUtil eu = new ExcelUtil(fileName,className,dataRow);
  List list = eu.getImportData();
  com.nurien.bbs.entity.Product[] plist = null;
  if(list != null){
   System.out.println("data length : "+list.size());
   plist = new com.nurien.bbs.entity.Product[list.size()];
   for(int i=0; i<list.size(); i++){
    plist = (com.nurien.bbs.entity.Product[])list.toArray(plist);
   }
   
   for(int i=0; i<plist.length; i++){
    //System.out.println(plist[i].toString());
   }
  }
  */
 }
 
}

 

2008년 11월 28일 금요일

javascript message처리

관련글 : Struts2의 properties를 객체에 담고 가공하기

 

Json방식으로 메시지를 넣은 경우 해당 메시지를 load하여 꺼낼 Javascript가 필요 하여 구현함

 

일단 코드!!!

function loadScript(src) {
        var s = document.getElementsByTagName('HEAD')[0].appendChild(document.createElement('script'));
        s.type = 'text/javascript';
        s.charset="utf-8";
        s.src = src;
}       
var src = '메시지 js가 있는 url';
var NrnMessage = function(jsUrl){       
        this.message = null;
        this.js_src = src;
        if(jsUrl)
                this.js_src = jsUrl;
        if(typeof message == 'undefined'){               
                loadScript(this.js_src);                               
        }
        setTimeout('nrnmessage.init()',100);
};
NrnMessage.prototype = {
        init: function(){
                this.message = message;
        },
        getMessage: function(path){
                var idx = path.lastIndexOf('.');
                return this.findIdx(path.substr(0,idx), path.substr(idx,path.length));
        },
        getDirectMessage: function(path){
                return eval('this.message.'+path);
        },
        findIdx: function(path,key){
                var len = eval('this.message.'+path).length;
                for(var i=0; i<len; i++){
                        if(eval('this.message.'+path+'['+i+']'+key))
                                return eval('this.message.'+path+'['+i+']'+key);
                }
                return null;
        }
};

다음은 호출될 message 양식 (관련글에서 유추하듯 properties를 가져오기 때문에 해당 양식을 지키려 했다)

 var message = {
         LOGIN :
                 { VALIDATION : [
                                 {EMPTY_ID:'<s:text name="LOGIN.VALIDATION.EMPTY_ID"/>'},
                                 {ID_SIZE:'<s:text name="LOGIN.VALIDATION.ID_SIZE"/>'},
                                 {EMPTY_PASSWORD:'<s:text name="LOGIN.VALIDATION.EMPTY_PASSWORD"/>'},
                                 {PASSWORD_SIZE:'<s:text name="LOGIN.VALIDATION.PASSWORD_SIZE"/>'}
                         ]
                 }        ,
                
         'TITLE_BUTTON_CLOSE' : '닫기',
         'TITLE$BUTTON$OPEN' : '열기'
 }

호출하는 page에서 객체를 생성하고 사용하는 방법은 아래와 같다.

<script type="text/javascript">

//메시지 호출

 nrnmessage.getMessage('LOGIN.VALIDATION.EMPTY_PASSWORD')
 nrnmessage.getDirectMessage('TITLE_BUTTON_CLOSE')
 nrnmessage.getDirectMessage('TITLE$BUTTON$CLOSE')

</script>

<script type="text/javascript">

nrnmessage = new NrnMessage('/service/main/message_js.nrn'); //생성

</script>

 

 

Struts2의 properties를 객체에 담고 가공하기

시작 : struts의 properties의 내용을 json형식으로 변환하여 메시지로 사용하고 싶다.

접근 : key=value 형식을 json형식으로 바꿔야 하므로....일단 properties를 객체화 시켜야 한다.

구조 : package단위 properties가 존재하며, 메시지는 자신과 상위것만 사용할 수 있다.

[내용]

일반적으로 properties의 값을 가져오는 방법은 java코드 단에서는 getText 메쏘드를 이용한다.

message = getText("BBS.FORM.LIST.TITLE.CS");

 물론 jsp와 같은 presentation단에서도 사용 가능하다.

<s:property value="getText('BBS.FORM.LIST.TITLE.CS')"/>
<s:text name="BBS.FORM.LIST.TITLE.CS"/> // 내부적으로 getText를 호출한다

문제는 해당 key값과 value값을 분리하는데 있다.

보통은 ResourceBundle로 받아 loop를 돌며 처리하곤 하는데, 여기에서는 package단위 메시지처리를 해야 하므로, package를 통한 ResourceBundle접근을 하겠다.

 

1. 메시지를 가지고 있는 객체(messageManager)는 싱글톤으로 구현한다. 최초 로딩시 최상단(root) pacakge의 메시지를 저장하고 있다가 호출될때마다 해당 메시지에 add on 시키는 방식을 취한다.

private static final String COMMOM_PACKAGE = "net/babyp";
private static final String PACKAGE_NAME = "/package_ko";

 

private static List rootList = null;

 

public static synchronized void init(Action action){
  rootList = setMassage(action,COMMOM_PACKAGE);
 }

2. 각 action에서 호출될 메쏘드는 root메시지에 자기 package 메시지를 붙인다.

public static List getMessage(Action action){  
  if(rootList == null)
   init(action);
  String url = action.getClass().getPackage().getName();
  url.replaceAll(".", "/");  
  List list = setMassage(action,url,rootList);  

  return list;
 }

3. setMessage method

public static List setMassage(Action action,String package_path){
  List list = new ArrayList();
  ResourceBundle rb = action.getTexts(package_path+PACKAGE_NAME);
  if(rb != null){
   String keys = null;
   Message message = null;
   for (Enumeration e = rb.getKeys() ; e.hasMoreElements() ;) {
           keys = (String)e.nextElement();
            message = new Message();
            message.setKey(keys);
            message.setValue(action.getText(keys));
            list.add(message);
      }
  }
  return list;
 }

 4. 위 messageManager를 호출하는 action은 ActionSupport가 포함된 package내 class를 넘겨줘야 한다. (보통 자기 자신을 보낸다)

public String message() throws BaseException {
  List list = MessageManager.getMessage(this);
  resultMap.put("list", list);
  return SUCCESS;
 }  

 

 

 

 

2008년 11월 20일 목요일

Java .Net간의 Soap 통신

닷넷쪽 개발자에게 'Webservice로 통신 합시다!'하는 메일을 떡하니 받았다.

 

응? 어떻게요? 하고 물으니

프로토콜은 Soap으로 맞춰 놓았으니 그렇게 호출 하시면 됩니다....하는 그쪽 개발자~

 

SAAJ로 soap 통신을 구현한 내용이 있어 차분히 인용하였다.

 

import javax.xml.soap.*;
import java.net.*;
import javax.activation.DataHandler;

public class SAAJTest {
    public static void main(String [] args) throws Exception {
        // SOAPMessage 객체 생성
        MessageFactory messageFactory = MessageFactory.newInstance();
        SOAPMessage requestMessage = messageFactory.createMessage();
       
        // SOAPPart 객체 생성
        SOAPPart soapPart = requestMessage.getSOAPPart();
       
        // SOAPEnvelope 객체 생성
        SOAPEnvelope envelope = soapPart.getEnvelope();
       
        // 네임스페이스 지정
        envelope.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
        envelope.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        envelope.addNamespaceDeclaration("enc", "http://www.w3.org/schemas.xmlsoap.org/soap/encoding/");
        envelope.addNamespaceDeclaration("ns0", "http://localhost:8080/hello/webservice/wsdl/webservice");
       
        // 인코딩 방식 지정
        envelope.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
       
        // SOAPFactory 객체 생성
        SOAPFactory soapFactory = SOAPFactory.newInstance();
       
        // SOAPHeader 객체 얻기
        SOAPHeader header = envelope.getHeader();
       
        // 헤더 엔트리 생성
        Name name = soapFactory.createName(
                "authentication", "auth", "http://www.mincheol.com/auth");
        SOAPHeaderElement headerElement = header.addHeaderElement(name);
        headerElement.setActor("http://www.mincheol.com/auth");
        headerElement.setMustUnderstand(true);
       
        // 헤더 엔트리 자식 엘리먼트 생성
        name = soapFactory.createName("userid");
        SOAPElement useridElement = headerElement.addChildElement(name);
        useridElement.addTextNode("angel");
       
        // 헤더 엔트리 자식 엘리먼트 생성
        name = soapFactory.createName("password");
        SOAPElement passwordElement = headerElement.addChildElement(name);
        passwordElement.addTextNode("abc12345");
       
        // SOAPBody 객체 얻기
        SOAPBody body = envelope.getBody();
       
        // 바디 엔트리 생성
       
        // 이미 envelope에서 네임스페이스를 선언했으므로 마지막인자는 null 이다.
        Name bodyName = soapFactory.createName("sayHello", "ns0", null);
        SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
       
        // 바디 엔트리 자식 엘리먼트 생성
        Name childName = soapFactory.createName("String_1");
        SOAPElement childElement = bodyElement.addChildElement(childName);
        Name typeName = soapFactory.createName("type", "xsi", null);
        childElement.addAttribute(typeName, "xsd:string");
        childElement.addTextNode("mincheol");
       
        // 첨부물 위치
        URL url = new URL("file:///home/kwon37xi/.vimrc");
        String contentId = "attached_image";
        // AttachmentPart 객체 얻기
        DataHandler dataHandler = new DataHandler(url);
        AttachmentPart attachment = requestMessage.createAttachmentPart(dataHandler);
        attachment.setContentId(contentId);
        // 요청 SOAP 메시지에 추가
        requestMessage.addAttachmentPart(attachment);
       
        // SOAPFault 객체 얻기
        SOAPFault fault = body.addFault();
        fault.setFaultCode(envelope.getPrefix() + ":Client"); // faultcode에는 접두사가필요하다.
        fault.setFaultActor("http://www.mincheol.com/auth");
        fault.setFaultString("Message does not have necessary info");
        Detail detail = fault.addDetail(); // detail 정보 생성
        Name entryName = soapFactory.createName("content"); // 네임스페이스 불필요
        DetailEntry entry = detail.addDetailEntry(entryName);
        entry.addTextNode("userid element does not have a value");
       
        // 지금까지 생성된 XML SOAP 메시지를 화면에 출력한다.
        System.out.println("-----------------------------------------------------");
        requestMessage.writeTo(System.out);
        System.out.println("-----------------------------------------------------");
       
        // SOAPConnection 객체생성
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection connection = soapConnectionFactory.createConnection();
       
        // 요청 SOAP 메시지를 보내고, 응답 SOAP 메시지를 받는다.
        SOAPMessage responseMessage = connection.call(requestMessage,
                "http://localhost:9000/hello/webservice");
    }
}

 [출처 : 권남님]