스위치 (DNS 포함) 이슈로 발생할 수 있다. 특히 시스템이 문제 없다면, JVM 자체 문제일 수 있다.


The NoRouteToHostException will be thrown while attempting to connect to a remote host but the host cannot be reached for instance because of a badly configured router or a blocking firewall.

Most applications should not catch this exception; it is more robust to catch the superclass SocketException. 



아래 내용은 인프라 이슈가 아닌 JVM자체 이슈에 대해서 다룬 것이다. 


 

* 원인


JVM를 restart하면된다. DNS를 추가. 혹은 ip변경시에 java는 항상 그것을 캐쉬하고 있는 상태이기 때문에 해당 서버를 DNS정보로부터 받지 못한다.

 

 

* 증상

 


 

Server is not available * Additional Info *
qString :
http://isag.google.com:8080/common/monitor/ok.html
vhost :

 

 2007-08-29 19:18:20 [ERROR](HttpClientWrapper.java:293) No route to host : HttpClientWrapper[ encoding = MS949 establishTimeout = 12000 followRedirects = true noCache = true params = [] prepareURL = null soTimeout = 5000 statusCode = -1 SYSTEM_ENCODING = ISO8859-1 url = http://isag.google.com.com:8080/common/monitor/ok.html vhost = bodyString = null]

java.net.NoRouteToHostException: No route to host

 

모니터 java단에서 No route to host라 계속 뜬다.

 

* 해결

JVM 웹서버 재시작 또는 매번 DNS서버에서 정보를 읽어 올 수 있도록 옵션 추가해서 재시작한다. 

 -Dsun.net.inetaddr.ttl=50


 

* 이유

파일은 캐쉬되는 경향이 있다. 실제 native단에서는 한번 try한 것은 일부러 캐쉬하여 다음번 요청에 대해서 그 결과를 알려주는 경우가 있다.

네트웍도 마찬가지로 그렇게 되어 있다.

 


------


java8 소스를 보니까. NoRouteToHostException이 발생하려면 2가지 이유 중의 하나이다. 


1. EADDRNOTAVAIL

NoRouteToHostException은 소켓 연결시 EADDRNOTAVAIL이 발생하면 Exception을 던지도록 되어 있다. EADDRNOTAVAIL의 의미가 Address not available 라는 의미더라구요. DNS 이슈 문제가 아니면, 순간적으로 app server에서 특정 서버 소켓 연결을 위해 클라이언트 포트를 많이 생성(임시포트(ip_local_port_range값에서 max-min의 값)까지 생성)하면서 나는 이슈로 볼 수 있을 것 같다.  

$  cat /proc/sys/net/ipv4/ip_local_port_range

32768 65000

$  cat /proc/sys/net/ipv4/tcp_tw_reuse

0


2. EHOSTUNREACH


routing table 쪽으로 이슈가 발생해서 reach할 수 없으면 해당 에러가 발생한다. 





Posted by '김용환'
,

웹스나이퍼

web 2007. 9. 4. 02:32

웹소스 보기, html 디버깅시 유용한 툴이다.

 

 

 

http://comingsoft.com/websniper/down.html

 

 

 

 

 

 

[시스템 사양]
운영체제: Windows98,WindowsME, Windows2000, Windows2003, WindowsXP
웹브라우저: Internet Explorer 6.0 이상 버전

[설치하기]
주의! 웹스나이퍼1B 사용하시는 분은 제거 하신 후에 설치해 주십시요.
주의! 웹스나이퍼2, 2a, 3을 사용하시는 분은 websniper3a_patch.zip를 다운받아 압축을 풀고 웹스나이퍼가 설치된 경로에 덮어씌우세요.

1. 아래의 버튼을 클릭해서 websniper3a_setup.exe 웹스나이퍼 프로그램을 다운 받습니다.(다운받은 경로를 기억하세요)

2. 모든 웹브라우저를 닫습니다.
3. 위 1번항목에서 다운받은 프로그램을 클릭하면 자동으로 설치가 됩니다.
4. 설치가 완료되면 아래 그림처럼 메뉴에 등록이 됩니다(큰 빨간사각형 참고)메뉴의 "보기>탐색창>WebSniper"를 찾아 선택합니다.

< 웹스나이퍼가 설치되어 실행된 화면 그림 >

위의 그림에서 (3)번 버튼이 보이지 않는다면, 메뉴의 "보기>도구모음>사용자 지정"을 선택하여
다음 그림처럼 설정하여 위 4번항을 다시 설정하시기 바랍니다.

< 메뉴에서 websniper가 보이지 않을 경우 설정 그림>

[웹스나이퍼 프로그램 제거하기]
제거판의 "프로그램 추가/제거"를 실행합니다.
프로그램 목록에서 WebSniper 선택하여 제거합니다.
주의! WindowsXP에서 완전히 제거되지 않는 경우가 있습니다. 이때는 로그오프 한 후 다시 로그인 하여 완전히 제거하십시요.

 

 

 

Posted by '김용환'
,

 

출처: http://www.javaservice.net/

 

제목 : [Comment] 다국어 인코딩 문제의 위치 및 까발리기
  글쓴이: EB(goEB)   2002/12/02 12:42:10  조회수:2182  줄수:289
======== 2002.12.03 23:12 공지 ========
이 글의 KSC5601-1992는 잘 못되었으므로 걸러서 읽어주시기 바랍니다.
이 글과 관련된 "2부"에서 설명합니다.
=======================================



제목 : [Comment] 다국어 인코딩 문제의 위치

많은 분들이 다국어 때문에 헤메이고 있습니다.
이에 대해 저의 짧은 지식이지만 공유할 까 해서 코멘트를 달아봤습니다...


글의 영양가는 뒷부분에 있습니다.
시간 없으신 분들 장문인 만큼 뒷부분을 읽어주십시오. 다만 문자셋의 기본은 --;;


이 글에선 DB는 부분은 범위밖이기 때문에 다루지 않을 것입니다.
사실 대부분의 문제는 DB외의 곳에서 발생할 것입니다.


저는, 엔코딩에서 제일 중요한 것을 아래와 같이 분류하였습니다.
1. 각 문자셋의 종류와 이해
2. 소스 파일의 엔코딩 형태
3. 컴파일된 파일의 엔코딩 형태
4. 컴파일된 파일을 사용하는 엔코딩 형태
5. UTF-8의 필요성 인식.
6. WebBrowser의 이상한 행동(?)

"new String(str.getBytes("8859_1"), "EUC_KR");"
와 같은 문제는 별개입니다. (문자셋의 종류와 이해가 우선이지요)


<
1번에서 주의해야 할 것은. Unicode와 Unicode(UTF-8)을 동일시 여겨셔는 안된다는 것입니다.
Unicode는 코드페이지 1200이며, Unicode(UTF-8)은 65001 입니다.
그 크기 또한 다릅니다. (하늘과 땅차이 -_-)

- Unicode와 Unicode(UTF-8)을 간단 정리
Unicode는 모든 문자를 2Byte로 표시한다. - ISO-2022형태의 다국어와 차이점.
(영문이고 다국어고 필요없다. 어떤 언어든 65536가지를 표현 가능하다.
이 뜻은 2Byte가 어떤 형태로 구성되는지를 알 수 있게 하는 말.)

UTF-8은 기존 ASCII 1xx까지 유지하며 다국어는 2, 3Byte로 표시한다.
(즉, 영문은 1Byte처리 - 아래에서 다시 설명하기 때문에 매우중요)
고로, UTF-8은 프로그래밍 언어에 사용하여도 손색이 없다.

☆다국어 - 여기서 필자 맘대로 재정의한 뜻으로 기존 2Byte이상을 필요하던 언어.
 (영어등도 포함해서 말한다고 딴지 걸지 말란 뜻에서;;;)
>


<
2번을 이해하지 못하였을 경우에는 이러한 문제들이 발생합니다.

가. 만약 소스가 JSP일 경우 파일을 Include할 때 A는 정상인데 B는 깨지거나
 하는 문제 발생. (혹은 그 반대)
 ※주의! <%@ page contentType="text/html;charset=xxx"%> 와는 별개이므로 소용 없습니다.
나. *.java를 컴파일 한뒤 다국어 사용시 깨어져 나온다. --;;
 (static이나 비교문등에 미리 입력해 놓은 다국어...)
 물론 Runtime시 복구할 수 있는 경우도 겠지만 그렇게 하는 사람 있다면 따돌림 당한다는.... --;;

해결법 :
가. 소스파일을 만들어 저장할 시에 자신이 작성한 소스의 문자셋을 확인한뒤
 그 와 동일하게 저장하도록 하고, 프로젝트에 관련된 모든 파일을 동일한 문자셋으로 작업해야 한다는...
 <%@ page contentType="text/html;charset=xxx"%>의 xxx에 자신이 작성한 문자셋을 동일하게 입력.
 만약 기존에 미리 만들어둔 소스가 있을 경우라면 밑에서 다시 언급하겠습니다.
나. 소사파일을 만들어 저장할 시에 자신이 작성한 소스의 문자셋을 확인한뒤
 그 에 따라 컴파일 할 수 있도록 한다.
>


<
3, 4번의 경우는 현재로써는 가정이다. (혹은 사실 - 물론 내 자신은 아직 접한적은 없다.)

컴파일된 파일이 JVM에 의하여 로딩되는 과정과 Runtime의 과정에서 엔코딩이 서로다른 형태의
Class를 불러 들였다면? 그렇다면 이중 entrypoint가 있는 클래스가 디코딩의 기준이
되는 것일까? 그렇다면 entrypoint외의 타 클래스에서 사용된 다국어는 모두 깨어질 것이다.
아니라면 클래스간 호출시 JVM은 그 에 따른 처리를 해야한다. (느려진다.)

물론 현재의 JVM은 일반적으로 모든 소스를 Unicode 혹은 UTF-8로 불러들일 테지만 아닐 경우는
어찌 해야 할 까? (컴파일된 파일의 원본의 형태가 뭐건 Unicode 혹은 UTF-8로 변형)

이렇게 3, 4번을 넘기자 --;;
>


<
5는 2번의 경우만으로도 UTF-8의 필요성을 느끼지 않을 수 없겠습니다.

번거롭게 경우에 따라 소스를 다시 원하는 형태로 엔코딩하여 만들어야 한다는 것은
Tool과의 노가다를 감행해야한다는 것인데 말이죠.
그러므로 할 일 많(-_-)은 프로그래머로써는 UTF-8을 사용해야 한다는...

또한, UTF-8의 정렬속도 쥑입니다. --b (Unicode와의 비교를 제외한다면.)
한글이 모두 순차배열되어 있기 때문입니다. :)
그에 비해KSC5601(KSC5601-1992)는 정렬속도는 떨어진다는... (공포의 8822자)
>


<
 Application에서 프로그램 소스등(*.JSP, *.JAVA, *.TXT)의 엔코드 타입을 자동으로 인식!?!
결론은 자동 인식 가능한 문자셋이 있기도 없기도 입니다.
일반적으로 2Byte로 된 문자셋은 인식이 불가능 하지만 Unicode는 가능 합니다.
첫 시작을 16진수로 FF FE로 시작하는 문서는 Unicode를 알리는 문서입니다.
또한 Unicode(UTF-8)은 서명있는 Unicode(UTF-8) 문서일 경우는 대부분 가능합니다.
없는 경우는 가능한 툴이 있기도 하고요. (말이 자동이기 거의 강제 --)
만약 서명이 있는 경우라면 EF BB BF로 시작합니다.
이에 따라 각종 Tool에서 자동으로 읽을 수 있는 것입니다.
>



소스의 문자셋을 변경사용하기...

일반적으로 프로젝트의 모든 소스는 엔코딩 형식이 동일해야 하겠죠?
만일 기존 소스가 있는데 다르다면 현 프로젝트와 맞추어야 할 텐데...
쉽게 구할 수 있는 툴은 UltraEdit가 정도가 되겠네요 저는 v9.10을 가지고 있고
File -> Conversions에 있습니다. 이 곳에서 원하는 형태로 가능하겠습니다.

-단, 한글들의 문자셋변환 툴은 아직 보질 못했음. 혹시 보신분 손 ^^/
 한글에서 하위변환은 완벽히 안되므로 이를 염두해야함.



JSP에서 <%@ page contentType="text/html;charset=xxx"%>와
META TAG의 contentType="text/html;charset=xxx"

이둘을 사실상 모두 사용하는 경우는 웃지 못할 일입니다.
(실로 대단한 이슈입니다.)

이곳 게시물중
----------------------------------------------------------------------------------
==게시물 1========================================================================
euc-kr 이나 ksc5601 을 사용할 경우 브라우저의 한글은 잘 나온다.

대신 확장한글을 표시할 수 없어서 샾 , 햏 , 잌 같은 글자는 ? 로 깨어져 나온다.

소스보기를 해도 완전히 깨진다.
...
...
중략
...
서버쪽 한글처리는 MS949 로 정하고, 브라우저의 한글처리는 ksc5601, euc-kr 등으로
한다. 즉 서버쪽은 @page 의 contentType 속성을 charset=MS949 로 <head> 태그 내의
<meta> 태그에서 Content-type 의 값을 charset=ksc5601 로 주면 브라우저쪽의
한글처리를 마무리지을 수 있다.
==게시물 2========================================================================
NOTE: '잌'과 같은 확장한글의 경우는 추가적인 테스트가 필요합니다.
   추정컨데, 
   1) MS949(Cp949)를 DB(Oracle,DB2,..)가 지원하는가? 
   2) JVM file.encoding MS949->Cp949 에서 정상적인 동작을 하는가?
   3) default.client.encoding/client.encoding.override MS949->Cp949 에서 정상적인
    동작을 하는가? 
   4) 위 팁문서처럼 META tag에서 KSC5601을 반드시 써 주어야 하는가?
==게시물 3========================================================================
Windows에서의 JVM의 한글디폴트 인코딩 캐릭터셋 문자열은 "EUC_KR" 입니다.
Linux에선 "KSC5601"이라 나오는 군요.

그러나 "EUC_KR", "KSC5601", "EUC-KR"은 모두 동일합니다.
==================================================================================
----------------------------------------------------------------------------------
이런 내용이 있었습니다.

MS949는 엄밀히 "KSC5601-1987" 입니다. 또한 "KSC5601-1992" 입니다.
KSC5601이들의 차이점은 1992는 1987를 모두 포함하고 문자의 위치까지 호환이 되며
1987에 추가된 문자 8822(공포의)개가 있다는 것 뿐입니다.
(현재 MS OS에서는 단순한 폰트차이로 봐도 무방)
그러므로 일반적으로 KSC5601라고 통합하여 사용하는 것입니다.
(엄밀히 MS949는 META TAG에서 windows-949 혹은 ks_c_5601-1987 에 해당합니다.)

그러니 위에 언급된 게시물에 있는 MS949관련 사건들은 무효-_-가 아닐까요?

무슨 의미인고 하니 EUC-KR(Extended Unix Code-Korean)에서는 잌이 깨지지만 KSC5601은 깨지지 않습니다.
쓩, 잌, 퓩, 끁, 덁을 비교해보면 EUC-KR은 쓩만을 표현할 뿐 입니다.
KSC5601-1992는 확장을 표함합니다. (물론 UTF-8과는 비교할 것이 못되지만...)
하지만 EUC-KR은 확장을 포함하지 않습니다.
(위의 게시물 3은 2000/05/28일자로 오래되었기에
그 시절 KSC5601 = EUC-KR 라고 한 표현한 것은 그다지 문제 삼을필요는 없는듯 --;;
다만 저 게시물을 보고 아직 맞다고 생각하시는 분들을 위하여 언급하였음.)


어쨌든 어떠한 환경이던 WebBrowser간엔 어떤 문자셋이건 쌍통합니다.
(이점이 중요합니다. 왜 깨어져야할 확장 글씨가 정상 표시되는지를 이제 설명합니다.
-MS Win XP에서 IE 6.0과 Nescape Navigator 7.0을 테스트 해봄. Linux, Unix에서 안해봄)

제가 위에서 언급한 확장글씨가 왜 이곳 게시판이 EUC-KR임에도 불구하고 깨지지 않고 정상으로 보일까요?


WebBrowser는(어쩌면 OS레벨) HTML 소스의 문자셋이 뭐건 Unicode (단, UTF-8 문자셋은 제외)로 변환시킵니다.
그리고 화면에 출력합니다. 이 때 필드(INPUT TAG, TEXTAREA TAG등)에 입력한 값 역시
당연 Unicode(UTF-8인지는 정확히 확인하지 않았음. 하지만 UTF-8문자셋은 그대로 UTF-8) 데이터 입니다.
(눈으로는 구분 못하죠.)
그래서 입력할 당시에는 모든 문자를 입력할 수가 있는 것입니다.
허나 값을 서버로 보내면 HTTP Header (혹은 META TAG)에 정의된 문자셋으로 컨버팅 합니다.
(Server로 전송되는 TCP/IP 데이터를 보면 증명 가능)
이 때 컨버팅 불가능한 문자는 &# + Unicode값 으로 변경됩니다. 그렇게 서버로 날라가는 것입니다.
(이 값만으로도 알 수 있겠지만 EUC-KR은 KSC5601에 비해 확장한글이 부족하단것을 알 수 있습니다.)

만약 서버에 날라간 엔코딩 타입이 KSC5601이였지만 깨지는 문자가 있었다면, 그 깨지는 문자는
&# + Unicode 형태로 계속 보존되게 되는 것입니다. DB에 역시 그렇게 입력됩니다.
그렇다고 한다면 눈치빠른 분들은 벌써 한가지 이상의 문제를 지적하실 것입니다.

첫째. &# + Unicode 로 표현된 문자는 특수처리를 하지 않는다면 영원히 그렇게 되어 있다는 것을...
(많은 문자셋을 보시면 알겠지만 ACSII는 유지되기 때문입니다.)
고로, WebBrowser 이외의 곳에서는 문제가 --;;
-이 때문에 DB에서 검색할 경우에 문제가 있다.

둘째. 기존 &# + Unicode를 추후 Unicode, UTF-8등에 마이그레이션 할 때 따로 작업 해야 할 것입니다.
(제가 아직 자동변경해주는 툴은 못 봤습니다. --;;
뭐 그리 어려운건 아니지만 양이 크면 큰일인 것 만은 확실합니다.)

셋째. DB의 필드의 길이가 개발자가 원했던 길이를 벗어날 수도 있는 문제.
&# + Unicode는 최대 7자의 길이를 가집니다. (MAX : &#65536) 그럼 EUC-KR이나 KSC5601로 DB용량 아끼려다
필드깨지고 필드길이 제한 없으면 오히려 Unicode혹은 UTF-8보다 용량만 증가하고 --;;

넷째. 간혹 게시물등 내용을 보면 &# + Unicode값이 그 대로 보이는 경우가 있습니다.
이유는 제가 일전에 올린 게시물 내용에도 언급했듯 & 을 &amp;로 변형하였기 때문입니다.
즉, &amp;를 &로 원래대로 놓으면 첨에 입력했을 당시의 문자가 보이는 것입니다.

다섯째. 어쩌면 MS외의 OS환경은 그 문자를 표현할 방법은 특수처리를 하지 않는 이상
현재로써는 없을 수도 있습니다. (제가 Linux, Unix에선 안해본지라 --;;)

참고.
'葶' <- 이 문자는 Unicode와 UTF-8문자셋이 아니면 깨집니다.
WebBrowser에서 보는 데는 지장 없습니다. 지금도 보이시죠?
이 '葶'는 서버에 전달 될 때 &#33910; 이렇게 변형되어 전달 됩니다.
(지금 이 게시판에서 WebBrowser의 소스보기를 해도 알 수 있습니다.)




정리하자면
1. 정말이지 UTF-8은 꼭 필요하며 (한글만 사용한다 할 지라도) 필요한 시기는 지금입니다.
2. MS949 와 KSC5601은 같으니 위에서 언급한 MS949사건(?)은 정확성을 위해
 여러 환경에서 (JAVA의 각 버젼별 등등) 재 테스팅이 필요할 것으로 사료됩니다.
 - 실제 제가 MS949로 서버에서 처리라는 곳에 가서 HTTP프로토콜로 전송되는 값을 확인한 결과
 KSC5601과의 차이를 못 봤습니다.
 Servlet, JSP, HTML페이지 = ksc5601로 해서 다시 한번 테스트 해보셨으면 함.
3. WebBrowser가 버젼과 OS별로 어떠한 형태로 서버에 값을 전달하는지 정확히 알아야 합니다.
 또한 이 때문에 JSP등 WebBrowser와 통신하는 처리는 DB의 특성을 안탄다고 봐도 무방.
 (대부분 DB의 엔코딩을 EUC-KR, KSC5601로 하고 프로그램 역시 그렇게 짜기에)
4. JAVA에서 EUC-KR을 사용하실 거라면 KSC5601을 추천합니다.
 (단, 정렬시 속도저하 혹은 엉뚱한 순서 우려)
5. EUC-KR과 KSC5601의 상호변환을 허용하지 말자. (특히 KSC5601-1992에 문제가 있음)


※ 문자는 bits와 Font의 장난이란걸 잊지 마세요. 
(Font의 장난에 특별히 주의하십시오.
bits값은 정상인데 OS따라 표시되지 않는 경우도 있고 Tools에 따라 표시되지 않는 경우도...
그러므로 문제가 되는 곳에서는 항상 bits값을 확인하는 습관을...)



지금껏 정리가 안되었다면 안된 장문 읽어주신것 감사드립니다.
잘못된점 있으면 지적하여 주시구요

건승하십시오.


==================================================================================
이 글은 EmotionalBrain이 작성하였으며 처음 게시된 곳은 www.javaservice.net 입니다.

이 글을 어디에 사용하든 작성자와 원 출처는 지울 수 없습니다.

2002.12.01
==================================================================================





P.S
위에 "게시물 1" 에서 언급된 내용을 잠깐 말하자면
JSP에서 <%@ page contentType="text/html;charset=XXX"%> 라고하면 아시겠지만
XXX가 META TAG보다 HTTP Header에 Context-Type이 먼저 날라갑니다.
이 때 JSP에서 MS949라고 하면 HTTP Header에서도 MS949라 날라가는데 WebBrowser에 그런게
없다는 걸 감안하면 JAVA의 황당함이 --;;
MS949는 엄밀히 말하면 META TAG에서 "windows-949" 혹은 "ks_c_5601-1987" 에 해당하는데
그대로 "MS949"가 -_-;;
그덕에 META TAG에 따로 windows-949나 "ks_c_5601-1987"를 무조건 넣어야 한다는...
어찌됐건 MS949는 KSC5601이기 때문에 KSC5601로만 모두 처리하면 MS949는 필요 없습니다.


P.S 2
이거 작성할라구 이것과 관련된 윈도우 창만 지금 30개가 떠 있네요 --;;
무려 5시간 허비 --;; (확실하게 쓰려구 많은 노력을 했기에...)
Navigator두 MS OS에 첨 깔아보고 --;;
(근데 제 컴이 빨라서인지 Navigator가 예전에 비해 실행속도 무지 빨라졌네요!)
제목 : Re: encoding 관련 url
  글쓴이: 허광남(heogn)   2002/12/04 01:42:33  조회수:478  줄수:36
게시물1 의 저자입니다. 
EB 님의 명성은 익히 보아온 바라 제 글을 토대로 연구결과를 공유해주셔서 감사드립니다.
(사실 좀 뜨끔했습니다. ^^;)
MS949 는 CP949 와 같다는 것
iana 에는 빠져있는 문자셋이며 윈도우즈와 java 진영에서 공유하는 OS 기반의 문자셋
라는 것
제가 이해하고 있는 것이었고, EB님의 글처럼 한글의 한계상황을 넘어가는데는 UTF-8 
문자셋을 해야된다는 것에 공감합니다.

Hangul and Internet in Korea FAQ 신정식님 8번글 참고
http://jshin.net/faq/index.html

iana 에 등록된 문자셋에 관한 링크
http://www.iana.org/assignments/character-sets

cp949 의 unicode mapping table
http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT

Extended Encoding Set (contained in i18n.jar)
http://www.mobilejava.co.kr/bbs/temp/lecture/personal/encoding.html

윤경구님과 김필호님의 Cp949 에 관한 글
http://java.freehosting.co.kr/java/messages/1297.html

사실 아직 정리가 완전히 안된 상태입니다.
EB님의 글을 저 또한 참고하고 두가지 인코딩을 표시해야되는 우스꽝스런 jsp 
코딩스타일을 빨리 벗어나야겠습니다.(^^; 언제가 될지는 저도... )

행복하세요.
---------------------------------
jakarta-seoul project 
jakarta 문서 한글화 사이트
http://www.apache-korea.org

---------------------------------
http://okjsp.pe.kr
제목 : [Comment] 다국어 인코딩 문제 2부 - 2002.12.04 13:20
  글쓴이: EB(goEB)   2002/12/04 12:28:11  조회수:1132  줄수:269
제목 : [Comment] 다국어 인코딩 문제 까발리기 2부

먼저, 첫글을 작성시 짧은 시간에 많은 것을 하려다 보니 본의아니게 큰 실 수를 저질렀다는 것
사과드립니다. (이런 실수는 해서는 안돼는데... 쩝)

대신 이 글에서 만회합니다. ^^;;

뿌리가 흔들리는 부분입니다. (쿠..쿨럭)
KSC5601-1992 는 KSC5601-1987 과 혼환 안된다고 보셔두 무방합니다. --;;
제가 가지고 있는 자료를 제가 잘 못 본 탓입니다... (변명이란 이런것 --;;)
완성형과 조합형의 차이는 아실겁니다.
KSC5601-1987는 KS완성형이라고도 합니다. KSC5601-1992 는 표준(상용이 아님) 조합형입니다.

헉헉 --;;

제가 저 부분 하나를 잘 못 읽었습니다;;;
그러한 이유로 뿌리가 안 흔들릴 수 없습니다.


KSC5601 = ks_c_5601-1987 = MS949 입니다.


KSC5601-1987는 확장이 아니라 제가 말씀드렸습니다. - 잌 등의 문자.

그럼 확장을 포함하는 것은 무엇일까요?
(기존엔 저의 글에서 KSC5601-1992라는 짜가가 이를 대신 했었습니다만... --;;)



제가 MS949 = KSC5601 = KSC5601 + 확장한글 이라고(확장이 KSC5601의 배열과 100% 호환) 하였는데 그렇다면?
(KSC5601 = KSC5061 + 확장한글이라는 정보는 예전 1998.11년 에도 마이크로 소프트웨어 잡지에 실렸음.
이 내용을 틀렸을 것이라 생각하지 않음. 이유는 테스트과정에서 밝혀낼 것. - 첨부자료참고)

바로 MS949 이였습니다.

제가 첨 게시물을 올리기 전에 어떤 아이러니한 점이 있었는데 그게 JAVA의 버그인줄만 알았으나
KSC5601-1992와 MS949가 별개라른 점을 알자 드디어 원인을 알게 되었습니다.
(또한 그당시 KSC5601-1992 도 문제가 있다고 봤습니다. -_ㅜ)

먼저 MS949으로 JAVA소스에 확장을 포함하여 작성하고 JAVAC -ENCODING옵션을 KSC5601로 하면
소스작성시 넣은 확장 한글이 깨지지 않습니다.

하지만 MS949의 확장한글을 Runtime환경에서 KSC5601로 하면 확장한글이 깨집니다.
(KSC5601로 변환할 때 변환기에서 확장한글영역은 ?로 바꾼다는 얘기)

즉, KSC5601 <> MS949는 호환이 되지만 안돼는 것입니다.

풀어서 말하면 MS949를 KSC5601으로 변경시에 MS949디코더기는 정확히 풀었으나 KSC5601엔코더기는
KSC5601표준정의에 의하여 MS949의 확장영역을 처리할 필요가 없어도 KSC5601의
디코더/엔코더가 정상 인증이 된다는 것입니다.
그러므로 표준정의에 의한 KSC5601밖의 DBCS영역은 ?로 처리해도 문제가 없는 것이 되겠습니다.
(KSC5601이 MS949의 확장영역을 ?로 변경하지 않으면 완존 MS949 De/Endcoder 라는 것입니다. -_-;;
이러한 경우가 실무에 존재하는데 그 예는 모르는 사람이 없을 정도로 유명한
JSP에서의 @Page와 HTML의 META에 각기 다르게 적용하는 경우와 제가 위에서 방금말한
JAVA소스는 MS949로 JAVA -ENCODING 은 KSC5601로 주었을 경우가 되겠습니다.
- 이곳에서 MS949가 확장을 포함하는 장본인이라는게 또 다시 증명되네요 --;;)

※ 참고. 확장완성형은 MS 독단으로 만든것입니다. - MS에게만 표준 = 국민의 표준 -_-;;


정리하자면 그리하여 JAVA에서 KSC5601외에 MS949를 따로 보유하고 있는 것이 되겠습니다.





많은 분들이 MS949 = CP949로 알고 있습니다. 여기서 CP는 CodePage를 말합니다.

하지만... 과연 그럴까요? 한번 까발려 보도록 하겠습니다.

---------------------------
첨부 소스 설명...

-첨부파일의 Class는 ISO8859-1 로 Encoding하여 컴파일 하였음.-

어떤한 OS이건 어떤한 형태로 Compile하건 특성을 없애기 위하여
한글은 Bytes(Source 변수에 해당)로 입력하였습니다.

그러므로 100% JAVA의 Runtime환경의 특성만을 탑니다.

입력된 한글의 내용은
가잌덁
이렇게 MS949를 기반으로한 Byte값 3글자입니다.

테스팅시 주의 사항은 문자를 출력할 때 OS에 따라 한글의 표현이 안될터이니
반드시 Byte[] 값을 확인해 보시기 바랍니다. Byte[] 값이야 말로 어떠한 상황이든
JAVA에서 처리한 처리 결과를 정확히 확인할 수 있기 때문입니다.


아래, 제가 테스팅한 결과를 올려보겠습니다. (JDK v1.3.1

============================================================
System.getProperty      : MS949

Source Output...
Source                  : -80, -95, -97, -27, -120, -28

String Output...
strMS949                : 가잌덁
strCP949                :
strCP949fix             : 가쌧
strKSC5601              : 가??
strKSC56011992          : 쌰?걳
strEUCKR                : 가??

Byte[] Output...
byteMS949               : -80, -95, -97, -27, -120, -28
byteCP949               :
byteCP949fix            : -80, -95, -101, 81
byteKSC5601             : -80, -95, 63, 63
byteKSC56011992         : -101, 88, 63, -127, -102
byteEUCKR               : -80, -95, 63, 63
============================================================

위의 값을 보시면 여지껏 제가 말씀드렸던 것들이 무엇인지 결과를 보고난뒤니 감이 잘 올 것입니다.

※ 보는 방법
- Source 변수 : 원본 데이터 이며 OS의 (Encoding문제) 특성을 없애기 위하여
 Byte[]로 구성되었다.
- strXXX 변수 : Source를 기준으로 각 문자셋으로 변환하여 화면에 출력해본다.
- byteXXX 변수 : strXXX로는 OS에 따라 보이는 문자가 있고 없고 하므로 정확성을 위하여
 strXXX를 Byte[] 로 변환하여 출력한 결과이다.
 이 값이 만약 저의 결과와 다르다면 제 시스템 혹은 결과가 다른 시스템 혹은 둘다 이상있는 겁니다. -_-;;
 (OS가 아닌 JAVA만 이상있다.)
- CP949와 CP949fix의 차이점은 CP949는 Source의 3글자를 표현하도록 했던 것이고
 CP949fix는 2글자까지만 표현하도록 했던 것의 차이입니다.
 이유는 제 시스템에선 3글자를 전혀 출력하지 못했기 때문입니다.
 (Byte[]가 안나왔으므로 엔코딩/디코딩 자체 문제.)
- Byte에서의 숫자 '63' 은 문자 '?'에 해당하는 것으로써 OS의 폰트문제로 글씨가 깨지는 것이 아닌
 엔코딩/디코딩 자체에서 처리할 수 없다는 뜻입니다.

※ 위의 Byte 코드에서 63이라고 나온 곳이 제일 중요한 곳이 되겠습니다.
63은 압축으로 비유하자면 손실 압축기법입니다.
무슨 뜻인고 하니 63이 아닌 다른 값들로 변환되었다면 실제 그 문자셋을 표현해주는 시스템
(위에서 저는 MS949였기 때문에 MS949만 모두 정상처리 된 것 입니다.)
에서는 글씨가 정상으로 출력된다는 얘기입니다.
(또한, 원래 문자셋으로 복원해도 정상으로 된다는 얘깁니다.)
위의 "byteKSC56011992" 결과를 본다면 그 시스템에서(표준 조합형)는 "기?덁"으로 보이는 것입니다.
그러니 문자셋 상호변환시 63으로 되는 곳이 있다면 그들간 변환은 절대 금물~!

위의 결과를 보시면 아시겠지만 JAVA에서는 MS949와 CP949는 100% 호환되지 못합니다.

그러므로 많은 분들이 알고계신 MS949 = CP949는 JAVA에선 딴 얘기로 통합니다. --;;





정리하면

가. 여전히 JAVA에서 EUC-KR(KS_C_5861-1992)은 사용하지 말아야할 존재 입니다.
- 메일 때문에 사용해야한 다면 차라리 KSC5601-1987과 ISO-2022-KR을 이용하여 처리하십시오.
 오직 MS949때문입니다. - Client가 MS환경이 많으니...
(얄미운 MS지만 UTF-8정의할 때 우리나라가 세계에서 두번째로 많은 코드를 사용할 수 있게 해주었습니다.)

나. Oracle에서 KO16KSC5601를 사용할 때 KSC5601 디코딩/엔코딩이 MS949를 무시 하는지 확인해야 할 것입니다.
 또한, KO16KSC5601이 EUC-KR을 100% 지원해주는가 의문이 들지 않을 수 없습니다.
 적어도 KSC5601에 MS949의 확장문자가 포함되었을 경우에
 EUC-KR로 컨버팅하여보면 특정문자가 깨지기 때문입니다.
 - Oracle에서도 Unicode 있지 않나요? (UTF-8 말고) 그럼 그거 쓰면 될텐데 --;;
   (UTF-8 쓰기 싫은 사람들에겐... 혹은 UTF-8사용하면 안되는 이들에겐 - 이런 경우가 있다;;)

다. Client가 WebBrowser이고 문서의 문자셋이 Unicode, UTF-8이 아닐경우
 WebBrowser가(어쩌면 OS레벨) HTTP header나 HTML의 META에 정의된 문자셋이 지원하지 않는
 문자가 있을 경우 이를 자동으로 &# + Unicode(Int16)로 변경한다는 것에 주의하셔야 하며
 이에 따른 문제는
 1. WebBrowser외의 곳에서는 한글 변환이 어려우며 100% 처리하기 위해서는 Unicode나 UTF-8를 이용하여
    직접제작한 처리기를 통해야만 표현할 수 있다.
 2. &# + Unicode로 입력된 내용을 검색시 부작용이 많이 있다.
    (이곳두 제가 '덁' 이라고 입력한거 검색 안됨... 제가 이곳 소스를 보진 않았지만
    모두 EUC-KR루 처리했으니 서버에 항상 &# + Unicode로 갔을 것이고 검색어 역시
    그렇게 처리되어 쿼리를 날릴 텐데두 안되는거 보면 이곳 소스한번 보구잡따. --;;
    더욱 재밌는 것은 파일명을 '덁'으루 하면 EUC-KR인 이곳에서 본문은 &# + Unicode로 가지만
    파일명은 제대로 간다. --;; 역쉬 %xx 로 전달되는게 짱이얌 -0-;; %xx 형태 원츄 --b
    - JAVA에서 직접 EUC-KR 스트링의 Byte를 편집할 수 있다면 이것이 쉽게 가능하게 한다.
     문제는 Byte를 편집하였기 때문에 표준에 어긋나는 일이라는거 --;; 그래서 무효 --;;
     또한, 눈에 보이는 '덁'이 실제 '덁'이 아닌 OS가 꺼벙해서 보이는 경우 있다. - 어렵지만 중요한 말)

라. Red Hat Linux 7.1 에서 UTF-8.
 - RedHat Linux v7.1 한글판 OS에서 (WebBrowser는 Navigator v7 한글판) '잌'
   등의 문자는 '이ㅋ' 이렇게 표현되었었다. --;;
   확장문자 입력은 아예 되지도 않는다. --;;
   Linux에서 JAVA코딩시 이들을 주의하자. (또한 실제적으로 정상인데 Font문제로 표시되지
   않을 수 있으므로 Byte값을 확인하자. 특히 Linux에서 "아햏햏"이 출력되지 않는 다고 하신분 -_-+
 - UTF-8관련 자료
    영문
    (인증문제가 걸린다면 상위디렉토리부터 접근해본다. --;;)
    한글

마. MS OS에서 Win NT 2000부터는 파일 시스템의 기본이 UTF-8이지만 Win98은 잘 모르겠다.
 이 것을 언급한 이유는 제가 올린 "UTF-8로 URL 요청할 시 한글 처리 가능케" 바꾸는 게시물에 올린
 *.htc의 소스를 보면 URL이 "file:///"이면 KSC5601(MS949)로 바꾸지 말라는 부분이 있는데 이 때문이다.

바. JAVAC -ENCODING   옵션을 잊지 말자. (이거 아직도 모르고 계시는 분이 있다는 -_-+)
 이 때, -ENCODING은 소스파일과 동일하게 해주어야 한답니다. ^^
 JSP에서는 @PAGE contentType의 charset 셋이 이 역할을 합니다.
 (또한, Application, Session Scope를 지닌 변수에도 적용됨, 그러므로 프로젝트의 모든
  ENCODING타입이 같아야 득이됨.)
 "JAVA -Dfile.encoding=" 이 옵션은 기본으로 통한다. ㅡㅡ;;

사. JSP에서 @PAGE 를 사용할 시 반드시 INCLUDE되는 파일이 아닌 불러들인 파일에 넣어주어야 한다.

아. MS949와 CP949는 다르다. (적어도 JAVA에선 다르다.)

자. JSP에서 MS949를 HTTP header로 보낼 땐 "KS_C_5601-1987" 로 보내게 만들어 달라구 항의 하자;;;
 아니면 우리 프로그래머가 그렇게 되도록 직접 뜯어 고치자;;



결론, 테스트고 모고 귀찮으니 그냥 UTF-8 사용하자 -0-;;



그럼 즐프~~~



p.s 글이 너무 길어 더는 못 쓰겠습니다. --;;
또한 글만 길었지 여러분께 많이 도움이 되는지도 모르겠음. ㅠㅠ (쿠..쿨럭;;)


첫 글에서 KSC5601-1992 를 잘 못 말씀드린것 다시한번 죄송합니다.



이 글에 도움을 주신분.
1. 허광남(heogn)
2. 기타 인터넷 사이트에서 참고자료 제공자...
끝 --;;


============================================================
작성자 : EmotionalBrain
처음 게시된 곳 : www.JavaService.net
============================================================






Update 2002.12.04 13:20

위에서
--------------
먼저 MS949으로 JAVA소스에 확장을 포함하여 작성하고 JAVAC -ENCODING옵션을 KSC5601로 하면
소스작성시 넣은 확장 한글이 깨지지 않습니다.

...
...

JAVA소스는 MS949로 JAVA -ENCODING 은 KSC5601로 주었을 경우가 되겠습니다.
--------------

은 제가 그 당시 만들었던 소스가 없어서 그걸 다시 테스팅 할 수 없지만 "심민우(smwpower)"
님 말씀대로 첨부된 소스로 재 테스팅 해보니 제 테스팅이 잘 못 되었던것 같습니다.

그럼 -encoding을 KSC5601로 하고 String(KSC5601) Byte[]를 편집해서 만들어 놓거나
컴파일된 Class파일에 확장문자를 찾아서 Byte[]를 변경하면 되겠습니다.
- 목적은 KSC5601에 Byte를 수정해서 확장을 넣는 것입니다. -




Update 2002.12.06 19:29
--------------------------

위의 업데이트 사항에서 EUC_KR 상태의 문자를 Byte(CharCode)가 편집된 경우는
3번째 [Comment]에서의 JSP와 DB "EUC_KR"에 관련된 내용에서도 있습니다. ^^;;

Download TTT.java (2331 Bytes) TTT.java (2331 Bytes)
Download TTT.class (2074 Bytes) TTT.class (2074 Bytes)
제목 : Re: mizi linux 에서의 한글
  글쓴이: 허광남(heogn)   2002/12/04 15:05:12  조회수:196  줄수:33
EB 님의 글 잘 읽었습니다. 
재밌는 글이 있어서 퍼옵니다. 
--------------------------------------------------------
1 cp949 또는 uhc(unified hangul code 통합완성형)
1995년 윈도95의 등장과 함께 나타났다.
처음에는 각계각층의 반대에 의해 입력만 막아놨지만 윈도98부터는 자연스럽게 포함이
되면서 일반적으로 쓰이는 글자셋이 되어버렸다.
이전부터 쓰이던 euc-kr이나 완성형에서 쓰이지 못했던 글자들을 마음대로 입/출력 할
수 있게 된것은 환영할 만한 일이나 다른 운영체제나 환경을 전혀 고려하지 않은
것이라 문제의 소지가 컸다.
지금 모질라에서는 euc-kr 글자셋 환경이라도 uhc글자를 읽을 수 있게 바뀌어졌다.
(지금 uhc가 컴퓨터바닥에서 얼마나 큰 영향을 끼치는지 알 수 있는 하나의 예라 할
수 있다)

2 MiziLinux에서 cp949 또는 uhc에 대한 대비
제일 근본적으로 처리할 수 있는 것은 유니코드 글자셋이라 볼 수 있을것이다. See
ko_KR.UTF-8 ( http://linux.mizi.com/wim/ko_5fKR_2eUTF_2d8 )
하지만 우리가 할 일이 너무 많아진다.
glibc의 gconv(iconv)에서도 cp949가 지원이 된다.
전에 농담조로 나온 말이지만 ko_KR.cp949라는 새로운 로케일을 만드는 것도 그럴듯
만한 대안이 될 수 있을것이다.
리눅스환경에서 한글입력기의 표준이다시피 한 아미는 아직 euc-kr밖에 지원을 하지
않는다.
from:
http://linux.mizi.com/wim/_ed_95_9c_ea_b8_80_ed_99_98_ea_b2_bd

---------------------------------
jakarta-seoul project 
jakarta 문서 한글화 사이트
http://www.apache-korea.org

---------------------------------
http://okjsp.pe.kr
제목 : Re: EB(goEB)님에 대한 테스트중 이상한점..
  글쓴이: 심민우(smwpower)   2002/12/05 00:42:16  조회수:197  줄수:60
주신 소스를 가지고 
javac TTT.java 와
javac -encoding ksc5601 TTT.java
로 컴파일 했을 경우 이상이 없었읍니돠..

그런대..
byte[] Source = new byte[] {-80, -95, -97, -27, -120, -28}; 을
byte[] Source = "가잌덁".getBytes(); 로 수정하거나..

strMS949		=	new String(Source,"MS949"); 을
strMS949		=	new String("가잌덁".getBytes(),"MS949"); 로
수정해서 테스트 할땐..

javac TTT.java로 컴파일 하면 출력결과에 이상이 없었읍니돠.

그런대
javac -encoding ksc5601 TTT.java 로 하면
출력결과가 아래와 같읍니돠..

System.getProperty      : MS949

Source Output...
Source                  : -80, -95, 63, 63

String Output...
strMS949                : 가??
strCP949                : 가??
strCP949fix             : 가쌧
strKSC5601              : 가??
strKSC56011992          : 쌰??
strEUCKR                : 가??

Byte[] Output...
byteMS949               : -80, -95, 63, 63
byteCP949               : -80, -95, 63, 63
byteCP949fix            : -80, -95, -101, 81
byteKSC5601             : -80, -95, 63, 63
byteKSC56011992         : -101, 88, 63, 63
byteEUCKR               : -80, -95, 63, 63

또한 
javac -encoding MS949 TTT.java 로 컴파일 하면
이상이 없읍니돠..

설명중 
/******
먼저 MS949으로 JAVA소스에 확장을 포함하여 작성하고 JAVAC -ENCODING옵션을 KSC5601로 하면
소스작성시 넣은 확장 한글이 깨지지 않습니다
********/
이부분이 바뀌지 않았나 싶어서여..
아님 제가 잘못 했나 싶기도 하구여...

참고로 UTF-8은 코드상에서 어떻게 구현 되남여?
혹  strUTF	 = new String(Source, "UTF-8"); 이렇게 하는 게 맞나여?





제목 : Re: Win95와 Win98에서의 문자셋
  글쓴이: EB(goEB)   2002/12/05 03:13:07  조회수:222  줄수:48
"허광남(heogn)" 님께...

제가 아는 정보는 Win95는 MS949가 맞지만(확장통합완성형), Win98은 Unicode 인데요
(KSC5700 표준 한글코드)

그리고 그 때문에 대부분의 글씨가 입력가능한 건데, (아시겠지만 확장통합완성형은
글씨 입력 시스템 제작시 두려움을 안겨줍니다. - 순서 엉망. 그래서 리눅스에서
EUC-KR말고 확장통합완성은 입력기를 만들기 어렵기에 아직 없음)

단지 확장문자는 원시스템인 Unicode에서 MS949(KSC5601)의 확장 영역에 넣어서
표현해줄 수 있는 것이기 때문에 Win98이 MS949인 것 처럼 보일 뿐이지요.

- 여기서 중요한 점은 한글만으로는 Unicode와 MS949의 비교가 안된다는 것입니다.
왜냐면 양쪽모두 한글 "11172"자를 지원하기 때문이죠.
그러므로 한글외의 것으로 비교를 해야 합니다.

MS949는 완전 Unicode안에 포함됩니다. 그래서 제가 Oracle에서 Unicode를
권장하였습니다. Oracle이 Unicode일 때 JAVA에서는 MS949라면 제한 문자가 MS949이기
때문에 사용시 전혀 지장이 없기 때문입니다.

그리고 MS에서 처리하는 방식이 표준에 의거한 것인지 (OS 버젼에 따라.)

또한 JAVA에서의 MS949와 CP949는 현재 차이를 보이는데 그 원인은?

MS측에서도 MS949와 CP949는 다릅니다... ...

CP949는 MS IDE 툴에서는 기본적으로 KS_C_5601-1987로 처리되게 되어 있더군요.
MS949와 CP949를 표준에 정의된 대로인지 문자셋 전체를 까봐야 할 것입니다.
(겉으로 확인할 수 없는 이유는 MS949가 CP949와 다르다 하더라도
CP949가 MS949시스템에서 같은 코드만 같구 있으면 정상인것 처럼 보이기 때문이죠.
그래서 많은 CP949의 디코더, 엔코더를 검증해야하며 관련 자료를 찾아
어떤 것이 진실인지 밝혀야 합니다.)


- 실제 차이가 있다면 Linux등의 시스템에서 MS949도 지원해주었으면 하네요...
그래야 지금 사용할 JAVA에서 MS949가 계속 문제 없이 돌아가죠 --;;


==================================================================================
"심민우(smwpower)" 님께...

o.O?

정말 그러네요? JAVAC 에서 엔코딩을 정상 처리는 군요! 그 당시 제가 테스팅 했던
파일을 지웠는데 (넘 지저분해서) 그럼 그 때 제가 잘 못 했었던것 같습니다.
그럼 String(KSC5601)을 Runtime환경에서 Byte[]를 편집해서 만들어 놓는 방법 밖에 없겠군요.
아니면 KSC5601로 컴파일된 Class파일에 KSC5601문자를 찾아서 Byte[]를 변경하거나요. ^^
시간 나면 이부분 다시 해보도록 하겠습니다.
제목 : Re: [Comment] 이 곳 사이트의 검색이 제대로 이루어 지지 않는 이유
  글쓴이: EB(goEB)   2002/12/07 02:13:20  조회수:1820  줄수:230
---------------------------------------------------------------------------------------------------
저희 나라에서 프로그래머 개인이 알고 있는 지식의 공유가 활발하지 않다고 느끼는 것은 건 저 뿐일까요?

어쩌면 저의 시각이 좁아서 그런 것일 수도 있겠습니다만 -ㅁ-;;
---------------------------------------------------------------------------------------------------



제가 2부의 글에서 말씀 드렸듯 제가 입력한 글이 검색되지 않았었습니다.
그것을 파헤처본 결과를 이 곳에서 다룹니다.

이 글은 여러분에게 Server Page개발/코딩시 주의해야할 점이 무엇이며 가짜 문자를 다룹니다.

이 본문의 주된 내용은 2부의 "결론"
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
나. Oracle에서 KO16KSC5601를 사용할 때 KSC5601 디코딩/엔코딩이 MS949를 무시 하는지 확인해야
 할 것입니다.
 또한, KO16KSC5601이 EUC-KR을 100% 지원해주는가 의문이 들지 않을 수 없습니다.
 적어도 KSC5601에 MS949의 확장문자가 포함되었을 경우에
 EUC-KR로 컨버팅하여보면 특정문자가 깨지기 때문입니다.
 

다. Client가 WebBrowser이고 문서의 문자셋이 Unicode, UTF-8이 아닐경우
 WebBrowser가(어쩌면 OS레벨) HTTP header나 HTML의 META에 정의된 문자셋이 지원하지 않는
 문자가 있을 경우 이를 자동으로 &# + Unicode(Int16)로 변경한다는 것에 주의하셔야 하며
 이에 따른 문제는
 1. WebBrowser외의 곳에서는 한글 변환이 어려우며 100% 처리하기 위해서는 Unicode나 UTF-8를 이용하여
    직접제작한 처리기를 통해야만 표현할 수 있다.
 2. &# + Unicode로 입력된 내용을 검색시 부작용이 많이 있다.
    (이곳두 제가 '덁' 이라고 입력한거 검색 안됨... 제가 이곳 소스를 보진 않았지만
    모두 EUC-KR루 처리했으니 서버에 항상 &# + Unicode로 갔을 것이고 검색어 역시
    그렇게 처리되어 쿼리를 날릴 텐데두 안되는거 보면 이곳 소스한번 보구잡따. --;;
    더욱 재밌는 것은 파일명을 '덁'으루 하면 EUC-KR인 이곳에서 본문은 &# + Unicode로 가지만
    파일명은 제대로 간다. --;; 역쉬 %xx 로 전달되는게 짱이얌 -0-;; %xx 형태 원츄 --b
    - JAVA에서 직접 EUC-KR 스트링의 Byte를 편집할 수 있다면 이것이 쉽게 가능하게 한다.
     문제는 Byte를 편집하였기 때문에 표준에 어긋나는 일이라는거 --;; 그래서 무효 --;;
     또한, 눈에 보이는 '덁'이 실제 '덁'이 아닌 OS가 꺼벙해서 보이는 경우 있다. 
     - 어렵지만 중요한 말)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
에 해당합니다.

이곳의 게시판의 문자셋은 EUC-KR이니 Form과 QueryString의 내용을 전송할 때
서버에 MS949에 포함된 문자(확장통합완성형)는 (eg. 덁, 횽, 햏)
&# + Unicode(Int16)의 형식으로 날라갑니다. (KSC5601은 문자그대로)

그럼 DB에 역시 그렇게 입력됩니다.
- 어떤한 문자셋으로 변경하건 ASCII문자들(7bit)이기 때문에 깨지지 않을 것입니다.


이제 제가 이곳에서 글을 올리는 과정과 검색하는 과정을 설명해보겠습니다.
(기본이라 다 알고 계신다구요? 그래도 보세요.)

1. 본문에 확장문자인 "아햏햏"을 입력하고 글을 작성합니다.
2. "아햏햏"을 검색합니다.
3. 결과를 지켜 봅니다. -_-;;
 결과는 성공적으로 "아햏햏"을 검색하였습니다.

히~ 검색이 정상으로 되어서 기쁘군요. ^^ 아이 저아 ^.~

그렇게 장난좀 치고 심심해서 "덁"을 검색했습니다.
왜... 왠걸? 제가 1부의 글과 2부의 글에 "덁"을 입력했는데 그 게시물은 검색이 안되고
타인이 올린 "덁"은 검색이 되는 것입니다. @.@ 화... 황당 --;;

이런 --;; 제가 작성해서 올린글은 '왕따'를 당한 것이였습니다. 쩌..쩝...
거..검색이 안 이루어지다뉘 --;;

다음날 이 문제를 까발리기루 했습니다.... 하나부터 열까정 많은 테스팅을 했던것...

이들간의 차이를 분석하니 "덁"은 &# + Unicode로 입력되었었고
"햏"'은 EUC-KR이 아닌대두 "햏" 으로 입력되었던 것입니다.

화...황당;;;
아시는 분도 있으시겠지만 EUC-KR에서의 "햏"은 존재하지 않습니다.
즉, "햏"이 보이긴 하지만 실제 EUC-KR에서의 "햏"은 가짜입니다.
그 가짜를 만드는 방법은 제가 2부에서 언급했듯 현재 문자셋 상태에서 문자셋간 변환하지 않고
직접 Byte(혹은 CharCode)를 수정하면 가능케 합니다.

2부의
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"다". 의 내용중
    더욱 재밌는 것은 파일명을 '덁'으루 하면 EUC-KR인 이곳에서 본문은 &# + Unicode로 가지만
    파일명은 제대로 간다. --;; 역쉬 %xx 로 전달되는게 짱이얌 -0-;; %xx 형태 원츄 --b
    - JAVA에서 직접 EUC-KR 스트링의 Byte를 편집할 수 있다면 이것이 쉽게 가능하게 한다.
     문제는 Byte를 편집하였기 때문에 표준에 어긋나는 일이라는거 --;; 그래서 무효 --;;
     또한, 눈에 보이는 '덁'이 실제 '덁'이 아닌 OS가 꺼벙해서 보이는 경우 있다. 
     - 어렵지만 중요한 말)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
내용에 해당합니다.

그럼 이제 원인을 알게 되었습니다. 서버에 전송될 때 EUC-KR형태이지만 어떤 문제로 인하여
&# + Unicode형태로 전달 되지 않는 다는 것!

하지만 여기서 이상한 점이 있습니다. 제가 작성했던 "덁"은 EUC-KR형태라 &# + Unicode형태로
서버로 갔는데 왜 "햏"은 처리되지 않고 가는 것일까? (--?)

그래서 게시물을 또 다시 작성하였는데 본문에 "덁", "햏" 모두 입력했습니다.
근데 역시 &# + Unicode 형태가 처리 되지 않는 것입니다.

이런 말도 안돼는 --;; 아까 "덁"으로 검색됐던 타인의 게시물을 봐도 &# + Unicode 형태가
아니였습니다.

타 사이트에서 EUC-KR로 처리된 것은 어떻게 처리될까아?
그래서 그곳에 가서 테스팅 했더니 "덁", "햏" 모두 &# + Unicode 처리로 되어 정상으로
동작하더란 것입니다.

그럼 이제 남은것은 웹브라워의 버그와, 이곳 사이트의 HTML Source의 이상 문제 였는데...

일단 제가 이곳에 입력했던 "덁" 처리가 "&# + Unicode" 로 처리된 게시물과
"덁"이 짜가 "덁"으로 처리된 게시물의 차이를 (아시겠지만 엄청난 분량임;;;) 확인시작후

10초만에 제가 입력한 글들의 차이를 발견하였습니다. (의외로 빨리 찾음 --v)

그 차이는 바로 1부에서 설명했던
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
참고.
'葶' <- 이 문자는 Unicode와 UTF-8문자셋이 아니면 깨집니다.
WebBrowser에서 보는 데는 지장 없습니다. 지금도 보이시죠?
이 '葶'는 서버에 전달 될 때 &#33910; 이렇게 변형되어 전달 됩니다.
(지금 이 게시판에서 WebBrowser의 소스보기를 해도 알 수 있습니다.)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"葶" 요 문자였습니다.

즉, 본문에 "葶"과 "덁", "햏"등의 확장문자를 포함하면 확장문자는 "&# + Unicode"
로써 정상처리된다는 것이였습니다. (어..엄청 황당;;)
(본문에 "葶"만 딸랑 하나 넣으면 이 것도 정상처리 되지 않습니다.)
그러니 저의 글에 있던 "덁"은 검색되지 않을 수밖에 --;;
본문엔 "&# + Unicode"이렇게 입력되고 검색어는 "%88%E4"(짜가 "덁") 로 전달되었으니...

그렇담 왜 이 곳 사이트에서만 그런일이 발생할 까?

그래서 이곳 사이트의 HTML Source를 분석하니...

이곳, 웹페이지는 HTML의 META TAG에 CharSet을 포함하지 않았습니다.
다만, Server에서 Header에 "Content-Type: text/html; charset=euc-kr" 를 보냅니다.
이 때문에 IE(WebBrowser)는 인코딩을 "한국어(EUC)"라고 인식하게 되는 것입니다만...

이 때, IE에서도 인코딩을 "한국어(EUC)"라고 표시하고,
또 Jscript를 이용하여 현재 보여지는 화면의 인코딩을 확인하여도 "euc-kr"이라고 인식을 하지만

IE의 버그 때문에 정상처리 되지 않았던 것이였습니다.


결론.
***************************************************************************************************
가. META TAG에 반드시 CharSet을 포함해야한다.
    - Unicode, UTF-8형태의 CharSet에서는 있어도 그만 없어도 그만인지는 확인하지 않았음;;;

	EUC-KR환경은 당연포함해야하지만
	
	KSC5601환경의 경우 당연 서버에서 모두 확장문자는 정상처리 하니 문제가 없겠지만
	위에서 언급한 "葶"는 META TAG에도 KSC5601을 포함하여야만 정상처리 되었고
	그렇지 않을 시엔 "匪" 이 문자가 이를 대신하였다. (짜가가 판치는 세상;;)
	그러므로 META TAG는 필수적으로 처리되어야 하며
	또한 META TAG앞에 다른 어떠한 화면에 출력되는 문자는 있어서는 안되었다.
	
	예로써 다음과 같은 환경엔 META TAG가 있으나 마나였다.
	---------------------------------------------------
	먼저 출력해본다.
	<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
	...
	---------------------------------------------------
	즉, 위의 환경엔 확장문자도 EUC-KR기준이 아닌 KSC5601(MS949)기준으로 처리된다.

***************************************************************************************************
나. DB의 "KO16KSC5601" 과 JAVA EUC-KR의 궁합.

 2부에선 언급했던 "나"의 내용

『나. Oracle에서 KO16KSC5601를 사용할 때 KSC5601 디코딩/엔코딩이 MS949를 무시 하는지 확인해야
 할 것입니다.
 또한, KO16KSC5601이 EUC-KR을 100% 지원해주는가 의문이 들지 않을 수 없습니다.
 적어도 KSC5601에 MS949의 확장문자가 포함되었을 경우에
 EUC-KR로 컨버팅하여보면 특정문자가 깨지기 때문입니다.』

 은 이곳 JAVAservice.net DB의 환경이 "KO16KSC5601" 이라면 이곳 본문에서 실험해봐서
 알겠지만 EUC-KR의 잘 못 된 내용까지도 DB에 모두 넣을 수 있다는 결론이기 때문에
 MS949를 "KO16KSC5601"에 넣어도 된다는 것이다.(이원형님이 우려하시던 내용)
 
 다만, EUC-KR에서 확장문자는 실질적으로 지원하지 않는 것이기 때문에
 String strNEW = new String(EUCKRsource.getBytes("EUC_KR"), "Some...");
 으로 변형해서는 절대로 그 확장문자는 보존할 수 없음에 주의하고 트릭을 사용하고 싶다면
 비록 현 문자가 EUC_KR (혹은 JSP의 @Page에서 EUC_KR이지만) 이긴해도
 String strNEW = new String(EUCKRsource.getBytes("MS949"), "Some...");
 라고 뻥을 처주는 트릭을 사용하여야만 EUC_KR에 입력된 가짜 확장문자도 복구할 수 있다.
 ※ 주의! 이 트릭은 반드시 IE WebBrowser에서 넘겨받은 값만 100% 오류없이 처리할 수 있습니다.
***************************************************************************************************
다. Navigator는 확장어 처리가 완전 엉뚱하게 된다.
 (다양한 셋팅으로 시도 하였으나, 본좌는 방법이 없다는 결론을 내었다. --)
***************************************************************************************************



테스팅 환경. WinXP, IE6, Navigator 7.0



이글의 모든 내용은 많은 테스팅을 거쳤으며 많은 증거들이 있으니 믿으셔도 됩니다. --;;



이 곳에 언급된 검색의 문제점은 이 내용 파헤치기 전 자체테스팅한 

검색 엔진의 문제 20% 정도에 해당하는 내용이 되네요...

그 테스팅 결과가 어마마해서뤼.. 어떻게 글을 작성해야할 지 --;;



---------------------------------------------------------------------------------------------------
미약한 저의 글 읽어 주셔서 감사드리며, 지식 공유하고 서로 부족한점 매꾸워 줍시다. ^_^

EmotionalBrain...
---------------------------------------------------------------------------------------------------




---------------------------------------------------------------------------------------------------
Update - 2002.12.06 19:42

기존
"가. META TAG에 반드시 CharSet을 포함해야한다. - Unicode, UTF-8은 있어도 그만 없어도 그만;;;"
을
"가. META TAG에 반드시 CharSet을 포함해야한다.
    - Unicode, UTF-8형태의 CharSet에서는 있어도 그만 없어도 그만인지는 확인하지 않았음;;;"
로 변경.
(죄송합니다. 문서를 몇번이고 읽어본뒤 올려야 했었는데)
---------------------------------------------------------------------------------------------------
제목 : Re: 그러면 "나"의 결론 DB부분은 꼭 검증해야...
  글쓴이: EB(goEB)   2002/12/07 21:50:52  조회수:234  줄수:66
전 확장자만 cgi 인줄 알았는데...

실질적으로 JSP 이거......


***************************************************************************************************
나. DB의 "KO16KSC5601" 과 JAVA EUC-KR의 궁합.

 2부에선 언급했던 "나"의 내용

『나. Oracle에서 KO16KSC5601를 사용할 때 KSC5601 디코딩/엔코딩이 MS949를 무시 하는지
 확인해야 할 것입니다.
 또한, KO16KSC5601이 EUC-KR을 100% 지원해주는가 의문이 들지 않을 수 없습니다.
 적어도 KSC5601에 MS949의 확장문자가 포함되었을 경우에
 EUC-KR로 컨버팅하여보면 특정문자가 깨지기 때문입니다.』

 은 이곳 JAVAservice.net DB의 환경이 "KO16KSC5601" 이라면 이곳 본문에서 실험해봐서
 알겠지만 EUC-KR의 잘 못 된 내용까지도 DB에 모두 넣을 수 있다는 결론이기 때문에
 MS949를 "KO16KSC5601"에 넣어도 된다는 것이다.(이원형님이 우려하시던 내용)
***************************************************************************************************

라는 부분이 이곳 DB환경이 "KO16KSC5601" 두 아니구 JSP 두 실제 아니니

이것은 검증해야 되겠네요....

(다른 내용은 모두 Client 부분이니까 이미 검증 되었고...
Socket상으로 전달되는 값도 확인했고...)


단순히 폼값만 받아서 DB에 저장해보면 돼는데...


아햏햏 으로 --;;


환경이 안되니 원...

오라클을 --;;


제가

"이곳 JAVAservice.net DB의 환경이 "KO16KSC5601" 이라면"

이라하였으니 다행히 제가 문법을 정확히 썼네요.... (글들에서 오타두 많은 편이였는데..)


테스팅 환경 돼시는분 부탁드립니다. ㅠㅠ



p.s 전 cgi(CGI 말고), php엔 관심이 없는지라 ... 분석할 의향이 --;;
굳이 분석할 필요도...

META TAG의 CHARSET 넣구 이미 만들어진 파일(DB)의 내용을 전부 바꾸시면 되니깐... ^^
(문자셋을 뭐로 하건간에 변경해야 함)

EUC-KR로 했지만 KSC5601을 흡수 하는걸 봐서 KSC5601로 해도 돼겠습니다.
다만 Unicode, UTF-8을 cgi에서 처리할 수 있는지는... 안해봐서..


p.s 2 여러분 META TAG 꼭 쓰세요.... --;; 안그럼 먼 훗날 후회해요 --;;
기회가 된다면 검색엔진에서 META TAG의 문자셋의 중요성을 (반다시!!)
언급할 까 합니다만.... 언제가 될지..

세상 이렇게 바쁘게 살아서야 원.. --;;
제목 : Re: 메타태그
  글쓴이: 서민구(4baf)   2002/12/08 06:09:42  조회수:244  줄수:46
캐릭터셋에 대해서 너무나 모른상태라서 이해가 안가는 것 몇가지를
질문드리겠습니다.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">

는 있으나 마나라고 하셨는데

그렇다면, 

<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<html>
<head>

이런 방식으로 해야한다는 말씀이신가요?

두번째로 

이곳, 웹페이지는 HTML의 META TAG에 CharSet을 포함하지 않았습니다.
다만, Server에서 Header에 "Content-Type: text/html; charset=euc-kr" 를 보냅니다.
이 때문에 IE(WebBrowser)는 인코딩을 "한국어(EUC)"라고 인식하게 되는 것입니다만...

라고 말씀하셨는데,

이 얘기는 jsp의 @page태그에서 contentType을 지정해야하고 동시에
meta 태그를 지정해야한다는 말씀으로 이해하면 될런지요...

세번째로 utf-8을 쓰라고 하셨는데 정작 리눅스에서 LANG을 utf-8로
지정할 수 있는건가요? 자바에서 컴파일 및 실행을 utf-8로 하면 되기야
하겠지만 리눅스에서 텔넷으로 들어가서 utf-8인코딩으로 문자를 입력하려면
어떤 환경을 써야하나요? 울트라 에디트로 편집하고 ftp로 올리는건
힘든것 같은데요..

마지막으로
전체적으로 내용을 정리했으면 하는데...

제가 했으면 좋겠지만 , 제가 요즘 시간이 안나서 저는 여력이 없군요... 
이달말이 되야 시간이 나는 관계로 이렇게 직접 해보지도 않고 질문을
드립니다.. 죄송하네요.

-----------------------------------------------
서민구 (NO---SPAM4baf@orgio.net)
제게 메일을 보내시려면 이메일 주소의 'NO---SPAM'을
제거하시고 메일을 보내주세요.
제목 : Re: 서민구님께~
  글쓴이: EB(goEB)   2002/12/08 12:09:14  조회수:239  줄수:174
제가 말씀 드린 것은
*--------------------------------------------------------------------------------------------------
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
--------------------------------------------------------------------------------------------------*
이 아니구요.

위에서 말씀 드렸듯
*--------------------------------------------------------------------------------------------------
먼저 출력해본다.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
...
--------------------------------------------------------------------------------------------------*
요겁니다.
위에 EUC-KR 앞에 출력된 문자 보이시죠? "먼저 출력해본다." 라는 글귀
그걸 가르킨 겁니다.

다시 한번 말씀드리자면 CharSet 정의 앞에 어떠한 것도 화면에 출력되어서는 안된다는 것입니다.

즉,
*--------------------------------------------------------------------------------------------------
<input type=button>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
...
--------------------------------------------------------------------------------------------------*
은 정상처리 되지 않으며

*--------------------------------------------------------------------------------------------------
<input type=hidden>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
...
--------------------------------------------------------------------------------------------------*
은 정상처리 된다는 것이죠.

간혹 CharSet 앞에 먼저 출력하시는 분이 있어서 설명드린 거구요.

왜 CGI들을 디버깅 할 때도 그런경우가 있짜나요.. 괜히 입력받은값 확인 한답시구.
*--------------------------------------------------------------------------------------------------
<%폼이나 쿼리스트링값 디버깅을 위해 출력하기%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
...
--------------------------------------------------------------------------------------------------*
라는 형식 말입니다.

이런 경우를 조심하잔 것이죠.

그러므로 CharSet을 설정하기전엔 어떠한 것도 화면에 출력해서는 안됩니다.
(Client측의 버그 때문에 --;;)




그리고 JSP의(엄밀히 이런류의 CGI 모두해당. eg. ASP, ASP.NET)
@page에도 넣어야 하는게 맞습니다.

그래야 소스를 제대로 읽을 수 있습니다. (javac -encoding과 같은 맥락입니다.)


*--------------------------------------------------------------------------------------------------
세번째로 utf-8을 쓰라고 하셨는데 정작 리눅스에서 LANG을 utf-8로
지정할 수 있는건가요? 자바에서 컴파일 및 실행을 utf-8로 하면 되기야
하겠지만 리눅스에서 텔넷으로 들어가서 utf-8인코딩으로 문자를 입력하려면
어떤 환경을 써야하나요? 울트라 에디트로 편집하고 ftp로 올리는건
힘든것 같은데요..
--------------------------------------------------------------------------------------------------*
라는 질문에 대한 답변은 불행히도...

UTF-8관련부분은 한글환경에선 리눅스에서는 어떠한 것도 해당하지 못합니다.

제가 아는 바로는 리눅스에서 UTF-8한글 입력도 안되고...
그렇다고 EUC-KR이나 KSC5601이나 MS949등등을 UTF-8로 변경해주는 툴도 없으니까요..
UTF-8로된 한글을 출력해주는 환경은 몇가지 제공된다지만 전혀 쓸모 없는 기능이라는;;;
(입력두 안되는데 어케 코딩을 해요 --;; 글타구 변환기두 없꽁)


그러니 JAVA를 이용해서 제작하심이 ^^;;
 - 그냥 간단히 InputStream과 OutputStream으로만으로도 할 수 있떠여

그리구 제가 언급한
*--------------------------------------------------------------------------------------------------
일반적으로 프로젝트의 모든 소스는 엔코딩 형식이 동일해야 하겠죠?
만일 기존 소스가 있는데 다르다면 현 프로젝트와 맞추어야 할 텐데...
쉽게 구할 수 있는 툴은 UltraEdit가 정도가 되겠네요 저는 v9.10을 가지고 있고
File -> Conversions에 있습니다. 이 곳에서 원하는 형태로 가능하겠습니다.

-단, 한글들의 문자셋변환 툴은 아직 보질 못했음. 혹시 보신분 손 ^^/
 한글에서 하위변환은 완벽히 안되므로 이를 염두해야함.
--------------------------------------------------------------------------------------------------*
라고 했듯

한글 변환은 제대로 처리되지 않더라구요.
(특히 왜 자꾸 UTF-8과는 어쩌다가 되는지 ㅠㅠ)

좋은 플그램 구하는 것보다 JAVA로 자작하는 것이 더 빠를 겁니다.
(그냥 작성한 내용 자동으로 UTF-8로 변환해주는 거)

-JBuilder로 작업하신다면 좋은 결과가 있을 수도 있겠네요
 * 참고. JBuilder의 프로젝트 옵션에 있습니다.




그리구 저...정리 라구요? --?

여기에 올린 내용은 문자셋 문제의 40% 정도 밖엔 해당 되지 않는데요 --;;
(많은 시간을 소비하였지만 애석하게도 아직 이것 밖엔 정리되지 않았기 때문에
완전한 모습이 나오기 전엔 현재 정리가 어렵습니다.)


제가 UTF-8 형식을 추구하는 진정한 이유와, 목적은 여지껏 설명했던 부분 속에 있어요!
겉에 드러나 있는 단순한 문제가 아니구요.

(현실적으로 가능만 하다면야 UTF-8이상의 것을 써야 하지만)

제가 첨부터 자세한 설명과 이곳 사이트의 검색 문제를 올린 이유는 왜 UTF-8이여야만 하는지를
내면적으로 나타내려 했기에 그런건데~
(내면을 직설적으로 표현 해봐야 그냥 결론만 날 뿐이겠네요
항상 그렇듯 그냥 그렇게 하라구 알려주고 이유는 설명않고 --;;)


굳이 표면적으로 말하자면
검색을 한다고 했을 때

"내가 입력한 검색어가 과연 검색어 일까?" <= 무지 어렵지만 상당히 의미있는말...

수수께끼라여기시는 분들은 문자셋 이해를 아직 못하신 것일 테고
아시는 분들이라면 이것은 상당한 의미를 지닌말로 해석하시겠네요.


요 수수께끼를 정확히 이해하셨다면 전세계에 있는 웹 검색엔진은 (Yahxx, Emxx, Hanxxx, 등등)
새롭게 만들어져야 한다는 걸 아실 겁니다. ^^
(최소한 수정은 불가피 합니다.
특히 몇몇 서버는 DB내용 자체를 바꿔야 한다는... 쩌비... <- 증거 있습니다. --;;
Yahxx도 DB를 바꿔야 --;;)

하지만 딱 한군데는 꼭(UTF-8초과 필요시만 아니라면. 현재 필요한 곳이 있던가요? 어느나라였더라?)
그럴 염려는 없겠더군요 ^^ 어딜까요? ^.~
(역시 그 곳은 세계 최고라 하여도 손색이 없습니다. 유명한.. GxxGxx)

흥미롭지 않나요? ㅡㅡ;;


저 역시 언능 정리는 하고 싶지만
전 아마 1개월 이후에나 가능할 것 같습니다.
지금 하는 작업이 저에게 중요하기 때문에

이 문제 저를 흥분시키지만 여지껏 테스팅한거 대충 메모만 한뒤 잠시 접으렵니다.


p.s
현재의 검색엔진에는 EUC-KR이나 KSC5601이 더 났지만 어디까지나 아주짧은 미래까지만
해당합니다.


p.s 2
나머지 60%를 언제 쯤 정리 하게 될런지.. ㅠㅠ


p.s 3
제가 테스팅 환경이 되지 않는 부분은 서로 해주었으면 합니다.
그래야 추후 정리할 때 깔끔히 할 수 있지 않겠어요?
어떤 사람이 정리할 진 모르지만


즐프 하십시오. ^^

'web' 카테고리의 다른 글

java.net.NoRouteToHostException: No route to host 해결  (0) 2007.09.04
웹스나이퍼  (0) 2007.09.04
Sitemesh에서 여러개의 configuration 파일을 읽게 하기  (0) 2007.08.24
Sitemesh 참조자료  (0) 2007.08.24
Sitemesh #4 Sitemesh 팁  (0) 2007.08.24
Posted by '김용환'
,

Sitemesh에서 기본적으로 제공하는 ConfigDecoratorMapper는 파일 하나만 달랑 읽게 하고 있다.

좀 당황스럽게 왜 하나만 읽게 하냐는 말이지. 여러개 파일을 읽고, 다양하게 나눠서 읽는 마당에..

 

  <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
   <param name="config" value="${decorators-file}" />
  </mapper>

 

여러개의 파일을 다음과 같이 사용한다.

 

         <mapper class="com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper">
                <param name="config1" value="/common/decorators/decorators.xml" />
                <param name="config2" value="/WEB-INF/decorators.xml" />
         </mapper>

 

ConfigDecoratorMapper를 수정한 소스는 다음과 같다.

 

package com.google.common.sitemesh.mapper;

import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.opensymphony.module.sitemesh.Config;
import com.opensymphony.module.sitemesh.Decorator;
import com.opensymphony.module.sitemesh.DecoratorMapper;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.mapper.AbstractDecoratorMapper;
import com.opensymphony.module.sitemesh.mapper.ConfigLoader;

/**
 * Reads decorators and mapping from the <code>param</code> property.
 * If param is not given, read default file('WEB-INF/decorators.xml')
 * <br>
 * It is extended for multiple config file for ConfigDecoratorMapper<br>
 * <br>
 * Example below <br>
 * <mapper class="com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper"> <br>
 *  <param name="config2" value="/WEB-INF/common-decorators.xml" /> <br>
 *  <param name="config1" value="/WEB-INF/decorators.xml" /> <br>
 * </mapper> <br>
 *
 * @author knight76
 *
 */
public class MultipleConfigDecoratorMapper extends AbstractDecoratorMapper {
 private static Log log = LogFactory.getLog(MultipleConfigDecoratorMapper.class);

 private List<ConfigLoader> configLoaderList = null;

 /** Create new ConfigLoader using '/WEB-INF/decorators.xml' file. */
 public void init(Config config, Properties properties, DecoratorMapper parent) throws InstantiationException {
         super.init(config, properties, parent);
         configLoaderList = new ArrayList<ConfigLoader>();
         try {
          // property의 모든 데이터 키값을 오름차순으로 받아  configLoader에 저장한다.
          String[] props = properties.keySet().toArray(new String[0]);
          Arrays.sort(props);
          for (Object propertyName : props) {
           String fileName = properties.getProperty((String)propertyName, "/WEB-INF/decorators.xml");
           ConfigLoader configLoader = new ConfigLoader(fileName, config);
           configLoaderList.add(configLoader);
          }
         }
         catch (Exception e) {
             log.error(e);
         }
     }

 /**
  * Retrieve {@link com.opensymphony.module.sitemesh.Decorator} based on
  * 'pattern' tag.
  */
 public Decorator getDecorator(HttpServletRequest request, Page page) {
  String thisPath = request.getServletPath();

  // getServletPath() returns null unless the mapping corresponds to a
  // servlet
  if (thisPath == null) {
   String requestURI = request.getRequestURI();
   if (request.getPathInfo() != null) {
    // strip the pathInfo from the requestURI
    thisPath = requestURI.substring(0, requestURI.indexOf(request
      .getPathInfo()));
   } else {
    thisPath = requestURI;
   }
  }

  String name = null;
  try {
   name = getMappedName(thisPath);
  } catch (ServletException e) {
   log.warn(e);
  }

  Decorator result = getNamedDecorator(request, name);
  return result == null ? super.getDecorator(request, page) : result;
 }

 /**
  * 주어진 thispath를 받아 해당 thispath에 매핑된 decorator 이름을 가져온다.
  * @param thisPath
  * @return
  * @throws ServletException
  */
 private String getMappedName(String thisPath) throws ServletException {
  String name = null;
  for (ConfigLoader loader : configLoaderList) {
   name = loader.getMappedName(thisPath);
   if (name != null) {
    return name;
   }
  }
  return name;
 }

 /**
  * Retrieve Decorator named in 'name' attribute. Checks the role if
  * specified.
  */
 public Decorator getNamedDecorator(HttpServletRequest request, String name) {
  Decorator result = null;
  try {
   result = getDecoratorByName(name);
  } catch (ServletException e) {
   log.warn(e);
  }

  if (result == null
    || (result.getRole() != null && !request.isUserInRole(result
      .getRole()))) {
   // if the result is null or the user is not in the role
   return super.getNamedDecorator(request, name);
  } else {
   return result;
  }
 }

 /**
  * 주어진 name을 받아 decorator를 얻어온다.
  * @param name
  * @return
  * @throws ServletException
  */
 private Decorator getDecoratorByName(String name) throws ServletException {
  Decorator result = null;
  for (ConfigLoader configLoader : configLoaderList) {
   result = configLoader.getDecoratorByName(name);
   if (result != null) {
    return result;
   }
  }
  return result;
 }
}

Posted by '김용환'
,

Sitemesh 참조자료

web 2007. 8. 24. 05:31

이 세 군데 외엔 쓸만한데 없더먼...

그 다음엔 내 블로그??!!! ㅋㅋ

 

http://opensymphony.com/sitemesh
http://blog.naver.com/paradozz?Redirect=Log&logNo=15918519

Posted by '김용환'
,

Sitemesh #4 Sitemesh 팁

web 2007. 8. 24. 05:29

당연하겠지만, 이 글은 그저 간단한 팁이라 생각하면 되겠당.. 더 좋은 방법이 있으면 더욱 많이 생겨나면 좋겠다.

샘플의 특정회사는 당근 가명이다...^^

 

특정 패턴을 빼거나 적용하기

특정 디렉토리에 모든 웹 컴포넌트(jsp, action, html등등)을 하나의 decoration으로 적용이 가능하다. 하지만, 때에 따라서는 그 폴더안에 특정 웹 컴포넌트등은 그 decoration을 적용시키지 않을 수도 있고, 다른 decoration을 적용시킬 수 있다.
즉, context상 같은 디렉토리에 있지만, UI상에서 다르게 decoration이 적용될 수 있는데, 이런 예외상황을 처리할 수 있는 방법을 Sitemesh는 가지고 있다.
exclude 패턴, jsp상에서의 meta 태그, decorator 패턴 지정등을 통해서 여러 패턴으로 지정이 가능하다.

Decoration의 exlclude 패턴 사용하기

특정 패턴의 action 혹은 html, jsp등에 지정된 pattern을 아예 적용하지 않고 싶을 때에 exclude를 사용할 수 있다. 이 때, 주의할 점은 decorators.xml에 exclude 패턴을 사용했다 해서 적용되지 않는다.

decorators.xml
...
<excludes> 
    <pattern>/exclude.gl</pattern> 
    <pattern>/alert.gl</pattern>
</excludes> 
...

그 이유는 sitemesh.xml 에서 exclude할 패턴을 적용할 파일을 지정해야 한다. sitemesh.xml 파일에서 exlcude할 파일 리스트가 적힌 xml파일을 지정한다.
decorator-mapper 태그안에 mapper class를 ConfigDecoratorMapper안에 해당 config파일을 적용했다 하더라도 이는 exclude 파일 리스트와는 무관하다.

<excludes file="/WEB-INF/decorators.xml"/>

다음은 exclude를 적용한 실제 예제이다.

sitemesh.xml
<sitemesh>
	<page-parsers>
		<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
		<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
	</page-parsers>

	<excludes file="/WEB-INF/d1.xml"/>
	<decorator-mappers>
		<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
			<param name="config" value="/WEB-INF/decorators.xml" />
		</mapper>
	</decorator-mappers>
</sitemesh>
d1.xml
<decorators>
    <excludes>
	<pattern>/exclude.gl</pattern> 
         <pattern>/alert.gl</pattern>
    </excludes>
</decorators>
decorators.xml
<decorators defaultdir="/WEB-INF/decorators">
    <decorator name="indexLayout" page="indexLayout.jsp">
        <pattern>/index.gl</pattern>
    </decorator>
 
    <decorator name="defaultHeader" page="defaultHeader.jsp"/>
    <decorator name="defaultFooter" page="defaultFooter.jsp"/>


    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>
</decorators>

decorator 설정 파일에서 null decorator 지정

위의 예처럼 exclude 패턴를 사용하여 지정된 패턴에서 일부 파일을 예외화할 수 있다. 또한 이 방법 외엔 다른 방법이 있다. decorator를 null로 지정하여 decoration이 적용안되게 할 수 있다. 또는 다른 특정 decoration을 지정할 수 있다.

decorators.xml
<decorator name="null">
    <pattern>/test.gl</pattern>
</decorator>

jsp, html파일에 meta 태그 사용

decorators.xml에 특정 decorator을 지정하였지만 해당 패턴에 속하지 않았지만, jsp의 파일에 decorator를 지정하여 사용이 가능하다. 이를 위해서는 sitemesh.xml에서 반드시 PageDecoratorMap 클래스가 decorator mapper로 바인딩되어야 한다. (순서는 com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper 보다는 상위에서 정의해야 한다. 그 이유에 대해서는 자세한 내용은 다음장에서 언급한다.)

siemesh.xml
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    <param name="property.1" value="meta.decorator" />
    <param name="property.2" value="decorator" />
</mapper>

decorators 설정파일에서 tv라고 하는 decorator와 아무 decoration도 적용되지 않는 null decorator를 적용한다.

decorators.xml
<decorator name="tv" page="tv.jsp">
</decorator>

<decorator name="null">
</decorator>

google.jsp파일에서 tv라고 하는 decorator를 지하여, tv.jsp의 decorator page를 UI에서 쓸 수 있도록 할 수 있다.

google.jsp
<meta name="decorator" content="tv" />
<%@ page language="java" pageEncoding="MS949" %>
<html>
<head>
<title> Google Test</title>
</head>
<body onload="http://~~~">
google6
</body>
</html>

만약, 아무 decoration도 적용하지 않겠다면, 다음의 코드를 jsp 상단에 지정하면 된다.

<meta name="decorator" content="null" />

Decorator 체인

sitemesh.xml에서 정의된 mapper들의 순서가 chain으로 연결되어 있다. 순서에 유의를 해야 하는데, 순서에 따라서 완젼 다른 결과가 나올 수 있다. 왜 순서에 주의해야 하는지를 예제를 통해서 알아본다.

sitemesh.xml은 PageDecoratorMapper와 ConfigDecoratorMapper를 가지고 있다.

sitemesh.xml
<sitemesh>
	<page-parsers>
		<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
		<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
	</page-parsers>

	<!-- <excludes file="/WEB-INF/d1.xml"/>  -->

	<decorator-mappers>

		<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
			<param name="property.1" value="meta.decorator" />
			<param name="property.2" value="decorator" />
		</mapper>

		<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
			<param name="config" value="/WEB-INF/decorators.xml" />
		</mapper>
	</decorator-mappers>
</sitemesh>

decorators.xml은 여러 decorator를 가지고 있다.

decorators.xml
<decorators defaultdir="/WEB-INF/decorators">
    <decorator name="defaultHeader" page="defaultHeader.jsp"/>
    <decorator name="defaultFooter" page="defaultFooter.jsp"/>

    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>
    
    <decorator name="tv" page="tv.jsp">
    </decorator>

    <decorator name="null">
    </decorator>
</decorators>

위에서 사용된 google.jsp를 사용한다.

google.jsp
<meta name="decorator" content="tv" />
<%@ page language="java" pageEncoding="MS949" %>
<html>
<head>
<title> Google Test</title>
</head>
<body onload="http://~~~">
google6
</body>
</html>

실행을 해보면, tv decorator가 적용된 결과값이 나온다. (당연하다.)

Header
tv앞 google6 tv뒤 
Footer

만약 sitemesh.xml에서 PageDecoratorMapper, ConfigDecoratorMapper의 연결자 순서를 바꾸어 본다.

sitemesh.xml
<sitemesh>
	<page-parsers>
		<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
		<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
	</page-parsers>

	<!-- <excludes file="/WEB-INF/d1.xml"/>  -->

	<decorator-mappers>
		<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
			<param name="config" value="/WEB-INF/decorators.xml" />
		</mapper>

		<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
			<param name="property.1" value="meta.decorator" />
			<param name="property.2" value="decorator" />
		</mapper>
	</decorator-mappers>
</sitemesh>

결과는?? tv decorator가 적용되지 않는다. 기본 디폴트 decorator로 적용된다.
그 이유는 ConfigDecoratorMapper에서 처리되어 default decorator로 decoration된다.

<decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>

즉, decoration mapper는 chain으로 구성되어 있고 (사실은 Filter Chain이다. ) 순서에 맞게 서비스를 처리하고 바로 리턴하도록 되어 있다는 점이다. 이 내용은 Site Mesh 매뉴얼 1(소개) 맨 마지막에서 언급되었으니, 참조하면 된다.

decoraotr page에서 특정 필드 추가하기

property 값을 두번 지정할 수 없다. 따로 따로 나눠서 decorator:getProperty를 사용한다.

아래의 예는 <decorator:getProperty/> 태그의 property 속성을 나란히 적어놓았다. 이 예제는 syntax 문제를 일으키기 때문에 동작이 되지 않아 에러를 web browser를 통해 볼 것이다.

X, layout.jsp
<body onload="<decorator:getProperty property="body.onload" property="body.bottommargin" writeEntireProperty="true" />" bgcolor=ffffff topmargin=0 marginheight=0>

아래의 예는 각각 따로 <decorator:getProperty/> 태그를 중복해서 사용한 것이다. 제대로 동작되는지 확인할 수 있다.

O, layout.jsp
<body onload="<decorator:getProperty property="body.onload" writeEntireProperty="true" />"  
body.bottommargin="<decorator:getProperty property="body.bottommargin"  writeEntireProperty="true" />"  
         bgcolor=ffffff topmargin=0 marginheight=0>

웹 페이지는 그저 onload와, bottommargin만 지정하면 해당 atribute가 적용되는지 알 수 있을 것이다.

<body onload="alert('1');" bottommargin=5>

Action과 Decoration

Action에 특정 decorator page를 지정한 상태에서 그 Action 에 여러 Request Parameter가 붙었을 때, 그 Action의 decorator page로 보여진다??

특정 Action에 decorator를 지정하고, Action의 디폴트 메소드외 다른 메소드를 호출하면, 또는 리쿼스트 파라미터가 여럿이 적용이 될까?

밑의 decorators.xml 파일의 예를 보자. google Action은 decorator page를 default.jsp로 가지고 있다. google.gl을 요청하면 default.jsp가decoration이 되어 xwork.xml에서 지정한 jsp파일을 보여줄 것이다.

decoratos.xml
<decorator name="default" page="default.jsp">
    <pattern>/google.gl</pattern>
    <pattern>/google.jsp</pattern>
</decorator>

만약 google Action에 parameter를 추가하거나, Action의 특정 메소드를 특정 메소드를 호출한다면, 적용이 안될 수 있도 있을 법하다. '*' 패턴을 추가하지 않기 때문에 아리까리할 수 있다.

/google.gl?m=register

결과는 해당 패턴에 적용된다는 것이다. Action 이름을 리쿼스트 파라미터로 받으면 파라미터가 얼마나 붙든지 간단하게 정의된 Action기반 Sitemesh 설정파일로 쉽게 처리할 수 있다.

Action의 결과(jsp)중 특정 결과 jsp만 다른 decorator를 줄 수 있다?? - 1번째 얘기

결론부터 말하면, 불행히도 이 방법을 시도했지만, 환경설정 파일만 수정해서는 할 수 없다.

다음의 예를 들어본다. 밑의 예에서 google Action의 결과중 유일하게 적용안되는 것이 있다. 바로 save.jsp 이다. 강조하지만, Sitemesh는 Request URL을 기준으로 되어 있어 dispatch할 경우 여전히 google.gl으로 남기 때문에 save.jsp에 대해서는 bean decorator가 적용되지 않는다.
하지만, redirection이 된 edit.jsp는 패턴이 제외된 채로 적용된다. 그러나 URL이 바뀌는 불상사는 감수해야 한다.

xwork.xml
<action name="google" class="com.google.publ.test.action.GoogleAction">
    <result name="register">/googleRegister.jsp</result>
    <result name="edit" type="redirect">/edit.jsp</result>
    <result name="save">/save.jsp</result>
</action>
decoratos.xml
<excludes>
    <pattern>/edit.jsp</pattern>
</excludes>

<decorator name="default" page="default.jsp">
    <pattern>/google.gl</pattern>
</decorator>

<decorator name="bean" page="beanLayout.jsp">
    <pattern>/save.jsp</pattern>
</decorator>

Action의 결과(jsp)중 특정 결과 jsp만 다른 decorator를 줄 수 있다?? - 2번째 얘기

제목을 보고 짐작했겠지만, 하나의 Action에서 나온 결과에 대해서 다른 decorator를 쓸 수 있는 방법은 존재한다. 바로 내용이 들어가는 jsp안에 특정 decorator를 설정하는 것이다.

밑의 예를 보자. 바로 google Action이 success인 경우 google.jsp로 dispatch되는데, google.jsp안에 있는 메타 태그에 지정된 content의 decoration 타입에 맞춰 브라우져에 나타나게 된다.

google.jsp
<META name="decorator" content="tv">
....
decorators.jsp
<decorator name="default" page="default.jsp">
   <pattern>/google.gl</pattern>
</decorator>

<decorator name="tv" page="tv.jsp">
</decorator>
xwork.xml
<action name="google" class="com.google.publ.test.action.GoogleAction">
    <result name="success">/google.jsp</result>
    <result name="register">/googleRegister.jsp</result>
</action>

이렇게 사용할 수 이유는 바로 sitemesh.xml 파일의 설정과 관련이 있다. sitemesh.xml 에서 ConfigDecoratorMapper보다 PageDecoratorMapper를 먼저 설정하기 때문이다.

sitemesh.xml
...
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
         <param name="property.1" value="meta.decorator" />
	<param name="property.2" value="decorator" />
</mapper>

..
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
	<param name="config" value="/WEB-INF/decorators.xml" />
</mapper>
..

decorator가 적용되는 순서

decorators.xml에 decorator 태그가 지정된 순서대로 decorator가 적용된다.

예를 들어보자. google.gl이라는 action이 호출될 때, 정확하게 URL과 동일한 이름을 패턴으로 갖는 tv decorator가 적용된다.

decorators.xml
<decorators defaultdir="/WEB-INF/decorators">

    <decorator name="defaultHeader" page="defaultHeader.jsp"/>
    <decorator name="defaultFooter" page="defaultFooter.jsp"/>
    <decorator name="leftMenu" page="leftMenuLayout.jsp"/>

    <decorator name="tv" page="tv.jsp">
	    <pattern>/google.gl</pattern>
    </decorator>

    <decorator name="default" page="default.jsp">
	    <pattern>/*.gl</pattern>
    </decorator>

    <decorator name="null">
    </decorator>

</decorators>

pattern이 적용되는 순서

패턴이 적용되는 순서가 다르다. Request URI를 보고 패턴이 지정된 것중에서 다음의 순서대로 해당 decorator page를 찾게된다.

  1. 정확하게 단어가 맞는 패턴 (Exact word)
  2. 'abc*'나 'abc?'와 같은 컴플렉스 패턴 (Complext)
  3. '/', '*', '/*'와 같은 디폴트 패턴 (Default)

tiles의 getAsString(또는 tiles에서 put을 이용하여 atrribute을 지정) 을 어떻게 변경시키냐?

webwork를 보면, <action> 태그 밑에 <param> 태그를 사용할 수 있다. static parameter interceptor를 이용하여 action에 필드를 넘길 수 있다. 이 때, action은 setter 메소드와 클래스 필드만을 적으면 된다.
자세한 내용은 webwork를 참조하라.

action을 기반하는 jsp중, jsp파일들이 서로 다른 Layout 템플릿을 쓰는 경우

어쩔 때는 rightmenu를 쓰고, 어쩔 때는 rightmenu를 안 쓰는 경우.

  • redirect 하기.
  • 해당 jsp파일에서 meta 태그를 이용하여 특정 decorator를 사용하게 함.
Posted by '김용환'
,

Sitemesh 싸이트에서 번역한 자료입니다. 좀 허접하게 번역했지만.. 아마도 번역을 안해줘서...

 

SiteMesh는 Decorator Tag, Page Tag 2개의 tag 라이브러리를 제공한다. Decorator Tag는 decorator page를 생성할 때 사용되는 tag이고, Page Tag는 decorator 페이지 내에서 다른 decorator를 포함할 때 사용된다.

Decorator Tags

<decorator:head />

원래 웹페이지의 HTML <head> 태그의 내용을 추가한다. 속성은 없다.

<decorator:body />

원래 웹페이지의 HTML <body> 태그의 내용을 추가한다. body의 onload, onunload 이벤트의 바디 속성은 body.onload 와 body.onunload decorator에 의해 포함되어 쓰일 수 있다.

<body onload="<decorator:getProperty property="body.onload" />">
<body onload="alert('1');" bottommargin=5>

좀더 자세히 알기 위해서는 getProperty를 참조할 것. 속성은 없다.

<decorator:title [ default="..." ] />

Insert title of 원래 HTML 페이지의 title 태그로부터 얻은 title을 추가한다. title을 찾을 수 없다면, value값을 default로 지정할 수 있다.

<decorator:getProperty property="..." [ default="..." ] [ writeEntireProperty="..." ]/>

원래 페이지의 속성을 추가한다. HTMLPage interface를 이용하여 해당 페이지의 속성들을 얻어낼 수 있다.

property : 추가할 속성의 이름 (key)
default : 속성을 발견하지 못헀을 때, default로 지정되는 값
writeEntireProperty : 1, yes, true, t, y 로 지정했을 때, 이름을 포함한 속성값(propertyName="propertyValue")이 그대로 쓰여진다.
예)

decorator: <body bgcolor="White"<decorator:getProperty property="body.onload" writeEntireProperty="true" />>
undecorated page: <body onload="document.someform.somefield.focus();">
decorated page: <body bgcolor="White" onload="document.someform.somefield.focus();">

<decorator:usePage id="..." />

decorator jsp에서 사용할 수 있는 Page Object id를 지정한다.
id : 지정할 ID
예1)

<decorator:usePage id="myPage" />
<% if ( myPage.getIntProperty("rating") == 10 ) { %>
  <b>10 out of 10!</b>
<% } %>

예2)

<decorator:usePage id="p" />
<%
	HttpServletRequest req = p.getRequest();
	StringBuffer printUrl = new StringBuffer();
	printUrl.append( req.getRequestURI() );
	printUrl.append("?printable=true");
	if (request.getQueryString()!=null) {
	    printUrl.append('&');
	    printUrl.append(request.getQueryString());
	}
%>
<p align="right">[ <a href="<%= printUrl %>">printable version</a> ]</p>

Page 태그

page 태그는 현재 페이지
The page tags, are used to apply decorators to inline or external content from within the current page.

<page:applyDecorator name="..." [ page="..." title="..." ] > .....body.... </page:applyDecorator>

특정 컨텐츠에 decorator를 적용한다. 해당 컨텐츠는 tag를 통해 body를 지정함으로서, 또는 page 속성을 지정하여 다른 page의 결과를 사용함으로서 인라인(inline)되게 할 수 있다.

name : 포함될 페이지에 적용될 decorator
page : 전체 page에서 쓸 수 있는 외부 자원을 상대적(relative), 절대적(absolute) 패쓰를 이용하여 지정한다.
title : Page.getTitle() 메소드 또는 decorator안에서 <decorator:title/> 를 사용하여 page의 title을 다시 지정(override)할 수 있다. <page:param name="title">...<page:param>에서 지정하여 식별이 가능하도록 한다.
Body : decorator가 적용될 내용.

<page:param name="..."> ... </page:param>

파라미터를 decorator로 넘긴다. 이 값은 Page.getProperty() 또는 <decorator:getProperty/>로부터 얻어온 값을 오버라이드할 수 있다.

name : 오버라이드될 파라미터의 이름
Body: 파라미터의 값.

DecoratorMappers

어떤 한 웹 페이지가 파싱이 될 때, 그것은 decorator에 매핑이 된다. 이 매핑은 DecoratorMappers의 체인에 의해 수행된다.
각 요청이 들어올 때마다 체인의 가장 첫번째 mapper는 어느 decorator가 쓰여져야 하는 지를 물어본다. 그래서 Page Object와 HttpServletRequest 객체를 reference로 받고, 해당 decorator가 쓰여지는지 알게 되면 그 decorator를 리턴하고, 모르면 null을 리턴한다.. 만약 null이 리턴 되면, 체인의 다음번 mapper에게 또다시 decorator 찾는 쿼리를 하게 된다.
이런 전체적인 프로세스는 체인에 더이상 mapper이 없거나, 체인에 있는 decorator가 valid한 decorator를 리턴할 때까지 반복된다. 만약 어떠한 mapper가 decorator를 리턴할 수 없는 상태면, 그 page는 전혀 장식이 되지 않고, 원래상태에 따라 화면이 표출될 것이다.

이런 체인의 mapper 호출 방식은 Chain of Responsibility 패턴으로 유명하다.

mapper의 예

  • 요청된 페이지의 path를 바탕으로 decorator를 결정한다.
  • 로케일, 시간 또는 브라우져에 따라 다른 decroator를 사용한다.
  • 검색 엔진 로봇에 맞은 간단한 decorator를 사용한다.
  • URL 파라미터, Request 속성 또는 meta-tag에 따라 decorator를 달리 사용한다.
  • 미리 저장된 사용자의 셋팅에 맞게 커스트마이즈된 decorator를 사용한다.

DecoratorMapper의 주요 구현은 ConfigDecoratorMapper이다. 이 클래스는 /WEB-INF/decorators.xml 파일을 읽어 mapping과 decorator를 읽는다. 적절한 decorator는 URL 패턴에 따라 적용되어 진다.

Mapper의 종류

Mapper 종류 내용
AgentDecoratorMapper browser에 따른 decorator를 선택할 수 있도록 한다.
browser 타입은 일반적인 경우와 같이 request.getHeader("User-Agent")를 통해 구해온다.
다른 mapper들이 특정 decorator를 지칭하여 반환하는 것과 달리 AgentDecoratorMapper는 적용될 decorator의 decorator page이름을 browser에 따라 수정한다.
예를 들어 decorator mapper가 main decorator를 선정했다면 decorator 페이지는 /decorators/main.jsp가 적용될 것이다. 하지만 http 클라이언트가 익스플러라면 main decorator에 /decorators/main-ie.jsp 장식자 페이지를 적용하게 된다.
모질라 기반 browser라면 /decorators/main-ns.jsp가 decorator page로 결정된다.
만약 선정된 decorator page를 찾는데 실패하면 기본 decorator page인 main.jsp가 적용될 것이다.
<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
    <param name="match.MSIE" value="ie" />
    <param name="match.Mozilla [" value="ns" />
    <param name="match.Opera" value="opera" />
    <param name="match.Lynx" value="lynx" />
</mapper>
ConfigDecoratorMapper DecoratorMapper의 디폴트 구현으로서, decorators.xml 파일을 읽어 decorator와 mapping된 데이터들을 읽는다.
<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
    <param name="config" value="/WEB-INF/decorators.xml" />
</mapper>
CookieDecoratorMapper 쿠키값을 바탕으로 하는 decorator를 선정할 수 있다.
EnvEntryDecoratorMapper decorator 이름으로 web-app 환경 entry에 대한 레퍼런스를 허락한다.
FileDecoratorMapper 파일 이름을 주어 decorator의 이름을 취급한다.
<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
</mapper>
FrameSetDecoratorMapper page가 HTMLPage나 isFrameSet()의 리턴값이 true일 때, 특정 decorator를 선정할 수 있도록 해준다. 그 decorator의 이름은 주어진 property에서 지정할 수 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
</mapper>
InlineDecoratorMapper inline decorator를 사용할 때, 올바른 decoraotor가 무엇인지 사용할 때 선정할 수 있다.
LanguageDecoratorMapper browser에서 page 요청에 대해 "Accept-Language" HTTP 헤더를 이용하여 language 페이지를 결정할 때 선정할 수 있다.
locale에 따라서 decorator의 파일의 이름에 '-en'에 붙여져서 사용될 수 있도록 지정할 수 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.LanguageDecoratorMapper">
  <param name="match.en" value="en" />
  <param name="match.zh" value="zh" />
</mapper>
PageDecoratorMapper 메타 태그에 decorator 항목이 있을 때 장식자를 리턴한다.
PageDecoratorMapper는 여러 파라미터를 받는다. 밑의 예를 보면, PageDecoratorMapper는 첫번째 파라미터로 meta.decorator 프로퍼티를 받는다. 이 의미는 decorator의 META 프로퍼티의 값이 decorator 이름으로 쓰여질 수 있다는 것을 의미한다. decorator_test라는 이름의 장식자를 특정페이지에 적용하고 싶다면 <META name="decorator" content="decorator_test">와 같이 페이지에 메타 태그를 추가하거나 또는 <HTML decorator="decorator_test">와 같이 <HTML> 태그를 수정하여 사용한다.
<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    <param name="property.1" value="meta.decorator" />
    <param name="property.2" value="decorator" />
</mapper>
decorators.xml에서 decorator_test decoration을 미리 정의
<decorator name="decorator" page="tv.jsp">
</decorator>
ParameterDecoratorMapper 설정에 정의된 파라미터와 동일한 스트링이 URL 쿼리 스트링에 존재할 때 정의해 놓은 decorator를 선정하도록 되어 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
    <param name="decorator.parameter" value="decorator" />
    <param name="parameter.name" value="confirm" />
    <param name="parameter.value" value="true" />
</mapper>

이 mapper는 3개의 parameter가 존재한다.
decorator.parameter : 특정 decorator의 이름을 지칭하는 리쿼스트 파라미터의 이름
parameter.name : 특정 리쿼스트 파라미터를 confirm하는데 사용하는 리쿼스트 파라미터의 이름
parameter.value : 특정 decorator 파라미터를 confirm하는데 사용하는 리쿼스트 파라미터의 값
만약 help.jsp 파일에 이 mapper에 test decorator를 적용하려면 다음의 코드로 호출하면 된다.

help.jsp
help.jsp?decorator=test&confirm=true
SessionDecoratorMapper session 어트리부트에서 지정한 decorator를 선정하도록 되어 있다.
디폴트로 decorator를 session 속성에서 찾지만, decorator.parameter 속성을 통해서 오버라이드 될 수 있다.
PrintableDecoratorMapper URL 쿼리 스트링의 printable=true라는 문자열에 반응한다.
decorators.xml에 정의된 decorator중 printable decorator를 리턴할 것이다.
아래의 예는 다음을 의미한다. printable로 정의된 decoraotr는 printable=true 라는 리쿼스트가 들어올 때 해당 jsp가 적용된다.
<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
	<param name="decorator" value="printable" />
	<param name="parameter.name" value="printable" />
	<param name="parameter.value" value="true" />
</mapper>
RobotDecoratorMapper 검색엔진 로봇에서 식별되어 지는 특정 decorator를 선정하도록 되어 있다.
<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
    <param name="decorator" value="robot" />
</mapper>

사용자 정의 mapper 환경 설정

sitemesh.xml

요청에 따라 적용될수 있는 mapper를 정의하기 위해서는 sitemesh.xml파일을 생성한다.

sitemesh.xml
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />
    <excludes file="${decorators-file}" />

    <page-parsers>
        <parser content-type="text/html"
            class="com.opensymphony.module.sitemesh.parser.HTMLPageParser" />
        <parser content-type="text/html;charset=ISO-8859-1"
            class="com.opensymphony.module.sitemesh.parser.HTMLPageParser" />
    </page-parsers>

    <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
            <param name="config" value="${decorators-file}" />
        </mapper>
    </decorator-mappers>
</sitemesh>

이 예에서 유일하게 적용된 mapper는 ConfigDecoratorMapper이다. 이 mapper는 웹페이지의 content-type이 text/html 이거나 text/html;charset=ISO-8859-1인 경우일때만 적용될 것이다. 다른 content-type(예, image/gif)의 page는 적용되지 않는다.

decorators.xml

부가적으로 패턴 매치를 이용하여 특정 파일들을 exclude하여 Sitemesh가 처리하지 않게 할 수 있다.
<excludes /> block을 이용하여 exlcude해야할 파일을 설정할 수 있다.

decorators.xml
<decorators>
    <excludes>
        <pattern>/plainPage.jsp</pattern>
        <pattern>/plain/*.jsp</pattern>
    </excludes>
</decorators>

/plainPage.jps와 /plain 디렉토리의 jsp 페이지는 장식이 전혀 되지 않는다. (패턴 매칭은 ConfigDecoratorMapper에서 사용되는 decorator 매핑처럼 정확하게 같은 룰을 따른다. )

일반적으로 <excludes /> 블럭은 decorators.xml 파일의 시작에서 추가되지만, 다른 XML 파일에서 정의할 수 있다.

디폴트 mapper 환경설정

만약 WEB-INF 디렉토리에서 sitemesh.xml이 발견되지 않으면, 디폴트 mapper 설정 화일이 사용되어 질 수 있다. 디폴트 mapper 환경설정파일의 정의는 sitemesh.jar안에 있는 sitemesh-default.xml의 설정파일이 적용된다. 그리고, 다음의 mapper들로 구성되어 진다.

  • PageDecoratorMapper
  • FrameSetDecoratorMapper
  • PrintableDecoratorMapper
  • FileDecoratorMapper
  • ConfigDecoratorMapper

디폴트로 오직 text/html 컨텐트 타입만 Sitemesh에 의해 decoration된다.

 

 

 

Freemarker 예제

Freemarker와 연동하여 decoration을 사용할 수 있다.

Freemarker lib

Freemarker lib을 사용한다.

web.xml 수정

WEB-INF/web.xml에 <web-app> 태그에 다음의 코드를 추가한다.

web.xml
<servlet>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <servlet-class>com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet</servlet-class>
	<init-param>
		<param-name>TemplatePath</param-name>
		<param-value>/</param-value>
	</init-param>
	<init-param>
		<param-name>default_encoding</param-name>
		<param-value>ISO-8859-1</param-value>
	</init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>sitemesh-freemarker</servlet-name>
    <url-pattern>*.dec</url-pattern>
</servlet-mapping>

decorators.xml 수정

\.dec 파일을 레퍼런스하여 decorators.xml을 수정한다.

decorators.xml
<#include "/includes/decorators/header.dec">
    <h2>${title}</h2>
    ${head}
    <img src="${base}/images/logo.gif" border="0">
    <td valign="top" class="body">
        <div class="header">
            <span class="pagetitle">${title}</span>
        </div>
        ${body}
    </td>
<#include "/includes/decorators/footer.dec">

Context

FreemarkerDecoratorServlet은 당신이 필요로 하게될 정보, 즉 Context object들을 저장한다.

기본 context 속성

모든 리쿼스트, 리쿼스트 파라미터, 세션, 서블릿 context 속성 그리고 어플리케이션 변수를 얻을 수 있다.

예)

${Session["user"]}

어플리케이션안에서, 세션안에서, 리쿼스트안에서 변수를 찾아낼 수 있고, 지정할 수 있다.

<#assign ww=JspTaglibs["/WEB-INF/webwork.tld"]>

JspTaglibs라고 하는 변수를 생성하고, JSP 태그 라이브러리에서 로드할 수 있도록 쓸 수 있다.

<#assign ww=JspTaglibs["/WEB-INF/webwork.tld"]>
...
<@ww.property value="myVar"/>

Sitemesh context 속성

base request.getContextPath()
title page title을 파싱한다. (<title>...<title>)
head page head를 파싱한다.
body page body를 파싱한다.
page SiteMesh의 내부 Page object 를 얻

'web' 카테고리의 다른 글

Sitemesh 참조자료  (0) 2007.08.24
Sitemesh #4 Sitemesh 팁  (0) 2007.08.24
Sitemesh #2 Sitemesh 소개  (0) 2007.08.24
Sitemesh #1 Tiles에서 Sitemesh로 변환하기  (0) 2007.08.24
multi-part/form-data  (0) 2007.08.23
Posted by '김용환'
,

Sitemesh #2 Sitemesh 소개

web 2007. 8. 24. 05:22

이글은 webwork,sitemesh를 기반으로 한 프레임워크에 적합한 내용입니다. 그리고, 이 글은 모든 내용이 다 맞지 않습니다.

한글 자료가 거의 전무하여 적어 놓게 되었습니다. 회사이름은 밝히기 않기 위해. 대충 가명썼습니다..

 

소개

SiteMesh는 web-page layout이고, decoration(장식) 프레임웍이고, 일관된 look/fee, navagation, layout scheme를 필요로 하는 많은 페이지로 구성된 큰 사이트를 만드는것을 도와주는 web-application 통합 프레임웍이다. 일관성있는 요소들때문에 조직화하고, 변화와 수정에 탁월해야 한다. Sitemesh,는 웹 서버에 요구된 정적/동적 요청을 가로채어 요청된 페이지 자원을 파싱하여 설정된 속성과 렌더링할 데이터를 컨텐츠로부터 읽어들여 원래의 페이지에 decoration과 수정을 가해 최종 페이지를 생성한다.

대부분의 HTML 문서는 다음과 같은 decorator 패턴 양식을 가지고 있다.

  • meta tags (keywords, description, author)
  • stylesheet (CSS)
  • header
  • navigation
  • footer
  • copyright notice

naviation과 layout 스킴만 정하면 나머지는 공통부분으로 따로 정리할 수 있도록 도와주는 프레임웍이 Sitemesh 이다.


Figure 1. Normal Page Rendering


Figure 2. SiteMesh Page Rendering

 

간단히 맛보기

기본적인 jsp 코드는 다음과 같다.

simple.jsp
<html>
    <head>
        <title>Simple Document</title>
    </head>
    <body>
        Hello World! <br />
        <%= 1+1 %>
        </body>
</html>

위의 코드의 템플릿으로 만들어지는 페이지를 데코레이션을 사용하여 jsp 페이지를 동적으로 승화시킬 수 있다.

decorator.jsp
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<html>
    <head>
        <title> My Site - <decorator:title default="Welcome!" /> </title>
        <decorator:head />
    </head>
    <body>
        <h1><decorator:title default="Welcome!" /></h1>
        <p><decorator:body /></p>
    </body>
</html>

첫번째 라인에 sitemesh 태그라이브러리가 소개되고, <decorator:title> 엘리먼트는 장식될 페이지의 <title> 엘리먼트의 텍스트를 가져와 삽입한다. <decorator:body> 엘리멘트는 페이지의 본문을 장식한다.

Sitemesh에 모든 패턴에 사용할 decorator를 WEB-INF/decorators.xml파일에 설정한다.

decorators.xml
<decorators>

    <decorator name="mydecorator" page="/decorator.jsp">
        <pattern>/*</pattern>
    </decorator>

<decorators>

이런 식으로 밑의 파일처럼 특정 디렉토리 또는 패턴에 따라 다양하게 decoration이 가능하다.

decorators.xml
<decorators defaultdir="/decorators">

    <decorator name="default" page="default.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="anotherdecorator" page="decorator2.jsp">
        <pattern>/subdir/*</pattern>
    </decorator>

    <decorator name="htmldecorator" page="html.jsp">
        <pattern>*.html</pattern>
        <pattern>*.htm</pattern>
    </decorator>

    <decorator name="none">
        <!-- These files will not get decorated. -->
        <pattern>/anotherdir/*</pattern>
    </decorator>
</decorators>

환경 설정

cvs서버로부터 test_project프로젝트를 update하고, 그 기반에서 동작하는 것을 기준으로 한다.

  • sitemesh.jar가 [web-app home directory]/WEB-INF/lib에 위치해 있는지 확인한다. (sitemesh 2.1.1 gl 버젼의 jar파일이 저장되어 있음을 확인할 수 있을 것이다.)
  • [web-app home directory]/WEB-INF/web.xml의 <web-app> 태그안에 다음의 내용이 추가되어야 한다. webwork-cleanup - sitemesh - webwork 의 순서대로 등록해야 한다.
    web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <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">
    
    .....fileter의 webwork-cleanup 정의 .....
             <filter>
    		<filter-name>sitemesh</filter-name>
    		<filter-class>
    			com.opensymphony.module.sitemesh.filter.PageFilter
    		</filter-class>
    		<init-param>
    			<param-name>pageEncoding</param-name>
    			<param-value>MS949</param-value>
    		</init-param>
    	</filter>
    
    .....fileter의 sitemesh 정의 .....
    
    
    .....filter-mapping의 webwork-cleanup 정의 .....
    	<filter-mapping>
    		<filter-name>sitemesh</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    .....filter-mapping의 sitemesh 정의 .....
  • [web-app home directory]/WEB-INF/sitemesh.xml 파일이 생성해야 한다. 필수 파일은 아니지만, 있어야 원하는 패턴을 지정할 수 있다.
    sitemesh.xml
    <sitemesh>
      <page-parsers>
        <parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
        <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
      </page-parsers>
    
      <decorator-mappers>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
          <param name="property.1" value="meta.decorator" />
          <param name="property.2" value="decorator" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
          <param name="match.MSIE" value="ie" />
          <param name="match.Mozilla [" value="ns" />
          <param name="match.Opera" value="opera" />
          <param name="match.Lynx" value="lynx" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
          <param name="decorator" value="printable" />
          <param name="parameter.name" value="printable" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
          <param name="decorator" value="robot" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
          <param name="decorator.parameter" value="decorator" />
          <param name="parameter.name" value="confirm" />
          <param name="parameter.value" value="true" />
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
        </mapper>
        <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
          <param name="config" value="/WEB-INF/decorators.xml" />
        </mapper>
      </decorator-mappers>	
    </sitemesh>
  • [web-app home directory]/WEB-INF/decorators.xml 파일이 생성되어야 한다.
    decorators.xml
    <decorators>
        <decorator name="defaultHeader" page="defaultHeader.jsp"/>
        <decorator name="defaultFooter" page="defaultFooter.jsp"/>
    
        <decorator name="default" page="default.jsp">
            <pattern>/*</pattern>
        </decorator>
    </decorators>

    헤더와 풋터 jsp를 지정한다.그리고, 디폴트 페이지를 모든페이지에 지정한다.

  • [web-app home directory]/WEB-INF/decorators 디렉토리에 템플릿으로 쓰일 default.jsp, defaultHeader.jsp, defaultFooter.jsp 파일을 생성한다.
    default.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    
    <head>
    <meta http-equiv=Cache-Control content=No-Cache>
    <meta http-equiv=Pragma content=No-Cache>
    <meta http-equiv="expires" content="0">
    <META HTTP-EQUIV="imagetoolbar" CONTENT="no">
    <meta http-equiv="Content-type" content="text/html; charset=euc-kr">
    <title><decorator:title default="퍼블 테스트" /></title>
    </head>
    
    <body bgcolor=ffffff bottommargin=0 topmargin=0 marginheight=0>
    <!-- TOP Menu -->
    <page:applyDecorator name="defaultHeader"/>
    <!-- //TOP Menu 영역 -->
    xxxx   <decorator:body/>   xxxx
    
    <!-- footer -->
    <page:applyDecorator name="defaultFooter"/>
    <!-- //footer 영역 -->
    </html>
    defaultHeader.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--head start-->
    Header<br>
    <!--head end-->
    defaultFooter.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <!--Footer start-->
    <br> Footer <Br>
    <!--Footer end-->
  • 하나의 액션 HelloWorld.java를 생성한다.
    HelloWorld
    import com.google.common.actions.GoogleBaseAction;
    
    public class HelloWorld extends GoogleBaseAction {
    	
    	public String execute() throws Exception {
    		return SUCCESS;
    	}
    }
  • [web-app home directory]/hello.jsp 코드를 작성한다.
    hello.jsp
    <%@ page language="java" pageEncoding="MS949" %>
    <%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
    <%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
    Hello World
  • 결과
    Web browser
    Header
    xxxx Hello World xxxx 
    Footer

Sitemesh의 설정 파일 설명

decorators.xml

decorators.xml 은 여러 decorator의 정의와 특정 decorator가 적용될 페이지의 리스트가 설정되어 있다. decorator의 순서에 따라 적용되어 진다.

decorators.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<decorators defaultdir="/decorators">
    <!-- Any urls that are excluded will never be decorated by Sitemesh -->
    <excludes>
        <pattern>/exclude.jsp</pattern>
        <pattern>/exclude/*</pattern>
    </excludes>

    <!-- decorator 태그안에 page의 경로는 web-app/decorators/main.jsp가 된다.-->
    <decorator name="main" page="main.jsp">
        <pattern>/*</pattern>
    </decorator>

    <decorator name="panel" page="panel.jsp"/>
    <decorator name="printable" page="printable.jsp"/>
    <decorator name="black" page="black.jsp"/>
    <decorator name="nopanelsource" page="nopanelsource.jsp"/>
    <decorator name="badpanelsource" page="badpanelsource.jsp"/>

    <decorator name="velocity" page="velocity.vm">
        <pattern>/velocity.html</pattern>
    </decorator>

    <decorator name="freemarker" page="freemarker.ftl">
        <pattern>/freemarker.html</pattern>
    </decorator>

    <decorator name="test" page="test.jsp">
        <pattern>/agent.jsp</pattern>
    </decorator>
</decorators>
  • decorators
    <decorators> 엘리먼트는 decorator들의 리스트를 정의하고 있다. <decorators defaultdir="/decorators">의 defaultdir="/decorators" attribute은 기본적으로 decorator page들이 위치하고 있는 경로를 나타낸다.
  • excludes
    <excludes> 엘리먼트는 decorator가 적용되지 않아야 할 패턴의 리스트이다.
    decorator name="main"의 main decorator는 모든 패턴의 리소스에 적용되며 main.jsp를 decorator page로 사용한다는 뜻이다.
    panel, printable, black, nonpanelsource, badpanelsource는 모두 패턴을 지정하지 않았고, freemaker, velocity는 특정페이지를 적용했다.
  • pattern
    <pattern> 엘리먼트는 decorator가 적용될 Request URI를 지정한다. 패턴이 적용되는 순서가 다르다. Request URI를 보고 다음의 순서대로 해당 decorator page를 찾게된다.
  1. 정확하게 단어가 맞는 패턴 (Exact word)
  2. 'abc*'나 'abc?'와 같은 컴플렉스 패턴 (Complext)
  3. '/', '*', '/*'와 같은 디폴트 패턴 (Default)

적절한 패턴이 설정되지 않은 decorator는 다른 decorator 내에서 <page:applyDecorator/>를 통해 포함할 때 사용되거나 decorator mapper(sitemesh.xml)에서 특정 decorator를 지정할 때 사용된다.

sitemesh.xml

sitemesh.xml은 decorator mapper 리스트가 설정되어 있다. 만일 Sitemesh가 해당 경로에서 설정 파일을 찾는데 실패하면sitemesh.jar 에 패키징 되어 있는 sitemesh-default.xml 파일로 대체된다.

sitemesh.xml
<sitemesh>
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />

    <page-parsers>
         <parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>

    <excludes file="${decorators-file}" />

    <decorator-mappers>
	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
	    <param name="property.1" value="meta.decorator" />
	    <param name="property.2" value="decorator" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper">
		<param name="match.MSIE" value="ie" />
		<param name="match.Mozilla [" value="ns" />
		<param name="match.Opera" value="opera" />
		<param name="match.Lynx" value="lynx" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper">
		<param name="decorator" value="printable" />
		<param name="parameter.name" value="printable" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper">
		<param name="decorator" value="robot" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
		<param name="decorator.parameter" value="decorator" />
		<param name="parameter.name" value="confirm" />
		<param name="parameter.value" value="true" />
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper">
	</mapper>

	<mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
		<param name="config" value="${decorators-file}" />
	</mapper>

	</decorator-mappers>
</sitemesh>
  • page parsers
    <page-parsers> 엘리먼트는 content-type에 따라 적용할 파서를 정의한다. SiteMesh는 현재 text/html을 파싱할 때 사용되는 FastPage Parser만 구현되어 있다. 나머지에 대해서는 디폴트로 DefaultPageParser가 사용가능하다.
    <page-parsers>
    	<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
    	<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
    </page-parsers>
  • decorator mapper
    decorator mapper는 Sitemesh에게 장식에 사용될 적합한 decorator를 설정해주는 역할을 한다. <decorator-mapper> 엘리먼트는 decorator mapper들을 정의한다. decorator mapper 추상 클래스는 링크드 리스트로 정의되어 있고, 적혀진 순서에 따라 decorator 체인으로 만들어진다.
    <decorator-mappers>
    	<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
    		<param name="property.1" value="meta.decorator" />
    		<param name="property.2" value="decorator" />
    	</mapper>
    </decorator-mappers>
    ....
  • excludes
    특정 웹 페이지(jsp)들을 모아 decoration이 적용되지 않도록 하는 설정파일을 지정한다.
    <excludes file="/WEB-INF/decorators.xml"/>
  • property
    변수화하여 쉽게 사용할 수 있도록 한다.
    <property name="decorators-file" value="/WEB-INF/decorators.xml" />
    ...
    <excludes file="${decorators-file}" />
    ...
    <mapper class="com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper">
    	<param name="config" value="${decorators-file}" />
    </mapper>

ConfigDecoratorMapper는 decorator 파일들을 config로 지정할 수 있음을 의미하며, 여러 개의 config 파일을 포함할 수 있다.

Decorator를 이용한 일관성있는 Look

jsp와 이미 기존에 쓰이고 있는 CGI script가 사용할 수 있도록 도와줌으로서, 일관성있는 look을 제공한다.

 

Flow Diagram

web.xml에서 정의된 필터, 즉 PageFiletr에 의해 Sitemesh가 사용되어진다.


페이지를 Page 객체에 파싱한 후 DecoratorMapper에 의해서 Decorator를 판단한다. 그래서 sitemesh.xml 파일에 DecoratorMapper 선언된 순서대로 decorator를 사용하고 mapper에서 결국 decorator를 얻지 못하면 본래 모습으로 보여준다. 주요 DecoratorMapper는 /WEB-INF/decorators.xml에서 decorator와 mapping을읽어들이는 ConfigDecoratorMapper 이다.

 

 

SiteMesh 구조와 흐름

  1. request 단계
    모든 request는 PageFilter에서 가로채어진다. PageFilter는 Context 초기화 시점에 decorator.xml에 정의된 <exclude> 태그에 따라 요청된 request의 url-pattern에 따라 장식을 수행할지 여부를 결정한다.
  2. paring 단계
    PageFilter는 요청된 자원에 대한 웹 어플리케이션의 수행결과를 do(request, respose) 메소드를 호출하여 받아낸다. 응답 파라미터에는 ServletResponse가 아닌 HttpServletResponseWrapper를 상속받아 확장한 PageResponseWrapper 객체를 사용한다.
    따라서 페이지 아웃풋은 writer로 보내지 않고 content-type에 따라 선택된 파서가 PageResponseWrapper에서 캡처된 page 아웃풋 데이터를 파싱한다. 현재는 반환 page의 content-type이 text/html일 경우만 FastPageParser가 작동한다.
  3. decorator 선정 단계
    적합한 decorator를 결정한다. 이 과정은 mapper 클래스의 getDecorator()에 의해서 이뤄진다. 처음 decorator 선정을 시도한 mapper 클래스가 적합한 decorator를 얻어낸다면 리턴하고, 아니면 decorator 체인상의 상위 링크의 getDecorator() 메소들르 호출하게 된다. 정확한 decorator가 결정될 때까지 반복된다.
  4. decorator 단계
    decorator를 얻오고, decorator로부터 decorator page를 구해 올 수 있다면, PageFilter는 applyDecorator()내에서 decorator 페이지에 대한 요청을 생성하고, decorator page는 FastPageParser에 의해 파싱된 결과 page의 적절한 부분들을 커스텀 태그를 통해 가져와 출력 페이지를 작성한다.

참조

http://today.java.net/pub/a/today/2004/03/11/sitemesh.html

마소의 sitemesh 기사

Posted by '김용환'
,

이글은 webwork,sitemesh를 기반으로 한 프레임워크에 적합한 내용입니다. 그리고, 이 글은 모든 내용이 다 맞지 않습니다.

한글 자료가 거의 전무하여 적어 놓게 되었습니다. 회사이름은 밝히기 않기 위해. 대충 가명썼습니다..

 

Concept

Tiles Layout은 만들어진 템플릿 jsp를 기준으로 extends 태그를 통해 확장하는 구조를 가지고 있는 반면, Sitemesh Layout은 action과 pattern을 이용하여 쉽게 장식을 할 수 있다. Lucy의 기본 프레임인 Webwork와 Sitemesh는 같은 Opensympony 프로젝트에 같이 포함되어 있어서 궁합(?)이 아무래도 Tiles보다는 높다.

Tiles는 특정 템플릿에 적용되는 여러 jsp(보통 하나의 Action에 해당되기도 한다.)에 일일히 지정해야 하는 불편함이 있어서, 환경설정 파일이 길어지는 단점이 있다. 하지만, Sitemesh는 action별로 분류하고, 서비스에 맞게 pattern(예, '*')을 지정하여 임의의 jsp 혹은 action을 그룹단위로 묶어 처리한다.

Tiles를 Sitemesh로 변환하기에 앞서 먼저 xwork.xml의 서술된 action과 result를 보고 활용해야 한다. Sitemesh는 요청받은 URL을 기준으로 처리하기 하기 때문에 action의 이름(예, index.gl)을 가지고 처리하는 것이 Sitemesh에서 쉽게 처리할 수 있다.
첫번째, 환경 설정을 먼저 해야 한다. Sitemesh를 쓰기 위해서는 당연히 web.xml에서 기술하고, 관련된 WEB-INF/web/sitemesh.xml 파일과 WEB-INF/web/decorators.xml 파일을 생성해야 한다.
두번째, Tiles 환경 설정파일(tiles.xml 라고 하자.)에서 Layout 템플릿을 Sitemesh 법칙에 맞게 변경한다. Tiles에 종속적인 태그라이브러리는 당연히 Sitemesh가 제공하는 태그 라이브러리로 바꾸면 된다.
그리고, Action과 jsp파일의 패턴을 템플릿에 적용시킨다.

간단하지 아니한가?! 이 글을 쓰는 시점에 game1을 Tiles에서 Sitemesh로 바꿨더니 줄 수가 1/3정도로 줄어들었다. 만약 처음부터 Sitemesh로 개발하면, 스크롤할 필요도 없이 잘 끝낼 수도 있다.

이 설명이 다인가 하고 놀랬을 터이지만, 놀라지 마라. 상세하고 친절한 설명이 계속 진행된다.

변환 가이드

1. web.xml에서 sitemesh를 적용한다.

  • 가장 먼저 tiles 관련 설정을 web.xml에서 제거한다.
  • [web-app home directory]/WEB-INF/web.xml의 <web-app> 태그안에 다음의 내용이 추가되어야 한다. webwork-cleanup - sitemesh - webwork 의 순서대로 등록해야 한다.
    web.xml
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <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">
    
    .....fileter의 webwork-cleanup 정의 .....
             <filter>
    		<filter-name>sitemesh</filter-name>
    		<filter-class>
    			com.opensymphony.module.sitemesh.filter.PageFilter
    		</filter-class>
    		<init-param>
    			<param-name>pageEncoding</param-name>
    			<param-value>MS949</param-value>
    		</init-param>
    	</filter>
    
    .....fileter의 webwork 정의 .....
    
    
    .....filter-mapping의 webwork-cleanup 정의 .....
    	<filter-mapping>
    		<filter-name>sitemesh</filter-name>
    		<url-pattern>/*</url-pattern>
    		<dispatcher>REQUEST</dispatcher>
    	</filter-mapping>
    .....filter-mapping의 webwork 정의 .....
    
    </web-app>

2. sitemesh.xml파일을 생성한다.

[web-app home directory]/WEB-INF/sitemesh.xml 파일을 생성한다.

디폴트로 여러 decoration 환경 설정을 포함할 수 없기 때문에, com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper 클래스를 사용해야 한다. 이 클래스는 <param> 태그의 이름을 오름차순 정렬하여 우선순위를 정하기 때문에, config.1, config.2 와 같이 우선순위가 높은 decorator를 지정할 수 있도록 해야 한다.

sitemesh.xml
<sitemesh>
	<excludes file="/WEB-INF/decorators.xml"/>

	<page-parsers>
		<parser default="true" class="com.opensymphony.module.sitemesh.parser.DefaultPageParser" />
		<parser content-type="text/html" class="com.opensymphony.module.sitemesh.parser.FastPageParser" />
	</page-parsers>

	<decorator-mappers>
		<mapper class="com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper">
			<param name="property.1" value="meta.decorator" />
			<param name="property.2" value="decorator" />
		</mapper>

		<mapper class="com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper">
			<param name="decorator.parameter" value="decorator" />
			<param name="parameter.name" value="confirm" />
			<param name="parameter.value" value="true" />
		</mapper>

                  <mapper class="com.google.common.sitemesh.mapper.MultipleConfigDecoratorMapper">
                            <param name="config.1" value="/common/decorators/decorators.xml" />
                            <param name="config.2" value="/WEB-INF/decorators.xml" />
                  </mapper>
	</decorator-mappers>
</sitemesh>

google 소스 트리에서 web/common/decorators/ 디렉토리에 공통으로 쓰일 decorators.xml 파일이 있고, 하위 폴더에 common-decorators 디렉토리가 있어 공통으로 쓰일 Layout 템플릿을 지정할 수 있다. 현재는 'underLayout'라는 이름으로 지정한 decorator page를 설정하고 있다.

web/common/decorators/decorators.xml
<decorators defaultdir="/common/decorators/common-decorators">
    <decorator name="underLayout" page="underLayout.jsp"/>
</decorators>

3. decorators.xml파일을 생성한다.

[web-app home directory]/WEB-INF/decorators.xml 파일을 생성한다. 정의된 defaultdir를 통해 파일안에서 상대 경로를 써서 Layout 페이지를 지정할 수 있다.

decorators.xml
<decorators defaultdir="/WEB-INF/decorators">
</decorators>

4. Tiles의 Layout 템플릿 정의를 Sitemesh의 decorator로 수정한다.

Tiles와 약간 다른 부분이다. Tiles는 임의의 파일을 메인 Layout 템플릿으로 지정하고, 이안에 저장될 스크립트, 상위메뉴, 우메뉴등등을 지정한다. 그리고, content 또는 body 부분을 "/"로 지정하여 extends한 Tiles 태그에서 적용될 jsp페이지를 적는다.

Sitemesh는 먼저 decorator 태그를 이용하여 태그를 지정하여 부분 Layout 템플릿을 정의한다. 그리고 나서, 메인 Layout 템플릿을 정의한다. 마지막으로 Tiles의 흔적이 남는 tiles디렉토리도 tiles에서 decorators로 변경해야 한다.

tiles.xml
<definition name=".layout.master.main" path="/WEB-INF/tiles/renewal_2006/layout/game1Layout.jsp">
    <put name="script" value="/share/tiles/game_script.jsp"/>
    <put name="common_activex" value="/common/common_activex.jsp"/>
    <put name="topmenu" value="/share/tiles/header_casual.jsp"/>
    <put name="rightmenu" value=".layout.master.rightmenu"/>
    <put name="content" />
    <put name="footer" value="/share/tiles/game1MainFooter.jsp"/>
</definition>
decorators.xml
<decorator name="script" page="/share/decorators/game_script.jsp"/>
<decorator name="common_activex" page="/common/common_activex.jsp"/>
<decorator name="topmenu" page="/share/decorators/header_casual.jsp"/>
<decorator name="rightmenu" page="renewal_2006/layout/rightMenuLayout.jsp"/>
<decorator name="footer" page="/share/decorators/game1MainFooter.jsp"/>
<decorator name="submenu" page="/share/decorators/right_casual.jsp"/>

<decorator name=".layout.master.main" page="renewal_2006/layout/game1Layout.jsp">
</decorators>

5. 메인 Layout 템플릿 소스를 Sitemesh의 정의에 맞게 수정한다.

game1Layout.jsp에 page 태그와 decorator 태그를 이용하여 수정한다. 쉽게 설명하면, page 태그는 이미 정의된 부분 Layout템플릿을 사용하는 것이고, decorators 태그는 실제 적용될 jsp 파일의 title, body 태그에서 정의된 내용을 참조하기 위함이다. (자세한 내용은 매뉴얼을 꼭 참조하라)

<tiles:insert> 일리먼트는 <page:applyDecorator> 일리먼트로 수정한다. 그리고, 실제 데이터가 들어갈 부분 content attribute을 <decorator:body/>로 바뀐다.

xwork.xml에서 action에서 result로 지정되어 dispatch된 jsp파일의 내용이 들어가게 된다. 이렇게 함으로서, tiles에 의존적이 않던 jsp 코드는 전혀 수정할 필요가 없게 된다. 만약, tiles.xml에서 정의된 content attribute에 정의된 show.jsp가 있다면, 이 내용 자체가 <decorator:body/>에 그대로 적용될 것이다. 유의할 점은 body 태그를 쓴다는 것이다.

Before,game1Layout.jsp,
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %>
<tiles:importAttribute scope="request" ignore="true"/>
<tiles:insert attribute="script"/>
<tiles:insert attribute="common_activex"/>
<tiles:insert attribute="topmenu"/>
<tiles:insert attribute="content"/>
<tiles:insert attribute="rightmenu"/>
<tiles:insert attribute="footer"/>
game/show.jsp
<script> 불라 불라 </script>
<table> 불라 불라 </table>
After,game1Layout.jsp
<%@ taglib prefix="decorator" uri="http://www.opensymphony.com/sitemesh/decorator" %>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/page" prefix="page" %>
<page:applyDecorator name="script"/>
<page:applyDecorator name="common_activex"/>
<page:applyDecorator name="topmenu"/>
<decorator:body/>
<page:applyDecorator name="rightmenu"/>
<page:applyDecorator name="footer"/>

6. 개별 페이지를 Layout템플릿에 적용시킨다.

  • Tiles의 definition이 Sitemesh의 decorator을 이용하여 메인 Layout 템플릿이 변경되었으니, 적용될 각 jsp 또는 action을 지정하면 된다. '*' 같은 pattern을 이용하여 Sitemesh를 잘 활용하여 한줄이라도 아껴쓰자.
    tiles.xml
    <definition name=".layout.master.main.goldwing" extends=".layout.master.main.goldwing.default">
    	<put name="gamegen" value="/WEB-INF/tiles/goldwinglayout/inpage/goldwinggen.jsp"/>
    </definition>
    decorators.xml
    <decorator name=".layout.master.main.goldwing.default" page="/WEB-INF/tiles/goldwinglayout/masterMainLayout.jsp">
             <pattern>goldwinglayout/inpage/goldwinggen.jsp</pattern>
             <pattern>/goldwing/*.gl</pattern>
    </decorator>
  • xwork.xml에 정의된 action을 이용하여 패턴화한다. xwork.xml에서 정의된 same Action을 참조하여 tiles.xml에서 사용되고 있음을 확인하고, decorators.xml에 decorator를 적용시킨다.
    xwork.xml
    <action name="same" class="com.google.game1.action.SameGameAction" >
    	<result name="main" type="tiles">.same.main</result>
    	<result name="iframe" type="tiles">.same.iframe</result>
    	<result name="rank" type="tiles">.same.rank</result>
    	<result name="includedrank" type="tiles">.layout.master.includedrank.casual</result>
    	<result name="search" type="tiles">.layout.master.searchrank.casual</result>
    </action>
    tiles.xml
    <definition name=".same.main" extends=".layout.master.main">
    	<put name="content" value="/same/layout/content_same.jsp"/>
    </definition>
    
    <definition name=".same.rank" extends=".layout.master.main">
    	<put name="content" value="/same/rank/rank_same.jsp"/>
    </definition>
    
    <definition name=".same.iframe" extends=".layout.master.main">
    	<put name="content" value=".layout.master.content.iframe"/>
    </definition>
    decorators.xml
    <decorator name=".layout.master.main" page="/WEB-INF/tiles/renewal_2006/layout/game1Layout.jsp">
    	<pattern>/same.gl</pattern>
    </decorator>
  • xwork.xml의 action을 수정한다
    xwork.xml에는 여전히 Tiles의 흔적이 남아 있다.바로 action의 result 태그에 type으로 지정되었다. 이를 dispatcher로 바뀌거나 아예 그 부분을 삭제한다. type을 지정하지 않으면, dispatcher 타입이다.
    Before,xwork.xml
    <action name="same" class="com.goole.game1.action.GoogleAction" >
    	<result name="main" type="tiles">.same.main</result>
    	<result name="iframe" type="tiles">.same.iframe</result>
    	<result name="rank" type="tiles">.same.rank</result>
    	<result name="includedrank" type="tiles">.layout.master.includedrank.casual</result>
    	<result name="search" type="tiles">.layout.master.searchrank.casual</result>
    </action>
    After,xwork.xml
    <action name="same" class="com.google.game1.action.SameGameAction" >
    	<result name="main">/same/layout/content_same.jsp</result>
    	<result name="iframe">/share/decorators/iframe_casual.jsp</result>
    	<result name="rank">/same/rank/rank_same.jsp</result>
    	<result name="includedrank">/share/rank/includedrank_casual.jsp</result>
    	<result name="search">/share/rank/searchrank_casual.jsp</result>
    </action>
  • 모든 jsp 파일에서 tiles에서 decorators로 변경된 path를 적용한다.
    이클립스를 검색을 이용하여 파일의 내용에 tiles가 들어간 xml, jsp파일을 검색해서 모두 변경해야 한다.
    Before, content_same.jsp
    <jsp:include page="/share/tiles/channel_casual.jsp"/>
    After, content_same.jsp
    <jsp:include page="/share/decorators/channel_casual.jsp"/>
  • Tiles의 insert 페이지를 변환한다.
    Tiles가 적용환 jsp파일에 <tiles:insert> 태그가 적용된 페이지를 <page:applyDecorator> 태그로 수정하고, decorators.xml에 decorator패턴으로 지정한다.
    jsp
    <tiles:insert page="/cross/bbs/pagelist.jsp"/>
    decorators.xml
    <decorator name="pageList" page="/cross/bbs/pagelist.jsp"/>
    jsp
    <page:applyDecorator name="footer"/>
  • 큰 Layout 템플릿에 속해 있는 일부 템플릿을 다른 템플릿으로 교체하는 경우
    Tiles는 이런 경우 extends를 이용하여 큰 Layout 템플릿을 extends하고, 해당 attribute만 put을 함으로서, overwrite가 가능하다. 그러나 Sitemesh는 새롭게 Layout을 설정해야 하고 서로 다르게 적용되어야 한다.
    예를 들어보자. 메인 Layout은 header, footer, rightmenu, leftmenu Layout을 사용하고 있다. 그 중 headerLayout만 다르고, 나머지 Layout은 같이 쓴다. a.jsp는 headerLayout.jsp라는 헤더 Layout을 사용하고, 그 외 모든 jsp 파일에서는 newHeaderLayout.jsp를 사용한다.
    메인 Layout에 <page:applyDecorator>를 이용하여 특정 템플릿 jsp를 정의한 decorator page을 정의만 할 수 있기 때문에(Tiles처럼 extends를 할 수 없음) a.jsp와 기타 jsp 파일은 서로 다른 메인 Layout을 사용해야 한다.
    <decorator name=".layout.master.main.goldwing.default" page="masterMainLayout.jsp">
    	<pattern>/a.jsp</pattern>
    </decorator>
    
    <decorator name=".layout.master.main.goldwing.default.norightmenu" page="masterMainLayout1.jsp">
    	<pattern>/*.jsp</pattern>
    </decorator>
  • Layout이 필요없는 페이지
    총 3가지 방법이 있다.
    • decorators.xml 파일에서 exclude 태그를 사용
    • jsp파일에서 메타 태그를 이용하여 decorator의 page가 null인 것을 지정
    • EmptyAction을 사용하여 page가 null인 decorator를 패턴으로 지정
      이 중, 첫번째 방법으로 Layout을 적용하는 것을 따로 빼어낼 수 있다.
under.jsp(common_google)
<%@ page language="java" pageEncoding="MS949" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Untitled</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<META name="decorator" content="underLayout"/>
<style>
...
...
decorators.xml
<decorators>
..
    <exclude>
        <pattern>/teasing.gl</pattern>
    </exclude>
...
 </decorators>
xwork.xml
<package name="empty" extends="com.google.news">
  <action name="teasing" class="com.google.news.action.auth.EmptyAction">
    <result name="success">/empty/m.jsp</result>
  </action>
</package>
  • ControllerURL 처리 방법
    • Inceptor 처리
    • 해당 controllerURL의 내용을 클래스로 전환.
  • Action에 Request 파라미터가 추다되어도 Sitemesh 적용
    search.gl action에 지정한 decorator 패턴에 그대로 적용된다.
    search.gl?m=list 의 경우도 <pattern>/search</pattern>와 똑같은 decorator를 사용한다. 따로 설정을 해 줄 필요 없다.

 

Posted by '김용환'
,

multi-part/form-data

web 2007. 8. 23. 03:34

제 자신을 위해서 좀 상세하게 씁니다.

 

<html>
<head>
<title>File manipulation test</title>
</head>

<body>
<form name="uploadForm" method="post" action="upload.jsp">
이름<input type=text name="name"><br>
전화번호
<input type=text name="phone"><br>
사진
<input type=file name="att"><br>
<input type=submit>
</form>
</body>
</html>

 

이것을 가능하게 만들기 위한 방법이 multipart/form-data 이며, 클라이언트(HTML) 서버모듈을 모두 고쳐주어야 하지요.

<html>
<head>
<title>File manipulation test</title>
</head>

<body>
<form name="uploadForm" method="post"
enctype="multipart/form-data"
action="upload.jsp">
이름<input type=text name="name"><br>
전화번호
<input type=text name="phone"><br>
사진
<input type=file name="att"><br>
<input type=submit>
</form>
</body>
</html>

 

서버에 다음의 형식으로 전송됩니다.

-----------------------------7d13603712507ca
Content-Disposition: form-data; name="name"
김용환
-----------------------------7d13603712507ca

Content-Disposition: form-data; name="phone"111-1111

-----------------------------7d13603712507ca

Content-Disposition: form-data; name="att"; filename="a.txt"

Content-Type: text/plain
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

 

스펙(http://www.w3.org/TR/html401/interact/forms.html#adef-enctype)을 보니까 enctype은 다음과 같이 나와있군요.

enctype = content-type [CI]

This attribute specifies the content type used to submit the form to the server (when the value of method is "post"). The default value for this attribute is "application/x-www-form-urlencoded". The value "multipart/form-data" should be used in combination with the INPUT element, type="file".

 

17.13.4에 잘 정리되어 있습니다.. 참고하세요

17.13.4 Form content types

17.13.4 Form content types

The enctype attribute of the FORM element specifies the content type used to encode the form data set for submission to the server. User agents must support the content types listed below. Behavior for other content types is unspecified.

Please also consult the section on escaping ampersands in URI attribute values.

application/x-www-form-urlencoded  

This is the default content type. Forms submitted with this content type must be encoded as follows:

  1. Control names and values are escaped. Space characters are replaced by `+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by `%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., `%0D%0A').
  2. The control names/values are listed in the order they appear in the document. The name is separated from the value by `=' and name/value pairs are separated from each other by `&'.

multipart/form-data  

Note. Please consult [RFC2388] for additional information about file uploads, including backwards compatibility issues, the relationship between "multipart/form-data" and other content types, performance issues, etc.

Please consult the appendix for information about security issues for forms.

The content type "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.

The content "multipart/form-data" follows the rules of all multipart MIME data streams as outlined in [RFC2045]. The definition of "multipart/form-data" is available at the [IANA] registry.

A "multipart/form-data" message contains a series of parts, each representing a successful control. The parts are sent to the processing agent in the same order the corresponding controls appear in the document stream. Part boundaries should not occur in any of the data; how this is done lies outside the scope of this specification.

As with all multipart MIME types, each part has an optional "Content-Type" header that defaults to "text/plain". User agents should supply the "Content-Type" header, accompanied by a "charset" parameter.

Each part is expected to contain:

  1. a "Content-Disposition" header whose value is "form-data".
  2. a name attribute specifying the control name of the corresponding control. Control names originally encoded in non-ASCII character sets may be encoded using the method outlined in [RFC2045].

Thus, for example, for a control named "mycontrol", the corresponding part would be specified:

Content-Disposition: form-data; name="mycontrol"

As with all MIME transmissions, "CR LF" (i.e., `%0D%0A') is used to separate lines of data.

Each part may be encoded and the "Content-Transfer-Encoding" header supplied if the value of that part does not conform to the default (7BIT) encoding (see [RFC2045], section 6)

If the contents of a file are submitted with a form, the file input should be identified by the appropriate content type (e.g., "application/octet-stream"). If multiple files are to be returned as the result of a single form entry, they should be returned as "multipart/mixed" embedded within the "multipart/form-data".

The user agent should attempt to supply a file name for each submitted file. The file name may be specified with the "filename" parameter of the 'Content-Disposition: form-data' header, or, in the case of multiple files, in a 'Content-Disposition: file' header of the subpart. If the file name of the client's operating system is not in US-ASCII, the file name might be approximated or encoded using the method of [RFC2045]. This is convenient for those cases where, for example, the uploaded files might contain references to each other (e.g., a TeX file and its ".sty" auxiliary style description).

The following example illustrates "multipart/form-data" encoding. Suppose we have the following form:

 <FORM action="http://server.com/cgi/handle"       enctype="multipart/form-data"       method="post">   <P>   What is your name? <INPUT type="text" name="submit-name"><BR>   What files are you sending? <INPUT type="file" name="files"><BR>   <INPUT type="submit" value="Send"> <INPUT type="reset"> </FORM>

If the user enters "Larry" in the text input, and selects the text file "file1.txt", the user agent might send back the following data:

   Content-Type: multipart/form-data; boundary=AaB03x   --AaB03x   Content-Disposition: form-data; name="submit-name"   Larry   --AaB03x   Content-Disposition: form-data; name="files"; filename="file1.txt"   Content-Type: text/plain   ... contents of file1.txt ...   --AaB03x--

If the user selected a second (image) file "file2.gif", the user agent might construct the parts as follows:

   Content-Type: multipart/form-data; boundary=AaB03x   --AaB03x   Content-Disposition: form-data; name="submit-name"   Larry   --AaB03x   Content-Disposition: form-data; name="files"   Content-Type: multipart/mixed; boundary=BbC04y   --BbC04y   Content-Disposition: file; filename="file1.txt"   Content-Type: text/plain   ... contents of file1.txt ...   --BbC04y   Content-Disposition: file; filename="file2.gif"   Content-Type: image/gif   Content-Transfer-Encoding: binary   ...contents of file2.gif...   --BbC04y--   --AaB03x--

 

Posted by '김용환'
,