자바/Web2009. 11. 2. 13:57

Ajax loading시 원하는 이미지를 제네레이트 해서 얻을 수 있는 사이트가 있당...

http://www.ajaxload.info/

이런 유용한 사이트는 미리 체크체크~
Posted by 양군이당
TAG Ajax, Loading

댓글을 달아 주세요

자바/Web2009. 7. 3. 11:46
요즘 한참 뜨고 있다는 이유로 Rest 한 Web App를 만들어 보겠다고 계속 자료를 보고 있는 상황인데

과연 꼭 Struts를 이용해서 Rest 한 페이지를 만들어야 하는가? 에 대한 의문이 자꾸 든다.

내가 아직 RESTful 에 대해 정확히 이해를 하지 못한건지 Struts rest plugin에 대한 이해도가 떨어져서 일지 모르지만

Struts의 Convention plugin만 되더라도 좀 더 POJO.답고 Struts Action의 기반에서 많이 벗어나지 않는 상태인데다가

Annotation을 이용해서 각종 설정을 할 수 있다. Action 부터 Result, Chain Action까지 많은것을 설정할 수 있는데 Rest

plugin은 구조상 그게 안될 것 같다는 생각이 많이 든다. Rest 한 App를 만들기 위해 상당히 정형화된 구조로 프로그램을 개발

해야 한다니 좀 아이러니 하다. 물론 정형화된 틀로 코딩을 하면 결과물에서는 엄청난 장점들이 쏟아져 나온다.

하지만 그만큼 융통성은 떨어지는 것 같다. 특히나 요즘 같이 Web App도 점점 복잡화 되고 있는데 Chain Action을 쓸수

없다는건 단점으로 보인다. 분명히 코딩하다 보면 여러가지를 활용해야 할텐데 그럴땐 어떻게 해야 할지가 고민이다. -_-

지금 Rest한 구조를 선택해서 끝까지 밀고 나가던가 아니면 적당히 Convention만 쓰는건데 어떤게 도움이 될까?

또 과연 Rest plugin을 썼을때 사용되는 id 값이 한개가 아닌 여러개일 경우는 과연 어떻게 처리해야 할까?

아.. 여러모로 결리는게 너무 많다. 적당한 타협점은 아무래도 Convention plugin 정도까지 사용한게 맞는것 같다.

Rest 는 그냥 테스트 정도까지만 접근해 보자.
Posted by 양군이당

댓글을 달아 주세요

자바/Web2009. 7. 3. 10:38
웹 어플리케이션을 하나 하나 만들어보려는 게으름 탈피 프로젝트에 의거 하나 하나 만들기 위해 자료 검색을 시작

최근 핫 이슈인  RESTful을 좀 건들여 보려고 했다. 마침 Struts 를 사용해서 Rest 한 구조를 구현할 수 있도록

플러그인들이 소개되어 있는데 이넘이 바로 struts2-convention-plugin 과 struts2-rest-plugin 이다.

그런데 이넘들이 만만한 자료가 없더라.. 넘쳐나는 수많은 자료중에 쓸만한건 거의 없었으니.. ㅡ_ㅡ;

게다가 struts 사이트에는 maven을 이용한 설정.. ㅡ_ㅡ

쌩 무시하고 나름 검색을 통해 환경을 구축하고 테스트를 한번 슬쩍 돌려봤다.

자 이제 시작!!



참고 사이트

http://struts.apache.org/2.x/docs/convention-plugin.html
http://struts.apache.org/2.x/docs/rest-plugin.html
http://www.zulutown.com/blog/2009/01/28/rest-web-application-with-struts21-rest-and-convention-plugins/

환경
JDK 6
Tomcat 6.0
Eclipse 3.4.1 EE version
Struts 2.1.6
JQuery
Prototype

Eclipse 디렉토리 구성

위에 이미지를 보면 알겠지만 필요한 binary들은 다음과 같다.
  • commons-beanutils-1.7.0.jar
  • commons-collections-3.2.jar
  • commons-fileupload-1.2.1.jar
  • commons-io-1.3.2.jar
  • commons-lang-2.3.jar
  • commons-logging-1.0.4.jar
  • ezmorph-1.0.3.jar
  • freemarker-2.3.13.jar
  • json-lib-2.1.jar
  • ognl-2.6.11.jar
  • struts2-convention-plugin-2.1.6.jar
  • struts2-core-2.1.6.jar
  • struts2-rest-plugin-2.1.6.jar
  • xpp3_min-1.1.3.4.O.jar
  • xstream-1.2.2.jar
  • xwork-2.1.2.jar
모두 struts2 lib 바이너리에 있으므로 해당 파일을 프로젝트에 추가해 주면 된다.



web.xml

 <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Framework</display-name>
 
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.FilterDispatcher
        </filter-class>
      <init-param>
          <param-name>struts.i18n.encoding</param-name>
          <param-value>utf-8</param-value>
      </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>


struts.xml

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
    "http://struts.apache.org/dtds/struts-2.1.dtd">

<struts>
    <constant name="struts.devMode" value="true" />
    <constant name="struts.convention.action.suffix" value="Controller"/>
    <constant name="struts.convention.action.mapAllMatches" value="true"/>
    <constant name="struts.convention.default.parent.package" value="rest-default"/>
    <constant name="struts.convention.package.locators" value="test"/>
</struts>

struts의 convention plugin 과 rest plugin은 무설정을 지향하고 있다. 따라서 struts.xml 파일에서는 설정할 것이 거의 없다.

이정도의 설정으로 거의 겜오버.. ㅡ_ㅡ)=b

여기서 주의할 것은 struts.convention.action.suffix 와 struts.convention.package.locators 설정이다.

struts.convention.action.suffix 는 앞으로 Rest 한 Action을 처리하고자 할때 실제로 Action을 취해줄 Class의 Suffix 가 된다. 앞으로 설명할 예제와 같이 http://localhost:8080/[Context]/messages 라는 호출이라면 이것을 처리할 Action의 이름은 MessagesController 가 되어야 해당 요청을 올바르게 처리할 수 있다.

또한 이 액션을 찾기 위해 패키지를 Search 하게 되는데 어떤 패키지를 찾을지 선택해 주는것이 바로 struts.convention.package.locators 이다. 이 설정은 ,로 여러개를 설정할 수 있으며 설정한 패키지를 검색하면서 해당 Action을 찾게 된다.

Action을 찾는 규칙과 요청처리 규칙은 다음번에 정리하도록 해야겠다..

아뭏든 지금 위의 그림과 같이 rest.test라는 패키지에 MessagesController를 만들어 놨으므로 struts.convention.package.locators는 test라고 설정해 놓았다.

struts의 rest plugin은 요청 결과를 따로 코딩해주지 않아도 xml 과 json 형식으로 결과 반환이 가능한데 이는 원하는 결과 요청 url 에 .xml 이나 .json을 붙여서 요청하면 된다. 완전 행복한 기능이 아닐수 없다.

우선 최종 결과 페이지를 보기 전에 샘플 소스를 보자.

Sample Source

 package rest.test;

public class Message {
    private String id;
    private String text;
    private String author;

    public Message() {
        super();
    }

    public Message(String id, String text, String author) {
        super();
        this.id = id;
        this.text = text;
        this.author = author;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Message other = (Message) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }
}

 package rest.test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MessageService {
    public static HashMap<String, Message> messages = new HashMap<String, Message>();
    private static int nextMessageId = 4;

    static {
        Message message1 = new Message("1", "hello", "john");
        Message message2 = new Message("2", "world", "ted");
        Message message3 = new Message("3", "rest", "sam");
        messages.put("1", message1);
        messages.put("2", message2);
        messages.put("3", message3);
    }

    public static List<Message> findAll() {
        return new ArrayList<Message>(messages.values());
    }

    public static Message find(String id) {
        return messages.get(id);
    }

    public static void save(Message message) {
        if (message.getId() == null) {
            String id = String.valueOf(nextMessageId);
            message.setId(id);
            nextMessageId++;
        }
        messages.put(message.getId(), message);
    }

    public static void remove(String id) {
        messages.remove(id);
    }
}


 package rest.test;

import java.util.Collection;

import org.apache.struts2.rest.DefaultHttpHeaders;
import org.apache.struts2.rest.HttpHeaders;

import com.opensymphony.xwork2.ModelDriven;

public class MessagesController implements ModelDriven<Object> {

    private static final long serialVersionUID = 89268916175477696L;
    private Message model = new Message();
    private String id;
    private Collection<Message> list;

    public HttpHeaders create() {
        MessageService.save(model);
        return new DefaultHttpHeaders("create");
    }

    public HttpHeaders destroy() {
        return new DefaultHttpHeaders("destroy");
    }

    public HttpHeaders show() {
        return new DefaultHttpHeaders("show").disableCaching();
    }

    public HttpHeaders update() {
        MessageService.save(model);
        return new DefaultHttpHeaders("update");
    }

    public HttpHeaders index() {
        list = MessageService.findAll();
        return new DefaultHttpHeaders("index").disableCaching();
    }

    public Object getModel() {
        return (list != null ? list : model);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        if (id != null) {
            this.model = MessageService.find(id);
        }
        this.id = id;
    }
}

위의 소스는 참고사이트로 링크된 Rest Sample 관련 블로그에서 업어왔다.

소스를 슬쩍 살펴봐도 아주 간단한 소스이기 때문에 특별히 어려운건 없겠으나 Controller는 사전지식이 좀 있어야 한다. 하지만 이번 포스팅에서는 넘어가도록 하자. 저거 설명하는것도 일이다. ㅡ_ㅡ;

다음번 포스팅때를 기대하시라...


결과

http://localhost:8080/[Context]/messages.json

http://localhost:8080/[Context]/messages.xml

지금 요청은 MessagesController를 이용해 get 요청을 처리한 결과이다.

순서가 좀 이상하게 되었지만 기본적으로 Rest한 서비스에 대한 기본 지식이 있어야 이해가 되는 부분이다.

다음 포스팅에 Rest에 대한 정리와 Struts에서 처리 방식을 정리해 봐야겠다.




Posted by 양군이당

댓글을 달아 주세요

  1. 웹개발하는 신입

    양군님 질문 있습니다 ㅠㅠ
    restfut에서 경로를 그냥 src안 즉, 패키지를 생성안하고 만들고 싶은대... 방법이 없는것인지요..

    2010.07.28 12:02 [ ADDR : EDIT/ DEL : REPLY ]

자바/Web2009. 6. 24. 11:34
JQuery를 이용해서 특정 페이지를 div 태그로 로딩해 올때 히스토리에 쌓이지 않아 뒤로가기/앞으로가기 버튼이 전혀 먹지 않게 된다. 혹시나 해서 검색해 봤더니 쓸만한 플러그인이 있었다.

JQuery 홈페이지에도 소개되어 있는 History 관련 plug-in은 두개인데 

History/Remote by Klaus Hartl 와 Ajax History by Taku Sano 이다.

해당 페이지로 가면 관련 소스와 js 파일 데모 화면을 볼수 있는데

History/Remote는 문제가 좀 있다. Firefox와 Crome 에서는 문제 없이 돌았는데 IE8에서는 뒤로가기를 두번해줘야 한다.

그래서 찾은게 Ajax History... 이쪽은 업데이트가 활발하다... 그런데 이건 제대로 돌지를 않는다. 

문제를 찾아보면 되는데 밤새 작업했더니 피곤해서 찾기도 싫다. 뭐 조만간 업데이트가 되겠지.. -_-

그냥 History/Remote 쓰기로 했다... 이게 헐씬 사용하기도 편하다. ^^


Posted by 양군이당

댓글을 달아 주세요

자바/Web2009. 6. 24. 02:48
뭐 이런걸 다시 한번 쭈욱 만들어 보는건 예전부터 생각해오던 문제긴 했는데

실천은 한적이 없는것 같다.. 그래서 남은 소스도 별로 없고... ㅡ_ㅡ

학교가 끝나기 전에 그래도 뭔가 좀 끄적거려 놔야 나중에 하나씩 붙여가면서라도 만들수 있을 것 같아서

공부를 다시 시작했다. 웬지 마음 먹으니까 불붙어 올라서 ㅡ_ㅡ;;; 계속 계속 자료 검색하고

장단점 비교해 보고 하다 보니 시간 정말 잘 간다...

암튼 이것들을 만드는데 편하고 빠르고 효율성 좋게 개발하려다 보니 Framework을 써야 하겠고

요즘 대세가 Framework 사용이고 이런 것들을 해놔야 나중에 먹고 살기도 편할듯 해서 이래 저래 고민하고 있다

기본 Web Framework은 Struts, Spring, 혹은 이 둘의 조합을 생각하고 있다. 

struts는 간단하고 빠르게 웹 개발할 수 있는 장점이 있고 Spring은 웹개발 뿐만이 아닌 객체 관리부터 MVC 까지 다양하고 광범히 하게 쓰이며 세부적인 개발이 가능하다... 하지만 그만큼 복잡하지.. ㅡ_ㅡ

Persistance 쪽도 좀 고민인게... 처음엔 아무 생각없이 iBatis를 선상에 올려놨었다.. 

예전에 써보기도 했고 성능도 좋은 편이고 해서... 그런데 이게 참 고민되는게 JPA도 관심이 있어서 그쪽도 계속 보게 되더라..

iBaits는 쿼리를 직접 컨트롤 가능하고 캐싱 기능부터 다양한 기능을 수행하는데 JPA는 POJO 기반의 클래스와

1:1 매핑을 Annotation을 통해 가능하게 하는 매력적인 넘이고 앞으로 주목받을 만한 기술이라 고민이다.. ㅡ_ㅡ

그리고 빼놓을수 없는 Ajax 이넘도 요즘 Web 2.0이 반짝하는 시대라 덩달아 아주 중요해졌다...

요즘 각종 자바스크립트 프레임웍이 난무하는데 물망에 올린건 Prototype, JQuery, ExtJs 였다

ExtJs 는 유료기 떄문에 이래 저래 좀 피곤할 듯 하고.. ㅡ_ㅡ;;

그래서 본게 Prototype 인데 이넘이 매력적인게 꼭 자바같다.. ㅡ_ㅡ OOP 개념이 거의 다 녹아들어가 있고

Ajax 통신에서 원하는 대부분을 지원하고 여러모로 맘에 들었다.

그런데 요즘 주변 얘기도 들어보고 했을때 JQuery가 상당히 뜨고 있는 상황이라는 얘기를 들었고 실제 뒤져보니

각종 UI 콤포넌트부터 시작해서 쉽고 빠르게 접근할수 있는 장점이 있었다...

지금 생각엔 죄다 짬뽕을 해서 쓸 생각도 한다.

Spring + Struts + JPA(or iBatis) + JQuery를 메인으로 필요할때 Prototype 곁다리로... 

대충 이렇게 버무리면 개발시간도 많이 단축될것 같다...

아... 사이트 신나게 디벼보고 있었더니 시간 정말 빨리 간다...

이렇게 대충 보고 시작하면 항상 내가 뭐 하려고 할때 뭔가 부족하던데... ㅡ_ㅡ;;

암튼 열심히 공부해보자...



Posted by 양군이당

댓글을 달아 주세요

자바/Web2009. 6. 2. 05:20
웹 프로그래밍질을 하다 보니 가끔 헷갈려서 정리한다. 

프로그래밍 하다 보면 프레임웍을 쓰기도 하고 안쓰기도 하고.... 호출 하는 것이 특정 Servlet, Action, JSP 등일때

이것들에서 사용하는 View 단에서는 CSS, JS, Image 등을 거의 필연적으로 가져다 쓰게 되는데

이넘들의 경로가 참 애매하더라... 그래서 한번에 정리하기로 맘 먹었다...

지금은 Struts2 기반의 프로젝트를 하고 있는데 이곳에서 사용하는 View 영역에서 JS 와 CSS, Image의 기준 경로가

몇번 헷갈렸는데 명확하게 해결했다.

Action의 Result인 JSP 파일에서 CSS, JS, Image 등을 가져다 쓸때는 [http://host:port/ContextPath] 부터 시작하게 된다.

결과적으로 무조건 ContextRoot를 기준으로 경로를 설정해 주면 된다.

이때 또 하나 헷갈려서 애를 먹였던 것이 CSS 에서 사용하는 아이콘이나 백그라운드 이미지다.

CSS 에서 사용하는 경로의 경우는 무조건 CSS 파일 자신이 기준이다.

자신을 기준으로 사용하는 이미지등이 어디 있는지 상대경로로 표시해주면 정확하게 맞아 떨어진다.

다음부터는 헷갈리지 말아야지.. ㅡ_ㅡ;
Posted by 양군이당
TAG CSS, image, js, Web, 경로

댓글을 달아 주세요

자바/Web2008. 12. 15. 20:29

기고한지 한달이 지나서 SDN에 올라와서 1.0 정식 버전이 발표된 후에야 이 글을 오픈한당. ㅡ_ㅡ;;

암튼 고고고~~~



필자는 작년부터 Web 2.0과 함께 부상한 RIA(Rich Internet Application)에 대해 귀가 따갑게 들어왔다. 필자가 현재 몸담고 있는 JCO내에서도 JCO가 직간접적으로 관여하는 각종 세미나 및 행사에서도 RIA는 큰 화두였으며 지금까지도 관심을 끄는 이슈로 부각되고 있다. 이런 이슈에 호응(?)하기 위해 Sun, Adobe, MS에서 JavaFX, Flex, Silverlight 라는 삼총사를 내놓았다. 세가지를 비교하는 것도 재미있는 일이겠지만 본인은 자바 프로그래머로만 10년 가까이 먹고 살았다. Silverlight는 어떤 것 이라는 것만 아는 편이고 Flex는 약간 끄적거려 보았다. 결국 가장 자신있는 Java 진영에서 나온 JavaFX 를 다루어 보기로 했다.

 

JavaFX를 처음 접한 것은 2007 JavaOne 이 끝난 후였다. 국내 유일의 자바 챔피언인 양수열 고문이(참고로 본인의 친형이다) JavaOne이 끝나고 귀국하고 만난 자리에서 JavaFX가 앞으로 엄청난 발전을 할 것이라고 흥분해서 말했던 기억이 있다. 그 후 몇 가지 관련된 글을 보았었고 2008 JavaOne에 운이 좋게 참석하게 되어 다시 보게 된 JavaFX는 정말 놀라울 정도로 발전해 있었다. 예전에 간단한 Flash ActionScript 같았던 모습에서 Multimedia 쪽이 대폭 강화되어 수많은 동영상이 화면에 Display되면서 자유롭게 떠도는 Demo를 보고 그 놀라운 Performance에 놀라움을 금치 못했다. 그러면서도 Demo가 일반적인 PC에서도 저만큼 가능할까?’ 라는 의문이 들었다. 그래서 결국 만들어 보게 되었으니

 

시작하기

JavaFX를 처음 접하면서 느낀점은 JavaFX 문법이 JavaScript와 상당히 닮아 있다는 점이었다. JavaScript Java의 절묘한 짬뽕(?)이랄까? JavaFX Application을 물론 메모장으로도 개발할 수 있지만 IDE에 길들여진 개발자들이 메모장으로 개발할리가 없다. 그리고 JavaFX를 전면에 내세운 Sun에서도 개발자들이 편하고 능률적으로 개발할 수 있도록 NetBeans 최신버전에 JavaFX plugin을 추가해 놓았다. 이전에는 JavaFX Pad라는 응용 프로그램을 활용했었으나 좀 더 융통성있고 편하게 개발할 수 있도록 NetBeans에 통합해 놓은 것이다. JavaFX Pad에서와 같이 Source Edit 창에서 코드를 변경하면 위쪽 Preview 영역에서 바로 변경된 결과물을 볼 수 있고 오른쪽 팔레트를 이용해 각종 콤포넌트나 노드 이벤트 등을 원클릭으로 소스에 적용할 수 있다.

NetBeans JavaFX plugin 설치는 신상철 박사님이 운영하시는 JavaPassion을 참고하면 편하게 설정할 수 있다. (http://www.javapassion.com/handsonlabs/javafx_basics1/)

 




[JavaFX plugin을 설치하고 실행중인 모습]

본론으로

JavaFX를 이용해 Multimedia 파일을 컨트롤 하기 위해 필요한 정보와 샘플들을 우선 수집하였다. 일차적으로 Sample Code를 몇 개 받아 mp3 파일을 재생하는 테스트 코드를 만들었을 때 mp3 파일은 아주 잘 재생되었다. 하지만 동영상 파일로 바꾸었을 때는 아래와 같은 에러를 발생시켰다.




FX Media Object caught Exception com.sun.media.jmc.MediaUnsupportedException: Unsupported media: file:/D:/Projects/NetBeans/SimpleMovie/build/classes/simplemovie/SoHot.avi

    source ='file:/D:/Projects/NetBeans/SimpleMovie/build/classes/simplemovie/SoHot.avi'

 

Exception의 이름으로 인해 해당 동영상 파일이 FX 에서 지원하지 않는 Media 형식인걸 확인하였고 빠르게 손가락은 구글링을 하여 JavaFX가 지원하는 미디어 포멧을 찾아내었다.

 

JavaFX Media 지원타입

  Container Types:

  ASF (Advanced Systems Format),MPEG-1, AVI (Audio-Video Interleaved),WAVE, MIDI (Standard MIDI)

  Encoding Types:

  WMAUDIO8 (WindowsMedia Audio 2/7/8),WMSCREEN (Windows Media Screen), WMVIDEO9 (Windows Media Video 9), Voxware, MS MPEG-4, WMVIDEO7 (Windows Media Video 7), MPEG11 Video, MPEG-1 Audio, Uncompressed video (RGB/YUV/RLE), PCM, ADPCM, MP3, MIDI

  Protocol Types:

  HTTP, FILE

  Known not to work at present are media with DRM (Digital Rights Management), and media played directly from DVD or CD.

 

Multimedia 파일을 컨트롤 하기 위해서는 항상 Codec이 문제인데 JavaFX에서는 생각보다 많은 종류의 Codec을 지원해주어 특별히 Codec에 신경 쓰지 않아도 되었다. (물론 가지고 있는 많은 수의 동영상은 실행되지 않았다.)

 

몇 가지 문제를 잡아나가면서 만들어 낸 결과물은 CustomNode를 사용해 재사용할 수 있는MediaViewNode를 만들었고 Timeline을 이용해 이 Node Animation 효과를 보여주는 프로그램을 만들어 보았다. 아래 소스를 실행하면 0.2 배율 스케일의 동영상 화면이 정지된 채로 실행되고 클릭시 회전하며 원래 비율로 커지고 실행되는 프로그램이다.

 

 

Source

/*

 * Main.fx

 *

 * Created on 2008. 11. 8, 오후 1:29:49

 */

 

package simplemovie;

 

import javafx.ext.swing.*;

import javafx.scene.*;

import javafx.scene.media.*;

import javafx.scene.effect.*;

import javafx.scene.paint.Color;

 

/**

 * @author eclips

 */

SwingFrame {

    title: "Movie Player"

    width: 800

    height: 600

    closeAction: function() {

        java.lang.System.exit( 0 );

    }

    visible: true

 

    menus: [  ]

 

    content: Canvas {

        width:800

        height:600

        background: Color.WHITE

        content: [

            MediaViewNode {

                // {__DIR__}은 클래스 파일이 있는 디렉토리이다

                mediaURL: "{__DIR__}Nobody.avi"

                viewX: 10

                viewY: 10

            }

        ]

    }

}

 

/*

 * MediaViewNode.fx

 *

 * Created on 2008. 11. 8, 오후 6:48:47

 */

 

package simplemovie;

 

/**

 * @author eclips

 */

 

import java.lang.System;

 

import javafx.scene.CustomNode;

import javafx.scene.*;

import javafx.input.*;

import javafx.scene.media.*;

import javafx.scene.effect.*;

import javafx.scene.paint.Color;

import javafx.scene.geometry.*;

import javafx.scene.transform.*;

import javafx.animation.Timeline;

import javafx.animation.KeyFrame;

import javafx.animation.Interpolator;

 

public class MediaViewNode extends CustomNode {

    /**

     * 동영상 화면의 X Sacle

     */

    public attribute viewScaleX:Number = 0.2;

   

    /**

     * 동영상 화면의 Y Scale

     */

    public attribute viewScaleY:Number = 0.2;

   

    /**

     * MediaViewNode의 회전 반경

     */

    public attribute rotation:Number = 0.0;

   

    public attribute viewX:Number = 50;

    public attribute viewY:Number = 40;

   

    /**

     * 현재 활성화 여부

     */

    private attribute actived:Boolean = false;

    /**

     * 현재 Animation 중인지 여부

     */

    private attribute moving:Boolean = false;

   

    private attribute media:Media;

    private attribute mediaView:MediaView;

   

    private attribute strokeColor:Color = Color.DARKGRAY;

   

    // 동영상 미디어 객체 URL

    public attribute mediaURL:String on replace {

        media = Media {

            source: mediaURL

        };

    }

   

    // Media Player 객체

    private attribute player =

        MediaPlayer {

            media: media,

            autoPlay: false

        }

 

   

    private attribute choiceTimeLine =

    Timeline {

        keyFrames : [

            KeyFrame {

                time: 0ms

                values: [

                    viewScaleX => 0.2,

                    viewScaleY => 0.2,

                    viewX => 10,

                    viewY => 10,

                    rotation => 0.0,

                    moving => true

                ]

            },

            KeyFrame {

                time : 500ms

                values: [

                    viewScaleX => 1.0 tween Interpolator.LINEAR,

                    viewScaleY => 1.0 tween Interpolator.LINEAR,

                    viewX => 40 tween Interpolator.LINEAR,

                    viewY => 40 tween Interpolator.LINEAR,

                    rotation => 360 tween Interpolator.LINEAR,

                    moving => false

                ]

                action: function():Void {

                    player.play();

                    mediaView.toFront();

                    actived = true;

                }

            }

        ]

    };

   

    private attribute unchoiceTimeLine =

    Timeline {

        keyFrames : [

            KeyFrame {

                time: 0ms

                values: [

                    viewScaleX => 1.0,

                    viewScaleY => 1.0,

                    viewX => 40,

                    viewY => 40,

                    rotation => 360,

                    moving => true

                ]

            },

            KeyFrame {

                time : 500ms

                values: [

                    viewScaleX => 0.2 tween Interpolator.LINEAR,

                    viewScaleY => 0.2 tween Interpolator.LINEAR,

                    viewX => 10 tween Interpolator.LINEAR,

                    viewY => 10 tween Interpolator.LINEAR,

                    rotation => 0.0 tween Interpolator.LINEAR,

                    moving => false

                ]

                action: function():Void {

                    player.pause();

                    mediaView.toBack();

                    actived = false;

                }

            }

        ]

    };

   

    public function create():Node {

        Group {

            content: [

                this.mediaView = MediaView {

                    mediaPlayer: player

                    scaleX: bind viewScaleX

                    scaleY: bind viewScaleY

                    translateX: bind viewX

                    translateY: bind viewY

                    transform: bind [Transform.rotate(rotation,200,150)]

 

                    onMouseEntered:

                        function(me:MouseEvent):Void {

                            strokeColor = Color.BLACK

                        }

                    onMouseExited:

                        function(me:MouseEvent):Void {

                            strokeColor = Color.DARKGRAY

                        }

                    onMouseClicked:

                        function(me:MouseEvent):Void {

                            System.out.println("clicked => " + actived);

                            if(moving == false) {

                                if(actived) {

                                    unchoiceTimeLine.start();

                                    System.out.println("inactive - " + viewScaleX);

                                }

                                else {

                                    choiceTimeLine.start();

                                    System.out.println("active - " + viewScaleX);

                                }

                            }

                        }

                },

                Rectangle {

                    width: 708

                    height: 472

                    scaleX: bind viewScaleX

                    scaleY: bind viewScaleY

                    translateX: bind viewX

                    translateY: bind viewY

                    stroke: strokeColor

                    strokeWidth: 10

                    transform: bind [Transform.rotate(rotation,200,150)]

 

                    onMouseEntered:

                        function(me:MouseEvent):Void {

                            strokeColor = Color.BLACK

                        }

                    onMouseExited:

                        function(me:MouseEvent):Void {

                            strokeColor = Color.DARKGRAY

                        }

                }

            ]

        }

    }

}

 

 

실행 결과

 

Clip을 클릭하면 해당 동영상 클립이 회전하면서 1:1 스케일로 커지면서 동영상이 실행된다.

 

 

아쉬운 것들

l  JavaFX Document의 부실함

n  작업을 위해 다운 받아 펼쳐본 Document는 한마디로 부실함이었다. 물론 아직 초기 버전이라 그런 것이라 생각되지만 현재의 Document는 그냥 어떤 것이 있다는 것을 설명하기 위해 만들어 놓은 수준이라고 봐야 할 것 같다. JDK SE 버전의 Document에 비하면 정말 완성도가 떨어졌다.

l  NetBeans JavaFX plugin

n  미디어 이름에 한글이 들어가거나 공백이 있을 경우 실행시 에러가 발생한다.

n  실시간으로 코딩시 에러 내용이 표시되는데 간혹 이런 에러 내용이 잘못 표시되는 문제

n  미디어의 이름을 바꿀 경우 간혹 미디어 적용이 안되 Rebuild 해야하는 불편함

n  소스에서 사용되는 클래스에 대해 자동으로 import 되지 않는 불편함

 이런 문제들은 앞으로 JavaFX 1.0 정식 버전이 나오고 plugin이 업그레이드 되면서 점점 좋아질 것이라고 생각하지만 아직까지는 약간의 불편함을 감수하고 개발해야 한다.

 

JavaFX로 간단한 동영상 실행 Application을 만들면서 어떻게 이렇게 간단할 수 있지? 하는 생각이 들었다. 이해하기 쉬운 코드 몇 줄로 꽤 대단한 애니메이션 효과를 줄 수 있었고 동영상 플레이도 코드 몇 줄로 끝났다. 자바 Application으로 만들려 했으면 엄청난 소스 코드 속에서 헤메야 간신히 나올만한 프로그램을 JavaFX의 스크립트 몇 줄이 해낸것이다. 물론 이런 힘이 JavaFX 에만 있는 것이 아니다. JavaFX가 경쟁하고 있는 Flex Silverlight도 비슷한 수준으로 지원하고 있거나 더 월등히 앞선 기능과 툴을 지원하고 있기도 하다. 지금 현재도 간단한 Application은 만들기 너무 쉽지만 정식 버전이 나올 시점이 되면 지금보다 모든 면에서 더욱 편하고 강력해져야 할 거라고 생각한다. 위쪽에서 지적한대로 Document도 현재 JDK 만큼 완성도가 높아져야 하며 IDE의 발전과 JavaFX가 적용될 수 있는 Platform도 더욱 넓어진다면 다양한 분야에서 JavaFX 가 활약하는 것을 볼 수 있을거라 생각한다.

 

참조사이트

http://www.javapassion.com/javafx/

http://www.javafx.com

http://java.sun.com/javafx/index.jsp

http://openjfx.dev.java.net

 

Posted by 양군이당

댓글을 달아 주세요

자바/Web2008. 12. 9. 17:19
아직 SDNKorea blog 에 올라가진 않았지만 JavaFX 를 이용해 동영상을 실행하는 글을 기고 했다.

해당 원고를 쓸때까지만 해도 JavaFX 가 정식이 아니었는데 오늘 간만에 들어가서 둘러보니

1.0 정식 버전이 릴리즈 되었다.

정식 전버전에는 정말 눈물날 정도로 API가 부실하고 자료도 없었는데

이번에 정식 릴리즈 되면서 다양한 샘플과 코드가 제공되고 무엇보다 달랑 한줄이나 설명도 안 붙어 있던 API가

정식으로 뜨면서 많이 정리가 되었다...

차라리 1.0 나온 다음에 기고를 할걸 그랬납다... ㅡ_ㅡ;;

JavaFX Script는 YahooUI 스크립트와 상당히 유사하게 닮아 있는데 이녀석이 Swing쪽과 짬뽕되면서

좀 더 복잡해져버려서 많이 헷갈렸는데 그나마 이제 API도 정리되고 샘플도 많이 생겨서 다행이다.

아래는 새로 나온 JavaFX 데모 캡쳐...




'자바 > Web' 카테고리의 다른 글

Web Project 에서 View에서 사용하는 파일에 대한 경로 설정 기준  (0) 2009.06.02
[SDN 기고] JavaFX 와 Multimedia  (0) 2008.12.15
드디어 JavaFX 1.0 정식 Release...  (0) 2008.12.09
Eclipse Ganymede 출동~  (0) 2008.07.02
JSON  (0) 2008.06.26
JSON vs XML  (0) 2008.06.26
Posted by 양군이당
TAG 1.0, JAVAFX

댓글을 달아 주세요

자바/Web2008. 7. 2. 00:12
사용자 삽입 이미지


Eclipse 새버전이 얼마전에 나왔다... 나온날 깔아봤는데 겉보기 상으로 달라진건 Splash 이미지 정도??

ㅎㅎ 내부적으로는 24개 정도의 plugin 이 추가되었다고 한다. 그리고 아래는 좋아졌다는 부분...

이중에 검색및 바꾸기에 정규표현식을 쓸수 있게 되었다는게 좀 와닿는 부분 같다...

전체
 - Editor 탭을 마우스 가운데 버튼 클릭으로 현재 문서를 닫을 수 있음
 - 찾기/바꾸기에서 정규식을 쉽게 쓸 수 있게 되었음
 - debugging 시에 변수를 watch 창으로 Drag & Drop 가능

CDT 5.0
 - file template 기능을 통해 New Class 를 했을 때 기본 코드를 지정할 수 있음
 - include 를 할 때 Ctrl+Space(Content Assist) 를 하면 쉽게 include 파일명을 넣을 수 있음
 - for, while, if 문등의 block 도 folding 할 수 있음
 - 단축키 설정에서 Scheme 에 "Microsoft Visual Studio" 가 추가되어 쉽게 단축키 설정을 할 수 있음
 - Rename 밖에 없던 C++ Refactoring 기능에 다음과 같은 기능들이 추가되었다.
  - Getter/Setter 생성
  - 함수 숨기기(private 로 이동)
  - Implement Method(함수 선언부에서 선택시 함수 구현부 생성)
  - Extract Constant
  - Extract Function
 - Indexer 향상(여러 상황 지원, 속도 향상)
 - Ensure newline at end of file 옵션이 기본적으로 켜져 있어서, 파일의 마지막 줄에 빈 줄을 넣지 않아서 warning 이 뜨는 현상을 위해 옵션을 고치지 않아도 된다.

자바
 - 숫자를 따로 하이라이트해준다.
 - 변수를 읽기/쓰기 하는 부분을 따로 표시할 수 있게 해준다(디버깅할 때 편할듯)
 - 멀티CPU 를 통해 30% 까지 속도 향상이 있다.
 - Java String 을 StringBuffer 로 컨버트

SWT
 - 3개의 상태를 가지는 체크 버튼(on/off 외에 중간 상태가 추가)
 - 윈도우 비스타에서의 native progress bar 지원
 - 이미지와 url 에 대한 Drag & drop 지원
 - 전체 화면 지원
 - 투명도(Alpha, Transparent) 지원

기타
 - (Beta인 셈이지만)Subversion 을 위한 Provider 제공(Help -> Software Updates -> Available Software 에서 Ganymede Update Sites -> Collaboration Tools -> SVN Team Provider 에서 설치)

출처 : http://link.allblog.net/11939288

'자바 > Web' 카테고리의 다른 글

[SDN 기고] JavaFX 와 Multimedia  (0) 2008.12.15
드디어 JavaFX 1.0 정식 Release...  (0) 2008.12.09
Eclipse Ganymede 출동~  (0) 2008.07.02
JSON  (0) 2008.06.26
JSON vs XML  (0) 2008.06.26
XML과 JSON 사이에 변환 패턴  (0) 2008.06.26
Posted by 양군이당

댓글을 달아 주세요

자바/Web2008. 6. 26. 02:26
원문 http://blog.naver.com/forioso/10009590986

1 문서 개요 #

  • 작성일 : 2006/04/04
  • 작성자 : http://www.0bin.net/moniwiki/wiki.php/Specification/OPML?action=download&value=mail.png
  • 문서 내용 : AJAX XMLHTTPREQUEST에서 데이터 교환 형식으로 사용되는 JSON에 대한 정리

2 개요 #

  • Javascript Object Notation.
  • lightweight data 교환 형식.
  • 사람이 읽고 쓰기 쉬움.
  • 기계가 파싱하고 생성하기 쉬움.

3 형식 #

3.1 Object #

  • 중괄호({})로 시작하고 끝남
  • member : 문자열과 값으로 구성되어 있고 콜론(:)으로 구분, 각 멤버들은 콤마(,)로 구분
  • array : 대괄호([])로 시작하고 끝나며 각 값은 콤마(,)로 구분
  • value : 값은 string, number, object, array, true, false, null 사용 가능
  • string : 문자열은 쌍따옴표(")로 둘러 쌓여야 하며 Unicode character 또는 일반적인 escape 문자(\", \\, \/, \b, \f, \n, \r, \t, \u four-hex-digits)를 포함한다.
    oav.gif
    sn.gif

3.2 예시 #

{

"Image": {

"Width":800,

"Height":600,

"Title":"View from 15th Floor",

"Thumbnail":{

"Url":"http:/\/scd.mm-b1.yimg.com\/image\/481989943",

"Height": 125,

"Width": "100"

},

"IDs":[ 116, 943, 234, 38793 ]

}

}
  • 출처 : Yahoo JSON 예제
  • 예제에서 Image는 최상위 object이고 모든 다른 데이터들은 이 object의 멤버.
  • Width, Height, Title는 숫자와 문자열 데이타를 포함하고 있는 기본적인 멤버.
  • Thumbnail은 Url, Height, Width를 멤버로 포함하고 있는 중첩 object.
  • ?IDs는 숫자 값을 가지고 있는 array.
  • Url 문자열 값에서 슬래쉬(/)가 escape 됨에 주의

4 참고 사이트 #

'자바 > Web' 카테고리의 다른 글

드디어 JavaFX 1.0 정식 Release...  (0) 2008.12.09
Eclipse Ganymede 출동~  (0) 2008.07.02
JSON  (0) 2008.06.26
JSON vs XML  (0) 2008.06.26
XML과 JSON 사이에 변환 패턴  (0) 2008.06.26
JavaScript 객체 JSON  (0) 2008.06.26
Posted by 양군이당
TAG JSON

댓글을 달아 주세요