원문 : http://simply.liftweb.net/index-Chapter-2.html#toc-Chapter-2
2장
유비쿼터스 챗 앱(The ubiquitous Chat app)
Lift로 다중사용자 채팅 애플리케이션을 작성하는 것은 아주 간단하고 Lift의 핵심개념들중 많은 것들을 설명해 줍니다. 소스코드는 https://github.com/dpp/simply_lift/tree/master/chat에서 볼 수 있습니다.
2.1 뷰(View)
Lift 앱을 작성할 때 사용자가 보는 것을 만들고 HTML페이지에 동작을 추가하는 유저인터페이스에서 시작하는 것이 종종 가장 좋습니다. 그래서 우리의 채팅애플리케이션을 만들 Lift 템플릿을 보겠습니다.
리스트 2.1 : index.html
유효한 HTML페이지이지만 약간 수상스러운 클래스속성들이 있습니다. 첫번째는 <body class=”lift:content_id=main”>입니다. 여기서 클래스는 “실제 페이지 내용은 id=’main’엘리먼트에 담겨있다”고 말해줍니다. 이것은 각각의 템플릿을 위한 유효한 HTML페이지를 가지도록 해주지만 동적으로 하나이상의 크롬(chrome) 템플릿에 기반한 컨텐츠에 “크롬(chrome)”을 추가합니다.
<div id=”main”>을 보겠습니다. 이것은 lift:surround?with=default;at=content같은 파격적인 클래스를 가지고 있습니다. 이 클래스는 기본템플릿으로 <div>를 둘러싸고 <div>와 기본템플릿에서 id가 “content”인 엘리먼트에서 그 자식들을 인서트하는 스니펫(snippet)을 호출합니다. 또는 <div>주변을 기본크롬으로 감쌉니다. 스니펫(snippet)에 대한 더 자세한 내용은 48페이지의 7.1을 보세요.
다음으로 챗 엘리먼트 <div class="lift:comet?type=Chat">와 동적인 동작을 어떻게 연계하는지 정의합니다. “comet” 스니펫은 CometActor를 상속받고 CometActor의 상태가 변경되었을 때 CometActor에서 브라우저로 컨텐츠를 푸싱(pushing)하는 메카니즘을 가능하게 하는 Chat이라는 이름의 클래스를 찾습니다.
2.2 Chat Comet 컴포넌트
Actor 모델은 Erlang을 포함하는 함수형 언어에서 상태(state)를 제공합니다. Lift는 Actor라이브러리와 강력한 상태와 동시성 모델을 제공하는 LiftActors(7.14 참고)를 가지고 있습니다. 이것은 모두 추상화되어 보이므로 Chat클래스를 보겠습니다.
리스팅 2.2 : Chat.scala
Chat 컴포넌트는 private state와 ChatServer 레지스터, 인커밍(incoming) 메시지 핸들러들을 가지고 있고 그것들을 렌더링할 수 있습니다. 이 각각의 조각들을 보겠습니다.
프로토타입 객체지향 코드에서 다른 private state처럼 private state는 객체의 행위를 정의하는 state입니다.
registerWith는 어떤 컴포넌트가 Chat 컴포넌트에 등록하는 지를 정의하는 메서드입니다. 등록은 Listener(또는 Observer) 패턴의 하나입니다. 잠시 ChatServer의 정의를 보겠습니다.
lowPriority메서드는 어떻게 들어오는 메시지를 처리하는지를 정의합니다. 이경우에 들어오는 메시지를 패턴 매칭(7.15 참조)하고 그것이 Vector[String]이면 local state에 설정된 액션을 Vector에 수행하고 컴포넌트를 리랜더링(re-rendering)합니다. 리랜더링(re-rendering)은 컴포넌트를 디스플레이하는 모든 브라우저가 변경되도록 할 것 입니다.
매칭하고 교체하려고(7.10 참고) CSS를 정의함으로써 컴포넌트를 어떻게 render하는지 정의합니다. 템플릿의 모든 <li>태그를 매치하고 각 메시지를 위해서 메시지에 설정하는 <li>태그를와 자식노드들을 생성합니다. 추가적으로 class 속성이 clearable인 모든 엘리먼트를 클리어 합니다.
이것이 Chat CometActor 컴포너트를 위한 것입니다.
2.3 ChatServer
ChatServer 코드:
리스팅 2.3 : ChatServer.scala
ChatServer는 class보다는 object로써 정의됩니다. 이는 그것을 애플리케이션 어디서든 ChatServer 이름으로 참조될수 있는 싱글톤으로 만듭니다. Scala의 싱글톤은 object의 인스턴스이고 이 인스턴스는 다른 모든 인스턴스처럼 건네질(be passed) 수 있다는 점에서 Java의 static과는 다릅니다. 이것이 Chat컴포넌트에서 registerWith메서드로부터 ChatServer 인스턴스를 리턴할 수 있는 이유입니다.
ChatServer는 채팅메시지의 리스트를 표현하는 Vector[String]인 private state을 가집니다. 명백하게 타입을 정의하지 않았기 때문에 Scala의 타입추론기는 msgs의 타입을 추론합니다.
createUpdate메서드는 리스터에 보낼 최신정보를 생성합니다. 리스너가 ChatServer에 등록되거나 updateListeners()메서드가 호출되었을 때 이 최신정보가 보내집니다.
마지막으로 lowPriority메서드는 이 컴포넌트가 다룰 수 있는 메시지들을 정의합니다. ChatServer가 메시지로 String을 받으며 String을 메시지의 Vector에 덧붙히고 리스터들을 업데이트합니다.
2.4 유저 인풋(User Input)
뷰(view)로 돌아가서 chat에 라인들을 추가하기 위해서 동작(behavior)이 어떻게 정의되는지 보겠습니다.
<form class="lift:form.ajax">는 input form을 정의하고 form.ajax 스니펫은 form을 전체 페이지가 로드는 일 없이 서버에 submit될 수 있는 Ajax(7.12 참고) form으로 바꿉니다.
다음으로 인풋 폼 엘리먼트 <input class="lift:ChatIn" id="chat_in"/>를 정의합니다. 이것은 plain old input form이지만 ChatIn 스니펫을 호출함으로써 Lift에게 <input>의 동작을 수정하라고 말합니다.
2.5 Chat In
ChatIn 스니펫(7.1 참조)는 다음과 같이 정의되었습니다:
리스팅 2.4 : ChatIn.scala
코드는 아주 간단합니다. 스니펩은 함수와 폼엘리먼트의 제출 onSubmit을 연결하는 메소드로 정의됩니다. 보통의 폼서밋이든 ajax든지 엘리먼트가 submit되었을 때, 함수는 form의 값에 적용합니다. 영어로말하면 사용자가 폼을 제풀했을때 함수는 사용자 인풋과 함께 호출됩니다.
함수가 메시지로 input을 ChatServer로 보내고 input box의 값을 빈스트링으로 설정하는 JavaScript를 리턴합니다.
2.6 실행(Running it)
어플리케이션을 실행하는 것은 쉽습니다. 서버에 Java1.6이상이 설치되어 있어야 합니다. chat디렉토리에서 sbt update jetty-run을 입력합니다. Simple Build Tool은 필요한 모든 의존성을 다운로드하고 프로그램을 컴파일한 뒤 실행합니다.
브라우저에서 http://localhost:8080에 접속하고 채킹을 시작합니다.
오, 재미를 위해서 <script>alert(’I ownz your browser’);<script> 입력하고 어떤 일이 일어나는지 보세요. 기대했던 대로 되는 것을 볼 것입니다.
2.7 당신이 보지 못한 것들
import와 주석을 제외하면 멀티쓰레드, 다중사용자 채팅애플리케이션을 구현하는데 약 20라인정도의 스칼라 코드정도입니다. 많지 않습니다.
첫째로 동기화나 다른 쓰레드락킹의 명백한 폼이 빠졌습니다. 애플리케이션은 Actor와 immutable 데이터 스트럭쳐의 이점을 취하기 때문에 개발자는 쓰레드와 primitive 락팅보다는 비즈니스로직에 집중할 수 있습니다.
다음으로 라우팅과 컨트롤러, Ajax호출과 서버변경에 대한 폴링을 연결하는 것들이 빠졌습니다. 애플리케이션에서 동작과 화면을 연결하면 나머지는 Lift가 알아서 합니다.(7.17 참조)
애플리케이션에서 크로스사이트 스크립팅을 피하는 어떤것도 하지 않았습니다. 왜냐하면 Lift가 Scala의 강한 typing과 type safety( 7.16참조)의 이점을 취했기 때문입니다. Lift는 HTML로 인코딩되어야 하는 문자열과 이미 알맞게 인코딩된 HTML 엘리먼트사이의 차이를 알고 있습니다. 기본적으로 Lift 애플리케이션은 OWASP 10대 보안취약성의 대부분을 방지합니다.
시작부터 액터야!!!! (#(*$&#@&*!^@*#&@*!&$^#*!@$)
나도 그거에 대해서 불평했었지...
시작얘제가 액터라니 ㅡ..ㅡ