XMLSocket은 뭔가 이상하군요-_-;

그냥 Socket클래스는 그냥 쓰던 소켓같은데 XMLSocket은 삽질한 결과 이상하게 주고 받는 것 같아요.

우선 보낼 때 이상하게 나눠서 보내게 되더라구요.

그리고 \0을 끝으로 인식하는 듯합니다. 그래서 자바서버에서 보낼 때 pw.println("blur~blur~")이렇게 보낼 때에는 blur~blur~\r\n이 가게 되는데 저것이 끝이라고 인식을 못하더라구요.
그래서 보낼 때에는 pw.print("blur~blur~\n\0") 이라고 보내야해요.

그리고,
mudchobo : 안녕하세요\n\0 라고 보내면, 이상하게 나눠서 호출이 되더라구요-_-;
mudchobo : 데이터를 받고, 그다음에 안녕하세요\n\0을 받아요-_-;

왜그럴까요-_-; 어쨌든, 편법으로 만든 채팅프로그램입니다.

서버(JAVA)
ChatServer.java
[code]package com.mudchobo.chat;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class ChatServer {

 private ServerSocket server;
 
 void startServer() {
  try {
   server = new ServerSocket(10001);
   System.out.println("접속을 기다립니다.");
   HashMap<String, PrintWriter> hashMap =
    new HashMap<String, PrintWriter>();
   
   while (true) {
    Socket sock = server.accept();
    ChatThread chatThread =
     new ChatThread(sock, hashMap);
    chatThread.start();
   } // while
  } catch (Exception e) {
   System.out.println(e);
  }
 }
 public static void main(String[] args) {
  ChatServer chatServer = new ChatServer();
  chatServer.startServer();
 }
}
[/code]

ChatThread.java
[code]package com.mudchobo.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

class ChatThread extends Thread {
 private Socket sock;
 private String id;
 PrintWriter pw;
 private BufferedReader br;
 private HashMap<String, PrintWriter> hashMap;

 public ChatThread(Socket sock, HashMap<String, PrintWriter> hashMap)
  throws UnsupportedEncodingException, IOException {
  this.sock = sock;
  this.hashMap = hashMap;
 
  pw = new PrintWriter(
    new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
  br = new BufferedReader(
    new InputStreamReader(sock.getInputStream(), "UTF-8"));
  id = br.readLine();
  hashMap.put(id, pw);
  broadcast(id + "님이 접속하였습니다.");
  System.out.println("접속한 사용자의 아이디는 " + id + "입니다.");
 }

 public void run() {
  try {
   String line = null;
   while ((line = br.readLine()) != null) {
    if (line.equals("/q")) {
     break;
    } else {
     broadcast(id + " : " + line);
    }
   }
  } catch (Exception ex) {
   System.out.println(ex);
  } finally {
   hashMap.remove(id);
   broadcast(id + " 님이 접속 종료하였습니다.");
   System.out.println(id + " 님이 접속 종료하였습니다.");
   try { if (sock != null) sock.close(); } catch (Exception ex) {}
  }
 }

 public void broadcast(String msg) {
  Collection<PrintWriter> collection = hashMap.values();
  Iterator<PrintWriter> iter = collection.iterator();
  while (iter.hasNext()) {
   PrintWriter pw = (PrintWriter) iter.next();
   pw.print(msg + "\n\0");
   pw.flush();
  }
 }
}
[/code]
저 부분만 바뀌었어요 ^^

이제 클라이언트로-_-;

 
Posted by 머드초보

댓글을 달아 주세요

  1. 계인 2007.11.27 11:53  댓글주소  수정/삭제  댓글쓰기

    좋은 정보가 많네요.. 머드초보님을 싸부로 생각하고 이것저것 해보고 있는데.. 제가 *.java 파일의 위치는 어디로 해야 할지 몰라서... 절대경로 ^^; 완전 초보라..ㅠ_ ㅠ

    • BlogIcon 머드초보 2008.01.26 17:39  댓글주소  수정/삭제

      아...서버쪽에서는 *.java파일을 저위에 package경로에 넣어야되는데요.
      패키지를 만드셔서 com.mudchobo.chat으로 만드셔서 넣으면 되는데요^^
      그냥 패키지안만드시면 위에 package를 없애버리면돼요 ^^
      저 허접해서 싸부로 생각하지마시고 같이 공부하는 동료로 생각해주세요^^
      허접해서 친구한테 맨날 욕먹고 있어요^^
      방문해주셔서 감사해요 ^^

  2. BlogIcon eizt 2010.07.04 22:39  댓글주소  수정/삭제  댓글쓰기

    제가 진행하고 있는데 flex 하고 java를 써야될것 같아서 ㅠㅠ 많이좀 참고좀 하겠습니다ㅠㅠ

    아 어렵다 어려워 ㅠㅠ

  3. BlogIcon 김상훈 2012.10.08 18:45  댓글주소  수정/삭제  댓글쓰기

    "mudchobo : 안녕하세요\n\0 라고 보내면, 이상하게 나눠서 호출이 되더라구요-_-;
    mudchobo : 데이터를 받고, 그다음에 안녕하세요\n\0을 받아요-_-;"

    이문제는 line = br.readLine() 시 종료되는 문자열이 같이 들어가서 생기는 문제였습니다.
    broadcast(id + " : " + line); => broadcast(id + " : " + line.trim()); 으로 해결되더군요.

  4. BlogIcon 김상훈 2012.10.08 18:45  댓글주소  수정/삭제  댓글쓰기

    플래시로 채팅 프로그램을 구현해야 했는데 이 프로그램으로 많은 도움 되었습니다.

 

채팅프로그램은 LCDS를 이용해서 메시지서비스를 하게 되면 매우 간단하게 작성할 수 있습니다.
하지만, 뭔가 자유도가 부족하군요-_-; 그래서 서버를 자바로하고 클라이언트를 FLEX로 한 프로그램을 만들어봤습니다.
플렉스 소켓으로 삽질하시는 분들께 도움이 되고자--;(뭐 도움은 안되겠지만-_-;)
JAVA 6.0에서 테스트했습니다.

서버(JAVA)
ChatServer.java 와 ChatThread.java 두개의 파일입니다.
ChatServer클래스에는 main클래스가 있으며, accept()를 호출해서 클라이언트의 접속을 기다리다가 접속이 되면 스레드를 시작을 하게 되는 구조입니다.

ChatServer.java
[code]package com.mudchobo.chat;

import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;

public class ChatServer {

 private ServerSocket server;
 
 void startServer() {
  try {
   server = new ServerSocket(10001);
   System.out.println("접속을 기다립니다.");
   HashMap<String, PrintWriter> hashMap =
    new HashMap<String, PrintWriter>();
   
   while (true) {
    Socket sock = server.accept();
    ChatThread chatThread =
     new ChatThread(sock, hashMap);
    chatThread.start();
   } // while
  } catch (Exception e) {
   System.out.println(e);
  }
 }
 public static void main(String[] args) {
  ChatServer chatServer = new ChatServer();
  chatServer.startServer();
 }
}
[/code]
우선 startServer를 보시면, ServerSocket을 생성합니다. 그리고, HashMap을 하나 생성하는데 이것은 id와 PrintWriter, 즉, 해당 스레드마다 각각의 PrintWriter를 저장해서 다른 클라이언트에게 뿌려줄 때 사용됩니다.
그래서 Thread만들 때 hashMap을 같이 넘겨주도록 합니다.

ChatThread.java
[code]package com.mudchobo.chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

class ChatThread extends Thread {
 private Socket sock;
 private String id;
 PrintWriter pw;
 private BufferedReader br;
 private HashMap<String, PrintWriter> hashMap;

 public ChatThread(Socket sock, HashMap<String, PrintWriter> hashMap)
  throws UnsupportedEncodingException, IOException {
  this.sock = sock;
  this.hashMap = hashMap;
 
  pw = new PrintWriter(
    new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
  br = new BufferedReader(
    new InputStreamReader(sock.getInputStream(), "UTF-8"));
  id = br.readLine();
  hashMap.put(id, pw);
  broadcast(id + "님이 접속하였습니다.");
  System.out.println("접속한 사용자의 아이디는 " + id + "입니다.");
 }

 public void run() {
  try {
   String line = null;
   while ((line = br.readLine()) != null) {
    if (line.equals("/q")) {
     break;
    } else {
     broadcast(id + " : " + line);
    }
   }
  } catch (Exception ex) {
   System.out.println(ex);
  } finally {
   hashMap.remove(id);
   broadcast(id + " 님이 접속 종료하였습니다.");
   System.out.println(id + " 님이 접속 종료하였습니다.");
   try { if (sock != null) sock.close(); } catch (Exception ex) {}
  }
 }

 public void broadcast(String msg) {
  Collection<PrintWriter> collection = hashMap.values();
  Iterator<PrintWriter> iter = collection.iterator();
  while (iter.hasNext()) {
   PrintWriter pw = (PrintWriter) iter.next();
   pw.println(msg);
   pw.flush();
  }
 }
}
[/code]
생성자를 보게 되면 해당클라이언트와 통신을 하도록 하는 PrintWriter와 BufferedReader를 만듭니다.
우선 접속하게 되면 클라이언트쪽에서 id를 보내도록 되어있죠.(나중에 클라이언트할때 설명-_-;)

그리고, run메소드를 보시게 되면, BuferedReader에서 readLine을 하게 되어서, 채팅데이터를 받게 되면, broadcast함수를 호출하게 되어, 연결되어 있는 모든 클라이언트에게 채팅데이터를 보냅니다.
hashmap에 printwriter를 저장해서 가능하죠 ^^

※플렉스는 UTF-8로 데이터를 전송하게 됩니다. 그래서 데이터를 받을 때 UTF-8로 받아야겠죠?
[code]pw = new PrintWriter(
    new OutputStreamWriter(sock.getOutputStream(),"UTF-8"));
  br = new BufferedReader(
    new InputStreamReader(sock.getInputStream(), "UTF-8"));
[/code]
위와 같이 "UTF-8"이라고 해주면 돼요 ^^
UTF-8빼면 한글이 깨져버려요 ^^

길이너무 길어져서 다음 글로-_-;

클라이언트
http://mudchobo.tomeii.com/tt/153
 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 다크호스 2009.01.12 11:17  댓글주소  수정/삭제  댓글쓰기

    와 투명아이 가족이네요 ㅎ

    플렉스 관심이 많았는데

    잘 보고 갑니다.

    • 머드초보 2009.01.14 17:26  댓글주소  수정/삭제

      앗~ 투명아이 가족이신가보군요 ^^
      저도 투명아이 가족입니다 ^^
      저도 플렉스에 관심이 많아서 삽질 중입니다 ^^
      반갑습니다 ^^

  2. -_-;; 2009.10.27 19:24  댓글주소  수정/삭제  댓글쓰기

    로컬에서는 도는데 결정적으로 원격으로는 문제가 있네요...
    방법을 찾아보고는 있습니다만... 좋은 방법이 없을까요?

    • 머드초보 2009.10.29 12:40  댓글주소  수정/삭제

      아 그문제는 저도 고생했었는데, 보안 샌드박스 문제 입니다.
      소켓으로 원격으로 접속할 때에는 crossdomain.xml파일을 먼저 요청을 합니다. 즉 내가 이서버에 접속해도 되나 하는 보안파일을 먼저 보내주는 프로세스를 만들어야합니다.
      Policy Server프로그램을 하나 만들면 되는데, 만들어진 것이 많아 가져다 쓰셔도 될 듯합니다^^
      http://code.google.com/p/assql/wiki/SecurityInformation

  3. 시원 2010.05.20 22:46  댓글주소  수정/삭제  댓글쓰기

    XMLSocket 보안 샌드박스 문제때문에 이틀째 고생중입니다.
    머드 초보님처럼 저도 Policy Server프로그램을 만들고 있는데 어디서 엉키는건지
    이상하게 접속이 안되네요.....-.-;

    혹시 시간나시면 님이 말씀하신 http://code.google.com/p/assql/wiki/SecurityInformation 예제로
    Policy Server 만든경험을 저와같이 고생하는 중생들을 위해 설명을 곁들여
    올려주시면 안될까용??? ^^;

    • 머드초보 2010.05.21 10:46  댓글주소  수정/삭제

      안녕하세요~
      저도 예전에 그걸로 삽질을 한적이 있었는데요^^
      의외로 간단해요.
      그냥 Policy Server프로그램을 서버에 띄워놓으면 swf가 그 서버에서 plicy파일을 요청합니다. 그걸 던져주는 걸 만들면 되는건데
      음...
      저 예제로 하면 되는데...
      나중에 시간날 때 한번 글을 써보겠습니다 ㅠㅠ

  4. 2010.06.11 10:23  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • 머드초보 2010.06.14 12:09  댓글주소  수정/삭제

      네네~
      그건 크로스도메인 문제인데요.
      서버측에서 843포트로 크로스도메인파일을 전송해줘야합니다.
      그거 관련된 것은 검색해보면 나오는데,
      나중에 이 글에 대해서 포스팅을 할께요.
      많이들 헷깔려하시는 것 같아서 ㅠㅠ

 

솔직히 뭐 구축하고 자시고 할것도 없는데-_-;
저도 몇시간의 삽질끝에 알아냈습니다. 삽질하시는 분들에게 도움을 드리고자-_-;

우선 SKVM SDK를 받아야 합니다.
http://www.developerzone.co.kr
이 사이트에서 회원가입을 해야합니다.
회원가입후에 메뉴에서 DOWNLOAD -> SDK 클릭한다음에
WIPI 에뮬레이터(SKVM 2.0)을 받습니다. 설치합니다.

※참고로 eclipse 버전이 3.2라면 eclipse plugin이 작동하지 않습니다. 설치시 체크 해제하고 설치하세요.

사용자 삽입 이미지
WIPI-Java 2.0.2를 실행했을 때에 요게 뜨면 제대로 설치된 겁니다.

지긋지긋한 이클립스를 켜봅시다.
새로운 자바프로젝트를 만듭시다.
File -> New -> Java Project
Project Name은 TestWipi로 합시다.

TestWipi프로젝트에 대고 alt + enter를 눌러서 Properties를 선택합니다.
얘는 자바sdk로 작동하는 놈이 아니기때문에 자체적인 클래스파일로 바꿔줘야 합니다.
그게 방금 설치한 SKVM에 포함되어 있습니다.
Java Build Path를 클릭하시고, Libraries를 클릭하시면 기본으로 있는 것을 지워버리고
Add External JARs를 클릭해서 C:\Program Files\xce\WIPI-JAVA 2.0.2\classes\classes.jar 파일을 추가합니다.
사용자 삽입 이미지


아 그리고, 위피는 SDK를 1.4로 쓰나봅니다. 그 이상의 SDK를 설치했으면 컴파일시 하위버전으로 컴파일 해야합니다.
Properties -> Java Compiler에서 Enable project specific settings를 체크해주고,
Compiler compilance level을 1.4로 바꿉니다.

사용자 삽입 이미지

그러면 셋팅은 다 된 겁니다-_-;

간단한 예제를 작성해봅시다.
새로운 클래스로 TestWipi.java를 생성하는데 extends를 MIDlet으로 합시다.
[code]
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.TextBox;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class TestWipi extends MIDlet {

 private Display display;
 private TextBox tb;

 public TestWipi() {
  display = Display.getDisplay(this);
  tb = new TextBox("Example", "Hello XCE", 20, TextField.ANY);
 }

 protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  // TODO Auto-generated method stub
 }

 protected void pauseApp() {
  // TODO Auto-generated method stub
 }
 
 protected void startApp() throws MIDletStateChangeException {
  // TODO Auto-generated method stub
  display.setCurrent(tb);
 }
}
[/code]
WIPI-Java 2.0에서 실행해봅시다.
File -> Open -> Add클릭 후 해당 class파일 선택 Run
사용자 삽입 이미지

아 잘되네요. 글이 너무 길어져서 핸드폰으로 받는 법은 다음으로-_-;
 
Posted by 머드초보

댓글을 달아 주세요

  1. 개발자 2008.01.28 10:29  댓글주소  수정/삭제  댓글쓰기

    머드초보님의 글을 보고 설치는 모두 똑같게 했는데요. 예제코드를 입력하고 빌드하면 class 파일이 생성되지 않습니다. 이클립스 상에서 classes 폴더에 클래스 파일이 보이지 않습니다. classes 폴더 자체가 생성되지 않네요. 빌드하면 자동으로 생성되는 걸로 알고 있는데 project properties 설정에서 build path도 classes 로 설정되어 있습니다. Run 하면 당연히 class 파일이 없으니 skvm 에뮬레이터에서 class not found 가 발생합니다. 이클립스 3.1 깔아서 머드초보님 블로그에 있는데로 설정을 했는데요 해결할 방법은 없는지 조언 부탁드리겠습니다.

    • BlogIcon 머드초보 2008.01.28 17:53  댓글주소  수정/삭제

      안녕하세요! 보니까 java파일이 컴파일이 안되는 듯 한데요. 음...class로 만들어져야하는데-_-; 이유는 잘 모르겠네요. 참고로 저는 이클립스 3.3.1에서 테스트를 해본 것 같습니다. 혹시 다른버전으로 한번 해보세요 ^^

  2. 이명진 2008.07.25 20:38  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 정말 감사합니다.

    너무 많은 곳을 헤매고, 맨땅에 헤딩하다가 님의 글 덕분에 한방에 해결 하였습니다.

    정말 정말 감사 하구요. 좋은 정보 많이 많이 남겨 주세요...^^

    꾸벅!!

    • 머드초보 2008.07.27 12:04  댓글주소  수정/삭제

      앗 도움이 되셨다니 다행이네요 ^^
      제가 모바일쪽으로 일은 안해서 잘 모르겠네요.
      잠깐 모바일애플리케이션이 좀 필요해서 잠깐 삽질했었어요^^
      선택력이 부족한 A형을 위한 랜덤 선택기를 가지고 다닐 필요가 있어서-_-; 그걸 만드느라 ^^
      방문해주셔서 감사해요~ ^^

 

iBATIS를 이용해서 간단한 예제를 만들어봅시다.

웹이랑 섞으면 복잡하니까 콘솔에서 아주 간단하게 해보겠습니다-_-;

iBATIS를 들어보기만 하고 저처럼 어려울 것 같아서 거부하신분들에게 바칩니다-_-; 저는 처음에 상당히 어려울 줄 알았는데 공식홈페이지가니까 이동국님이 번역해 놓으신 문서가 있더라구요. 약간 이상하게(?) 번역해 놓긴 했지만 영어울렁증이 있는 저에게는 정말 도움이 되는 자료 였습니다 ^^

iBATIS공식홈페이지입니다.( 개발자 가이드와 튜토리얼 메뉴얼도 있습니다.)
for Java를 클릭하면 자바용이 나옵니다.
http://ibatis.apache.org/

접근하기 쉽게 하기 위해서 원더걸스멤버를 DB에 저장해놓고 해봅시다-_-;

[code]
CREATE TABLE `WONDERGIRLS` (
  `NUM` int(11) NOT NULL,
  `NAME` varchar(10) NOT NULL,
  `AGE` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=euckr;

INSERT INTO `WONDERGIRLS` (`NUM`, `NAME`, `AGE`) VALUES
(1, '선예', 18),
(2, '선미', 15),
(3, '소희', 15),
(4, '예은', 18),
(5, '유빈', 99);
[/code]

사실 원더걸스가 이렇게 어린지 몰랐습니다-_-; 자 우선 넘어가고-_-;

이클립스를 실행하고 JAVA PROJECT로 프로젝트를 하나 만듭시다.
그리고 패키지를 jyp라고 해서 만듭시다-_-;
iBATIS lib파일인 ibatis-2.3.0.677.jar과 OracleJDBC를 LIB으로 추가합시다.

iBATIS를 사용하기 위한 설정파일을 구성해봅시다.
jyp에다가 new해서 xml파일을 하나 만듭시다. 이름은 SqlMapConfig.xml 이라고 합시다.

SqlMapConfig.xml
[code]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

 <properties resource="./jyp/SqlMapConfig.properties" />
 
 <settings
     cacheModelsEnabled="true"
     enhancementEnabled="true"
     lazyLoadingEnabled="true"
     maxRequests="32"
     maxSessions="10"
     maxTransactions="5"
     useStatementNamespaces="false"
 />
   
 <transactionManager type="JDBC" >
    <dataSource type="SIMPLE">
      <property name="JDBC.Driver" value="${driver}" />
      <property name="JDBC.ConnectionURL" value="${url}" />
      <property name="JDBC.Username" value="${username}" />
      <property name="JDBC.Password" value="${password}" />
    </dataSource>
 </transactionManager>
 
 <sqlMap resource="./jyp/WonderGirls.xml" />
 
</sqlMapConfig>
[/code]
내용을 보면 환경을 설정하고 JDBC와 연결하기 위한 작업을 하는 듯 합니다. JDBC연결작업은 SIMPLE이라고 되어있는데 DBCP로도 됩니다. 메뉴얼에 보시면 개발자가이드 부분에 보면 하는 법이 있습니다.
그리고 마지막에 sqlMap의 resource를 WonderGirls.xml을 추가해놨는데요 차후 설명하겠습니다.

그다음에 저기 JDBC설정에 ${driver}등 변수형식으로 되어있는데 맨위에 properties파일을 하나 설정한게 있는데 저기에 정의 하면 됩니다.

SqlMapConfig.properties
[code]
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@127.0.0.1:1521:XE
username=MUDCHOBO
password=1234
[/code]
오라클은 저렇게 하면 되구요. mysql은 mysql에 맞게 바꾸면 돼요.
만약 한 프로그램에서 여러개의 db를 접근한다면 저 파일들을 또 만들면 되겠죠?

그 다음 클래스를 하나 만듭시다. MyAppSqlmapConfig라는 클래스를 만듭시다.
[code]
package jyp;

import java.io.Reader;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;

public class MyAppSqlMapConfig {

 private static final SqlMapClient sqlMap;
 
 static {
  try {
   String resource = "./jyp/SqlMapConfig.xml";
   Reader reader = Resources.getResourceAsReader(resource);
   sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
  } catch (Exception e) {
   e.printStackTrace();
   throw new RuntimeException("Error initializing class. Cause:" + e);
  }
 }

 public static SqlMapClient getSqlMapInstance() {
  return sqlMap;
 }
}
[/code]
방금 설정한 설정파일을 이용해서 sqlMapClient를 만드는 듯 합니다. 저 sqlMap객체를 통해서 db에 접근할 수 있는 듯 합니다. 저도 잘은 모르겠네요 ^^

원더걸스 getter, setter를 만들어 봅시다. WonderGirls라는 이름으로 클래스를 만듭니다.
WonderGirls.java
[code]
package jyp;

public class WonderGirls {

 private int num;
 private String name;
 private int age;
 
 public int getNum() {
  return num;
 }
 public void setNum(int num) {
  this.num = num;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public int getAge() {
  return age;
 }
 public void setAge(int age) {
  this.age = age;
 }
}
[/code]
이제 가장 중요한 부분인 Wondergirls에 관련된 sqlMap을 작성해봅시다.
이름은 아까 정의한 WonderGirls.xml파일로 만듭시다.
[code]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="WonderGirls">
 
 <resultMap id="WondergirlsResult" class="jyp.WonderGirls">
  <result column="NUM" property="num" />
  <result column="NAME" property="name" />
  <result column="AGE" property="age" />
 </resultMap>
 
 <select id="getWondergirls" resultMap="WondergirlsResult">
  SELECT NUM, NAME, AGE
  FROM WONDERGIRLS
  ORDER BY NUM
 </select>

 <select id="selectWondergirl" parameterClass="Integer"
             resultClass="jyp.WonderGirls">
  SELECT NUM, NAME, AGE
  FROM WONDERGIRLS
  WHERE NUM = #num#
 </select>
 
 <insert id="insertWondergirl" parameterClass="jyp.WonderGirls">
  INSERT INTO
  WONDERGIRLS (NUM, NAME, AGE)
  VALUES (#num#, #name#, #age#)
 </insert>
 
 <update id="updateWondergirl" parameterClass="java.util.Map">
  UPDATE WONDERGIRLS SET
  NAME = #name#,
  AGE = #age#
  WHERE NUM = #num#
 </update>
 
 <delete id="deleteWondergirl" parameterClass="Integer">
  DELETE FROM WONDERGIRLS
  WHERE NUM = #num#
 </delete>
 
</sqlMap>
[/code]
sql문을 xml로 뺐습니다. 나중에 고칠 때 편할 듯 싶네요.
sql이 총 5가지가 있네요.
전체리스트가져오기, 멤버번호받아서 한명멤버정보 가져오기, 멤버추가하기, 멤버수정하기, 멤버삭제하기

select해서 List를 가져올 때에는 원래 자동맵핑이 되서 알아서 가져오지만 그래도 명시적으로 맵핑을 해줘야돼요. 그래서 resultMap태그를 이용해서 명시해준뒤에 select를 선언해서 그 resultMap의 id를 resultMap속성값에 넣어주면 됩니다.
insert할 때에도 WonderGirls클래스형으로 받아서 넣어주면 되구요.
update할 때 좀 틀린게 parameterClass를 Map으로 선언합니다. 이름, 나이, 번호를 각각 객체로 받아서 Map에 저장한 것을 받아서 사용하는 것이죠.
delete할 때에는 Integer클래스형으로 숫자하나 받아서 해당 멤버를 지우게 됩니다.

이번엔 DAO를 만들어봅시다. WondergirlsDao라는 이름의 클래스를 만들어봅시다.
[code]
package jyp;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import com.ibatis.sqlmap.client.SqlMapClient;

public class WondergirlsDao {

 @SuppressWarnings("unchecked")
 public void viewMember(SqlMapClient sqlMap) throws SQLException {
  List<WonderGirls> wonderGirlsList = (List<WonderGirls>) sqlMap
    .queryForList("getWondergirls");
  for (int i = 0; i < wonderGirlsList.size(); i++) {
   WonderGirls wonderGirl = (WonderGirls) wonderGirlsList.get(i);
   System.out.print("번호 : " + wonderGirl.getNum());
   System.out.print("   이름 : " + wonderGirl.getName());
   System.out.println("   나이 : " + wonderGirl.getAge());
  }
 }

 public void insertMember(SqlMapClient sqlMap, WonderGirls wonderGirls)
    throws SQLException {  
  sqlMap.insert("insertWondergirl", wonderGirls);
  System.out.println("추가에 성공했습니다.");
 }

 public void modifyMember(SqlMapClient sqlMap, Map<String, Object> map)
    throws SQLException {
  sqlMap.update("updateWondergirl", map);
  System.out.println("수정에 성공했습니다.");
 }

 public void deleteMember(SqlMapClient sqlMap, int num) throws IOException,
   SQLException {
  sqlMap.delete("deleteWondergirl", num);
  System.out.println("삭제에 성공했습니다.");
 }
 
 public boolean validateMember(SqlMapClient sqlMap, int num) throws SQLException {
  WonderGirls wonderGirls =
   (WonderGirls) sqlMap.queryForObject("selectWondergirl", num);
 
  if (wonderGirls == null) {
   return false;
  }
  return true;
 }
}
[/code]
DAO를 보면 이상하게 간단합니다. 위에 xml에 다 쿼리를 선언해줬기때문에 그냥 파라메터만 넘겨주면 됩니다.
List보기는 sqlMap.queryForList("getWondergirls"); getWondergirls는 위에 선언한 쿼리의 id입니다.
insert할 때에는 객체를 받아서 넘겨주고, 수정할 때에는 Map을 넘겨주고, 삭제 할때에는 숫자를 넘겨주면 됩니다.
아 간단해요. 한줄이면 끝나요-_-;
예전에 Connection을 close()안해줬더니 서버가 다운되려고 한 경험이 있는데 이런일은 절대 없을 것 같군요.

이제 main함수를 작성해봅시다. 이름은 WondergirlsApplication으로 해봅시다.
public static void main(String[] args)에 체크해주시는 것 잊지 마시구요-_-;
WondergirlsApplication.java
[code]
package jyp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.ibatis.sqlmap.client.SqlMapClient;

public class WondergirlsApplication {

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

  BufferedReader bufferedReader = new BufferedReader(
    new InputStreamReader(System.in));
  SqlMapClient sqlMap = MyAppSqlMapConfig.getSqlMapInstance();
  WondergirlsDao wondergirlsDao = new WondergirlsDao();
  WonderGirls wonderGirls = new WonderGirls();
 
  Integer age, num;
  String name;
 
  while (true) {
   try {
    System.out.println("\n1.멤버출력\n2.멤버추가\n3.멤버수정\n4.멤버삭제\n5.종료");
    System.out.print("--> ");
    String temp = bufferedReader.readLine();
    int MenuNum = Integer.parseInt(temp);
    switch (MenuNum) {
    case 1:
     wondergirlsDao.viewMember(sqlMap);
     break;
     
    case 2:
     wonderGirls = new WonderGirls();
     System.out.print("번호을 입력하세요 : ");
     wonderGirls.setNum(Integer.parseInt(bufferedReader.readLine()));
     System.out.print("이름을 입력하세요 : ");
     wonderGirls.setName(bufferedReader.readLine());
     System.out.print("나이을 입력하세요 : ");
     wonderGirls.setAge(Integer.parseInt(bufferedReader.readLine()));
     wondergirlsDao.insertMember(sqlMap, wonderGirls);
     break;
     
    case 3:
     Map<String, Object> map = new HashMap<String, Object>(3);

     System.out.print("수정할 번호을 입력하세요 : ");
     num = new Integer(Integer.parseInt(bufferedReader.readLine()));
     if (!wondergirlsDao.validateMember(sqlMap, num)) {
      System.out.println("없는 멤버번호입니다.");
      break;
     }
     System.out.print("이름을 입력하세요 : ");
     name = bufferedReader.readLine();
     System.out.print("나이을 입력하세요 : ");
     age = new Integer(Integer.parseInt(bufferedReader.readLine()));

     map.put("num", num);
     map.put("name", name);
     map.put("age", age);
     wondergirlsDao.modifyMember(sqlMap, map);
     break;
     
    case 4:
     System.out.print("삭제할 멤버번호를 입력하세요 : ");
     num = Integer.parseInt(bufferedReader.readLine());
     if (!wondergirlsDao.validateMember(sqlMap, num)) {
      System.out.println("없는 멤버번호입니다.");
      break;
     }
     wondergirlsDao.deleteMember(sqlMap, num);
     break;
     
    case 5:
     System.exit(0);
     
    default:
     System.out.println("1~5중에서 선택하세요!");
     break;
    }
   } catch (NumberFormatException e) {
    System.out.println("잘못 입력했습니다. 다시 입력하세요");
   }
  }
 }
}
[/code]
자세히 보시면 뭐 별거없는데 거창하게 만들어놨군요(제가 좀 허접해서-_-) 아 참고로 예외처리 잘 안해놨으니 알아서 버그많아요 알아서 보세요-_-;

1번은 멤버 리스트를 가져오는군요.
[code]
1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 1
번호 : 1   이름 : 선예   나이 : 18
번호 : 2   이름 : 선미   나이 : 15
번호 : 3   이름 : 소희   나이 : 15
번호 : 4   이름 : 예은   나이 : 18
번호 : 5   이름 : 유빈   나이 : 5

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
-->
[/code]
2번은 멤버를 추가하는데 추가해봅시다-_-;
[code]
1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 2
번호을 입력하세요 : 6
이름을 입력하세요 : 성종천
나이을 입력하세요 : 25
추가에 성공했습니다.

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 1
번호 : 1   이름 : 선예   나이 : 18
번호 : 2   이름 : 선미   나이 : 15
번호 : 3   이름 : 소희   나이 : 15
번호 : 4   이름 : 예은   나이 : 18
번호 : 5   이름 : 유빈   나이 : 5
번호 : 6   이름 : 성종천   나이 : 25

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
-->
[/code]
아 멤버가 추가되었어요-_-; (이거 욕먹겠군요-_-;)
멤버를 수정해봅시다. 유빈양의 나이가 잘못 되었으니 수정해봅시다.
[code]
1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 3
수정할 번호을 입력하세요 : 5
이름을 입력하세요 : 유빈
나이을 입력하세요 : 20
수정에 성공했습니다.

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 1
번호 : 1   이름 : 선예   나이 : 18
번호 : 2   이름 : 선미   나이 : 15
번호 : 3   이름 : 소희   나이 : 15
번호 : 4   이름 : 예은   나이 : 18
번호 : 5   이름 : 유빈   나이 : 20
번호 : 6   이름 : 성종천   나이 : 25

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
-->
[/code]
아.... 유빈양이 제일 마지막에 들어왔는데 나이가 제일 많군요-_-;
그리고 이제 말도 안되는 성종천이라는 멤버를 지워봅시다-_-;
[code]
1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 4
삭제할 멤버번호를 입력하세요 : 6
삭제에 성공했습니다.

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
--> 1
번호 : 1   이름 : 선예   나이 : 18
번호 : 2   이름 : 선미   나이 : 15
번호 : 3   이름 : 소희   나이 : 15
번호 : 4   이름 : 예은   나이 : 18
번호 : 5   이름 : 유빈   나이 : 20

1.멤버출력
2.멤버추가
3.멤버수정
4.멤버삭제
5.종료
-->
[/code]
아.....잘 되는군요-_-; 난 왜 이짓을 하고 있는거지-_-;

 
Posted by 머드초보

댓글을 달아 주세요

  1. 이전 댓글 더보기
  2. BlogIcon 머드초보 2007.10.20 09:09  댓글주소  수정/삭제  댓글쓰기

    새벽 5시까지 뭐한거야-_-; 어쨌든 자네가 칭찬해줘서 고맙구먼. 다 자네덕분이지-_-;

  3. 초보입니다. 2008.07.18 19:18  댓글주소  수정/삭제  댓글쓰기

    완전 멋지네요...나도 이런 장난도 칠수있는 여유가 있었음 좋겠스빈다 ㅠ

    • 머드초보 2008.07.21 08:24  댓글주소  수정/삭제

      아...저예제의 잘못된 점이 참 많은데....-_-;
      고마워요 ^^ 저도 사실 초보에요 ㅠ
      방문해주셔서 감사해요~

  4. BlogIcon 지니랜드 2009.01.05 17:29  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다.

    • 머드초보 2009.01.07 02:21  댓글주소  수정/삭제

      아넵 방문해주셔서 감사합니다 ^^
      도움이 되셨다니 다행이네요^^
      헉...이거 너무 오래전에 짠거라-_-;

  5. 지나가는초보 2009.12.31 11:48  댓글주소  수정/삭제  댓글쓰기

    ㄳ 속쉬원하네요
    소스도 다 잘되고요
    다만 WonderGirls.xml에서 DELETE FROM WONDERGIRLS WHERE NUM = #num# 이렇게 해줘야지 되네요 FROM빠졌다고 에러나던데...

  6. BlogIcon 선화 2010.07.22 02:36  댓글주소  수정/삭제  댓글쓰기

    감사합니다..도움이 많이 되었네요...

    블로그로 살포시 복사해갑니당..

  7. BlogIcon 누리군 2010.09.01 14:13  댓글주소  수정/삭제  댓글쓰기

    앗...이렇게 좋은 예제가...

    감사해요^^

  8. BlogIcon 박일권 2012.01.18 10:38  댓글주소  수정/삭제  댓글쓰기

    사랑해요

  9. BlogIcon 웅담 2012.02.09 09:59  댓글주소  수정/삭제  댓글쓰기

    오우 .. 왜 이짓을 하긴요 무지한 저같은 사람을 위해서?

  10. BlogIcon 박민규 2012.03.13 22:17  댓글주소  수정/삭제  댓글쓰기

    DB와의 연동을 매끄럽게 해주는군요!!
    프로젝트에 써먹어야겠네요 ㅎㅎㅎㅎ
    감사합니다.
    근데 HIBERNATE라는 놈이랑iBatis는 어떤관계지요 ?

    • BlogIcon 머드초보 2012.03.22 11:35 신고  댓글주소  수정/삭제

      Hibernate는 Object Relation Mapper구요. 즉 객체와 디비의 관계형을 매핑하는 것이죠. 그래서 그냥 디비가 프로그래밍에 녹는 느낌? iBatis는 지금은 많이 바뀌었지만, 그때 당시만해도 그냥 sqlmapper였습니다. sql이 미리 정의되어있고, 그걸 손쉽게 함수로 꺼내쓰는 그런 존재였습니다^^

  11. 차메 2012.06.11 17:48  댓글주소  수정/삭제  댓글쓰기

    아주 좋은 예제입니다.
    웹과 postgresql 연동할때 필수지침처럼 항상 참고합니다.
    군더더기없고 깔끔한 코딩이십니다.

  12. BlogIcon 노진우 2012.06.25 15:57  댓글주소  수정/삭제  댓글쓰기

    감사해요 많은 도움이 되었습니다 :)

  13. 웹웹 2013.02.05 02:08  댓글주소  수정/삭제  댓글쓰기

    감사합니다^^
    재밌게 보았습니다 ㅎㅎㅎ

  14. 1 2013.03.07 17:51  댓글주소  수정/삭제  댓글쓰기

    이것은 좋은 예제다.

  15. 26살 동정 2013.03.11 21:15  댓글주소  수정/삭제  댓글쓰기

    님아 사랑해요

  16. 2013.04.12 09:36  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  17. 똥광이 2013.08.21 15:31  댓글주소  수정/삭제  댓글쓰기

    재밋게 잘 봤습니다..^^ 큰 도움이 됬습니다!!

  18. 덜덜 2014.01.06 15:43  댓글주소  수정/삭제  댓글쓰기

    잘보고 갑니다.선예 아아.

  19. 레베 2014.01.10 09:26  댓글주소  수정/삭제  댓글쓰기

    잘 보았씁니다~~

  20. ㅇㅇ 2014.04.11 09:52  댓글주소  수정/삭제  댓글쓰기

    감사합니다 머릿속에 정리가 딱 되네요

  21. 호박 2015.09.04 00:47  댓글주소  수정/삭제  댓글쓰기

    감사합니다.
    초짜로 아무것도 모르고 예제를 따라만 쳐봤어요^^
    이제 분석해야될 것 같습니다.^^

 

건국대를 한번도 안가봐서 혹시나 늦을 까봐 일찍 갔더니 9시30분에 도착했습니다.
아직도 준비중이었습니다-_-; 온사람도 몇명 없었고-_-; 어쨌든 기다리고 있는데, ADOBE에서 뭐 가입하라고 쓰는 종이를 작성하면 옥상훈님이 쓰신 "예제로 배우는 플렉스2"를 나눠주더군요-_-;

가볍게 적고 받았습니다. 제가 FLEX공부할 때 가장 도움이 되었던 책인데 도서관에서 빌려서 21일밖에 못 봤는데 이제 나의 것이 되버리니 참 좋았습니다 ^^ FLEX공부를 더 하라는 하나님의 뜻인가봐요-_-;

어쨌든 밖에서 주는 네이버가 준비한 기념품을 몇개(볼펜, 연습장, 핸드폰액적클리너, 포스트잇 등)를 받고 교재를 5000원에 구입하고 입장했습니다. 아....개인적으로 SUN에서 하는 이벤트인 SCJP응시권이 당첨되었으면 좋겠어요-_-;

입장을 하니 네이버가 OPEN API광고를 무한반복으로 돌려 보여주더라구요-_-; 자바 광고도 나오는데 DARK STAR인지 뭔지-_-;

우선 옥상훈님이 개회사를 하시고, 축사로 고건님이 하셨는데, 오픈소스활성화 하자 뭐 그런 내용이었어요-_-; 기조연설 두분이 하셨는데 우리나라가 언어의 장벽때문인지 오픈소스프로젝트에 참여도 매우 낮다고 하더군요. 하긴 맨날 야근하고, 그러는데 영어공부할 시간도 없고, 참여할 시간도 없고 그러는 우리나라 현실이 참 안타깝기만 하네요. 그렇다고 우리나라가 실력은 뒤쳐진다고 생각하지 않는데요. 네이버에서 오픈소스프로젝트를 준비한다고 하는데 잘 되었으면 좋겠네요 ^^

그나저나 세션은 왜 나눠놓은 걸 까요-_-; 뭘 들어야 할지 고민많이 했어요 ^^

1 ROUND NHN 박재성 VS OKJSP허광남
이건뭐 대결하는것도 아니고 세션을 나눠놨어요-_-; 알고보니 허광남님은 GS강서타워에서 일하시더라구요. 그럼 밥먹을 때 몇번 봤을텐데-_-; 저희회사도 그쪽에서 있는데 밥은 GS지하식당에서 먹습니다-_-; 다음에 보면 싸인이라도 받아야 겠군요-_-;
전 박재성씨 강의를 들으러 갔어요-_-; 제가 프레임워크에 관심이 많아서 그쪽으로 설명할 것 같아서 ^^
우선 박재성씨는 NHN에서 "비디오로그"라는 것을 런칭하려고 작업중이시라고 하는데요. 대충 내용은 협업을 가능하게 하자 뭐 그런거 였는데 그걸 하기위해서 오픈소스를 이용하자 그런내용이네요.
박재성씨 개그맨 하셔도 될 것 같습니다-_-; 아놔 웃겨요^^ 참 몰랐는데 네이버블로그나 카페같은 것이 Struts, Spring, iBATIS 등등의 오픈소스프레임워크를 이용해서 만들었다고 하더군요. JIRA라는 것에 대해서 처음알았구요.
그리고 특히 강조한게 Mylyn이라는 이클립스플러그인인데 이게 강력하다고 이것을 쓰면 협업이 쉬워진다 뭐 그런내용인거 같습니다 ^^ 한가지 기능을 위해서 여러개의 class, jsp, xml이 필요해서 막 헷깔리는데 Mylyn으로 편하게 관리할 수 있다고 하더군요. 어쨌든 좋은 프레임워크는 업무를 효율적으로 만드니 오픈소스를 활용하라 뭐 그런내용이었어요. 유익한 내용이었어요 ^^

2 ROUND SUN 배헌장 차장 VS 윤종수 판사
이건 당연히 배헌장씨 강의를-_-; 법을 들으면 왠지 졸릴것 같아서 JAVA 7에 대해서 말하는 듯 해서 이것을 선택했습니다. JAVA7이 2009년에 공개된다고 하더군요-_-; 아직 멀었네요 ^^
JAVA가 오픈소스화 했기때문에 더욱 향상되고 기대되는 부분인데요.
솔직히 졸려서 잤습니다-_-; 그리고 그냥 JAVA랑 지금 하고있는 글래스피쉬인지뭔지를 홍보하러 온 것 같습니다 ^^ 한가지 기억나는것은 JAVA프로젝트 코드명이 동물의 왕국이라더군요-_-;
JAVA7은 돌핀인데 전에 JAVA5인가? 는 TIGER더군요-_-; 어쨋든 자바가 더욱 더 발전했으면 하는 바램입니다. 오픈소스로 인하여 더욱 향상된 기능으로 만났으면 하네요 ^^(뭐 지금도 충분히 좋은데 ^^)

3 ROUND 오픈마루 강규영 VS 한국모질라그룹 윤석찬
파이어폭스를 제가 안쓰기 때문에 그냥 강규영씨 강의 들었습니다-_-; 솔직히 Xquared도 뭔지 잘 몰랐습니다-_-; 근데 스프링노트라는 사이트에서 쓰이는 편집기 기능인데 이것만 따로 떼어다가 다른 곳에 적용할 수 있는 것 같습니다. 이것도 졸려서 잤습니다-_-;
사실 금요일날 12시넘어서 집에 들어가서--; (핑계를-_-)

4 ROUND ADOBE 커뮤니티 챔피언 배준균 VS RED HAT 이희승
FLEX에 관심이 많아서 당연히 배준균씨 강의 들었습니다-_-; FLEX에 대해서 많이 알려지지 않아서 인지 홍보하러 나온 것 같습니다 ^^ 예전에는 APP에서 되던데 WEB에서 안되는게 많았는데 그것을 가능하게 해주는 RIA제작 툴이라고 설명을 하는데요. 뭐 제가 FLEX를 조금 만져본 결과 생각하면 모든게 다 가능할 것 같습니다 ^^
FLEX관련 오픈소스가 뭐가 있는지 설명해주셨구요. 마지막에 신기한 플렉스 사이트를 알려줬는데 이거 정말 신기하더군요. 그리고 "AIR" 라는 것에 대해서 말해주셨는데 데스크탑에서 웹과 연동해서 띄우는 프로그램 뭐 그런거 같은데 위젯같은거라고 말해야하나요? 저도 잘모르겠네요. 한번 알아봐야겠습니다 ^^

5 ROUND DAUM 박성길 VS SKUG 안영회
당근 스프링 2.0 활용을 찾아갔어요-_-; 아직 전 스프링에 대해서 위대하다고 못느껴서 그것을 느껴보려고 갔습니다. 주위에서 하도 스프링스프링해서-_-; 스프링을 사용하게 되면 자신이 침해당하지 않고 코드를 작성할 수 있다? 뭐 그런건가요?-_-; IOC, AOP 등등 뭐 이상한 개념이 아직도 이해가 안가네요-_-; 마지막에 스프링 한국 유저 모임 홍보하시고-_-; 세계 최초(?)로 2.5 적용한 서적을 준비중이라고 하더군요 ^^ 세계최초 ^^
암튼 재미있게 설명 잘하시더라구요 ^^

마지막에 혹시나 하는 마음에 추첨행사에 갔는데 역시나 안되더군요 ㅠㅠ

어쨌든 참 좋은 행사 였던 것 같습니다. 근데 예상외로 사람들이 많이 안 온것 같습니다. 개발자분들은 야근때문에 바빴는지--; 그리고 대학교에서 참관하라고 강제로 뭐라 했는지 대학생들도 많이 온 것 같네요. 오픈소스에 관심있는 분들이 오신거일 수도 ^^ 나름 좋은 정보를 알아가서 좋았던 것 같습니다 ^^

 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 열이아빠 2007.10.15 10:11  댓글주소  수정/삭제  댓글쓰기

    플렉스 책 경품으로 받았다는 분이 계셔서..아직 경품으로 통하는구나 라고 생각했는데 그냥 막 나눠주었다니...부럽습니다.ㅎㅎ

    • BlogIcon 머드초보 2007.10.15 12:14  댓글주소  수정/삭제

      오홋 flex component에서 뵙던 열이아빠님께서 누추한 저의 블로그를 오시다니 영광입니다 ^^
      그냥 일찍 갔는데 adobe부스에서 책을 20권정도(?)를 선착순으로 나눠주더라구요-_-; 그래서 잽싸게 받았죠 ^^
      방문해주셔서 감사하고 영광이네요 ^^