Netbeans에서도 Google App Engine플러그인을 설치해서 개발할 수 있습니다.
하지만, 구글에서 공식적으로 제공하는 플러그인이 아니라 누가 만든 것 같네요.

이곳에서 보고 설치 및 샘플을 실행할 수 있습니다.

아.....이건 상관없는 그림이지만, 그림을 보면 볼수록 왠지 슬퍼지는데요.
오늘 권순선님 미투데이에서 발견했습니다-_-
사용자 삽입 이미지

Java를 낳고 돌아가신 Sun이군요-_- 오라클이 인수하는 걸 EC에서 승인했다더군요.



암튼 대충 따라해보면...

1. 플러그인 설치
Tools -> Plugins -> Settings -> Add -> Name에 App Engine이라고 하고, URL에 아래 주소를 입력
그러면 Available Plugins에 5개의 Google App Engine플러그인이 생김. 체크해서 설치 고고싱

2. SDK다운로드
여기서 자바용으로 받아서 적당한 폴더에 풀어주면 됨 ㄷㄷ

3. Google App Engine 서버 설정
넷빈즈에서 Services탭에서 Servers에서 마우스 오른쪽버튼 클릭 후 Add Server선택
Google App Engine을 선택한 뒤, 위에서 받은 sdk폴더 경로 지정. 포트는 맘에 드는걸로 하면 끝남

4. 새로운 프로젝트 생성
New 프로젝트 -> Java Web -> Web Application -> Project Name은 HelloGoogleAppEngine -> Server는 Google App Engine -> Finish하면 끝남.
F6을 눌러서 실행하면 Hello World 볼 수 있음 ㄷㄷ

5. 배포
배포 시 Web Pages -> WEB-INF -> appengine-web.xml파일에서 Application Name을 자신이 얻은 Name으로 수정하고 해야함.

그런데 배포 시 약간 문제가 있음.
아무것도 안건드렸다고해도 이런 에러를 보게 될 꺼임.
[code]java.lang.IllegalStateException: cannot find javac executable based on java.home, tried "C:\Program Files\Java\jre6\bin\javac.exe" and "C:\Program Files\Java\bin\javac.exe"
Unable to update app: cannot find javac executable based on java.home, tried "C:\Program Files\Java\jre6\bin\javac.exe" and "C:\Program Files\Java\bin\javac.exe"
Please see the logs [C:\Users\mudchobo\AppData\Local\Temp\appcfg7950519452562723725.log] for further information.[/code]
javac파일을 java\bin에서 찾는 것 같음. 거기엔 javac.exe파일이 없음. java.home위치를 수정하는 법을 몰라서, 검색해보니 그냥 그 폴더에 javac.exe를 복사하는 거임. tools.jar파일도 lib폴더에 같이 복사해야함 ㄷㄷ

제꺼기준으로
C:\Program Files\Java\jdk1.6.0_17\bin\javac.exe파일을 -> C:\Program Files\Java\jre6\bin에 복사.
C:\Program Files\Java\jdk1.6.0_17\lib\tools.jar파일을 -> C:\Program Files\Java\jre6\lib\폴더에 복사.

그러면 잘 될꺼임.

ps. 결론은.......그냥 이클립스 플러그인 쓰는 게 나아요. 그건 GWT연동도 되거든요-_- 이런 짓을 하면서 까지 넷빈즈에서 개발하고 싶진 않은 듯. 공식으로 지원하는 플러그인으로....-_- 이클립스가 짱인 듯.
 
Posted by 머드초보
,
 
아주 오래전에 Hibernate xml로 삽질했던 기억이 있는데, Annotation으로 해보겠다는 게 세월(?)이 벌써 이렇게 흘렀군요.

하이버네이트는 셋팅이 참 어렵군요. 책을 보면 그냥 hibernate함수를 이용해서 어떻게 이용하는지, 하이버네이트의 특성이 주로 나와있는데, 셋팅에 대한 삽질은 좀 자세하지 않은 듯(내가 못본 것일 수도 있음-_-)

NetBeans 6.8에서 삽질했습니다.
넷빈즈다운로드 : http://netbeans.org/downloads/index.html

일단 소녀시대 테이블만 하나 만들어 놓읍시다.
테이블은 sosi랑 schedule 2개가 1:N의 관계형태로 만드려고 합니다. (DB쪽에 취약해서 맞는지 모르겠네-_- 뭐 다취약하지만-_-)
[code]
DROP TABLE IF EXISTS `sosi`;
CREATE TABLE IF NOT EXISTS `sosi` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `birthYear` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=10 ;

INSERT INTO `sosi` (`id`, `birthYear`, `name`) VALUES
(1, 1989, '효연'),
(2, 1990, '윤아'),
(3, 1990, '수영'),
(4, 1989, '유리'),
(5, 1989, '태연'),
(6, 1989, '제시카'),
(7, 1989, '티파니'),
(8, 1990, '써니'),
(9, 1991, '서현');
[/code]

1. 프로젝트 생성
File -> New Project(Ctrl + Shift + N) -> Java -> Java Application -> Project이름은 SosiSchedule

2. 하이버네이트 설정파일 셋팅
 Ctrl + N을 눌러서 새로운 파일을 만듭니다. SosiSchedule을 선택하고, Hibernate -> Hibernate Configuration Wizard선택, File Name은 hibernate.cfg 디폴트로, Database는 자신이 셋팅하고 sosi테이블을 만들어놓은 Mysql 데이터베이스를 선택합니다. 안만들었으면 New Database Connector를 선택해서 Host, Port, Database, User Name Password를 입력하면 됩니다. 이거 하면 자동으로 Library가 추가되나봅니다.
설정 파일이 만들어졌어요. 근데, 하이버네이트에서는 src최상위 폴더에 넣으면 자동으로 설정파일을 인식하나봐요. 설정파일 경로 지정하는 부분이 없는 것 같은데-_-
테이블 자동생성 및 날라가는 sql을 보기위해 아래 두옵션을 추가합니다.
[code]<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>[/code]

3. HibernateUtl만들기
Ctrl + N을 눌러서 새로운 파일 작성 -> Hibernate -> HibernateUtl.java, ClassName은 HibernateUtl로 package는 sosischedule.util로 finish!

4. 매핑할 ENTITY클래스 작성
일단 entity클래스는 database에 table이 존재하면 자동으로 만들 수 있습니다.
Ctrl + N을 눌러서 새로운 파일 작성 -> Persistence -> Entity Classes  from Database 선택.
Database Connection에서 셋팅한 mysql선택하면  테이블명이 나오는데, sosi테이블을 Add합니다.
package는 알아보기 쉽게 sosischedule.entity로 하고 finish를...-_-
이쁘게 소스가 만들어지네요.
Sosi.java
[code]/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sosischedule.entity;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author mudchobo
 */
@Entity
@Table(name = "sosi")
@NamedQueries({
    @NamedQuery(name = "Sosi.findAll", query = "SELECT s FROM Sosi s"),
    @NamedQuery(name = "Sosi.findById", query = "SELECT s FROM Sosi s WHERE s.id = :id"),
    @NamedQuery(name = "Sosi.findByBirthYear", query = "SELECT s FROM Sosi s WHERE s.birthYear = :birthYear"),
    @NamedQuery(name = "Sosi.findBySosiName", query = "SELECT s FROM Sosi s WHERE s.sosiName = :sosiName")})
public class Sosi implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id")
    private Long id;
    @Basic(optional = false)
    @Column(name = "birthYear")
    private int birthYear;
    @Column(name = "sosiName")
    private String sosiName;

    public Sosi() {
    }

    public Sosi(Long id) {
        this.id = id;
    }

    public Sosi(Long id, int birthYear) {
        this.id = id;
        this.birthYear = birthYear;
    }

    public Long getId() {
        return id;
    }

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

    public int getBirthYear() {
        return birthYear;
    }

    public void setBirthYear(int birthYear) {
        this.birthYear = birthYear;
    }

    public String getSosiName() {
        return sosiName;
    }

    public void setSosiName(String sosiName) {
        this.sosiName = sosiName;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Sosi)) {
            return false;
        }
        Sosi other = (Sosi) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "sosischedule.entity.Sosi[id=" + id + "]";
    }

}
[/code]
각각의 어노테이션들은 구글링을 통해 찾아보는걸로 저도 잘 몰라서-_-
Annotation기반으로 하기전에는 mapping xml파일을 작성했는데, 그걸 그냥 클래스에 보기좋게 해놓은 거라고 보면 될 듯.

스케쥴 클래스는 직접 만들어봅시다.
Ctrl + N을 통해 새로운 파일생성, Persistence -> Entity Class, Class Name은 Schedule, package는 sosischedule.entity선택 후 finish.
그러면 id만 달랑 있습니다. 여기에 칼럼을 만들어 봅시다. 많이 만들면 귀찮아 지니까-_- program명과 소시객체 연동하는 것만 만들어봅시다.
[code]private String program;
private Sosi sosi;[/code]입력하고, Alt + Insert하면 getter, setter자동생성기로 만듭니다.
사실 이렇게만 만들어 놓아도 테이블이 생성됩니다-_- 다 디폴트로 만들어서. 귀찮으니까 이렇게만 만들고 맙시다-_- 아 그리고, 생성자를 두개 추가했습니다. 기본생성자와 property를 세팅해서 만들어주는 생성자.
그리고 테이블과 관계를 맺기 위해 @ManyToOne을 넣어줘야합니다. 안 넣어주면 무슨 Blob으로 그냥 저장해버리는..-_-
Schedule.java
[code]package sosischedule.entity;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Schedule implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String program;

    @ManyToOne
    private Sosi sosi;

    public Schedule() {
    }

    public Schedule(String program, Sosi sosi) {
        this.program = program;
        this.sosi = sosi;
    }

    public Sosi getSosi() {
        return sosi;
    }

    public void setSosi(Sosi sosi) {
        this.sosi = sosi;
    }

    public Long getId() {
        return id;
    }

    public String getProgram() {
        return program;
    }

    public void setProgram(String program) {
        this.program = program;
    }

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

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Schedule)) {
            return false;
        }
        Schedule other = (Schedule) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "sosischedule.entity.Schedule[id=" + id + "]";
    }
}
[/code]
오...이저 hibernate.cfg.xml파일을 열어서 매핑파일이라고 추가합니다.
hibernate.cfg.xml
[code]<mapping class="sosischedule.entity.Sosi"/>
<mapping class="sosischedule.entity.Schedule"/>[/code]
작성한 클래스 두개. 이제 hql을 날릴 수 있어요. hibernate.cfg.xml파일을 선택 후 오른쪽버튼을 누르면 "Run HQL Query"라는 메뉴가 나와요.
from Sosi때리면 소시멤버데이터가 나오네요.
※여기서 해당 프로젝트에 대해서 한번이라도 run을 때리지 않으면 Sosi is not mapped라고 나오네요. 안되면 한번 실행하고 해보세요.
사용자 삽입 이미지
이제 다 된 것 같으니 dao와 service를 만들어봅시다.

5. Dao생성
sosischedule.dao.SosiScheduleDao.java파일을 생성
SosiScheduleDao.java
[code]package sosischedule.dao;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import sosischedule.entity.Schedule;
import sosischedule.entity.Sosi;
import sosischedule.util.HibernateUtil;

public class SosiScheduleDao {

    public List<Sosi> getSosiList() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Query q = session.createQuery("from Sosi");
        List<Sosi> list = q.list();
        session.close();

        return list;
    }

    public Sosi getSosi(int sosiId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Sosi sosi = (Sosi) session.get(Sosi.class, new Long(sosiId));
        session.close();

        return sosi;
    }

    public List<Schedule> getSchedule(Long sosiId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Query q = session.createQuery("from Schedule s where s.sosi.id = " + sosiId);
        List<Schedule> list = q.list();
        session.close();

        return list;
    }

    public void addSchedule(Schedule schedule) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        session.save(schedule);
        tx.commit();
        session.close();
    }

    public void removeSchedule(int scheduleId) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = session.beginTransaction();
        Schedule schedule =
                (Schedule) session.load(Schedule.class, new Long(scheduleId));
        session.delete(schedule);
        tx.commit();
        session.close();
    }
}
[/code]
음....분명 이렇게 하는 건 아닌 것 같아-_- 암튼, 일단 셋팅이 목적이니-_- 대충 이렇게도 할 수 있다는 것을..-_-
getSosiList는 소시리스트를 가져오고, getSosi는 소시를 가져오고, getSchedule은 스케쥴리스트를 가져오고, addSchedule은 스케쥴추가하고, removeSchedule은 스케쥴을 삭제하고...

6. 서비스생성
이걸 사용할 서비스를 만들어봅시다.
sosischedule.service.SosiScheduleService.java
[code]package sosischedule.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import sosischedule.dao.SosiScheduleDao;
import sosischedule.entity.Schedule;
import sosischedule.entity.Sosi;

public class SosiScheduleService {

    private SosiScheduleDao sosiScheduleDao = new SosiScheduleDao();

    public void menuSosi() {
        List<Sosi> sosiList = sosiScheduleDao.getSosiList();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        while(true){
            try {
                for (Sosi sosi : sosiList) {
                    System.out.println(sosi.getId() + "." + sosi.getSosiName());
                }
                System.out.println("번호를 입력하세요!(0은 종료) => ");
                int menuNum = Integer.parseInt(br.readLine());
                if (menuNum == 0){
                    System.out.println("종료!");
                    break;
                }
                // 소시데이터 가져오기
                Sosi sosi = sosiScheduleDao.getSosi(menuNum);
                if (sosi != null){
                    menuSchedule(sosi);
                    break;
                } else {
                    System.out.println("없는 번호입니다.");
                }

            } catch (IOException ex) {
                Logger.getLogger(SosiScheduleService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void menuSchedule(Sosi sosi) {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        while(true){
            try {
                List<Schedule> scheduleList = sosiScheduleDao.getSchedule(sosi.getId());
                for (Schedule schedule : scheduleList) {
                    System.out.println(schedule.getId() + "." + schedule.getProgram());
                }
                if (scheduleList.size() <= 0){
                    System.out.println("스케쥴이 없습니다.\n");
                }
                System.out.println("1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>");
                int menuNum = Integer.parseInt(br.readLine());
                if (menuNum == 0) {
                    System.out.println("뒤로!");
                    menuSosi();
                    break;
                }
                else if (menuNum == 1) {
                    System.out.println("스케쥴명 입력 : ");
                    String program = br.readLine();
                    System.out.println("스케쥴 = " + program);
                    sosiScheduleDao.addSchedule(new Schedule(program, sosi));
                    System.out.println("추가완료!");
                }
                else if (menuNum == 2) {
                    System.out.println("스케쥴번호 : ");
                    int scheduleId = Integer.parseInt(br.readLine());
                    sosiScheduleDao.removeSchedule(scheduleId);
                    System.out.println("삭제완료!");
                }
            } catch (IOException ex) {
                Logger.getLogger(SosiScheduleService.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}[/code]
메인에서 이렇게 사용하면 됩니다.
Main.java
[code]package sosischedule;

import sosischedule.service.SosiScheduleService;

public class Main {

    public static void main(String[] args) {
        SosiScheduleService sosiScheduleService = new SosiScheduleService();
        sosiScheduleService.menuSosi();
    }
}
[/code]

결과
[code]Hibernate: select sosi0_.id as id0_, sosi0_.birthYear as birthYear0_, sosi0_.sos
iName as sosiName0_ from sosi sosi0_
1.효연
2.윤아
3.수영
4.유리
5.태연
6.제시카
7.티파니
8.써니
9.서현
번호를 입력하세요!(0은 종료) =>
5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
스케쥴이 없습니다.

1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
1
스케쥴명 입력 :
태연의 친한친구
스케쥴 = 태연의 친한친구
Hibernate: insert into Schedule (program, sosi_id) values (?, ?)
추가완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
1
스케쥴명 입력 :
태연의 친한친구2
스케쥴 = 태연의 친한친구2
Hibernate: insert into Schedule (program, sosi_id) values (?, ?)
추가완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
4.태연의 친한친구2
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>
2
스케쥴번호 :
4
Hibernate: select schedule0_.id as id1_1_, schedule0_.program as program1_1_, sc
hedule0_.sosi_id as sosi3_1_1_, sosi1_.id as id0_0_, sosi1_.birthYear as birthYe
ar0_0_, sosi1_.sosiName as sosiName0_0_ from Schedule schedule0_ left outer join
 sosi sosi1_ on schedule0_.sosi_id=sosi1_.id where schedule0_.id=?
Hibernate: delete from Schedule where id=?
삭제완료!
Hibernate: select schedule0_.id as id1_, schedule0_.program as program1_, schedu
le0_.sosi_id as sosi3_1_ from Schedule schedule0_ where schedule0_.sosi_id=5
Hibernate: select sosi0_.id as id0_0_, sosi0_.birthYear as birthYear0_0_, sosi0_
.sosiName as sosiName0_0_ from sosi sosi0_ where sosi0_.id=?
3.태연의 친한친구
1.스케쥴추가 2.스케쥴삭제 0.뒤로 =>[/code]
와....잘된다....-_-
 
Posted by 머드초보
,
 
[code]package test;

import java.awt.Image;
import java.net.URL;

import javax.imageio.ImageIO;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            URL url = new URL("http://wstatic.naver.com/w9/lg_naver_v3.gif");
            Image image = ImageIO.read(url);
            int width = image.getWidth(null);
            int height = image.getHeight(null);
            System.out.println("width = " + width + ", height = " + height);
           
        } catch (Exception e) {
            System.out.println("파일이 없습니다.");
        }
    }

}
[/code]

 
Posted by 머드초보
,
 
구글 앱 엔진이 자바를 지원하기 시작했습니다.
전 세계적으로 가장 인기있는(?) 언어인 자바를 지원하다니 대단합니다-_-(사실...파이썬 보다 자바나 PHP를 먼저 지원했어야 했을 것 같은데-_- 그때 얘기를 들어보니 앱엔진 담당하는 사람이 파이썬 전문가라는 얘기를 들은 것 같군요-_-)

거기에 더 대단한 것은 파이썬 같은 경우에는 툴 같은 것이 없었는데, 이번엔 이클립스를 이용한 툴까지 제공해줍니다. 구글플러그인인데요. App Engine JAVA SDK랑 덤으로 Web Toolkit SDK까지 깔아주는군요. 게다가 구글 앱엔진에 쉽게 배포까지 할 수 있습니다.

이클립스 설치주소 : http://dl.google.com/eclipse/plugin/3.4 (3.3버전은 뒤에 3.3-_-)
참조문서 : http://code.google.com/intl/ko-KR/appengine/docs/java/tools/eclipse.html

설치를 하게 되면 File -> New -> Other에 보시면 Google이라는 폴더에 Web Application Project라는 프로젝트가 있습니다. 이걸 선택하게 되면 아래와 같은 화면이 나옵니다.
사용자 삽입 이미지
Web Toolkit은 체크를 안해도 됩니다.

프로젝트가 완성이 되면 익숙한(?) 폴더구조를 볼 수 있습니다. src는 java소스부분이 들어가는 곳이고, war부분은 WebContent부분이군요. 안에 더욱 익숙한 WEB-INF도 있어요-_- 라이브러리 마구 처박아도 되나-_- web.xml도 있군요.

자 그럼, 손쉬운 배포를 해봅시다. 갓난애기도 할 수 있는 앱엔진 배포!(과연..-_-)
war -> WEB-INF폴더에 appengine-web.xml파일을 엽니다.
[code]<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>mudchobo</application>
    <version>1</version>
   
    <!-- Configure java.util.logging -->
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
    </system-properties>
   
</appengine-web-app>[/code]
<application>부분에 자신이 애플리케이션 생성 시 입력한 Application Identifier를 입력합니다.

그리고, 프로젝트에 대고, 마우스오른쪽 버튼을 누르면 Google이라는 메뉴가 있습니다.
Deploy to App Enigne이라는 메뉴를 선택합니다.
사용자 삽입 이미지
자신의 App Engine계정을 입력하면 바로 배포할 수 있습니다.

http://mudchobo.appspot.com/ 여기에 배포가 되었습니다.

Spring 등의 라이브러리도 다 되는거겠죠?-_- 이번 연휴에 삽질을 해봐야겠습니다.

PS. 혹시나 파일의 용량제한이 있나테스트해봤더니 10메가 이상파일은 안올라가네요.
Unable to upload app: Found a file too large to upload: "C:\Users\mudchobo\AppData\Local\Temp\appcfg3803788145857696233.tmp\Aptana Studio.zip".  Must be under 10000000 bytes.
 
Posted by 머드초보
,
 
오픈아이디에서 제공하는 추가정보(이메일, 닉네임, 생일 등)를 얻어오려면 Simple Registration Extension를 이용해서 가져와야합니다. (OpenID4java에 들어있는 Servlet예제를 보면 Attribute Exchange로 하는데, 이걸로 하면 안되더군요-_-; 그래서 Outsider님의 블로그의 글을 참조를 했습니다.
http://blog.outsider.ne.kr/170

만약 myid.net에 한글 닉네임이 있는 경우에는 가져올 때 URL을 통해서 가져오는데요.
URL이 UTF-8로 되어있고, encodeURI해서 오는데, 이것을 제대로 decode를 못해줘서 인증에 실패를 하더군요.

가져올 때
[code]ParameterList response = new ParameterList(httpReq.getParameterMap());[/code]
이렇게 해서 가져오면 한글인 경우 문제가 발생합니다.
Verification failed for: null reason: null 이런 에러를 발생하는데, 디버깅할 때 parameterList에 있는 한글로 받아야하는 닉네임이 있다면 깨져서 나올겁니다.
그래서 제가 임의로 url을 URIDecoder로 decode를 해서 nickname을 한글로 바꿨더니 인증이 되더군요.
다른 방법을 찾다가 MyID담당자님께 물어봤더니 아래와 같은 방법을 가르쳐주셨습니다 ^^

아래와 같이 파라메터를 얻어오면 됩니다.
[code]ParameterList paramList = ParameterList.createFromQueryString(request.getQueryString());[/code]
이렇게 하니까 되더군요.

알려주신 MyID의 수호이님 감사합니다 ^^

 
Posted by 머드초보
,