posted by 희정냥★ 2012. 7. 7. 15:04


n
         
쿠키란?

ü        쿠키란 서버측에서 클라이언트측에 상태 정보를 저장하고 추출할 수 있는 메커니즘

ü        클라이언트의 매 요청마다 웹 브라우저로부터 서버에게 전송되는 정보패킷의 일종

ü        HTTP에서 클라이언트의 상태 정보를 클라이언트의 하드 디스크에 저장하였다가 필요 시 정보를 참조하거나 재사용할 수 있음.

ü        사용 예

       방문했던 사이트에 다시 방문 하였을 때 아이디와 비밀번호 자동 입력

       팝업에서 오늘 이 창을 다시 보지 않음” 체크

ü        쿠키의 제약조건

       클라이언트에 총 300개까지 쿠키를 저장할 수 있다

       하나의 도메인 당 20개의 값만을 가질 수 있다

       하나의 쿠키 값은 4096Byte까지 저장 가능하다


하나의 도메인에서 설정한 쿠키값이 20개를 초과하면 가장 적게 사용된 쿠키부터 지워짐또한 쿠키는 기존에 설정한 값이 있는 곳에 값을 저장하거나 배열형태의 쿠키에 단일 값을 저장하려고 할 때 아무런 경고 없이 덮어쓰기 때문에 주의를 해야 한다.


n         세션이란?

ü        세션이란 클라이언트와 웹서버 간에 네트워크 연결이 지속적으로 유지되고 있는 상태를 말함

ü        클라이언트가 웹서버에 요청하여 처음 접속하면 JSP(혹은ASP)엔진은 요청한 클라이언트에 대하여 유일한 ID를 부여하게 되는데이 ID를 세션이라 부른다

ü        세션 ID를 임시로 저장하여 페이지 이동 시 이용하거나클라이언트가 재 접속 했을 때 클라이언트를 구분할 수 있는 유일한 수단이 된다

ü        세션의 장점

       각각의 클라이언트마다 고유의 ID 부여

       세션 객체마다 저장해 둔 데이터를 이용하여 서로 다른 클라이언트의 요구에 맞게 서비스 제공

       클라이언트 자신만의 고유한 페이지를 열어놓아서 생길 수 있는 보안상의 문제 해결 용이


n         쿠키와 세션의 차이점

 쿠키(cookie)와 세션(session)은 기능상 비슷한 역할을 하고동작원리도 비슷하다왜냐하면일반적인 세션은 쿠키를 바탕으로 동작하기 때문이다그러나 가장 중요한 차이점은 저장되는 곳이 다르다는 것이다쿠키는 클라이언트에 저장되고세션은 서버에 저장된다쿠키의 경우에는 서버의 자원을 전혀 사용하지 않지만세션의 경우에는 서버에 저장되기 때문에 서버의 자원을 사용할 수가 있다쿠키와 세션의 만료 되는 기간도 다르다.


n         쿠키와 세션의 차이점()

구분

쿠키

세션

저장 위치

클라이언트

서버

저장 형식

텍스트형식

Object 

종료 시점

쿠키 저장 시 설정(설정하지 않으면 브라우저 종료 시 소멸)

정확한 시점을 알 수 없다

     

클라이언트의 자원을 사용

서버의 자원을 사용

용량 제한

한 도메인 당 20쿠키 하나 당 4KB,  300

서버가 허용하는 한 용량에 제한이 없음

 


* 출처 : http://cacung82.blog.me/10035514681

'Computer > Web' 카테고리의 다른 글

쿠키, 세션  (0) 2012.07.07
CSS3 미디어 쿼리  (0) 2012.07.07
반응형 웹(Responsive Web)  (0) 2012.07.07
구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29

댓글을 달아 주세요

posted by 희정냥★ 2012. 7. 7. 14:59

출력 장치의 여러 특징 가운데 일부를 참조하여 CSS 코드를 분기 처리함으로써 하나의 HTML 소스가 여러가지 뷰를 갖도록 구현할 수 있는 명세이다. 일반적으로 뷰포트 해상도에 따라 CSS 코드를 분기한다.

CSS 코드 내부에서 분기하는 방법

CSS 코드 내부에서 사용하는 미디어 쿼리의 기본적인 문법 예는 다음과 같다. 일반적으로 권장하고 널리 쓰이는 방식이다.

@media only all and (조건문) {실행문}

  • @media: 미디어 쿼리가 시작됨을 선언한다. @media, only, all, and, (조건문) 사이에 포함되어 있는 공백은 필수적이다.
  • only: only 키워드는 미디어 쿼리를 지원하는 사용자 에이전트만 미디어 쿼리 구문을 해석하라는 명령이며 생략 가능하다. 생략했을 때 기본 값은 only로 처리 된다. 생략해도 무방하므로 이 키워드는 일반적으로 작성하지 않는다. 이 자리에는 not 키워드를 사용할 수 있는데 뒤에 오는 모든 조건을 부정하는 연산을 한다.
  • all: all 키워드는 미디어 쿼리를 해석해야 할 대상 미디어를 선언한 것이다. all 이면 모든 미디어가 이 구문을 해석해야 한다. all 키워드 대신 screen 또는 print와 같은 특정 미디어를 구체적으로 언급할 수도 있다. all 키워드는 생략 가능하고 생략했을 때 기본 값은 all 으로 처리된다. 이 밖에도 다양한 미디어 타입(all, aural, braille, embossed, handheld, print, projection, screen, speech, tty, tv)이 있다. all, screen, print를 가장 널리 쓴다.
  • and: and 키워드는 논리적으로 ‘AND’ 연산을 수행하여 앞과 뒤의 조건을 모두 만족해야 한다는 것을 의미한다. 조건이 유일하거나 또는 only, all과 같은 선행 키워드가 생략되면 and 키워드는 사용하지 말아야 한다. and 대신 콤마 ‘,’ 기호를 사용하면 ‘OR’ 연산을 수행한다. ‘OR’ 연산은 나열된 조건 중에서 하나만 참이어도 {실행문}을 해석한다.
  • (조건문): 브라우저는 조건문이 참일때{실행문}을 처리하고 거짓일 때 무시한다. 조건문은 두 가지 이상 등장할 수 있다. 둘 이상의 조건문은 ‘and’ 키워드 또는 콤마 ‘,’ 기호로 연결해야 한다.
  • {실행문}: 일반적인 CSS 코드를 이 괄호 안에 작성한다. 브라우저는 (조건문)이 참일때 실행문 안쪽에 있는 CSS 코드를 해석한다.

CSS 코드 외부에서 분기하는 방법

조건문에 따라 별도의 외부 CSS 파일을 참조하여 분기하는 방법은 다음과 같다. 이 방식은 성능 최적화 측면에서 권장하지 않는다.

<link rel=”stylesheet” type=”text/css” media=”all and (조건A)” href=”A.css”>
<link rel=”stylesheet” type=”text/css” media=”all and (조건B)” href=”B.css”>

데스크탑 브라우저 사용자가 언제든 조건을 변경(예를 들면 창 크기를 조절해서 해상도를 바꿈)할 수 있기 때문에 웹 브라우저는 조건에 관계 없이 A.css 파일과 B.css 파일을 항상 요청한다. HTTP 요청을 불필요하게 두 번 발생시켜 이 페이지를 처음 로딩하는 사용자에게는 성능 저하의 원인이 된다. CSS 파일은 하나로 병합하고 CSS 코드 내부에서 조건 분기하는 방식을 권장한다.

미디어 쿼리 코드 템플릿

아래 코드는 모든 해상도를 커버하기 위한 미디어 쿼리 코드 템플릿이다. All, Mobile, Tablet, Desktop 으로 기기별 대응 코드를 분류 했지만 Liquid 레이아웃 기법을 사용하면 사실상 모든 해상도를 커버할 수 있다.

@charset “utf-8″;

/* All Device */
모든 해상도를 위한 공통 코드를 작성한다. 모든 해상도에서 이 코드가 실행됨.

/* Mobile Device */
768px 미만 해상도의 모바일 기기를 위한 코드를 작성한다. 모든 해상도에서 이 코드가 실행됨. 미디어 쿼리를 지원하지 않는 모바일 기기를 위해 미디어 쿼리 구문을 사용하지 않는다.

/* Tablet & Desktop Device */
@media all and (min-width:768px) {
사용자 해상도가 768px 이상일 때 이 코드가 실행됨. 테블릿과 데스크톱의 공통 코드를 작성한다.
}

/* Tablet Device */
@media all and (min-width:768px) and (max-width:1024px) {
사용자 해상도가 768px 이상이고 1024px 이하일 때 이 코드가 실행됨. 아이패드 또는 비교적 작은 해상도의 랩탑이나 데스크톱에 대응하는 코드를 작성한다.
}

/* Desktop Device */
@media all and (min-width:1025px) {
사용자 해상도가 1025px 이상일 때 이 코드가 실행됨. 1025px 이상의 랩탑 또는 데스크톱에 대응하는 코드를 작성한다.
}

조건문이 될 수 있는 특징들

width / height

뷰포트의 너비와 높이. 뷰포트의 크기는 HTML body 콘텐츠를 표시하는 영역으로 실제 스크린의 크기와는 다르다. 반응형 웹 구현시 가장 일반적으로 사용하는 조건이 된다.

  • Value: <length>
  • Applies to: visual and tactile media types
  • Accepts min/max prefixes: yes

Example:

@media all and (min-width:768px) and (max-width:1024px) { … } // 뷰포트 너비가 768px 이상 ‘그리고’ 1024px 이하이면 실행

@media all and (width:768px), (width:1024px) { … } // 뷰포트 너비가 768px 이거나 ‘또는’ 1024px 이면 실행

@media not all and (min-width:768px) and (max-width:1024px) { … } // 뷰포트 너비가 768px 이상 ‘그리고’ 1024px 이하가 ‘아니면’ 실행

device-width / device-height

스크린의 너비와 높이. 스크린은 출력 장치가 픽셀을 표시할 수 있는 모든 영역으로 일반적으로 HTML body 콘텐츠를 표시하는 뷰포트 보다 크다.

  • Value: <length>
  • Applies to: visual and tactile media types
  • Accepts min/max prefixes: yes

Example:

@media all and (device-width:320px) and (device-height:480px) { … } // 스크린 너비가 320px ‘그리고’ 높이가 480px 이면 실행

@media all and (min-device-width:320px) and (min-device-height:480px) { … } // 스크린 너비가 최소 320px 이상 ‘그리고’ 높이가 최소 480px 이상이면 실행

orientation

뷰포트의 너비와 높이 비율을 이용하여 세로 모드인지 가로 모드인지를 판단한다.

  • Value: portrait | landscape
  • Applies to: bitmap media types
  • Accepts min/max prefixes: no

Example:

@media all and (orientation:portrait) { … } // 세로 모드. 뷰포트의 높이가 너비에 비해 상대적으로 크면 실행

@media all and (orientation:landscape) { … } // 가로 모드. 뷰포트의 너비가 높이에 비해 상대적으로 크면 실행

aspect-ratio

뷰포트의 너비와 높이에 대한 비율. ‘너비/높이’ 순으로 조건을 작성한다. min/max 접두사를 사용하면 너비 값의 최소/최대 비율을 정할 수 있다.

  • Value: <ratio>
  • Applies to: bitmat media types
  • Accepts min/max prefixes: yes

Example:

@media all and (aspect-ratio:5/4) { … } // 뷰포트 너비가 5, 높이가 4 비율이면 실행

@media all and (min-aspect-ratio:5/4) { … } // 뷰포트 너비가 5/4 비율 이상이면 실행

@media all and (max-aspect-ratio:5/4) { … } // 뷰포트 너비가 5/4 비율 이하면 실행

device-aspect-ratio

스크린의 너비와 높이에 대한 비율. ‘너비/높이’ 순으로 조건을 작성한다. min/max 접두사를 사용하면 너비 값의 최소/대최 비율을 정할 수 있다.

  • Value: <ratio>
  • Applies to: bitmap media types
  • Accepts min/max prefixes: yes

Example:

@media all and (device-aspect-ratio:5/4) { … } // 스크린 너비가 5, 높이가 4 비율이면 실행

@media all and (min-device-aspect-ratio:5/4) { … } // 스크린 너비가 5/4 비율 이상이면 실행

@media all and (max-device-aspect-ratio:5/4) { … } // 스크린 너비가 5/4 비율 이하면 실행

color

출력 장치의 색상에 대한 비트 수. 출력 장치가 컬러가 아닌 경우 ’0′의 값에 대응한다.

  • Value: <integer>
  • Applies to: visual media types
  • Accepts min/max prefixes: yes

Example:

@media all and (color) { … } // 출력 장치가 컬러를 지원하면 실행

@media all and (color:0) { … } // 출력 장치가 컬러가 아니면 실행

@media all and (color:8) { … } // 출력 장치가 8비트 색상이면 실행

@media all and (min-color:8) { … } // 출력 장치가 8비트 이상 색상이면 실행

@media all and (max-color:8) { … } // 출력 장치가 8비트 이하 색상이면 실행

color-index

출력 장치가 색상 색인 테이블을 사용하는 경우 표현할 수 있는 색의 수. 출력 장치가 색상 색인 테이블을 사용하지 않으면 ’0′의 값에 대응한다. 현재 제대로 지원하는 브라우저가 없다.

  • Value: <integer>
  • Applies to: visual media types
  • Accepts min/max prefixes: yes

Example:

@media all and (color-index) { … } // 출력 장치가 색상 색인 테이블을 사용하면 실행

@media all and (color-index:0) { … } // 출력 장치가 색상 색인 테이블을 사용하지 않으면 실행

@media all and (color-index:256) { … } // 출력 장치가 256 색을 지원하면 실행

@media all and (min-color-index:256) { … } // 출력 장치가 256 이상 색을 지원하면 실행

@media all and (max-color-index:256) { … } // 출력 장치가 256 이하 색을 지원하면 실행

monochrome

출력 장치가 흑백인 경우 픽셀당 비트 수. 출력 장치가 흑백이 아니라면 ’0′의 값에 대응한다.

  • Value: <integer>
  • Applies to: visual media types
  • Accepts min/max prefixes: yes

Example:

@media all and (monochrome) { … } // 출력 장치가 흑백이면 실행

@media all and (monochrome:0) { … } // 출력 장치가 흑백이 아니면 실행

@media all and (min-monochrome:2) { … } // 출력 장치가 흑백이고 2비트 이상이면 실행

@media all and (max-monochrome:2) { … } // 출력 장치가 흑백이고 2비트 이하이면 실행

resolution

출력 장치의 해상력에 대응한다. min/max 접두사는 사각형 아닌 픽셀(인쇄 장치)에도 대응하지만 접두사 없는 resolution 조건은 사각형 픽셀에만 대응한다. 조건의 값으로 dpi와 dpcm 단위를 사용할 수 있다.

  • Value: <resolution>
  • Applies to: bitmap media types
  • Accepts min/max prefixes: yes

Example:

@media all and (resolution:96dpi) { … } // 1인치당 96개의 사각형 화소를 제공하면 실행

@media all and (min-resolution:96dpi) { … } // 1인치당 96개 이상의 화소를 제공하면 실행

@media all and (max-resolution:96dpi) { … } // 1인치당 96개 이하의 화소를 제공하면 실행

scan

TV의 스캔 방식에 따라 대응한다. progressive 값은 초당 60회 수준의 고화질 스캔에 대응하고 interlace 값은 초당 30회 수준의 일반 스캔에 대응한다. 대부분의 HDTV는 progressive와 interlace 방식을 모두 지원하고 있다.

  • Value: progressive | interlace
  • Applies to: “tv” media types
  • Accepts min/max prefixes: no

Example:

@media tv and (scan:progressive) { … } // 초당 60회 수준의 고화질 스캔 방식 TV에 대응한다

@media tv and (scan:interlace) { … } // 초당 30회 수준의 일반 스캔 방식 TV에 대응한다

grid

출력 장치가 그리드 방식이면 대응한다. 그리드 방식은 타자기와 같이 고정된 글꼴만 사용하는 장치이다. 통상 출력 장치는 비트맵이 아니면 그리드 방식이다. 값은 정수 ’0′과 ’1′ 뿐이고 ’0′의 값은 비트맵 방식에 대응한다.

  • Value: <integer> 0 | 1
  • Applies to: visual and tactile media types
  • Accepts min/max prefixes: no

Example:

@media all and (grid) { … } // 출력 장치가 그리드 방식이면 실행

@media all and (grid:0) { … } // 출력 장치가 그리드 방식이 아니면 실행

@media all and (grid:1) { … } // 출력 장치가 그리드 방식이면 실행


* 미디어 쿼리 속성 리스트

 width

 화면의 너비

 height

 화면의 높이

 device-width

 단말기의 너비

 device-height

 단말기의 높이

 orientation

 화면의 가로/세로 모드

 aspect-ratio

 화면 비율

 device-aspect-ratio

 단말기 화면 비율

 color

 색상 비트수

 color-index

 색상 테이블 엔트리 수

 monochrome

 모노크롬 프레임 버퍼의 픽셀당 비트수

 resolution

 화면 해상도

 scan

 TV의 스캔 방식

 grid

 그리드/비트맵 방식 여부



* 출처 : http://naradesign.net/wp/2012/05/30/1823/

http://blog.naver.com/clxm300?Redirect=Log&logNo=10141136099


'Computer > Web' 카테고리의 다른 글

쿠키, 세션  (0) 2012.07.07
CSS3 미디어 쿼리  (0) 2012.07.07
반응형 웹(Responsive Web)  (0) 2012.07.07
구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29

댓글을 달아 주세요

posted by 희정냥★ 2012. 7. 7. 14:55

반응형 웹(Responsive Web)의 등장 배경?
최근 다양한 모바일 기기가 보급되면서 하나의 사이트를 만들더라도 데스크탑 / 모바일 폰 / 타블렛 PC 등 서로 다른 해상도를 가진 디바이스들을 고려하지 않을 수 없게 되었다. 데스크탑 하나만 보더라도 와이드의 고해상도 디스플레이가 확산됨에 따라 많은 사이트들이 기존의 1024*768 크기를 넘어 점차 사이즈를 키워가고 있는 추세이지만 그렇다고 하나의 해상도에만 맞춰 사이트를 제작하기도 어렵다. 이렇듯 N-Screen의 시대로 불리는 다양한 디바이스의 해상도에 맞춰 사이트의 레이아웃을 변환하는 이슈에 맞춰 등장한 것이 반응형 웹(Responsive Web)이다.

 


반응형 웹(Responsive Web) 이란?
반응형 웹이란 HTML5의 “미디어 쿼리”를 이용하여 하나의 소스로 제작된 컨텐츠가 데스크탑에만 국한되지 않고 타블렛 PC, 모바일 폰 등 다양한 크기의 디바이스 환경에 맞추어 해상도나 화면이 동적으로 변환되는 기법을 말한다.

 

대표적인 예로 The Boston Globe 사이트를 보면 가로 길이에 따라 다음과 같이 레이아웃이 변화된다. 모바일 웹을 별도로 제작할 필요 없이 하나의 반응형 웹사이트로 사이즈에 맞춰 이미지나, 폰트, 사이즈 및 UI가 자동으로 변환되어 모든 디바이스에서 사이트를 이용할 수 있는 것이다.

 

 


 

반응형 웹의 주요 컨셉은 다음과 같다. (참고)
1. A flexible, grid-based layout : 그리드를 상대적(% 단위 등)으로 지정하여 브라우저 크기에 따라 유동적으로 변환 
2. Flexible width media: images, video : 너비가 변경되어도 웹페이지 안의 미디어가 넘치지 않게 하는 기법
3. Media queries : 다양한 브라우저에서 표현양식을 제어할 수 있게 고안된 기능

 

즉, 반응형 웹은 “유동형 그리드, 가변폭 이미지, 미디어쿼리 개념”을 하나로 묶고 체계화 시킨 용어이다. 그러나 반응형 웹에도 아직 극복해야 할 단점들이 있다. 가장 큰 문제는 IE8 이하에서는 사용이 불가능하다는 점이다. (참고)
1. 실제 사용되는 이미지보다 더 큰 이미지를 사용할 수 있다.
2. 이미지 리사이징은 단말기의 CPU를 보다 더 많이 사용한다.
3. 실제로 사용하지 않은 자원(이미지, CSS)을 전송 받을 수 있다.
4. 미디어 쿼리를 지원하지 않는 브라우저의 사용자가 많다 : CSS3의 속성으로 IE8 이하의 버전에서는 사용이 불가능

 

이와 같이 아직까지 미디어 쿼리를 지원하지 않는 브라우저의 사용자가 많기 때문에 기존의 데스크탑 사이트에 HTML5의 미디어 쿼리만 적용한다고 반응형 웹이라고 볼 수 는 없을 것이다. 일부에게는 반응하지 않는 사이트이기 때문이다.


 

반응형 웹(Responsive Web) 디자인 적용 사례 (참고)
# 1 Deren Keskin : 상단 메뉴의 변화가 눈에 띄며 사이트 전체의 이미지/텍스트의 변경이 자연스럽게 이루어진다.

 


 

dConstruct 2011 : 가로 폭에 따라 이미지가 리사이징되며 레이아웃도 변경되는 모습을 볼 수 있다.

 

 

 

#3 Naomi Atkinson : 실제로 브라우저의 가로 폭을 변경해보면 이미지 박스들이 이리저리 옮겨가는 모습을 볼 수 있다. 

 

 

 

#4 Neovada : 사이트 전체가 슬라이딩 방식으로 이루어져 있어 반응형 웹으로 구현하기 좀 더 용이해 보인다.

 


 

반응형 웹(Responsive Web)은 기획? Mobile First!
반응형 웹이 크게 이슈화 된 것도 결국은 모바일 웹 환경 때문이다. 앞서 언급했듯이 모바일 폰과 타블렛 PC를 위해 별도의 사이트를 제작해야 하는 번거로움을 반응형 웹이 대체할 수 있을 것이다. 그렇다면 이렇게 변화하는 사이트를 어떻게 기획해야 효과적인 결과물이 나올까?

 

 

 

“새로운 규칙은 모바일 우선이다 (We understand that the new rule is mobile first)”
 – 구글 CEO 에릭 슈미트(Eric Schmidt)

 

 

 

이번 포스팅을 위해 참고한 대부분의 자료가 “데스크탑용 사이트 + 미디어쿼리 = 반응형 웹”이 아닌 모바일 사이트를 먼저 고려하여 기본적인 사이트를 기획하고 이후 점차적으로 확장해가야 한다고 말하고 있다. 물론 이때 사이트의 사용성과 컨텐츠의 구조는 기본이다.

 

아직까지는 극복해야 할 한계들이 있는 상황(미디어 쿼리를 지원하지 않는 브라우저의 사용자 등)에서 국내에는 반응형 웹 디자인을 적용한 사이트가 많지는 않다(현대자동차 혹은 BLUEWAVE 참조). 하지만 피할 수 없는 N-Screen 시대에 최적화된 웹 환경 제공이 용이하고 기업에서는 노동과 비용을 줄일 수 있다는 장점이 있어 앞으로 반응형 웹의 발전은 필수가 되지 않을까 생각해 본다.


* 출처 : http://allje.tistory.com/109

'Computer > Web' 카테고리의 다른 글

쿠키, 세션  (0) 2012.07.07
CSS3 미디어 쿼리  (0) 2012.07.07
반응형 웹(Responsive Web)  (0) 2012.07.07
구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29

댓글을 달아 주세요

posted by 희정냥★ 2012. 7. 6. 19:36
구글 개발자 서르게이 브린 논문 번역

Abstract

웹 페이지의 '중요성'은 본질적으로 주관적인 문제여서 읽는 사람의 관심사나 지식 그리고 태도 등에 의존한다. 하지만 웹 페이지의 상대적 중요성에 관해서는 객관적으로 얘기할 수 있는 부분이 많다. 이 논문은 객관적이고 기계적으로 웹 페이지를 랭킹해서 읽는 사람의 관심이나 기울이는 주의를 효과적으로 측정할 수 있는 수단인 "PageRank"를 소개한다. 우리는 페이지랭크(PageRank)를 이상적인 랜덤 웹 써퍼(random web surfer)에 비교해 볼 것이며, 어떻게 많은 웹 페이지를 대상으로 PageRank를 능률적으로 계산할 수 있는지를 설명할 것이다. 그리고 어떤 방식으로 PageRank를 검색이나 사용자 네비게이션에 응용할 수 있는지도 보여 주고자 한다.

1. 도입과 동기(Introduction and Motivation)

월드와이드웹(World Wide Web)은 정보검색(Information Retrieval)에 새로운 과제를 안겨 주었다. 웹은 매우 거대하며 이질적(heterogenous)이다. 현재 추산으로도 약 1억5천만 페이지 이상이 웹에 존재하며, 이 숫자는 매년 적어도 두 배씩 커지고 있다. 더욱 중요한 점은, 웹 페이지들이 극단적으로 다양하다는 것이다. 예를 들면 "Joe가 오늘 점심 때 뭘 먹었지?"와 같은 질문이 있는가하면 정보검색에 관한 전문적 논문집이 있기도 하다. 이런 주된 도전 과제들 외에도 웹에는 익숙하지 못한 초보 사용자들과 검색 엔진의 랭킹 기능(ranking function)을 교묘히 이용하려는 많은 웹 페이지들로부터 비롯되는 문제점이 있다.

그러나 웹은 다른 "평면적"인 문서 컬렉션(flat document collections)과 달리 하이퍼텍스트가 있다. 하이퍼텍스트(hypertext)는 웹 페이지 자체의 텍스트 외에 링크 구조(link structure)나 링크 텍스트(link text)같은 상당한 수준의 부가적인 정보를 제공한다.

이 논문에서 우리는, 모든 웹 페이지를 보편적 "중요도" 순으로 순위를 매기기 위해 웹의 링크 구조를 사용하였다. 이 랭킹은 페이지랭크(PageRank)라 하며, 검색엔진 사용자나 웹 사용자가 거대한 이질적 세계인 월드와이드웹을 빠르게 이해할 수 있게 도와준다.

1.1 웹 페이지의 다양성(Diversity of Web Pages)

학술적 인용(academic citation)을 분석한 문헌은 이미 많이 존재하지만 웹 페이지와 학술 출판물 사이에는 많은 중요한 차이가 있다. 학술 논문은 철두철미하게 리뷰되지만 웹 페이지는 '품질 관리'나 '출판 비용' 없이 늘어난다. 단순한 프로그램 하나만으로도 아주 많은 페이지를 손쉽게 만들어 낼 수 있으며 인위적으로 인용 횟수를 쉽게 부풀릴 수 있다. 웹 환경 속에는 그 안에서 이익을 찾는 많은 벤쳐들이 있기 때문에 이들이 사용자의 주의를 끌어오는 전략 역시 검색엔진 알고리듬의 발달에 맞춰서 함께 진화되어 왔다. 이러한 이유로 복제가능한 특징을 세는 방식으로 웹 페이지를 평가하려는 전략은 손쉽게 악용될 수 있다. 게다가, 학술 논문의 경우는 그 갯수를 정확히 셀 수 있을 뿐만 아니라 사실상 질적인 면 및 인용 횟수 등에서 유사하고 그 목적 역시 비슷하다.(대개 '지식의 몸체'를 키우기 위한 목적으로 만들어진다.) 하지만 웹 페이지는 질적인 면에서나 사용적인 측면, 인용, 길이 등에 있어서 학술 논문보다 훨씬 더 다양하다. IBM 컴퓨터에 관한 애매한 질문들을 모아놓은 것은 IBM 홈페이지와 매우 다르다. 운전자에게 휴대폰이 미치는 영향에 관해서 연구한 논문은 특정 휴대폰 회사의 광고와 매우 다르다. 사용자가 읽은 웹 페이지의 평균적인 질은 평균적인 웹 페이지의 질보다 높다. 그것은 웹 페이지를 만들고 퍼블리슁하는 것이 매우 쉽기 때문에 웹에는 사용자들이 읽지 않으려 하는 많은 저품질의 웹 페이지가 있기 때문이다.

웹 페이지에는 여러 가지 분화될 수 있는 요소가 많이 있다. 이 논문에서 우리는 그 중의 하나 - 웹 페이지의 상대적 중요성을 어떻게 추산할 것인가 - 라는 문제를 주로 다룬다.

1.2 페이지랭크(PageRank)

웹 페이지의 상대적 중요성을 측정하기 위해 우리는 웹 그래프를 기반으로 웹 페이지를 랭킹(ranking)하는 방식인 페이지랭크를 제안한다. 페이지랭크는 검색이나 브라우징, 트래픽 추산에 적용될 수 있다. 섹션 2에서는 페이지랭크의 수학적 기술을 다룰 것이며 직관적인 정당화(intuitive justification)를 얘기할 것이다. 섹션 3에서는 5억1800만 개에 이르는 하이퍼링크에 대해 어떻게 효율적으로 페이지랭크를 계산할 수 있는지 보여주고자 한다. 페이지랭크의 유용성을 테스트하기 위해 우리는 구글(Google)이라는 웹 검색 엔진을 구축했다. 이것은 섹션 5에서 다룬다. 섹션 7.3에서는 페이지랭크가 어떻게 브라우징을 도울 수 있는지 보여주고자 한다.

2. 웹 상의 모든 페이지의 순위 매기기(A ranking for every page on the Web)

2.1 관련 자료

학술 인용 분석에 관해서는 매우 많은 연구가 이미 존재한다. Goofman은 과학 커뮤니티에서 일종의 유행병처럼 정보 흐름이 퍼져 나간다는 것을 주장한 흥미로운 이론을 발표하기도 했다.

웹 같은 대형 하이퍼텍스트 시스템에서 어떤 방식으로 링크 구조(link structure)를 이용할 수 있는지에 관해서도 최근들어 상당한 연구가 이뤄지고 있다. Pitkow는 얼마 전에 다양한 방식의 링크 기반 분석을 설명한 "월드와이드웹 생태계의 특징"이라는 제목의 박사 학위 논문을 완성했다. Weiss는 링크 구조를 감안한 클러스터링 방식에 대해서 논했다. Spertus는 여러 가지 적용사례에 있어서 링크 구조로 부터 얻어낼 수 있는 정보에 관해 발표했다. 좋은 시각화를 위해서는 하이퍼텍스트에 부가적인 구조가 필요하다는 연구도 있었다. Kleinberg는 웹을 서로 인용하는 행렬로 보고 그 고유벡터(eigenvector)를 계산하는 방식을 기반으로 "헙 & 오쏘리티(Hubs and Authorities) 모델"이라는 흥미로운 모델을 개발했다. 마지막으로, 도서관 커뮤니티 쪽에서는 웹의 "질"이라는 것에 대해 관심을 갖고 있기도 하다.

일반적인 인용 분석 테크닉을 웹의 하이퍼텍스트적 인용 구조에 적용하고자 시도하는 것은 너무도 자연스러운 것이다. 단순하게 웹 페이지에 있는 각각의 링크를 학술적 인용처럼 생각해 볼 수 있는 것이다. 야후! 같은 메이져 페이지는 야후!를 가리키는 수 만, 수십 만 개의 백 링크(backlinks) 또는 인용을 갖고 있는 것이다.

야후! 홈페이지가 아주 많은 백 링크를 갖고 있다는 사실은 야후! 홈페이지가 매우 중요하다는 사실을 함축한다. 사실 많은 웹 검색엔진들은 어떤 페이지가 얼마나 중요한가 내지는 높은 질을 갖고 있는가를 판단할 때 백 링크 숫자를 바탕으로 가중치를 주고 있다. 하지만 단순히 백 링크의 갯수를 세는 것은 많은 문제점을 갖는다. 이 문제점들은 학술 인용 데이타베이스에는 존재하지 않는 웹만의 특징과 관련이 있는 것들이다.

2.2 웹의 링크 구조(Link Structure of the Web)

약간의 편차는 있지만 현재 크롤링 가능한 웹 그래프는 약 1억5천만개의 노드(node;페이지)와 17억 개의 엣지(edge;링크)가 있다고 알려져 있다. 각각의 웹 페이지는 그 페이지로부터 밖으로 나가는 포워드 링크(forward link; outedges)와 그 페이지를 가리키는 백 링크(backlink; inedges)를 갖는다. 어떤 페이지의 모든 백 링크를 다 찾아낸다는 것은 불가능하지만 페이지를 다운로드하고 나면, 포워드 링크가 무엇인지는 알 수 있다.

backlink 백 링크

웹 페이지가 백 링크를 몇 개나 갖느냐는 매우 다양하다. 우리가 갖고 있는 데이타베이스에 따르면 넷스케잎 홈페이지는 62804개의 백 링크를 갖는데 반해 대개의 페이지들은 단지 몇 개의 백 링크만을 갖는다. 일반적으로 링크가 많이 된 페이지일수록 그렇지 못한 페이지보다 더 "중요하다". 학술 인용에서도 인용의 횟수를 세는 단순한 방법이 미래의 노벨상 수상자를 예측하는 데 사용될 수 있다. 페이지랭크는 인용 횟수를 세는 방식 이상의 훨씬 더 정교화된 방법을 제시한다.

페이지랭크가 흥미로운 이유는 인용 횟수가 일반적인 의미의 중요성과 일치하지 않는 경우가 매우 많기 때문이다. 어떤 웹 페이지가 야후!에 링크가 되어 있다면 그 페이지는 오직 하나의 백 링크밖에 없지만 그 링크는 매우 중요한 링크다. 야후!에 링크된 그 페이지는 다른 별 볼 일 없는 여러 곳에서 링크된 페이지보다 더 높은 순위를 가져야 한다. 페이지랭크는 링크 구조만을 사용해서 어떻게 "중요성"을 정확히 추정해낼 수 있을까를 시도한 것이다.

2.3 링크를 통한 랭킹의 전파(Propagation of Ranking through Links)

위의 논의를 기초로, 우리는 페이지랭크에 대한 직관적 기술을 다음과 같이 할 수 있다: 어떤 페이지가 높은 랭크의 백 링크를 많이 가질수록 그 페이지의 랭크도 올라간다. 이것은 어떤 페이지가 많은 백 링크를 갖는 경우와 몇 개의 높은 랭크값 백 링크를 갖는 경우 모두를 포괄하는 것이다.

2.4 페이지랭크(PageRank)의 정의

어떤 웹 페이지를 u라고 하고 u 페이지가 가리키는 페이지들의 집합을 Fu, u 페이지를 가리키는 페이지의 집합을 Bu라 하자. Nu = |Fu|라 하고, 이것은 u 페이지로부터 나가는 링크의 갯수, 즉 Fu의 갯수다. 그리고 노멀라이제이션에 사용되는 팩터를 c라고 하자.(노멀라이제이션은 전체 웹 페이지의 랭크 총합을 일정하게 하기 위해서다.)

일단, 단순 랭킹 R을 정의하는 것에서 출발해 보자. 단순 랭킹 R은 페이지랭크(PageRank)를 약간 단순화시킨 버전이다.

Simple PageRank

위 식은 전 섹션에서 얘기한 직관을 공식화한 것이다. 어떤 페이지가 가리키는 페이지들의 랭크에 균일하게 기여하기 위해, 링크가 나가는 페이지의 랭크를 그 페이지의 포워드 링크 갯수로 나누고 있다는 점에 주의하자. 그리고 c는 1보다 작아야 하는데, c < 1인 이유는 포워드 링크가 없는 페이지도 많이 있기 때문에 그런 페이지들의 가중치는 시스템 속에서 사라질 수 있기 때문이다.(섹션 2.7을 참조하라.) 위 등식은 재귀적(recursive)인 식이지만 초기 랭크 집합을 주고 수렴할 때까지 연산을 함으로써 계산할 수 있다.

단순 버전 페이지랭크

그림 2 단순화된 페이지랭크의 계산

단순 버전 페이지랭크의 계산
그림 3 정상상태를 이루고 있는 페이지들

그림 2는 한 쌍의 페이지로부터 다른 한 쌍의 페이지로 랭크가 전파되어 나가는 것을 보여주고 있다. 그림 3에서는 일군의 페이지들 사이에서 일정한 정상상태(steady state)의 솔루션을 이루고 있는 것을 볼 수 있다.

이것을 다른 방식으로 표현해 보자. 각 행과 열이 웹 페이지에 대응하는 정방행렬을 A라 하자. 그리고, 페이지 u에서 v로 가는 연결(edge)이 있다면 Au,v = 1/Nu이라 하고, 엣지가 없다면 Au,v는 0이라 하자. R을 웹 페이지들의 벡터로 생각해 보면, R = cAR이 된다. 그러므로 R은 A의 아이겐벡터(eigenvector; 고유벡터)가 되고 아이겐밸류는 c이다. 사실, 우리가 원하는 것은 A의 지배적 고유벡터(dominant eigenvector)다. 이것은 A를 여러 비퇴화적 시작 벡터(nondegenerate start vector)에 반복적으로 적용함으로써 계산될 수 있을 것이다.

랭크 싱크
그림 4 랭크 싱크

위에서 살펴 본 단순화된 랭킹 함수는 약간의 문제가 있다. 두 페이지가 서로서로 가리키고 있으며 다른 페이지로는 연결되어 있지 않은 경우를 생각해 보자. 다른 웹 페이지가 그 두 페이지 중 하나를 가리키고 있는 경우, 반복연산(iteration)이 진행되면서 그 루프에서는 랭크가 계속 축적될 뿐 외부로 전혀 분산하지 못 한다.(왜냐하면 외부로 나가는 엣지가 전혀 없으므로.) 루프는 일종의 함정을 형성하게 된다. 우린 이것을 랭크 싱크(rank sink)라 부른다. 랭크 싱크로부터 초래되는 문제를 해결하기 위해, 우리는 랭크 소스를 도입한다.

정의 1:
랭크의 소스에 해당하는 웹 페이지의 벡터 중 하나를 E(u)라 하자. 그러면 일군의 웹 페이지들의 페이지랭크는 다음 식을 만족하며 ||R||1 = 1(||R||1은 R'의 L1 norm)이고 c가 최대값을 가질 때의 R'이다.역자주

PageRank 페이지랭크

E가 모두 다 양수이면 등식의 균형을 위해서 c 값이 줄어들어야만 한다는 것에 주의하자. 그러므로 이 테크닉은 소멸계수(decay factor)에 해당한다. 위 식을 행렬 용어로 표현하면 R' = c(AR' + E)이고, ||R||1 = 1이므로 이 식은R' = c(A + E x 1)R'로 다시 쓸 수 있다. 여기서 1은 1로만 구성된 벡터다. 그러므로, R'은 (A + Ex1)의 아이겐벡터라고 할 수 있다.

역자주 L1 norm은 (a,b,c,d,e,..)라는 벡터가 있을 때 (a+b+c+d+e+..)의 값을 의미합니다. '소스'(source)와 '싱크'(sink)는 그래프 이론에서 나온 용어로, 아웃엣지가 없는, 즉 밖으로 나가는 링크가 없는 것을 싱크라 하고 반대로 인엣지가 없는, 즉 안으로 들어 오는 링크는 없고 밖으로 나가는 것만 있는 것을 소스라 합니다.

2.5 랜덤 써퍼 모델(Random Surfer Model)

위와 같은 페이지랭크의 정의는 그래프 상의 랜덤 워크(random walks)라는 또 하나의 직관적 기반을 갖고 있는 것으로 볼 수 있다. 단순화된 버전의 페이지랭크는 웹 그래프 상에서 랜덤 워크의 확률분포에 해당한다. 직관적으로 생각해 보면 이것은 "랜덤 써퍼"의 행동을 모델링한 것으로 볼 수 있다. "랜덤 써퍼"는 무작위로 일련의 링크들을 클릭해 나간다. 하지만 실제 웹 써퍼가 작은 루프에 빠져 들었을 때도 계속해서 그 루프 내를 맴돌 가능성은 거의 없다. 대신, 그 써퍼는 다른 페이지로 점프하려 할 것이다. 부가적 팩터인 E는 바로 그 행동을 모델링한 것으로 볼 수 있다. 즉, 써퍼는 주기적으로 "지루해지고" E의 분포에 기반해서 선택된 무작위 페이지로 점프하는 것이다.

지금까지 우리는 E를 사용자 정의 퍼래미터로 생각했다. 대부분의 테스트에서 우리는 E를 모든 웹 페이지에 걸쳐 동일하게 α값을 갖는 것으로 했다. 하지만, 섹션 6에서는, E 값이 달라짐에 따라 페이지의 랭크가 어떻게 "사용자화"될 수 있는지를 보여줄 것이다.

2.6 페이지랭크 계산(Computing PageRank)

페이지랭크를 계산하는 것은 규모의 문제를 무시한다면 아주 간단명료하다. S를 웹 페이지의 벡터(E 같은)라 하자. 그러면 페이지랭크는 다음과 같이 계산될 수 있을 것이다.


R0 <--- S
loop:
	Ri+1 <--- ARi
		d <--- ||Ri||1 - ||Ri+1||1
	Ri+1 <--- Ri+1 +dE
		δ<--- ||Ri+1 - Ri||1
while δ> ε

d 팩터가 수렴속도를 빠르게 하고 ||R||1을 유지하는 것에 주목하자. 또 다른 노멀라이제이션 방법은 적절한 팩터를 R에 곱하는 것이다. d의 사용은 E의 영향에 작은 효과만 미칠 것이다.

2.7 댕글링 링크(Dangling Links)

이 모델과 관계되는 이슈 중 하나는 댕글링 링크 문제다. 댕글링 링크란 외부로 나가는 링크가 없는 페이지를 가리키는 링크를 뜻한다. 댕글링 링크가 모델에 영향을 주는 이유는, 이것의 가중치가 어디로 분산되고 있는지가 불분명하고 또 아주 많은 댕글링 링크가 존재하기 때문이다. 종종 댕글링 링크가 가리키고 있는 페이지는 다운로드되지 않은 페이지일 수도 있다. 웹을 통째로 샘플링하는 것은 어렵기 때문이다.(현재 우리가 다운로드한 2400만 페이지에는 아직 URL이 가리키는 문서가 다운로드되지 않은 5100만 개의 URL이 있는 상태다. 즉, 5100만 개의 댕글링 링크가 있는 것이다.) 댕글링 링크는 다른 페이지의 순위에 직접적으로 영향을 주지는 않기 때문에, 우리는 모든 페이지랭크가 계산될 때까지 댕글링 링크를 그냥 제거했다. 페이지랭크 계산이 다 끝난 뒤에, 즉 큰 문제를 일으키지 않게 되었을 때, 댕글링 링크를 다시 첨가할 수 있다. 링크가 제거됨으로써 그 페이지에 있는 다른 링크의 노멀라이제이션이 영향받을 수는 있지만 크게 변화되는 건 아니다.

3 임플리멘테이션(Implementation)

스탠포드 웹 베이스 프로젝트(Stanford WebBase project)의 일환으로, 우리는 현재 총 2400만 페이지의 리파지터리(repository)를 갖고 있는 완전한 크롤링 & 인덱싱 시스템을 구축했다. 웹에 있는 모든 URL을 찾을 수 있게 하기 위해서는 모든 웹 크롤러가 URL 데이타베이스를 유지하고 있어야 한다. 웹 크롤러는 페이지랭크의 임플리멘테이션을 위해, 크롤링하면서 만나는 링크의 인덱스만 구축하면 된다. 작업 자체는 단순한 것이지만 볼륨이 거대하기 때문에 쉽지 않다. 예를 들어, 현재 우리가 구축한 2400만 페이지의 데이타베이스를 5일 안에 인덱싱하기 위해서는, 초당 50 페이지를 프로세싱해야 한다. 보통의 페이지 하나에 통상 11개의 링크가 있으므로(무엇을 링크로 셀 것인가에 따라 달라질 수는 있다.) 초당 550개의 링크를 프로세싱해야 하는 것이다. 또한, 우리가 구축한 2400만 페이지의 데이타베이스는 7500만 개의 각기 다른 URL을 참조하고 있으며, 각각의 링크는 반드시 서로 비교되어야만 하는 것이다.

웹에 깊숙히 그리고 미묘하게 존재하는 결함들에 유연하게 대응할 수 있는 시스템을 구축하기 위해서 많은 시간이 걸렸다. 웹에는 한없이 커다란 싸이트, 페이지, 심지어 끝없이 계속되는 긴 URL들이 있다. 상당수의 웹 페이지가 잘못된 HTML을 담고 있기 때문에 파서(parser)를 디자인하는 것이 까다로왔다. 예를 들어, 우리는 URL에 /cgi-bin/이 들어 있는 경우 크롤링하지 않았다. 물론, 웹은 계속해서 변하고 있기 때문에 "전체 웹"을 정확하게 샘플링한다는 것은 불가능하다. 싸이트가 다운되는 경우도 있고, 어떤 경우는 자신의 싸이트를 인덱싱되지 않도록 해 놓기도 한다. 이런 모든 점에도 불구하고, 우리는 공개적으로 접근가능한 웹의 실제 링크 구조를 상당한 수준으로 표현했다고 생각하고 있다.

3.1 페이지랭크 임플리멘테이션

우리는 각각의 URL을 각기 유니크한 정수로 변환하고, 하이퍼링크의 페이지를 구분할 수 있도록 모든 하이퍼링크를 페이지의 정수 ID를 이용해서 데이타베이스에 저장했다. 임플리멘테이션에 관한 자세한 사항은 구글 검색엔진의 해부학 논문에서 밝혔다. 보통, 페이지랭크는 다음과 같은 식으로 임플리멘테이션했다.

먼저, 부모 ID(Parent ID)를 이용해서 링크 구조를 정렬한다. 그 다음, 앞에서 말한 것과 같은 이유로 링크 데이타베이스에서 댕글링 링크를 제거한다. (몇 번의 반복 작업만으로도 대부분의 댕글링 링크를 제거할 수 있다.) 그 다음, 랭크 값을 초기화한다. 초기화 값을 어떻게 할 것인가는 어떤 전략을 갖고 있느냐에 따라 달라진다. 수렴할 때까지 반복작업을 계속할 생각이라면, 일반적으로 초기값은 최종값에 영향을 미치지 않는다. 단지 수렴 속도만 빠르게 할 뿐이다. 하지만 초기값을 잘 선택하면 수렴과정의 속도를 높일 수 있다. 우리는 초기 할당값을 신중하게 선택하면 제한적 횟수의 많지 않은 반복 작업만으로도 아주 좋은 결과를 얻거나 더 나은 퍼포먼스를 만들어 낼 수 있다고 믿고 있다.

각 페이지의 가중치에 메모리를 할당한다. 우리는 단정도 부동소수점(single precision floating point) 값을 사용했고, 각각은 4바이트씩 할당했으므로 7500만 개의 URL은 곧 300메가바이트의 크기가 된다. 만약 모든 가중치를 담고 있을 만큼 램이 충분치 않으면 여러 번의 패쓰(pass)를 사용해도 된다.(우리가 임플리멘테이션한 것은 메모리의 절반과 2개의 패쓰를 사용했다.) 현재 진행 중인 단계의 가중치는 메모리에 저장되고, 전단계의 가중치는 디스크를 통해 리니어(linear)하게 억세스한다. 또한, 링크 데이타베이스 - 즉 알고리듬 정의에서의 A - 로의 모든 억세스도 정렬되어 있기 때문에 리니어하다. 그러므로 A 역시 디스크에 저장될 수 있다. 이러한 데이타 구조들이 매우 큰 크기임에도 불구하고, 리니어 디스크 억세스를 통한 각 반복작업에 걸리는 시간은 보통의 웍스테이션상에서 약 6분 정도면 된다. 가중치들이 수렴하고 나면, 다시 댕글링 링크를 추가하고, 랭킹을 재연산한다. 댕글링 링크를 되돌려 넣은 뒤에 필요한 반복 작업 횟수는 댕글링 링크를 제거하는 데 요구되었던 횟수와 똑같다는 점에 주의하라. 그렇지 않으면, 댕글링 링크의 일부는 가중치가 0이 될 것이다.

이상의 모든 과정은 현재의 임플리멘테이션의 경우 총 5시간이 소요된다. 수렴 조건을 덜 엄격하게 하고, 더 최적화를 한다면 계산속도는 더 빨라질 수 있을 것이다. 또는, 아이겐벡터를 추산하는 보다 더 효율적인 테크닉이 사용되어도 퍼포먼스가 더 좋아질 것이다. 어쨌든, 페이지랭크를 계산하는 데 필요한 코스트는 풀 텍스트 인덱스를 구축하는 데 필요한 것에 비하자면 아주 사소한 것이라 할 수 있다.

4 수렴 특성(Convergence Properties)

그림 5에서 볼 수 있는 것처럼, 3억 2200만개라는 큰 링크 데이타베이스를 합리적으로 감내할 만한 수준으로 수렴시키는 데 필요한 반복작업은 약 52회다. 데이타의 크기가 반이라면 대략 45회면 된다. 이 그래프를 통해서, 극단적으로 큰 크기의 컬렉션에서도 페이지랭크가 아주 쉽게 확장될 수 있다는 것을 알 수 있다. 스케일링 팩터가 대략 logn과 거의 선형관계를 이룬다.

페이지랭크의 수렴
그림 5 페이지랭크 연산의 수렴

페이지랭크 연산이 아주 빠르게 수렴한다는 사실로부터 파생되는 한 가지 흥미로운 점은 웹이 익스팬더양 그래프(expander-like graph)라는 점이다. 이 부분의 이해를 돕기 위해서 그래프 상의 랜덤 워크 이론의 간단한 개론을 살펴 보자. 자세한 것은 Motwani-Raghavan이 쓴 페이퍼를 참조하라.

그래프 상의 랜덤 워크는 스토캐스틱(stochastic)한 과정이다. 즉, 임의의 한 타임스텝에 우리는 그래프 상의 특정 노드에 서 있고, 다음 타임스텝에 어떤 노드로 이동할 것인지는 균일하게 무작위적으로 분포하는 아웃엣지 중 하나를 선택해서 결정하는 것이다. 만약 모든 (너무 크지는 않은) 서브셋 노드 S가 이웃(neighborhood; S에 속한 노드들로부터 아웃엣지를 통해 접근가능한 꼭지점들의 집합)을 가지고 있고, 그 이웃 노드의 크기가 |S|보다 α배 이상 크다면 그 그래프는 하나의 익스팬더(expander)라고 할 수 있다. 그리고 만약, 특히 가장 큰 아이겐벨류가 두 번째로 큰 아이겐벨류보다 충분히 더 큰 경우, 그 그래프는 좋은 익스팬젼 팩터를 갖고 있다고 볼 수 있다. 랜덤 워크가 빠른 속도로 그래프 상의 노드들의 제한된 분포로 수렴해 가면 그 그래프는 래피들리-믹싱(rapidly-mixing)하다. 또한 그래프가 익스팬더이고 아이겐벨류 분리(eigenvalue separation)를 갖고 있다면 그 랜덤 워크는 래피들리-믹싱인 경우라 할 수 있다.

이상의 내용을 페이지랭크 연산과 관련 지어 보자. 페이지랭크란 본질적으로, 웹 그래프 상의 랜덤 워크의 제한된 분포로 결정짓는 것이다. 어떤 노드의 중요도 랭킹이란, 본질적으로 충분히 시간이 흐른 뒤에 랜덤 워크가 그 노드에 있을 확률인 것이다. 페이지랭크 연산이 로그 시간 내에 종결될 수 있다는 사실은 랜덤 워크가 래피들리 믹싱이거나 그래프가 좋은 익스팬젼 팩터를 갖고 있다는 말이 된다. 익스팬더 그래프는 여러 가지 바람직한 특성을 많이 갖고 있기 때문에 웹 그래프와 관계된 연산을 함에 있어서 앞으로 다양하게 활용할 수 있을 것이다.

5 페이지랭크를 이용한 검색

페이지랭크의 주된 적용처는 검색이다. 우리는 페이지랭크를 활용한 두 가지 검색엔진을 임플리멘테이션했다. 하나는 단순한 타이틀 기반의 검색엔진이고 다른 하나는 풀 텍스트 검색엔진이다. 후자의 이름은 구글이다. 구글은 표준적인 IR 측정치, 근접성(proximity), 앵커 텍스트(웹 페이지를 가리키는 링크의 텍스트), 그리고 페이지랭크 등의 많은 요소를 바탕으로 검색 결과를 랭킹한다. 페이지랭크가 어떤 이점을 갖는지에 관한 포괄적인 유져 스터디는 이 논문의 범위를 벗어나지만, 몇 가지 비교 실험과 검색 결과 샘플을 이 논문을 통해 얘기해 보려 한다.

페이지랭크의 이점이 가장 크게 활용될 수 있는 부분은 덜 특화된 질의어(underspecified queries)를 처리하는 것이다. 예를 들어, "스탠포드 대학"이라는 질의어를 넣으면, 일반적인 검색엔진은 스탠포드가 들어 간 많은 페이지들을 결과로 보여 줄 뿐이다. 하지만 페이지랭크를 활용하면 스탠포드 대학 홈 페이지가 순위의 가장 위로 올라 오는 것이다.

5.1 타이틀 검색

페이지랭크가 검색에 활용되면 얼마나 유용한지를 시험해 보기 위해 우리는 1600만 페이지의 제목만을 사용하는 검색엔진을 만들어 보았다. 그 검색엔진은 질의어를 넣으면 문서 제목에 질의어가 들어 있는 모든 웹 페이지를 찾은 다음, 그 결과를 페이지랭크를 이용해서 정렬한다. 이 검색엔진은 아주 단순한 것이고 간단하게 구축할 수 있는데, 비공식적인 시험을 해 본 결과 놀랄 만큼 훌륭한 성능을 보여 주었다. 그림 6에서 볼 수 있는 것처럼 "University"라는 검색어에 대해 페이지랭크를 이용한 제목 검색엔진은 대표적인 대학들의 목록을 보여 준 것이다. 이 그림은 우리가 만든 MultiQuery 시스템으로, 두 개의 검색엔진에 동시에 질의를 할 수 있는 시스템이다. 그림의 왼 편에 있는 것이 페이지랭크를 기반으로 한 타이틀 검색엔진이다. 검색 결과에 있는 바 그래프와 퍼센티지는 탑 페이지를 100%로 잡고 페이지의 실제 페이지랭크 값에 로그를 취한 다음 노멀라이징한 값이다. 이 논문의 다른 곳에서는 계속 퍼센타일(percentile)을 사용했지만 여기서는 아닌 것이다. 그림의 오른 쪽에 있는 것은 알타비스타 검색엔진이다. 알타비스타의 검색 결과를 보면 "University"라는 질의어에 맷칭되는 무작위적으로 보이는 웹 페이지들 그리고 여러 써버의 루트 페이지가 보인다. (알타비스타는 퀄리티 휴리스틱으로 URL의 길이를 사용하는 것 같다.)

Multi Search
그림 6 "University" 검색어에 대한 결과 비교

5.2 랭크 머징(Rank Merging)

타이틀에 기반한 페이지랭크 시스템이 아주 훌륭한 결과를 보여 주는 이유는, 제목을 맷칭하는 것이 페이지의 높은 프리시젼을 보장하고, 페이지랭크가 페이지의 높은 품질을 보장하기 때문이다. 웹 검색에서 "University" 같은 질의를 하는 경우, 사용자가 살펴 볼 페이지보다 훨씬 많은 페이지들이 존재하기 때문에 리콜은 그다지 중요하지 않다. 리콜이 중요하게 요구되는 특화된 검색의 경우는 풀 텍스트에 대한 전통적인 정보검색 점수와 페이지랭크를 함께 적용할 수 있을 것이다. 구글 시스템은 그런 형태의 랭크 머징을 사용한다. 랭크 머징은 아주 까다로운 문제로 알려져 있어서 우리는 그런 형태의 질의어를 합리적으로 평가할 수 있게 구축하기 위해 상당한 노력을 부가적으로 기울여야만 했다. 하지만, 그런 형태의 질의어에 있어서도 페이지랭크가 상당히 도움이 된다고 생각된다.

5.3 몇 가지 샘플 결과

우리는 페이지랭크를 이용한 풀 텍스트 검색엔진인 구글을 이용해서 상당히 많은 테스트를 해 보았다. 완전한 형태의 유져 스터디는 이 논문의 범위를 벗어나지만, 몇 개의 샘플을 이 논문의 부록 A에 수록했다. 더 많은 질의어에 대한 결과를 원하는 분은 직접 구글을 테스트 해보면 된다.

표 1은 페이지랭크에 기반한 탑 15위 페이지 목록이다. 이 리스트는 1996년 7월 시점의 결과다. 최근 다시 페이지랭크를 계산해 보았을 때는 마이크로소프트가 넷스케잎보다 조금 더 큰 페이지랭크를 보여 주었다.

Top 15 페이지랭크
표 1

5.4 커먼 케이스(Common Case)

페이지랭크의 디자인 목표 중 하나가 질의어의 커먼 케이스를 잘 처리하게 한다는 것이었다. 예를 들어, 미시건 대학의 학생 관리자 기능 시스템의 이름에 "wolverine"이라는 게 들어 있었던 것으로 기억하고 있는 사람이 "wolverine"이라는 검색을 한다고 하자. 우리의 페이지랭크 기반 타이틀 검색엔진은 "Wolverine Access"를 검색 결과의 첫 번째로 보여 준다. 이것은 대단히 합리적이다. 왜냐하면 모든 학생들은 Wolverine Access 시스템을 사용하고 있고, "wolverine"이라는 질의를 한 사람이라면 Wolverine Access 페이지를 살펴 보려 할 가능성이 매우 크기 때문이다. 그런데 Wolverine Access 싸이트가 좋은 커먼 케이스라는 사실은 그 페이지의 HTML에는 전혀 담겨 있지 않다. 심지어 이런 형태의 메타 정보를 페이지 내에 담을 수 있는 방법이 있다고 하더라도, 이런 류의 평가에 있어서는 페이지를 만든 사람을 신뢰하기 힘들다는 게 문제가 된다. 웹 페이지를 만드는 많은 사람들이 자신이 만든 페이지가 웹에서 가장 훌륭하고 가장 자주 읽힌다고 주장할 것이기 때문이다.

wolverine이라는 것에 관해서 가장 많은 정보를 담고 있는 페이지를 찾는 것과 wolverine 싸이트의 커먼 케이스를 찾는 것은 전혀 다른 일이라는 사실이 중요하다. 웹의 링크구조를 통해 텍스트의 매칭 점수를 전파해 나감으로써 어떤 주제를 자세하게 다룬 싸이트를 찾아내는 흥미로운 시스템이 있다.(Massimo Marchiori. The quest for correct information on the web: Hyper search engines.) 그 시스템은 그런 과정을 통해 가장 중심적인 경로에 포함되는 페이지들을 결과로 보여주는 것이다. 이런 방식은 "flower" 같은 질의어의 경우 좋은 결과를 보여 준다. 즉, 그 시스템은 '꽃'이라는 주제를 자세히 다루고 있는 싸이트에 도달할 수 있는 경로 중 가장 좋은 것을 보여주는 것이다. 이것과 커먼 케이스를 찾는 접근법을 비교해 보자. 커먼 케이스 접근법은 꽃에 관한 정보대신 꽃을 구입하는 방법만이 담긴, 사람들이 가장 많이 찾는 꽃 판매 싸이트를 보여줄 지도 모른다. 두 가지 방식 모두 중요하다는 게 우리의 생각이고, 일반적 목적의 웹 검색엔진이라면 마땅히 위의 두 가지 태스크 모두에 있어서 만족스러운 결과를 보여줘야 한다고 생각한다. 이 논문에서는, 우리는 커먼 케이스적 접근법에만 집중하고 있다.

5.5 커먼 케이스의 하부 구성요소(Subcomponents of Common Case)

페이지랭크가 도움이 될 수 있는 커먼 케이스 시나리오가 어떤 성격을 갖는가를 생각해 보는 것은 무척 유익하다. Wolverine Access 싸이트처럼 가장 자주 사용되는 페이지 외에도, 페이지랭크는 협동적 오쏘리티 또는 신뢰할 수 있는 싸이트 역시 표현해 준다. 예를 들어, 사용자는 어떤 뉴스가 단지 뉴욕 타임즈 홈 페이지로부터 직접 링크되어 있다는 이유만으로 더 선호할 수 있다. 물론, 그 뉴스 페이지는 뉴욕 타임즈처럼 중요도가 높은 페이지로부터 링크되어 있다는 사실만으로 매우 높은 페이지랭크 값을 갖게 된다. 이것은 일종의 협동적 신뢰(collaborative trust)의 특성을 잡아내고 있는 것처럼 보인다. 왜냐하면, 신뢰도가 높고 권위 있는 소스로부터 언급된 페이지일수록 그 페이지의 신뢰도와 권위가 올라가기 때문이다. 유사하게, 페이지의 품질이나 중요도 역시 이런 류의 순환적 정의에 잘 부합되는 것 같다.

6 개인화된 페이지랭크(Personalized PageRank)

페이지랭크 연산의 중요한 요소 중 하나가 E이다. E는, 랭크 싱크처럼 아웃엣지가 없는 싸이클을 보충하기 위한 랭크 소스 웹 페이지의 벡터다. 한편, E는 랭크 싱크 문제에 대한 해결책으로써뿐만 아니라, 페이지랭크 값을 조정할 수 있는 강력한 퍼래미터이기도 하다. 직관적으로 보자면, E 벡터는 랜덤 써퍼가 주기적으로 점프해 가는 웹 페이지의 분포에 해당한다. 밑에서 살펴 보겠지만, 이것은 웹을 거시적으로 관찰하거나 특정 부분에 대해 집중적이고 개인화된 관찰을 하는 데 사용될 수 있다.

우리가 수행한 실험은 대부분 E 벡터를 모든 웹 페이지에 걸쳐 균일하게 ||E||1 = 0.15로 가정했다. 즉, 랜덤 써퍼가 주기적으로 또 다른 랜덤 웹 페이지로 점프하는 것을 가정한 것이다. 이것은 모든 웹 페이지가 단지 존재하고 있다는 이유만으로 똑같이 가치를 부여받는 것이므로 E를 무척 민주적으로 선택한 것이다. 이런 테크닉이 상당히 성공적이었기는 했지만 중요한 문제점도 갖고 있다. 관련 링크가 많은 어떤 웹 페이지들이 지나치게 높은 랭킹을 받을 수 있는 문제다. 예컨데, 저작권 관련 페이지나 상호간에 링크가 많이 된 메일링 리스트 모음 등이 여기에 해당한다.

또 하나의 극단적 형태로, E를 오직 하나의 웹 페이지로만 구성할 수 있다. 우리는 두 가지로 실험해 보았다. 하나는 넷스케잎 홈 페이지로 해 보았고 다른 하나는 유명한 컴퓨터 과학자인 존 맥카씨(John McCarthy)의 홈 페이지로 했다. 넷스케잎의 홈 페이지로 한 실험은, 넷스케잎을 기본 홈 페이지로 하고 있는 초보 사용자의 시각에서 페이지의 랭크를 만들어 내려는 시도를 한 것이다. 존 맥카씨의 홈 페이지를 이용한 실험은, 그의 홈 페이지에 있는 링크를 바탕으로 우리에게 상당한 문맥적 정보를 제공한 개인의 시각에서 페이지랭크를 계산한 것이다.

두 경우 모두, 위에서 말한 메일링 리스트 문제가 나타나지 않았다. 그리고 두 경우 모두에서, 각각의 홈 페이지가 가장 높은 페이지랭크 값을 나타냈으며 그 페이지로부터 직접 연결된 페이지들이 그 뒤를 이엇다. 그 다음 시점부터는 불균형은 줄어 들었다. 표 2는 각각의 경우에서 여러 페이지들의 페이지랭크 퍼센타일을 나타낸 것이다. 컴퓨터 사이언스에 관계된 페이지일수록 넷스케잎 쪽 랭크보다 매카씨 랭 크쪽이 더 높은 값을 갖고, 특히 스탠포드 대학의 컴퓨터 사이언스 학과와 관계되는 페이지는 더욱 높은 매카씨 랭크 값을 갖는 것을 볼 수 있다. 예를 들어 스탠포드 컴퓨터 사이언스 학과의 또 다른 교수의 웹 페이지는 매카씨 쪽 랭크가 넷스케잎의 경우보다 6 퍼센타일 더 높다. 그리고 페이지랭크 값을 퍼센타일로 표시한 것에 주의하자. 이렇게 한 것은 상위 순위에서 나타나는 페이지랭크 값의 큰 차이를 줄여서 표현하기 위해서다.

Netscape vs McCarthy
표 2

위와 같은 개인화된 페이지랭크는 개인화된 검색엔진처럼 다양하게 응용할 수 있을 것이다. 개인화된 검색엔진은, 단순히 북마크나 홈 페이지를 입력하는 것만으로 사용자의 취향을 상당 부분 효과적으로 추측해내서 사용자의 수고를 대폭 덜어줄 수 있을 것이다. "Mitchell"이라는 질의어로 시행한 예를 부록 A에 수록했다. 그 예를 보면, 웹 상에 "Mitchell"이라는 이름을 가진 사람이 아주 많음에도, 존 매카씨 교수의 동료인 존 밋첼 교수의 홈 페이지가 결과의 1위로 나타난 것을 볼 수 있다.

6.1 상업적 이익을 위한 조작

이런 형태의 개인화된 페이지랭크는 상업적 이익을 위해 조작하는 것을 사실상 완전히 차단할 수 있다. 높은 페이지랭크 값을 갖기 위해서는 중요한 페이지로부터 언급되거나 중요하지 않은 많은 페이지로부터 링크되어야만 한다. 최악의 경우, 중요한 싸이트에서 광고(링크)를 구입하는 형태의 조작이 있을 수 있겠지만 그건 비용이 소요되므로 충분히 조절 가능하다. 조작에 대한 이런 저항성은 정말로 중요한 특성 중 하나다. 왜냐하면 상업적 조작 때문에 많은 검색엔진이 골머리를 앓고 있으며 훌륭한 기능을 임플리멘테이션하는 것이 조작 때문에 매우 어려워지기 때문이다. 예컨데, 문서가 자주 업데잇되는 것은 매우 바람직한 특징임에도 검색 결과를 조작하고자 하는 사람에 의해 이런 특징이 남용되고 있는 것이다.

균일한 E로 할 것인지 아니면 단일 페이지 E로 할 것인지의 절충안으로 E를 모든 웹 써버의 루트 수준 페이지로 구성할 수도 있다. `이 경우, 어느 정도의 페이지랭크 조작이 가능하다는 것에 주의해야 한다. 많은 루트 레벨 써버를 확보해서 특정 싸이트로 링크하면 간단히 조작되기 때문이다.

7 적용(Applicaitons)

7.1 웹 트래픽의 추산

페이지랭크는 대략 랜덤 웹 써퍼에 해당하기 때문에(섹션 2.5 참조), 페이지랭크가 실제 사용도와 어떻게 대응되는지 알아 보는 것은 아주 흥미로운 일이다. 우리는 NLANR(NLANR)의 프록시 캐쉬로부터 얻은 웹 페이지의 접근 횟수를 페이지랭크와 비교해 보았다. NLANR 데이타는 미 전역에 있는 프록시 캐쉬에 있는 여러 달에 걸쳐진 기록으로, 11,817,665개의 각기 다른 URL에 관한 자료이다. 그 데이타에 따르면 가장 히트가 높은 것은 알타비스타로 638,657 히트다. 그 데이타베이스는 우리가 갖고 있는 7500만 개 URL 데이타베이스와 260만 페이지가 중복된다. 이들 데이타셋을 분석, 비교하는 것은 몇 가지 이유에서 대단히 까다로운데, 우선 캐쉬 억세스 데이타에 있는 많은 URL들이 무료 이메일 서비스에 있는 개인 메일을 읽기 위해 접근한 것들이라는 점이 있다. 그리고 중복된 써버 이름과 페이지 이름도 심각한 문제점이다. 불완전성과 편향됨은 페이지랭크 데이타와 사용도 데이타 모두에서 문제가 된다. 하지만, 몇 가지 흥미로운 트렌드를 볼 수 있었다. 캐쉬 데이타에서는 포르노그래프 싸이트들이 높은 사용도를 보였음에도 이들의 페이지랭크 값은 대부분 낮았다. 이것은, 사람들이 자신의 웹 페이지에 포르토그래피 싸이트로 링크하는 것을 원하지 않기 때문인 것으로 생각된다. 그러므로 페이지랭크와 사용도 데이타 사이의 차이점을 살펴 보는 것을 통해, 사람들이 보고는 싶어하는데 자신의 웹 페이지에서는 언급하고 싶어 하지 않는 게 어떤 것이 있는지를 알아낼 수 있을 것이다. 어떤 싸이트는 매우 높은 사용도를 갖는데 페이지랭크가 낮은 경우가 있다. netscape.yahoo.com 같은 게 그렇다. 이것은 아마도 우리 데이타베이스에 중요한 백 링크가 누락되어 있기 때문인 것 같다. 우리 데이타베이스는 웹 링크 구조이 일부분만을 담고 있기 때문이다. 사용도 데이타를 페이지랭크 계산의 시작 벡터로 사용하고 페이지랭크 연산을 몇 차례 반복하는 것도 가능할 것이다. 이렇게 하면 사용도 데이타가 채워주지 못 한 부분을 메꿀 수 있을 것이다. 어떤 식이 되었든, 이런 형태의 비교는 향후 연구를 위한 흥미로운 주제이다.

7.2 백 링크 예측자로써의 페이지랭크

페이지랭크는 백 링크의 예측자로써의 의미가 있다. "Efficient crawling through url ordering"(Junghoo Cho, Hector Garcia Molina, and Lawrence Page) 논문에서, 우리는 어떻게 웹을 효율적으로 크롤링할 수 있는지, 더 좋은 문서들을 먼저 크롤링할 수 있는지의 문제를 탐색했다. 우리는 스탠포드 웹에서 시행한 테스트를 통해서 페이지랭크가 단순히 인용 횟수를 세는 것보다 훨씬 더 좋은 미래 인용 횟수의 예측자라는 것을 알게 되었다.

실험은, 다른 정보 없이 단일 URL에서 출발해서 가급적 최적의 순서에 가깝게 페이지를 크롤링하는 것을 목표로 하고 있다. 최적의 순서란 평가함수에 따른 랭크 순서와 정확히 일치하는 순서로 페이지를 크롤링하는 것이다. 이 실험에서의 평가함수는 완전한 정보가 주어졌을 때의 인용 횟수 순서로 했다. 문제는, 평가함수를 계산할 정보를 완전히 알게 되는 것은 모든 문서를 크롤링한 다음이라는 점이다. 이렇게 불완전한 데이타를 사용해서 크롤링 순서를 정할 때, 단순히 이미 알고 있는 인용 횟수를 활용하는 것보다 페이지랭크를 이용하는 쪽이 더 효과적인 것으로 드러났다. 바꿔 얘기하자면, 심지어 측정 기준이 인용횟수를 세는 것일지라도, 페이지랭크가 인용회수를 직접 세는 것보다 더 좋은 예측자라는 얘기다! 이것의 이유는 페이지랭크의 경우 인용 횟수를 세는 것이 국소적으로만 최대화되는 것을 피할 수 있기 때문인 것 같다. 예를 들어, 인용 횟수를 직접 세는 경우에는 스탠포드 CS 웹 페이지들의 컬렉션 속에만 빠져 드는 경향이 있어서 그곳을 벗어나 다른 곳에 있는 인용 회수가 높은 페이지를 찾아 나서는 데 오랜 시간이 걸린다. 하지만 페이지랭크는 스탠포드 홈 페이지가 중요하다는 것을 금방 알게 되고, 그 하부 페이지들에게 우호적인 점수를 주기 때문에 더 효율적이고 광범위한 검색이 가능한 것이다.

이러한 인용 횟수의 예측자로써의 페이지랭크의 능력은 페이지랭크를 사용해야 하는 아주 설득력 있는 이유가 된다. 웹의 인용구조를 완전히 매핑하는 것은 아주 까다롭기 때문에, 인용 횟수를 직접 세는 것보다 페이지랭크가 훨씬 더 좋은 인용 횟수 근사치가 될 수 있는 것이다.

7.3 사용자 네비게이션: 페이지랭크 프락시(User Navigation: The PageRank Proxy)

우리는 사용자가 각 링크의 페이지랭크와 함께 부가적인 설명을 볼 수 있는 웹 프락시 애플리케이션을 개발했다. 그 애플리케이션은 아주 유용했는데, 사용자가 링크를 클릭하기 전에 관련 정보를 미리 알 수 있기 때문이다. 그림 7은 프록시 프로그램의 스크린샷이다.빨간 바의 길이는 URL의 페이지랭크 값에 로그를 취한 값이다. 그림을 보면 스탠포드 대학 같은 메이져 조직은 매우 높은 랭킹을 받게 되고, 뒤이어 리서치 그룹이, 그 다음으로 개인이 -개인의 경우 스케일의 최상단에는 교수가 위치한다 - 나타남을 알 수 있다. 또한 ACM이 스탠포드 대학보다는 높지 않지만 매우 높은 페이지랭크를 갖는 것도 볼 수 있다. 재미있는 것은, 아주 지명도가 높은 교수의 페이지가 심할 정도로 낮은 페이지랭크 값을 갖고 있는 것을 찾으면 URL이 잘못 되어 있는 것을 찾아낼 수 있다는 점이다. 결과적으로, 프락시 툴은 네비게이션 뿐만 아니라 페이지 제작에도 도움이 될 수 있는 것 같다. 이 프락시 애플리케이션은 다른 검색엔진의 결과를 살펴 보는 데에도 아주 유용하다. 그리고 야후의 리스팅 같이 링크가 매우 많은 페이지를 파악하는 데도 큰 도움이 된다. 프락시를 통해서 많은 링크 중 어떤 것이 더 흥미로운 것인지를 짐작할 수 있기 때문이다. 또는 자신이 찾고 있는 링크가 "중요도" 측면에서 어느 정도인지를 알 수도 있고, 훨씬 더 빠르게 페이지를 전체적으로 살펴볼 수 있다.

PageRank Proxy
그림 7 페이지랭크 프락시

7.4 페이지랭크의 다른 용도

페이지랭크의 최초 목표는 백 링크를 정렬해서, 만약 어떤 문서가 많은 백 링크를 갖는다면 그 중 어떤 것이 "최상"의 것인지를 찾아서 그걸 가장 먼저 보여주려는 것이었다. 그리고 우리는 그런 시스템을 임플리멘테이션했다. 페이지랭크를 기준으로 정렬된 백 링크를 살펴 보는 것은 경쟁을 파악하는 측면에서도 아주 흥미롭다. 예를 들어, 뉴스 싸이트를 운영하는 사람이라면 경쟁자가 확보한 중요한 백 링크가 어떤 것인지 지속적으로 관찰하고자 할 것이다. 또한, 페이지랭크는 사용자가 어떤 싸이트가 신뢰할 수 있는 것인지 아닌지 판단하는 데 도움을 준다. 예를 들어, 스탠포드 홈 페이지에서 직접 인용된 정보라면 아무래도 사용자가 더 신뢰하려 할 것이다.

8 결론

이 논문에서, 우리는 웰드 와이드 웹 상의 모든 페이지를 페이지랭크라는 단일한 숫자로 압축하고자 하는 담대한 작업을 다루어 보았다. 페이지랭크는 페이지의 컨텐트와 상관없이, 오직 웹의 그래프 구조 상의 위치에만 의존하는 모든 웹 페이지의 글로벌 랭킹이다.

페이지랭크를 사용함으로써 우리는 더 중요하고 중심적인 웹 페이지들을 더욱 선호하는 식으로 검색 결과를 정렬할 수 있다. 여러 실험을 통해서, 페이지랭크는 고품질의 검색 결과를 보여줌을 알 수 있었다. 페이지랭크의 기반이 되는 직관은 웹 페이지 외부에 있는 정보, 즉 일종의 피어 리뷰인, 백 링크를 사용한다는 것이다. 게다가, "중요한" 페이지들로부터의 백 링크는 평균적인 페이지들로부터의 백 링크보다 더 중요하며, 이것은 페이지랭크의 재귀적인 정의(섹션 2.4 참조)를 통해 확실히 구현되어 있다.

페이지랭크는 대부분의 질의어에 대한 답변이 될 수 있는 소수의 자주 사용되는 문서들을 분리해 내는 데에도 사용될 수 있다. 풀 데이타베이스는 작은 데이타베이스가 질의어에 적절히 응답할 수 없을 때만 참조되면 된다. 마지막으로, 페이지랭크는 클러스터의 센터로 사용할 수 있는 대표 페이지를 찾아내는 좋은 방법이 될 수도 있을 것이다.

페이지랭크는 검색 외에도 트래픽 추산이나 사용자 네비게이션 같은 다른 많은 곳에 적용될 수 있다. 또한, 웹을 특정 시점에서 바라볼 수 있는 사용자화된 페이지랭크 역시 만들어 낼 수 있다.

종합하자면, 페이지랭크를 이용한 실험은 웹 그래프의 구조가 다양한 정보검색 작업에서 매우 유용하게 사용될 수 있음을 보여 준다고 할 수 있다.


문서출처: 이명헌 경영스쿨 http://www.emh.co.kr/xhtml/google_pagerank_citation_ranking.html

'Computer > Web' 카테고리의 다른 글

CSS3 미디어 쿼리  (0) 2012.07.07
반응형 웹(Responsive Web)  (0) 2012.07.07
구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29
HTML5 웹소켓  (4) 2012.06.29

댓글을 달아 주세요

posted by 희정냥★ 2012. 6. 30. 00:04

* HTML5 WebStorage


클라이언트측에 데이터를 저장할 수 있는 기능이다.

키/값 쌍으로 데이터가 저장되고 키를 기준으로 데이터를 조회한다.


로컬스토리지(Local Storage): 영구 데이터를 저장하는 용도로 사용

window 전역객체의 localStorage 컬렉션을 이용해서 접근할 수 있다.


세션스토리지(Session Storage): 브라우저 컨텍스트에서만 유지.

window 전역객체의 sessionStorage 컬렉션을 이용해서 접근할 수 있다.


기존의 쿠키와 많이 비슷하지만 다음과 같은 점이 개선되었다.


1. 네트워크 트래픽 감조: 웹스토리지는 저장된 데이터를 서버에 전송되지 않는다.

2. 더 많은 저장 용량: 쿠키는 데이터의 개수와 용량에 제한(한사이트당 20개,4KB)을 두고 있지만, 

무제한은 아니지만 훨씬 더 큰 자료를 저장할 수 있도록 제약이 적다.

3. 더 긴 데이터 보존 기간: 만료기간이 없으므로 한번 저장한 데이터는 영구적으로 보관된다.

4. 객체 저장: 쿠키는 문자열만 저장 가능하지만 웹스토리지는 객체를 저장할 수 있다.


<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>HTML5-WebStorage</title>
<script type="text/javascript">


//Local Storage에 데이터 저장
function setLocalStorage(){
if(!!window['localStorage']){
var textBox = document.querySelector('#textBox1');
window.localStorage['key1'] = textBox.value;
}
}


//Local Storage 조회
function getLocalStorage(){
if(!!window['localStorage']){
var textBox = document.querySelector('#textBox2');
textBox.value = window.localStorage['key1'];
}
}

//Session Storage에 데이터 저장

function setSessionStorage(){
if(!!window['sessionStorage']){
var textBox = document.querySelector('#textBox3');
window.sessionStorage['key1'] = textBox.value;
}
}

//Session Storage 조회
function getSessionStorage(){
if(!!window['sessionStorage']){
var textBox = document.querySelector('#textBox4');
textBox.value = window.sessionStorage['key1'];
}
}
</script>
</head>
<body>
<input type="text" id="textBox1">
<button onclick="setLocalStorage()">Local Storage에 데이터 저장</button>
<br>
<input type="text" id="textBox2">
<button onclick="getLocalStorage()">Local Storage 조회</button>
<hr>

<input type="text" id="textBox3">
<button onclick="setSessionStorage()">Session Storage에 데이터 저장</button>
<br>
<input type="text" id="textBox4">
<button onclick="getSessionStorage()">Session Storage 조회</button>
</body>
</html>

'Computer > Web' 카테고리의 다른 글

반응형 웹(Responsive Web)  (0) 2012.07.07
구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29
HTML5 웹소켓  (4) 2012.06.29
CSS Box Model  (0) 2011.09.18

댓글을 달아 주세요

  1. 문정규 2012.07.17 20:30  Addr  Edit/Del  Reply

    좋은자료 잘 보고 갑니다.
    VD 근무하시군요? 반가워요.^^

posted by 희정냥★ 2012. 6. 29. 23:59

HTML5


-.  WebPage에서 WebApp로의 변화에 대응하는 해결책

-. 2012년 W3C에서 표준화 예정이나 현재 대부분 브라우저에서 제공.

   (IE는 버전 9에서 지원 예정, IE점유가 약한 모바일은 현재 지원한다고 보아야 함)

-. 현재 브라우저별 지원 수준이 틀리나, 향후 1 ~ 2년 내 변화 주시 필요.



HTML5의 주요기술


1. 캔버스

  -. 도형, 선, 글자, 이미지 등을 사각형에 그릴수 있다.

2. 웹 비디오

  -. 브라우저가 컨테이너와 코덱을 직접 지원한다.

3. 오프라인 웹App

  -. URL에 있는 리소를 PC 로컬에 캐싱하고 갱신한다.

  -. 인터넷 연결 단절시는 웹사이트가 아닌 로컬 캐싱에 접속한다.

4. 강력해진 웹폼

  -. 달력, 메일, 숫자, 진행바, 입력검증 기능 등을 테그가 지원한다.

5. 다양한 웹 App작성용 API

  -. Drag & Drop이 가능

  -. Communication api

  -. Web Storage: 로컬 저장소를 지원, 쿠기 수준 이상으로 용량 큼.

  -. Web Sql Database: 로컬 저장소를 SQL로 접근 가능한 랩퍼 제공, 현재 구글 기어.

  -. Web Workers: 백그라운드 프로세스 처리로, 쓰레딩이 가능.

  -. Web Socket

  -. Server Sent Events

  -. Geolocation API

  -. etc(file api, Xhttp…level2)


* 출처 : http://blog.naver.com/imdhnam?Redirect=Log&logNo=110104108968

'Computer > Web' 카테고리의 다른 글

구글 페이지랭크(PageRank) 알고리즘  (0) 2012.07.06
HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29
HTML5 웹소켓  (4) 2012.06.29
CSS Box Model  (0) 2011.09.18
CSS 선택자  (0) 2011.09.18

댓글을 달아 주세요

posted by 희정냥★ 2012. 6. 29. 23:49

1. HTML5 웹소켓

- 서버측에서의 복잡한 프로그래밍 없이 웹을 통해서 일반적인 TCP소켓과 같이 실시간 연결지향 양방향 전이중 통신을 가능하게 하는 기술

- 기존 웹브라우져에서 서버로 데이터를 요청하는 방식에 비해, 서버에서 브라우저로 데이터 전송이 가능

- HTTP 통신에서, 서버 통신중에 발생하는 불필요한 데이터인  파일 '헤더' 부분을 최대 1/1000 가량 줄일수 있음

-  웹소켓 기술 업체 카징(Kaazing)에서는 '카징 케이트웨이 HTML5 에디션'  런칭 발표, 본격적인 웹 소겟 시대를 알림


 

2. 웹 소켓과 (Ajax의 통신 객체인) XMLHttpRequest 의 속도 비교

http://bloga.jp/ws/jq/wakachi/mecab/wakachi.html  (크롬 or 사파리에서 실행)

웹 소켓이 대략 50배 이상 좋은 성능을 나타냄



3. 웹 소켓이 필요한 경우

Your web application has data that must flow bi-directional simultaneously.

- 실시간 양방향 데이터 통신이 필요한 경우

Your web application must scale to large numbers of concurrent users.

- 많은 수의 동시 접속자를 수용해야 하는 경우

Your web application must extend TCP-based protocols to the browser.

- 브라우저에서 TCP 기반의 통신으로 확장해야 하는 경우

Your web application developers need an API that is easy to use.

- 개발자에게 사용하기 쉬운 API가 필요할 경우

Your web application must extend SOA over the Web and in the Cloud.

- 클라우드 환경이나 웹을 넘어 SOA 로 확장해야 하는 경우



4. 지원 브라우저

IE와 오페라를 제외한 사파리,크롬,파이어폭스 최신버전에서 웹 소켓을 지원



그림1. 브라우저별 Web Sockeet 지원 현황 (출처: http://caniuse.com/)



5. 웹소켓 구현

서버연결
HTML5가 제공하는 WebSocket 객체를 통해 서버 연결 수행.

일반 통신은 ws, 보안 통신은 wss 프로토콜을 이용.
기본 포트 역시 http,https와 동일한 80,443을 이용.
var wSocket = new WebSocket("ws://yourdomain/demo");

- 데이터 송신
서버와 연결이 되면 데이터를 주고 받을 수 있게 된다. 

WebSocket 객체의 send 함수로 데이터를 서버로 송신.
wSocket.send("송신 메시지");

데이터 수신
서버에서 푸시(전송)하는 데이터를 받으려면 message 이벤트를 구현.
wSocket.onmessage function(e){ //매개변수 e를 통해 수신된 데이터를 조회할 수 있다 }

- 이벤트 제공
-- open 이벤트: 연결이 설정되면 발생
-- close 이벤트: 연결이 끊어지면 발생

- 웹 소켓을 이용하는 클라이언트 코드의 전체 모습

<script>
  var wSocket = new WebSocket("ws:yourdomain/demo");
  
  wSocket.onmessage = function(e){  alert(e.data);  }  

  wSocket.onopen = function(e){ alert("서버 연결 완료"); } 
  wSocket.onclose = function(e){ alert("서버 연결 종료"); }  

  function send(){ //서버로 데이터를 전송하는 메서드
    wSocket.send("Hello");
  }
</script>



6. 웹소켓 서버

웹 소켓은 일반적인 TCP 소켓과는 다른 프로토콜로 설계되었다. 

따라서 웹소켓 서버 사양에 맞게 새로 구현해야 한다.

- 웹 소켓 서버를 위한 오픈소스 모듈
pywebsocket

phpwebsocket

jWebSocket

web-socket-ruby

Socket.IO-node



7.  jWebSocket를 이용한 모듈
- 라이브러리 다운로드 : http://jwebsocket.org/ 
- jWebSocketServer : 자바로 구현된 웹 소켓 서버모듈

- jWebSocketClient : 자바스크립트로 구현된 웹 소켓 클라이언트 데모 

- jWebSocketFullSource : jWebSocket 라이브러리의 전체 소스코드 



8. jWebSocketServer 구동
- 아파치 웹서버나 톰켓을 이용하여 구동

- Stand-Alone 구동

- java 설정

 -- jre 1.6 이상.

 -- PATH에 java.exe 등록.

 -- 환경변수에 JAVA_HOME 설정 : 자바 ROOT

 -- 환경변수에 JWEBSOCKET_HOME 설정 : jWebSocket 루트 디렉토리


- Stand-Alone로 구동 예제
1) 다운받는 jWebSocketServer을 압축해제 

2) bin 폴더에 있는 jWebSocketServer.bat 파일을 명령프롬프트에서 실행 

3)  웹 소켓 서버의 구동됨.

4) 웹 소켓 서버와의 통신로그와 디버그 메세지 기록됨.
5) 실행창을 닫으면 서버 종료

* 참고 퀵스타트 : http://code.google.com/p/jwebsocket/wiki/QuickStart



9. jWebSocketClient 데모 테스트
- jWebSocketClient 다운 후 압축해제
- 채팅데모인 chat.htm 을 실행

두 개의 크롬 브라우저에서 각각 로그인 한 뒤, 채팅하는 모습




jWebSocket 에서 서버 연결을 위해 다음과 같은 url을 정의하고 있다
var lURL = jws.JWS_SERVER_URL + "/;prot=json,timeout=360000";
...
JWS_SERVER_URL: "ws://" + ( self.location.hostname ? self.location.hostname : "localhost" ) + ":8787"

ws 프토토콜

localhost, 8787포트로 연결

json 포맷과 타임아웃이 설정


포트 등 변경시 : \conf\jWebSocket.xml 파일 수정

상태 검사 : ws.readState == WebSocket.OPEN / CONNECTING / CLOSED


* 출처 : http://m.mkexdev.net/98

http://blog.daum.net/hopefullife/241


'Computer > Web' 카테고리의 다른 글

HTML5 WebStorage  (1) 2012.06.30
HTML5 주요기술  (0) 2012.06.29
HTML5 웹소켓  (4) 2012.06.29
CSS Box Model  (0) 2011.09.18
CSS 선택자  (0) 2011.09.18
Web 2.0 기반의 Presentation On The Web  (0) 2009.08.06

댓글을 달아 주세요

  1. june 2012.07.10 15:04  Addr  Edit/Del  Reply

    안녕하세요^^ 정보 감사합니다. 혹시..개인적 질문인데... jwebsocket나 websocket을 통해서 파일전송 관련된 예제나 참고할 만한 자료 있는 곳을 아시나요? 그럼 좋은 하루 보내세요^^

  2. Brad 2012.11.16 04:45  Addr  Edit/Del  Reply

    저 SOA는 서비스 지향 아키텍쳐를 말씀하시는것 같습니다!?

  3. 김영규 2013.01.31 17:20  Addr  Edit/Del  Reply

    많은 도움이 되었습니다. 감사합니다.^^

  4. 우왕 2013.12.24 18:21  Addr  Edit/Del  Reply

    감사합니다..^^

posted by 희정냥★ 2011. 9. 18. 23:15

각각의 엘리먼트를 문서에 배치하기 위해서는 Box Model 이라고 부르는 margin, padding 그리고 border 속성을 전체적으로 이해해야 합니다.

 

위의 그림에서 중요한 4가지는 content, padding, border, margin 입니다.

content : 순수한 콘텐츠
padding : 콘텐츠와 경계선 사이의 여백
border : 경계선
margin : 경계선 밖에서 박스모델의 최종 경계선까지의 여백
 

 <table width="300" cellpadding="0" cellspacing="0" border="0" align="center">
<tr>
 <td bgcolor="#EEEEEE">
  <div style="padding:10px; margin:10px; border:1px gray solid;">Box Model을 설명하기 위한 예제</div>
 </td>
</tr>
</table>
이 예제에서 padding값과 margin값을 변경해 보면 이 값이 어떤 부분을 의미하는지 이해할 수 있습니다.

'Computer > Web' 카테고리의 다른 글

HTML5 주요기술  (0) 2012.06.29
HTML5 웹소켓  (4) 2012.06.29
CSS Box Model  (0) 2011.09.18
CSS 선택자  (0) 2011.09.18
Web 2.0 기반의 Presentation On The Web  (0) 2009.08.06
syntaxhighlighter를 tistory에서 사용 하는 방법  (0) 2008.10.08

댓글을 달아 주세요

posted by 희정냥★ 2011. 9. 18. 23:13
CSS에서 가장 중요한 개념은 선택자(Selector)라고 할 수 있습니다. 선택자(Selector)가 있어야 선언된 CSS가 어디에 적용될지를 결정할 수 있기 때문입니다. 특히 CSS는 상속의 개념을 가지므로 선택자(Selector)에 대한 확실한 이해가 없이는 CSS를 제대로 활용하지 못합니다.

선택자(Selector)의 종류

선택자(Selector)는 아래와 같이 4개로 나누어볼 수 있습니다.

공통 선택자(Universal Selector)
타입 선택자(Type Selector)
ID 선택자(ID Selector)
Class 선택자(Class Selector)
 

공통 선택자(Universal Selector)
공통 선택자(Universal Selector)는 *로 표현되는 선택자입니다.

* { color: gray; }
위와 같이 정의하면 모든 element 에 color: gray; 라는 스타일을 지정한다는 의미입니다.

 

타입 선택자(Type Selector)
타입 선택자(Type Selector)는 p, div, span, table, td, form...등과 같은 HTML 태그를 선택하는 선택자 입니다.

p { color: gray; }
이런식으로 정의하면 P element에 color: gray; 라는 스타일을 지정한다는 의미입니다.

 

ID 선택자(ID Selector)
#이라는 지시어를 사용하면서 element의 아이디값을 지정해주면 됩니다. 즉 특정 element에만 스타일을 지정한다는 의미입니다. 

#gray_text { color: gray; }
위와 같이 지정하면 id 값이 gray_text 인 element에만 스타일이 적용됩니다.

 

Class 선택자(Class Selector)
.이라는 지시어를 사용하면서 element의 클래스값을 지정해주면 됩니다. 특정 element에만 스타일을 지정한다는 의미로 ID 선택자와 차이점이라면 클래스의 경우는 한 문서에 동일한 이름의 클래스가 여러개 위치해도 괜찮으나 아이디는 유일해야 한다는 차이가 있습니다.

.gray_text { color: gray; }
위와 같이 지정하면 클래스 값이 gray_text 인 element에만 스타일이 적용됩니다.

 

'Computer > Web' 카테고리의 다른 글

HTML5 웹소켓  (4) 2012.06.29
CSS Box Model  (0) 2011.09.18
CSS 선택자  (0) 2011.09.18
Web 2.0 기반의 Presentation On The Web  (0) 2009.08.06
syntaxhighlighter를 tistory에서 사용 하는 방법  (0) 2008.10.08
IE6,IE7 ,FireFox 에 대해 CSS 맞추기  (0) 2008.07.09

댓글을 달아 주세요

posted by 희정냥★ 2009. 8. 6. 16:31

* 과제소개 : Samsung Software Membership online 9th Exhibition
아래는 제가 2007년도에 멤버십 회원이 되고 나서 처음으로 했었던 과제이고,
2007년 5월부터 2007년 7월까지 진행했었습니다.
위에 링크되어 있는 온라인전시회 페이지에 소개된 내용입니다.


1. Introduction




웹 환경에서 프레젠테이션 문서를 제작함으로써 설치와 같은 환경의 제약이 없이 사용이 가능하며, 데이터 공유와 정보의 공개 등을 통한 새로운 사용자 컨텐츠 문화를 조성한다. 제작한 문서의 사용자간 공유 기능이 매우 뛰어난 장점이 있다. AJAX와 ASP .NET을 이용한 동적인 컨텐츠를 통해 표현의 제약을 뛰어 넘고, 나아가 여러 비즈니스 모델을 제시한다.




김정하  하승우  김희정 


 


            


이 서비스는 두 가지 측면의 문제를 해결하고자 기획되었다.


첫째, 프리젠테이션 프로그램의 로컬환경의 작업으로 인해 문서 및 정보의 사용자간 공유가 매우 힘들다는 점이다. 무거운 프로그램과 웹 환경에서 편집이 되지 않는 점 등이 웹 환경으로의 전환을 꾀하지 못한다는 단점이 있다.

둘째, 현재 존재하고 있는 온라인상의 많은 부분의 컨텐츠가 텍스트 위주의 정적인 컨텐츠이다. 또, 각 컨텐츠는 하나의 특징만을 가지는 독립적인 것이 대부분이다.

이 서비스를 통해 다양한 방법에서 표현할 수 있는 진정한 동적 컨텐츠를 생성하고자 하며 사용자간 데이터 공유와 정보의 공개 등을 통한 새로운 사용자 컨텐츠 문화를 조성하며, 서비스 제공자는 이를 통한 여러 상업적인 효과를 창출할 수 있다.



2. Development Description


본 과제는 웹 오피스 Web 2.0의 한 부분을 비중있게 다룬 작품이다.

많은 분야에서 이와 같은 모델이 연구되고 있지만 웹 오피스의 장점을 비즈니스 모델과 접목 시키는 부분에 대해서는 미흡한 것이 사실이다. 우리는 이에 착안하여 웹의 특성을 살린 사용자들간의 공유와 출판의 개념을 접목 시키고자 하였다. 또한, 관련 기술은 AJAX를 심도있게 다루었으며, ASP .NET을 이용하여 내부적인 비즈니스 로직을 제작하였다.

로컬 환경의 프로그램이 웹 환경으로 진화하면서 사용자들은 자신의 지식을 다른 사용자와 공유할 수 있으며, 이를 자신을 표현하고 나타내는 수단으로 사용할 수 있다. 또한 서비스 제공 업체에서는 관련 서비스를 이용하여 많은 비즈니스 모델을 구상할 수 있게 되었다.

이것은 바로 Web 2.0 의 개념을 가장 잘 표현한 부분이며, 이 작품에서 자신있게 보여주는 부분이다.



 

  



DB를 제외한 전체적인 3-Tier Architecture로 구성이 되어 있다. 이는 추후 서비스가 대형화 되었을 때를 대비하여 커넥션 풀링과 같은 부분을 고려하기 위함이라 할 수 있다.

1. UI

일반 사용자에게 보여지는 Web Site, PT문서작성, Open API를 포함한다. 사용자의 이벤트 등을 처리하며 입력 Data를 BIZ layer로 넘기거나 BIZ layer를 통해 Data를 조회한다.

2. BIZ

각종 업무단위로 묶여지며 입력 Data를 처리하고 처리된 Data를 DAC layer로 넘기거나 DAC layer를 통해 Data를 조회한다. AJAX처리를 위한 WebService BIZ와 일반적인 Web Site부분에서 사용될 BIZ부분으로 나누어지며 WebService BIZ는 다시 공용 BIZ를 사용하게 된다. 공용 BIZ는 COM+로 구성되며 Transaction 처리를 담당한다.

3. DAC

COM+과 SQL Helper을 통해 DataBase와의 Connection과 Connection Timeout등을 관리하며 Stored Procedure의 Parameter 생성과 호출을 담당한다.

4.  DataBase

MS SQL 2005로 구성된다.



 

5. XML

데이터베이스에서 문서를 불러오거나 사용자의 요구에 의해서 문서가 편집 되었을 때, 하나의 XML 문서의 형태로 데이터가 저장되어 제어를 할 한다. 또한 이렇게 제작된 XML 데이터를 바탕으로 사용자 디스플레이에 렌더링 된다.




  

1. 과제 목표

본 과제는 동기에서 볼 수 있듯이 Web 2.0 이란 기술을 활용해서 웹 오피스와 접목 시켰을 경우, 얼마나 많은 상승 효과를 보여줄 수 있는 지에 대한 증명을 목표로 하고 있다.

프로그램 측면에서 기본적인 텍스트와 이미지의 입력과 편리한 유저 인터페이스의 제공을 목표로 하고 있으며, 웹 컨텐츠 확보를 위한 포스팅과 사용자들간의 자료 공유에 중점을 두어 프로젝트의 기획을 하게 되었다.

또한, 데이터베이스의 확장성과 향후 서버의 확장을 고려하여 XML 문서의 형태를 분리 저장하고 로딩되는 과정에서 통합하는 형태로 자료구조를 설계하고자 하였다.

2. 과제 결과

2.1. UI

오피스 제품군을 사용하던 사용자들이 웹 환경에서 본 서비스를 사용하였을 때, 이질감을 줄이기 위해 최대한 편리한 UI를 제공해주고 있는데, 이와 같은 UI의 형태를 리본 UI라고 한다.

           

 

2.2. Editing

편집 기능에서는 로컬에서 제공되는 것과 같은 텍스트 입력과 이미지, 멀티미디어 등이 제공되며, 각 객체에는 애니메이션을 부여하여 동적인 문서를 제작할 수 있다.
또한, 이미지에 대한 그룹화와 스마트 아트를 지원하고 있으며, Redo/Undo 기능을 위한 메모리 스택을 제작하였다.

프리젠테이션 프로그램의 특성을 살려 분할 출력 기능이나 클립보드와 같은 기능 역시 제공을 하고 있다.

2.3. Viewing

제작된 문서는 다음과 같은 화면의 형태로 사용자에게 보여지게 된다.

좌측 하단에 현재 페이지가 나오고 있으며, 우측 하단에는 페이지 이동, 슬라이드쇼, 프린트 기능 등을 제공하고 있다.

               

 

2.4. Posting

사용자는 서비스 사이트에서 제공되는 문서를 포스팅 하여 자신의 블로그나 타 사이트의 게시판에 포스팅 할 수 있다. 이러한 기능을 통해 사용자들은 기존의 텍스트, 이미지가 아닌 새로운 형태의 매체를 접할 수 있게 된다.

               

 

2.5. Contents Upload

웹의 특징을 활용한 부분의 한 방법으로 컨텐츠의 업로드 기능이 있다.

사용자는 자신이 만든 도형이나 클립아트, 템플릿 등을 서버에 업로드를 할수 있으며 이를 이용하여 다른 사용자들과 공유를 할 수 있게 된다.

이러한 기능을 통해 사용자간의 데이터 공유의 활성화를 기대할 수 있으며, 이는 사용자들의 컨텐츠 제작의 질을 한층 더 향상 시킬 수 있다.

               

 

2.6. Task Sharing

다음 그림은 두명의 사용자가 하나의 문서를 동시에 작업할 수 있다는 것을 보여주고 있다.

파일 기반의 서비스의 경우 하나의 문서에 대해서 여러명이 동시에 작업을 할 경우에, 문서를 제작하고 통합하는 과정이 번거로웠다. 하지만 웹환경에서는 문서 작업을 원하는 사용자에게 편집 권한만을 부여해주는 행위 하나만으로 사용자간의 협업 시스템이 훌륭하게 이루어 지게된다.



 

2.7. Service Site

위에서 설명한 모든 기능을 서비스하기 위한 서비스 사이트를 제작하였으며, 이 사이트 역시 전반적인 AJAX 기술을 활용하여 제작하였다.

사용자의 편의성을 위해, 카테고리별 등록과 실시간 인기 검색어, 검색 자동완성 기능 등을 제공해 주고 있다.

 

 

[[applied technology]]

1. AJAX

서버와 클라이언트의 비동기 통신 방식인 AJAX 기술을 활용하여, PT 제작 부분의 전반적인 부분에 활용이 되었다.

본 프로젝트의 경우 데이터의 로딩과 저장을 하는 과정이 AJAX 기술을 가장 많이 활용한 부분이다. 이를 이용해 웹 상에서의 데이터 유실을 막을 수 있는 자동저장과 같은 기능을 구현하였다.

2. Vector Image 제작

웹 환경에서는 로컬 환경의 오피스 제품군과는 달리 벡터 형식의 이미지 처리를 지원하지 못한다.

때문에 이미지의 확대나 축소와 같은 기능을 사용자에게 제공하기 위해서는 사용자로부터 입력받은 마우스의 위치 데이터를 파악하여야 한다. 벡터 이미지 계산 수식을 적용하여 비즈니스 로직 부분에서 계산된 데이터를 바탕으로 렌더링 과정을 통해 브라우저로 실시간에 표시하게 된다.

3. COM+

3Tier Architecture 상에서 BIZ Layer 와 DAC Layer에 COM+ 기술을 적용하였다.

BIZ Layer에서는 데이터 처리상에 Transaction 을 담당하게 되고 DAC Layer에서는 Connection Pooling을 담당하게 되는데 이를 통해 대규모의 Data 및 다수의 동시접속자에 대한 처리를 할 수 있도록 설계하였다.




1. Software 

  [IDE] Visual Studio .Net 2005
  [Database] MS SQL 2005
  [Etc] JAVASCRIPT (AJAX 기술 포함)



3. Improvement



 

1. PPT 포맷 호환

현재는 자체 제작한 XML Document의 형태로 문서가 저장되고 있지만, 추후 업데이트를 통해 MS사의 PPT와도 호환이 가능하도록 구현할 예정이다. 이러한 호환이 가능해 질 경우 사용자들에게 편의성을 증가시키고, 서비스의 확대를 가지고 올 수 있다.

2. 모바일 장치와의 연동

웹 환경 어디에서든 적용이 가능하기 때문에 모바일 장치에서도 문서를 제작하거나 볼 수 있는 환경을 만들 수 있다.



4. Epilogue

 


1. 그래픽 환경

로컬 환경의 프로그램의 경우 벡터형태의 이미지로 이루어진 반면, 웹에서는 벡터 이미지를 표현해 주지 않기 때문에 이 부분을 처리하는데 어려움이 있었지만, 내부적인 계산 로직을 적용하여 해결할 수 있었다.

2. 표

사이즈의 조절과 같은 기능은 제공을 할 수 있지만, 표 안에 내용을 직접 삽입하는 등의 방법에서 많은 에로사항이 발생하였다. 이 부분에 대해서는 향후 적합한 방법을 모색중에 있다.

3. 텍스트 입력

텍스트 박스를 로컬 환경과 같은 모습으로 제작하기 위해서는 상당히 많은 기술적인 부분을 요구 했지만, 개발의 목적과 시간을 고려하여 텍스트 입력창을 따로 두었던 점이 약간의 아쉬운 점으로 남는다.

 

5. Manager's comment


 

현재 활발히 연구되고 있는 Desktop Client의 한 분야로써, 로컬 환경에서만 사용되었던 프로그램을 설치 없이 웹에서 사용할 수 있다는 점에 Web 2.0 개념을 접목시켜 사용자 측면의 편의성을 최대한으로 높였다. 기존의 파워포인트를 웹에서도 클라이언트처럼 실행할 수 있다는 것이 상당한 매력이다.
[SW멤버십 WEB2.0 공모전 금상]



 

'Computer > Web' 카테고리의 다른 글

CSS Box Model  (0) 2011.09.18
CSS 선택자  (0) 2011.09.18
Web 2.0 기반의 Presentation On The Web  (0) 2009.08.06
syntaxhighlighter를 tistory에서 사용 하는 방법  (0) 2008.10.08
IE6,IE7 ,FireFox 에 대해 CSS 맞추기  (0) 2008.07.09
CSS에서 브라우저 구별 (IE6, IE7, FIREFOX)  (0) 2008.07.09

댓글을 달아 주세요

posted by 희정냥★ 2008. 10. 8. 13:42
syntaxhighter란 홈페이지에 있는 소스코드를 아래와 같이 색상으로 구문 강조를 해 주는 기능 입니다.

  1. #include <stdio.h>   
  2. int main( int argc, const char* argv[] )   
  3. {   
  4.     printf( "\nHello World\n\n" );   
  5. }  


우선 아래 주소에 가서 현재 최신 버전인 SyntaxHighlighter_1.5.1.rar를 다운 받습니다.
 
     http://code.google.com/p/syntaxhighlighter/

가기도 귀찮으신 분은 아래 파일을 다운로드 받으시면 됩니다.

압축을 풀면 아래와 같이 3개의 디렉토리가 나옵니다.

사용자 삽입 이미지

여기서 Styles디렉토리를 css파일이 있습니다. 그리고 scripts와 uncompressed는 같은 내용의 자바스크립트가 들어 있습니다. 다른점은 내용이 압축이 되어 있고 없고 차이 입니다.
올리 때는 둘 중에 하나를 선택해서 올리시면 됩니다. 개인적으로는 scripts에 있는 파일을 올리시길 권장 합니다. 조금이라도 페이지 로딩 속도를 빠르게 하는게 좋으니까요. ^^;;
사용자 삽입 이미지

이제는 스크립트 파일을 업로드 하고 편집을 해 보겠습니다. 먼저 tistory의 스킨 메뉴로 가서 [HTML/CSS]를 선택 합니다.
사용자 삽입 이미지

html/css편집 모드에서 [파일 업로드] 버튼을 눌러 줍니다.
사용자 삽입 이미지

위와 같이 scripts 디렉터리styles디렉터리에 있는 모든 파일을 올려 줍니다.
캡쳐 공간이 부족해서 clipboard.swf파일은 빠졌네요 ^^; 그 파일도 역시 올려 줍니다.

업로드가 끝나면 다시 [HTML/CSS] 편집 모드로 돌아 갑니다.
사용자 삽입 이미지
여기서 페이지 상단에 css를 포함 하는 부분에 다음 줄을 추가 해 줍니다.


  1. <link type="text/css" rel="stylesheet" href="./images/SyntaxHighlighter.css"></link>  

위에 줄을 복사 하시면 됩니다.
사용자 삽입 이미지

그리고 페이지 하단에 </body>태그 위에 아래 문장을 복사 해 줍니다.
여기서 포함하는 스크립트의 순서는 별 지장이 없습니다. 하지만, 가장 위에 있는 shCore.js 파일의 위치는 항상 위로 올라가야 정상적으로 동작하는 것만 주의해 주시면 됩니다.

  1. <script class="javascript" src="./images/shCore.js"></script>  
  2. <script class="javascript" src="./images/shBrushCSharp.js"></script>  
  3. <script class="javascript" src="./images/shBrushCpp.js"></script>  
  4. <script class="javascript" src="./images/shBrushCss.js"></script>  
  5. <script class="javascript" src="./images/shBrushDelphi.js"></script>  
  6. <script class="javascript" src="./images/shBrushJScript.js"></script>  
  7. <script class="javascript" src="./images/shBrushJava.js"></script>  
  8. <script class="javascript" src="./images/shBrushPhp.js"></script>  
  9. <script class="javascript" src="./images/shBrushPython.js"></script>  
  10. <script class="javascript" src="./images/shBrushRuby.js"></script>  
  11. <script class="javascript" src="./images/shBrushSql.js"></script>  
  12. <script class="javascript" src="./images/shBrushVb.js"></script>  
  13. <script class="javascript" src="./images/shBrushXml.js"></script>  
  14. <script class="javascript">  
  15. dp.SyntaxHighlighter.ClipboardSwf = './images/clipboard.swf';     
  16. dp.SyntaxHighlighter.HighlightAll('code');   
  17. </script>  

위와 같은 내용을 skin.html에 포함해 주시면, 설치는 끝났습니다.
그리고 여기 있는 모든 .js파일을 포함 하실 필요는 없습니다.
사용자 분이 주로 사용하는 언어만 넣어 주신다면, 로딩 속도가 조금이나마 빨라 지겠죠?
그렇다고 shCores.js파일은 빼지 마세요. 빼면 동작을 하지 않습니다.

이제는 설치가 끝났습니다. 마음껏 사용을 해 주시면 됩니다.

syntaxhighlighter 사용하기.

tistory에서 사용하기 위해서는 좀 귀찮습니다.
솔직히 기본 편집모드에서 편집하면서 사용하는것은 거의 힘이 듭니다.
복사해서 붙여넣기를 하는 방법으로 사용하시길 권장합니다.

먼저 사용하는 방법은 <pre>테그를 이용하는 방법과 <textarea>테그를 이용하는 방법등 2가지가 있습니다.
먼저 <pre>테그를 사용하는 방법 입니다.

  1. <pre name="code" class="c-sharp">  
  2. ... some code here ...   
  3. </pre>  

pre테그를 사용할 경우에느 <와 같은 html테그를 사용할 경우 &lt;와 같이 변환을 해서 사용해야 합니다. 테그가 좀 편하긴 하지만, 꺽쇠(<) 테그로 인해서 귀찮은 경우가 있습니다.
다음으로 <textarea> 테그를 사용하는 방법입니다.
  1. <textarea name="code" class="c#" cols="60" rows="10">  
  2. ... some code here ...   
  3. </textarea>  
<textarea>테그로 쓸 경우 귀찮은 <를 &lt;로변환 하지 않아도 됩니다.
못쓰는 경우는 내용물에 </textarea>를 쓰는 경우 빼고는 없습니다. 중간에 </textarea>를 쓰게 되면, 중간에 멈춰 버리게 되겠죠?
저 같은 경우에도 바로 위의 <textarea> 샘풀의 경우 내용물에 </textarea>가 들어가야 해서 에는 <pre>테그를 사용해서 표현 했습니다.
꼭 한가지가 답은 아닌가 적당하게 섞어서 사용하시면 되겠습니다.
하지만, 특별한 경우가 아니면, <textarea>테그를 사용하는 것을 권장합니다.

여기서 class뒤에 넣은 형태는 아래 표의 명칭을 보시고 넣으시면 됩니다.
언어  명칭
C++ cpp, c, c++
C# c#, c-sharp, csharp
CSS css
Delphi delphi, pascal
Java java
Java Script js, jscript, javascript
PHP php
Python py, python
Ruby rb, ruby, rails, ror
Sql sql
VB vb, vb.net
XML/HTML xml, html, xhtml, xslt

기본적이 사용법은 이렇게 이해 하시면 됩니다.

그런데, tistory에서는  edit상태에서는 입력을 하시면 입력한 값이 그대로 나와 버리고 코드로 나오지 않습니다.
사용자 삽입 이미지
이럴때는 edit모드 버튼을 눌러서 html모드로 편집해 주시면 됩니다.

편집 할 때 보기에는 별로 안 좋고 귀찮기는 하지만, 그래도 결과물이 잘 나오니까 걱정하지 마시고 쓰시면 됩니다.
그럼 잘 사용하세요~

ps. 좀더 상세한 사용법을 보실려면 syntaxhighlighter 홈페이지를 방문해서 확인 하세요~

끝~


출처 : http://gyuha.tistory.com/193


'Computer > Web' 카테고리의 다른 글

CSS 선택자  (0) 2011.09.18
Web 2.0 기반의 Presentation On The Web  (0) 2009.08.06
syntaxhighlighter를 tistory에서 사용 하는 방법  (0) 2008.10.08
IE6,IE7 ,FireFox 에 대해 CSS 맞추기  (0) 2008.07.09
CSS에서 브라우저 구별 (IE6, IE7, FIREFOX)  (0) 2008.07.09
Daum UI DevDay  (0) 2008.05.18

댓글을 달아 주세요

posted by 희정냥★ 2008. 7. 9. 16:10

출처: [http]Creating different CSS style selector
[http]css-design-concerns-for-ie6-ie7-and-firefox

IE7 의 렌더링 방식이 IE6과 다르다.
CSS testing of Selector and Pseudo selectors 를 보면 IE7 은 FF 에 더 가까와 지고 있다.
그래서 바야흐로 브라우저 3개를 켜고 코딩을 해야하는 시대가 온 것이다.

이를 해결하기 위한 방법 중 하나는 Selector Hack 을 이용하는 것이다.

.context_bar_form_field
{
height: 15px; // 모든 브라우저
#height: 15px; // IE 전용
_height: 21px; // IE6.0 과 이전버젼용
}
우선 파폭에 맞추어 개발을 한 후 E7 에서 점검한다. 수정할 부분이 있다면 # 접두어를 붙여 수정해 준다. #이 붙은 것은 FF 에서 무시한다. 하지만 IE 는 재설정 해준다.
다음에 IE6 을 열고 수정하면서 _ 를 접두어로 붙여 새로 재설정 한다. IE7 은 '-' 가 붙은 것을 무시한다.
 
또 다른 방법은,
.title h3 {height: 21px; }
.title > h3 {height: auto; min-height: 21px; }

이렇게 하는 방법도 있다. 맨 아래줄은 파이어폭스와 IE7만 적용된다.

한가지 주의할 점은

body
{
text-align:-moz-center; /*FF*/
#text-align:center; /*IE */
}
속성 키워드 자체가 다른 것이 많다. 주의 할 것!
위에서 처럼 속성값 자체가 다른 경우가 있다. 그러니 안된다고 hack 만 쳐다보고 있으면 밤세야 한다.

내가 보기에 가장 좋은 방법은 Conditional Comments 를 사용하는 것이다.
복잡하게 한 파일에 구질구질 작성하지 말고 파일을 분리해 버리는 것이다.

참고 :http://webborg.blogspot.com/2007/01/css-compatibility-ie6-ie7-firefox-and.html

<head>
<title>my css hacked page</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="iehacks.css">
<![endif]-->
<body>
  <div class="watermark">....</div>...

이렇게 분리해서 각개격파하는 것이 좋을 듯 싶다.

참고글
w3cschools.com 브라우저 접속률
CSS Hacks

댓글을 달아 주세요

posted by 희정냥★ 2008. 7. 9. 16:08
<!--[if IE]>
<h1>Internet Explorer입니다</h1>
<![endif]-->
<!--[if IE 5]>
<h1>Version 5</h1>
<![endif]-->
<!--[if IE 5.0]>
<h1>Version 5.0</h1>
<![endif]-->
<!--[if IE 5.5]>
<h1>Version 5.5</h1>
<![endif]-->
<!--[if IE 6]>
<h1>Version 6</h1>
<![endif]-->
<!--[if IE 7]>
<h1>Version 7</h1>
<![endif]-->

IE 이외의 브라우저를 처리하려면 다음과 같이 한다.


<!--[if !IE]><!-->
<h1>Internet Explorer가 아닙니다.</h1>
<!--<![endif]-->
출처 : http://worms.tistory.com/93



'Computer > Web' 카테고리의 다른 글

syntaxhighlighter를 tistory에서 사용 하는 방법  (0) 2008.10.08
IE6,IE7 ,FireFox 에 대해 CSS 맞추기  (0) 2008.07.09
CSS에서 브라우저 구별 (IE6, IE7, FIREFOX)  (0) 2008.07.09
Daum UI DevDay  (0) 2008.05.18
희정냥의 ppt  (0) 2008.03.18
강의편람이 나와따;  (0) 2008.01.29

댓글을 달아 주세요

posted by 희정냥★ 2008. 5. 18. 00:45
Daum에서 UI 관련 DevDay 행사를 개최한다고 합니다.

개인적으로 너무너무 기대됩니다 ^-^

UI에 대해서는 저도 참 관심이 많고,

과제에서도 주로 제가 UI를 담당하기 때문에

이번 행사에 꼭 참가할 수 있었으면 좋겠어요... ^-^

많은 것을 배워오고 싶습니다.... ^^

자세한 사항은 아래를 참고하세요!

----

UI 개발 분야의 전문성을 확립하고 생태계 발전을 도모하기 위한 Daum UI DevDay 행사를 개최합니다. 이 행사는 Daum에서 주최하는 UI 기술 행사로써 재미있는 강의도 듣고 Daum UI/RIA 개발자와 만남의 자리를 통해 친목을 나눌 수 있는 자리입니다. 또한 푸짐한 경품과 기념품을 함께 증정해드릴 예정이오니 많은 참여 바랍니다.

uidevday.jpg

Daum UI DevDay

  • 일시: 2008년 5월 30일(금) 오후 1시 30분 ~ 오후 6시
  • 장소: 삼성동 섬유센터 17층
  • 인원: 250명

프로그램 안내

자세한 프로그램은 행사 안내페이지를 참고하세요!

참가 신청은 5월 26일(월)까지 가능하며 이후 추첨을 통해 250명을 선정하여 5월 27일(화) 이 곳에 다시 공지하도록 하겠습니다. 선착순으로 참가 우선권을 드릴 예정이오니 자리에 여유있다고 신청을 미루지 마시고 미리미리 신청해 주세요 ^^

이벤트: 블로그에 Daum UI DevDay 행사 소개 글을 올리고 트랙백을 보내는 분 중 추첨을 통해 3분께 CGV 영화 상품권 2매를 증정합니다. 많은 참여 바랍니다.
* 트랙백 URL: http://dna.daum.net/archives/428/trackback

행사 소개 및 참가 페이지: http://dna.daum.net/uidevday/

'Computer > Web' 카테고리의 다른 글

IE6,IE7 ,FireFox 에 대해 CSS 맞추기  (0) 2008.07.09
CSS에서 브라우저 구별 (IE6, IE7, FIREFOX)  (0) 2008.07.09
Daum UI DevDay  (0) 2008.05.18
희정냥의 ppt  (0) 2008.03.18
강의편람이 나와따;  (0) 2008.01.29
신나는 Mash Up Camp!  (6) 2008.01.14
TAG

댓글을 달아 주세요

posted by 희정냥★ 2008. 3. 18. 20:57

2월, 3월에 제가 발표했던 ppt들 입니다.


2월 18일~21일엔 멤 기술세미나,

3월 15일엔 디자인패턴 스터디 때문에

발표를 했습니다.


ppt 내용은 다 web에서 긁어모은것들이라,

혹시 저작권이 문제된다면 말씀해주세요.. ㅎㅎ


기술세미나 같은 경우는,,

ppt엔 사실 별 내용이 없어요... ㅎㅎ

거의 다 직접 보여주는 형식으로 했거든요...^^;;


(매쉬업 캠프 내용이 정말 많은 도움이 되었습니다.^^ http://cutewebi.tistory.com/358)


2월 18일 프로그래머가 알아야 할 Photoshop :

2월 19일 생활속의 Web 2.0 :

2월 20일 OpenAPI 이용하기 :

2월 21일 Mashup! :

2월 22일 BlogAPI를 이용한 원격 호스팅 :


그리고 디자인패턴 ppt는 시간이 없어서 공부도 많이 못하고, 준비도 많이 못했어요.

게다가 내용도 사실 잘 모르는 상태에서 발표준비를 해서인지

글자가 너무 많고 이미지는 너무 없다고,,  혼났습니다.. ㅎㅎ


3월 15일 디자인패턴 스터디 Bridge Pattern :

'Computer > Web' 카테고리의 다른 글

CSS에서 브라우저 구별 (IE6, IE7, FIREFOX)  (0) 2008.07.09
Daum UI DevDay  (0) 2008.05.18
희정냥의 ppt  (0) 2008.03.18
강의편람이 나와따;  (0) 2008.01.29
신나는 Mash Up Camp!  (6) 2008.01.14
웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12

댓글을 달아 주세요

posted by 희정냥★ 2008. 1. 29. 18:19

얼마전에 Code Review에 대한 교육을 받고 나서

소프트웨어 공학, 설계, 리펙토링, 디자인 패턴 등등에 대해 생각해보았다.

결론은 아주 중요하다는것이다.. ㅡ,ㅡ;;!!!

 

4학년 1학기에 대해 많은 생각을 해봤는데,

 

졸업학점까지 5학점밖에 안남았고,

2학점짜리 전공필수를 들어야 하므로

3학점만 아무거나 들으면 되는데,

 

전공과목의 중요성을 최근에 많이 느끼고 있으므로

아무래도 학과 공부를 좀 더 해야 될 것 같다.

(전공과목을 제대로 배울수 없는 경우가 있긴 하지만...)

 

나에겐 막장학기가 될 이번 학기.

전공과목+영어교양으로

빡씨게 달려야겠다; ㄱㄱㄱ

'Computer > Web' 카테고리의 다른 글

Daum UI DevDay  (0) 2008.05.18
희정냥의 ppt  (0) 2008.03.18
강의편람이 나와따;  (0) 2008.01.29
신나는 Mash Up Camp!  (6) 2008.01.14
웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12
웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10

댓글을 달아 주세요

posted by 희정냥★ 2008. 1. 14. 00:48

완전 기다리고 있었던 매쉬업 캠프를 갔다왔다 ㅋ

너무너무 재밌었다 ㅋ

대전까지 왔다갔다 하느라 좀 피곤하긴 했지만 ㅋ

장소는 대전에 있는 카이스트였다.

내가 예전부터 그토록 가고싶어 했던 카이스트 ㅠ_ㅠ!!

(드디어 가긴 갔네 ㅡ,ㅡ; 오늘 처음 가봤따;)

대전역에서 카이스트까지, 그리고 카이스트에서 대전역까지 네이버 버스가 친절하게 태워주었다;

사용자 삽입 이미지


오전에는 설명을 듣고~

사용자 삽입 이미지


맛있는 뷔페식 점심을 먹고~

사용자 삽입 이미지

오후에는 직접 자신이 원하는 섹션을 선택해서

멘토님과 함께 구현해보는 시간을 가졌다;


나는 멀티블로그편집기(?)를 선택했는데

Daum Blog API를 이용했다.


멘토님께서 너무너무 잘 가르쳐 주셔서

짧은 시간동안 많은 것을 배웠다 ㅎ

( 멘토님 블로그 : http://neouser.tistory.com )

그리고 예쁜 선물도 많이 받았다;


너무너무 재밌는 하루였다 ㅎ



이 상자에는 무엇이 들어있을까 ㅡ,ㅡ?

사용자 삽입 이미지



오늘의 대세는 네이버 모자 ㅋ

사용자 삽입 이미지

이것이 바로 셀카 ㅋ

이렇게 보니 거울이 정말 지저분하네 ㅡ,ㅡ;

그리고,, 모두모두 수고 많으셨습니다 ^-^!



- 추가 -
으헐... 웹에 내 사진이 떴다... -0-;;

사용자 삽입 이미지


사진의 왼쪽은 노트북을 안가져오셔서 나와 함께 봤던 부산대 심대성님;
가운데가 나.
오른쪽이 나의 멘토님이셨던 다음 개발팀 고영민님.

나 완전 눈감고 자고 있는것 같다 ㅡ,ㅡ; 급열코딩했는뒈 ㄷㄷㄷ

'Computer > Web' 카테고리의 다른 글

희정냥의 ppt  (0) 2008.03.18
강의편람이 나와따;  (0) 2008.01.29
신나는 Mash Up Camp!  (6) 2008.01.14
웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12
웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26

댓글을 달아 주세요

  1. BlogIcon 유진우 2008.01.15 18:40  Addr  Edit/Del  Reply

    네이버 모자 참 잘 어울리시네요^^

  2. BlogIcon 강준수 2008.01.15 21:18  Addr  Edit/Del  Reply

    안녕하세요^^
    저하고 같은 프로젝트 수행하셨네요.
    저는 님 자리에서 오른쪽 끝에 앉아있던..ㅋ
    프로필이 너무 화려하시네요..^^
    아무튼 반가웠습니다.
    지금의 열정으로 언제나 즐거운 개발하세요~

    • BlogIcon 희정냥★ 2008.01.18 00:36 신고  Addr  Edit/Del

      우연히 다음 블로그 보고 알게된건데,, 혹시 마지막 프로젝트 결과 발표때,,,,,;; 멀티블로그편집기 프로젝트 저와 함께 결과 발표하신분 아닌가요...? 블로그 글 보니 기억나네요... ㅋㅋ

  3. BlogIcon ironmask84 2008.09.06 15:08 신고  Addr  Edit/Del  Reply

    안녕하세요. 저 위에 사진속에 심대성군 입니다. ㅋㅋ
    크아 ㅋㅋ 이 사진 이제서야 보는군요 ㅋㅋ
    요즘 어떻게 잘 지내세요?
    저도 이제 얼마전에 티스토리인이 되었습니다 ㅋㅋ
    사진 퍼가욤~

posted by 희정냥★ 2007. 10. 12. 14:40

방금 웹서핑을 하다가 발견한 사이트.

인맥 네트워크 사이트이다.

자신의 프로필을 등록하고, 검색해서 관심 상대를 찾고,

그러다 인연이 되서 연락을... (ㅡ_ㅡ);;;; 하는 그런 사이트인것 같다.

주소는 http://www.linknow.kr/ 이다.





방금 가입해서 대충 프로필을 넣었는데;; 이렇게 태그로 링크시켜서 보여주게 하고,

관심 있으면 1촌 맺고, 2촌, 3촌... 이렇게.. 등록을 하는 듯 하다.

Web 2.0 특징 중에 소셜 네트워크라는 것이 있는데,

바로 이런 인맥 네트워크를 말한다.

IBM 사내 인트라넷에는 이미 도입이 되었고(데모를 보긴 했다).

간단하게 어떤 기술을 가진 사람을 찾고 싶을때, 검색을 하고,

그 사람을 아는 사람도 검색이 되고, 그사람이 아는 사람의 아는 사람도....;;

뭐 이런 네트워크 이고, 이 특징이 구현된 사이트라고 생각된다.

엠파스에 있는 인물 검색도 비슷한 유형인데,

이름을 넣고 검색하면 그 사람과 관계된 사람들도 다 검색이 된다.

음... ;; 나를 필요로 하는곳이 있을까...?
 
스토커만 안 붙는다면 재밌을것 같다. ㅎㅎㅎ

'Computer > Web' 카테고리의 다른 글

강의편람이 나와따;  (0) 2008.01.29
신나는 Mash Up Camp!  (6) 2008.01.14
웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12
웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16

댓글을 달아 주세요

  1. BlogIcon achiven 2007.10.13 00:28 신고  Addr  Edit/Del  Reply

    스토커 붙으면 재밌겠는걸..ㅋㅋ

posted by 희정냥★ 2007. 5. 10. 14:00

웹 2.0 기술의 주역
OpenAPI의 무한한 가능성

박지강 jkwave@gmail.com l SK 커뮤니케이션즈 근무

OpenAPI는 ‘플랫폼으로서의 웹’이라는 특징을 기술적으로 구현시켜주는 대표적인 웹 2.0 기술이다. 이미 해외에서는 OpenAPI를 이용하여 만든 매쉬업을 통해 다양한 비즈니스 모델을 창출되고 있으며 차세대 웹의 핵심 기술로 평가하며 투자를 아끼지 않고 있다. 국내에서도 오랫동안 OpenAPI에 대한 관심과 투자가 지지부진 했으나, 최근 들어 OpenAPI에 대한 열기가 고조되고 있다. 이번 1부에서는 OpenAPI를 활용한 구체적인 사례와 비즈니스 모델을 통해 웹 2.0 기술의 미래를 조명한다.

우리는 빠르게 다가오는 새로운 시대에 유연하게 대처하기 위해 좀 더 표준을 지켜야한다. 또, 좀 더 가벼워져야 하고, 쉽게 다른 서비스와 통합 가능해져야 한다. 필자는 웹 2.0의 화두는 점점 무거워지는 기술 속에서 생산성을 확보하기 위한 치열한 싸움이라고 생각한다. 웹 2.0의 핵심이 데이터이기 때문에 새로운 콘텐츠를 누가 먼저 사용자에게 소개하느냐가 웹 개발 환경 업그레이드의 화두가 될 것이다.

그럼 웹 2.0의 대표라고 할 수 있는 OpenAPI가 가지는 의미는 무엇일까? 흔히 이 OpenAPI를 공짜 서비스나 개발자용 장난감 퍼즐 정도로 치부하기도 하지만, OpenAPI는 그것을 사용하는 개발자의 역량에 따라 무한한 가능성을 발휘하는 신무기다. OpenAPI를 사용하면 지도 위에 부동산 정보를 표시할 수 있고, 쇼핑몰에 채팅을 결합할 수 있으며, 멀티미디어 포털도 만들 수 있다. 우리는 신속하게 변하는 차세대 서비스를 위해 웹 콘텐츠 조합이나 타 시스템과의 연동 시에 발생하는 웹 개발환경의 비용을 줄여주고, 큰 수익으로 연결되기도 한다. 이제부터 기존의 사례들을 통해 개발자가 OpenAPI를 어떻게 활용하고, 자신의 역량과 가치를 높이는 수단으로 쓸 수 있을 지에 대해 알아보자.

OpenAPI의 성장과 수익모델

웹 2.0이 이전의 웹과 명확히 구분되는 중요한 기술적 특징은 바로 OpenAPI의 등장으로 인한 “플랫폼으로서의 웹”이다.

OpenAPI는 기업 중심의 SOA(Service-Oriented Architectu re)가 웹에 반영된 결과물로써 웹 사이트가 자신의 기능을 이용할 수 있도록 공개한 프로그래밍 인터페이스를 말한다. 사용자는 웹 사이트의 내부를 모르더라도 공개된 API를 이용해 해당 사이트의 기능을 쉽게 사용할 수 있다. 이는 서비스 중심의 개발 방법으로 SOA의 기술적인 유전자를 웹에 이식한 것이다.

하지만 이처럼 무척 가까워 보이는 SOA와 OpenAPI는 자세히 알고 보면 그리 친한 사이는 아닌 듯하다. SOA가 기술적으로 더욱 복잡하고 서비스의 캡슐화를 통해 기업의 프로세스를 조율하는 등 좀 더 고차원적인 개념이라면, OpenAPI는 데이터를 제어할 수 있는 간단하고 직관적인 인터페이스의 제공을 통해 사용자의 참여를 유도하는 사용자 중심의 비즈니스 모델이라고 할 수 있다. SOA라는 아키텍처가 참여를 중시하는 웹 2.0의 정신과 맞물려 OpenAPI을 탄생시킨 것이다.

SOA를 도입해 얻을 수 있는 효과는 시장에 대한 빠른 적응력과 기업 내부의 생산성 제고 등 여러 가지 결과로 실현될 수 있어 그 실효성에 대해 다양한 논쟁을 일으키지만 OpenAPI는 명확해서 좋다. OpenAPI로 매쉬업이라는 명확한 결과물을 얻을 수 있기 때문이다. OpenAPI를 제공하는 서비스는 많지만 그 중에서도 제일 많이 사용되고 알려진 것은 아마도 구글 맵 OpenAPI일 것이다.


<그림 1> 매쉬업에 사용된 OpenAPI 점유율 <출처 : ProgrammableWeb.com>

구글 맵은 자바스크립트만을 이용하여 웹에 지도 정보를 표시하는 혁신적인 서비스다. 이 서비스는 AJAX란 용어가 구글 맵에서 영감을 받아 탄생했을 정도로 대중에게 많은 주목을 받았다. 구글 맵은 웹에 지도를 표시하고 위치 정보를 제어할 수 있는 기능을 OpenAPI로 제공한다. 위치 정보란 실생활에 밀접하게 사용되는 인프라 데이터이기 때문에 지도를 이용한 매쉬업은 가장 활발하게 생산되고 있다. 예를 들어 부동산 정보를 지도에 표시하는 매쉬업이나 소비자와 제일 가까운 자동차 판매처를 찾아내는 매쉬업 등 그 응용 영역은 무궁무진하다.

이렇게 구글 맵의 강력한 기능을 쉽게 가져와 사용할 수 있다는 것은 개발자의 입장에서 보면 분명 열광할 만한 일이다. 하지만 구글은 어떤 이익을 기대하고 이런 API를 제공하는 것일까? 구글은 구글 맵을 이용할 수 있는 인터페이스를 공개하여 이미 많은 광고 효과를 얻었다. 구글에 대한 인식은 높아지고 방문자 수도 증가했을 것이다. 하지만 더욱 중요한 것은 그들이 추후에 지도 위에 광고를 표시할 수 있는 권리를 서비스 약관에 명시하고 있다는 점이다. 이처럼 생산자와 소비자 모두 참여를 통해 이익을 얻을 수 있는 플랫폼은 웹 2.0의 흐름과 정확히 일치한다고 볼 수 있다.

개발자는 매쉬업을 통해 무엇을 얻을 수 있을까?

많은 사람들이 기발한 매쉬업에 열광하고 있지만 냉철한 시각으로 매쉬업을 비판하는 사람들도 있다. 그들은 매쉬업이 API 제공 서버에 의존적이기 때문에 서비스의 안정성을 보장하지 않고, API 사용 횟수나 데이터 전송량에 제한이 있다고 불평한다. 또한 상업적 용도에 제한을 가하는 경우도 있고, 누구나 비슷한 서비스를 만들 수 있다는 점을 지적한다. 그래서 비즈니스 모델로서 매쉬업은 큰 가치가 없다는 결론을 내리고 있다. 하지만 실제로 매쉬업이 여러 가지 방법으로 수익을 거둘 수 있다는 명백한 증거는 주위에서 쉽게 확인할 수 있다. 현재 알려진 가장 확실한 수익 모델은 광고와 제휴 프로그램이다.

● 광고

광고는 사이트의 가장 보편적인 수익 모델이며 이는 매쉬업에서도 마찬가지다. 단순히 OpenAPI의 조합만으로 만들어진 매쉬업은 다양한 수익 모델을 만들어내기가 어렵다. 그러므로 기발하고 다양하지만 데이터에 대한 소유권을 가지고 있지 않은 매쉬업은 광고가 가장 유력한 수익모델일 수밖에 없다.
현재 지속적으로 생산되고 있는 매쉬업의 대부분은 구글 애드센스(Google AdSense)와 같은 키워드 광고 프로그램을 도입하고 있다. 구글 애드센스는 문맥 검색을 통해 웹 페이지에 알맞은 광고를 제공하는 맞춤형 광고 프로그램이다. 애드센스를 이용하면 간단한 HTML 코드를 사이트에 붙이기만 하면 추가적인 노력 없이 자동으로 광고가 개제되고 그로 인한 수익을 받게 된다. 물론 큰 수익은 아니지만 충분한 헌신 없이 매쉬업 개발자가 취할 수 있는 최선의 수익모델이라 할 수 있다.
하지만 좀 더 많은 관리와 추가적인 노력으로 사용자의 방문수가 점점 올라간다면 직접 광고주를 모집하거나 더 나은 조건의 광고를 유치하느라 동분서주할 수도 있을 것이다. 아직까지는 매쉬업을 비즈니스를 추진하는 수단으로 사용하기보다는 호기심을 충족시키거나 기발한 아이디어를 현실화하기 위해 만드는 경우가 대다수이다. 매쉬업을 만든 후 시장을 관망하며 사용자의 평가만 기다리는 안일한 개발자는 단지 구글 애드센스로 사이트 호스팅 비용만 버는 괴짜로 남을 것이며, 매쉬업을 비즈니스를 도구로 적극적으로 활용한다면 광고주의 환영을 받는 혁신가로 남을 것이다.

<화면 1> 화면의 회색 박스에 구글 어드센스를 설치한 그림 단어 생성 매쉬업

● 제휴 프로그램

매쉬업의 또 다른 비즈니스 모델은 제휴 프로그램이다. 아담 트래첸버그는 Dude, Where’s My Used Car?(https://www. dudewheresmyusedcar.com)라는 다소 긴 제목의 매쉬업을 만들었다. 이 매쉬업은 구글 맵과 이베이의 자동차 카테고리 상품을 조합한 사이트이다. 이 사이트는 사용자의 위치에 가장 근접한 중고차 판매자를 찾아내는 일을 수행하며, 그가 개발한 서버에는 OpenAPI를 다루는 페이지 외에 아무런 데이터도 가지고 있지 않았다. 아담은 2005년에 열린 웹 2.0 컨퍼런스에서 자신이 만든 매쉬업은 사용자에게 이베이에서 제공하지 않는 지도 정보를 제공하는 동시에 이베이에서 할 수 있는 많은 기능들도 추가적으로 제공하였기 때문에 방문자에게 색다른 만족을 줄 수 있다고 말했다.
이베이의 API를 이용한 매쉬업에 지속적인 방문자를 확보할 수 있다면 이베이의 제휴프로그램으로 수익을 거둘 수 있다. 제휴 프로그램은 어떤 일을 할까? 아담이 만든 매쉬업은 이베이의 잠재고객을 창출하는데 크게 기여한다. 사이트의 검색 결과가 이베이의 자동차 카테고리의 자동차 구매 페이지와 연결 되어있기 때문이다. 실제로 이베이는 자사의 상품에 구매를 유발하는 제휴사에게 금액으로 보상하는 제휴 프로그램을 마련하고 있다. 사용자는 매쉬업을 통해 위치 검색 결과로 이베이의 자동차 구매 페이지를 접속할 수 있고, 사용자가 자동차를 구매하면 이베이가 그 수익의 일부를 매쉬업에 제공함으로써 아담이 돈을 벌 수 있는 것이다.
앞서 열거한 두 가지 외에도 충분히 다른 비즈니스 모델들도 있을 수 있다. 매쉬업은 계속 진화하고 있으며, 그 가능성을 예측하는 것은 불가능하기 때문이다. 이 가능성을 비즈니스 모델로 바꾸는 주체는 OpenAPI를 제공하는 선도 기업과 매쉬업을 창출해내는 혁신가들이다.

<화면 2> 구글 맵과 이베이를 조합한 Dude, Where's my used car?

거액의 투자를 받은 매쉬업

지금까지는 매쉬업을 통해 구현할 수 있는 일반적인 수익 모델을 정리해보았다. 하지만 빈손이 아니라 경쟁력 있는 데이터와 OpenAPI를 결합시키면 백만장자가 될 기회를 좀 더 빨리 얻게 될지도 모른다. 다음은 투자를 받은 매쉬업의 사례들이다.

<화면 3> 구글 맵 OpenAPI를 이용한 부동산 정보 사이트 Trulia

Trulia.com은 구글 맵 OpenAPI를 이용한 부동산 정보 매쉬업을 만들어 Accel Partner란 벤처 캐피탈에게 약 800만 달러에 달하는 투자를 받았다. 이 사이트는 구글 맵 위에 부동산 정보를 뿌려 사용자가 지도를 이용해 편리하게 부동산 정보를 검색할 수 있는 사용자 인터페이스를 구현하여 많은 호응을 얻었다.

부동산 정보 사이트인 Zillow는 마이크로소프트의 버추얼 어스(Virtual Earth) OpenAPI를 사용하여 매물로 나온 부동산의 실제 사진을 원하는 방향에서 상세히 볼 수 있다. 이 기능은 Zillow에서 “Bird’s Eye View”로 불리는데 새의 눈으로 본 시점이라는 뜻이다. Zillow는 Benchmark Capital로부터 약 5,700만 달러의 투자를 받았다. 물론 이 사이트는 단순히 지도를 이용한 부동산 정보 사이트로 이런 어마어마한 투자를 받은 것은 아니다. Zillow는 해당 가격대의 낮은 범죄율을 가진 지역 내 집이나 높은 등급의 초등학교 위치에 있는 30분 거리에 있는 집을 검색할 수 있는 데이터를 갖추었고, 자신의 소유의 집에 대한 가격을 주변 환경 요인에 입각하여 평가를 해주는 기능도 가지고 있다. 하지만 Virtual Earth의 API를 사용해 집을 육안으로 확인할 수 있는 기능을 보탬으로써 사용자에게 더 많은 만족을 주었고 이는 더 많은 투자를 받을 수 있는 계기가 되었을 것이다.

이 사례들은 매쉬업을 통해 누군가의 투자를 받으려면 비즈니스를 수행할 수 있는 기본적인 기반을 갖추고 있어야 함을 보여준다.

매쉬업 비즈니스의 눈부신 미래

OpenAPI와 매쉬업은 단지 괴짜들이 가지고 놀 수 있는 개발자용 장난감처럼 보일 수도 있지만 기본적으로 OpenAPI는 사이트 개발의 생산성을 높여주는 전략적 제휴의 훌륭한 도구이다. 다른 곳의 가치 있는 자원을 마음만 먹으면 사용할 수 있다는 것은 그 활용의 범위도 무궁무진하다는 증거이다. 단지 장난감처럼 레고 블록을 쌓듯이 가지고 놀며 지나치기엔 너무나 유용한 기회이다. 단지 미래의 활용 가능성은 차치하더라도 우리가 흔히 겪는 비즈니스 사례에 OpenAPI를 대입하더라도 충분히 그 가치를 깨달을 수 있다. OpenAPI와 매쉬업을 활용한 비즈니스 사례들을 살펴보자.

OpenAPI를 이용해 킬러 사이트 만들기

기존의 사이트가 가지지 못한 창의적이고 독창적인 사이트를 기획하여 개발하는 것은 비즈니스를 수익으로 변화시키기 위해 가장 우선시 되어야 할 것이다. 하지만 새로운 사이트를 직접 만드는 작업은 그리 쉬운 일이 아니다. 웹 페이지는 둘째치더라도 데이터베이스와 웹 서버 설정까지 신경을 써야 할 것들은 한두 가지가 아니다. 이처럼 경쟁력 있는 사이트를 만들기 위해서는 적지 않은 개발 리소스가 투입되고, 투자비용을 회수하기 위해 모험적인 시도를 하기 보다는 좀 더 안정적이고 보수적인 시각으로 사이트를 구축하게 된다. OpenAPI는 새로운 사이트를 구축할 때 좀 더 낮은 비용으로 빨리 새로운 사이트를 구축할 수 있도록 도와준다.

아무런 컨텐츠도 가지고 있지 않고 맘대로 움직일 수 있는 신체와 아이디어밖에 없는 빈털터리라면 여러 가지 OpenAPI를 조합하여 새로운 서비스를 만들어 보자. 매쉬업 캠프의 두 번째 모임에서 최고의 매쉬업으로 꼽힌 Weatherbonk(http://www. weatherbank.com)는 무려 열 개의 OpenAPI를 조합하여 지도 위에 기상 정보와 해당 지역의 실시간 날씨 사진, 교통 상황 정보 등 수많은 정보를 지도 위에 표시하는 매쉬업이다.

<화면 4> 해당 지역의 실시간 날씨 사진을 보여주는 Weatherbonk

이 새로운 스타일의 기상 정보 사이트는 많은 블로거들과 언론에게 호평을 받고 있으며 구글의 키워드 광고 API인 애드센스(AdSense)로 수익을 얻고 있다. 물론 이처럼 열 개 정도의 많은 API를 조합해야지 훌륭한 사이트가 만들어지는 것은 아니다. 한두 개 정도의 API만으로도 독창적인 사이트를 만들 수 있다.

하지만 이처럼 매력적인 매쉬업들이 많음에도 불구하고 다양한 수익 모델을 찾기는 쉽지가 않다. OpenAPI로 고객에게 서비스하는 데이터들은 모두 매쉬업 개발자 소유가 아니다. API 제공 기업의 소유이기 때문이다. 그러므로 OpenAPI만으로 만든 매쉬업은 광고나 제휴 프로그램같이 제한된 수익 모델을 가질 수밖에 없다. Weatherbonk의 개발자인 데이비드 쇼어(David Schorr)는 광고 이외에도 호텔이나 항공사의 예약 프로그램과 제휴하여 수익을 얻을 가능성이 있지만 제휴를 맺기가 아직까지 쉽지가 않다고 한다. 물론 인터넷에서 광고나 제휴 프로그램은 수익을 낼 수 있는 전통적인 비즈니스 모델이다. 하지만 현재는 구글의 광고 중계 API인 애드워즈를 사용하거나 아마존이나 이베이 등 몇 개의 기업만이 제휴 프로그램을 진행하고 있기 때문에 선택의 폭과 수익의 질은 떨어질 수밖에 없다. 그렇다고 좌절할 필요는 없다. OpenAPI와 매쉬업 시장은 이제 성숙기에 접어들었고 앞으로 보다 많은 기업들이 제휴 프로그램과 광고 모델을 제시할 것이다. 대표적으로 지도 OpenAPI 제공 업체들은 지도 위에 광고를 표시할 움직임을 보이고 있으며 이 광고 수익을 매쉬업과 공유할 계획도 세우고 있다. 이제 다시 장밋빛 미래가 아닌 냉정한 현실로 돌아오자. 지금 당장 OpenAPI로 좀 더 경쟁력 있는 사이트를 만들 수는 없을까?

이미 가지고 있는 컨텐츠가 있다면 OpenAPI를 추가하여 더욱 경쟁력 있는 새로운 사이트를 만들 수 있다. 예를 들어 부동산 정보나 여행 정보, 맛집 정보와 같은 위치 기반 데이터를 가지고 있다면 지도를 제공하는 네이버 지도, 구글 맵, 야후 맵 등을 이용해 새로운 사이트를 만들 수 있다. 물론 네이버 지도를 제외한 구글 맵이나 야후 맵은 해외에서는 유명한 지도 API이지만 국내에서 대체 무슨 용도로 사용할 수 있냐고 반문할 수도 있다. 하지만 만약 해외여행에 관한 서비스를 기획하고 있다면 어떨까? 어학연수를 위한 수많은 교육 기관을 소개하는 것은 어떨까? 이처럼 발상의 전환은 OpenAPI를 활용하는데 큰 원동력이 될 것이다. 미국에서 열린 매쉬업 정보 공유 모임인 매쉬업 캠프(http:// www.mashupcamp.com)에서 최고의 매쉬업으로 선정되었던 Podbop(http://www.podbop.org)를 살펴보자.

<화면 5> 매쉬업 캠프에서 최고의 매쉬업으로 선정된 Podbop

Podbop은 이벤트 정보를 서비스하고 있는 Eventful(http:// www.eventful.com)의 OpenAPI와 음악을 하는 아티스트의 데이터를 연결하여 전 세계의 콘서트 정보를 확인할 수 있는 사이트이다. 물론 Eventful에는 콘서트 정보와 같은 음악 이벤트만 서비스하는 것이 아니다. 하지만 OpenAPI의 기능을 이용하여 “music”이라는 태그가 붙어 있는 이벤트만 가져올 수 있기 때문에 이런 콘서트 검색 사이트가 가능한 것이다. 이것이 전부가 아니다. 콘서트를 열 예정인 아티스트의 무료 mp3를 함께 제공해서 음악을 미리 듣고 콘서트 참여 여부를 결정할 수 있도록 만들어서 사용자의 궁금증을 해소시키고 있다. 이 독창적인 사이트는 Eventful의 방대한 이벤트 데이터베이스를 이용하지 않았다면 높은 구축비용 때문에 시도도 해보지 못하고 아이디어로만 남았을 것이다. 이 사이트의 성공 비결은 자신이 소유하고 있는 컨텐츠로 인해 비즈니스 경쟁력을 자체적으로 확보할 수 있었고 OpenAPI를 사용해 컨텐츠를 더욱 빛나게 만들었기 때문이다. 이는 단지 OpenAPI만을 조합한 매쉬업의 현실적인 한계를 극복한 훌륭한 매쉬업 사례라 할 수 있다.

OpenAPI로 기존 사이트를 업그레이드하자

기존의 서비스에 OpenAPI를 추가하여 쉽고 빠르게 좀 더 나은 서비스를 만들 수 있다. Simplyhired.com은 새로운 개념의 구인 전문 검색 사이트이다. 이 사이트는 채용 전문 사이트의 정보와 회사 홈페이지의 구인 정보 등 여러 가지 구인 정보 페이지에서 데이터를 수집하는 전문 검색 엔진(Vertical Search Engine)을 활용한 사이트이다. 하지만 이게 전부가 아니다. 구글 맵의 OpenAPI와 LinkedIn(http://www.linkedln.com), Pay Scale (http://www.payscale.com), ZoomInfo(http://www. zoominfo.com)의 기능을 제휴를 통해 통합하여 만든 사이트이기도 한다. 검색 엔진을 통해 수집한 채용 정보를 바탕으로 구글 맵은 회사의 위치를 알려 주고, LinkedIn은 인맥 정보를 알려준다. 그리고 PayScale은 해당 직업의 연봉 정보를 알려주며, ZoomInfo는 회사 정보를 알려준다.

결국 이 사이트는 OpenAPI를 이용해 다른 경쟁 사이트와 차별화된 사이트를 구성하여 사용자를 끌어들였고, 투자자들의 도움을 받아 사용자들의 트래픽으로 광고비를 벌어들이고 있다.

<화면 6> 구인회사의 위치를 구글 맵으로 보여주는 Simplyhired.com

Simplyhired는 처음부터 여러 기업들과 전략적 제휴를 맺었던 것은 아니다. 채용 정보 전문 검색 엔진이란 핵심 기술을 이용하여 사이트를 오픈한 후 구글 맵의 OpenAPI를 사용하였고 Linkedln, PayScale, ZoomInfo와 같은 채용 관련 정보를 가진 기업과 전략적 제휴를 맺으며 정보의 질을 점점 높였다. 이처럼 한 사이트에서 채용에 대한 모든 정보를 볼 수 있도록 다른 기업과의 제휴를 통해 개선에 개선을 거듭한 결과 Simplyhired는 최고의 직업 검색 사이트로 성장하게 되었다.

기업 간의 매혹적인 제휴, 엔터프라이즈 매쉬업

우리는 매쉬업이 SOA의 소비자 버전이라는 사실을 기억해야 한다. SOA라는 기업용 서비스 지향 아키텍처가 웹의 사용자 레벨로 보급된 산물이 바로 개발자들이 만들어 내는 기발한 매쉬업이다. 하지만 여러 가지 데이터의 손쉬운 조합이라는 어디서나 통용될 수 있는 비즈니스 기회를 굳이 웹에서 사용자에게만 제한시킬 필요는 없다. 기업 간의 전략적 제휴에도 충분히 매쉬업이 사용될 수 있다. 이름하여 엔터프라이즈 매쉬업(Enterprise Mashup)이다.

물론 기업 간의 전략적 제휴는 지금까지 항상 있어왔다. 하지만 서로 다른 시스템과 컨텐츠로 인해 인터페이스를 맞추어 데이터를 통합하기란 쉬운 일이 아니다. 하지만 XML 포맷이 범용화 되고 RSS와 OpenAPI와 같은 열린 데이터 채널이 웹 2.0 기술로 주목을 받으면서 데이터를 주고받는 방식이 점점 표준화되고 있기 때문에 기업 간의 제휴에 매쉬업을 사용하면 좀 더 적은 비용으로 좀 더 빨리 새로운 비즈니스를 펼칠 수 있다. 이런 특징은 사용자를 중심으로 빠르게 변화하는 인터넷 비즈니스에 신속하게 적응하기 위해 반드시 필요한 기업의 조건으로 정확히 SOA의 최종 목표이기도 하다.

예를 들어 택배 회사의 콜 센터와 네이버 지도의 OpenAPI가 제휴를 맺으면 고객의 데이터를 지도 위에 시각적으로 확인할 수 있는 훌륭한 엔터프라이즈 매쉬업이 탄생할 것이다. 일본의 자동차 회사인 혼다(Honda)는 구글 어스(Google Earth)를 통해 도로의 교통량 확인 텔레매틱스(Telematics) 서비스를 고객에게 제공하고 있다.

이처럼 서로의 이익을 위해 기업이 가지고 있는 핵심 역량을 공개하고 공유하는 일은 무한 경쟁 시대에서 살아남기 위해 피할 수 없는 선택이며 엔터프라이즈 매쉬업은 그에 대한 이상적인 선택이 될 수 있다. 물론 가볍고 빠른 개발 속도를 가진 매쉬업은 기업 간의 치명적인 비즈니스 데이터를 거래하기엔 여러 가지 명백한 보안적인 문제를 가지고 있다. 하지만 치명적이지 않은 분야의 프로세스와 로직에는 매쉬업이 충분히 그 강력한 효과를 발휘할 수 있다. 이처럼 매쉬업은 기업이 SOA를 채택해야 하는 이유를 서서히 입증하고 있으며, 엔터프라이즈 매쉬업으로 인해 소비자 중심의 매쉬업과 기업 중심의 SOA의 경계는 점점 모호해 지고 있다.


기회란 아무 때나 오지 않는다

지금 이 시간에도 OpenAPI를 제공하는 사이트는 끊임없이 늘어나며, 그에 발맞추어 매쉬업의 숫자도 증가하고 있다. OpenAPI와 매쉬업에 대한 대표적인 정보 사이트인 프로그래머블웹(http://www.programmableweb.com)에 의하면 2007년 3월 기준, 전 세계적으로 398개의 API와 1,683개의 매쉬업이 존재하며 하루에 약 3.08개의 매쉬업이 생성된다고 한다. 구글 맵은 수백 개의 매쉬업을 가지고 있고 아마존은 API에 과금을 하여 큰 성공을 거두고 있다. 또, 가트너 그룹은 Ajax와 매쉬업이 향후 10년간 기업에 큰 영향을 줄 것이라고 전망하고 있다. 국내에서는 오로지 네이버와 다음만이 OpenAPI를 제공하고 있는 상황이다.

하지만 국내에 매쉬업이 많지 않다고 하여 그리 비관할 만한 상황은 아니다. 다수의 조합으로 이루어지는 매쉬업의 특성상 OpenAPI의 수만큼 매쉬업은 비례하여 증가하기 때문이다. 다행히도 국내의 힘 있는 포탈들이 OpenAPI의 제공을 계획하여 진행하고 있다고 한다. OpenAPI의 종류가 더 많아진다면 국내의 매쉬업 시장도 더욱 성장하게 될 것이다. 네이버와 다음이 공동으로 개최한 매쉬업 캠프도 OpenAPI에 대한 구체적인 기업의 지원이 시작된 첫 사례이기에 많은 희망을 갖게 한다. 하지만 국내 OpenAPI의 수가 많아질 때까지 무작정 기다리는 일은 수없이 지나가는 기회를 놓치는 것과 같다. 이미 해외에 사용할 수 있는 수많은 OpenAPI들이 당신을 기다리고 있으며 나름대로의 수익구조를 갖추고 있는 훌륭한 매쉬업 레퍼런스들도 널려있다. 웹에서만큼은 국내와 해외의 구분이 큰 의미를 가지지 못한다. 구글 맵과 같은 경우 국내의 해외여행 정보 사이트나 이민, 유학정보 사이트에 충분히 활용될 수 있다. 그 밖에 해외 API를 활용할 수 있는 좀 더 구체적인 사례를 들어보자. 위즈위드(http:// www.wizwid.com)로 대변되는 해외 구매 대행 사이트들은 해외쇼핑몰들의 상품정보를 수동으로 입력하거나 별도의 웹스크래핑 툴로 긁어와 국내의 사용자들에게 전시한다. 그리고 국내 사용자들이 결제한 상품을 해당 해외쇼핑몰에 대신 결제해주고 배송해주는 역할을 한다. 이 사이트들에게 해외쇼핑몰들의 상품정보를 빠르고 신속하게 가져오는 기능은 무엇보다 중요한데 해외의 쇼핑 API를 이용하면 이런 기능을 쉽게 구현할 수 있다. 이베이나 아마존 등과 같은 쇼핑사이트들이 이미 상품정보를 API로 제공하고 있게 때문이다.

인터넷 주소에 국가 명이나 도시 명을 적는 곳은 없다. 웹은 사회적으로는 누구에게나 열린 공간이며 비즈니스 적으로는 세계를 대상으로 한 무한 경쟁의 시장이다. 네이버, 다음, 구글이나 야후와 같은 세계적인 공룡 IT 기업과 전략적 제휴를 맺고 싶은가? 그럼 그들과 함께 매쉬업을 만들어라.

돈 버는 매쉬업의 특징

누군가의 지갑에서 큰돈을 꺼내려면 사용자의 요구를 충족시켜 비즈니스를 할 수 있는 경쟁력 있는 서비스가 바탕이 되어야 한다. 특히 투자를 받은 부동산 매쉬업의 특징은 다음의 두 가지로 요약된다. 이것은 비단 지도 관련 매쉬업에만 해당되는 법칙은 아니다. 기발한 아이디어와 비즈니스를 할 수 있는 추진력이 있다면 데이터와 OpenAPI를 사용하여 킬러 사이트를 만들어 육백만 달러의 사나이가 될 수 있는 기회는 항상 열려있다.

● OpenAPI외에도 경쟁력 있는 데이터를 확보하고 있다.
● 소비자가 돈을 지출해야 하는 행위와 관련이 있다.


제공 : DB포탈사이트 DBguide.net

출처명 : 한국 마이크로소프트

'Computer > Web' 카테고리의 다른 글

신나는 Mash Up Camp!  (6) 2008.01.14
웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12
웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12

댓글을 달아 주세요

posted by 희정냥★ 2007. 4. 26. 23:30
#93DAFF #98DFFF #9DE4FF #A2E9FF #A7EEFF #ACF3FF #B0F7FF #B4FBFF #B9FFFF #C0FFFF
#87CEFA #91D8FA #A5D8FA #AFDDFA #B9E2FA #C3E7FA #CDECFA #D7F1FA #E1F6FA #EBFBFF
#00BFFF #0AC9FF #14D3FF #1EDDFF #28E7FF #32F1FF #3CFBFF #46FFFF #96FFFF #C8FFFF
#00A5FF #00AFFF #00B9FF #00C3FF #00CDFF #00D7FF #00E1FF #00EBFF #00F5FF #00FFFF
#1EA4FF #28AEFF #32B8FF #3CC2FF #46CCFF #50D6FF #5AE0FF #6EE0FF #6EEAFF #78F3FF
#1E90FF #289AFF #32A4FF #3CAEFF #46B8FF #50C2FF #5ACCFF #64D6FF #6EE0FF #78EAFF
#96A5FF #A0AFFF #AAB9FF #B4C3FF #BECDFF #C8D7FF #D2E1FF #DCEBFF #E8F5FF #F4FFFF
#86A5FF #90AFFF #9AB9FF #A4C3FF #AECDFF #B8D7FF #CCE1FF #E0EBFF #EBF5FF #F9FFFF
#6495ED #6E9FED #78A9ED #82B3ED #8CBDED #96C7ED #A0D1F7 #AADBFF #B4E5FF #BEEFFF
#0078FF #0A82FF #148CFF #1E96FF #28A0FF #32AAFF #3CB4FF #46BEFF #50C8FF #5AD2FF
#0064FF #0A6EFF #1478FF #1E82FF #288CFF #3296FF #3CA0FF #46AAFF #50B4FF #5ABEFF
#0000FF #3232FF #5050FF #646EFF #6478FF #6482FF #648CFF #6496FF #64A0FF #64AAFF
#4169E1 #4B73E1 #557DE1 #5F87E1 #6991E1 #739BE1 #7DA5E1 #87AFEB #91B9F5 #9BC3FF
#0064CD #0A6ECD #1478CD #1E82CD #288CD2 #3296D7 #3CA0E1 #46AAEB #50B4F5 #5ABEF5
#5A5AFF #6464FF #6E6EFF #7878FF #8282FF #8C8CFF #A0A0FF #B4B4FF #C8C8FF #D2D2FF
#7B68EE #8572EE #8F7CEE #9986EE #A390EE #AD9AEE #B7A4EE #C1AEEE #CBB8EE #D5C2EE
#6A5ACD #7E6ECD #8878CD #9282CD #9C8CCD #A696CD #B0A0CD #BAAAD7 #C4B4E1 #CEBEE1
#0000CD #2828CD #4646CD #6464CD #6E6ED7 #7878E1 #8282EB #8C8CF5 #9696FF #A0A0FF
#00008C #14148C #28288C #3C3C8C #50508C #646496 #7878AA #8C8CBE #A0A0C8 #B4B4DC
#483D8B #52478B #5C518B #665B8B #70658B #7A6F95 #84799F #8E83A9 #988DB3 #A297BD
#000069 #1E3269 #323C73 #3C467D #3C5087 #3C5A91 #46649B #506EA5 #5A78AF #6482B9

#3DFF92 #47FF9C #51FFA6 #5BFFB0 #65FFBA #6FFFC4 #79FFCE #75FFCA #7AFFCF #7FFFD4
#55EE94 #5FEE9E #69EEA8 #73EEB2 #7DEEBC #87EEC6 #91F8D0 #9BFFDA #A5FFE4 #AFFFEE
#66CDAA #70D2B4 #7AD7BE #84DCC8 #8EE1D2 #98EBDC #9DF0E1 #A2F5E6 #A7FAEB #ACFFEF
#AAEBAA #B4F0B4 #BEF5BE #C8FAC8 #D2FFD2 #DCFFDC #E1FFE1 #E6FFE6 #EBFFEB #F0FFF0
#80E12A #8AE634 #94EB3E #9EF048 #A8F552 #B2FA5C #BCFF66 #C1FF6B #C6FF70 #CBFF75
#52E252 #5CE75C #66EC66 #70F170 #7AF67A #84FB84 #89FB89 #8EFB8E #93FB93 #98FB98
#64CD3C #6ED746 #78E150 #82EB5A #8CF064 #96F56E #9BFA73 #A0FA78 #A5FA7D #AAFA82
#13C7A3 #18CCA8 #1DD1AD #22D6B2 #27DBB7 #2CE0BC #31E0C1 #36E0C6 #3BE0CB #40E0D0
#46B4B4 #50BEBE #5AC8C8 #64D2D2 #6EDCDC #73E1E1 #78E6E6 #7DEBEB #82F0F0 #87F5F5
#20B2AA #2ABCB4 #34C6BE #3ED0C8 #48DAD2 #52E4DC #57E9E1 #5CEEE6 #61F3EB #66F8F0
#5F9EA0 #69A8AA #73B2B4 #7DBCBE #87C6C8 #91D0D2 #96D5D7 #9BDADC #A0DFE1 #A5E3E6
#3CB371 #46BD7B #50C785 #5AD18F #64DB99 #6EE5A3 #73EAA8 #78EFAD #7DF4B2 #82F9B7
#2E8B57 #389561 #429F6B #4CA975 #56B37F #60BD89 #65C28E #6AC793 #6FCC98 #74D19D
#228B22 #2C952C #369F36 #40A940 #4AB34A #54BD54 #5EC75E #63CC63 #68D168 #6DD66D
#497649 #538053 #5D8A5D #679467 #719E71 #7BA87B #80AD80 #85B285 #8AB78A #8FBC8F
#006400 #0A6E0A #147814 #1E821E #288C28 #329632 #3CA03C #41A541 #46AA46 #4BAF4B
#008C8C #0A9696 #14A0A0 #1EAAAA #28B4B4 #32BEBE #37C3C3 #3CC8C8 #41CDCD #46D2D2
#008080 #0A8A8A #149494 #1E9E9E #28A8A8 #32B2B2 #37B7B7 #3CBCBC #41C1C1 #46C6C6

#FFB6C1 #FFBBC6 #FFC0CB #FFC5D0 #FFCAD5 #FFCFDA #FFD4DF #FFD9E4 #FFDEE9 #FFE3EE
#FFAAAF #FFB4B9 #FFBEC3 #FFC8CD #FFD2D7 #FFDCE1 #FFE1E6 #FFE6EB #FFEBF0 #FFF0F5
#FF9E9B #FFA8A5 #FFB2AF #FFBCB9 #FFC6C3 #FFD0CD #FFD5D2 #FFDAD7 #FFDFDC #FFE4E1
#FF7A85 #FF848F #FF8E99 #FF98A3 #FFA2AD #FFACB7 #FFB1BC #FFB6C1 #FFBBC6 #FFC0CB
#FF5675 #FF607F #FF6A89 #FF7493 #FF7E9D #FF88A7 #FF92B1 #FF9CBB #FFA6C5 #FFB0CF
#FF82FF #FF8CFF #FF96FF #FFA0FF #FFAAFF #FFB4FF #FFBEFF #FFC8FF #FFD2FF #FFDCFF
#FF7DB4 #FF87BE #FF91C8 #FF9BD2 #FFA5DC #FFAFE6 #FFB4EB #FFB9F0 #FFBEF5 #FFC3FA
#FF69B4 #FF73BE #FF7DC8 #FF87D2 #FF91DC #FF9BE6 #FFA5F0 #FFAAF5 #FFAFFA #FFB4FF
#FF1493 #FF1E9D #FF28A7 #FF32B1 #FF3CBB #FF46C5 #FF50CF #FF5AD9 #FF64E3 #FF6EED
#DB7093 #DB7A9D #DB84A7 #E08EB1 #E598BB #EAA2C5 #EAB1D4 #EFACCF #F4BBDE #F4B6D9
#D7567F #DC6089 #E16A93 #E6749D #EB7EA7 #F088B1 #F592BB #FA9CC5 #FFA6CF #FFB0D9
#C71585 #C71F8F #C73399 #C73DA3 #CC47AD #D151B7 #D65BC1 #E065CB #EA6FD5 #F479DF
#CD1039 #CD1F48 #CD2E57 #CD3861 #CD426B #D24C75 #D7567F #DC6089 #E16A93 #E6749D
#B9062F #B91A4D #BE2457 #C32E61 #C8386B #CD4275 #D24C7F #D75689 #DC6093 #E16A9D

#FAEB78 #FAF082 #FAF58C #FAFA96 #FAFAA0 #FAFAAA #FAFAB4 #FAFABE #FAFAD2 #FAFAD2
#FFDC3C #FFE146 #FFE650 #FFEB5A #FFF064 #FFF56E #FFFA78 #FFFA82 #FFFF8C #FFFF96
#FFC81E #FFD228 #FFD732 #FFDC3C #FFE146 #FFE650 #FFEB5A #FFF064 #FFF56E #FFF978
#FFB400 #FFBE0A #FFC314 #FFC81E #FFCD28 #FFD232 #FFD73C #FFDC46 #FFE150 #FFE65A
#FDCD8C #FDD296 #FDD7A0 #FDDCAA #FDE1B4 #FDE6BE #FDEBC8 #FDF5D2 #FDF5DC #FDF5E6
#FAC87D #FACD87 #FAD291 #FAD79B #FADCA5 #FAE1AF #FAE6B9 #FAEBC3 #FAEBCD #FAEBD7
#FFA500 #FFAF0A #FFB914 #FFC31E #FFCD28 #FFD732 #FFDC37 #FFE13C #FFE641 #FFEB46
#FF9100 #FF9B00 #FFA500 #FFAF00 #FFB900 #FFC300 #FFC800 #FFCD00 #FFD200 #FFD700
#FF8200 #FF8C0A #FF9614 #FFA01E #FFAA28 #FFB432 #FFB937 #FFBE3C #FFC341 #FFC846
#FFA98F #FFB399 #FFBDA3 #FFC7AD #FFD1B7 #FFDBC1 #FFE0C6 #FFE5CB #FFEAD0 #FFEFD5
#FFA374 #FFAD7E #FFB788 #FFC192 #FFCB9C #FFD0A1 #FFD5A6 #FFDAAB #FFDFB0 #FFE4B5
#FF9473 #FF9E7D #FFA887 #FFB291 #FFBC9B #FFC6A5 #FFD0AF #FFD0AF #FFD5B4 #FFDAB9
#FF7F50 #FF895A #FF9364 #FF9D6E #FFA778 #FFB182 #FFBB8C #FFC091 #FFC596 #FFCA9B
#CD853F #CD8F49 #D29953 #D7A35D #DCAD67 #E1B771 #E6C17B #EBC680 #F0CB85 #F5D08A
#D2691E #D27328 #D27D32 #D7873C #DC9146 #E19B50 #E6A55A #EBAA5F #EBAF64 #F0B469
#AE5E1A #B86824 #C2722E #CC7C38 #D68642 #E0904C #E59551 #EA9A56 #EF9F5B #F4A460
#8B4513 #8B4F1D #8B5927 #8B6331 #906D3B #957745 #9F814F #A48654 #A98B59 #AE905E

#FF9696 #FFA0A0 #FFAAAA #FFB4B4 #FFBEBE #FFC8C8 #FFD2D2 #FFDCDC #FFE6E6 #FFF0F0
#F08080 #F08A8A #F09494 #F59E9E #FAA8A8 #FAB2B2 #FAB7B7 #FABCBC #FAC1C1 #FAC6C6
#F56E6E #F57878 #F58282 #F58C8C #F59696 #F5A0A0 #F5AAAA #FAB4B4 #FABEBE #FAC8C8
#F06464 #F06E6E #F07878 #F08282 #F08C8C #F09696 #F4A0A0 #F4AAAA #F4B4B4 #FEBEBE
#FF0000 #FF3232 #FF4646 #FF5050 #FF5A5A #FF6464 #FF6E6E #FF7878 #FF8282 #FF8C8C
#EB0000 #EB3232 #EB4646 #EB5050 #EB5A5A #EB6464 #F06E6E #F57878 #FA8282 #FA8C8C
#CD0000 #CD3C3C #CD4646 #CD5050 #D25A5A #D76464 #DC6E6E #E17878 #E68282 #EB8C8C
#CD5C5C #CD6666 #CD7070 #CD7A7A #D28484 #D78E8E #DC9898 #E6A2A2 #EBACAC #F0B6B6
#B90000 #B93232 #B93C3C #B94646 #B95050 #BE5A5A #C35F5F #C86464 #CD6969 #D26E6E
#B22222 #B24040 #B24A4A #B25454 #B75E5E #BC6868 #C17272 #CB7776 #CB7C7C #D08180
#A52A2A #AA3E3E #AF4848 #B45252 #BE5C5C #C36666 #CD7070 #CD7A7A #D28484 #D78E8E
#800000 #803232 #853C3C #8F4646 #945050 #9E5A5A #A36464 #AD6E6E #B77878 #C18282

#CD853F #CD8B45 #CD904A #D2954F #D29A54 #D79F59 #D7A45E #E1A963 #E1AE68 #E6B36D
#DB631F #E56D29 #E57733 #EA813D #EF8B47 #EF904C #F49551 #F49A56 #F49F5B #F4A460
#D2691E #D27328 #D77D32 #D7873C #DC9146 #E19B50 #E6A055 #EBA55A #F0AA5F #F5AF64
#A0522D #A05C37 #A06641 #A5704B #AA7A55 #B4845F #B98E69 #C39873 #CDA27D #D7AC87
#8B4513 #8B4F1D #8B5927 #8B6331 #906D3B #9A7745 #A4814F #AE8B59 #B89563 #C29F6D
#DA70D6 #DF75DB #E47AE0 #E97FE5 #EE84EA #F389EF #F88EF4 #FD93F9 #FF98FE #FF9DFF
#BA55D3 #BF5AD8 #C45FDD #C964E2 #CE69E7 #D36EEC #D873F1 #DD78F6 #E27DFB #E782FF
#9932CC #9E37D1 #A33CD6 #A841DB #AD46E0 #B24BE5 #B750EA #BC55EF #C15AF4 #C65FF9
#9400D3 #9905D8 #9E0ADD #A30FE2 #A814E7 #AD19EC #B21EF1 #B723F6 #BC28FB #C12DFF
#942894 #9E329E #A83CA8 #B246B2 #BC50BC #C65AC6 #D064D0 #DA6EDA #E478E4 #EE82EE
#8c008c #960a96 #a014a0 #aa1eaa #b428b4 #be32be #c83cc8 #d246d2 #dc50dc #e65ae6
#800080 #8a0a8a #941494 #9e1e9e #a828a8 #b232b2 #bc3cbc #c646c6 #d050d0 #da5ada
#834683 #8d508d #975a97 #a164a1 #ab6eab #b578b5 #bf82bf #c98cc9 #d396d3 #dda0dd
#828282 #8c8c8c #969696 #a0a0a0 #aaaaaa #b4b4b4 #bebebe #c8c8c8 #d2d2d2 #dcdcdc
#000000 #282828 #323232 #3c3c3c #464646 #505050 #5a5a5a #646464 #6e6e6e #787878

'Computer > Web' 카테고리의 다른 글

웹 서핑하다가 발견한 사이트! - 링크나우  (1) 2007.10.12
웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 16. 08:11

servlet.jar , servlet-api.jar 파일을,시스템의 jre폴더의 lib/ext 안에 복사후 사용.
혹은 웹서버 lib폴더(TOMCAT_HOME/common/lib)에 넣고 사용.

* local의 기본 정보(IP, Name, Port)를 보여줌(local이라 하면 일반적으로 서버를 의미)
Local IP : =request.getLocalAddr()
Local Name : =request.getLocalName()
Local Port : =request.getLocalPort()

* 클라이언트의 정보(IP, Host, Port)
Remote IP : <%=request.getRemoteAddr()%>
Remote Host : <%=request.getRemoteHost()%>
Remote Port : =request.getRemotePort()

* 서버 이름, 포트(일반적으로 local 기본정보와 동일)
Server Name : <%=request.getServerName()%>
Server Port : <%=request.getServerPort()%>

* 지역 정보(대부분 한국을 의미하는 ko가 나옴)
Locale : <%=request.getLocale()%>

* 사용하는 프로토콜("프로토콜/메이저버전.마이너버전" 의 형태)
Protocol : <%=request.getProtocol()%>
http, https, ftp와 같은 것을 의미.
Scheme : <%=request.getScheme()%>

* https와 같은 보안 채널의 사용 여부(true/false 값으로 되어 있음)
Secure Channel : <%=request.isSecure()%>

* 요청에 대한 URI, URL, 컨텍스트 경로, 서블릿 경로, GET/POST등의 메소드를 나타냄
Request's URI : <%=request.getRequestURI()%>
Request's URL : <%=request.getRequestURL()%>

Context Path : <%=request.getContextPath()%>
Servlet Path : <%=request.getServletPath()%>
Method : <%=request.getMethod()%>

* 세션 ID에 대한 정보들
Session ID : <%=request.getRequestedSessionId()%>
Session ID from Cookie : <%=request.isRequestedSessionIdFromCookie()%>
Session ID from URL : <%=request.isRequestedSessionIdFromURL()%>
Session ID is still valid : <%=request.isRequestedSessionIdValid()%>

* Header 정보를 보는 방법
<%
 Enumeration eHeader = request.getHeaderNames();
 while (eHeader.hasMoreElements()) {
 String hName = (String)eHeader.nextElement();
 String hValue = request.getHeader(hName);

 out.println(hName + " : " + hValue + "<br>");
 }
%>

* Request 객체를 통해서 쿠키 정보를 보는 방식
<%
 Cookie cookies[] = request.getCookies();
 for (int i=0; i < cookies.length; i++) {
  String name = cookies[i].getName();
  String value = cookies[i].getValue();

  out.println(name + " : " + value + "<br>");
 }
%>

* HTML 폼을 통해 넘어온 데이터를 받는 부분
<%
 Enumeration eParam = request.getParameterNames();
 while (eParam.hasMoreElements()) {
  String pName = (String)eParam.nextElement();
  String pValue = request.getParameter(pName);

  out.println(pName + " : " + pValue + "<br>");
 }
%>

* 미리 설정한 attribute를 가져오는
<%
 Enumeration eAttr = request.getAttributeNames();
 while (eAttr.hasMoreElements()) {
  String aName = (String)eAttr.nextElement();
  String aValue = request.getHeader(aName);

  out.println(aName + " : " + aValue + "<br>");
 }
%>

'Computer > Web' 카테고리의 다른 글

웹 2.0 기술의 주역 - OpenAPI의 무한한 가능성  (0) 2007.05.10
색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
TAG

댓글을 달아 주세요

  1. BlogIcon 해토일도류 2009.05.06 06:05 신고  Addr  Edit/Del  Reply

    좋은 자료 감사합니다^^

posted by 희정냥★ 2007. 3. 12. 12:07

Code Conventions for the JavaServer PagesTM Version 1.x Language

JavaServer PagesTM (JSPTM)가 점점 널리 웹기반 어플리케이션으로 자리잡아가면서, 개발과 유지보수에 종사하는 많은 JSP 프로그래머들과 웹 개발자들은, 예전에 자바프로그래머들이 겪었던 것과 같은 딜레마에 직면했다. "어떻게 JSP 코드를 짜면 읽기, 쓰기, 유지보수하기를 일관적으로 쉽게 할 수 있을까?"

이 글은, 웹 컴포넌트를 사용하는 전형적인 소프트웨어 프로젝트에서 준수해야 할 JSP(1.1 과 1.2버전) 표준 작성요령을 제안한다. 이 문서의 모체는 자바 언어 코드 작성요령이다. (JSP 와 관련된) 코드 작성 방법 스펙에 소개된 다양하고 중요한 요소들을 확인할 수 있는 템플릿으로 삼았다. 특히, 파일명, 구성, 들여쓰기, 주석, 지시자, 선언문, 스크립틀릿, 표현식, 공백, 명명법(이름 짓는 법), 프로그래밍 습관 등을 소개한다. 처음으로 시도되는 JSP 코드 작성요령이기 때문에, 이 권고 문서에 대한 여러분들의 관심과 피드백을 기다린다. 연락처는 jsp-codeconv-comments@sun.com이다.

JSP 2.0 스펙에서는 1.2 버전을 모두 포용하지만, 스크립트가 없는 프로그래밍 스타일(선언문, 스크립틀릿, 표현식이 없는)을 지향하고, 수많은 새 특징들을 갖고 있어서, 이 작성요령을 더 진보시켜야 될 필요가 있다. 가능한 한, 이 문서는 새로운 JSP 2.0 특징에 도움을 주는 작성방식을 선택했다.

마지막으로, 이 글을 읽는 수준은 JSP, Java, 자바 코드 작성요령에 익숙해야 하고, 이미 프로젝트를 수행하는 팀에 적용이 되어 있어야 된다. 그렇지 않다면, 이 링크를 읽어 보기를 추천한다. Java 링크 JSP 링크.

 

왜 코드 작성요령이 필요한가? Why Have Code Conventions?

코드 작성요령은 프로그래머와 웹 컨텐츠 개발자에게 여러 가지 이유로 중요하다:

  1. 소프트웨어 산출물의 가독성을 향상시킨다.
  2. 견습 관리와 노력을 경감한다.
  3. 표준화에 대한 조직적 참여도를 배가시킨다.

파일 이름과 위치 File Names and Locations

파일 이름짓기는 툴 벤더와 웹 컨테이너로 하여금 파일 타입을 인식하고, 각각에 맞게 해석할 수 있는 방법을 제공한다. 다음 테이블은 추천하는 방식의 파일 확장자와 위치 목록이다. 

File Type File 확장자 추천 위치
JSP .jsp <context root>/<subsystem path>/
JSP fragment .jsp <context root>/<subsystem path>/
.jspf <context root>/WEB-INF/jspf/<subsystem path>/
cascading style sheet .css <context root>/css/
javascript .js <context root>/js/
HTML page .html <context root>/<subsystem path>/
web resource .gif, .jpg, etc. <context root>/images/
tag library descriptor .tld <context root>/WEB-INF/tld/

위 테이블을 볼 때 몇 가지 유념할 것이 있다. 우선, <context root> 는 웹 어플리케이션(.war 파일 내의 루트 디렉토리) 컨텍스트의 루트이다. 둘째로, <subsystem path> 는 동적, 정적 웹페이지 컨텐츠의 논리적인 그룹으로 나누도록 한다. 작은 웹 어플리케이션일 경우, 이게 필요하지 않을 수도 있다. (한 곳에 모두 놓아도 된다.)

세째로, 다른 JSP 파일에 포함되는 JSP 를 언급할 때 JSP fragment (JSP 프래그먼트 조각)라는 용어를 사용한다. 주의할 것은 JSP 2.0 에서는 "JSP fragment" 용어가 겹치기 때문에 "JSP 세그먼트(JSP segment)" 용어가 대신 사용된다. JSP fragment 는 확장자로 .jsp 또는 .jspf 를 사용하고, /WEB-INF/jspf나 다른 정적인 컨텐츠와 함께 각각 위치하면 된다. 불완전한 JSP fragment는 언제나 .jspf 확장자를 사용하고, /WEB-INF/jspf에 위치해야 된다. 네째로, JSP 스펙에서는 JSP fragment 확장자로 .jspf.jsp 양쪽 모두를 권장하지만, 추천하는 것은 .jspf 인데, .jsfJavaServer Faces™ 스펙에서 사용될 것이기 때문이다.

끝으로, 태그 라이브러리 디스크립터 파일이나 다른 비공개적인 컨텐츠는 WEB-INF/ 또는 이 하위 디렉토리에 놓아두는 것은 보편적으로 좋은 습관이다. 웹 컨테이너는 WEB-INF/ 아래 있는 어떤 파일도 송출하지 않기 때문에, 이 방법을 사용하면, 클라이언트가 접근하거나 볼 수 없게 된다.

배치 설명자(web.xml)의 welcome-file 엘리먼트에 선언되어 있는 웰컴 파일의 이름은 동적인 컨텐츠를 생성하려면, index.jsp 가 되어야 되고, 정적인 웰컴 페이지라면 index.html 로 해야 한다. 

JSP 파일을 다국어로 작성할 때, 로케일에 따라 디렉토리를 나누어 그룹 짓기를 추천한다. 예를 들어서 index.jsp 의 US English 버전은 /en_US/index.jsp 에, 같은 파일의 일본어판은 /ja_JP/index.jsp 에 있게 한다. 일반적으로 자바 코드의 국제화에 관한 추가적인 정보는 Java Tutorial 에 있고, 웹 어플리케이션의 국제화에 대한 정보는 Designing Enterprise Applications with the J2EETM Platform 책에 나와있다.

파일 구조 File Organization

구조가 잘 갖춰진 소스 코드 파일은 읽기 쉽고, 파일 사이에 정보를 더 빨리 놓아둘 수 있다. 이 섹션에서, JSP와 태그 라이브러리 디스크립터 파일 모두를 위한 구조를 소개하려한다.

JSP 파일 / JSP Fragment 파일

JSP 파일은 다음의 섹션들이 나열한 순서대로 구성된다:

  1. 도입 주석
  2. JSP 페이지 지시자(directive)
  3. 선택적 태그 라이브러리 지시자
  4. 선택적 JSP 선언문
  5. HTML 과 JSP 코드

도입 주석 Opening Comments

JSP 파일 또는 프래그먼트 파일은 서버측 주석으로 시작한다:

<%--
  - 작성자:
  - 일자:
  - 저작권 표시:
  - @(#)
  - 설명:
  --%>

이 주석은 서버측에서만 볼 수 있다. JSP 변환 과정에서 제거되기 때문이다. 여기에는 웹 개발자를 위한 JSP에 대한 작성자, 일자, 개정판의 저작권, 증명과 설명이 포함된다. "@(#) " 문자 조합은 증명의 시작을 지시하는 것으로 어떤 프로그램에서 인식된다. 이런 표식을 사용하는 프로그램들은 많이 사용되지 않지만, 있어도 해가 될 것은 없다. 추가로, 이 조합은 때때로 "$Id$" 를 덧붙여서, 어떤 종류의 버전 관리 프로그램에서는 자동으로 증명 정보를 JSP에 기록하도록 한다. 설명 부분은 JSP의 목적에 관한 축약된 정보를 제공한다. 한 문단 이상 넘어가지 않도록 한다.

어떤 상황에서는, 도입 주석이 JSP 변환과정을 지나서 출처가 확실하다는 뜻과 법적인 목적으로 클라이언트의 브라우저에 보여질 필요가 있다. 이럴 경우 주석 부분을 두개로 나눠서 우선 클라이언트측 스타일의 주석을 단다:

<!--
  - Author(s):
  - Date:
  - Copyright Notice:
  --%>

그리고 나서 짧아진 나머지 서버측 스타일의 주석을 단다:

<%--
  - @(#)
  - Description:
  --%>

JSP 페이지 지시자 JSP Page Directive(s)

JSP 페이지 지시자는 JSP 변환 시점에 관련된 속성을 정의한다. JSP 스펙은 같은 페이지에 JSP 페이지 지시자의 수량을 제한하지 않는다. 그래서 다음 두 개의 코드 예제는 똑같다.(다른 점이 있는데, 첫 예제는 출력시에 맨 위에 두 개의 빈 줄이 포함된다):

코드 예제 1:

<%@ page session="false" %>
<%@ page import="java.util.*" %>
<%@ page errorPage="/common/errorPage.jsp" %>

페이지 지시자 같이 지시자의 길이가 일반적인 JSP 폭(80 문자)을 넘어갈 경우 여러 줄로 나눠진다:

코드 예제 2:

<%@ page    session="false"
            import="java.util.*"
            errorPage="/common/errorPage.jsp"
%>

일반적으로, 코드 예제 2는 코드 예제 1보다 즐겨 사용된다. 예외가 있는데, 매우 긴 import 속성을 쓰게 되는, 여러 개의 자바 패키지가 JSP페이지에서 필요할 경우이다:

<%@ page    session="false"
               import="java.util.*,java.text.*,
                   com.mycorp.myapp.taglib.*,
                       com.mycorp.myapp.sql.*, ..."
...
%>

이런 경우, 페이지 지시자를 다음과 같이 나누는 것이 즐겨사용된다:

<%-- import를 제외한 모든 속성 --%>
<%@ page
...
%>
<%-- import 속성들은 여기부터 시작 --%>
<%@ page import="java.util.*" %>
<%@ page import="java.text.*" %>
...

주의할 점은, 일반적으로 import문은 자바의 지역 코드 작성요령을 준수한다. 예를 들어, 같은 패키지에서 세 개의 클래스까지만 사용되면, import 는 패키지를 선언하기 보다는, 클래스를 일일이 선언한다. 세 개를 넘어가면, 클래스를 일일이 지정할 것인지 아니면, ".*" 표시를 사용할 것인지는 웹 개발자 마음이다. 전자의 경우, 외부 클래스가 무엇이 사용되는지를 쉽게 알수 있다. 특히 버그가 많은 클래스를 위치시키려고 하거나, JSP 가 자바 코드와 어떻게 상호작용하는지를 이해하려할 경우에 유용하다. 예를 들어서, 아래처럼 임포트한 자바 패키지들에 관해 알지 못하면, 웹 개발자는 Customer 클래스를 찾기 위해서 이 모든 패키지들을 검색해봐야 된다:

<%@ page import="com.mycorp.bank.savings.*" %>
<%@ page import="com.thirdpartycorp.cashmanagement.*" %>
<%@ page import="com.mycorp.bank.foreignexchange.*" %>
...

후자의 경우, 작성된 JSP 가 깔끔하지만, 사용한 클래스가 무엇인지 아는 것은 어려워진다. 일반적으로, JSP 에 임포트 지시자가 너무 많으면, 자바 코드가 너무 많이 들어가 있기 쉽다. 보다 나은 선택은 JSP 태그를 더 사용하는 것이다.(후에 언급하겠다).

선택적 태그 라이브러리 지시자 Optional Tag Library Directive(s)

태그 라이브러리 지시자는 JSP 에서 사용하는 커스텀 태그 라이브러리를 선언한다. 짧은 지시자는 하나의 줄에 선언할 수 있다. 여러 개의 태그 라이브러리 지시자들은 JSP 의 한 곳에 같이 모아둔다:

<%@ taglib uri="URI1" prefix="tagPrefix1" %>
<%@ taglib uri="URI2" prefix="tagPrefix2" %>
...

페이지 지시자처럼, 태그 라이브러리 지시자의 길이가 일반적인 JSP 폭(80 문자)을 넘어갈 경우 여러 줄로 나눠진다:

<%@ taglib
    uri="URI2"
    prefix="tagPrefix2"
%>

오직 페이지에서 사용하는 태그 라이브러리만 임포트되어야 한다.

JSP 1.2 부터, 웹 어플리케이션의 JSP에 JSTL;JSP 표준 태그 라이브러리사용하기를 적극 권장한다. 페이지에서 JSP 스크립틀릿 사용할 필요를 줄여주기 때문이다. 일반적으로, JSTL을 사용하는 페이지는 소스읽기와 유지보수가 보다 편하다.

선택적 JSP 선언문 Optional JSP Declaration(s)

JSP 선언문은 JSP에서 소속된 메소드와 변수를 선언한다. 이들 메소드와 변수는 자바 프로그램에서의 선언문과 다를바 없다. 그래서 적절한 코드 작성요령을 따르기만 하면 된다. 선언문은 <%! ... %> JSP 선언문 블록 하나에 모두 몰아서 한 곳에 집중해 놓는 것이 좋다. 예를 들면:

다른 선언문 블록들 바람직한 선언문 블록
    <%! private int hitCount; %>
    <%! private Date today; %>
    ...
    <%! public int getHitCount() {
            return hitCount;
        }
    %>
    
    <%!
        private int hitCount;
        private Date today;

        public int getHitCount() {
            return hitCount;
        }
    %>

HTML 과 JSP 코드 HTML and JSP Code

이 섹션은 JSP 코드와 HTML 이 섞여있는 페이지에 대해 설명한다. JSP 표현식, 스크립틀릿, 자바빈즈 지시자 등이 해당된다.

태그 라이브러리 설명서 Tag Library Descriptor

태그 라이브러리 설명서(TLD)는 적당한 XML선언과 올바른 DTD 문으로 시작한다. 예를 들어서, JSP 1.2 TLD 는 다음과 같이 시작해야 된다:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
    "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

바로 뒤이어 서버측 주석과 같은 스타일의 주석을 기입한다. 작성자, 일자, 저작권, 증명 정보, 라이브러리에 대한 짧은 설명이다:

<!--
  - 작성자:
  - 일자:
  - 저작권 표시:
  - @(#)
  - 설명:
  -->
 

여기에 관한 규칙과 가이드라인은 JSP 파일/프래그먼트 파일에서 정의된 것과 동일하다.

태그 라이브러리 파일의 나머지는 다음에 나오는 순서대로 이루어져 있다:

  • 태그 라이브러리 검증기 하나의 선택적 선언문
  • 이벤트 리스너들의 선택적 선언문
  • 하나 이상의 가능한 태그들의 선언

TLD 에서 엘리먼트 마지막에 선택적 서브 엘리먼트를 항상 덧붙이기를 추천한다. 이 선택적 서브 엘리먼트는 태그 디자이너가 TLD의 습성과 추가적인 정보를 문서화할 장소를 제공한다. 이것은 웹 컴포넌트 개발자들에게는 보이지 않게 된다.

TLD Element JSP 1.2 Recommended
Sub-element
JSP 1.1 Recommended
Sub-element
attribute (JSP 1.2) description  
init-param (JSP 1.2) description  
tag display-name, description, example name, info
taglib uri, display-name, description uri, info
validator (JSP 1.2) description  
variable (JSP 1.2) description  

들여쓰기 Indentation

들여쓰기는 반드시 공백문자로 채워야한다. 탭은 사용하는 에디터마다 표시하는 공백의 수가 다르기 때문에 JSP 내에서 들여쓰기로 사용하기에는 적합하지 않다. 특별히 통합개발환경(IDE) 툴에서 제한되지 않았다면, 기본 들여쓰기 단위는 4개의 공백문자로 한다. 다음은 그 사용예이다:

<myTagLib:forEach var="client" items="${clients}">
    <myTagLib:mail value="${client}" />
</myTagLib:forEach>

연속 들여쓰기는 이전 줄의 적당한 지점에서 시작한다. 연속 들여쓰기의 공백은 기본 들여쓰기 공백의 배수이다. (4개의 공백문자의 배수):

<%@ page    attribute1="value1"
            attribute2="value2"
            ...
            attributeN="valueN"
%>

스크립트 엘리먼트의 들여쓰기 Indentation of Scripting Elements

JSP 스크립트 엘리먼트(선언문, 스크립틀릿, 표현식과 같은)가 한 줄에 맞지 않는 경우, 스크립트 언어의 들여쓰기 작성요령이 엘리먼트 내에 적용된다. 몸체는 엘리먼트의 여는 기호 <%=와 같은 줄에서 시작한다. 다음줄의 기준도 여는 기호 <%=가 된다. 몸체의 끝은 다른 줄에 있는 엘리먼트의 닫는 기호(%>)로 마무리된다. 예제이다:

<%= (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
        = Calendar.SUNDAY) ?
    "Sleep in" :
    "Go to work"
%>

첫줄과 마지막 줄을 제외한 몸체의 가운데 줄들은 단위 들여쓰기 공백(앞 예제에서  로 보인다)이 앞에 있기 때문에 나머지 JSP 보다 확연히 드러나게 된다.

JSP, HTML, JAVA의 복합 들여쓰기 Compound Indentation with JSP, HTML and Java

자바의 스크립트 코드와 템플릿 텍스트(HTML)가 섞여있는 JSP 엘리먼트를 위해서 복합 들여쓰기가 필요한 이유는 JSP 소스를 이해하기 위해 드는 노력을 덜어주기 위해서이다. 기존의 들여쓰기 요령은 JSP 소스파일을 더 알아보기 어렵게 할 수 있기 때문이다. 보편적인 규칙에 따라서, 다른 소스 사이에 끼어 있을 경우마다 보통 들여쓰기에 특별한 단위를 할당한다. 클라이언트에 보여지는 들여쓰기에 영향을 준다. 추가적인 들여쓰기는 (브라우저에 의해) 보통 무시되고, 브라우저에 나타나는 결과는 차이가 없다. 예를 들어, <TABLE> 태그 앞에 공백이 몇 개 더 추가된다고 해서, 브라우저에서 보여지는 테이블의 위치가 달라지는 것은 아니다. 그래서 이러한 작성요령을 사용하는 것이 더 좋아 보인다:

    <table>
        <%  if { tableHeaderRequired ) { %>
            <tr>
                <th>Last Name</th>
                <th>First Name</th>
            </tr>
        <%  } %>
        <c:forEach var="customer" items="${customers}">
            <tr>
                <td><c:out value="${customer.lastName}"/></td>
                <td><c:out value="${customer.firstName}"/></td>
            </tr>
        </c:forEach>
    </table>

위 방식보다는 아래 방식이 낫다:

    <table>
        <%  if { tableHeaderRequired ) { %>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
        </tr>
        <% } %>
        <c:forEach var="customer" items="${customers}">
        <tr>
            <td><c:out value="${customer.lastName}"/></td>
            <td><c:out value="${customer.firstName}"/></td>
        </tr>
        </c:forEach>
    </table>

주석 Comments

주석은 추가 정보 전달이나 코드를 둘러쌀 목적으로 사용한다. 여기서는 JSP에서 사용하는 두가지 형태의 주석을 볼 것이다: JSP 측과 클라이언트 측 주석이다.

JSP 주석 JSP Comments

JSP 주석(또는 서버 측 주석)은 서버에서만 볼 수 있다(즉, 클라이언트로 전파되지 않는다). 순수 JSP 주석을 스크립팅 언어와 섞여있는 JSP 주석보다 즐겨 사용한다. 전자가 기반 스크립트 언어에 덜 종속적이기 때문이고, JSP 2.0 으로 진화하기 더 쉽기 때문이다. 다음 도표는 이것을 설명한다:

Line JSP 스크립틀릿과 스크립트 언어 주석 순수 JSP 주석
한 줄
    <% /**  ...  */ %>
    <% /*  ...  */ %>
    <% //  ...  %>
    
    <%--  ...  --%>
    
여러 줄
    <%
    /*
     *
    ...
     *
     */
    %>
    
    <%--
      -
     ...
      -
      -- %>
    <%
    //
    //
    ...
    //
    %>
    

클라이언트 측 주석 Client Side Comments

클라이언트 측 주석(<!-- ... -->)은 응답에 대해서 부가적인 정보를 클라이언트로 보내기 위해 응답에 주석을 다는 것이다. 서버 어플리케이션의 행동이나 내부적인 구조에 대한 것과 응답 내용을 생성하는 코드가 포함되어서는 안된다.

클라이언트/사용자의 입장에서 서버에서 보내온 응답을 해석하기 위해서 이런 종류의 주석을 직접 볼 필요가 없기 때문에, 클라이언트 측 주석은 보편적으로 사용되지 않는다. 앞서 얘기한대로 증명이나, 저작권 정보 등의 법적인 목적의 증명에 사용될 경우는 예외가 되겠다. 다른 예외적인 경우는 HTML 저작도구들이 HTML 문서 구조의 틀을 잡아주기 위해 작은 양의 HTML 주석들을 사용하는 경우가 되겠다. 예를 들면 다음과 같다:

<!-- 툴바 섹션 -->
    ...
<!-- 왼쪽 네비게이션 메뉴 -->
    ...
<!-- main body -->
    ...
<!-- footer -->
    ...

여러 줄의 주석 Multiline Comment Block

JSP 또는 클라이언트 측 모두, 여러 줄의 주석은 대시 문자 "-" 로 꾸며진다. XML 스펙에서, 더블-대시 문자열 "--"은 XML 주석 문 내에 허용되지 않는다. 그러므로, 이 스펙에 호환성과 일관성을 갖기 위해서, 더블-대시 문자열은 여러줄의 주석문 내에 사용되면 안된다. 다음 도표는 클라이언트 측 여러 줄 주석 사용법을 보여준다:

권장 XML과 맞지 않는 법
    <!--
      - line 1
      - line 2
    ...
      -->
    
    <!--
      -- line 1
      -- line 2
    ...
      -->
    

JSP 선언문 JSP Declarations

자바 코드 작성요령에 따라서, 같은 타입의 변수 선언문은 다른 줄에서 이루어져야 된다:

비 추천 추천
    <%! private int x, y; %>
    
    <%! private int x; %>
    <%! private int y; %>
    

자바빈즈는 <jsp:useBean> 액션 태그를 사용하는 대신, JSP 선언문을 통해서 선언되고 인스턴스화되면 안된다.

일반적으로, 변수를 위한 JSP 선언문은 그 자체가 스크립트 언어의 사용을 부추기기 때문에 사용하지 않는 것이 좋다. JSP 는 프리젠테이션 목적으로 설계되었는데, 여기에 비지니스 로직과 자바코드를 섞어놓기 때문이다. 그리고, 변수의 스코프 관리에 따른 부담도 생기게 된다.

JSP 스크립틀릿 JSP Scriptlets

가급적, 태그라이브러리로 동일한 기능을 구현할 수 있으면, JSP 스클립틀릿은 피하기 바란다. 이렇게 하면 페이지 가독성도 높이고, 유지보수도 쉬워진다. 비지니스 로직을 프리진테이션 로직에서 분리하는데 일조하며, JSP 2.0 스타일의 페이지로 쉽게 옮겨갈 수 있다(JSP 2.0 도 스크립틀릿을 지원하지만 덜 강조한다). 다음 예제는 customers 표시 방법이 데이터 형에 따라서 다른 스크립틀릿을 사용하는 것을 보여준다:

customers 는 Customers의 배열

    <table>
        <%  for ( int i=0; i<customers.length; i++ ) { %>
            <tr>
                <td><%= customers[i].getLastName() %></td>
                <td><%= customers[i].getFirstName() %></td>
            </tr>
        <%  } %>
    </table>

customers 는 Enumeration

    <table>
        <%  for ( Enumeration e = customers.elements();
                e.hasMoreElements(); ) {
                Customer customer = (Customer)e.nextElement();
        %>
            <tr>
                <td><%= customer.getLastName() %></td>
                <td><%= customer.getFirstName() %></td>
            </tr>
        <%  } %>
    </table>

그러나, 공통 태그라이브러리를 사용하면, customers 의 데이터 형이 달라도 보다 높은 유연성이 생긴다. 예를 들어서, JSTL 에서는customers 를 나타내기 위해서 배열과 Enumeration 양쪽 모두 지원하는 다음과 같은 코드로 표시할 수 있다:

    <table>
        <c:forEach var="customer" items="${customers}">
            <tr>
                <td><c:out value="${customer.lastName}"/></td>
                <td><c:out value="${customer.firstName}"/></td>
            </tr>
        </c:forEach>
    </table>

비지니스 로직과 프리젠테이션 층과의 결합도을 줄이기 위한 모델-뷰-컨트롤러(MVC) 디자인 패턴을 적용하려고 한다면, JSP 스크립틀릿은 비지니스 로직을 구현하기 위해서 사용되어서는 안된다. 오히려, JSP 스크립틀릿은 클라이언트의 요청을 처리한 뒤에 나오는 데이터("가치 객체 value objects"로 불리는)를 적절한 클라이언트의 준비된 형식에 전송하기 위해 필요하다면 사용된다. 심지어 그럴 경우에도, 프론트 컨트롤러 서블릿이나 커스텀 태그로 하는 게 더 낫다. 예를 들면, 다음의 코드는 데이터베이스에서 직접 customers 의 이름을 가져와 클라이언트에 보여준다:

<%
    // 스크립틀릿을 이용하는 것은 추천하지 않음!

    Connection conn = null;
    try {
        // Get connection
        InitialContext ctx = new InitialContext();
        DataSource ds = (DataSource)ctx.lookup("customerDS");
        conn = ds.getConnection();

        // Get customer names
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT name FROM customer");

        // Display names
        while ( rs.next() ) {
            out.println( rs.getString("name") + "<br>");
        }
    } catch (SQLException e) {
        out.println("Could not retrieve customer names:" + e);
    } finally {
        if ( conn != null )
            conn.close();
    }
%>

다음의 JSP 코드는 데이터베이스 처리부분을 내부적으로 데이터베이스 코드의 의존성을 숨기고 캡슐화한 커스텀태그myTags:dataSource에 위임하고 있기 때문에 더 보기 좋다:

<myTags:dataSource
    name="customerDS"
    table="customer"
    columns="name"
    var="result" />
<c:forEach var="row" items="${result.rows}">
    <c:out value="${row.name}" />
    <br />
</c:forEach>

result 는 커스텀 태그 myTags:dataSource가 customer 데이터베이스에서 customer의 이름들 뽑아낸 결과를 담으려고 만들어 낸 스크립팅 변수이다. JSP 코드는 클라이언트의 요구에 따라 동적으로 다른 종류의 출력(HTML, XML, WML)을 생성하기 위해 확장할 수 있다. 그것도 백엔드 코드(dataSource 태그를 위한)를 변경하지 않고도 가능하다. 더 나은 선택은 이것을 프론트 컨트롤러 서블릿에 위임하는 것이다. 이 서블릿은 데이터를 불러와서 그 결과를 request 스코프의 속성을 통해서 JSP에 제공한다. 예제는 자바 BluePrint의 엔터프라이즈 섹션을 참고하기 바란다.

요약하면 :

  • 이상적으로, 스크립트 언어로부터 독립하기 위해서 JSP 스크립틀릿은 JSP 내에서 사라져야 되고, JSP 내의 비지니스 로직 구현은 피해야 된다.
  • 그것이 불가하면, 서버 측에서 정보를 전달하는데 값 객체(자바빈즈)를 사용하고, JSP 스크립틀릿은 클라이언트 출력에 이 값 객체를 전달하는 데 사용한다.
  • 가능하면 커스텀 태그(태그 핸들러)를 사용해서 서버측에서 정보를 처리하도록 한다.

JSP 표현식 JSP Expressions

JSP 표현식은 JSP 스크립틀릿처럼 가능하면 삼가는 것이 좋다. 동일한 작업을 수행하는 다음 3가지 예제가 잘 설명해준다:

Example 1 (자바 코드 사용):

    <%= myBean.getName() %>

Example 2 (JSP 태그 사용):

    <jsp:getProperty name="myBean" property="name" />

Example 3 (JSTL 태그 사용):

    <c:out value="${myBean.name}" />

Example 1 은 myBean 이라는 스크립트 변수가 선언된 것이라고 가정한다. 다른 두 예제에서 myBean은 어떤 스코프의 속성으로 PageContext.findAttribute()을 통해서 접근할 수 있다고 가정한다. 두 번째 예제는 또한 <jsp:useBean> 에 의해서 페이지에 소개된 myBean이라고 가정한다.

셋 중에서 JSTL 태그 예제가 낫다. JSP 표현식 만큼 짧고, 가독성도 좋고, 유지보수하기도 보다 편하다. 그리고, 자바 스크립틀릿에 의존하지 않는다(스크립틀릿은 자바 언어와 API 함수들에 익숙해야 다룰 수 있다.) 더우기, JSP 2.0 스타일 프로그램으로 쉽게 이동할 수 있는 장점이 있다. 어떤 선택이 채택되든, 모든 개발자들의 동의를 얻어서, 같은 프로젝트에 있는 JSP 결과물들은 전체적으로 일관된 방식을 사용해야 된다.  주의할 점은, JSTL 예제는 로컬 자바 스크립트 변수로부터가 아닌, page 컨텍스트로부터 myBean 의 값을 가져온다는 것이 실질적으로 조금 다른 점이다.

마지막으로, JSP 표현식은 기반 스크립팅 언어의 문법에 의존하는, 같은 기능의 JSP 스크립틀릿보다 낫다. 예를 들어,

    <%= x %>

로 하는 게 아래 방법보다 좋다.

    <% out.print( x ); %>

공백 White Space

코드의 이해와 유지보수에 드는 노력을 줄이기 위해서 JSP 코드를 보기 좋게 들여쓰기하는데 공백을 사용한다. 특히, 빈 줄과 공백은 필요한 곳에서 JSP 의 여러 곳에 삽입되어야 한다.

빈 줄 Blank Lines

빈 줄은 출력에 원하지 않는 영향만 주지 않는다면 JSP의 가독성을 높이기 위해서 가끔 사용된다. 아래 예제에서, HTML <PRE> 블록 내에 두 개의 JSP 표현식 사이에 있는 빈 줄은 클라이언트의 브라우저에 HTML 출력 결과에서 한줄 더 생기게 만든다. 그러나 빈 줄이 <PRE> 블록 사이에 있지 않다면, 브라우저의 출력에 나타나지 않는다.

JSP 구문 클라이언트의 HTML 출력
    <pre>
    <%= customer.getFirstName() %>
    <%= customer.getLastName() %>
    </pre>
    
    Joe
    Block
    
    <pre>
    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>
    </pre>
    
    Joe

    Block
    
    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>
    
    Joe Block
    

빈 문자열 Blank Spaces

공백 문자( ; 역자주:공백은 길이가 1, 빈 문자열은 ""처럼 길이가 0)는 JSP 태그와 몸체 사이에 쓰여져야 된다. 예를 들어 다음

    <%= customer.getName() %>

코드는 아래 것보다 좋다.

    <%=customer.getName()%>

JSP 주석 태그와 주석을 분리하는 공백 문자들이 있어야 된다:

<%--
  - 여러 줄의 주석이 나뉘어지면, 각각의 줄은
  - 한 줄씩 차지한다.
  --%>
<%-- 짧은 주석 --%>

이름짓는 요령 Naming Conventions

이름짓는 요령을 적용하면, 프로젝트 내의 웹 컴포넌트 엘리먼트들을 쉽게 확인, 분류, 통합할 수 있다. 이 섹션에서, JSP에 적합한 요령을 살펴보자.

JSP 이름 JSP Names

JSP (파일) 이름은 언제나 소문자로 시작해야 한다. 여러 개의 단어로 구성될 수 있고, 이러한 경우 단어들은 모두 붙여쓰고, 이어지는 단어의 첫글자는 대문자로 쓴다. JSP 이름은 간단한 명사나 짧은 문장이 될 수 있다. 동사뿐인 JSP 명은 개발자에게 충분한 의미를 전달하지 못하기 때문에, 피하도록 한다. 예를 들면:

    perform.jsp

파일은 다음 파일보다 명확하지 않다.

    performLogin.jsp

JSP 이름에 동사가 들어가는 경우, 은연 중에 뒷쪽에서 처리하고 있다는 표시로 현재형을 쓴다:

    showAccountDetails.jsp

로 쓰는 게 아래 파일명 보다 좋다

    showingAccountDetails.jsp

태그 이름 Tag Names

태그 핸들러와 관련된 클래스에 대한 이름짓는 요령은 다음과 같다:

설명 클래스 명
XXX tag extra info (javax.servlet.jsp.tagext.TagExtraInfo를 상속함) XXXTEI
XXX tag library validator (javax.servlet.jsp.tagext.TagLibraryValidator를 상속함) XXXTLV
XXX tag handler interface (javax.servlet.jsp.tagext.Tag/IterationTag/BodyTag를 상속함) XXXTag
XXX tag handler implementation XXXTag

덧붙여, 태그 이름은 자바에 관련된 코드작성법에서 정한 클래스와 인터페이스 이름 짓는 요령을 따라서 정해야 된다.

태그 관련된 클래스와 다른 클래스와 더 분명하게 구분하기 위해서, 패키지 접미사(tags 또는 taglib)를 클래스의 패키지명에 적용한다. 예를 들면:

    com.mycorp.myapp.tags.XXXTag

태그 prefix 이름 Tag Prefix Names

태그 prefix 는 짧지만 의미가 담긴 명사를 사용해야 하고, 첫문자는 소문자로 해야한다. 태그 prefix 는 알파벳 문자만 포함해야 된다. 몇 가지 예를 들면 다음과 같다:

OK?
mytaglib no
myTagLib yes
MyTagLib no
MyTagLib1 no
My_Tag_Lib no
My$Tag$Lib no

XML 문법의 JSP 페이지 JSP Pages in XML Syntax

JSP 는 두가지 다른 문법을 제공한다: JSP 페이지를 작성하는 '표준 문법'과 JSP를 XML문서로 작성하는 'XML 문법'이 있다. 표준 문법을 사용하는 JSP 페이지들이 'JSP 페이지'로 많이 쓰인다. XML 문법으로 작성된 JSP는 'JSP 문서'라고 일컫는다. 이 기사는 우선적으로 JSP 페이지를 소개하지만, 많은 부분의 개념들이 JSP 문서에도 역시 적용될 수 있다. XML이 좀 더 유행하면 JSP 문서 사용도 많아질 것이라고 기대된다. JSP 2.0 스펙에서는 더 많은 XML 문법 친화적인 것들이 소개될 것이다.

주의할 것은 XML 문법을 이용해서 JSP를 만드는 것과 JSP로 XML 결과(view)를 만들어 내는 것과 혼동해서는 안된다. 페이지 제작도구는 JSP를 만들기 위해 표준 또는 XML 문법을 사용한다. 그리고 나서 컨테이너는 JSP를 XML 결과로 변환하고, 이것은 태그 라이브러리 밸리데이터(유효성 검증기)에서 확인한다.

JSP 문서 구조 JSP Document Structure

JSP 문서는 다음과 같은 기본 구조를 갖는다:

    <? xml version="1.0" ?>
    <!--
      - Author(s):
      - Date:
      - Copyright Notice:
      - @(#)
      - Description:
      -->
    <jsp:root   xmlns:jsp="http://java.sun.com/JSP/Page"
                xmlns:prefix1="URI-for-taglib1"
                xmlns:prefix2="URI-for-taglib2"
                version="1.2">
        JSP Document ...
    </jsp:root>

첫 줄은, 이 페이지가 XML 문서라고 정의하는 선택적 XML 프롤로그이다. 다음으로 오는 것은 문서에 대한 주석이다. <jsp:root> 엘리먼트는 이것이 JSP 문서임을 정의하고, 반드시 이 엘리먼트가 루트 엘리먼트로 나타나야 된다. jsp 이름공간은 반드시 가져와야 되고, 모든 태그 라이브러리는 이 루트 엘리먼트를 사용해서 가져와야 된다. 버전 속성이 필요하고, 어떤 버전을 사용할 지를 정해준다. JSP 문서의 실제 내용은 <jsp:root> 엘리먼트의 서브엘리먼트에 나타난다. 표준 XML 들여쓰기 룰에 따라서 문서 전체적으로 일관되게 적용하는 들여쓰기 단위는 4개의 공백문자이다.

JSP 문서는 형식이 잘 갖춰진 XML 문서이기 때문에, <% %> 와 같은 엘리먼트는 <jsp:scriptlet /> 같이 XML로 바꿔서 표기해야 된다. 자세한 것은 JSP 스펙을 보기 바란다.

XML 주석 XML Comments

JSP 스펙은 XML 스타일의 주석을 어떻게 처리할 지에 대해 불분명하기 때문에, 주석이 클라이언트로 안전하게 전달되기 위해서는, <jsp:text>로 다음과 같이 감싸주어야 된다:

    ...
    <jsp:text><![CDATA[
        <!--
          - Multiline comment
          - to be sent to client.
          -->
    ]]></jsp:text>
    ...

JSP 문서 내의 자바 코드 Java Code in JSP Documents

선언문, 스크립틀릿, 표현식에서 자바 코드를 쓰려고 할 때, 코드가 문서의 구조를 망가뜨리지 않는다면, CDATA엘리먼트를 사용한다.

    ...
    <jsp:scriptlet>
        for( int level = 0; level < 3; level++ ) {
    </jsp:scriptlet>
    <tr>
        <td>
            <jsp:expression><![CDATA[
                "<h" + level + ">Text</h" + level + ">"
            ]]></jsp:expression>
        </td>
    </tr>
    <jsp:scriptlet>
        }
    </jsp:scriptlet>
    ...

표준 문법에서와 다르게, XML 들여쓰기 법칙은 엘리먼트의 내용과 상관없이 준수되어야 한다.

프로그래밍 습관 Programming Practices

일반적으로, 다음과 같은 이유로 JSP 페이지에 자바 코드(선언문, 스크립틀릿, 표현식) 쓰기를 피한다:

  • JSP 페이지의 자바 코드 문법 에러는 페이지가 배치되기 전까지 발견되지 않는다. 반면에, 태그 라이브러리와 서블릿에 있는 문법 에러는 배치 이전에 발견된다.
  • JSP 페이지 내의 자바 코드는 디버깅하기 힘들다.
  • JSP 페이지 내의 자바 코드는 유지보수하기 힘들다. 특히 자바 전문가가 아니라면 더욱 더 그렇다.
  • 보통 복잡한 비즈니스 로직과 프리젠테이션 로직을 섞어놓지 않는 것이 납득이 가는 습관이다. JSP는 우선적으로 프리젠테이션 로직을 목적으로 한다.
  • 자바 코드가 포함된 코드와 HTML과 다른 스크립트 명령어가 섞여있다면 더 읽기 어려워진다.
  • JSP 2.0 은 더 단순한 표현 언어를 덕분에 스크립틀릿의 중요도를 낮추었다. JSP 에서 JSP 2.0 스타일로 쉽게 옮기기 위해서는 페이지에서 자바 코드를 사용하지 않는 것이 좋다.

자바 BluePrints의 엔터프라이즈 섹션에 있는 더 자세한 정보와 가이드라인을 참고하기 바란다.

자바빈즈 초기화 JavaBeans Initialization

JSP는 JavaBeanTM의 프로퍼티로 증명되는 모든 PropertyDescriptor를 초기화하기 위해 편리한 엘리먼트를 제공한다. 예를 들면:

    <jsp:setProperty name="bankClient" property="*"/>

그러나, 주의해서 사용해야 한다. 첫째로, 빈이 프로퍼티를 갖고 있다, 즉 amount 프로퍼티가 있다고 하고, 현재 ServletRequest 객체에 파라미터(amount)가 없거나 파라미터 값이 ""라고 한다면, 아무것도 하지 않는다: JSP는 빈의 특정 프로퍼티에 null를 할당하지도 않는다. bankClient 빈에 amount의 기존 값이 무엇이든지 간에 영향을 받지 않는다. 둘째로, PropertyEditors를 선언하지 않은 비-요소적인 프로퍼티는 ServletRequest 객체의 스트링 값에서 암묵적으로 초기화 되지 않기 때문에, 명시적인 변환이 필요하다. 세째로, 만일 어플리케이션이 주의 깊게 설계되지 않았다면, 악의를 가진 사용자는 추가적으로 요청 파라미터를 덧붙여서 빈의 사용하지 말아야할 프로퍼티 값을 설정할 수 있다.

깔끔한 코드를 위해서 jsp:setProperty 태그에 property="*"를 사용한다면, jsp:setProperty 태그 이전에 ServletRequest 객체를 통해서 받아와야 할, 빈을 초기화하기 위한 파라미터들에 대해 주석을 달기를 권한다. 다음 예제에서는 bankClient 빈을 초기화하기 위해서 firstNamelastName 파라미터가 필요하다는 것을 주석에서 읽을 수 있다:

<%--
  -  ServletRequest에서 firstName와 lastName를 요구
  --%>
<jsp:setProperty name="bankClient" property="*" />

JSP 내장 객체 JSP Implicit Objects

API 호출을 통해서 객체를 참조하기 보다는 JSP 내장 객체를 직접 사용하는 것이 좋다. 그래서 ServletContext 인스턴스에 의해 제공되는 초기 파라미터에 접근하기 위해 다음을 쓰는 대신에

    getServletConfig().getServletContext().getInitParameter("param")

기존 내장 객체를 사용하는 게 낫다:

    application.getInitParameter("param")

초기 파라미터 값이 출력이 되어야 하는 경우에는, JSTL로 접근해서 출력하는 것이 더 좋다:

    <c:out value="${initParam['param']}" />

인용부호 Quoting

일정한 인용부호의 사용을 채택한다. 인용부호는 작은따옴표 ' 대신 큰따옴표 " 를 사용한다.

불규칙한 인용부호 좋은 인용부호 사용
<%@ page import='javabeans.*'%>
<%@ page import="java.util.*" %>
<%@ page import="javabeans.*" %>
<%@ page import="java.util.*" %>

예외적인 경우는 작은따옴표가 필요할 때이다. 예를 들어서 스크립트 언어에서 큰따옴표를 사용하는 경우를 들 수 있다:

    <jsp:include page='<%= getFoodMenuBar("Monday") %>' />

커스텀 태그 사용하기 Using Custom Tags

만일 커스텀태그가 몸체가 없다면, 컨텐트는 (생략해서 "JSP" 기본값으로 하지 말고) empty라고 명확하게 선언되어야 한다. 태그 라이브러리 설명서에서 다음과 같이 정해준다:

<tag>
    <name>hello</name>
    <tag-class>com.mycorp.util.taglib.HelloTagSupport</tag-class>
    <body-content>empty</body-content>
    ...
</tag>

이렇게 하면 JSP 컨테이너는 태그 몸체가 무조건 비어야 되며 파싱할 어떤 JSP 문법도 포함하지 않아야 된다고 인식한다. 효과는 빈 몸체를 파싱하기 위해서 불필요하게 자원의 할당이 이뤄지는 것을 제거한다.

빈 태그는, 가독성향상을 위해 열고 닫는 XML 엘리먼트 쌍으로 표시하기보다는, 짧은 XML 엘리먼트로 표시한다. 그래서

    <myTag:hello />

라고 표기하는 것이 아래보다 낫다.

    <myTag:hello></myTag:hello>

TagExtraInfo와 TagLibraryValidator 사용 Use of TagExtraInfo and TagLibraryValidator

때때로, 태그 라이브러리를 사용하는데 TLD 하나로 유효성을 검증할 수 없는 경우가 있다. 그 때는 TLD에 등록된 TagExtraInfo 클래스나 TagLibraryValidator 클래스를 사용해서, 변환할 때 태그 라이브러리에 있는 에러를 잡아낼 수 있다.

자바스크립트 사용 Use of JavaScriptTM

스크립트가 제대로 돌아가기 위해서는 자바스크립트는 브라우저 타입의 특성과 관계없어야 된다.

동작을 한다면, JSP에서 자바스크립트 코드를 독립적인 파일로 분리하고, 다음과 같이 JSP에서 자바스크립트를 불러쓰는 방식은 좋은 생각이다:

<script language=javascript src="/js/main.js">

이렇게 하면 자바스크립트의 재사용성도 향상되고, 여러 JSP 사이에 일관된 습성의 자바스크립트를 유지할 수 있고, JSP페이지의 복잡성을 줄여준다.

캐스케이딩 스타일 시트 CSS Cascading Style Sheets

CSS를 사용해서 헤딩, 테이블 등의 공통적인 특성을 중앙에서 제어하도록 한다. 이 방법은 사용자들에게 프리젠테이션의 일관성을 향상시키고, 유지보수 노력과 JSP 페이지의 코드 사이즈를 줄여준다. 그래서, 다음과 같이 HTML 태그에서 스타일 정보를 끼어쓰지 말고:

<H1><FONT color="blue">Chapter 1</FONT></H1>
...
<H1><FONT color="blue">Chapter 2</FONT></H1>
...

하나의 스타일 시트 파일myJspStyle.css에 다음과 같은 스타일 정보를 정의한다:

H1 { color: blue }

그리고 JSP 페이지에 스타일 시트를 적용한다:

<link rel="stylesheet" href="css/myJspStyle.css" type="text/css">
...
<H1>Chapter 1</H1>
...
<H1>Chapter 2</H1>
...

컴포짓 뷰 패턴 사용 Use of Composite View Patterns

여러 JSP 페이지에서 반복되는 고정되고 복잡한 구조가 요구될 때, 이것을 다루는 방법으로 컴포짓 뷰 패턴(Composite View pattern;자바 Blueprints 의 패턴 섹션 참고)을 사용해서, 조각조각으로 나눠서 처리하는 법이 있다. 예를 들어, 프리젠테이션 구조에서 JSP 는 때때로 다음과 같은 로직 레이아웃을 갖고 있다:

header
menu bar main body
footnote
footer

이런 방식으로, 컴포짓 JSP 는 각각 분리된 JSP로 구현되는 다른 모듈로 나뉠 수 있다. 구성성분이 되는 JSP는 서블릿으로 변환할 때나 요청시에 include JSP 태그를 사용해서 컴포짓 JSP 의 적당한 위치에 놓이게 된다. 보편적으로, 독립적으로 요청되지 않는 페이지를 불러쓰는, 정적인 include 지시자를 사용할 때는 .jspf 확장자를 사용하고, 웹 어플리케이션 (war)에서 /WEB-INF/jspf/ 디렉토리에 놓아둘 것을 기억하기 바란다. 예를 들면 다음과 같다:

<%@ include file="/WEB-INF/jspf/header.jspf" %>
...
<%@ include file="/WEB-INF/jspf/menuBar.jspf" %>
...
<jsp:include page="<%= currentBody %>" />
...
<%@ include file="/WEB-INF/jspf/footnote.jspf" %>
...
<%@ include file="/WEB-INF/jspf/footer.jspf" %>
...

다른 추천사항 Other Recommendations

이 문서에서, JSP 코드와 웹 컴포넌트를 작성하는데 보다 유지보수하기 쉽고, 일관된 추천 코드 작성법 한 세트를 제시했다. 이 주제에 보다 더 관심있다면, 더 많은 최고의 작성법이 존재한다. 예를 들어, JSP 1.2 스펙에서는 다음을 추천한다:

  • 새로운 내장 객체 선언하기
  • 벤더 고유의 안내서 읽기
  • 커스텀 태그 라이브러리 사용하기

덧붙여서, 자바 BluePrints 는 더 큰 스케일에서 최고의 작성법을 제공한다. (패턴 섹션에서 보여지는) 모델-뷰-컨트롤러 패턴과 같은 것을 예로 들 수 있다.

우리는 이 문서에서 제시한 작성요령에 대한 여러분의 의견에 관심이 있습니다. JSP 코드 작성요령에 대해서 여러분의 다른 의견이 있다면 나누면 좋겠습니다. 피드백은 여기로 보내기 바랍니다. jsp-codeconv-comments@sun.com.

아래에, 위에서 설명한 코드 작성요령을 적용해 놓은 완전한 웹 어플리케이션의 소스를 소개한다. 이 어플리케이션의 WAR 파일을 여기 에서 다운로드 받을 수 있다.

코드 예제 Code Examples

여기에 있는 웹 어플리케이션 예제는 이 문서에 있는 내용이 어떻게 적용되는지 보여주기 위한 것이다. .war 파일에는 다음의 소스코드 파일과 디렉토리 구조로 되어 있다:

/index.jsp
/WEB-INF/classes/codeconv/GetResultsTag.class
/WEB-INF/jspf/footer.jspf
/WEB-INF/lib/jstl.jar
/WEB-INF/lib/standard.jar
/WEB-INF/tld/lotterylib.tld
/WEB-INF/web.xml

index.jsp 페이지에서는 오늘까지 포함된 이번 달의 모의 복권 추첨결과를 보여주는 커스텀 태그 라이브러리( lotterylib.tld )를 사용한다. 그리고, HTML 에 보여질 결과를 형식화하고, 반복하기 위해서 JSTL을 사용한다.

예제는 JSP 1.2 과 JSTL 1.0 을 사용한다.

/index.jsp 파일 소스

<%--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc.  All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Renders fake lottery results for the current month.
  --%>

<%@ taglib prefix="c"
    uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="fmt"
    uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="lottery"
    uri="http://codeconv/lotterylib" %>

<html>
    <head>
        <title>Fake Lottery Results for this Month
        </title>
    </head>
    <body>
        <jsp:useBean id="now" class="java.util.Date" />
        <h1>
            Fake Lottery Results for
            <fmt:formatDate value="${now}"
                pattern="MMMM yyyy" />
        </h1>
        <hr />
        <table border="1" cellpadding="5">
            <%-- Store current month and year --%>
            <c:set var="currentMonth">
                <fmt:formatDate value="${now}" pattern="M" />
            </c:set>
            <c:set var="currentYear">
                <fmt:formatDate value="${now}"
                    pattern="yyyy" />
            </c:set>

            <%-- Determine last day to report results for --%>
            <c:set var="endDay">
                <fmt:formatDate value="${now}" pattern="d" />
            </c:set>

            <%-- Display one row for each day --%>
            <c:forEach var="day" begin="1" end="${endDay}">
                <%-- Construct date --%>
                <c:set var="dateString">
                    <c:out value="${currentMonth}/${day}/${
                        currentYear}" />
                </c:set>

                <fmt:parseDate  var="date"
				    value="${dateString}"
                        pattern="M/d/yyyy" />
                <jsp:useBean id="date" class="java.util.Date"
                    />

                <tr>
                    <td>
                        <c:out value="${dateString}" />
                    </td>
                    <%-- Retrieve and display fake results
                            for this day --%>
                    <lottery:getResults var="numbers"
                        date="<%= date %>" />
                    <c:forEach var="number" items="${numbers}">
                        <td>
                            <c:out value="${number}" />
                        </td>
                    </c:forEach>
                </tr>
            </c:forEach>
        </table>
        <%@ include file="/WEB-INF/jspf/footer.jspf" %>
    </body>
</html>

/WEB-INF/classes/codeconv/GetResultsTag.java 소스

/*
 * codeconv.GetResultsTag
 *
 * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
 *
 * This software is the proprietary information of
 * Sun Microsystems, Inc.
 * Use is subject to license terms.
 *
 * Version: @(#)
 *
 * Date: January 13, 2003
 *
 */

package codeconv;

import java.util.Date;
import java.util.Random;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * Retrieves fake lottery results for the given date and
 * returns the result in the given attribute
 *
 * @version @(#)
 * @author Mark Roth
 */
public class GetResultsTag extends TagSupport {

    /** The maximum number that can be drawn */
    private static final int MAX_NUMBER = 58;

    /** The number of numbers that are drawn */
    private static final int NUMBER_COUNT = 6;

    /** The variable to store results to */
    private String var;

    /** The date on which the numbers were drawn */
    private Date date;

    /** The PageContext, used to return the result */
    private PageContext pageContext;

    /**
     * Remember the PageContext so it can be used later
     * to return the result.
     *
     * @param pageContext The page context of the calling page
     */
    public void setPageContext( PageContext pageContext ) {
        this.pageContext = pageContext;
    }

    /**
     * Returns fake lottery results for the given date.
     *
     * @return EVAL_PAGE so the rest of the page is evaluated.
     */
    public int doEndTag() throws JspException {
        // Generate the (fake) results.
        Random random = new Random( this.date.getTime() );
        int[] result = new int[NUMBER_COUNT];
        for( int i = 0; i < NUMBER_COUNT; i++ ) {
            result[i] = random.nextInt( MAX_NUMBER ) + 1;
        }

        // Place the result in the scoped attribute named by 'var'.
        pageContext.setAttribute( this.var, result );

        return EVAL_PAGE;
    }

    /**
     * Setter for date
     *
     * @param date The fake date on which the lottery numbers
     * were drawn
     */
    public void setDate( Date date ) {
        this.date = date;
    }

    /**
     * Getter for date
     *
     * @return The fake date on which the lottery numbers
     * were drawn
     */
    public Date getDate() {
        return this.date;
    }

    /**
     * Setter for var
     *
     * @param var The name of the variable to store the result in
     */
    public void setVar( String var ) {
        this.var = var;
    }

    /**
     * Getter for var
     *
     * @return The name of the variable to restore the result in
     */
    public String getVar() {
        return this.var;
    }
}

/WEB-INF/jspf/footer.jspf 소스

<%--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Sample Footer that can be included on pages.
  - Assumes JSTL fmt taglib is imported.
  --%>
<!-- common footer -->
<hr />
<jsp:useBean id="footerNow" class="java.util.Date" />
<i>
    Last Updated:
    <fmt:formatDate type="both" value="${footerNow}"
                    dateStyle="full" timeStyle="full" />
</i>

/WEB-INF/tld/lotterylib.tld 파일 소스

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
    PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
    "http://java.sun.com/j2ee/dtd/web-jsptaglibrary_1_2.dtd">

<!--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Tag Library for fake lottery results.
  -->

<taglib>
    <tlib-version>1.0</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>lottery</short-name>
    <uri>http://codeconv/lotterylib</uri>
    <display-name>FakeLotteryTaglib</display-name>
    <description>
        Tag Library for fake lottery results.
    </description>

    <tag>
        <name>getResults</name>
        <tag-class>codeconv.GetResultsTag</tag-class>
        <body-content>empty</body-content>
        <display-name>getResults</display-name>
        <description>
            Retrieve an array of fake lottery results for the given
            date and store them in the given scoped attribute.
        </description>
        <variable>
            <name-from-attribute>var
                </name-from-attribute>
            <declare>true</declare>
            <description>
                The fake lottery results for the given date.
            </description>
        </variable>
        <attribute>
            <name>var</name>
            <required>true</required>
            <description>
                The name of the variable to store the results in.
            </description>
        </attribute>
        <attribute>
            <name>date</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.util.Date</type>
            <description>
                The date on which the fake lottery numbers
                    were drawn.
            </description>
        </attribute>
        <example><![CDATA[
            <lottery:getResults var="numbers"
                date="${date}" />
        ]]></example>
    </tag>
</taglib>

/WEB-INF/web.xml 소스

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<!--
  - Author: Mark Roth
  - Date: January 17, 2003
  -
  - Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
  -
  - This software is the proprietary information of
  - Sun Microsystems, Inc.
  - Use is subject to license terms.
  -
  - @(#)
  - Description: Web Deployment Descriptor for JSP 1.2 fake
  - lottery example
  -->

<web-app>
    <display-name>FakeLotteryExample</display-name>
    <description>
        JSP 1.2 example application that illustrates correct JSP
        coding style.
    </description>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <taglib>
        <taglib-uri>http://codeconv/lotterylib</taglib-uri>
        <taglib-location>/WEB-INF/tld/lotterylib.tld
            </taglib-location>
    </taglib>
</web-app>

감사의 말 Acknowledgments

이 문서의 이전 드래프트에 소중한 조언을 제공해 주신 Gregory Murray (Java BluePrints Team), Damian Fauth (Sun Java Center), Kate Morris (Sun Java Center) 님들께 감사드립니다.

References

  1. Code Conventions for the Java Programming Language.
  2. JSP best practices.
  3. Hans's Top Ten JSP Tips.
  4. JavaServer Pages Specification version 1.2.
  5. Alur D., Crupi J., Malks D., Core J2EE Patterns: Best Practices and Design Strategies, Sun Microsystems Press, Prentice Hall Inc., 2001.
  6. Naming Conventions for Enterprise Applications.
  7. JavaServer Pages Standard Tag Library.
  8. Gamma E., Helm R., Johnson R., Vlissides J., Design Patterns: Elements of Reusable Software, Addison-Wesley, 1995.
  9. JavaServerTM Faces Technology.
  10. Java BluePrints.
  11. Designing Enterprise Applications with the J2EETM Platform, 2nd ed..

'Computer > Web' 카테고리의 다른 글

색상표  (0) 2007.04.26
JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12

댓글을 달아 주세요

  1. wonny 2008.10.01 20:34  Addr  Edit/Del  Reply

    좋은 정보 감사해요. ^^

posted by 희정냥★ 2007. 3. 12. 12:00

JSP 2.0: 뭐가 바뀌었나? - 4부

원문 : http://www.onjava.com/pub/a/onjava/2004/05/12/jsp2part4.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr)

2004/07/30

이번 "JSP 2.0: 뭐가 바뀌었나?" 시리즈의 마지막회에서는 커스텀 태그 라이브러리를 개발하기 쉽게 해주는 두가지 새로운 기법을 알아볼 것이다 : 태그 파일(tag files)과 새롭고 간결해진 태그 핸들러 JAVA API이다.

JSP 태그 파일로 커스텀 액션 개발하기

(주: "커스텀"은 "사용자 정의, 사용자가 따로 만든"이라는 정도의 의미이다. 이미 많은 책들이 커스텀 태그, 커스텀 액션이라는 말을 쓰고 있으므로 번역하지 않는다.)

JSP는 Java의 구루 경지에 오르지 않은 사람들이 동적인 컨텐트를 가진 웹 페이지를 만들 수 있도록 하려고 탄생한 것이다. 지금까지 동적이고 복잡한 컨텐트의 조각들을 여러 페이지간에 재사용하는 것이 약간 힘들었던게 사실이다. 만약 당신이 변수에 저장된 질문과 답변들을 가진 간단한 설문조사를 여러 페이지에 추가하고 싶다고 하자. JSP 2.0 이전에는 세가지 방식이 있었다. 설문조사가 필요한 모든 페이지에 설문조사 코드를 복사해서 붙여넣을 수 있다. 더 나은 방법으로 설문조사 폼을 생성하는 JSP를 따로 제작하고, 설문조사가 필요한 페이지에서 <jsp:include>나 <c:import> 액션으로 이 페이지를 불러들인다. 하지만 제약사항이 있는데, 예를들어 답변같은 것을 인자로 넘겨주기 위해 자바 빈이나 Map 등을 사용하지 못하고 오직 String만을 사용할 수 있다. 세번째 방식으로 Java 태그 핸들러 클래스로 커스텀 액션을 구현하는 것인데, 이것은 Java를 알아야만 한다.

JSP 2.0에는 네번째 방식이 있다: 다시 말해서 태그 파일로 커스텀 액션을 개발하는 것이다. 태그 파일은 정규 JSP페이지 처럼 동적인 부분에 JSP 요소들을 사용할 수 있는 텍스트 파일이다. 이것은 Java 태그 핸들러와 같은 목적으로 만들어진 것이다. 즉, 커스텀 액션을 위한 로직을 제공한다. 태그 파일과 JSP 페이지의 주된 차이점은 태그 파일은 파일 확장자가 .tag이고, 페이지 지시자 대신 태그 지시자를 사용하고 태그 파일에서만 유효한 새로운 몇몇 지시자를 이용해서 입력과 출력을 선언할 수 있다는 것이다.

자세히 한 번 살펴보자. 여기 간단한 설문조사 폼을 만드는 "poll.tag"라는 태그 파일이 있다.

<%@ tag body-content="empty" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
   type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Question: ${question}<br>
<form action="result.jsp" target="result">
   <input type="hidden" name="question" value="${question}">
   <input type="hidden" name="votesMapName" value="${votesMapName}">
   <input type="hidden" name="answersMapName" value="${answersMapName}">
   <c:forEach items="${answers}" var="a">
      <input type="radio" name="vote" value="${a.key}">${a.value}<br>
   </c:forEach>
   <input type="submit" value="Vote">
</form>

파일 맨 위 태그 지시자가 있다. 태그 지시자는 JSP 페이지에서 사용하는 페이지 지시자와 비슷하게 일반적인 파일의 성격을 규정한다. 여기서 나는 body-content 속성을 사용해서 JSP 페이지에서 이 태그 파일을 나타내는 액션 요소의 값이 비어 있어야 함을 선언했다. 예를 들면, 이 액션 요소는 바디를 가져서는 안된다. 비어있는 값 대신 스크립트가 아닌 값(바디는 스크립팅 요소를 제외하고 어떤 값이든 포함할 수 있다), 혹은 태그 의존값(컨테이너는 바디의 내용을 어떠한 변환도 없이 그대로 태그 핸들러에 넘겨준다) 등을 사용할 수 있다. 커스텀 액션을 자바 클래스로 개발해봤다면, body-content와 유효한 값들이 태그 라이브러리 기술자(Tag Library Descriptor; TLD)에서 왔음을 알 수 있다. 태그 지시자와 다른 특별한 태그 파일 지시자들은 TLD가 JSP 컨테이너에 제공하는 것과 동일한 정보를 제공하기 위해 사용된다.

이 예제에서 태그 지시자 다음에 나오는 attribute 지시자는 동명의 TLD 요소가 하는 것과 같은 역할을 한다. 이것은 유효한 커스텀 액션 요소의 속성을 선언한다. poll 태그 파일은 네가지 속성을 가진다 :

  • question : 설문조사 질문
  • answers : 숫자로 된 키값과 설문조사 답변을 가진 application 스코프의 Map 객체이다.
  • votesMapName : 숫자로된 키와 답변당 득표수를 가지고 있는 application 스코프 Map 객체의 이름.
  • answersMapName: 답변 Map(예를 들면 answers 속성의 값으로 넘겨 받은 Map)을 가지고 있을 어플리케이션 스코프 변수의 이름.

액션 요소 속성 하나당 name 속성으로 선언된 이름을 가진 한개의 attribute 지시자가 있다. 이 예제의 모든 액션 요소 속성은 각 attribute 지시자의 required 속성에 선언된 대로 필수적으로 요구된다. type 속성에 의해 선언된 대로, answers 속성의 값은 Map 객체이어야만 한다. 그외 다른 모든 속성은 기본 형인 String 형이어야한다. 그래서 나는 그러한 속성에는 type 속성을 명시하지 않았다.

이 태그 파일의 나머지는 일반적인 기존 JSP 이다. taglib 지시자가 JSTL core 라이브러리가 이파일에서 사용된다고 선언하고, 파일의 바디에서는 EL 표현식안에서 속성 값들(태그 파일에 페이지 스코프 변수로 생성된)을 사용해서 질문과 각 답변마다 라디오 버튼이 달린 폼을 생성한다. 폼에서 answers와 votes의 Map 변수 이름과 질문은 hidden으로 인코딩 되어 다음과 같은 형태로 사용될 투표 처리하는 페이지로 보내지게 된다 :

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
   <head>
      <title>Poll Results</title>
   </head>
   <body bgcolor="white">
      <c:set target="${applicationScope[param.votesMapName]}"
        property="${param.vote}"
        value="${applicationScope[param.votesMapName][param.vote] + 1}" />
   
      <p>
        Question: ${param.question}<br>
        <c:forEach items="${applicationScope[param.answersMapName]}"
          var="a">
          ${a.key}) ${a.value}:
          ${applicationScope[param.votesMapName][a.key]}<br>
        </c:forEach>
      </p>
   </body>
</html>

이것은 JSTL 액션을 사용한 평범한 JSP 페이지이다. voteMapName 파라미터에 의해 제공되는 이름으로 어플리케이션 스코프에 존재하는 Map 객체가 투표 결과를 가지고 있는데, 그 객체에 있는 설문조사답변과 키값이 일치하는 변수의 값을 증가시켜준다. 다음으로, 이것은 질문을 출력하고 "answerMapName" 파라미터에 의해 제공되는 어플리케이션 스코프의 설문조사 답변들의 맵 변수를 순회하여 각 답변을 현재 득표수와 함께 출력한다.

우리는 설문조사 투표 처리를 어떻게 하는가 보다는 설문조사 태그 파일을 통해 구현된 커스텀 액션을 어떻게 사용하는지에 더 관심이 있으므로, 여기 예제를 보여준다:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>

<html>
   <head>
      <title>My Page</title>
   </head>
   <body bgcolor="white">
      <jsp:useBean id="myAnswers" scope="application"
        class="java.util.TreeMap">
        <c:set target="${myAnswers}" property="1" value="Yes" />
        <c:set target="${myAnswers}" property="2" value="No" />
        <c:set target="${myAnswers}" property="3" value="Maybe" />
      </jsp:useBean>
      <jsp:useBean id="myVotes" scope="application"
        class="java.util.HashMap" />    
      ...
      <p>
        <my:poll question="Will you start using tag files?"
          answers="${myAnswers}"
          answersMapName="myAnswers" votesMapName="myVotes" />
      </p>
      ...
   </body>
</html>

주의해서 볼 첫번째 사항은 태그 파일을 가지고 있는 태그 라이브러리를 선언하는 taglib 지시자이다. TLD를 생성하지 않고 태그 파일을 사용하려면, WEB-INF/tags 디렉토리 아래의 어디엔가 태그 파일을 저장해야만 한다.

poll.tag 예제파일은 WEB-INF/tags/mytags 디렉토리에 저장되었고 이 디렉토리 이름을 taglib 지시자의 'tagdir ' 속성의 값으로 사용했다. 이렇게하여 컨테이너에게 이 디렉토리에 있는 모든 태그 파일이 한개의 동일한 태그 라이브러리에 속한다고 선언하고, 이 라이브러리의 액션을 위한 액션 요소들이 taglib 지시자의 prefix 속성에 지정된 값 - 이 예제에서는 "my" - 을 이용해 구분라고 알려준다. 다른 방법으로, 태그 파일을 TLD파일과 함께 .jar 로 묶을 수 있다. 그리고 태그 라이브러리를 일반적인 커스텀 태그 라이브러리와 마찬가지 방식의 taglib 지시자로 선언할 수 있다. 예를들어, tagdir 속성대신 uri 속성을 사용한다.

이 예제에서, 답변과 투표 결과를 위한 Map 객체는 <jsp:useBean> 액션에 의해 생성되고 JSTL의 <c:set> 액션에 의해 값이 증가된다. 하지만, 물론 다른 어떤 방식으로 객체를 생성해도 된다. (예: 아파치의 Struts 에서는 컨텍스트 리스너나 "plugin" 클래스에서). 객체들어 어떻게 생성되었든지 간에, 태그 파일은 일반적인 JSP 커스텀 액션 요소를 통해 수행된다. 나는 answers 속성의 값으로서 answers Map의 값을 계산하기 위해 EL 표현식을 사용했다. 태그 파일 속성은 EL 표현식을 기본적으로 받아들인다. 하지만 attribute 지시자의 rtexprvalue를 이용해 정적인 값만을 받아들이도록 선언할 수도 있다.

이 페이지를 요청하면, JSP 컨테이너는 다른 것들과 마찬가지로 그것을 처리한다. taglib 지시자와 요소의 선행자(prefix)의 도움을 받아 <my:poll> 커스텀 요소의 구현을 적재한다. 컨테이너는 태그 파일을 자기 나름의 방법으로 처리한다. Tomcat 5 컨테이너는 태그 파일을 Java 태그 핸들러 클래스로 바꾸고 컴파일한 뒤 그것을 실행한다.

커스텀 액션의 바디 처리하기

자바로 작성된 태그 핸들러 클래스와 마찬가지로, 태그 파일도 컨테이너에게 커스텀 액션 요소의 바디를 평가하고, 추가적으로 평가 결과를 더 처리하도록 할 수 있다.

액션 요소의 바디에 설문조사에 관한 짧은 설명을 추가할 수 있도록 만들어보자. 다음과 같다 :

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="my" tagdir="/WEB-INF/tags/mytags" %>
...
<html>
   ...
   <body bgcolor="white">
      ...
      <p>
        <my:poll question="Will you start using tag files?"
          answers="${myAnswers}"
          answersMapName="myAnswers" votesMapName="myVotes" >
          JSP 2.0 introduces a new way to develop custom action
          tag handlers, called <i>tag files</i>
        </my:poll>
      </p>
      ...
   </body>
</html>

이 예제에서의 바디는 오직 텍스트만을 가지고 있다. 하지만 액션 요소나 EL 표현식이 올 수도 있다. 바디를 평가하고 결과를 출력하기 위해, poll 태그 파일을 다음과 같이 수정할 필요가 있다:

<%@ tag body-content="scriptless" %>
<%@ attribute name="question" required="true" %>
<%@ attribute name="answers" required="true"
   type="java.lang.Object" %>
<%@ attribute name="votesMapName" required="true" %>
<%@ attribute name="answersMapName" required="true" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<p>
   <jsp:doBody/>
</p>
Question: ${question}<br>
<form action="result.jsp" target="result">
   <input type="hidden" name="question" value="${question}">
   <input type="hidden" name="votesMapName" value="${votesMapName}">
   <input type="hidden" name="answersMapName" value="${answersMapName}">
   <c:forEach items="${answers}" var="a">
      <input type="radio" name="vote" value="${a.key}">${a.value}<br>
   </c:forEach>
   <input type="submit" value="Vote">
</form>

첫째, 태그 지시자의 body-content 속성의 값을 "scriptless"로 변경한다. 이미 말했다시피, 이렇게 하면 바디는 스크립팅 요소를 제외하고는 어떠한 내용이라도 포함할 수 있게된다. 다음으로, <jsp:doBody>액션을 추가한다. 이를통해 컨테이너가 바디를 평가하고 결과를 출력하게 한다. 다른 방법으로, var 속성을 사용해서 평가 결과를 가져와 다른 처리를 할 수도 있다.

여기서 설명한 기능외에 추가적으로, 태그 파일은 자신을 호출한 파일에 변수를 통해 정보를 돌려줄 수도 있고, 선언되지 않은 속성을 처리하고 단편적인 속성을 가질 수 있다(예: 태그 파일이 액션 요소의 바디를 평가하는 것과 비슷한 방법으로 태그 파일에의해 평가되는 액션 요소와 EL 표현식을 갖고 있는 속성). 이에 대한 모든 사항을 나의 JSP 책 11장에서 볼 수 있다. 온라인에서 샘플로 볼 수 있다.

더 간편해진 Java 태그 핸들러 API

커스텀 액션 태그 핸들러를 태그 파일로 작성할 수 있게 된 것은 특히 많은 양의 HTML을 생성하는 커스텀 액션에서 매우 훌륭한 기능이다. 그러나 몇몇 기능은 단지 JSP 액션과 EL 표현식만으로만 작성하기는 어렵다. 그래서 Java 태그 핸들러 API가 여전히 필요하다. JSP 2.0 이전에는 Java로 태그 핸들러를 작성하는 것이 꽤 까다로왔다. 액션 요소의 바디를 처리하기 위해 컨테이너와 태그 핸들어사이의 복잡한 상호작용이 필요했기 때문이다.

액션 요소 바디에서 Java 스크립팅 요소를 지원하기 위해서 이렇게 복잡하게 되었다. 그러나, 바디가 오직 템플릿 텍스트와 EL 표현식, 액션 요소만 포함하게 된다면, 더욱 단순한 API 디자인이 가능해 진다. 바로 그것이 JSP 2.0에서 이뤄진 것이고, 단순한 태그 핸들러 API(simple tag handler API)라고 불리운다.

좀전에 태그 파일로 구현했던 설문조사 커스텀액션의 Java 태그 핸들러 :

package com.mycompany.mylib;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class PollTag extends SimpleTagSupport {
   private String question;
   private Map answers;
   private String votesMapName;
   private String answersMapName;

   public void setQuestion(String question) {
      this.question = question;
   }

   public void setAnswers(Map answers) {
      this.answers = answers;
   }

   public void setVotesMapName(String votesMapName) {
      this.votesMapName = votesMapName;
   }

   public void setAnswersMapName(String answersMapName) {
      this.answersMapName = answersMapName;
   }

   public void doTag() throws JspException, IOException {
      JspWriter out = getJspContext().getOut();
      JspFragment body = getJspBody();
      if (body != null) {
         out.println("<p>");
         body.invoke(null);
         out.println("</p>");
      }
      out.print("Question:");
      out.print(question);
      out.println("<br>");
      out.println("<form action=\"result.jsp\" target=\"result\">");
      out.print("<input type=\"hidden\" name=\"question\" value=\"");
      out.print(question);
      out.println("\">");
      out.print("<input type=\"hidden\" name=\"votesMapName\" value=\"");
      out.print(votesMapName);
      out.println("\">");
      out.print("<input type=\"hidden\" name=\"answersMapName\" value=\"");
      out.print(answersMapName);
      out.println("\">");
      Iterator i = answers.keySet().iterator();
      while (i.hasNext()) {
         String key = (String) i.next();
         String value = (String) answers.get(key);
         out.print("<input type=\"radio\" name=\"vote\" value=\"");
         out.print(key);
         out.print("\">");
         out.print(value);
         out.println("<br>");
      }
      out.println("<input type=\"submit\" value=\"Vote\">");
      out.println("</form>");
   }
}

단순한 태그는 새로운 javax.servlet.jsp.tagext.SimpleTag 인터페이스를 구현해야 한다. 예제의 태그 핸들러는 모든 메소드의 기본적인 구현을 제공해 주는 javax.servlet.jsp.tagext.SimpleTagSupport 클래스를 상속해서 작성했다. 기존의 태그 핸들러 클래스와 마찬가지로, 각각의 커스텀 액션 속성을 위해 셋터 메쏘드(setter methods)가 필요하다. 하지만 처리 메소드는 오직 doTag() 하나만 구현하면 된다.

예제 태그 핸들러에서는, doTag() 메쏘드가 SimpleTagSupport 클래스에서 상속받은 getJspBody() 메소드를 실행함으로써 액션 요소 바디의 실행 대행자(JspFragment의 인스턴스)를 얻는다. 만약 바디가 존재한다면, 태그 핸들러는 수행 결과를 출력에 추가하라는 의미로 null 값을 인자로주어 invoke() 메쏘드를 실행한다. <jsp:doBody> 액션과 마찬가지로, Writer의 인스턴스를 invoke() 메쏘드의 인자로 넘김으로써 결과를 잡아낼 수 있다. 그러면 doTag() 메쏘드는 태그 파일 구현에서 했던 것 처럼 모든 답변을 위한 라디오 단추를 가진 폼 HTML을 출력한다.

기존의 태그 핸들러가 바디를 처리하기위해 세 개의 메쏘드(doStartTag(), doAfterBody() 그리고 doEndTag(). 각 메소드는 컨테이너가 다음에 뭘 할지를 지정하는 값을 리턴한다)를 호출하는데 반해, 지금은 태그 핸들러를 작동시키기 위해 컨테이너가 호출하는 메소드가 오직 한 개이기 때문에, SimpleTag로 태그 핸들러를 구현하는것이 기존 태그 핸들러 API를 이용하는 것보다 훨씬 쉽다. 게다가 단순한 태그 핸들러의 인스턴스는 결코 재사용되지 않기 때문에, 상태를 재설정하는 것에 대해 걱정 꺼도 된다. 상태 재설정하기는 나의 이전 글, "JSP 1.2: Great News for the JSP Community, Part 2" 에서 설명한 대로 상당히 많은 문제를 야기시키는 것으로 알려졌다.

단순한 태그 핸들러의 TLD 선언은 기존 태그 핸들러와 완전히 동일한 방식으로 한다. 하지만 <body-content> TLD 요소는 JSP가 아닌 값을 가져야만 한다. 스크립팅 요소가 단순한 태그 핸들러로 구현된 커스텀 액션 요소의 바디에서 허락되지 않기 때문이다.

이 사항 이외에는 단순한 태그 핸들러로 구현한 커스텀 액션을 사용한는 것은 기존의 태그 핸들러를 사용하는 것과 전혀 다를 바 없다.

단순한 태그 핸들러와 기존 태그 핸들러 모두 javax.faces.jsp.tagext.DynamicAttributes라 고 불리는 새로운 인터페이스를 구현함으로써 선언되지 않은 속성을 지원할 수 있다. 두 형태 모두를 위한 속성은 다른 액션이나 EL 표현식을 포함하는 속성을 위한 JspFragment 형이 될 수 있고 태그 핸들러에 의해 몇번이라도 평가 될 수 있다. 이러한 기능에 대해 나의 책 JavaServer Pages 제3판에서 읽어 볼 수 있다.

마무리

이번 시리즈에서 나는 JSP 2.0에 추가된 모든 새로운 기능을 보여주었다 : Expression Language, 더 나은 오류 처리, 새로운 설정 옵션, 더 나아진 XML 페이지 형식 그리고 태그 핸들러를 개발하기위한 두가지 새로운 방법. 전부 해서, 이러한 개선 사항들은 JSP 페이지를 더욱 쉽게 이해하고 유지보수 할 수 있도록 해준다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 12:00

JSP 2.0: 뭐가 바뀌었나? - 3부

원문 : http://www.onjava.com/pub/a/onjava/2004/04/21/JSP2part3.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr

2004/04/21

더욱 유연해진 JSP 문서 포맷 규칙

JSP 스펙은 두 가지 형태의 JSP 페이지를 지원한다. 어떤 형태의 텍스트나 마크업이라도 포함하는 일반 JSP 페이지와 XHTML이나 JSP 엘리먼트와 같은 웰폼드(Well-formed) XML 인 JSP 문서(Document)이다. 웰폼드 XML 문서가되려면 JSP 지시자와 스크립트 요소들이 일반 JSP와는 다른 방식으로 기술되어야 한다.

일반 JSP 페이지 JSP 문서
<%@ page 속성목록 %> <jsp:directive.page 속성목록 />
<%@ include file="path"%> <jsp:directive.include file="path" />
<%! 선언 %> <jsp:declaration>선언 </jsp:declaration>
<%= 수식 %> <jsp:expression>수식</jsp>
<% 스크립틀릿 %> <jsp:scriptlet>스크립틀릿</jsp:scriplet>

태그 라이브러리는 JSP 문서에서 XML 네임스페이스로 선언된다. 예를들어 XHTML과 JSP 표준 액션 그리고 JSTL 코어 라이브러리를 사용하는 JSP 문서는 <html> 루트 엘리머튼에 다음과 같은 네임 스페이스 선언을 가져야 한다.

<html
    xmlns="http://www.w3c.org/1999/xhtml"
    xmlns:jsp="http://java.sun.com/JSP/Page"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xml:lang="en" lang="en">

xmlns 속성은 기본 네임스페이스를 XHTML의 네임스페이스로 설정한다. xmlns:jsp 속성은 JSP 표준 액션에 정의된 jsp 접두사에 관한 것이고, xmlns:c 속성은 JSTL Core 라이브러리에 의해 정의된 c 접두사에 관한 것이다.

JSP 문서는 처음부터 JSP 명세의 한 부분이었으나 초기에는 선택사항일 뿐이었고 나중에도 많은 제약을 갖고 있었다. JSP 2.0 은 대부분의 제약을 없애고, 매우 쉽게 XML과 JSP를 함께 사용할 수 있게 했다.

JSP 2.0 이전에는 JSP 문서는 <jsp:root>요소를 꼭 포함하여 JSP 컨테이너에게 이것이 JSP 페이지임을 알려주어야만 했다. JSP 2.0은 JSP 문서임을 알려주는 다른 방법을 정의하여 이 제한을 없앴다. 다음 조건들 중 한 가지만 만족하면 JSP 컨테이너는 파일을 JSP 문서로서 처리한다 :

  1. 요청된 경로가 web.xml 파일에서 JSP 속성 그룹의 선언에 <is-xml> 요소를 true로 하여 정의된 URL 패턴과 일치하면 된다. Part 2 에서 JSP 속성 그룹의 선언에 대해 더 자세한 사항을 볼 수 있다.
  2. 요청된 경로의 확장자가 .jspx이고, 이 확장자가 JSP 속성 그룹 선언에서 <is-xml> 요소를 false로 지정하지 않았다면 JSP 문서로 인식한다. 다시 말해 .jspx는 JSP 문서의 기본 확장자이다. 하지만 속성 그룹 선언에 의해 명시적으로 다른 용도로 사용할 수 있다.
  3. 요청된 경로의 확장자가 .jsp이거나 혹은 JSP 속성 그룹 선언의 URL 패턴에 일치하고 최상위 요소(root element)가 <jsp:root>이면 JSP 문서로 간주한다.

이 새로윤 규칙에 의해 JSP 문서를 <jsp:root> 요소가 필요 없는 일반 XHTML 파일처럼(물론 동적 컨텐트를 위해서 JSP 요소를 포함하면서) 작성할 수 있게 되었다. JSP 속성 그룹 선언을 다음과 같이 하면 확장자가 .html인 JSP 문서도 가능하다 :

...
<jsp-config>
  <jsp-property-group>
    <url-pattern>*.html</url-pattern>
    <is-xml>true</is-xml>
  </jsp-property-group>
</jsp-config>
...

XML 요소를 생성하는 새로운 방식

JSP 1.2 명세에 따라 JSP 문서를 작성해보았다면, 거의 대부분 XML 요소의 속성에 동적으로 값을 대입할때 문제가 있음을 발견했을 것이다. 예를 들어, XML 요소의 class 속성에 사용자의 스타일 설정을 가지고 있는 빈(bean) 프라퍼티 값을 대입한다고 하자. 당신은 아마 다음과 같은 시도를 먼저 해볼 것이다 :

<table class="<%= user.getTableClass() %>">

JSP 문서에서 이런 형태의 자바 수식이 JSP 액션 요소의 속성 값으로 사용될 수도 있으나, JSP는 템플릿 텍스트에서는 이러한 문법을 인정하지 않는다. 그러므로 여기서와 같은 방법은 작동하지 않는다.

JSP 액션 요소를 사용하여 속성값을 정하려는 시도 또한 작동하지 않는다:

<table class="<c:out value="${user.tableClass}"/>">

이것은 작동하지 않는다. 웰폼드 XML은 요소의 속성값으로 보다 작다 기호(<)를 포함할 수 없다.

JSP 1.2에서 웰폼드 XML을 준수하면서 동적으로 XML 요소의 속성값을 지정하는 방법은 매우 보기 안좋은 CDATA 섹션을 이용하는 것이다. 이것은 XML 요소의 처음과 끝을 마크업이 아닌 일반 텍스트(동적으로 생성된 값으로 둘러 쌓인)로 간주한다 :

<jsp:text><!CDATA[<table class="]]></jsp:text>
<c:out value="${user.tableClass}""/>
<jsp:text>[CDATA[">]]</jsp:text>

JSP 2.0은 매우 간단한 해결책을 제시해 준다. 템플릿 텍스트 중간에 EL 표현식을 사용하거나 요소를 생성하는 새로운 표준 액션을 사용하면 된다. EL 표현식으로 예제를 바꿔 쓰면 다음과 같다:

<table class="${user.tableClass}">

JSP 2.0 컨테이너는 액션의 속성은 물론 템플릿 텍스트 사이의 EL 표현식을 평가(계산)한다. 그러므로 거의 모든 경우에 이것이 가장 훌륭한 해결책이 된다.

EL 표현식으로 대입하고자 하는 값을 평가할 수 없다면, 그 대신에 3개의 새로운 표준 액션과 속성값을 나타낼 수 있는 아무 JSP 코드나 함께 이용하여 동적으로 XML 요소를 만들어낼 수 있다:

<jsp:element name="table">
  <jsp:attribute name="class">
    <c:out value="${user.tableClass}"/>
  </jsp:attribute>
  <jsp:body>
   ....
  </jsp:body>
</jsp:element>

<jsp:element> 액션은 XML 요소를 만들고 거기 포함된 <jsp:attribute> 요소는 요소의 속성을 만든다. 속성의 값은 <jsp:attribute>의 바디의 평가 결과로 설정된다. 그러므로 이 예에서 사용한 <c:out>을 쓴 것 처럼 요소 값을 생성하는 사용자 정의 액션을 사용하여도 된다. 유사하게 <jsp:body> 요소에 포함된 값을 평가하여 생성될 요소의 값으로 지정할 수 있다.

XML 선언을 위한 새로운 표준 액션

XML 문서는 문서의 맨 위에 XML 선언을 가질 수 있다. 일반적으로 그 뒤에 DOCTYPE 선언이 뒤따른다. JSP 2.0 에서는 <jsp:output> 표준 액션을 이용하여 이 두가지 선언의 생성을 조절할 수 있다.

JSP 문서가 최상위 요소로 <jsp:root> 요소를 가지고 있지 않은 이상(혹은 이 시리즈의 다음 기사에서 다룰 tag 파일을 나타내거나), JSP 컨테이너는 기본적으로 다음과 같은 XML 선언을 생성한다:

<? xml version="1.0" encoding="encodingValue" ?>

encoding 속성의 값은 JSP page 지시자의 contentType 속성에 의해 지정된 문자 인코딩이 되거나 명시적으로 지정하지 않았을 경우에는 UTF-8이 된다. XML 선언이 생성되는 것을 막고 싶을 때(아마도 JSP 문서가 다른 JSP 페이지에 포함될 경우에), JSP 문서에서 <jsp:output> 액션 요소를 사용해 JSP 컨테이너를 설득할 수 있다 :

<jsp:output omit-xml-declaration="true" />

선언 생성을 막기 위해 속성의 값을 'true'나 'yes'로 지정하고, 그렇지 않다면 'false'나 'no'를 사용한다.

DOCTYPE 선언은 XML 파서(브라우저에서 사용되는 것과 같은)에게 이 문서가 어떤 Document Type Declaration(DTD)를 따르는지를 알려준다. 파서는 이 정보를 이용해서 오직 DTD에 의해 선언된 XML 요소만을 포함하고 있는 문서인지를 검사한다. JSP 문서에 의해 생성될 문서에 대한 DOCTYPE 선언을 넣어서는 안된다. 그렇게 하면 JSP 문서 자신이 그 DTD에 따른다고 지정하는 것이 되어버린다. 대신 <jsp:output> 액션을 사용하여 JSP 문서에 의해 생성될 결과 문서의 DTD 선언을 추가할 수 있다 :

<jsp:output doctype-root-element="html"
  doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
  doctype-system="http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>

<jsp:directive.page contentType="text/html" />

이 예에서와 같이 사용하면 <jsp:output> 액션은 결과로 XHTML을 위한 DOCTYPE 선언을 추가한다 :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"   "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

나는 또한 이 예제에서 브라우저가 결과 컨텐트를 어떻게 다뤄야 할지를 판단하게 하기 위해, <jsp:directive.page> 선언에 contentType 속성을 text/html MIME 타임으로 지정하여 포함시켰다. 참고로 XHTML에 맞는 정확한 MIME 타입은 application/xhtml+xml인데, 몇몇 최신 브라우저(특히 Internet Explorer 6)은 그것을 인식하지 못한다. text/html은 대부분의 브라우저들이 어떻게 다뤄야 할지를 아는 XHTML을 위한 MIME 타입으로 통용된다.

마무리

지금까지 보았듯이 JSP 2.0은 매우 쉽게 JSP 페이지를 XML 문서로 작성할 수 있도록 해준다. 이 시리즈의 마지막 편은 커스텀 태그 라이브러리에 관한 새로운 특징들을 알아볼 것이다 : 새로운 태그 파일 형식과 간단한 태그 API.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 11:59

JSP 2.0: 뭐가 바뀌었나? - 2부

원문 : http://www.onjava.com/pub/a/onjava/2003/12/03/JSP2part2.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr

2004/07/29

이것은 JavaServer Pages(JSP) 2.0 명세에 추가된 사항들을 설명하는 시리즈의 두번째 글이다. 1부에서는 새로운 표현식(Expression Language)에 대해서 설명했으나, 알아둘게 더 많이 있다. 이번 회에서는 오류 처리 부문에서의 발전된 모습과 새로운 배치 기술자(deployment descriptor) 기능에 대해 알아볼 것이다. 나는 당신이 JSP 1.2에 익숙하고 JSP Standard Tag Library(JSTL)에 대해 들어보기는 했다고 가정하고 글을 썼다.

JSP Error Pages

JSP나 서블릿에서 JSP 오류 페이지를 사용해 보았다면, 이 페이지를 불러들인 예외에 관해 출력하거나 로그 정보를 보여주기를 바랬을 것이다. 하지만 JSP 1.2에서는 그게 그리 쉬운일이 아니다. 그 이유는 errorPage 선언을 가진 서블릿과 JSP가 예외를 request 속성(attribute으로 전달하고, 서로 다른 속성 이름을 사용하기 때문이다. 오직 JSP 속성 이름으로 전달된 예외만이 자동으로 JSP 오류 페이지에 나타날 뿐이다(exception 스크립트 변수나 ${pageContext.exception} EL을 이용해서).

JSP 2.0에서는 서블릿 명세와 같은 속성이름 - javax.servlet.error.exception으로 변경함으로써 이 문제를 해결했다. 또한, 내장 EL pageContext 변수에 errerData라는 새로운 프라퍼티가 있어, 발생한 문제에 대한 다른 정보들도 제공해 준다. errerData 속성은 javax.servlet.jsp.ErrorData 클래스의 인스턴스이며 다음과 같은 프라퍼티로 빈(Bean)으로써 사용할 수 있다.

프라퍼티 자바 형 설명
requestURI String 요청이 실패한 URI.
servletName String 실패한 JSP나 서블릿의 이름.
statusCode int 실패 상태 코드.
throwable Throwable 오류 페이지를 불러들인 예외.

저 프라퍼티들을 사용하는 JSP 오류 페이지의 예제가 있다 :

<%@ page isErrorPage="true" contentType="text/html" %>
<%@ taglib prefix="log" uri="http://jakarta.apache.org/taglibs/log-1.0" %>

Sorry, but things didn't work out as planned. I've logged as much as
I know about the problem, so rest assured that my master will look
into what's wrong as soon as he's sober.

<jsp:useBean id="now" class="java.util.Date" />
<log:fatal>
  -----
  ${now}
  Request that failed: ${pageContext.errorData.requestURI}
  Status code: ${pageContext.errorData.statusCode}
  Exception: ${pageContext.errorData.throwable}
  -----
</log:fatal>

이 페이지에서 사용자들을 다소 안심시켜주는 메시지와 아파치 자카르타 Taglib 프로젝트의 Log 태그 라이브러리를 사용해서 상세한 로그를 보여준다.

특정 파일이 서블릿과 JSP 페이지의 오류 페이지임을 선언하기 위해, web.xml 파일에서 <error-page> 요소를 사용할 수도 있다.

...
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/error.jsp</location>
  </error-page>
  <error-page>
    <exception-code>500</exception-code>
    <location>/error.jsp</location>
  </error-page>
...

특정 JSP 페이지에 대해서 다른 오류 페이지를 보여주고자 한다면, 페이지 지시자의 errorPage 속성을 이용해서 web.xml의 선언을 오버라이드 할 수 있다.

<%@ page errorPage="/other_error.jsp" contentType="text/html" %>

JSP 문법 오류 보고

JSP 1.2와 2.0간의 작지만 중요한 차이점은 JSP 2.0이 JSP 컨테이너가 jsp:id 기능을 지원하도록 한다는 점이다. 이것은 1.2에서는 단지 "권장사항"일 뿐이었다. JSP 개발자들에게 이것이 무엇을 의미하는가? 바로 JSTL이나 커스텀 태그 라이브러리의 문법 오류 내용이 더욱 쓸만해진다는 것이다.

어떻게 작동하냐구? 컨테이너가 JSP 페이지를 실행 가능한 형태(서블릿 클래스)로 변환할 때, 페이지 내에 선언된 모든 태그 라이브러리를 살펴본다. 한 개 혹은 여러개의 태그 라이브러리 선언이 태그 라이브러리 유효성 검사기(TLV; Tag Library Validator)를 가지고 있다면, 컨테이너가 페이지를 받아들이기 전에 TLV가 페이지의 유효성을 검사할 기회를 주게 된다.

이것은 TLV가 페이지를 분석할 때 XML 뷰(View)를 제공 한다. XML 뷰는, 이름에서 보듯이, 모든 정규 JSP 요소와 템플릿 텍스트(HTML 같은..)를 웰 폼드(Well-Formed) XML 문서로 변환한 것이다.

XML 뷰는 TLV가 모든 커스텀 액션이 올바르게 사용되었는지를 확신하도록 파싱 하는 것을 쉽게 만들어 준다.(예를 들어, 엘리먼트들이 올바르게 중첩되었는가, 함께 나와서는 안되는 속성들이 동일한 액션 요소에 같이 사용되지는 않았는가?)

여기 jsp:id가 온 곳이 있다. 컨테이너는 페이지의 각 커스텀 액션 요소에 ID를 부여하고 ID와 요소의 위치(파일, 줄 번호, 행 번호)간의 맵을 유지한다. 컨테이너는 jsp:id 속성을 ID를 값으로 하여 XML 뷰의 모든 커스텀 액션 요소에 추가한다. TLV가 오류를 발견하면, 오류 메시지에 잘못된 액션 요소의 jsp:id 속성 값을 추가하여 컨테이너에 넘겨주게 된다. 컨테이너는 매핑 정보를 이용해서 잘못된 커스텀 액션 요소의 위치 정보를 사용자에게 보여주는 에러 메시지에 추가한다. 이로 인해 문제점을 찾고 수정하기가 쉬워진다.

모든 JSTL 라이브러리는 TLV를 갖고 있다. 나는 당신이 작성할 커스텀 라이브러리에 TLV를 만들고, 당신이 사용할 서드 파티 라이브러리 개발자들에게도 그렇게 하도록 주장할것을 강력히 권한다.

당신이 XML 뷰와 TLV를 잘 모르겠다면, 내가 2001년에 JSP 1.2에 대해 쓴 글에 간단한 설명을 해 뒀으니 보기 바란다.(JSP 1.2: Great News for the JSP Community).

JSP 배치 기술자(deployment descriptor) 새소식

JSP 2.0 은 이전 JSP 명세에서 그랬던 것 처럼 서블릿 명세에 의해 정의된 배치 기술자(web.xml)파일 형식을 사용한다.

어쨌든, JSP 2.0에는 두가지 중요한 변화가 있다: web.xml의 규칙이 XML 스키마(Schema)로 정의되었고, 대부분의 JSP 관련 설정 아이템들이 새로운 XML 요소로 이동해서 JSP 명세의 제어 하에 놓이게 되었다(서블릿과 JSP 명세간의 결합도(coupling)를 최소화 하기 위해서).

XML 스키마는 XML 문서의 문법 규칙을 설명하는 XML 언어이다(예. 요소가 어떻게 중첩되는가, 요소가 어떤 값을 가질 수 있는가, 값이 중복 될 수 있는가, 그리고 그 외 여러가지). 이건 매우 복잡한 명세이지만 운좋게도, 당신이 web.xml을 작성하기 위해 그 XML 스키마의 문법 규칙을 이해해야 할 필요는 없다. 왜냐하면 서블릿과 JSP 명세는 이해하기 쉬운 도표를 제공하기 때문이다(나의 JavaServer Pages, 제 3판 책은 읽기 쉬운 문법 도표를 포함하고 있다). 그래도 XML 스키마를 공부하고 싶다면 W3C 웹 사이트를 참조하라.

규칙을 예전의 DTD 대신 XML 스키마를 이용해서 선언하는 것의 장점은 XML 스키마는 더욱 세부적이라 web.xml 파일을 파싱할 때 더 많은 오류를 찾을 수 있고, 덕분에 컨테이너들 간의 더 나은 이식성을 가져온다는 것이다.

내 생각에 당신이 더욱 기뻐할 다른 장점으로는 XML 스키마가 web.xml의 최상위 요소들이 어떤 순서로 배열되도 상관없게 만들어 준다는 것이다. 이전 버전의 서블릿과 JSP 명세에서는 예를 들어 <error-page> 요소가 <welcome-file-list> 요소보다 먼저 오기라도 하면 오류를 발생시켰지만, 새로운 버전에서는 그런것도 아무 상관 없다. 그렇더라도 최상위 요소 안에 오는 요소들의 순서는 여전히 엄격한 순서에 따라야만 한다. 어쨌든 당신은 최상위 요소들을 마음대로 할 수 있는 자유를 가졌다.

<servlet> 요소 안에 중첩된 <jsp-file> 요소를 제외하고 모든 JSP 관련 요소들은 <jsp-config>라는 최상위 요소 아래에 함께 묶이게 되었다. <jsp-config>안에 중첩해서 <taglib>요소도 JSP 1.2에서와 같은 문법과 의미로 사용할 수 있다. 하지만 사실 JSP 1.2 이후의 컨테이너에서는 <taglib>가 불필요하다. 컨테이너가 배치된 JAR파일로 부터 자동으로 태그 라이브러리 정의를 뽑아내기 때문이다.

새로운 <jsp-property-group> 하위요소(subelement)는 훨씬 더 관심있게 볼만하다. 이 요소는 특정한 URL패턴에 부합하는 JSP 페이지의 집합에 특정한 설정을 적용할 수 있게 한다. 예를 들어보면:

...
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <scripting-invalid>true</scripting-invalid>
    </jsp-property-group>
  </jsp-config>
...

<url-pattern> 요소는 설정을 적용할 JSP 페이지의 집합을 구분한다.다른 중첩된 요소들은 설정 옵션을 정의한다. 이 예제에서는, <scripting-invalid> 요소가 모든 JSP 페이지에서 JSP 스크립팅 요소(Java 코드 같은)를 사용할 수 없게 만든다.

대체로(all in all), 다음과 같은 설정 요소들을 <jsp-property-group> 요소 안에 중첩해서 <scripting-invalid> 요소와 같은 방식으로 사용할 수 있다:

요소 설명
<el-ignored> true이면, URL 패턴이 일치하는 JSP 페이지 내의 EL 표현식을 EL 표현식이 아니라 일반적인 텍스트로써 다루게 된다. 이것은 JSP 1.2에서 EL 표현식처럼 보이는 텍스트를 JSP 2.0 으로 천천히 마이그레이션 하는데 유용하게 사용될 수 있다. 'elIgnored' 페이지 지시자 속성을 이용해서 JSP 2.0으로 변환한 페이지들에서 선택적으로 EL을 사용하게 만들 수도 있다.
<scripting-invalid> true이면, URL 패턴이 일치하는 JSP 페이지에서 스크립팅 요소를 사용하면 번역시(translation-time) 오류를 발생시킨다.
<page-encoding> URL 패턴이 일치하는 모든 JSP 페이지에 대해 지정된 페이지 문자 인코딩을 사용한다. 모든 JSP 페이지에 인코딩을 지정하는 대신 사용할 수 있고, JSP 페이지에 몇몇 특수한 파일 인코딩(예를들면 EBCDIC)을 지정할 수 있는 유일한 방법이다.
<include-coda> URL 패턴이 일치하는 모든 JSP 페이지의 끝에 자동으로 포함될 파일의 컨텍스트에 상대적인 경로를 지정한다. 한개의 <jsp-property-group> 요소 안에서 여러개의 요소를 사용할 수도 있고, 여러개의 <jsp-property-group> 요소에서 사용할 수도 있다.
<include-prelude> URL 패턴이 일치하는 모든 JSP 페이지의 시작 부분에 자동으로 포함될 파일의 컨텍스트에 상대적인 경로를 지정한다. 한개의 <jsp-property-group> 요소 안에서 여러개의 요소를 사용할 수도 있고, 여러개의 <jsp-property-group> 요소에서 사용할 수도 있다.
<is-xml> true이면, URL 패턴이 일치하는 모든 JSP 페이지가 JSP XML 문법을 사용한다고 지정하는 것이다(이것이 JSP 문서이다).

마무리

이번 회에서는 JSP 2.0 오류 처리방식의 개선점과 새로운 배치 기술자의 기능들을 설명했다. 이 시리즈의 다음번 글에서는 JSP 2.0이 XML 컨텐트를 위해 JSP를 사용하는 것이 어떻게 쉬워졌는지와 커스텀 태그 라이브러리에 관련된 새로운 기능들을 알아볼 것이다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요

posted by 희정냥★ 2007. 3. 12. 11:58

JSP 2.0: 뭐가 바뀌었나? - 1부

원문 : http://www.onjava.com/pub/a/onjava/2003/11/05/jsp.html

by Hans Bergsten, JavaServer Pages, 3판의 저자

번역 손권남(kwon37xi_aT_yahoo dOt co DoT kr)

2004/07/06

기다림이 거의 끝나간다(번역시점에서는 이미 끝났다). 최신 JavaServer Pages(JSP)스펙인 JSP 2.0이 다른 J2EE 1.4스펙과 함께 발표될 때가 가까워왔다. 소수점 앞부분의 버전 번호가 바뀐것으로 보아 JSP를 사용하는 많은 방식들이 바뀌었음을 알 수 있다. 더이상 JSP페이지에 JAVA 코드는 필요없다. 새로운 표현식(EL:Expression Language)과 JSP Standard Tag Library(JSTL)덕분이다. 또한 커스텀 액션을 개발하는 새로운 방식덕분에 코드 재사용이 훨씬 쉬워졌다. 보다 명확하게 말해, JSP 2.0은 다음과 같은 이점들을 가지고 있다.

  • JSTL 1.0 스펙에서 소개되었던 EL(Expression Language)이 JSP 스펙에 포함되었다. EL을 이제는 템플릿 텍스트(HTML 등)에서 뿐만 아니라 모든 표준/사용자 정의 컴포넌트에서 사용할 수 있다.
  • EL이 JSP 1.1이 이용하는 함수 호출 메카니즘까지 확장되었고, 일반적으로 사용되는 함수 모음을 미리 준비해 놓았다.
  • 서블릿 스펙에 정의된 오류 처리 메카니즘으로 정돈된 새로운 변수들을 통해, JSP 오류 페이지가 이제는 오류에 대한 더 많은 정보에 접근할 수 있게 되었다.
  • JSP컨테이너가 JSP문법 오류를 보고하는 방법에관한 요구사항이 까다로와져서 오류를 찾기가 더 쉬워졌다.
  • JSP 2.0과 Servlet 2.4를 포함한 모든 J2EE 1.4스펙은 배포 기술자 규칙(the deployment descriptor rules)의 선언을 XML스키마를 사용해서 한다. 이 방식의 한가지 장점은 이제 web.xml의 선언을 아무 순서로나 배치해도 된다는 것이다. JSP 2.0은 또한 배포기술자에 많은 새로운 설정 옵션들을 추가하여 각 페이지마다 설정하는 대신 전체적으로 설정하는 것을 가능케하였다.
  • JSP 페이지를 XML 문서화하는 것이 더 쉬워졌다. 새로운 유연한 규칙들과 표준 액션 엘리먼트들 덕분이다.
  • 커스텀 태그 라이브러리를 tag 파일(JSP 요소를 가진 텍스트 파일)의 묶음으로 만들수 있게 되었다. 그리고 Java 클래스로 구현된 태그 핸들러는 새롭고 단순화된 태그 핸들러 API를 사용할 수 있게 되었다. 동시에, 동적 속성 목록이나 실행 가능한 프래그먼트 속성(executable fragment attributes)와 같은 많은 새로운 특징들이 추가되었다.

이 기사는 JSP 2.0 의 새로운 기능을 설명하는 기사 시리즈의 첫번째 이다. 이번 장에서는 EL과 관련된 사항만 볼 것이며, 다른 사항들은 다음 회에 보기로 한다. 나는 당신이 JSP 1.2에 익숙하고 JSP Standard Tag Library(JSTL)에 대해 들어보기는 했다고 가정하고 글을 썼다.

당신은 또한 나의 JavaServer Pages 책 3판에 관심이 있을 지도 모른다. 이 책은 이제 설명할 모든 것을 더 자세히 설명하고, 당신이 JSP와 JSTL을 모를 수도 있다고 생각하고 쓴 것이다. 이 책은 2003년 12월에 출간될 예정이다. 하지만 Amazon.com 등의 서점에서 미리 주문할 수도 있다.

Expression Language (EL)

당신이 JSTL을 사용해봤다면, 이미 JSP Expression Lnaguage를 잘 알고 있을 것이다. EL은 JSTL 1.0 스펙에서 소개된 것으로 JAVA코드를 대신해 실행시간에 액션(태그) 엘리먼트의 속성에 값을 지정하는 역할을 한다. JSTL의 EL은 매우 빨리 인기를 끌었다. 하지만 문제가 하나 있는데 JSTL EL은 오직 JSTL 액션에서만 작동했고, 커스텀 액션은 표준이 아닌 API를 사용해서 EL을 수행하도록 특별히 작성되어야만 EL을 사용할 수 있었다.

JSP 2.0을 시작하며, JSP 컨테이너 자신이 EL 표현식을 해석할 수 있게 되었고, 표준과 커스텀 액션 그리고, 템플릿 텍스트(HTML같은)와 같이 JAVA 코드를 사용해야 했던 모든 곳에서 EL을 사용할 수 있게 되었다.

구체적인 예제를 보기전에, EL이 뭔지 더 자세히 살펴보자. EL은 JavaScript에서 조금 확장하고 XPath(XML 문서의 정보에 접근하기 위해 사용되는 언어)에서 힌트를 얻어 만들어진 언어이다. 그러나 EL은 값이 없는 변수(null)에 대해 좀더 관대하고, 데이타형 변환을 좀더 자동적으로 해준다. 이러한 특징들은 파라미터들을 폼에서 얻어오는 웹 어플리케이션에 중요하다. 파라미터들이 몇몇 요청에서는 존재하고 어떤 경우에는 값이 없을 수 있으며, 브라우저가 파라미터값을 항상 문자열(text)로 보내는데 반해, 웹 어플리케이션에서는 숫자나 불린(true/false)로 사용해야 할 경우도 생긴다. EL이 설계된 방식에 따르면, 값이 없을 경우(null)나, 형 변환 같은 것에 전혀 신경쓸 필요가 없다.

EL 표현식은 변수와 연산자를 포함한다. JSP 스코프(page, request, session, application)에 저장된 어떤 빈이라도 EL 변수로서 사용될 수 있다. 게다가 EL은 다음과 같은 내장 변수들도 지원한다:

변수 이름 설명
pageScope 모든 page 스코프 변수에 대한 컬렉션(java.util.Map).
requestScope 모든 request 스코프 변수에 대한 컬렉션(java.util.Map).
sessionScope 모든 session 스코프 변수에 대한 컬렉션( java.util.Map).
applicationScope 모든 application 스코프 변수에 대한 컬렉션(java.util.Map)
param 모든 request 파라미터 값들을 한개의 문자열로 가진 컬렉션(java.util.Map).
paramValues 모든 request 파라미터의 값들을 파라미터당 문자열 배열로 가진 컬렉션(java.util.Map).
header 모든 헤더의 값들을 헤더당 하나의 문자열로 가진 컬렉션(java.util.Map).
headerValues 모든 헤더의 값들을 헤더당 문자열 배열로 가진 컬렉션(java.util.Map).
cookie 모든 쿠키의 값들을 쿠키당 한개의 javax.servlet.http.Cookie의 값으로 가진 컬렉션(java.util.Map).
initParam 모든 어플리케이션의 초기화 파라미터를 파라미터당 한개의 문자열로 가진 컬렉션(java.util.Map).
pageContext javax.servlet.jsp.PageContext 클래스로서, 다양한 request 데이타에 대한 액세스를 가능케 한다.

연산자들은 변수들로 뭘 할 것인지를 지정하는 것이다. EL에서 사용할 수 있는 연산자들은 프로그래밍을 해봤다면 많이 눈에 익을 것이다. 왜냐면, 거의 모든 언어에서 지원되는 연산자들과 같기 때문이다.

연산자 설명
. 빈의 프라퍼티나 Map의 엔트리 접근
[] 배열이나 리스트 엘리먼트 접근
() 부가적인 표현식을 연산 순서를 바꿔서 연산하게 할 때. 3 * (1+2)
? : 조건 테스트 - 조건 ? true일때리턴값 : false일때리턴값
+ 더하기
- 빼기 혹은 음수
* 곱하기
/ 혹은 div 나누기
% 혹은 mod 나머지
== 혹은 eq 같다
!= 혹은 ne 다르다
< 혹은 lt 보다 작다
> 혹은 gt 보다 크다
<= 혹은 le 작거나 같다
>= 혹은 ge 크거나 같다
&& 혹은 and 논리 AND
|| ('|'가 연속으로 두개) 혹은 or 논리 OR
! 혹은 not 단항 not (true를 false로 false를 true로)
empty 빈 변수 값(null, 빈 문자열, 빈 배열, 엔트리가 없는 맵이나 컬렉션)인가 테스트
func(args) 함수 호출. func는 함수 이름이고 args는 없거나, 한개 혹은 쉼표(,)로 분리된 여러개의 함수 인자이다

EL 표현식은 숫자, 문자열(홑따옴표 혹은 쌍 따옴표와 함께), 불린 값과 null같은 리터럴(상수 값)들도 포함할 수 있다.

EL 표현식이 템플릿 문자열(HTML등)이 오는 곧에도 올 수 있기 때문에, JSP 컨테이너에게 그것이 EL표현식이라고 알려줘야만 한다. 구획문자(delimiter)를 이용해서 하면 된다. EL은 항상 ${ 구획문자로 시작해서 }로 끝난다. 여기 5를 amount라는 변수에 더하는 EL 표현식이 있다.

${amount + 5}

빈 프라퍼티에 5를 더하고자한다면, 프라퍼티 접근 연산자를 사용하면 된다:

${order.amount + 5}

프라퍼티 접근 연산자(.)은 EL에게 빈이나 컬렉션(여기서는 order, 빈이나 java.util.Map 일 수 있다)에서 그 다음에 오는 이름과 같은 프라퍼티(여기서는 amount)를 찾게한다.

대신, 배열 접근 연산자를 사용해도 된다.

${order['amount'] + 5}

[] 안의 값은 프라퍼티의 이름을 나타내는 문자열(이 예제에서 쓰인대로)이거나 아니면 프라퍼티 이름을 값으로 가진 변수 (혹은 다른 EL 표현식)이면 된다.

EL은 동적으로 값을 받도록(dynamic value 혹은 request-time attribute) 지정된 표준(JSTL)이나 커스텀 JSP 액션의 속성에 값을 지정할 때도 사용할 수 있다 :

<c:out value="${order.amount + 5}"/>

JSP 2.0 이전에는 속성에 동적으로 값을 주기 위해 JAVA 표현식을 써야만 했다. 이로인해 우리는 지난 몇년간 수많은 문법 오류에 시달려야만 했다.

마침내 EL 표현식이 페이지 내에서 템플릿 텍스트와 직접적으로 함께 쓰일 수 있게 되었다. 이것은 HTML 엘리먼트와 속성을 동적으로 지정해야 할 때 매우 편리하다.

<input name="firstName" value="${customer.firstName}">

JSP 1.2 에서는, 같은 작업을 하기 위해 JSTL의 <c:out> 액션을 사용해야만 했다. 이것은 서로 다른 형의 두 엘리먼트를 섞어써서 이해하기 매우 어렵다 :

<input name="firstName"
    value="<c:out value="${customer.firstName}"/>" >

새로운 JSTL 1.1 태그 라이브러리 지정자

JSTL 1.1은 JSTL을 JSP 2.0에 통합하기 위한 마이너 스펙 릴리즈이다. 눈에 띄는 변화는 JSTL 1.0의 두개로 분리되있던 라이브러리(한가지는 EL를 사용하고 한가지는 JAVA 표현식을 사용하는)가 EL과 JAVA 표현식 모두를 사용할 수 있는 한가지 라이브러리로 통합된 것이다.

JSTL 1.1의 라이브러리들은 다음과 같은 지정자를 사용해야 한다. 1.0과 다르니 주의해야 한다.

Library URI Prefix
Core http://java.sun.com/jsp/jstl/core c
XML processing http://java.sun.com/jsp/jstl/xml x
I18N formatting http://java.sun.com/jsp/jstl/fmt fmt
Database access http://java.sun.com/jsp/jstl/sql sql
Functions http://java.sun.com/jsp/jstl/functions fn

JSTL 1.0을 사용했었다면, 모든 라이브러리의 URI의 중간에 '/jsp' 패스가 들어간 것을 제외하고, 기존의 라이브러리 지정자와 동일함을 알 수 있다. 또한, JSTL 1.1이 EL Function 이라는 새로운 라이브러리를 포함하고 있음도 볼 수 있다. 이것을 짧게 살펴볼 것이다.

새로운 EL 연산자

JSP 페이지에서 매우 자주 필요한 기능 중의 하나는 어떤 조건이 true 일 때 템플릿 텍스트를 포함시키는 기능이다. JSP 1.2와 JSTL 1.1을 이용하면, 이것을 <c:if> 블록을 이용해서 할 수 있다. 하지만, 그건 무척 복잡한 해결책이다. JSP 2.0은 EL에 새로운 조건 연산자를 추가하여 더욱 고상하게 이런 문제를 처리할 수 있다.

조건 연사자는 많은 프로그래밍 언어에 존재하므로(예를 들어 JAVA, C, JavaScript 등). 이미 본적이 있을 것이다. 이 연산자는 불린 조건과 조건이 참일때 사용할 값과 조건이 거짓일 때 사용할 또 다른 값을 취한다. 예제를 보면 어떻게 돌아가는지 확실히 알 수 있을 것이다:

<select name="artist">
 <option value="1" ${param.artist == 1 ? 'selected' : ''}>
 Vesica Pisces
 <option value="2" ${param.artist == 2 ? 'selected' : ''}>
 Cortical Control
 <option value="3" ${param.artist == 3 ? 'selected' : ''}>
 Vida Vierra
</select>

여기서 나는 select 목록에서 입력된 값에 일치하는 값을 가지는 option에 selected 속성을 지정하기 위해 조건 연산자를 사용했다. 만약 조건 (param.artist == 1)이 true이면, 첫번째 결과 ('selected')가 페이지에 추가된다. 그렇지않으면 두번째 값(빈 문자열)이 추가된다.

EL 함수

EL이 JSTL스펙에서 JSP 스펙으로 넘어가면서, 새로운 묘기를 추가했다. 다시말해 함수를 호출하는 방법이다. EL 함수 문법은 단순하다. 인자들을 괄호안에 가지고 있는 함수의 이름:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

${fn:length(myCollection)}

함수는 태그 라이브러리에 속하는 것이고, 함수 이름은 각 페이지의 태그 라이브러리 지시자를 통해 라이브러리에 지정된 prefix를 포함한다.

태그 라이브러리 기술자(TLD; Tag Library Descriptor)는 함수 이름을 함수의 기능을 구현한 자바 클래스의 static 메소드로 매핑한다.

<function>
<description>
컬렉션의 아이템 갯수나 문자열의 문자 갯수를 리턴한다.
</description>
<name>length</name>
<function-class>
org.apache.taglibs.standard.functions.Functions
</function-class>
<function-signature>
int length(java.lang.Object)
</function-signature>
</function>

여기서 가장 주의해서 볼 것은 <function-signature> 엘리먼트이다. 여기에 함수가 리턴할 값의 형에 대한 선언, static으로 구현한 메소드의 이름, 그리고 괄호안에 모든 인수(없거나 1개 이상, 쉼표로 분리)의 형 선언한 것이 포함된다. 리턴 형과 인수의 형은 JAVA 원시형이거나 완전한(패키지까지 포함한) 형 이름이어야 한다.

length() 함수에 대한 static 메소드는 Jakarta Taglibs Standard library에서는 아래와 같이 구현되어있다:

public static int length(Object obj) throws JspTagException {
if (obj == null)
    return 0;
if (obj instanceof String)
    return ((String)obj).length();
if (obj instanceof Collection)
    return ((Collection)obj).size();
if (obj instanceof Map)
    return ((Map)obj).size();

int count = 0;
if (obj instanceof Iterator) {
    Iterator iter = (Iterator) obj;
    count = 0;
    while (iter.hasNext()) {
        count++;
        iter.next();
    }
    return count;
}
if (obj instanceof Enumeration) {
    Enumeration enum = (Enumeration) obj;
    count = 0;
    while (enum.hasMoreElements()) {
        count++;
        enum.nextElement();
    }
    return count;
}
try {
    count = Array.getLength(obj);
    return count;
} catch (IllegalArgumentException ex) {}
    throw new JspTagException("Unsupported type");
}

여기 보듯이, 별로 낯설것이 없다. 이건 그냥 평범한 static 메소드로 인수의 특정한 런타임 형에 따라 length를 구하는 것이다.

여기서 예로든 length() 메소드 외에도, JSTL 1.1 함수 태그 라이브러리는 자주 사용되는 많은 함수들을 포함하고 있다:

함수 설명
fn:contains(string, substring) string이 substring을 포함하면 true 리턴.
fn:containsIgnoreCase(string, substring) 대소문자에 관계없이, string이 substring을 포함하면 true 리턴.
fn:endsWith(string, suffix) string이 suffix로 끝나면 true 리턴.
fn:escapeXml(string) string에 XML과 HTML에서 특별한 의미를 가진 문자들이 있으면, XML 엔티티 코드로 바꿔준 뒤 문자열 리턴.
fn:indexOf(string, substring) string에서 substring이 처음으로 나타나는 인덱스 리턴.
fn:join(array, separator) array(배열) 요소들을 separator를 구분자로 하여 연결해서 리턴
fn:length(item) item 이 배열이나 컬렉션이면 요소의 갯수를, 문자열이면 문자의 갯수를 리턴.
fn:replace(string, before, after) string 내에 있는 before 문자열을 after 문자열로 모두 바꿔서 리턴.
fn:split(string, separator) string 내의 문자열을 separator에 따라 나누어서 배열로 구성해 리턴.
fn:startsWith(string, prefix) string이 prefix로 시작하면 true 리턴.
fn:substring(string, begin, end) string에서 begin 인덱스에서 시작해서 end 인덱스에 끝나는 부분(end 인덱스에 있는문자 포함)의 문자열을 리턴.
fn:substringAfter(string, substring) string에서 substring이 나타나는 이후의 부분에 있는 문자열을 리턴.
fn:substringBefore(string, substring) string에서 substring이 나타나기 이전의 부분에 있는 문자열을 리턴.
fn:toLowerCase(string) string을 모두 소문자로 바꿔 리턴.
fn:toUpperCase(string) string을 모두 대문자로 바꿔 리턴.
fn:trim(string) string 앞뒤의 공백(whitespace)을 모두 제거하여 리턴.

마무리

이 글에서, 새로운 EL의 특징과 JSTL 1.1 함수 라이브러리 등 JSP 스펙에 도입된 EL을 다루었다. 다음 회에서는 JSP의 오류 페이지(error-page)의 향상과 jsp:id 속성의 이점, 새로운 배치 기술자(deployment descriptor)의 형식, JSP 2.0 이 JSP와 XML 사용을 어떻게 쉽게 만들어주는가, 그리고 커스텀 태그 라이브러리에 관한 사항들을 다룰 것이다.

JSP 2.0의 새로운 기능들을 접해보고 싶다면, Apache Tomcat 5를 사용해보라고 권하고 싶다. 톰캣은 새로운 JSP 스펙을 최초로 구현한 JSP 컨테이너이다. Jakarta Project 사이트에서 구할 수 있다.

'Computer > Web' 카테고리의 다른 글

JSP / request 내부 객체  (1) 2007.03.16
JSP 코드 작성 요령  (1) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 4부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 3부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 2부  (0) 2007.03.12
JSP 2.0: 뭐가 바뀌었나? - 1부  (0) 2007.03.12
TAG

댓글을 달아 주세요