자바에서 디컴파일을 할 필요가 있는 경우 사용하는 Decompiler로 jad를 이용하곤 했는데

그 jad를 이클립스에서 사용할 수 있도록 제공했던 jadclipse라는 플러그인이 있었습니다.

지금은 jd-eclipse라는 다른 이름으로 플러그인을 제공하고 있네요.

이전 update사이트로는 더이상 다운로드 받을수 없습니다.

저역시 이클립스 3.4 Ganymede를 사용하면서 이전 버젼이 동작되지 않아서 혹시 3.4버젼으로 업데이트가 되지 않았나 싶어

기존의  http://jadclipse.sf.net/update 로 업데이트를 받아보았지만 실패...

(다른 분들의 블로그에서는 3.4 버젼에서도 잘 동작된다고 하던데 ...-_-)

사이트로 직접 가보니 이런이런 http://java.decompiler.free.fr/jd-eclipse/update 로 바뀌었네요..

이름도 jadclipse에서 jd-eclipse로 바뀌었다는 사실..

그래도 설정메뉴는 window>preferences>java>JadClipse 로 예전과 동일합니다...

 

다음 3.4 버젼과 그 이전버젼의 설치방법은 아래에 소개합니다.

 

1단계 : Equinox/p2 plug-in 설치

  1. JD-Eclipse를 설치하기 위해서는 Equinox/P2 플러그인이 필요합니다. 먼저 설치를 해야합니다.
  2. 이클립스 메뉴 Help > Software Updates... 을 클릭하시면 Software Updates and Add-ons 팝업창이 뜨네요



  3. Available Software 탭을 선택합니다.
  4. Ganymede 항목을 펼칩니다.
  5. 하위리스트에서 Uncategorized 항목을 한번 더 클릭하여 펼칩니다.
  6. Equinox p2 Provisioning 항목을 선택하고 우측 상단의 Install... 버튼을 클릭합니다.
  7. 전 이미 설치가 되어있었지만 버젼이 달라서인지 설치에러가 나더라구요 그경우에는 installed software 탭을 선택후 업데이트를 진행하시면 됩니다.



  8. 잠시후 인스톨이 되면 활성화가 된 Finish 버튼을 클릭합니다.

2단계 : JD-Eclipse plug-in 설치하기

  1. 다시 Eclipse Help> Software Updates... 을 클릭하여 Software Updates and Add-ons 팝업창을 띄웁니다.
  2. Available Software 탭을 선택하시고.
  3. Add a new remote site 버튼을 클릭한 후 add JD-Eclipse plug-in을 추가합니다
    1. Add Site... 클릭하면 Add Site 팝업창이 뜹니다.
    2. Location 필드에 다음과 같이 http://java.decompiler.free.fr/jd-eclipse/update 라고  JD-Eclipse update 사이트주소를 입력후 OK 버튼을 클릭합니다



  4.  Software Updates and Add-ons 윈도우창에 JD-Eclipse update site가 표시되면, 다음과 같이 JD-Eclipse Plug-in 를 선택한 다음Install... 버튼을 클릭합니다.



  5. 진행후 다음 화면에서 Finish 버튼을 클릭합니다.
  6. Java Decompiler Eclipse Plug-in certificate 확인 페이지가 뜨는데 체크박스를 선택하고 OK 버튼 클릭.

JD-Eclipse plug-in이 성공적으로 설치가 된 경우에는 이클립스를 재구동하면 적용사항을 확인할 수 있다

비고.Eclipse 3.2, 3.3 의 경우

  1. 역시 이클립스 Help 메뉴 아래 Software Updates > Find and Install... 를 선택하면 Install/Update 팝업창이 뜹니다



  2. Install/Update 팝업창에서 Search for new features to install 옵션선택후 Next 버튼 클릭.
  3. new remote site 팝업창에서 JD-Eclipse plug-in 업데이트 주소를 입력합니다:
    1.  New Remote Site... 버튼을 클릭하면 New Update Site 팝업창이 뜹니다.
    2.  New Update Site 팝업창에서 Name 필드에는  JD-Eclipse Update Site 라고 입력합니다 
    3. URL 필드에는 http://java.decompiler.free.fr/jd-eclipse/update 라고 입력후 OK 클릭.



    4. Finish 버튼을 클릭하여 Updates 팝업창으로 돌아옵니다.
  4. Updates 창에서 JD-Eclipse Update Site 를 선택하고 Finish 버튼을 클릭.



  5. 다음화면에서 JD-Eclipse Update Site 를 선택후  Next 버튼 클릭.
  6. 역시 the license agreement를 확인하는 창에서 체크박스를 선택후 Next 버튼 클릭.
  7. Finish 버튼 클릭.
  8. Install All 버튼을 클릭. (끝)

다음 해야될것이 .class 파일클릭시 기본적으로 jadclipse 가 실행되도록 설정해줘야 합니다.

Windows> Preferences > General > Editors > File Associations 클릭하게 되면

모든 확장자가 기본적으로 취하게 되는 프로그램명들을 설정할수 있게 되어있는데 .class 파일을

클릭해서 아래에 jadclipse file view를 기본으로 사용하겠다고 오른쪽 default 클릭해서 셋팅합니다.

 

설정항목은 이클립스 window메뉴>preferences>java>JadClipse 에서 확인할 수 있습니다.

보통은 그대로 두시면 되는데

혹 안되신다면 path to decompiler 항목에 디컴파일러인 jad.exe가 있는 경로를 지정합니다.

jadClipse와 마찬가지로 jad를 다운받는곳이 바뀌었는지 링크가 걸리질 않습니다.

그래서 기냥 첨부파일로 올려드리구여. 압축을 임의의 폴더에 푸신후 경로를 지정하시면 됩니다.

(예 d:\dev\jad\jad.exe) 

 

혹 한글이 깨지시는 분은 window메뉴>preferences>java>JadClipse>Misc 에서 

Convert Unicode String into ANSI Strings 항목을 선택합니다.

사용방법은 jar파일내 class파일을 클릭하시면 디컴파일된 코드로 보실수 있습니다.(초간단)


 

 

Eclipse 가 deploy 등등 조작(?)을 하려면 서버 설정을 하나 해줘야 합니다.


- 서버 시작
시작 → 프로그램 → Oracle WebLogic → User Projects → base_domain → Start Admin Server for Weblogic Server Domain


- Administration Console 실행 → 상단에 Preferences 클릭




- 마지막 Automatically Acquire Lock and Activate Changes를 체크해제하고 Save 클릭




-_- ; 웹로직 10.1 과 달랐던 부분. 크 따라하다가 결국 다시 10.3으로 설치를...



- 왼쪽 상단의 Change Center가 수동으로 바뀌었습니다.




- Release Configuration을 클릭하여 Lock & Edit 버튼이 활성화되게 바꿉니다.
이 상태가 되어야 Eclipse가 자동 배포 등이 가능하게 됩니다..







Eclipse에 Runtime Server 추가하기


- Eclipse IDE for Java EE Developers로 시작합니다... File → New → Other... 선택



- Server → Server 선택. Next 클릭



- 처음에는 WebLogic이 없습니다. Download additional server adapters 클릭



- 기다리면 정보를 받아와 목록이 생깁니다. Oracle WebLogic Support 선택. Next 클릭



- 라이선스에 동의. Finish 클릭





- 프로그램을 다운로드 받아 설치한다고 합니다. OK 클릭




- 다운로드 및 설치 중... 설치가 완료되면 자동으로 Eclipse를 재시작합니다.



- JDK 버젼 어쩌고 나오는군요... Yes 클릭



- 다시 File → New → Other... 그리고 Server → Server
서버 목록에 Oracle WebLogic Server v10.3 이 생겼습니다. 선택 후 Next




- 전 처음에 서버 목록 중 BEA Systems에서 한참 찾았습니다.
아무리 봐두 10.0만...

   무심코 진행했는데 조금 구동 스크립트가 다른지 에러가...

   다시 확인해보니 10.3은 오라클 밑에 있네요. 오라클 밑에 10.3을 선택하세요...(*_*)



- WebLogic Server 의 위치를 설정합니다.




- 도메인을 설정합니다.



- 적용시킬 프로젝트를 추가시킵니다. 현재는 프로젝트가 하나도 없군요...



- 아래 Servers 탭에 WebLogic Server 가 추가되었습니다.






간단한 세션 빈 테스트 - Server(WebLogic)
※ 컴퓨터 2대(Tomcat 6.0.18, WegLogic 10.3)로 분산환경에서 테스트 합니다.


File → New → Other... 그리고 General → Faceted Project 선택. Next 클릭



- 프로젝트 이름 설정. Next 클릭



- Facet 를 조합합니다. WebLogic에 맞는 EJB Porject를 생성하기 위해서는 아래와 같이 조합합니다.

오른쪽 Runtimes 탭에서 꼭 Oracle Weblogic Server v10.3을 체크해주세요.
체크하지 않으면 "Failed to retrieve WLS runtime for EJB processing" 에러가 납니다.



- Source Folder를 설정합니다.



- 잘 만들어 졌다네요..(아닌가?)



- Project Explorer를 보게되면 아래와같이 EJB Project가 만들어졌습니다.



- New → Package. 패키지를 하나 만듭니다.



- New → WebLogic Session Bean 선택. 여기서 만드는 파일이 빈(Bean) 클래스 파일이 됩니다.



- 소스 코드를 완성합니다.(샘플코드는 첨부파일로...)

기본적으로 세션빈에서 만들어져야 하는 명세는 GenericSessionBean 클래스에 작성되어있고 이걸 상속 받는군요...
public class HelloWorld extends GenericSessionBean implements SessionBean
{



중요한 부분은 @ 가 있는 부분입니다.

@JndiName은 클라이언트에서 lookup하는 JNDI 이름을 설정합니다.
@FileGenerration은 remoteClass, remoteHome, localClass, localHome 클래스 파일을 자동 생성할지 설정합니다.

@Session(ejbName = "HelloWorld")
@JndiName(remote = "ejb.HelloWorldRemoteHome")
@FileGeneration(remoteClass = Constants.Bool.TRUE, remoteHome = Constants.Bool.TRUE,
                          localClass = Constants.Bool.FALSE, localHome = Constants.Bool.FALSE)


remoteClass를 TRUE로 설정시, 사용자가 추가하는 메소드에는 꼭 @RemoteMethod를 적어줘야 원격(Remote) 클래스에 메소드가 추가됩니다.
@RemoteMethod
public String helloWorld() {
     return "Hello World!!";
}


빈(Bean) 클래스 파일만 작성하면 원격(Remote) 클래스, 홈(Home) 클래스, 기타파일(ejb-jar.xml, weblogic-ejb-jar.xml) 등을 알아서 만들어줍니다.

ex)
빈(Bean) 클래스 : HelloWorld.java
원격(Remote) 클래스 : HelloWorldRemote.java ← 자동생성
홈(Home) 클래스 : HelloWorldRemoteHome.java ← 자동생성
배치 디스크립터 파일 : ejb-jar.xml , weblogic-ejb-jar.xml ← 자동생성


- 아래 Servers 탭에서 WebLogic을 선택후 마우스 우클릭 → Add and Remove Projects...
현재 만든 프로젝트를 Configured projects 목록에 추가시킵니다.




- 서버 아래에 HelloWorld 프로젝트가 추가되었습니다.




- Run → Run 선택. Run on Server 선택 후 OK




- 서버 확인 후 Finish




- 서버가 실행되면서 자동으로 배치(재배치) 합니다.



※ 프로젝트의 State가 둘다 "Republish", "Synchronized"가 아니면 배치가 안된거니 확인하세요.

(명세에 안맞거나 기탕 등등 에러)

※ 여기서 이런 오류가 나온다면, 위에 "시작전설정" 이 제대로 안되서 나오는 오류 입니다.




- Administration Console 실행 후 Deployments에서 배치가 되어있으면 성공!
※ 이클립스 프로젝트가 삭제되거나 서버의 프로젝트 목록에 없으면 배치가 안되니 다 완성후에는

수동으로 배치 시켜줘야겠죠?;;






클라이언트 설정하기


- 서버에서 작성된 EJB jar 파일이 클라이언트에서 필요합니다.
프로젝트 최상위 루트에서 마우스 우클릭 → Export → EJB JAR File 선택 후 적당한 위치에 저장합니다.
이 파일(HelloWorld.jar)은 클라이언트 프로젝트의 WebContent\WEB-INF\lib 에 저장합니다.



- 클라이언트가 서버와 다른 컴퓨터. 다른 JVM, 다른 컨테이너 등등 다를 경우 서버(WebLogic)의 라이브러리가 필요합니다
wlfullclient.jar 파일은 [톰켓설치폴더]\lib 에 저장합니다.



간단한 세션 빈 테스트 - Client(Tomcat)
※ 컴퓨터 2대(Tomcat 6.0.18, WegLogic 10.3)로 분산환경에서 테스트 합니다.


- File → New → Dynamic Web Project 선택. 프로젝트 이름, Target Runtime 설정





- 소스 코드를 완성합니다.(샘플코드는 첨부파일로)

소스의 내용은 JNDI로 룩업해서 Hello World!!! 찍는거...

wlfullclient.jar과 HelloWorld.jar 파일이 아래와 같이 라이브러이에 등록되어있어야 합니다.
wlfullclient.jar : [톰켓설치폴더]\lib
HelloWorld.jar : [프로젝트]\WebContent\WEB-INF\lib




- Run → Run. Server 확인 후 Finish




- 잘 실행되었습니다!! ㅠ_ㅠv


역시 antop님의 블로그에서 퍼온글입니다.

 

출처 : http://antop.tistory.com

 

도메인이란? 관리적인 개념으로서 단일 Administration Server로 관리하는 Server, Machine 및 Cluster의 그룹(인터넷 도메인 x)

- 시작 → 프로그램 → Oracle WebLogic → WebLogic Server 10gR3 → Tools → Configuration Wizard

- Create a new WebLogic domain 선택



- Generate a domain configured automatically to support to following products 선택



- User name과 User password 설정



- 서버 모드(개발, 운용) 및 JDK 설정



- 다른 옵션들 추가 설정



- 도메인 이름, 디렉토리 설정



- 도메인 생성 완료






※ html, jsp, Servlet 테스트

Test.war 파일을 배치하여 테스트 해봅시다.

- Test.war 파일을 적당한 위치로 옮깁니다.




- 서버를 실행합니다.
시작 → 프로그램 → Oracle WebLogic → User Projects → base_domain → Start Admin Server for Weblogic Server Domain



Administration Console을 실행합니다.



- 왼쪽의 Domain Structure 트리에서 Deployments를 선택합니다.



-
Install 클릭



- 배치할 파일이나 디렉토리를 설정합니다.
여기서 war, jar 파일이나 디렉토리가 선택이 되지 않으면 잘못 작성되었기 때문입니다.



- Next 클릭



- Finish 클릭.(더 자세한 설정을 하려면 Next로 더 설정할 수 있습니다)



- war 파일이 정상적으로 배치(deploy) 되었습니다.



- html 테스트



- jsp 테스트



- Servlet 테스트



앞서 말한바와 같이 antop님의 블로그에서 퍼왔습니다.

테스트 파일은 첨부파일로 별도 첨부합니다..

출처 : http://antop.tistory.com/

 

WAS로 제우스를 쓰다가 지금은 JBoss로 넘어왔기에 웹로직을 접해본지가 벌써 6년전이네요.

오라클로 넘어갔다는 말을  얼핏 들었던거 같았는데 지금은 사이트도 오라클로 통합되었네요.

 

버젼이 10.x 네요. 와우~

참고한 블로그는 antop님의 블로그입니다.

사이트에서 10.1을 받았는데 antop 님은 10.3을 가지고 글을 쓰셨더라구여

이클립스 연동부분에서 버젼이 달라서인지 메뉴가 조금 다르다는 사실...

결국 10.3 을 다시 다운 받아 따라 해보았습니다. 참고하시길...

 

출처 : http://antop.tistory.com/

 

 

- 설치 환경



java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Client VM (build 11.2-b01, mixed mode, sharing)



설치파일을 다운로드 받습니다.




- 다운로드 받은 설치파일을 실행합시다. (Net Installer - net_server103_win32.exe)




- Welcome~ Next...



- BEA Home Directory 설정후 Next



- Net Installer 에서만 나오는 설정입니다. 설치하면서 받을 파일 저장 위치를 지정합니다.



- 기본설치, 사용자설치 선택. 아무것도 모르겠다 하면 Complete 하시면 되겠죠... 저는 Custom로 합니다.




- 설치할 프로그램을 설정합니다.
Workshop은 Eclipse를 개량하여 최적화시킨 것입니다. 저는 Eclise를 따로 쓰기 때문에 패스.




- 사용할 JDK 를 선택합니다.
WebLogic 기본으로 1.6.0_05를 설치하는데 저는 1.6.0_12를 사용하기 위해서 따로 JDK를 추가 했습니다.




- JDK 1.6.0_12 쓸거냐고 물어보는군요... 가볍게 Yes




- 설치파일을 다운로드 받습니다. Net Installer 에서만 볼 수 있습니다.




- 다운로드 받은 설치파일을 검사합니다. Net Installer 에서만 볼 수 있습니다.




- WebLogic이 설치될 디렉토리를 설정합니다.



- Node Manager Service를 설치할지 설정.


- 시작메뉴를 전체 다 보여줄지 선택.. 윈도우 관련된 것이죠.. -_-/


- 설치될 파일들을 마지막으로 확인합니다.



- 설치 시작


- 설치가 완료되었습니다.




- 간단하게 설치가 잘 되었는지 확인하기 위해서....
시작 → 프로그램 → Oracle WebLogic → WebLogic Server 10gR3 → Examples → Start Examples Server 선택



http://localhost:7001/ 잘 되면 설치 완료!



- 서버 끄기 : 시작 → 프로그램 → Oracle WebLogic → WebLogic Server 10gR3 → Examples → Stop Examples Server 선택
※ 서버 끌때 그냥 cmd 창 닫아버리지 말고, 꼭 stop하는 명령(?)을 이용합니다.


- 설치하다가 이런거 나오면 윈도우 보안 관련된 것이니 '차단 해체' 선택해주세요.

 

2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어

(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자

"학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

 그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다.

아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을

사용할 수 있게 되었다는 점입니다. 학습 곡선 일지 시리즈의 1편, 2편 및 3편은 컴파일러 기반 버전의

언어 사용 방법을 보여주기 위해 업데이트 되었습니다.

최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

4편은 시리즈의 2편에서 시작된 JavaFX 이미지 검색 애플리케이션을 완결하는 새로운 부분입니다.

학습 곡선 일지의 앞 부분에서는 JavaFX 스크립트를 사용하여 Flickr에서 이미지를 검색하는

기존 이미지 검색 애플리케이션의 사용자 인터페이스(UI)를 재현했습니다.

결과 JavaFX 스크립트는 원래 UI와 완전히 똑같진 않지만 상당히 근접했습니다.

그림 1은 JavaFX 스크립트 구현으로 생성된 기본 UI를 보여줍니다.

 

그림 1. JavaFX 이미지 검색 애플리케이션 UI

 UI 구축에는 계층 구조적인 Swing 기반 접근 방법을 따랐습니다.

이 시리즈의 1편에서 언급한 것처럼 JavaFX 개발자는 앞으로 노드 기반 접근 방법을 사용할 것입니다.

이제 애플리케이션의 JavaFX 스크립트 버전을 완료하고 사용자가 Flickr 웹 사이트에서 이미지를 검색, 나열 및

표시할 수 있도록 하겠습니다. 완성된 JavaFX 스크립트 애플리케이션을 위해 NetBeans 프로젝트 다운로드를 받을 수 있습니다.


이미지 검색

구 현할 첫 번째 동작은 이미지 검색입니다.

사용자가 UI의 검색 필드에 검색어를 입력하면 애플리케이션은 Flickr 웹 사이트에서 이미지 검색을 시작합니다.

검색어와 매칭되는 이미지가 있으면 애플리케이션은 최대 100개의 매칭되는 축소판 이미지의 목록을 로드하여

UI의 Matched Images 영역에 선택 가능한 목록으로 표시합니다. 또한 진행 표시줄이 이미지 검색을 추적합니다.

기 존 이미지 검색 애플리케이션은 Matched Images 영역에 반환된 축소판 이미지의 목록을 제목과 함께 표시합니다.

우리는 JavaFX 스크립트 애플리케이션 목록에서 매칭되는 이미지의 반환된 제목만 보여주도록 단순화하겠습니다.

JavaFX 스크립트의 ListItem 구성요소는 현재 icon 속성을 갖지 않습니다.

따라서 현재 ListListItem 구성요소가 생성하는 목록은 이미지를 포함할 수 없습니다.

이미지 검색을 위해 ImageSearcherPhoto의 두 가지 JavaFX 스크립트 클래스를 생성했습니다.

또한 진행 표시줄을 위한 별도의 클래스도 생성했습니다. JavaFX 스크립트 패키지에 ProgressBar 구성요소는 아직 없습니다.

임시 해결책으로 학습 곡선 일지 시리즈에서 구축한 이미지 검색 UI에 Swing JProgressBar 구성요소로부터

JavaFX 스크립트 진행 표시줄을 생성하는 createProgressBar 함수를 포함했습니다.

우리는 이 함수를 자체 파일의 자체 클래스로 이동하기로 결정했습니다.

이는 애플리케이션의 주요 부분을 깔끔하게 만드는 이점이 있습니다.

따라서 애플리케이션에는 이제 4개의 파일이 있습니다.

  • Main.fx: 애플리케이션의 주요 부분을 제공합니다. UI를 표시하고 이미지 검색 및 가져오기를 호출합니다.
  • ImageSearcher.fx: 이미지 검색을 수행합니다.
  • Photo.fx: Flickr 사진을 나타냅니다.
  • TempProgressBar.fx: 진행 표시줄을 생성합니다.

다음은 이미지 검색을 호출하는 Main.fx의 코드입니다.

  var searcher = ImageSearcher {
      callback: function(photos:Photo[]):Void {
          thumbnailList.items = for(photo in photos) {
              ListItem {
                  text: photo.title
                  value: photo
              }
          };

          matchedImagePB.indeterminate= false;
      }
  };

  var search = function():Void {
      System.out.println("searching... {searchTextField.text}");
      matchedImagePB.indeterminate = true;
      searcher.search(searchTextField.text);
  };

  searchTextField.action=search;

사용자가 UI의 검색 필드에 검색어를 입력하면 ImageSearcher 클래스 내의 search 함수를 호출하는 작업을

트리거하고 검색어를 search 함수로 전달합니다.

변수에 함수가 지정된 것에 유의하십시오.

  var search = function():Void {...}
 

JavaFX 스크립트에서 함수는 변수에 지정되거나 매개 변수로써 다른 함수에 전달될 수 있는 1급 개체(first-class object)입니다.

또한 함수는 matchedImagePB의 indeterminate 등록 정보를 true로 설정합니다. 

  var matchedImagePB = TempProgressBar { };
  matchedImagePB.indeterminate = true;

TempProgressBar 클래스는 matchedImagePB 변수에 지정됩니다.

따라서 matchedImagePB의 indeterminate 등록 정보를 설정하는 것은 실질적으로

TempProgressBar 개체의 indeterminate 등록 정보를 설정하는 것입니다.

그 영향을 이해하기 위해 TempProgressBar 클래스를 살펴보겠습니다.


TempProgressBar 클래스

다음은 TempProgressBar 클래스입니다.

 package javafxscriptimgsearch2;

  import javafx.ext.swing.*;

  public class TempProgressBar extends Component {
      protected function createJComponent():javax.swing.JComponent {
          return new javax.swing.JProgressBar();
      }
      public attribute indeterminate:Boolean = false on replace {
          var prog = this.getJComponent() as javax.swing.JProgressBar;
          prog.setIndeterminate(indeterminate);
      }
}
클래스에는 createJComponent 함수와 indeterminate 속성이 있습니다. 
replace
트리거가 indeterminate 속성에 연결되어 있습니다.
      public attribute indeterminate:Boolean = false on replace {
          var prog = this.getJComponent() as javax.swing.JProgressBar;
          prog.setIndeterminate(indeterminate);
      }
 

애플리케이션의 주요 부분이 속성을 true로 설정하는 것과 같이 속성 값이 변경되면 트리거는 진행 표시줄을 생성합니다.

특히 트리거는 getJComponent() 함수를 사용하여 JavaFX 스크립트 구성요소로 캡슐화된 Swing JProgressBar

구성요소를 생성합니다. 트리거는 또한 JProgressBar 구성요소의 indeterminate 등록 정보를

true로 설정하여 검색 진행 중에 진행 표시줄이 계속 움직이도록 합니다.

트 리거는 JavaFX 스크립트의 강력한 기능 중 하나입니다. 트리거는 특정 조건 충족 시 코드 블록을 실행하도록 합니다.

또한 기존 Swing 구성요소의 재사용이 얼마나 쉬운지에도 유의하십시오.

Swing 구성요소를 사용하려면 JavaFX 스크립트로 간단한 래퍼(wrapper)를 작성하기만 하면 됩니다.


ImageSearcher 클래스

다음은 ImageSearcher 클래스입니다.


   package javafxscriptimgsearch2;

import javax.xml.parsers.*;
import org.xml.sax.helpers.DefaultHandler;
import java.lang.System;
import java.lang.Thread;
import java.lang.Runnable;
import javax.swing.SwingUtilities;

public class ImageSearcher {
public attribute callback: function(photos:Photo[]):Void;

public function search(search:String) {
var thread = new Thread(Runnable {
public function run():Void {
var photos:Photo[];

var handler = DefaultHandler {
public function startDocument() { }
public function startElement(uri:String, localName:String, qName:String , attributes:org.xml.sax.Attributes ) {
if(qName == "photo") {
var photo = Photo {
id: attributes.getValue("id")
server: attributes.getValue("server")
farm: attributes.getValue("farm")
title: attributes.getValue("title")
secret: attributes.getValue("secret")
};
insert photo into photos;
}
}
public function endElement(uri:String , localName:String , qName:String ) { }
public function endDocument() { }

};

var SEARCH_URL = "http://api.flickr.com/services/rest/?" +
"method=flickr.photos.search";
var key = "339db1433e5f6f11f3ad54135e6c07a9";
var MAX_IMAGES = 100;
var searchUrl = "{SEARCH_URL}&api_key={key}&per_page={MAX_IMAGES}&text={search}";
var url = new java.net.URL(searchUrl);
var is = url.openStream();
var factory = SAXParserFactory.newInstance();
var saxParser = factory.newSAXParser();
saxParser.parse(is, handler);

SwingUtilities.invokeLater(Runnable {
public function run():Void {

if(callback != null) {
callback(photos);
}
}
});
}
});
thread.start();
}
}
 

ImageSearcher 클래스는 애플리케이션에서 이미지 검색을 수행하는 search 함수의 래퍼(wrapper)입니다.

새 스레드를 시작하여 search 함수가 시작됩니다. 스레드 내에서 함수는 검색어와 매칭되는 이미지(Flickr에서는 사진)를 가져오기

위해 Flickr 사진 검색 웹 서비스를 호출합니다. 다음은 Flickr 서비스를 호출하는 코드입니다. 

   var SEARCH_URL = "http://api.flickr.com/services/rest/?" +
          "method=flickr.photos.search";
  var key = "339db1433e5f6f11f3ad54135e6c07a9";
  var MAX_IMAGES = 100;
  var searchUrl = "{SEARCH_URL}&api_key={key}&per_page={MAX_IMAGES}&text={search}";
  var url = new java.net.URL(searchUrl);
  var is = url.openStream();

호출은 Flickr API의 REST(Representational State Transfer) 버전을 사용합니다

(Flickr는 XML-RPC 및 SOAP 버전도 제공합니다). API에 전달되는 인수에는 API 키, 반환되는 이미지의 최대 갯수,

사용자가 지정한 검색어가 포함됩니다. 애플리케이션에서 최대 100개의 매칭되는 이미지 목록을 다운로드하고 싶으므로

이미지 최대 갯수를 100으로 설정했습니다. 사진 검색 서비스는 사진을 XML 문서로 반환하므로 문서를 분석하는 기법이 필요합니다.

이 애플리케이션에서는 분석 수행을 위해 SAX DefaultHandler를 사용했습니다.

   var handler = DefaultHandler {
public function startDocument() { }
public function startElement(uri:String, localName:String, qName:String , attributes:org.xml.sax.Attributes ) {
if(qName == "photo") {
var photo = Photo {
id: attributes.getValue("id")
server: attributes.getValue("server")
farm: attributes.getValue("farm")
title: attributes.getValue("title")
secret: attributes.getValue("secret")
};
insert photo into photos;
}
}
public function endElement(uri:String , localName:String , qName:String ) { }
public function endDocument() { }

};

 

각 Flickr 사진에 대해 DefaultHandler사진 개체를 인스턴스화하고 속성 값을 Flicker 사진의 해당 속성 값으로 설정합니다.

DefaultHandler는 그 다음 각 Photo 개체를 photos라는 시퀀스에 추가합니다.

학습 곡선 일지 3편: JavaFX 스크립트 함수에서 시퀀스는 동일한 유형을 갖는 개체의 순서별 목록을 나타냈습니다.

search 함수는 그 다음 callback을 호출하는 다른 스레드를 시작합니다.

 SwingUtilities.invokeLater(Runnable {
          public function run():Void {

              if(callback != null) {
                  callback(photos);
              }
          }
  }
 

SwingUtilities.invokeLater 메소드는 스레드의 Runnable 작업을 이벤트 디스패치 스레드에 놓습니다.


Callback 함수

ImageSearcher 클래스는 속성 유형이 함수인 callback이라는 속성을 갖습니다. 함수는 photos 시퀀스를 매개 변수로

받고 아무 것도 반환하지 않습니다.

   public attribute callback: function(photos:Photo[]):Void;

ImageSearcher 클래스가 인스턴스화되면(애플리케이션의 주요 부분에 발생) callback 함수는 UI의 Matched Images

영역에 표시하기 위해 제목의 목록을 구축합니다. 목록의 각 항목은 속성 값이 반환된 사진의 제목인 text 속성과

속성 값이 Photo 개체인 value 속성을 갖습니다. 다음 코드는 애플리케이션의 주요 부분 내에서

 ImageSearcher 클래스를 인스턴스화하고 callback 함수를 제공합니다. 

  var searcher = ImageSearcher {
       callback: function(photos:Photo[]):Void {
          thumbnailList.items = for(photo in photos) {
              ListItem {
                  text: photo.title
                  value: photo
              }
          };
           matchedImagePB.Indeterminate= false;
      }
  };

매칭되는 사진 목록을 구축한 후 callback 함수는 Matched Images 진행 표시줄의 indeterminate 등록 정보를

기본값인 false로 다시 설정합니다.


이미지 검색 수행

이미지 검색을 다루는 코드를 검토했으니 이제 작업을 살펴봅시다. 그림 2는 사용자가 검색어를 입력한 후 Search 필드와

Matched Images 진행 표시줄의 상태를 보여줍니다.


그림 2.
검색어 입력

애플리케이션이 매칭되는 이미지를 검색하는 동안 검색어를 기반으로 검색 중임을 나타내는 메시지가 나타납니다.

이 예제에서는 "searching... polar bear" 메시지가 나타납니다.

그림 3은 매칭되는 이미지의 반환된 제목 목록 일부를 보여줍니다.


그림 3. 이미지 검색 결과
검색 함수가 올바르게 작동합니다!
 
이미지 표시

구현할 다음 동작은 이미지 표시입니다.

사용자가 반환된 이미지 제목 목록에서 제목을 선택하면 애플리케이션은 해당 이미지를 Flickr 사이트에서 가져와

UI의 Selected Image 영역에 표시해야 합니다.

표시를 위해 이미지를 가져오도록 onChange 위임을 추가하는 List 클래스의 사용자 정의 하위 클래스인

PhotoList라는 클래스를 추가했습니다. 다음은 Main.fx 파일에서 PhotoList 가 인스턴스화되는 방법을 보여줍니다.


   class PhotoList extends List {
       public
attribute onChange:function(photo:Photo);
       public
attribute selectedPhoto:ListItem = bind selectedItem on replace {
           var
photo = selectedPhoto.value as Photo;
           if
(onChange != null) {
               onChange(
photo);
           
}
       
}
   
}
 
   var
thumbnailList = PhotoList {
       preferredSize:[
300, 230]
       hmax:
Layout.UNLIMITED_SIZE
       vmax
: Layout.UNLIMITED_SIZE
   
};


사용자가 목록에서 항목을 선택하면 애플리케이션은 PhotoList 개체의 selectedPhoto 속성을 선택된 항목으로 설정합니다.

이는 PhotoList 개체의 selectedPhoto 속성이 다음 표현식의 결과에 바인딩되었기 때문입니다. 

  selectedItem on replace {
      var photo = selectedPhoto.value as Photo;
  }
 

바인딩은 표현식의 결과를 변수와 연관시키는 것을 의미합니다. 표현식이 변경되면(이 경우 selectedItem가 변경됨) 변수 값은

변경됩니다(이 경우 PhotoListselectedPhoto 속성이 자동으로 업데이트됨).

바인딩은 JavaFX 스크립트의 또 다른 강력한 기능입니다. 바인딩을 사용하여 애플리케이션의 부분을 직접적이고

우아하게 동기화할 수 있습니다.

또한 사용자가 목록에서 항목을 선택하면 애플리케이션은 PhotoList 개체의 onChange 속성과 연관된 이미지 로더 함수를 호출합니다.

이 함수는 선택된 진행 표시줄의 indeterminate 등록 정보를 true로 설정하여 이미지를 가져오는 동안 계속 진행되도록 합니다.

그 다음 선택된 Photo 개체에서 해당 이미지를 가져오기 위해 loadFullImage 함수를 호출합니다.

 class PhotoList extends List {
      public attribute onChange:function(photo:Photo);
      ...
          if(onChange != null) {
              onChange(photo);
       }

  // configure the image loader
  var imageLoader = function(photo:Photo):Void {
      if(photo != null) {
          selectedImagePB.indeterminate = true;
          photo.loadFullImage(function():Void{
              selectedImageDisplay.icon = Icon { image: photo.fullImage };
              selectedImagePB.indeterminate = false;
          });
      }
  };

thumbnailList.onChange = imageLoader;
 

이미지 로더는 Selected Image 영역에 표시하기 위해 이미지를 설정하고 이미지를 가져온 후

선택된 진행 표시줄의 indeterminate 등록 정보를 다시 false로 설정합니다. 

  selectedImageDisplay.icon = Icon { image: photo.fullImage };
  selectedImagePB.indeterminate = false;
 


Photo 클래스

Photo 클래스를 살펴봅시다.

 

    package javafxscriptimgsearch2;

import javafx.scene.image.*;
import java.lang.*;
import javax.swing.SwingUtilities;
import javax.imageio.ImageIO;

public class Photo {
public attribute id:String;
public attribute server:String;
public attribute farm:String;
public attribute title:String;
public attribute secret:String;

private attribute image:Image = null;

public attribute fullImage:Image = null;

public attribute fullImageURL = bind "http://static.flickr.com/{server}/{id}_{secret}.jpg";

public function loadFullImage(
callback:function():Void
):Void {

if(image == null) {
var thread = new Thread(Runnable {
public function run():Void {
var strImageUrl = "http://static.flickr.com/{server}/{id}_{secret}.jpg";
System.out.println("loading: {strImageUrl}");
var buffImg = ImageIO.read(new java.net.URL(strImageUrl));

SwingUtilities.invokeLater(Runnable {
public function run():Void {
image = Image.fromBufferedImage(buffImg);
fullImage = image;
if(callback != null) {
callback();
}
}
});

}});
thread.start();
} else {
callback();
}

}
}
 

Photo 클래스는 Flickr에 저장된 사진과 연관시키는 XML 속성에 해당하는 몇 가지 속성을 갖습니다.

예를 들어 Photo 클래스의 id 속성은 Flickr에 저장된 사진의 id 속성에 해당합니다. 또한 클래스는 Flickr에서 사진을 가져오는

loadFullImage 함수도 제공합니다.

새 스레드를 시작하여 loadFullImage 함수가 시작됩니다.

스레드 내에서 함수는 특정 사진에 대해 사진 소스 URL을 구성한 다음 사진을 가져옵니다.

다음은 사진 소스 URL을 구성하고 사진을 가져오는 코드입니다

   var strImageUrl = http://static.flickr.com/{server}/{id}_{secret}.jpg
   var buffImg = ImageIO.read(new java.net.URL(strImageUrl));

loadFullImage 함수가 URL 구성을 위해 Photo 개체의 server, idsecret 속성을 사용하는 것에 유의합니다.

또한 이미지 로드를 위해 자바 imagio 패키지의 ImageIO.read 메소드를 사용했습니다.

함수는 JavaFX 스크립트 Image 클래스의 fromBufferedImage 메소드를 사용하여 가져온 사진을 Photo 개체의

image 속성에 지정합니다. 그런 다음 호출자(이 경우 애플리케이션의 주요 부분에 있는 이미지 로더)에게의 callback

호출하는 다른 스레드를 시작합니다.

   SwingUtilities.invokeLater(Runnable {
       public function run():Void {
           image = Image.fromBufferedImage(buffImg);
           fullImage = image;
           if(callback != null) {
               callback();
           }
       }
   }); 

SwingUtilities.invokeLater 메소드는 스레드의 Runnable 작업을 이벤트 디스패치 스레드에 놓습니다.


목록에 이미지 표시

애플리케이션의 이미지 표시 부분을 테스트해봅시다. 그림 4는 Matched Images 영역에서 이미지를 선택한 후

Selected Image 진행 표시줄의 상태를 보여줍니다.


그림 4. 표시할 이미지 선택

애플리케이션이 이미지를 가져오면 이미지의 사진 소스 URL을 식별하는 메시지를 표시합니다.

이 예제에서는 "loading: http://static.flickr.com/3234/2595583764_a2e6661d3a.jpg" 메시지가 나타납니다.

이미지 가져오기가 끝나면 애플리케이션은 "loaded" 메시지를 표시합니다.

그림 5는 UI의 Selected Image에 선택한 이미지가 표시된 완전한 UI를 보여줍니다.


그림 5. 표시된 이미지

애플리케이션의 이미지 가져오기 부분이 작동합니다. 애플리케이션도 의도대로 작동합니다.

완성된 JavaFX 스크립트 애플리케이션을 위해 NetBeans 프로젝트 다운로드를 받을 수 있습니다.

 

요약

이 학습 곡선 일지 시리즈에서는 JavaFX 스크립트 프로그래밍 언어

(이 시리즈에서는 JavaFX 스크립트라고 줄여서 부름)의 사용을 시작하는데 도움이 되는 몇 가지 기본 개념 및 기법을 소개했습니다.

 

시리즈의 1편에서는 간단한 JavaFX 애플리케이션을 만드는 방법을 소개했습니다.

2편에서는 풍부한 UI 생성을 위해 사용 가능한 JavaFX 라이브러리 내의 일부 클래스와 언어의 선택적 구문을 설명했습니다.

UI 구축에는 계층 구조적인 Swing 기반 접근 방법을 따랐습니다.

이 시리즈의 1편에서 언급한 것처럼 앞으로 JavaFX 개발자는 노드 기반 접근 방법을 사용할 것입니다.

노드 기반 접근 방법에서는 UI 구축을 위해 다른 JavaFX 라이브러리를 사용할 것입니다.

3편에서는 뷰와 데이터 모델 등의 애플리케이션 부분을 동기화하기 위해 사용 가능한 JavaFX 스크립트의 바인딩 기능과

JavaFX 스크립트 함수를 다뤘습니다.

4편(본 기사)에서는 웹 서비스 액세스를 위한 JavaFX 스크립트 사용 방법을 보여주었습니다.

그 과정 중에 FX 스크립트에서 Swing 클래스와 같은 자바 기술 슬래스의 액세스가 얼마나 쉬운지도 보여주었습니다.

또한 이 시리즈를 통해 코드 완성과 같은 기능이 어떻게 NetBeans IDE 6.1에서 JavaFX 애플리케이션의 빌드 및 실행을

단순화하는지도 볼 수 있었습니다. JavaFX Preview SDK를 사용하여 명령줄에서 JavaFX 애플리케이션을

빌드 및 실행할 수도 있습니다.JavaFX 포함 NetBeans IDE 6.1을 다운로드하여 설치하거나

JavaFX Preview SDK를 다운로드하여 JavaFX 스크립트를 시작하십시오.


자세한 정보
이 글의 영문 원본은 Learning Curve Journal, Part 4: Accessing a Web Service에서 보실 수 있습니다.
 
2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어
(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자
"학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다.
아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을
사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다.

업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

지난 학습 곡선 기사에서는 간단한 사용자 인터페이스(UI)를 구현하고 UI 시험이 성공적이었음을 확인했습니다.

결과 JavaFX 스크립트는 Flickr에서 이미지를 검색하는 이미지 검색 애플리케이션 구축을 위한

원래 자바 프로그래밍 언어 UI와 비슷하게 보였습니다. 그림 1은 결과적인 기본 프레임을 보여줍니다.

 


그림 1. 원래 UI를 복제한 JavaFX 이미지 검색 애플리케이션

선언적 JavaFX 스크립트 구문을 사용한 결과 코드는 자바 언어 UI의 이식을 위한 괜찮은 시작이었습니다.

그러나 유휴 상태의 프레임, 응답하지 않는 검색 필드, 비활성 진행 표시줄, 빈 목록 상자 및

빈 이미지 레이블에 대한 추가 작업이 필요합니다. 여기에서는 아무 일도 발생하지 않습니다.

현재까지는 활성 데이터모델에 아무 UI 요소도 연결되지 않았으며 사용자 상호작용에도 응답하지 않습니다.

예를 들어 Search 텍스트 필드는 입력한 문자를 받아서 보여주지만 아직 아무 것도 하지 않습니다.

이 골격 뿐인 UI에는 추가 작업이 필요합니다. 이를 위해 비활성 애플리케이션에서 필요한 작업을 수행하도록 하는 함수가 필요합니다.


함수

JavaFX 스크립트 함수는 자바 프로그래밍 언어 메소드와 비슷합니다.

이들 메소드와 마찬가지로 함수는 매개 변수와 반환 값을 갖습니다.

또한 속성 및 변수와 if-then, while 루프, for 루프 및 기타 조건문도 가질 수 있습니다. 다음은 몇 가지 유효한 함수의 예입니다. 

function z(a,b) {
      var x = a + b;
      var y = a - b;
      return sq(x) / sq (y);
 }

 function sq(n) {return n * n; }

 function main() {
      return z(5, 10);
  }

  function min(x1 : Number, x2 : Number ): Number {
      if (x1 < x2) {
        return x1;
      }else {
        return x2;
     }
 }



반환 값 유형이나 매개 변수 유형을 선언할 필요가 없습니다.

그러나 자바 언어 프로그래머인 저에게는 min 함수에서와 같이 유형을 사용하는 것이 익숙하므로

가능한 경우에는 항상 사용하곤 합니다. 매개 변수 유형을 선언하는 것은 명확성에 도움이 됩니다.

따라서 z 함수를 다음과 같이 다시 작성하겠습니다.


 

function z(a: Number, b: Number): Number {
   var x: Number = a + b;
   var y: Number = a - b;
   return sq(x) / sq (y);
}

return 키워드는 선택 사항입니다.

 function sq(n) {n*n;}

 

위 함수는 다음과 같습니다.

 function sq(n) {return n*n;}
함수는 function 키워드로 시작합니다. 그 뒤에는 함수 이름과 매개 변수 목록이 나옵니다. 

JavaFX 스크립트에서는 유형이 변수나 함수 이름 다음에 나옵니다.

예를 들면 b: Number 매개변수는 b 라는 인수의 유형이 Number라는 의미입니다.

마지막으로 함수는 Number를 반환하므로 이를 매개 변수 목록 뒤에 선언할 수 있습니다.

함수의 본문 앞뒤에는 자바 언어에서 메소드 본문을 둘러싸는 것과 같이 괄호가 있습니다.

함수는 매개 변수나 기타 참조 변수가 변경될 때마다 반환 값을 재평가합니다.

이 기능은 개체를 자주 변경될 수 있는 특정 값에 바인드하려는 경우 유용합니다.

바인딩에 대해서는 나중에 자세히 설명하겠습니다.

클래스에 대해 함수가 정의될 수도 있습니다. 다음은 Friends 클래스에 대해 정의된 함수의 예입니다.

import java.lang.System;
  import javafx.lang.Sequences;

  class Friends {
      attribute knownNames: String[];
      function sayHello(name: String): String {
          var index = Sequences.indexOf(knownNames,name);
          if (index >= 0) {
              return "Hello, {name}!";
              } else {
              return "Sorry, I can't talk to strangers.";
              }
      }
  }

  var buddies = Friends {
      knownNames: ["John", "Robyn", "Jack", "Nick", "Matthew",
      "Tressa", "Ruby"]
  };

  var greeting = buddies.sayHello("John");
  System.out.println(greeting);

이 작은 프로그램은 sayHello 메소드에 아는 이름을 입력하면 "Hello"라고 응답합니다.

그렇지 않은 경우엔 "can't talk to strangers"라고 합니다.

Friends 클래스에는 한 가지 속성과 속성을 사용하여 메시지를 반환하는 함수가 포함되어 있습니다.

Sequences 클래스를 사용하는 것에 유의합니다. 이 클래스는 시퀀스 조작을 위한 다양한 함수를 포함합니다.

시퀀스는 이 예제에서 아는 이름의 목록과 같이 개체의 순서별 목록을 나타냅니다.

SequencesindexOf 함수는 지정된 시퀀스에서 같은 값을 갖는 개체를 검색합니다.

여기에서 indexOf는 아는 이름 시퀀스에서 지정된 이름(이 예제에서는 "John")과 매칭되는 개체를 검색합니다.


반응적 UI 요소

UI 요소(JavaFX 스크립트 라이브러리에서는 노드)는 키 입력이나 마우스 클릭과 같은 사용자 상호작용에 응답할 수 있습니다.

위젯은 action, onMouseClicked, onKeyTyped 및 기타 이벤트 기반 속성을 갖습니다. 이들 속성과 함수를 연관시킬 수 있습니다.

예를 들어 함수를 TextFieldaction 속성과 연관시키면 해당 함수는 필드 내에서 Enter를 누를 때 실행됩니다.

Button 위젯의 동일한 action 속성은 사용자가 클릭할 때마다 활성화됩니다.

JavaFX 이미지 검색 애플리케이션과 관련된 함수가 필요하므로 UI 요소에 대한 이벤트 핸들러를 작성하기로 했습니다.

다음 애플리케이션은 두 개의 버튼과 하나의 레이블을 생성합니다.

Bigger 버튼을 누르면 레이블의 글꼴 크기가 증가하고 텍스트가 변경됩니다.

Smaller 버튼을 누르면 레이블의 글꼴 크기가 감소하고 텍스트가 변경됩니다.

이 애플리케이션에서는 계층 구조적인 Swing 기반 접근 방법을 따릅니다.

이 시리즈의 1편에서 언급한 것처럼 앞으로는 JavaFX 스크립트 개발자가 노드 기반 접근 방법을 사용하도록 할 것입니다.

 

 import javafx.ext.swing.SwingFrame;
  import javafx.ext.swing.BorderPanel;
  import javafx.ext.swing.FlowPanel;
  import javafx.ext.swing.Button;
  import javafx.scene.Font;
  import javafx.scene.HorizontalAlignment;
  import javafx.ext.swing.Label;

  var font = Font { size: 18 };

  class FontDataModel {
      attribute text: String;

      function increaseFontSize() {
         font = Font { size: font.size + 1 };
         text= "Font Test ({font.size})";
         }
      function decreaseFontSize() {
         font = Font { size: font.size - 1 };
         text= "Font Test ({font.size})";
      }
  }

  SwingFrame {
       var myFont = FontDataModel {
           text: "Font Test (18)"
        }

      content:
      BorderPanel {
          top: FlowPanel {
              alignment: HorizontalAlignment.LEADING
              content: [
                  Button { text:"Bigger"
                      action :
                      function() {
                           myFont.increaseFontSize();
                      }
              },

              Button { text:"Smaller"
                  action : function() {
                      myFont.decreaseFontSize();
                  }
              }

              ]
          }
          center:
              Label {
                  width: 200
                  font: bind font
                  text: bind myFont.text

          }

       }
       visible: true
  }

 

 

 이 코드를 잘라내어 JavaFX 애플리케이션에 바로 붙여넣을 수 있습니다. Preview 버튼을 사용하면 그림 2의 결과가 보입니다.


그림 2. 미리보기 기능을 사용하여 JavaFX 스크립트 언어를 대화형으로 시험

이 Bigger-Smaller 글꼴 애플리케이션은 텍스트 문자열 속성을 갖는 FontDataModel을 생성합니다.

애플리케이션은 FontDataModel 인스턴스를 생성하고 text 속성을 초기화합니다.

FontDataModel에도 increaseFontSizedecreaseFontSize라는 두 가지 함수가 있습니다.

이들 함수는 텍스트 속성을 변경하고 Font 클래스의 인스턴스를 생성하며 인스턴스의 글꼴 크기를 업데이트합니다.

왜 글꼴을 FontDataModel의 속성으로 지정하고 텍스트 속성과 같은 방법으로 함수에서 업데이트하지 않는지 궁금할 지도 모릅니다.

이러한 접근 방법은 Font가 변경할 수 없는 개체, 즉 원래 개체의 속성을 변경할 수 없기 때문에 사용할 수 없습니다.

개체의 인스턴스에서만 속성을 변경할 수 있습니다.

각 버튼은 연관된 함수를 포함하는 action 속성을 갖습니다.

예를 들어 Bigger 레이블이 있는 버튼은 myFont 변수의 increaseFontSize 함수를 호출합니다.

 Button { text:"Bigger"

       action :
      function() {
           myFont.increaseFontSize();
      }
   
}
 

버튼을 누를 때마다 글꼴 크기와 텍스트가 변경되는 것을 볼 수 있습니다.

그림 3은 Bigger 버튼을 두 번 눌렀을 때의 결과를 보여줍니다.


그림 3. 버튼을 클릭하면 텍스트와 글꼴 크기 변경

분명히 increaseFontSize 메소드는 글꼴과 텍스트를 변경합니다. 이를 위해 바인딩이라는 JavaFX 스크립트 기능을 사용했습니다.


뷰와 모델 바인딩
 

JavaFX 스크립트에는 하나의 속성이 다른 속성의 변경을 추적하도록 하는 bind 연산자가 있습니다.

하나의 속성을 다른 속성에 바인딩한다는 것은 바인딩된 속성이 대상 속성의 변경 사항을 항상 인지한다는 것을 의미합니다.

이 Bigger-Smaller 글꼴 애플리케이션에서는 Label이 글꼴과 텍스트의 변경 사항을 추적하도록 하려고 합니다.

이를 위해 Labelfont 속성을 Font 변수에 바인드하도록 bind 연산자를 사용했습니다.

또한 Labeltext 속성을 FontDataModeltext 속성에 바인드하도록 bind 연산자를 사용했습니다.

다음은 Label 선언입니다.

  Label {
      width: 200
      font: bind font
      text: bind myFont.text

  }
 

bind 연산자는 함수에도 사용할 수 있습니다. 함수는 인수나 참조 변수가 변경될 때마다 결과를 업데이트하므로

함수에의 바인딩은 단일 속성에의 바인딩과 마찬가지로 작용합니다.

사실 함수는 실제로 바인딩과 함께 사용하도록 설계되었습니다.

본문 내의 매개 변수 및 참조 변수를 모두 포함하는 모든 종속성을 자동으로 추적하는

재사용 가능한 하위 루틴으로의 바인딩을 리팩터링하기 위해 이들을 사용할 수 있습니다.

표 1에서 코드의 일부를 참조하십시오.

 

표1. 함수와 함께/함수 없이 바인드 사용
 함수 없이 바인드  함수와 함께 바인드
 import java.lang.System;

   class Data {

       attribute foo: Number;
       attribute baz: Number;
   }

   var data = Data {
       foo: 4
       baz: 7
   };

   var zoo = bind data.foo +
           data.baz + 10;
   System.out.println(zoo);
   data.baz = 12;
   System.out.println(zoo);
 import java.lang.System;

   class Data {
       attribute foo: Number;
       attribute baz: Number;
       function add(x, y, z): Number {
           return x+y+z;
       }
   }

   var data = Data {
       foo: 4
       baz: 7
   };

   var zoo = bind data.add(data.foo, data.baz, 10);
   System.out.println(zoo);
   data.baz = 12;
   System.out.println(zoo);
 출력:  출력:
21.0
26.0
21.0
26.0
 
요약

JavaFX 애플리케이션에 동작을 추가하기 위해 함수를 사용합니다. UI 구성요소의 속성은 함수에 매핑됩니다.

action, onMouseClickedonKeyTyped와 같은 UI 이벤트 처리를 위해 이들 함수를 정의할 수 있습니다.

함수에는 함수 본문 내에서 매개 변수 및 참조 변수를 재평가하는 추가적인 등록 정보가 있습니다.

bind 연산자를 사용하여 하나의 속성을 다른 속성에 연결할 수 있습니다.

이는 UI 위젯이 모델 속성을 추적하도록 할 때 특히 유용합니다.

뷰 속성을 모델 속성에 바인딩한다는 것은 모델과 뷰가 동일한 데이터로 항상 동기화됨을 의미합니다.

JavaFX 이미지 검색 애플리케이션의 UI에 아직 기능을 추가하지 않았지만 함수가 필요하다는 것을 알게 되었습니다.

검색 텍스트를 가져오기 위해서는 거의 확실히 함수를 사용해야 합니다.

같은 함수가 이미지를 가져오기 위해 Flickr 사이트에도 액세스할 것입니다.

또한 뷰를 기본 모델에 연결하기 위해 bind 연산자도 사용해야 할 것입니다.

이제 UI를 일부 기본 작업 및 함수에 연결하는 방법을 알게 되었습니다.

또한 UI를 기본 모델에 연결하기 위해 bind 연산자도 사용할 수 있습니다.

 

자세한 정보
이 글의 영문 원본은 Learning Curve Journal, Part 3: JavaFX Script Functions에서 보실 수 있습니다.
 
2007 년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어
(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자
"학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다.
아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을
사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다.

업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다.
최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

사용자 인터페이스를 정의하기 위해 10년 가까이 자바 프로그래밍 언어를 사용해온 저는

JavaFX 스크립트를 처음 사용해보고 두 가지 환경 사이의 큰 차이점을 금방 느낄 수 있었습니다.

프로그래머는 자바 언어에서 사용자 인터페이스(UI) 정의를 위해 절차적 언어를 사용하지만

JavaFX Script에서는 UI 정의에 선언적 문을 사용할 수 있습니다.

이는 커다란 차이이며 여기에 적응하는 데는 약간의 시간과 노력이 필요할 수 있습니다.

UI 생성을 위한 새로운 선언적 스타일에 대해 알아보고자

기존 애플리케이션 UI를 자바 언어 구현에서 JavaFX 스크립트로 이식하기로 했습니다.

썬 개발자 네트워크자바 언어 허브에 있는 Swingworker 기사에서 만든 이미지 뷰어 애플리케이션을 선택했습니다.

 

원래 애플리케이션은 Java SE 6에서 SwingWorker 클래스의 사용 방법을 보여주기 위한 것이었지만

UI 자체는 JavaFX 스크립트로의 간편한 이전을 제공할 만큼 충분히 단순해 보입니다.


기존 사용자 인터페이스

기존 애플리케이션에서는 사용자가 유명한 Flickr 웹 사이트에서 이미지를 검색, 나열 및 표시할 수 있도록 했습니다.

사용자는 검색어를 입력할 수 있으며 애플리케이션은 REST API를 사용하여 매칭되는 축소판 이미지 목록을 Flickr에 쿼리합니다.

사용자는 축소판 이미지를 하나 선택하여 크고 상세한 이미지를 가져올 수 있습니다.

그림 1은 검색 결과가 나온 기존 애플리케이션을 보여줍니다.

 

그림 1. 검색 결과가 나온 애플리케이션 UI

이 UI는 위에서부터 아래로 다음 구성요소로 이루어져 있습니다.

  • 기본 프레임 창 컨테이너 
  • 검색 레이블 및 검색 텍스트 필드 
  • 검색 매칭 레이블 및 진행 표시줄
  • 매칭되는 축소판 이미지 목록과 짧은 설명 
  • 선택 레이블 및 진행 표시줄
  • 선택한 이미지를 보여주는 레이블 
     

UI는 JFrame, JLabel, JProgressBar, JScrollPaneJList.와 같은 일반 Swing 구성요소로 이루어집니다.

JList 구성요소는 축소판 이미지와 제공되는 짧은 설명을 표시하기 위한 사용자 정의 렌더러를 갖지만 여전히 상대적으로 간단한 UI로서

JavaFX 스크립트의 선언적 UI 측면을 조사하는 데 도움이 될 것입니다.

전체 애플리케이션의 구현을 시도해 보겠지만 현재로는 기존 UI와 적당히 비슷한 정도로도 충분합니다.

작동하는 데모처럼 극적이진 않겠지만 그림 2에 나온 비활성 UI는 JavaFX 스크립트의 선언적 UI에 대한 초기 목표를 보여줍니다.

 

그림 2. 애플리케이션 UI

원래 UI는 NetBeans IDE 6.1과 Matisse GUI 편집기를 사용하여 구현했습니다.

Swingworker 기사에서 모든 원래 코드 및 생성된 UI 주변의 코드를 다운로드 받을 수 있습니다.

코드에서 이 UI를 생성하기 위해 NetBeans IDE가 GroupLayout를 어떻게 사용했는지 볼 수 있습니다.

 

private void initComponents() {
    lblSearch = new javax.swing.JLabel();
    txtSearch = new javax.swing.JTextField();
    lblImageList = new javax.swing.JLabel();
    scrollImageList = new javax.swing.JScrollPane();
    listImages = new JList(listModel);
    lblSelectedImage = new javax.swing.JLabel();
    lblImage = new javax.swing.JLabel();
    progressMatchedImages = new javax.swing.JProgressBar();
    progressSelectedImage = new javax.swing.JProgressBar();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setTitle("Image Search");
    lblSearch.setText("Search");
    lblImageList.setText("Matched Images");

    // ...
    // event listeners, models, and cell renderers removed for this example
    //

    lblSelectedImage.setText("Selected Image");

    lblImage.setBorder(javax.swing.BorderFactory.createLineBorder(
            new java.awt.Color(204, 204, 204)));
    lblImage.setFocusable(false);
    lblImage.setMaximumSize(new java.awt.Dimension(500, 500));
    lblImage.setMinimumSize(new java.awt.Dimension(250, 250));
    lblImage.setOpaque(true);
    lblImage.setPreferredSize(new java.awt.Dimension(500, 250));

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                .addComponent(lblImage, javax.swing.GroupLayout.Alignment.LEADING,
                        javax.swing.GroupLayout.DEFAULT_SIZE, 462, Short.MAX_VALUE)
                .addComponent(scrollImageList, javax.swing.GroupLayout.DEFAULT_SIZE,
                        462, Short.MAX_VALUE)
                .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(lblImageList)
                        .addComponent(lblSelectedImage))
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addComponent(progressMatchedImages, javax.swing.GroupLayout.DEFAULT_SIZE,
                                350, Short.MAX_VALUE)
                        .addComponent(progressSelectedImage, javax.swing.GroupLayout.DEFAULT_SIZE,
                                350, Short.MAX_VALUE)))
                .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                    .addComponent(lblSearch)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(txtSearch, javax.swing.GroupLayout.DEFAULT_SIZE,
                            411, Short.MAX_VALUE)))
            .addContainerGap())
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(lblSearch)
                .addComponent(txtSearch, javax.swing.GroupLayout.PREFERRED_SIZE,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(lblImageList)
                .addComponent(progressMatchedImages, javax.swing.GroupLayout.PREFERRED_SIZE,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(scrollImageList, javax.swing.GroupLayout.PREFERRED_SIZE, 235,
                    javax.swing.GroupLayout.PREFERRED_SIZE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(lblSelectedImage)
                .addComponent(progressSelectedImage, javax.swing.GroupLayout.PREFERRED_SIZE,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(lblImage, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE)
            .addContainerGap())
    );
    pack();
} 

 

 

NetBeans IDE를 사용한 UI 레이아웃은 쉽습니다. 드래그 앤 드롭이면 충분합니다.
이 예제에서 NetBeans IDE 6.1은 여러 가지 호스트 플랫폼에서 정확한 크기, 위치 및 구성요소의 간격을 제공하는 javax.swing.GroupLayout을 사용하여 UI 코드를 생성했습니다.
결과 코드는 그다지 읽기 쉽진 않지만 도구 지원이 뛰어나 레이아웃 코드를 직접 수동으로 작업할 필요가 없습니다.

 
선언적 JavaFX 스크립트 인터페이스

JavaFX 스크립트용의 설계 도구가 개발 중이지만 아직은 사용할 수 없습니다.
그러나 JavaFX 스크립트 플러그인이 포함된 NetBeans IDE 6.1의 미리보기 기능을 사용하면
수동으로 UI 코드를 입력하고 결과를 즉시 볼 수 있습니다.

이 인터페이스에 필요한 UI 구성요소는 javafx.ext.swing 패키지 및 javafx.scene으로 시작하는

다양한 패키지에 들어 있습니다. UI 구축은 계층 구조적인 Swing 기반 접근 방법을 따릅니다.

이 시리즈의 1편에서 언급한 것처럼 앞으로 JavaFX 개발자는 노드 기반 접근 방법을 사용할 것입니다.

노드 기반 접근 방법으로 UI를 구축하면 javafx.application 클래스의 일부 클래스가 필요할 것입니다.

JavaFX 스크립트는 패키지 구조 및 가져오기 문을 지원한다는 점에서 자바 언어와 유사합니다.

구성요소에 대해 공부하는 동안은 전체 패키지를 가져오는 대신 한 번에 하나씩 특정 구성요소를 가져오겠습니다.

이는 매우 지루하지만 하나씩 사용하게 함으로써 패키지에 어떤 구성요소가 있는지 보여줍니다.

 

JavaFX 스크립트 구성요소는 height, width, textcontent와 같은 속성을 갖습니다.

content 속성은 자녀 구성요소를 갖습니다. 구성요소에 따라 content 속성은 array로 선언되는

여러 개의 구성요소를 포함할 수 있습니다. 이미지 검색 애플리케이션을 위해 사용자 인터페이스를 선언할 때는

JavaFX 스크립트 구성요소의 선택 및 사용 후 속성을 설정합니다.

예를 들어 다음의 짧은 스크립트는 빈 프레임을 정의합니다. 이 코드는 컨텐츠가 없는 프레임 컨테이너를 생성합니다.

import javafx.ext.swing.SwingFrame;

  SwingFrame {
      title: "JFX Image Search"
      height: 500
      width: 500
      visible: true
  }
 

Swing의 JFrame에 해당하는 JavaFX 스크립트는 javafx.ext.swing.SwingFrame입니다.

title 속성은 프레임에 나타나는 텍스트인 창 프레임 제목을 선언합니다.

heightwidth 속성은 픽셀 단위로 크기 규격을 정의합니다.

마지막으로 visible 속성은 Swing의 JFrame 클래스 setVisible 메소드와 유사하게 프레임의 가시성 여부를 선언합니다.


Border Panel 및 Flow Panel
 

javafx.ext.swing 패키지에는 SwingFrame, Label, BorderPanel, FlowPanelList와 같은 구성요소가 포함됩니다.

이러한 이름은 일반적인 Swing 구성요소 같으므로 대상 UI 구현에 이들을 먼저 사용해보겠습니다.

javafx.scene 패키지의 HorizontalAlignment 구성요소와 javafx.scene.paint 패키지의 Color 구성요소도 사용했습니다.

그러나 JavaFX 스크립트 패키지에 ProgressBar 구성요소는 아직 없습니다.

따라서 진행 표시줄을 생성하는 함수를 코딩했습니다. 이 시리즈의 3편에서는 JavaFX 스크립트 함수를 검토합니다.

BorderPanelFlowPanel 등의 구성요소와 진행 표시줄의 함수를 사용하기로 결정하고 다음

JavaFXImageSearchUI1.fx 코드를 생성했습니다.

 

package com.sun.demo.jfx;

  import javafx.ext.swing.SwingFrame;
  import javafx.ext.swing.BorderPanel;
  import javafx.ext.swing.FlowPanel;
  import javafx.ext.swing.Label;
  import javafx.ext.swing.TextField;
  import javafx.ext.swing.List;
  import javafx.ext.swing.Component;
  import javafx.scene.paint.Color;
  import javafx.scene.HorizontalAlignment;
  import java.awt.Dimension;

  function createProgressBar(preferredSize:Integer[]) :Component {
      var jprogressbar = new javax.swing.JProgressBar();
      var comp = Component.fromJComponent(jprogressbar);
      comp.preferredSize = preferredSize;
      comp;
  }

  SwingFrame {
      title: "JFX Image Search"
      content: BorderPanel  {

          top: FlowPanel {
              alignment: HorizontalAlignment.LEFT
              content: [
              Label {
                  text: "Search"
                  },
              TextField {
                  columns: 50
              }
              ]
          }
          center: BorderPanel {
              top: FlowPanel {
                  alignment: HorizontalAlignment.LEFT
                  content: [
                  Label {
                      text: "Matched Images"

                      },
                  createProgressBar([360, 20])
                  ]
              }
              center: List {
                  preferredSize: [100, 200]
              }
              bottom: FlowPanel {
                  alignment: HorizontalAlignment.LEFT
                  content: [
                  Label {
                      text: "Selected Image"
                      },
                  createProgressBar([365, 20])
                  ]
              }
          }
          bottom: Label {
                  preferredSize: [400, 300]

          }

      }
      visible: true
  }

 

NetBeans IDE 6.1에 프로젝트를 생성한 후에 JFXImageSearchUI1.fx 파일에 위의 코드를 입력했습니다. 
미리보기 버튼을 클릭하면 그림 3과 같은 결과가 나타납니다.

그림 3. JavaFX 이미지 검색 UI -- 첫 번째 시도


프레임의 컨텐츠는 BorderPanel 구성요소로, top 속성은 FlowPanel 구성요소에 지정되고
center 속성은 다른 BorderPanel 구성요소에 지정되며 bottom 속성은 Label 구성요소에 지정되었습니다.
FlowPanel 구성요소는 content 등록 정보를 갖습니다. 이 등록 정보에 하나 이상의 구성요소를 넣을 수 있습니다.
여러 개의 구성요소를 삽입할 때는 array를 정의하는 괄호 속에 구성요소를 넣어야 합니다.
다음과 같이 쉼표를 사용하여 컨텐츠 array에서 개별 구성요소를 구분합니다.

content: [
  Label {
     text: "Search"
     },
  TextField {
     columns: 50
  }
  ]
 

상단 FlowPanel에는 Label 구성요소와 TextField 구성요소가 중첩되어 있습니다.

FlowPanel 의 방향 속성은 HorizontalAlignment.LEFT입니다.

이는 FlowPanel 내의 구성요소를 가로와 왼쪽으로 정렬합니다.

가운데의 BorderPanel은 이 영역의 상단에 가로로 정렬된 레이블과 진행 표시줄을, 중앙에 목록을,

하단에 다른 레이블과 진행 표시줄을 레이아웃합니다. 프레임의 하단에는 레이블이 들어갑니다.

FlowPanel 구성요소는 레이블-구성요소 쌍을 만들기에 좋습니다.

여기에서는 여러 개의 FlowPanel을 사용하여 레이블과 TextField 등의 구성요소를 묶었습니다.

createProgressBar 함수는 JavaFX 스크립트를 사용하여 Swing 구성요소로부터

javafx.gui 구성요소를 생성하는 방법을 보여줍니다.

여기에서는 Swing JProgressBar 구성요소로부터 JavaFX 스트립트 진행 표시줄을 생성했습니다.

function createProgressBar(preferredSize:Integer[]) :Component {
          var jprogressbar = new javax.swing.JProgressBar();
          var comp = Component.fromJComponent(jprogressbar);
          comp.preferredSize = preferredSize;
          comp;
  }
 

첫 번째 시도에서 UI는 상당히 잘 작동하지만 원래 UI를 제대로 재현하지는 못합니다. 그래서 다른 접근 방법을 시도해 보겠습니다.


클러스터
 

원래 UI를 복제하려는 두 번째 시도에서는 JavaFX 스크립트 ClusterPanel 구성요소를 활용하겠습니다.

이 구성요소를 사용하여 프레임 내에서 구성요소를 클러스터할 수 있습니다.

JavaFX 스크립트에는 ClusterPanel 내에서 구성요소를 순서대로나

병렬로 정리하기 위해 사용할 수 있는 SequentialClusterParallelCluster도 포함됩니다.

진행 표시줄, 검색 텍스트 필드, 축소판 이미지 목록 및 선택된 이미지 표시 영역의 최대 너비 및 높이를 설정하기 위해

JavaFX 스크립트 Layout 구성요소도 활용하기로 결정했습니다.

Layout 구성요소는 UNLIMITED_SIZE 등의 레이아웃 관련 상수를 제공합니다.

UI의 두 번째 버전은 다음 JFXImageSearchUI.fx 파일에 코딩되었습니다.


   package com.sun.demo.jfx;

import javafx.ext.swing.Component;
import javafx.ext.swing.SwingFrame;
import javafx.ext.swing.Label;
import javafx.ext.swing.TextField;
import javafx.ext.swing.List;
import javafx.ext.swing.Cluster;
import javafx.ext.swing.Layout;
import javafx.ext.swing.ClusterPanel;
import javafx.ext.swing.SequentialCluster;
import javafx.ext.swing.ParallelCluster;
import javafx.scene.paint.Color;
import java.awt.Dimension;
import java.lang.System;

import javax.swing.border.LineBorder;

function createProgressBar() :Component {
var jprogressbar = new javax.swing.JProgressBar();
var comp = Component.fromJComponent(jprogressbar);
comp.hmax = Layout.UNLIMITED_SIZE;
comp;
}

var searchLabel = Label {
text: "Search:"

}
var searchTextField = TextField {
hmax: Layout.UNLIMITED_SIZE
columns: 50
}

var matchedImageLabel = Label {
text: "Matched Images"
}
var matchedImagePB = createProgressBar();


var thumbnailList = List {
preferredSize:[300, 230]
hmax: Layout.UNLIMITED_SIZE
vmax: Layout.UNLIMITED_SIZE
}

var selectedImageLabel = Label {
text: "Selected Image"
}
var selectedImagePB = createProgressBar();

var selectedImageDisplay = Label {
preferredSize: [400,300]
hmax: Layout.UNLIMITED_SIZE
vmax: Layout.UNLIMITED_SIZE
}

selectedImageDisplay.getJComponent().setOpaque(true);
selectedImageDisplay.getJComponent().setBackground(Color.WHITE.getAWTColor());
selectedImageDisplay.getJComponent().setBorder(new LineBorder(Color.BLACK.getAWTColor(), 1, true));

SwingFrame {
title: "JavaFX Image Search"
content:
// main panel within the frame
ClusterPanel {

hcluster: SequentialCluster {
content: [
ParallelCluster{ // mainCol
resizable: true
content: [
SequentialCluster{
content: [
ParallelCluster { //searchLabelCol
content: searchLabel
},
ParallelCluster { //searchTextFieldCol
resizable: true
content: searchTextField
}
]},
SequentialCluster {
content: [
ParallelCluster { //lblCol
content: matchedImageLabel
},
ParallelCluster { //progressBarCol
resizable: true
content: matchedImagePB
}
]},
thumbnailList,
SequentialCluster {
content: [
ParallelCluster { //lblCol
content: selectedImageLabel
},
ParallelCluster { //progressBarCol
resizable: true
content: selectedImagePB
}
]},
selectedImageDisplay
]
}
]

}

vcluster: SequentialCluster {
content: [
ParallelCluster{ //searchRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [searchLabel, searchTextField]
}
]
}
},
ParallelCluster{ // matchedProgressRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [matchedImageLabel, matchedImagePB]
}
]
}
},
ParallelCluster{ // thumbNailRow
resizable:true
content: thumbnailList
},
ParallelCluster{ // selectedProgressRow
content: SequentialCluster {
content: [
ParallelCluster { // row
content: [selectedImageLabel, selectedImagePB]
}
]
}
},
ParallelCluster{ // imageRow
content: selectedImageDisplay
}

]
}

}
visible: true
}


 
이 코드의 결과는 훨씬 보기 좋습니다.
그림 4에 나온 것처럼 구성요소는 이제 프레임의 왼쪽과 오른쪽으로 완벽하게 정렬되었습니다.
 

그림 4. JavaFX 이미지 검색 UI -- 두 번째 시도


 

프레임의 주 컨텐츠는 ClusterPanel 구성요소입니다.
ClusterPanel 내에서 SequentialCluster 구성요소 그룹의 구성요소는 모두 순서대로 있습니다.
ParallelCluster 구성요소 그룹의 구성요소는 병렬로 있습니다.
예를 들어 다음은 구성요소를 프레임의 상단 영역에 정리합니다. 검색 레이블과 검색 텍스트 필드를 병렬 열로 클러스터합니다.


 
 hcluster: SequentialCluster {
      content: [
          ParallelCluster{ // mainCol
              resizable: true
              content: [
                  SequentialCluster{
                      content: [
                          ParallelCluster {  //searchLabelCol
                              content: searchLabel
                          },
                          ParallelCluster { //searchTextFieldCol
                              resizable: true
                              content: searchTextField
                          }
              ]},
 

SequentialClusterSequentialClusterParallelCluster와 같은 ClusterElement 구성요소를 지정할 수 있는

content 속성을 갖습니다. ParallelCluster 구성요소는 크기 조정이 가능하므로 필요에 따라 프레임 너비를 채웁니다.

인터페이스의 나머지도 같은 패턴을 따릅니다. 인터페이스의 각 5개 영역 내에서 구성요소는 SequentialCluster 구성요소 내에서 ParallelCluster 구성요소를 사용하여 그룹화 및 정리됩니다.

예를 들어 다음 코드는 매칭되는 이미지 레이블과 매칭되는 이미지 진행 표시줄을 병렬 열로 클러스터합니다.

클러스터 다음에는 검색과 매칭되는 이미지의 축소판 목록이 나옵니다.


 
SequentialCluster {
      content: [
          ParallelCluster {  //lblCol
              content: matchedImageLabel
          },
          ParallelCluster { //progressBarCol
              resizable: true
              content: matchedImagePB
          }
      ]},
  thumbnailList,
 

한 가지 주목할 점은 javafx.ext.swing 패키지의 Label 구성요소가 테두리 특성, 불투명도 또는 배경 색상의 설정을 위한 속성을

현재 지원하지 않는다는 것입니다. 따라서 이들 설정을 위해 getJComponent 함수에 대한 Label 구성요소의 지원을 활용했습니다.

함수는 JavaFX 스크립트 구성요소로 캡슐화된 Swing jComponent를 반환합니다.

이 경우에는 Swing Label 구성요소를 반환합니다. 다음 코드를 사용하여 필요한 레이블 속성을 정의할 수 있습니다.


var selectedImageDisplay = Label {
         ...
  }

  selectedImageDisplay.getJComponent().setOpaque(true);
  selectedImageDisplay.getJComponent().setBackground(Color.WHITE.getAWTColor());
  selectedImageDisplay.getJComponent().setBorder(new LineBorder(Color.BLACK.getAWTColor(), 1, true));
 
설계 도구 없이 이미지 검색 사용자 인터페이스를 복제하는 것에 대해 처음에 걱정했던 것과 달리 가장 유용하고 필요한 기능은 
빠르고 쉽게 액세스가 가능합니다. 또한 NetBeans IDE용 JavaFX 플러그인은 구성요소를 사용하여 작업할 때 사용 가능한
속성을 띄우는 문맥 인식 코드 완성을 제공합니다. 코드 완성을 사용하면 UI의 구현이 처음 생각처럼 어렵지만은 않습니다.
그림 5는 IDE에서 Ctrl+spacebar를 입력할 때 활성화되는 일부 팝업 옵션을 보여줍니다.


그림 5. 옵션


요약
 

UI 생성을 위한 선언적 구문을 살펴보기 위해 기존 애플리케이션의 UI를 이식했습니다.

원래 애플리케이션에서는 구성요소의 배치 및 정렬에 Swing의 GroupLayout을 사용했습니다.

NetBeans IDE 6.1은 아직 JavaFX 스크립트를 위한 그래픽 설계 도구를 지원하지 않지만

수동으로 인터페이스를 레이아웃하는 것은 처음 걱정했던것 만큼 어렵지 않았습니다.

ClusterPanel, SequentialClusterParallelCluster 구성요소의 조합을 통해

JavaFX 스크립트 구현은 원래 UI와 사실상 똑같아 보입니다.

이들 조합에 NetBeans IDE용 JavaFX 플러그인 및 문맥 인식 코드 완성이 더해져 작업은 더욱 쉬워졌습니다.


자세한 정보


이 글의 영문 원본은 # Learning Curve Journal, Part 2: Declarative User Interfaces에서 보실 수 있습니다.
 
2007년 8월과 9월에 썬 개발자 네트워크의 John O'Conner는 JavaFX 스크립트 프로그래밍 언어(이 기사에서는 JavaFX 스크립트라고 줄여서 부름)를 시작하는 사용자에게 도움을 주고자 "학습 곡선 일지(Learning Curve Journal)"라는 제목의 시리즈를 기고했습니다.

그 이후로 이 언어의 많은 중요한 부분이 개선되었습니다. 아마도 가장 중요한 변화는 JavaFX 스크립트의 초기 인터프리터 기반 버전을 대신하여 컴파일러 기반 버전을 사용할 수 있게 되었다는 점입니다. 이전의 학습 곡선 일지에서는 인터프리터 기반 버전 사용에 대해 설명했습니다. 업데이트된 학습 곡선 일지에서는 컴파일러 기반 버전의 언어 사용법을 보여줍니다. 최신 내용을 반영하여 다른 변경 사항도 적용되었습니다.

이 전과 마찬가지로 시리즈의 1편은 JavaFX 프로그램, 즉 JavaFX 스크립트 언어로 쓰여진 간단한 프로그램으로 시작합니다. JavaFX 스크립트에서의 프로그래밍을 위한 환경 설정 방법과 JavaFX 프로그램 빌드 및 실행 방법을 배우게 됩니다. 2편은 JavaFX 스크립트에서 사용 가능한 선언적 코딩 스타일에 중점을 둡니다. 이러한 스타일이 어떻게 그래픽 애플리케이션을 더욱 단순하고 직관적으로 만들 수 있는지 볼 수 있을 것입니다. 3편에서는 JavaFX 프로그램에서 작업 구현을 위한 JavaFX 스크립트 함수의 사용 방법을 보여줍니다. 4편에서는 웹 서비스 액세스를 위한 JavaFX 스크립트 사용 방법을 보여줍니다. 그 과정 중에 FX 스크립트에서 Swing 클래스와 같은 자바 기술 슬래스의 액세스가 얼마나 쉬운지도 보여줍니다.

JavaFX 스크립트는 개발자가 동적인 그래픽 컨텐츠 생성에 사용할 수 있는 새로운 스트립팅 언어입니다. 데스크탑에서 언어는 Swing 사용자 인터페이스(UI) 툴킷과 자바 2D API를 편리하게 사용할 수 있는 라이브러리를 제공합니다. Swing 또는 자바 2D를 대체하는 것이 아니고 풍부한 컨텐츠 개발자가 이들 API에 더욱 쉽게 액세스할 수 있도록 하는 것이 목적입니다. 모바일 시스템과 같은 다른 환경에서 JavaFX 스크립트는 Swing 이외의 사용자 인터페이스 기술을 사용합니다. JavaFX 스크립트를 사용하여 여러 가지 플랫폼과 운영 환경에서 실행되는 시각적으로 풍부한 애플리케이션을 만들 수 있습니다.

언어는 선언적 및 절차적 구문을 모두 제공합니다. 선언적으로 풍부한 사용자 인터페이스를 만든 다음 이벤트 처리 루틴과 작업을 추가할 수 있습니다.

그러나 대부분의 사용자는 좀 더 소박하게 시작해야 하며 이 기사의 목적도 그러합니다. 목표는 JavaFX 스크립트를 시작하는 방법을 보여주는 것입니다. 먼저 다음이 필요합니다.



자바 플랫폼 설정

개발자라면 물론 시스템에 JDK가 설치되어 있을 것입니다. 그러나 시스템을 한동안 업데이트하지 않은 경우에는 자바 SE 6이 설치되어 있는지 확인하십시오. 학습 곡선 일지는 JavaFX 스크립트의 컴파일러 기반 버전과 NetBeans IDE 6.1에서의 지원에 중점을 두고 있습니다. JavaFX 기술이 적용된 NetBeans IDE 6.1을 설치 및 사용하려면 시스템에 자바 SE 6의 최신 수준(현재는 자바 SE 6 업데이트 10 베타)을 설치하는 것이 좋습니다. 썬 개발자 네트워크의 자바 SE 다운로드 페이지에서 최신 JDK를 다운로드합니다. Mac OS X를 사용하는 경우에는 Apple Developer Connection의 자바 섹션에서 직접 Apple의 최신 자바 플랫폼 개발 키트(현재는 Mac OS X 10.5, 업데이트 1용 자바)를 다운로드 받을 수 있습니다.


자료 참조

새로운 환경이나 언어를 경험할 때는 교착 상태에 빠지거나 난관에 봉착하게 됩니다. 이는 최첨단 기술을 사용할 때 모두가 겪게 되는 과정입니다. 학습 곡선을 원만하게 하기 위해서는 훌륭한 문서와 예제가 매우 중요합니다. 썬 개발자 네트워크의 JavaFX 기술 허브와 함께 javafx.comProject OpenJFX 웹 사이트는 정확한 정보를 얻을 수 있는 최신 문서와 데모 자료를 제공합니다.

일 부 사용자들은 언어 참조 자료를 읽지도 않고 프로그래밍을 바로 시작하고자 할 수 있습니다. 또다른 사용자들은 JavaFX 스크립트를 실제로 사용하기 전에 모든 자료를 읽을 것입니다. 바로 시작하는 유형의 사용자더라도 일종의 언어 사양이나 자습서부터 시작해야 합니다. 전형적인 "Hello, world" 예제를 쓰기 전에 기본 언어 구문을 알아야 합니다. JavaFX 참조 페이지의 문서부터 시작하는 것이 좋습니다. 여기에서 JavaFX 스크립트 프로그래밍 언어 참조 자료 등의 참조 문서와 JavaFX 기술 시작하기NetBeans IDE를 사용하여 간단한 JavaFX 애플리케이션 생성 등의 많은 기사와 자습서로의 링크를 찾을 수 있습니다.


JavaFX 애플리케이션 생성

일부 언어 참조 문서를 읽었다면 이제는 간단한 JavaFX 애플리케이션을 만들어 볼 차례입니다. 명령줄에서 수동으로 JavaFX 애플리케이션 빌드 및 실행이 가능하긴 하지만 애플리케이션 개발을 단순화하는 많은 기능을 가진 NetBeans IDE 6.1를 사용해 봅시다. NetBeans용 JavaFX 플러그인을 설치해야 합니다.

NetBeans IDE 6.1을 설치하지 않은 경우에는 NetBeans IDE 6.1과 NetBeans용 JavaFX을 포함하는 하나의 패키지인 JavaFX 포함 NetBeans IDE 6.1 다운로드가 가능합니다. NetBeans IDE 6.1을 이미 설치한 경우에는 NetBeans 업데이트 센터에서 JavaFX 플러그인을 설치하여 JavaFX 기술 지원을 추가할 수 있습니다. NetBeans용 JavaFX는 현재 Windows 및 Mac OS/X 환경에서 사용 가능합니다. JavaFX 플러그인을 설치하면 NetBeans IDE 6.1을 사용하여 JavaFX 스크립트의 컴파일러 기반 버전으로 작성된 애플리케이션을 생성, 테스트, 디버그 및 배포할 수 있습니다. 플러그인은 JavaFX 스크립트 파일 포함을 위한 프로젝트 및 편집기 지원을 향상시킵니다. 또한 스크립트 엔진 및 라이브러리를 위한 코어 라이브러리도 제공합니다.

JavaFX 포함 NetBeans IDE 6.1이나 NetBeans용 JavaFX 플러그인을 설치했으면 첫 번째 JavaFX 애플리케이션을 빌드할 준비가 된 것입니다. 물론 "Hello, world!"부터 시작해야겠지요.

다음과 같이 프로젝트 생성을 시작합니다.

  1. 주 메뉴에서 File -> New Project를 선택합니다.
  2. New Project 마법사에서 JavaFX 범주와 JavaFX Script Application 프로젝트 유형을 선택합니다.
  3. Next 버튼을 클릭합니다.
  4. HelloWorldJFX와 같이 프로젝트의 이름을 지정합니다.
  5. 기본 프로젝트 위치를 수락하거나 다른 위치를 선택하여 이동합니다.
  6. Create Main Class 확인란을 선택된 상태로 두고 다른 기본 설정도 변경하지 않습니다.
  7. Finish 버튼을 클릭합니다.

그림 1과 같이 IDE는 지정된 프로젝트 폴더에 프로젝트 디렉토리를 생성하고 프로젝트 이름과 같은 HelloWorldJFX라는 이름을 부여합니다. HelloWorldJFX 프로젝트를 확장합니다. Source Packages 노드의 helloworldjfx 패키지 아래에 Main.fx 클래스 파일이 있습니다. IDE는 프로젝트 생성 시 Create Main Class 확인란이 선택되어 있었으므로 Main.fx 파일을 생성합니다. 이 파일에 애플리케이션의 소스 코드가 들어갑니다.


그림 1.
HelloWorldJFX 프로젝트 파일


  /*
   * Main.fx
   *
   * Created on ...
   */

  package helloworldjfx;

  /**
   * @author ...
   */

  // place your code here
 

// place your code here 라인을 다음 코드로 바꿉니다.

  import javafx.ext.swing.Label;

  Label {
      text: "Hello, world!"
  }
 


JavaFXScript 편집기는 기본 서식 설정과 코드 완성을 제공합니다. 우리와 같이 JavaFX 스크립트에 익숙하지 않은 프로그래머는 언어 구문에 확신이 들지 않을 때도 있으므로 코드 완성이 도움이 됩니다. Ctrl + Space 키를 누르면 편집기에서 코드 완성이 활성화됩니다.

또 한 JavaFX 스크립트 플러그인은 컴파일과 실행을 해 볼 필요 없이 애플리케이션의 결과를 볼 수 있는 미리보기 기능을 제공합니다. 소스 파일에 변경한 내용은 즉시 미리보기 창에 반영됩니다. 미리보기 기능은 현재 Mac OS X 플랫폼에서는 사용할 수 없습니다.

Enable Preview 버튼

을 클릭하여 미리보기 기능을 작동시킵니다. 그림 2와 같이 편집기 바로 위에서 출력을 볼 수 있습니다.



그림 2. 기본적인 "Hello, world!"

별로 놀라지 않으셨나요? 좋습니다. 설정 방법을 보여주려는 것 뿐이었지만 좀 더 재미있는 것을 해보도록 하겠습니다. JavaFX 환경은 모든 Swing UI 구성요소를 구현하므로 레이블에만 한정될 필요는 없습니다. 버튼이나 대화 상자 같은 다른 위젯을 사용할 수도 있습니다.

다음은 버튼의 이벤트 핸들러를 소개하는 예제입니다. 언어 참조 자료에서 actionfunction 구문을 읽었으면 버튼을 누를 때 메시지 상자가 표시되도록 해봅시다.


  import javafx.ext.swing.SwingFrame;
   
import javafx.ext.swing.Button;
   
import javafx.ext.swing.SwingDialog;
   
import javafx.ext.swing.Label;
 
   
SwingFrame {
       content
: Button {
           text
: "Press me!"
           action
: function() {
               
SwingDialog {
                   title
: "You pressed me"
                   content
: Label{ text: "Hey, don't do that!"}
                   visible
: true
               
}
       
}
   
}
 
   visible
: true
   
}



Main.fx 파일에 이를 입력한 후에 Press me! 버튼을 누르면 그림 3과 같은 결과가 나타납니다.

그림 3. "Press me!" 버튼 메시지


앞에서 말한 것처럼 미리보기 기능을 사용하여 코드를 컴파일 및 실행하지 않고도 애플리케이션의 결과를 볼 수 있습니다. 코드를 컴파일하려는 경우에는 Project 창에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Build Project를 선택합니다. 애플리케이션을 실행하려면 Project 창에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 Run Project를 선택합니다.


구성요소 기반에서 노드 기반 UI로의 이동

이전 예제에서 Frame과 Dialog의 구성요소가 간단하게 FrameDialog가 아니라 SwingFrameSwingDialog라 는 클래스 이름을 갖는지 궁금하셨을지도 모릅니다. 그 답은 JavaFX 스크립트 개발자가 Swing 기반 구성요소의 계층 구조를 사용하는 기존 접근 방법 대신 노드 기반 접근 방법을 사용하여 UI를 구축하는 향후의 접근 방법에 관련되어 있습니다. 사실 이러한 향후의 접근 방법에 대한 초기 지원은 이미 JavaFX 라이브러리에 포함되어 있습니다. 예를 들면 javafx.application 패키지에는 노드 기반 접근 방법을 지원하는 Frame, DialogWindow 등의 클래스가 포함됩니다. 다른 접근 방법을 지원하는 클래스와의 혼동을 피하기 위해 javafx.application 패키지에 해당 항목이 있는 javafx.ext.swing 패키지는 클래스 이름에 접두어 "Swing"을 추가했습니다.

학습 곡선 시리즈에서는 계층 구조적인 Swing 기반 접근 방법을 사용했지만 javafx.ext.swing 패키지의 SwingFrame, SwingDialogSwingWindow와 같은 클래스는 임시적입니다. JavaFX 팀은 Swing 구성요소와 유사하지만 더욱 유연하고 강력한 새로운 노드 기반 구성요소 집합을 설계 중입니다.

노드 기반 접근 방법을 사용한 UI 구축에 대한 자세한 내용은 장면 그래프를 사용하여 JavaFX 스크립트에서 비주얼 개체 표시 기사를 참조하십시오. NetBeans IDE를 사용하여 간단한 JavaFX 애플리케이션 생성 자습서도 노드 기반 접근 방법을 사용하는 JavaFX 애플리케이션을 설명합니다.


프로파일

JavaFX는 특정 플랫폼이나 장치에서만 사용 가능한 클래스 그룹을 의미하는 프로파일을 지원합니다. javafx.ext.swing 패키지의 클래스는 데스크탑 프로파일에 들어 있으며 데스크탑 환경에서만 가용성이 보장됩니다. 예를 들어 많은 휴대 전화는 Swing 클래스를 갖지 않습니다. 휴대 전화와 TV를 포함한 모든 플랫폼에서 보장되는 클래스를 정의한 일반 프로파일도 있습니다. 새로운 노드 기반 구성요소는 일반 프로파일에 있으므로 모든 화면 및 장치에서 작동합니다.

JavaFX API 문서는 정확한 프로파일 사용을 보장하기 위해 하나의 프로파일에서 다른 프로파일로 전환할 수 있도록 하는 버튼을 제공합니다. 이 기사 시리즈에서는 데스크탑 환경을 위한 애플리케이션을 구축하므로 데스크탑 프로파일의 클래스와 일반 프로파일의 일부 클래스를 사용할 것입니다.


명령줄에서 JavaFX 애플리케이션 빌드 및 실행

다음과 같이 명령줄에서 JavaFX 애플리케이션을 빌드 및 실행할 수 있습니다.

  1. JavaFX Preview SDK 다운로드를 받습니다. SDK에는 JavaFX 스크립트 컴파일러, 문서, 런타임, 라이브러리 및 코드 샘플이 포함됩니다.
  2. 다운로드한 패키지를 확장합니다. 여러 디렉토리 중에 javafxcjavafx 명령을 위한 실행 가능 파일을 포함하는 bin 디렉토리가 보여야 합니다.
  3. fx 확장자를 갖는 파일(예: MyApp.fx)에 애플리케이션의 소스 코드를 저장합니다
  4. 다음과 같이 javafxc 명령을 수행하고 소스 파일을 지정하여 애플리케이션을 컴파일합니다.
       javafxc MyApp.fx

    애플리케이션을 위한 클래스 파일이 생성됩니다.

  5. 다음과 같이 javafx 명령을 수행하고 클래스 파일을 지정하여 애플리케이션을 위한 클래스 파일을 실행합니다.
       javafx MyApp

요약

새로운 기술을 조사할 때는 올바르게 시작하는 것이 중요합니다. 정확한 정보와 도구를 사용하여 시작하도록 하십시오. JavaFX 스크립트에 대한 최선의 방법은 4단계 절차를 따르는 것입니다.

  1. 최신의 Java SE Development Kit를 받습니다.
  2. 정보의 출처로 JavaFX 기술 허브, javafx.com 사이트Project OpenJFX 사이트를 사용합니다.
  3. IDE용 개발 플러그인을 받습니다. JavaFX 포함 NetBeans IDE 6.1은 새로운 JavaFX 스크립트의 컴파일러 기반 버전을 지원합니다. NetBeans IDE 6.1을 이미 설치한 경우에는 NetBeans 업데이트 센터에서 JavaFX 플러그인을 설치하여 JavaFX 기술 지원을 추가할 수 있습니다.
  4. 첫 번째 스크립트 시험에 미리보기 기능을 사용합니다.


자세한 정보

이 시리즈의 2편인 선언적 사용자 인터페이스를 참조하십시오.



이 글의 영문 원본은
Learning Curve Journal, Part 1: Exploring JavaFX Script
에서 보실 수 있습니다.

 

지난 장에선 사설이 넘 길어 아파치 설치하는 것만 하고 마치고 말았다.ㅋ

트레이창에 아파치서비스 모니터링 아이콘을 확인할 수 있다. 오른쪽 마우스를 클릭 Open Apache Monitor를 선택하여 아파치를 구동/정지할 수 있다. 톰캣의 경우 압축만 풀면 되지만 아파치의 경우 설치하게 되면 서비스에  등록이 된다.

설치시 자동으로 초기설정되기 때문에 윈도우 시작등 리소스를 소모하는 부분도 있어

일단 먼저 Open Services를 클릭하여 Apache2.2를 자동에서 수동으로 변경한다(안해도 상관은 없다.대신 가끔 시스템이 느려질수 있다)

 

1. 이젠 톰캣을 설치하자.

http://tomcat.apache.org/ 에서 톰캣을 다운받는다. 현재 최신버젼은 6.0.18 .

 

톰캣설치는 앞서말한바와 같이 압축만 풀면 되니 설명은 패스. 설치할 디렉토리에 푼다.

 

2. http://tomcat.apache.org/download-connectors.cgi 에서 연동파일을 다운 받는다.

다운 받을 파일은 다음과 같다.

 

  • mod_jk-1.2.26-apache-2.0.59.so is for Apache 2.0, and works with Apache 2.0.59 and later.
  •    Rename to mod_jk.so before putting it in your Apache2/modules directory.

  • mod_jk-1.2.26-apache-2.2.4.so is for Apache 2.2, and works with Apache 2.2.4 and later.
  •    Rename to mod_jk.so before putting it in your Apache2.2/modules directory.

  • isapi_redirect-1.2.26.dll is for IIS 5 and later Web Server.
  • nsapi_redirect-1.2.26.dll is for Sun ONE Web Server 6.1 and later (formerly Netscape iPlanet).
  •  

    아파치2.2 이상은 mod_jk-1.2.26-apache-2.2.4.so 파일을 다운 받으면 된다.

     

    3. 다운받은 파일을 mod_jk.so로 이름을 변경후 아파치설치폴더/modules 에 복사한다.

     

    4. 아파치설치폴더/conf 에서 httd.conf를 수정한다

    LoadModule 어쩌구저쩌구 하는 부분 아래쪽에 다음과 같이 추가한다.

     

    LoadModule jk_module modules/mod_jk.so

     

    그리고 맨 아래 다음과 같은 구문을 추가한다.

    Include conf/mod_jk.conf

     

    5. 아파치설치폴더/conf에 mod_jk.conf 파일을 만들어 넣는다.

    아파치와 톰캣연동을 위한 설정부분으로 mod_jk.conf의 내용은 다음과 같이 작성하면 된다.

     

    JkWorkersFile "아파치설치폴더/conf/workers.properties"
    JkLogFile "톰캣설치폴더/logs/mod_jk.log"
    JkLogLevel error
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
    JkRequestLogFormat "%w %V %T"

    JkAutoAlias "톰캣설치폴더/webapps"
    JkMount /*.jsp ajp13
    JkMount /servlet/* ajp13
    JkMount /jsp-examples ajp13
    JkMount /jsp-examples/* ajp13
    JkMount /url ajp13

    <Directory "톰캣설치폴더/webapps">
        Options Indexes FollowSymLinks
        allow from all
    </Directory>

     

    6. 아파치설치폴더/conf에 workers.properties 파일을 만들어 넣는다.

     

    workers.tomcat_home="톰캣설치폴더/webapps"
    workers.java_home="JDK또는 JRE설치위치"
    ps=/

    worker.list=ajp12, ajp13
    worker.ajp12.port=8007
    worker.ajp12.host=localhost
    worker.ajp12.type=ajp12
    worker.ajp12.lbfactor=1

    worker.ajp13.port=8009
    worker.ajp13.host=localhost
    worker.ajp13.type=ajp13
    worker.ajp13.lbfactor=1
    worker.loadbalancer.type=lb
    worker.loadbalancer.balanced_workers=ajp12, ajp13
    worker.inprocess.type=jni
    worker.inprocess.class_path=$(workers.tomcat_home)$(ps)lib$(ps)tomcat.jar
    worker.inprocess.cmd_line=start
    worker.inprocess.stdout=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stdout
    worker.inprocess.stderr=$(workers.tomcat_home)$(ps)logs$(ps)inprocess.stder

    7. 이제 아파치와 톰캣연동은 끝.

    아파치와 톰캣설정은 끝났기 때문에 이클립스에서 웹프로젝트를 작성 후 확인해보면 된다.

     

    이클립스에서 서버설정은 Window>Preferences>Server>Installed Runtime 에서 할 수 있다.

    톰캣은 Apache 폴더 아래에서  6.0을 선택한후 설치 디렉토리를 지정하면 되고

    아파치는 Basic폴더 아래에서 HTTP Server를 선택한 후 아파치 설치 디렉토리/htdocs 를 지정하면 된다.

    아니면 프로젝트 생성시 New Project에서 Static Web Project 또는 Dynamic Web Project를 선택 후

    Target Runtime의 옆에 있는 New 버튼을 클릭하여 등록할 수도 있다.

     

    전장에서 말한 바와 같이 dynamic content(서블릿,JSP,필터,관련메타데이터)를  제외한 content-based 웹 어플리케이션을 구현하고자 할때 static Web Project를 선택한다. 물론 당연히 dynamic Web Project에서도 static resource들을 등록/관리할 수 있다.

     

    특이한점은 Static Web Project의 경우 Dynamic Web Project와 달리 서버탭에서는 항상 status가 started 상태에 있다는 것을

    확인할 수 있다.처음엔 서비스로 등록되기 때문에 서비스를 죽이면 이클립스에서 Dynamic Web Project에서처럼 아파치를 구동/정지하지 않을까 하고 생각했는데 그것과는 무관했다. 첨엔 status가 started여서 http://localhost/img/sample.jpg 를 찾아보려 했는데 실패했다. (당시 당연히 서비스는 죽어있었지만...*^^*) 앞서 웹서버설정시 HTTP Server는 로컬 HTTP Server를 사용하는 것을 의미하기 때문에 프로젝트내 내용은 아파치설치폴더/htdocs아래 복사(동기화)된다. 

     

    다소 설정상의 귀차니즘은 있지만 설정이후의 컴파일 속도는 static resource를 빼고 수행하기 때문에 훨씬 빨라진 것을 확인 할 수 있을 것이다. 

     

     

     

     

     

    운영중인 WEB시스템을 보면 정적인 페이지와 동적인 페이지를 구분해서 관리하곤한다.

    가장 일반적으로는 정적인 페이지는 아파치에서 동적인 페이지는 톰캣에서 구동되도록 하고 있는데...

    왜 그런걸까?

    현재 톰캣에서 http spec을 지원(즉 웹서버기능을 포함)하고 있기 때문에 굳이 옛날처럼 웹서버와 어플리케이션 서버를 구분할 필요가 있을까? 물론 간혹 이제까지 해왔기 때문에 라는 이상한 논리를 펴시는 분들은 아마도 이제까지 그리 해오는것이 당연하게 생각해왔기 때문은 아닐까? 하지만 구분하시는 분들은 시스템의 퍼포먼스를 위해서라는 나름 경험적인 말들을 하곤하다.

    반대로 예전에는 톰캣에서 웹서버 기능을 지원하지 않았지만 지금은 톰캣만으로 충분하다고 말씀하시는 개발자분들도 계시다.

    내 개인적인 생각은 둘다 맞는 것 같다. 분명 정적페이지만을 아파치에서 관리하게 되면 정적인 파일에 대해서도 동적구동루틴의 타게 함으로써 생겨나는 부하를 줄이게 되기 때문에 퍼포먼스를 줄일 수 있다(즉 정적인 페이지를 요청하는 횟수가 줄이게 됨으로써 네트워크의 부하를 줄임). 또한 이미지의 경우 전송되는 헤더의 크기가 훨씬 적어지기 때문에 더 나은 퍼포먼스를 가지게 된다.(즉 쿠키가 필요없는 이미지파일에 대한 요청에 대해 정적인 페이지에서 헤더에 포함되어 전송되기 때문에 전송패킷의 크기는  달라진다. 이미지 파일크기가 달라진다는 의미는 아님.도메인 분리에 대한 헤더파일 크기 비교는 링크페이지 참조). 또한 작은 이미지의 경우 톰캣이나 아파치나 큰 성능차이는 없지만 큰 이미지의 경우 아파치에서 구동하는 것이 훨씬 빠르다고 한다. 하지만 요새 운영시스템의 사양은 톰캣이나 JBoss같은 WAS만을 구동하기엔 너무나 고사양이다.

    즉 어떤 시스템인가에 따라 다르긴 하지만 톰캣하나만으로도 웬만큼 충분하다는 말이다.

    일반적으로 개발할때는 톰캣하나만으로 개발하다가 운영시 분리하곤 한다. 하지만 난 오히려 운영보다는 개발할때 분리를 해야 한다고 생각을 한다. 어떤 개발자분들을 보면 작업표시줄에 수많은 프로그램이 떠 있는 상태에서 개발하곤 한다. 물론 디버깅이나 모니터링때문에 텔넷창을 여럿 띄어두기도 하고 웹브라우저도 몇개 띄어두고 이클립스랑 기타 성능관리 툴, 워드파일이니 엑셀파일도 열고. 크 놋북사양이 부럽다는 생각만 든다. (나도 물론 여럿 띄워둔채 개발하긴 하지만..). 현재 이클립스 3.4를 가지고 개발하고 있는데 다이나믹 웹프로젝트로 프로젝트를 만들고 개발 소스가 많아질수록 초기 구동시 등록된 Context를 동기화 하면서 간혹 구동에 실패하곤 한다. (물론 재시작하면 정상구동이 되거나 계속 실패가 반복되는 경우 디버깅모드를 ERROR로 바꿔 재구동하면 해결된다). 그래서 다이나믹 웹프로젝트에는 JSP만을 올리고 나머진 static 웹프로젝트로 만들어 처리하여 톰캣 초기구동시 걸리는 시간을 줄일 수 있다.

    아 사설이 넘 길었다. 후딱 후딱 지나가야지..

    먼저 아파치를 설치한다.

    우선 Apache 서버를 설치해 보기로 보자.

    http://httpd.apache.org/ 에서 아파치를 다운받는다. 최신 버젼은 2.2.9.


    다운받은 Apache 설치 파일을 실행시킨다. 실행버튼 클릭!!

    실행후 바로 나타나는 화면이다. Next 버튼 클릭 !!



    라이센스!! 사실 읽어보는 사람 잘 없을거다. 게다가 영어다. ㅋ
    약관에 동의를 해야지만 설치가 가능하다.
    약관 아래쪽 2개의 항목중 위에 있는 I accept the terms in the license agreement 를 선택후 Next 클릭 !!



    실행하기 전에 읽어보라는데 이것 역시 영어다. 패스!! Next 버튼을 클릭!!
    한번쯤 읽어 보시기를 권장한다. ㅎㅎ



    아래 입력박스에 해당하는 도메인정보와 이메일 정보를 입력한다.지금 입력되어 있는 것은 내가 임의로 입력한 내용으로 각자에게 알맞는 정보를 입력하면 된다. 그리고, 아래쪽에 있는 항목은 IIS가 설치되어 운영중일 경우 그러니까 80번 포트가 아닌 8080이나 기타 다른 포트를 사용할 경우에는 아래쪽을 선택하고 그냥 기본으로 설치하고자 한다면 위쪽 항목을 선택하면 된다.
    입력과 선택을 마쳤다면 Next 버튼을 클릭 !!



    설치 타입은 기본으로 해도 되고 사용자 선택(Custom)으로 설치 해도 상관없슴.Next 버튼을 클릭 !!


    설치 디렉토리를 지정하고, Next 버튼을 클릭 !!기본으로 두고자 한다면 그냥 넘어가면 되고, 다른 디렉토리에 설치를 원하면  Change 버튼을 눌러 설치하고자 하는 디렉토리를 선택하면 된다.

    Install 버튼을 클릭하면 자동으로 설치된다.

    Finish 버튼을 클릭하고 설치 프로그램을 빠져 나가면 된다.

     

    설치과정에서 기본 포트(80)을 선택하였다면, 웹브라우저를 실행시켜서 아래와 같이 입력해본다.

    다음과 같은 내용이 웹브라우저에 표시된다면 정상적으로 설치된 것이다.
     

     

     
    블로그 이미지

    시반

    시반(詩伴)이란 함께 시를 짓는 벗이란 뜻을 가지고 있습니다. 함께 나눌수 있는 그런 공간이길 바라며...

    카테고리

    분류 전체보기 (233)
    개발 이야기 (73)
    WEB2.0 (57)
    DB2 (24)
    MySQL (6)
    오라클 (26)
    기타 (44)
    취미 (0)
    잡담 (2)