태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

Knowhow/Programming2009/02/17 14:19
Creative Commons License
PHP 강의 3
조회(148)
프로그래밍 | 2007/11/16 (금) 16:19
추천 | 스크랩
이번 강의는 코드의 설명은 없습니다.
다만 제가 생각하는점과 그 동안 강의에서 사용한 코드를 정리합니다.

3편 코드 및 정리

1,2 편에서 클래스로 된 DB나 게시판을 보여드렸습니다.
아직 클래스에 대해 생소한분이나 귀찮게 생각하여 멀리하는분들이 많은듯합니다.
클래스는 많이 들었다시피 재사용성을 높이기 위해 만듭니다.
하지만 웹프로그램에서는 재사용성을 높이는 부분이 많이 떨어지는게 사실입니다.
각 페이지마다 고유의 방식으로 프로그램을 처리해야할일이 있고 공통된점을 찾기도 힘듭니다.
하지만 클래스를 만들어서 사용하다보면 꼭 재사용성만이 아니라 깔끔한 코드를 볼 수 있습니다.
함수의 중복으로 인한 오류도 줄일 수 있고 기능별로 파일을 구분하기도 쉬워집니다.
그리고 자주 클래스를 만들다보면 공통된 부분이 생기기 마련이고 점점 발전된 코드를 작성하는 자신을 볼 수 있게 될것입니다.

그 동안 강의에 사용된 파일들입니다.
hwani.zip
파일 다운로드

압축파일안에 pear.zip 파일은 Pear 파일입니다.
아마 같은 디렉토리에 압축을 풀면 DB.php 는 작동할것입니다. 하지만 정식으로 Pear를 설치하는것을 권합니다.
Pear 사이트 : http://pear.php.net
Pear 메뉴얼 : http://pear.php.net/manual/en/
최신버전의 PHP는 기본으로 Pear가 설치됩니다.

이것으로 저희 허접한 첫 강의를 마칩니다.
많은 분에게 도움이 되었으면 합니다^^ [이 게시물은 PHPSCHOOL님에 의해 2006-02-21 15:11:26 팁앤테크에서 복사 됨]

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/542 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 14:19
Creative Commons License
PHP 강의 2
조회(248)
프로그래밍 | 2007/11/16 (금) 16:18
추천 | 스크랩
이 강의는 게시판을 만드는것에 대한것이 아닙니다.
일반 글을 쓰는 게시판이라기보단 DB의 데이타를 게시판형식으로 출력하는 부분에 대한 강의입니다.
웹프로그램을 하다보면 회원목록, 게시물목록, 로그등 다양한 DB의 기록을 게시판형식으로 보여줘야할 경우가 많습니다.
매번 같은일을 하면서 코딩이 많다고 느끼신적은 없는지요?

2편 게시판

본 강의는 1편 DB를 이용합니다.
일단 게시판 클래스 소스입니다. 억지로 소스코드를 이해하려고 할 필요는 없습니다.

  1. <?php
  2. require_once "common.php";    //common function
  3. require_once "mydb.php";    //db class
  4. class board
  5. {
  6.    var $db;
  7.    var $FNAME;
  8.    var $LIST_SIZE, $SQL_LIST;
  9.    var $TOTAL;
  10.    var $pagelist;
  11.    var $start;
  12.    function board($db)
  13.    {
  14.        $this->db=$db;
  15.        $this->FNAME=$_SERVER[PHP_SELF];
  16.    }
  17.    function config($totalsql, $listsql, $listsize)
  18.    {
  19.        $this->TOTAL=$this->db->qo($totalsql)+0;
  20.        $this->SQL_LIST=$listsql;
  21.        $this->LIST_SIZE=$listsize;
  22.    }
  23.    function blist($page, $add='', $pageline=10)
  24.    {
  25.        if(!$page) $page=1;
  26.        $this->pagelist=paging($this->FNAME, $page, $this->TOTAL, $this->LIST_SIZE, $pageline, $add, $start, $end);
  27.        if($start) $start--;
  28.        $sql=$this->SQL_LIST. " limit $start, ". $this->LIST_SIZE;
  29.        $data=$this->db->q($sql);
  30.        $this->start= $this->TOTAL - $start ;     //게시물의 번호를 얻기위한 변수
  31.        return $data;
  32.    }
  33. }
  34. ?>
소스는 간단합니다. 페이징 처리는 common.php 에 따로 함수로 만들어서 사용하고 있습니다.
그럼 게시판 클래스가 어떻게 사용되는지 한번 보도록 하겠습니다.

  1. <?php
  2. require_once "board.php";
  3. require_once "mydb.php";
  4. $page=$_REQUEST[page];    //현재 페이지를 받는다
  5. $mydb=new mydb();    //db생성
  6. $board=new board($db);    //게시판 클래스 생성
  7. $totalsql="select count(*) from user ";    //사용자의 수를 세는 퀴리
  8. $listsql="select * from user ";    //사용자의 정보를 보여주는 퀴리
  9. $board->config($totalsql, $listsql, 30);    //설정에 퀴리를 넣고 30은 한페이지당 보여줄 겟수이다
  10. $add="&age=$age&date=$date";     //검색후 페이지 이동시 추가정보
  11. $data=$board->blist($page, $add);    //현재 페이지와 페이지 이동시 추가적인 정보를 전달한다
  12. $pagelist=$board->pagelist;     //페이지 넘기는부분 코드가 생성되어 변수로 나온다
  13. foreach($data as $key => $val)
  14. {
  15.    $no=$board->start - $key;    //현재 글의 번호를 만든다
  16.    echo "$no - $val[name] - $val[birth]";    //글번호 - 이름 - 생일 을 출력한다
  17. }
  18. echo $pagelist;    //페이지 넘기는 부분[이전] [1] [2] [3] [다음] 출력 common.php 안에 참고
  19. ?>
조금 사용법이 복잡해 보일진 몰라도 그도안 게시판형식으로 데이타를 보여주기위한 작업을 생각하신다면 많이 간결해진것을 느끼실 겁니다.
그리고 디자인적인 요소는 템플릿을 하나 배우셔서 사용하시길 권합니다.
저는 보통 Template_ (http://www.xtac.net/ ) 를 많이 사용합니다. 템플릿의 종류는 중요하지 않습니다. 자신이 편하다고 생각하시는 것을 사용하시는게 좋습니다.
템플릿을 사용하면 속도가 느려지지 않을까하는 고민을 하시는분도 있습니다.
하지만 편리함을 생각하신다면 0.001초의 속도는 중요하지 않습니다.
프로그램은 반복적인것을 컴퓨터에게 명령하기 위해 배우니깐요^^;
그 속도를 줄이는 시간에 차라리 하드웨어를 업그레이드하는것이 비용이 더 적게든다고 생각합니다.

이와 비슷한 예제로 DB가 아닌 배열을 게시판형식으로 사용하는 클래스를 소개합니다.

  1. <?php
  2. class boardarr
  3. {
  4.    var $FNAME;
  5.    var $data;
  6.    function boardarr()
  7.    {
  8.        $this->FNAME=$_SERVER[PHP_SELF];
  9.    }
  10.    function config($data, $listsize)
  11.    {
  12.        $this->data=$data;
  13.        $this->LIST_SIZE=$listsize;
  14.    }
  15.    function blist($page, $add='', $pageline=10)
  16.    {
  17.        if(!$page) $page=1;
  18.        $total=count($this->data);
  19.        $this->pagelist=paging($this->FNAME, $page, $total, $this->LIST_SIZE, $pageline, $add, $start, $end);
  20.        if($start) $start--;
  21.        $data=array_slice($this->data, $start, $this->LIST_SIZE);
  22.                
  23.        $this->start= $this->TOTAL - $start ;
  24.        return $data;
  25.    }
  26.    function csort($array, $column, $ops=0)    // 디폴트 내림차순
  27.    {
  28.        foreach($array as $key => $val)
  29.        {
  30.            if($val[$column] != false)
  31.            {
  32.                $array2[]=$val;
  33.            }
  34.        }
  35.        for($i=0; $i<count($array2); $i++){
  36.                $sortarr[]=$array2[$i][$column];
  37.        }
  38.        $op = array(SORT_DESC, SORT_ASC);     // 내림차순 : 오름차순
  39.        @array_multisort($sortarr, $op[$ops], $array2);
  40.        return($array2);
  41.    }
  42. }
  43. ?>
위의 DB를 사용한 클래스와 비슷합니다.
다만 배열의 데이타를 게시판형식으로 보여주는데 사용합니다.

  1. <?php
  2. require_once "boardarr.php";
  3. //예제 배열 데이타
  4. $data[0][no]=1;
  5. $data[1][no]=2;
  6. $data[2][no]=3;
  7. $data[3][no]=4;
  8. $data[0][title]="aaa";
  9. $data[1][title]="bbb";
  10. $data[2][title]="ccc";
  11. $data[3][title]="ddd";
  12. $page=$_REQUEST[page];    //현재 페이지를 받는다
  13. $board=new boardarr();    //클래스 생성
  14. $data=$board->csort($data, 'no');    //no 를 기준으로 배열을 정렬한다
  15. $board->config($data, 10);    //배열 데이타와 한페이지에 보여줄갯수를 설정한다
  16. $add="&age=$age&date=$date";     //검색후 페이지 이동시 추가정보
  17. $data=$board->blist($page, $add);    //현재 페이지와 페이지 이동시 추가적인 정보를 전달한다
  18. foreach($data as $key => $val)
  19. {
  20.    $no=$board->start - $key;    //현재 글의 번호를 만든다
  21.    echo "$no - $val[no] - $val[title]";    //글번호 - 번호 - 제목 을 출력한다
  22. }
  23. echo $pagelist;    //페이지 넘기는 부분[이전] [1] [2] [3] [다음] 출력 common.php 안에 참고
  24. ?>

사용법도 DB를 사용하는 게시판 클래스와 비슷합니다.
배열형식을 게시판형식으로 보여줄일은 많지 않지만 디렉토리의 파일목록을 보여주는일등에 사용할 수 있습니다.

이것으로 2편 게시판 강의를 마칩니다^^ [이 게시물은 PHPSCHOOL님에 의해 2006-02-21 15:11:12 팁앤테크에서 복사 됨]

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/541 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 14:19
Creative Commons License
PHP 강의 1
조회(217)
프로그래밍 | 2007/11/16 (금) 16:17
추천 | 스크랩
이 강의는 코딩에 지친 웹프로그래머들에게 바칩니다;;
저는 PHP를 접한지 5년이란 세월이 흘렀습니다.
어떡하면 효율적으로 코딩을 할까? 어떻하면 코딩을 간결하게 할 수 있을까? 하는 많은 고민을 했습니다.
그 동안 저의 노하우를 강의를 합니다.
이건 단지 저의 방식이고 더욱 편한 방법이나 자신과 스타일이 맞지 않으면 이 글을 안읽으셔도 됩니다.
다만 자신이 웹프로그래밍을 하면서 너무 반복적인일을 한다고 생각되면 한번쯤 읽어보시면 분명 도움이 되리라 생각합니다.

일단 글을 다 읽고 소스는 강의의 끝에 첨부합니다.
처음에는 부담없이 읽기만 해주세요^^

1편 DB의 사용
본 강의는 MySQL기준입니다.

웹프로그램에서 빠질 수 없는 DB의 사용입니다.
mysql_connect, mysql_fetch_array등의 함수를 아직도 이용하시나요? 그럼 본 강의를 본것은 행운입니다^^

저는 일단 Pear를 사용하여 DB를 사용합니다. 하지만 Pear도 복잡한 함수와 사용법을 배워야 합니다.
그래서 저는 Pear를 한번더 감싸서 편리하게 사용하고 있습니다.(Adapter패턴)
일단 제가 사용하고 있는 DB 클래스입니다.

  1. <?php
  2. require_once 'DB.php'; //Pear
  3. require_once 'common.php';
  4. class mydb
  5. {
  6.    var $db;
  7.    var $debug=true;
  8.    function mydb($user='유져', $pass='암호', $name='데이타베이스')
  9.    {
  10.        $dsn = "mysql://$user:$pass@localhost/$name";
  11.        $this->db = DB::connect($dsn);
  12.        if(DB::isError($this->db)) die("DB Connect Error<br>죄송합니다. 잠시만 기다려주세요.");
  13.    }
  14.    function close()
  15.    {
  16.        if($this->db)
  17.        {
  18.            $this->db->disconnect();
  19.        }
  20.    }
  21.    //데이타 가져오기
  22.    function select($dbname, $arr='', $where='')
  23.    {
  24.        if($arr)
  25.        {
  26.            $sel=join(", ", $arr);
  27.        }
  28.        else
  29.        {
  30.            $sel=" * ";
  31.        }
  32.        $sql="select $sel from $dbname $where";
  33.        $data=$this->q($sql);
  34.        if($data && count($data) == 1)
  35.        {
  36.            return $data[0];
  37.        }
  38.        else
  39.        {
  40.            return $data;
  41.        }
  42.    }
  43.    //일반퀴리
  44.    function q($sql)
  45.    {
  46.        $data=$this->db->query($sql);
  47.        $this->error($data);
  48.        while ($row = $data->fetchRow(DB_FETCHMODE_ASSOC))
  49.        {
  50.            $var[] = $row;
  51.        }
  52.        return $var;
  53.    }
  54.    //퀴리 한줄만 얻기
  55.    function ql($sql)
  56.    {
  57.        $data=$this->q($sql);
  58.        if(!$data) return false;
  59.        $data2=$data[0];
  60.        return $data2;
  61.    }
  62.    //저장용 퀴리
  63.    function sq($sql)
  64.    {
  65.        $data=$this->db->query($sql);
  66.        $this->error($data);
  67.        return $data;
  68.    }
  69.    //한개의 값만 얻어오기
  70.    function qo($sql)
  71.    {
  72.        $data=$this->db->getOne($sql);
  73.        $this->error($data);
  74.        return $data;
  75.    }
  76.    //데이타 넣기
  77.    function in($dbname, $arr)
  78.    {
  79.        $num=$this->db->autoExecute($dbname, $arr, DB_AUTOQUERY_INSERT);
  80.        $this->error($num);
  81.        return $num;
  82.    }
  83.    //데이타 업데이트
  84.    function up($dbname, $arr, $where)
  85.    {
  86.        $num=$this->db->autoExecute($dbname, $arr, DB_AUTOQUERY_UPDATE, $where);
  87.        $this->error($num);
  88.        return $num;
  89.    }
  90.    //데이타 수정하기 up=up+1 이 되게
  91.    function up2($dbname, $arr, $where='')
  92.    {
  93.        foreach($arr as $key=>$val)
  94.        {
  95.            if( (!find_str($val, "+") && !find_str($val, "-") && !find_str($val, "*") ) && is_string($val) )
  96.            {
  97.                $val="'".$val."'";
  98.            }
  99.            $filed[]="$key = $val";
  100.        }
  101.        $view=join(",", $filed);
  102.        if($where) $where=" where " . $where;
  103.        $sql="update $dbname set $view $where";    //sql문 생성
  104.        $data=$this->sq($sql);
  105.        return $data;
  106.    }
  107.    //auto_increment 현재값
  108.    function seq($dbname, $field)
  109.    {
  110.        $sql="select max($field) from $dbname ";
  111.        $val=$this->qo($sql)+0;
  112.        return $val;
  113.    }
  114.    //최근 auto_increment 값
  115.    function auto()
  116.    {
  117.        $sql="select LAST_INSERT_ID()";
  118.        $val=$this->qo($sql);
  119.        return $val;
  120.    }
  121.    //에러 첵킹
  122.    function error($info)
  123.    {
  124.        if (DB::isError($info))
  125.        {
  126.            if($this->debug)
  127.            {
  128.                die($info->getDebugInfo());
  129.            }
  130.            else
  131.            {
  132.                die("DB 에러");
  133.            }
  134.        }
  135.    }
  136. }
  137. ?>
굳이 소스코드를 이해할려고 하실 필요는 없습니다.
DB의 사용이 이렇게 간결하게 될 수 있다는 것을 알려드릴려는것 뿐입니다.
많이 사용하는 방식의 DB처리를 예제로 보여드리겠습니다.

  1. <?php
  2. $db=new mydb();    //DB의 접속
  3. //다른 db에 접속하려면 $db=new mydb("aaaa", "bbbb", "cccc"); 방식으로 접속하면된다
  4. //사용자 정보의 갯수 가져오기
  5. $sql="select count(*) from user";    //퀴리문
  6. $data=$db->qo($sql);    //QueryOne 의 줄임표현입니다. 한개의 정보만 가져옵니다.
  7. echo $data;    //사용자 정보 갯수 출력
  8. // aaaa란 사용자의 정보 출력
  9. $sql="select * from user where id='aaaa' ";
  10. $data=$db->ql($sql);    //QueryLine 의 줄임표현입니다. 한라인의 정보만 가져옵니다.
  11. echo "이름 : $data[name] - 생일 : $data[birth] ";    //$data 에는 각 필드명으로 배열에 들어가 있습니다.
  12. //모든 사용자 정보 가져오기
  13. $sql="select * from user ";
  14. $data=$db->q($sql);    //보통 Query의 줄임표현입니다.
  15. foreach($data as $key => $val)    //루프를 돌립니다.
  16. {
  17.    echo "이름 : $val[name] - 생일 : $val[birth] ";    //$val 에는 한라인의 정보가 들어있습니다.
  18. }
  19. //사용자의 정보 넣기
  20. $in[name]="이름";    //정보의 배열은 $in[필드명]=값 의 형식이다.
  21. $in[birth]="1213";
  22. $in[id]="bbbb";
  23. $db->in("user", $in);    //Insert 의 줄임표현이다. 만든 배열을 넣는다
  24. //사용자 정보 수정
  25. $up[name]="이름2";    //정보의 배열은 $up[필드명]=값 의 형식이다.
  26. $up[birth]="1111";
  27. $db->up("user", $up, "id='bbbb' ");    //Update의 줄임표현이다.
  28. //+ - 되는 정보수정
  29. $up[age]="age + 1";
  30. $db->up2("user", $up, "id='bbbb' ");     //Update 에서 + - 가 필요한 형식의 경우를 위해 따로 함수를 만들었다
  31. /*
  32. 기존의 Insert문으로 보면 많이 간단해졌다는것을 알 수 있다.
  33. $sql = " insert into user set name = '이름',    birth = '1213',    id = 'bbbb' ";
  34. 필드명이 많아질수록 처리가 힘들것을 많이 격어봤을 것입니다.
  35. DB의 Insert와 Update를 배열로 넣는것은 보기편한것 외에 더 많은 장점이 있다.
  36. 배열로 사용하면서 많은 처리를 줄일 수 있다.
  37. */
  38. /*
  39. .........
  40. 여러가지 처리들(아이디 중복같은 검사들)
  41. ......
  42. $data[name]="이름";
  43. */
  44. if($no)    //회원번호가 있을경우
  45. {
  46.    $db->up("user", $data, "no=$no");
  47. }
  48. else    //회원번호가 없을경우
  49. {
  50.    $db->in("user", $data);
  51. }
  52. /*
  53. 이렇게 수많은 처리를 앞쪽에 두고 뒤에는 해당 데이타를 업데이트할 것인지 인설트할것인지를 정해서 처리하면 된다.
  54. */
  55. /*
  56. 이 방법을 보시면 더욱 놀랄것입니다.
  57. PHP는 $_POST에 배열로 전송하는 값들을 담고 있습니다. DB처리의 배열을 이것과 연결하면 수많은 단계를 줄일 수 있습니다.
  58. 아래와 같이 폼이 있다고 봅니다.
  59. <form target=post>
  60. <input type=text name=id>
  61. <input type=text name=name>
  62. <input type=text name=birth>
  63. <input type=submit value=save>
  64. </form>
  65. */
  66. $data=$_POST;    //POST로 넘어온값을 data에 저장한다
  67. unset($data[save]);    //POST 데이타중 필요없는 정보는 지운다
  68. $db->in("user", $data);    //배열을 DB에 넣는다.
  69. /*
  70. 보통 이것보다 더 많은 필드를 처리해야 했을것입니다.
  71. 물론 이 방법은 보안에 문제가 생길 수도 있습니다.
  72. 하지만 예외처리를 적당히 해주시면 수많은 DB코딩을 줄일 수 있게 됩니다.
  73. */
  74. $db->close();    //DB연결 종료
  75. ?>

이것으로 DB의 사용에 대한 강의를 마칩니다. [이 게시물은 PHPSCHOOL님에 의해 2006-02-21 15:10:54 팁앤테크에서 복사 됨]

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/540 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 14:18
Creative Commons License
윈도우즈XP에 APM_Setup 설치 방법 입니다.
조회(677)
PC이모저모 | 2007/11/06 (화) 18:00
추천 | 스크랩
APM_Setup 설치 방법 입니다.

APM_Setup 의 설치는 매우 간단합니다.
이미지를 참고 하시면서 한번 확인해 주시기 바랍니다.



APM_Setup 은 여러가지 언어로 설치가 가능 합니다.
해당 하는 언어로 설치를 진행 하여 주시기 바랍니다.
일단 한글로 설치 하도록 하겠습니다.



설치를 시작 합니다.



간단한 설명 문구가 있으니 한번쯤 읽어 주시기 바랍니다.



설치할 구성 요소를 선택 합니다.
만약 처음 설치 하시는 경우라면 다음 버튼을 클릭하셔서 설치를 진행 하시면 됩니다.

만약 덮어 쓰는 설치 방법을 선택 하시려면 Default MySQL DB & Homepage Files 를 선택 하지 말고 설치를 진행 하시면 됩니다.


설치 디렉터리를 선택 합니다.
기본적으로 C:\APM_Setup 에 설치 합니다.
만약 다른 디렉터리에 설치 하시려는 분은 찾아보기 버튼을 클릭하셔서 설치 장소를 변경하여 주시기 바랍니다.



설치가 진행 중입니다.
서버 운영에 필요한 모든 파일을 복사 합니다.



설치가 완료 되었습니다.


README 파일을 꼭 읽어 주시기 바랍니다.
README 파일에는 기본적인 패스워드와 phpMyAdmin 의 패스워드를 명시 하고 있습니다.



만약 APM_Setup Monitor 을 다른 언어로 사용하시려면 위와 같은 방법을 사용해 주시기 바랍니다.
 

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/538 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:38
Creative Commons License
SAP "SapWorkDir" Changing the default directory
조회(82)
SAP | 2006/06/23 (금) 18:05
추천 | 스크랩

We are running SAP Release 4.0B using the 620 GUI. By default, my list, save, local file, directory is C:SapWorkDir. How do I change this to something else? If I click on Options there is a directory for the local data area, which looks like the place to change the directory, but that does nothing. There must be a way to change this.

 
Use transaction SO21 to maintain the PC local directory. Or, run the ABAP program (via SA38 or SE38) RSSOPCDR.

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/473 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:31
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (하) - Equinox 기반 프로젝트 5
조회(142)
프로그래밍 | 2006/02/02 (목) 11:17
추천 | 스크랩
이전 글 에서 예상한 것처럼 인코딩 문제의 해결은 쉽지가 않았다.
 
SiteMesh의 기본 인코딩은 iso-8859-1 다.
다행이 SiteMesh 사이트에는 인코딩을 해결하는 방법을 설명하고 있다.
 
하지만, 알려준대로 해도 해결되지 않았다.
혹시나 해서 SiteMesh 적용을 피해 같은 코드를 테스트하자
브라우저에서 인코딩일 잘 표현되었다.
IE와 파이어폭스 모두
 
그럼... 원인은 SiteMesh 라고 짐작할 수 있다.
일단, 공식 문서에서의 내용이 도움이 되지 못하니까
코드를 뜯어봐야할지도 모른다. ㅡㅡ;
 
일단, 결과를 확인해보는 기초적인 기법을 통해서 알아낸 것은
sitemesh.xml 에서의 설정에 따라 브라우저가 인코딩을 설정한다는 점이다.
 
    <page-parsers>
        <parser default="true"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
        <parser content-type="text/html"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
        <parser content-type="text/html;charset=ISO-8859-1"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
    </page-parsers>
 
즉 위와 같이 되어 있는 경우, 브라우저가 ISO-8859-1 로 페이지를 인식한 반면
 
    <page-parsers>
        <parser default="true"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
        <parser content-type="text/html"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
        <parser content-type="text/html;charset=UTF-8"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
    </page-parsers>
 
이렇게 변경하자 UTF-8 로 인식했다. 문제는 그래도 한글이 제대로 출력되지 않는다는 점이다.
브라우저 인식 문제가 아니라, 한글 자체가 잘못 출력되어진다고 할 수 있겠다.
 
    <page-parsers>
        <parser default="true"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
        <parser content-type="text/html;charset=UTF-8"
            class="com.opensymphony.module.sitemesh.parser.FastPageParser"/>
    </page-parsers>
 
이렇게 chsrset이 없는 것에 대한 설정이 지워버리자 IE는 변화가 없고
파이어폭스는 SiteMesh 태그 파싱 자체가 안되었는데
원인은 알 수 없다. ㅡㅡ;
 
흠... 아무래도 소스 코드를 바꾸는 래퍼를 만드는건 조잡하고
필터.. 그래.. 인코딩 필터를 하나 더 설치해봐야겠다.
원본 : Spring 웹 어플리케이션 만들기 (하) - Equinox 기반 프로젝트 5


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/467 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:29
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (파) - Equinox 기반 프로젝트 4
조회(92)
프로그래밍 | 2006/02/02 (목) 11:17
추천 | 스크랩
일단 돌려서 눈으로 확인해보고 싶군요.
 
Equinox의 ANT 타겟(<target>s)들의 의미를 정확히 알려하지 않고
이것 저것 시도하다보니 시행착오가 많았습니다.
 
결국 지금 myapp 로 뭔가 돌아가고 있는 상황에서는
remove -> clean -> compile -> war -> deploywar -> start
 
위와 같은 순서로 ANT를 돌려야 하더군요.
너무 번거로워서 Run 이라는 이름으로 타겟을 하나 만들어서 이들이 순서대로 돌아가게 했습니다.
 
 <!-- Run in Tomcat After modification (author: MiKE) -->
 <target name="Run" depends="remove, clean, deploywar
        , start">
 </target>
 
그런데, 이 타겟은 논리적인 결함이 있는 것인지 문제가 좀 있었습니다.
무엇보다 톰캣이 romove 하고 난 컨텍스트를 동적으로 인지하지 못한다는 것이 문제였죠.
결국 톰캣을 내렸다가 올리거나 jsp 만 변경한 경우는 jsp 파일만 복사하거나 해야 합니다.
음... 톰캣을 내렸다 올리는 일을 ANT에 추가해야 할 것 같기도 한데
당장은 돌리는 방법부터 설명드리죠.
 
1. 일단, 톰캣을 실행중이어야 합니다. 그리고, 예전의 myapp가 실행중인 상태라고 가정하겠습니다.
이를 확인하기 위해서 list 타겟을 실행합니다. myapp가 있으면 remove 타겟을 실행시키세요.
없으면 먼저 start 타겟을 실행하고 다시 list 타겟을 실행해봅니다.
start가 안되면 좋고, 되면 다시 remove 타겟을 실행시키고, list를 실행해서 지워진걸 확인합니다.
 
주의하실 점은 start 되지 않은 상태에서는 remove가 되지 않는다는 점입니다.
그리고 여러 차례 테스트해보니까 remove는 정상적으로 동작하지 않는다고 짐작되네요.
어떤 경우는 remove 후에 톰캣을 내렸다가 올려도 남는 경우도 있네요.
 
결국 가장 완전한 방법은 CATALINA_HOME 아래의 webapps 디렉토리에서 제거하는 것이죠.
 
이젠 Run을 약간 바꾸죠. 지우는 것은 따로 하고, 여기서 부터 Run을 하는 것으로 합니다.
 <!-- Run in Tomcat After modification (author: MiKE) -->
 <target name="Run" depends="clean, war, install, start" />
 
이젠 잘 뜨는군요.
문제는 제가 인코딩을 UTF-8로 해서인지 한글이 전부 깨져서 나오네요.
 
단박에 고쳐질 것 같지는 않은데 밥을 먹고 해야겠네요.
 
 
원본 : Spring 웹 어플리케이션 만들기 (파) - Equinox 기반 프로젝트 4


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/466 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:28
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (타) - Equinox 기반 프로젝트 3
조회(68)
프로그래밍 | 2006/02/02 (목) 11:17
추천 | 스크랩
음.. default.jsp를 대체할만한 녀석을 하나 만들어야겠습니다.
첫 페이지 용도롤 쓰기 위해서 front.jsp 라고 작명하겠습니다.
그리고 미리 만들어놓은 첫 페이지 내용을 복사하도록 하죠.
(혹시 따라해보기 위해서 jsp 파일이 필요하시면 드리겠습니다. 
마땅히 올려둘 곳이 없으니 의견달아주시면 메일로 메일이나 메신저 등으로 보내드리죠.)
 
1. default.jsp에서처럼 태그 라이브러리를 그대로 쓰기 위해서 다음 코드를 추가합니다.
 
<%@ include file="/taglibs.jsp"%>
 
2. 페이지 제목을 아래와 같이 달았었는데 이것도 가변적으로 바꾸겠습니다.
 
<title>DeveloperInside since 2004, 자바 프로그래머를 넘어서</title>
 
이 부분을 다음과 같이
 
<title><decorator:title default="DeveloperInside since 2004, 자바 프로그래머를 넘어서"/></title>
 
그러면, 틀이 되는 front.jsp만 남고 원래 의도했던 첫 페이지는 없어지니까
일종의 인스턴스격이 첫 페이지를 index.jsp로 만들겠습니다.
기존의 index.jsp는 지워버리기 뭐하니까 index.jsp.bak 으로 파일명을 바꾸겠습니다.
 
새로 만든 index.jsp에는 다음 내용을 넣겠습니다.
 
<title><fmt:message key="index.title"/></title>
 
그리고, index.title 값으로 쓸 문자열도 지정해주죠.
 
WEB-INF/classes/messages.properties 파일을 열면 다음과 같은 부분이 있는데
index.title=Equinox ~ Welcome
 
이걸 원하는 제목으로 바꾸면 되겠죠.
 
3. 다음은 link 태그에서 css 위치를 지정할 때 decorators 디렉토리를 중심으로 하면 복잡하니까
웹 어플리케이션 루트(context)를 읽어오기 위해서 JSTL 구문을 넣습니다.
 
<c:set var="ctx" value="${pageContext.request.contextPath}" scope="request"/>
 
그리고 아래와 같이 되어 있던 부분을 변수를 EL 변수를 쓰도록 바꿉니다.
 
<link href="styles/difront.css" rel="stylesheet" type="text/css" />
<link href="styles/dinavigation.css" rel="stylesheet" type="text/css" />
 
그러면 이렇게 되겠죠.
 
<link href="${ctx}/styles/difront.css" rel="stylesheet" type="text/css" />
<link href="${ctx}/styles/dinavigation.css" rel="stylesheet" type="text/css" />
 
이젠 css 파일들을 옮겨 놓아야겠죠. 물론, 미리 만들어둔 것이 있어야죠.
 
원본 : Spring 웹 어플리케이션 만들기 (타) - Equinox 기반 프로젝트 3


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/465 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:28
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (카) - Equinox 기반 프로젝트 2
조회(40)
프로그래밍 | 2006/02/02 (목) 11:16
추천 | 스크랩
역시 모르니까 헤매고 다녔는데 태그 라이브러리에 있었군요.
 
 
매뉴얼을 찾았습니다. 간과했던 taglibs.jsp 가 열쇠였는데...
 
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"%>
 
SiteMesh에 기본적으로 포함된 태그 라이브러리는 두 개의 태그를 지원합니다.
 
Decorator Tags Page Tags
Used to create decorator pages. Used to access decorators from content pages.
<decorator:head />
<decorator:body />
<decorator:title />
<decorator:getProperty />
<decorator:usePage />
<page:applyDecorator />
<page:param />
 
 
우리가 찾던 의문은 바로 decorator:bodydecorator:getProperty 입니다.
그 녀석 들 위주로 매뉴얼을
 

<decorator:body />

Description:
Insert contents of original page's HTML <body> tag. The enclosing tag will not be be written, but its contents will.

Note: the content of the body onload and onunload events (and other body attributes) can be included in the decorator by getting the property body.onload and body.onunload (the named attributes).
For example (the decorator): <body omload="<decorator:getProperty name="body.onload" />">
원래 페이지의 HTML body 태그를 집어넣는다네요.
으흠.. 그럼 default.jsp에서 의 decorator:body 위치에 index.jsp의 <body>가 들어가는군요.
태그는 빠지고 내용만 들어간다고 합니다.
그래서 default.jsp에 보면 <body> 태그가 있네요.
  
body에 이벤트를 걸었거나 특정 속성이 있는 경우 이들을 포함시키기 위해서는 getProperty 태그가 필요한 모양입니다. 음... index.jsp에는 아예 body 태그가 없군요.
title 등의 별도의 태그로 감싸지 않는 녀석들은 모두 body의 컨텐츠로 취급하는 것인지 의문이 생기네요. 이러한 의문은 차후에 풀도록 해야겠습니다. 생산성을 위해서...
 
아무튼 decorator:body 태그를 풀면서 더불어 decorator:getProperty 도 해결하게 되었네요.
default.jsp의 해당 코드를 다시 보면
 
<div id="underground"><decorator:getProperty property="page.underground"/></div>
 
page.underground 라는 속성 값을 요구했군요.
page 태그는 없는데, 아마 index.jsp의 아래 태그를 가리키는 것으로 짐작됩니다.
 
<content tag="underground">
 
page는 아마도 SiteMesh가 HTMLPage 객체를 표현하는 내부 객체명인 듯 합니다.
이 부분도 다소 미진하게 이해하게 되네요. ㅡㅡ;
 
default.jsp의 head 부분을 보니까 decorator 태그가 두 개가 더 있네요.
 
<decorator:title default="Equinox"/>
<decorator:head/>
 
이 부분은 굳이 설명을 듣지 않아도, 유추해서 의미를 이해할 수 있을 것 같습니다.
 
 
원본 : Spring 웹 어플리케이션 만들기 (카) - Equinox 기반 프로젝트 2

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/464 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:28
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (차) - Equinox 기반 프로젝트
조회(49)
프로그래밍 | 2006/02/02 (목) 11:16
추천 | 스크랩
연이어 연재하던 시리즈가 연휴를 지나면서 복구가 어렵게 되었습니다. ^^;
처음부터 다시 훑어봐야 기억이 날 것도 같아서...
그런데 무엇보다 생산성이 떨어지는 접근법인 것도 같아서
이번에는 효과적인 방법으로 웹 어플리케이션을 만드는 것은 계속하려고 합니다.
 
Equinox는 앞서와 같이 어플리케이션 개발을 위한 작은 틀을 제공해줍니다.
앞서의 시리즈는 그것을 치밀하게 이해하려고 했는데
그보단 원하는 결과물을 만들어내면서 이해를 수반하는 식으로 가려구요.
 
일단, 첫화면은 앞에서도 본 것으로 기억합니다.
 


 
어찌 되었건 눈에 보이는 것은 index.jsp 에 기록된 HTML 들인데
첫 화면을 바꾸려면 이것을 바꿔야겠죠.
 
근데 Ctrl+F 로 찾아봐도 좌측이나 아래쪽의 링크들은 index.jsp에서 볼 수가 없습니다.
아무래도 템플릿으로 화면이 꾸며진 듯 하네요.
이미 SiteMesh를 썼다는 사실은 앞서두 언급했고
뒤져보니까 decorators 디렉토리에 default.jsp 파일이 있는데 이 녀석이 범인 같군요.
 
default.jsp 파일을 body 부분만 div로 분리된 영역을 정리해보면 다음과 같습니다.
 
container
   - intro
      - pageHeader
      - quickSummary
      - content
   - supportingText
      - underground
      - footer
   - linkList
      - linkList2
         - lresources
 
논리적으로 크게 삼등분 하고 있고, 이 녀석이 index.jsp 보다 먼저 로딩되는 것만은
확실한 것 같습니다. 다시 이녀석을 분석하고 싶은 마음이 또 생기지만 이를 억누르고
제가 만든(혹은 여러분이 만든) index.jsp가 보여지도록 할 수 있도록 궁리를 해보죠.
 
직관적으로 두 가지 정도를 먼저 알면 될 것 같습니다.
default.jsp가 어떤 설정을 통해서 불리게 되느냐?
그걸 알아야 다른 템플릿을 만들 수 있으니까요.
 
그리고 다른 하나는
동적으로 다른 jsp를 삽입시키는 방법
이건 아마도 decorator라는 태그가 알고 있을 듯 합니다.
default.jsp 에서 decorator 태그가 등장하는 부분만 추려내면 다음과 같습니다.
 
    
        <div id="content">
            <%@ include file="/messages.jsp"%>
            <decorator:body/>
        </div>
    </div>
    <div id="supportingText">
        <div id="underground"><decorator:getProperty property="page.underground"/></div>
먼저 주요 설정 저장소인 WEB-INF 디렉토리를 보면, decorators.xml 파일이 있습니다.
 
<decorators defaultdir="/decorators">
    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>
</decorators>
 
sitemesh를 잘 모르지만 자바 커뮤니티의 코딩 관습(coding convention)에 따라 해석하면
모든 요청에 대해서 /decorators 디렉토리에 있는
default.jsp를 적용하란 것이라고 생각됩니다. default 라는 이름도 지정했는데
이건 어디서 쓰이는지 모르겠네요. 서블릿처럼 이 녀석도 패턴을 밖으로 정의할 수 있나 봅니다.
 
이제 풀리지 않은 의문은 decorator:bodydecorator:getProperty 입니다.
이 의문을 풀 수 있는 단서는 web.xml 의 다음 설정 같은데요.
 
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>
 
SiteMesh API를 봐야겠군요. Ultra-API에 없네요. 갱신해야지.
갱신한 것은 북마크에서 Ultra-API 를 클릭하시면 됩니다.
 
API 문서에서 com.opensymphony.module.sitemesh.filter.PageFilter 를 찾아보죠.
설명은 간단하게 아래와 같이 나와 있네요.
 
Main SiteMesh filter for applying Decorators to entire Pages
데코레이터(장식을 해주는 객체죠)를 전체 페이지에 적용하는 SiteMesh의 주요 필터라.
 
핵심이 되는 녀석이군요. 근데 이녀석만 봐서는 decorator:bodydecorator:getProperty
알기는 어렵네요. 메소드나 필드로 이런 것들이 노출되어 있지는 않네요.
원본 : Spring 웹 어플리케이션 만들기 (차) - Equinox 기반 프로젝트


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/463 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:27
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (자) - Equinox 파악하기(4) - users.html 요청 처리(B)
조회(44)
프로그래밍 | 2006/02/02 (목) 11:16
추천 | 스크랩
Sitemesh의 PageFilter 클래스의 소스 코드를 볼까요?
 
doFilter 메소드 위주로 보도록 하죠.
 
    public void doFilter(ServletRequest rq, ServletResponse rs, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) rq;
        if (rq.getAttribute(FILTER_APPLIED) != null || factory.isPathExcluded(extractRequestPath(request))) { // (1)
            // ensure that filter is only applied once per request
            chain.doFilter(rq, rs);
        }
        else {
            request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
            // force creation of the session now because Tomcat 4 had problems with
            // creating sessions after the response had been committed
            if (Container.get() == Container.TOMCAT) { // (2)
                request.getSession(true);
            }
            HttpServletResponse response = (HttpServletResponse) rs;
            // parse data into Page object (or continue as normal if Page not parseable)
            Page page = parsePage(request, response, chain);
            if (page != null) {
                page.setRequest(request);
                Decorator decorator = factory.getDecoratorMapper().getDecorator(request, page);
                if (decorator != null && decorator.getPage() != null) {
                    applyDecorator(page, decorator, request, response);
                    page = null;
                    return;
                }
                // if we got here, an exception occured or the decorator was null,
                // what we don't want is an exception printed to the user, so
                // we write the original page
                writeOriginal(request, response, page);
                page = null;
            }

        }
    }
 
 
FILTER_APPLIED 라는 상수는 RequestConstants 인터페이스에 정의된 것이고, PageFilter 는 이를 구현학 있습니다. (1) 구문은 결국 이 필터가 한번만 수행되도록 하는 부분인 것 같네요.
Container는 서블릿 컨테이너를 표현하기 위한 클래스인데, 여기 설정된 상수들이 SiteMesh가 지원하는 것들이라고 생각됩니다. 주요 컨테이너는 모두 지원하네요.
 
    public static final int TOMCAT    = 1;
    public static final int RESIN     = 2;
    public static final int ORION     = 3; // Orion or OC4J
    public static final int WEBLOGIC  = 4;
    public static final int HPAS      = 5;
    public static final int JRUN      = 6;
    public static final int WEBSPHERE = 7;
 
(2) 구문에서는 톰캣에서 수행되는 경우만 새로운 세션을 생성합니다.
 
하늘색으로 칠한 부분이 SiteMesh가 Decorator 패턴을 활용하여 페이지를 구성하는 것으로 보입니다. 자세한 처리 결과까지 살펴보는 것은 뒤로 미뤄야 할 것 같습니다. Spring을 이해하는 것인데 SiteMesh를 따라 가다가 길을 잃을 우려가 있을 듯 해서..ㅡㅡ;
 
PageFilter 에서는 SiteMesh를 이용하여 페이지를 구성한다 정도로 정리해두죠.
 
마지막으로 exportFilter 가 남았네요. 보아하니 이 녀석도 DisplayTag라는 라이브러리(3-rd party library)를 이용하는 것이군요. 이번엔 API 정도만 살펴보죠.
 
 
    <filter>
        <filter-name>exportFilter</filter-name>
        <filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>
    </filter>
 
이는 DisplayTag 라이브러리의 TableTag를 사용하면서 Export 기능을 구현하고자 할 때 쓰는 것이라고 하네요.
 
DisplayTag 라이브러리 API 문서: http://displaytag.sourceforge.net/apidocs/
 
필터 설정을 정리하면 messageFilter 가 요청 URL을 기억해서 공유하게 했구요. sitemesh라는 이름으로 설정한 com.opensymphony.module.sitemesh.filter.PageFilter와 exportFilter 라는 이름으로 설정한 org.displaytag.filter.ResponseOverrideFilter가 각각 SiteMesh를 이용한 페이지 구성 준비와 TableTag의 Export 기능을 준비하게 하는 것이었습니다.
 
 
원본 : Spring 웹 어플리케이션 만들기 (자) - Equinox 파악하기(4) - users.html 요청 처리(B)


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/462 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:27
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (아) - Equinox 파악하기(3) - users.html 요청 처리(A)
조회(41)
프로그래밍 | 2006/02/02 (목) 11:15
추천 | 스크랩
View Demonstration  버튼을 눌러서 users.html 요청을 발생시키면 어떻게 될까요?
 
먼저 필터 매핑 정의에 따라서 필터(Servlet Filters)를 거쳐야겠네요.
 
    <filter-mapping>
        <filter-name>messageFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>exportFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
 
messageFilter와 sitemesh 는 모든 URL(/*)이 거쳐야 하고, users.html 요청이니까 exportFilter 도 거쳐야 하는군요.
 
역시 같은 web.xml 파일에 정의된 필터 선언을 하나씩 볼까요?
 
    <filter>
        <filter-name>messageFilter</filter-name>
        <filter-class>org.appfuse.web.MessageFilter</filter-class>
    </filter>
 
메세지필터는 뭐하는 녀석일까요?
 
주요 메소드인 doFilter() 만 살펴보죠.
 
    public void doFilter(ServletRequest req, ServletResponse res,
                         FilterChain chain)
    throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        // grab messages from the session and put them into request
        // this is so they're not lost in a redirect
        Object message = request.getSession().getAttribute("message"); // (1)
        if (message != null) { // (2)
            request.setAttribute("message", message);  // (2)
            request.getSession().removeAttribute("message"); // (2)
        }
        // set the requestURL as a request attribute for templates
        // particularly freemarker, which doesn't allow request.getRequestURL()
        request.setAttribute("requestURL", request.getRequestURL());
        chain.doFilter(req, res);
    }
 
(1) 먼저 요청을 보낸 세션을 읽어서 message라는 이름의 속성을 얻어옵니다. 처음에는 없으니까 null 이 되겠죠. (2) 만약에 뭔가 (남아) 있다면 이를 제거해버립니다. (3) requestURL 이라는 이름으로 해당 요청의 request url 값을  Request 영역(scope)에서 공유될 수 있는 속성을 설정합니다. 이때, URL은 프로토콜(protocol), 서버 이름(server name), 포트 이름(port number)과 서버 경로(server path) 등을 포함하지만 질의 문자열 매개변수(query string parameters)는 제외됩니다.
 
이 경우 request url은 http://localhost/myapp/users.html 이 되는 것이죠. 물론 제 경우는 디폴트 HTTP 포트가 80인 경우이니까 8080 등인 경우는 http://localhost:8080/myapp/users.html 이 되겠죠.
 
아무튼 messageFilter를 거치고 난 요청들은 모두 requestURL 이라는 이름으로 요청의 URL을 읽어올 수 있습니다. 쉽게 생각해서 서버측에서 사용자가 주소창에 무엇을 입력했는지를 식별하기 위한 변수라고 볼 수 있죠.
 
다음 필터는 sitemesh 인데요.
 
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>
 
sitemesh는 jar 형태로 참조하기 때문에 소스를 보시려면 다운로드를 해야 합니다.
 
아래 sitemesh의 처리 흐름을 도표화 한 그림을 첨부합니다. 출처는 역시 Opensymphony.com 이구요. 좀 길어져서 쉬었다가 PageFilter 소스를 살펴보죠.
 


원본 : Spring 웹 어플리케이션 만들기 (아) - Equinox 파악하기(3) - users.html 요청 처리(A)

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/461 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:27
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (사) - Equinox 파악하기(2) - index.jsp
조회(42)
프로그래밍 | 2006/02/02 (목) 11:15
추천 | 스크랩

가. include 지시문
<%@ include file="/taglibs.jsp"%>
 
먼저 include 지시문(directive)이 나옵니다. 공통적으로 사용하는 파일을 매번 타이핑 하지 않기 위한 것이죠. 이름으로 보아선 taglib 지시어를 지정하는 코드를 모아둔 것 같네요.
 
<%@ page language="java" errorPage="/error.jsp" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
<%@ taglib uri="http://displaytag.sf.net/" prefix="display" %>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator"%>
<%@ taglib uri="http://www.springframework.org/tags/commons-validator" prefix="html" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
<c:set var="datePattern"><fmt:message key="date.format"/></c:set>
 
위의 내용이 taglibs.jsp의 내용입니다. 먼저 page 지시문을 통해서 errorPage를 지정했네요. 오류가 발생하면 error.jsp로 보내라는 것이죠. 예외처리문 출력하는 것입니다. 코드를 설명하는건 생략하죠.
 
다음에는 예상대로 taglib 지시어가 늘어서 있네요. JSTL 중에서 Core와 Format 을 사용하는 것 같네요. 그리고, 목록보기를 위해선 오픈소스인 DisplayTag를 쓰려고 이를 선언했네요. 뒤어어서 Spring에서 제공하는 두 가지 태그와 함께 화면을 분할하기 위해서 Sitemesh의 태그를 쓰네요.
 
뒤이어서 JSTL Core의 태그를 썼네요. set 태그는 변수에 값을 할당하는 것입니다. var 속성이 변수 이름을 나타내고 태그안의 텍스트가 값이 됩니다. dataPattern 이라는 변수에 data.format 이라는 키값으로 메시지를 꺼내와서 할당하네요.
 
message 태그는 국제화 지원을 위한 태그 중 하나입니다. 다국어 지원이라는 표현이 더 자연스러울 듯 하네요. 다국어 지원을 위해서 localization context 라는 메커니즘을 사용하게 되는데요. 음... 특정 지역과 언어에 맞는 문자나 통화 기호등을 표현하기 위해서 문맥(context)를 지역에 따라 달리하는 방법이죠.
 
이를 위해서는 web.xml 에서 javax.servlet.jsp.jstl.fmt.localizationContext 라는 이름의 context parameter를 설정해야 하는데 그 값은 String 타입의 문자열이거나javax.servlet.jsp.jstl.fmt.LocalizationContext 객체 타입이 됩니다.
 
    <!-- Define the basename for a resource bundle for I18N -->
    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>messages</param-value>
    </context-param>
 
web.xml 파일에 위와 같은 설정이 있는데, message 라는 값은 ResourceBundle의 기반(base)이 되는 이름이 되며, 결국 WEB-INFclasses 디렉토리의 message_xx_XX.properties 파일에서 메시지를 읽어오게 되는 것이죠.
 
date.format=MM/dd/yyyy
 
messages.properties 파일에 위와 같은 내용이 있네요.
 
나. 제목 및 본문부
<title><fmt:message key="index.title"/></title>
 
이 내용은 위와 같이 다국어 메시지를 지원하려는 의도라고 볼 수 있죠.
 
index.title=Equinox ~ Welcome
 
이렇게 되어 있네요.



그리고 본문은 주로 html 로 되어 있는 설명문들이라서 설명하지 않을 부분은 생략하고, 전문을 저 아래 첨부하기로 하죠.
 
<acronym title="Create, Retrieve, Update and Delete">CRUD</acronym>
 
음.. 이런 태그도 있었네요. ^^;
 


 
<a href="?" omclick="readMore(); return false">Click here</a>
Click here 라는 문자에는 onclick 이벤트가 걸려있구요. id가 readmore인 div 태그 안의 버튼에도 onclick 이벤트가 걸려있네요. 
 
<div id="readmore" style="display:none">
    <h3>Introduction to Equinox</h3>
...
        <button class="button" omclick="readMore();">&laquo; Back</button>
    </p>
</div>
 
onclick 이벤트가 발생하면 호출되는 자바 스크립트 함수의 정의는 맨 아래 있네요.
 
<script type="text/javascript">
function readMore() {
    var main = document.getElementById("main");
    var more = document.getElementById("readmore");
    if (main.style.display == "") {
        main.style.display = "none";
        more.style.display = "";
    } else {
        more.style.display = "none";
        main.style.display = "";
    }
}
</script>
 
엘리먼트(태그죠)의 id 값이 main인 엘리먼트 객체를 얻고, readmore인 엘리먼트 객체를 각각 얻구요. 그 중에서 main인 엘리먼트(id는 div 태그에만 있어서 결국 div 태그를 말하죠)의 style 속성의 display 값이 아무것도 없으면 none으로 설정하고, readmore 라는 id를 같는 div 태그의 style 속성의 display 값을 아무것도 없는 것으로 설정합니다. 그렇지 않은 경우는 반대로 하구요.
 
이것은 결국 두 개의 div 태그가 번갈아 보여지는 효과가 나죠. 자바 스크립트 강좌는 아니기 때문에 이건 여기까지 하죠. 저도 자바 스크립트는 약해서.. ^^;
 
<content tag="underground">
이런 태그도 있었네요.. 별다른 효과는 없는 것으로 보이는데..ㅡㅡ;
 
아무튼 여기까진 전부 HTML/JS 관련된 것이고, 실제로 자바 웹프로그래밍이나 Spring에 관련된 부분은 바로 이거죠.
 
<button class="button" omclick="location.href='users.html'">View Demonstration</button>
users.html 이라는 GET 요청을 발생하게 되는 부분이죠.
 
 
---------------------------------------------------------------------------------------
<%@ include file="/taglibs.jsp"%>
<title><fmt:message key="index.title"/></title>
<div id="main">
    <h3>Welcome to Equinox!</h3>
    <p>
        <b>Equinox</b> is a lightweight version of <a href="http://raibledesigns.com/appfuse">AppFuse</a>.
        I was inspired to create it while writing <a href="http://springlive.com">spring/ Live</a> and
        looking at the <em>struts-blank</em> and <em>webapp-minimal</em>
        applications that ship with Struts and Spring, respectively.
        These "starter" apps were not robust enough for me, and I wanted
        something like AppFuse, only simpler.  Much of the documentation for developing
        with Equinox can be found in the <a href="http://www.sourcebeat.com/docs/Spring%20Live/Rev_4/Spring%20Live_SampleChapter.pdf">
        Spring QuickStart Chapter</a> in Spring Live.  If you have issues downloading this
        PDF, you might try saving it to your hard drive before opening it.
    </p>
    <p>
        The basic Equinox application shows how to do simple
        <acronym title="Create, Retrieve, Update and Delete">CRUD</acronym> on a database table. 
        To see this feature, click on the button below. <a href="?" omclick="readMore(); return false">Click here</a>
        to learn more about Equinox.
    </p>
    <p>
        <button class="button" omclick="location.href='users.html'">View Demonstration</button>
    </p>
</div>
<div id="readmore" style="display:none">
    <h3>Introduction to Equinox</h3>
    <p>
        Equinox is designed to show webapp developers how to start
        a bare-bones webapp using a <a href="http://www.springframework.org/">
        Spring</a>-managed middle-tier backend and <a href="http://www.hibernate.org/">
        Hibernate</a> for persistence. By default, Equinox uses Spring for
        its MVC framework, but you can change it to
        <a href="http://struts.apache.org">Struts</a>,
        <a href="http://opensymphony.com/webwork">WebWork</a>,
        <a href="http://jakarta.apache.org/tapestry">Tapestry</a>
        or <a href="http://www.myfaces.org">JSF</a>.  Installers are in the "extras" directory.
    </p>
    <p>
        An in-memory <a href="http://hsqldb.sf.net">HSQL</a> database is used by default.
        The database and its tables are created on-the-fly when tests (or the application)
        is run.  The one issue of using this method is that records disappear every
        time the app is started.  The nice side effect is that you never write tests
        that depend on existing data.  If you have issues with records not showing up or
        want to use a different database, see <a href="http://jroller.com/page/raible/20040809#alternate_database_configurations_with_myusers">
        these instructions</a>.  Since there is no container
        configuration required, the application should work with any Servlet 2.4
        servlet engine. 
    </p>
    <p>
        <button class="button" omclick="readMore();">&laquo; Back</button>
    </p>
</div>
<content tag="underground">
<h3>Assumptions</h3>
<ul>
    <li>It's 2004, no one uses Netscape 4 anymore, or at least
        no one does by choice. All HTML will be XHTML compliant,
        without a space: i.e. &lt;br/&gt; not &lt;br /&gt;.</li>
    <li>JSP 2.0 is out, so it will be used to simplify syntax.</li>
    <li>Simplicity is more important than configurability.</li>
</ul>
<h3>Notes</h3>
<ul>
    <li>Equinox ships with project files for both <a href="http://www.eclipse.org">Eclipse</a>
    and <a href="http://www.jetbrains.com/idea/">IDEA</a>. For information on setting up 
    Equinox to run tests and debug Tomcat, see
    <a href="http://confluence.sourcebeat.com/display/SPL/FAQ">the FAQ</a>.</li>
    <li><a href="http://opensymphony.com/sitemesh">SiteMesh</a> is used for page decoration. It was
    <a href="http://raibledesigns.com/page/rd?anchor=sitemesh_passed_the_10_minute">
    so easy to use</a>, I couldn't resist!</li>
</ul>
</content>
<script type="text/javascript">
function readMore() {
    var main = document.getElementById("main");
    var more = document.getElementById("readmore");
    if (main.style.display == "") {
        main.style.display = "none";
        more.style.display = "";
    } else {
        more.style.display = "none";
        main.style.display = "";
    }
}
</script>
원본 : Spring 웹 어플리케이션 만들기 (사) - Equinox 파악하기(2) - index.jsp

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/460 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:27
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (바) - Equinox 파악하기(1) - 시작 페이지 설정
조회(37)
프로그래밍 | 2006/02/02 (목) 11:15
추천 | 스크랩
먼저 Equinox 가 제공하는 템플릿 성격의 어플리케이션을 파악하고 나면 어떤 산출물이 필요한지 알 수 있고, 예제를 통해 배우는 식으로 따라하다보면 Spring 사용에 더욱 익숙해지리라 생각됩니다.
 


 
일단, 첫화면부터 추적을 해나가죠.
 
출발점이라고 할 수 있는 web.xml 파일을 먼저 살펴보죠. web.xml 전문은 저 아래 첨부합니다.
가장 먼저 보게 되는 페이지는 welcome-file-list 엘리먼트에 의해서 결정되죠.
관습을 깨지 않고 index.jsp로 했군요.
 
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
 
컨텍스트 리스너가 먼저 실행되겠지만 그건 차후에 관여된 것이 나타날 때 보도록 하고 index.jsp를 먼저 살펴보도록 하겠습니다.
 
 
 
------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
    <display-name>Equinox</display-name>
    <!-- Define the basename for a resource bundle for I18N -->
    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>messages</param-value>
    </context-param>
    <filter>
        <filter-name>exportFilter</filter-name>
        <filter-class>org.displaytag.filter.ResponseOverrideFilter</filter-class>
    </filter>
    <filter>
        <filter-name>messageFilter</filter-name>
        <filter-class>org.appfuse.web.MessageFilter</filter-class>
    </filter>
    <filter>
        <filter-name>sitemesh</filter-name>
        <filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
    </filter>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext*.xml</param-value>
    </context-param>
    <filter-mapping>
        <filter-name>messageFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>sitemesh</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    <filter-mapping>
        <filter-name>exportFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error.jsp</location>
    </error-page>
</web-app>
 
 
원본 : Spring 웹 어플리케이션 만들기 (바) - Equinox 파악하기(1) - 시작 페이지 설정


Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/459 관련글 쓰기

댓글을 달아 주세요

Knowhow/Programming2009/02/17 13:26
Creative Commons License
[스크랩] Spring 웹 어플리케이션 만들기 (마)
조회(36)
프로그래밍 | 2006/02/02 (목) 11:15
추천 | 스크랩
5. Equinox 배포하기
 
Equinox가 템플릿처럼 기본으로 제공하는 웹 어플리케이션을 배포하자.
드디어 귀찮아서 ANT_HOMEbin 을 패스에 넣었다.
먼저 톰캣을 띄운 후에 명령창에서 다음 명령을 입력한다.
 
ant list
 
톰캣의 관리자 연결을 위한 정보가 빌드파일과 다르면 문제가 발생한다.


 
build.properties 파일에 정의된 다음 내용을 변경해야 한다.
tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=admin
tomcat.manager.password=admin
 
관리자 인증 정보는 톰캣 설치 디렉토리(CATALINA_HOME) 아래의 conf 에 tomcat-users.xml 파일에 기록되어 있다. 이를 변경하면 관리자 인증정보(id/패스워드)가 바뀐다.
 
<user username="mike" password="younghoe" roles="admin,manager"/>
 
이들을 적절히 변경했다면 다시 ant list를 입력해보자.


 
잘 되는군요. ANT에서 하지 않고, 브라우저 주소창에서 URL을 입력하고 관리자 로그인을 하는 방법으로도 동일한 효과를 얻을 수 있습니다.
 


 
 
저는 디폴트 HTTP 포트를 80 으로 지정해서 포트 번호를 주소에 입력하지 않은 것이죠.
manager/list 와 같이 입력하면 위와 같이 보여지구요.
manager/html 이라고 입력하면 아래와 같이 HTML 형태로 보입니다.
 


 
이제 배포를 해보자.
명령어는
 
ant deploy
 
성공했으면 다음 명령어로 확인해본다.
 
ant list
 
myapp 가 올라온 것을 확인할 수 있다.^^
브라우저에서 확인해보자... 잘 돌아가네
 


 
원본 : Spring 웹 어플리케이션 만들기 (마)

Posted by 프랭크리

TRACKBACK http://frank.nextios.com/trackback/458 관련글 쓰기

댓글을 달아 주세요