앱엔진에 뭔가 제 사이트를 만들고 싶어서 이렇게 삽질을 하고 있는데, 망할 제한이 왜이렇게 많지-_-

암튼, "구글 앱 엔진"에서는 JPA를 지원합니다. 하지만, 이상하게도 잘 안됩니다-_- 굉장히 제한적으로 이것저것 막아둔 것 같습니다. 사실 구글 앱 엔진에서는 DataBase를 BigTable인지 뭐시기인지 그걸 사용하고, 직접적으로 접근을 못하기 때문에(전부 프로그래밍 또는 관리페이지(관리페이지도 매우 제한적인-_-)에서만 관리 가능), 이걸 이용하는 API에서도 엄청나게 뭔가 막아둔 것 같습니다.
뭐 좀 해보려고 하면 에러를 내뱉습니다. 검색해보면 구글앱엔진에서만 나는 에러입니다-_- 사실 아직 구글앱엔진이 프리뷰버전이기에 뭐라 따지지도 못하는 게 사실입니다^^ 정식버전(언제나오려나....Beta딱지 떼는데 10년넘게 걸리겠지-_-)나오면 매우 안정화가 되지 않을까 싶습니다^^

암튼, Spring3 + JPA의 조합으로 앱엔진에 올리는 건 성공했는데, 사실 스프링에서 제공하는 TransactionManager를 사용했어야 했는데, JPATemplate으로 뭔가 처리를 하면 잘 안되더군요-_- 일단 가져오고, persist하고, 이런건 잘 되는데, 왜 삭제가 안될까요-_- 삭제가 안되서 그냥JPATemplate빼고 했습니다-_-
JPATemplate사용해서 성공하신 분 트랙백좀 ㅠㅠ

0. 환경
Eclipse 3.5 + Google AppEngine Plugin + Spring 3.0.0
일단 스프링3다운로드 - http://www.springsource.org/download

1. 프로젝트 생성
New Project -> Google에 있는 Web Application Project 선택.
Project Name은 SosiSchedule. package는 com.mudchobo.
Use Google Web Toolkit은 체크해제. 사용안할꺼라....(이것도 언제한번 공부해야하는데-_-)
Finish.

2. 라이브러리 복사 및 build path추가
spring3에서는 spring.jar가 산산조각 났어요. 필요한 것만 넣으면 되는 듯.
일단 제가 사용한 것은....
org.springframework.asm-3.0.0.RELEASE.jar
org.springframework.beans-3.0.0.RELEASE.jar
org.springframework.context-3.0.0.RELEASE.jar
org.springframework.core-3.0.0.RELEASE.jar
org.springframework.expression-3.0.0.RELEASE.jar
org.springframework.orm-3.0.0.RELEASE.jar
org.springframework.web.servlet-3.0.0.RELEASE.jar
org.springframework.web-3.0.0.RELEASE.jar
그리고, jstl을 사용할 것이기에....
jstl.jar와 standard.jar
※이번버전에서는 lib폴더가 없습니다-_- 어디서 찾아야하는 거지-_- 암튼 그래서 2.5.6버전에서 가져왔습니다^^

앱엔진에서는 lib폴더 복사로 libpath가 잡히지 않네요. 그래서 각각 다 추가해줘야한다는...-_-
일단 war/WEB-INF/lib폴더에 복사 후에 복사한 파일 선택 후 오른쪽버튼 후, Build Path -> Add to Build Path 선택하면 됩니다^^

3. web.xml파일 수정
web.xml
[code]<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/sosischedule/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
</welcome-file-list>[/code]
일단 sosischedule/*요청은 spring이 받습니다.

4. dispacher-servlet.xml파일과 persistence.xml파일 생성
war/WEB-INF/폴더에 생성
dispatcher-servlet.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.mudchobo" />
   
    <bean id="entityManager"
        factory-bean="EMF"
        factory-method="get" />
   
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
</beans>[/code]

src/META-INF/ 폴더에 생성
persistence.xml
[code]<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
   
    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>
</persistence>[/code]

5. EMF클래스 생성.
이제 jpa접근할 수 있는 EntityManagerFactory클래스(EMF)를 생성해봅시다.
com.mudchobo.sosi.sosischedule.dao.EMF.java
[code]package com.mudchobo.sosischedule.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.springframework.stereotype.Component;

@Component
public final class EMF {
     private static final EntityManagerFactory emfInstance =
        Persistence.createEntityManagerFactory("transactions-optional");

    private EMF() {}

    public EntityManager get() {
        return emfInstance.createEntityManager();
    }
}[/code]

6. Entity클래스 생성
일단 Sosi와 Schedule이라는 Entity를 생성할 건데요. 둘의 관계는 1:N관계입니다.
com.mudchobo.sosischedule.entity.Sosi.java
[code]package com.mudchobo.sosischedule.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

import com.google.appengine.api.datastore.Key;

@Entity
public class Sosi implements Serializable {
    private static final long serialVersionUID = 5448408922872112420L;

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Key key;
   
    private String sosiName;
   
    @OneToMany(mappedBy="sosi", cascade=CascadeType.ALL)
    private List<Schedule> scheduleList = new ArrayList<Schedule>();

    public Key getKey() {
        return key;
    }

    public void setKey(Key key) {
        this.key = key;
    }

    public List<Schedule> getScheduleList() {
        return scheduleList;
    }

    public void setScheduleList(List<Schedule> scheduleList) {
        this.scheduleList = scheduleList;
    }

    public String getSosiName() {
        return sosiName;
    }

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

    public Sosi() {
       
    }
   
    public Sosi(Key key, String sosiName) {
        super();
        this.key = key;
        this.sosiName = sosiName;
    }
}[/code]
com.mudchobo.sosischedule.entity.Schedule.java
[code]package com.mudchobo.sosischedule.entity;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

@Entity
public class Schedule implements Serializable{
    private static final long serialVersionUID = -8676837674549793653L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;
   
    private String program;
   
    @ManyToOne(fetch=FetchType.LAZY)
    private Sosi sosi;
   
    public Sosi getSosi() {
        return sosi;
    }

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

    public Key getKey() {
        return key;
    }

    public void setKey(Key key) {
        this.key = key;
    }
   
   
    public String getKeyString() {
        return KeyFactory.keyToString(key);
    }
   
    public String getProgram() {
        return program;
    }

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

    public Schedule(String program, Sosi sosi) {
        this.program = program;
        this.sosi = sosi;
    }
}[/code]
일단 App Engine용 JPA에서는 ID 타입이 Long이면 관계형태를 사용할 수 없더라구요. 그래서 앱엔진에서 제공하는 Key타입이 있는데, 이걸 이용해야합니다.

7. Dao만들기
com.mudchobo.sosisochedule.SosiDao.java
[code]package com.mudchobo.sosischedule.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.google.appengine.api.datastore.KeyFactory;
import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;

@Repository
public class SosiDao {
    private EntityManager em;
   
    @Autowired
    public void setEntityManager(EntityManager em) {
        this.em = em;
       
        // 소시데이터 추가
        addSosi(new Long(1), "효연");
        addSosi(new Long(2), "윤아");
        addSosi(new Long(3), "수영");
        addSosi(new Long(4), "유리");
        addSosi(new Long(5), "태연");
        addSosi(new Long(6), "제시카");
        addSosi(new Long(7), "티파니");
        addSosi(new Long(8), "써니");
        addSosi(new Long(9), "서현");
    }
   
    public void addSosi(Long id, String sosiName) {
        em.getTransaction().begin();
        em.persist(new Sosi(KeyFactory.createKey(Sosi.class.getSimpleName(), id), sosiName));
        em.getTransaction().commit();
    }
   
    @SuppressWarnings("unchecked")
    public List<Sosi> getSosiList() {
        return em.createQuery("select s from Sosi s").getResultList();
    }

    public Sosi getSosi(Long sosiId) {
        return em.find(Sosi.class, sosiId);
    }
   
    @SuppressWarnings("unchecked")
    public List<Schedule> getScheduleList(final Long sosiId) {
        Query q = em.createQuery("select s.scheduleList from Sosi s where s.key = :key");
        q.setParameter("key", KeyFactory.createKey(Sosi.class.getSimpleName(), sosiId));
        return (List<Schedule>) q.getSingleResult();
    }
   
    public void addSchedule(Long sosiId, String program) {
        em.getTransaction().begin();
        Sosi sosi = em.find(Sosi.class, sosiId);
        sosi.getScheduleList().add(new Schedule(program, sosi));
        em.getTransaction().commit();
    }
   
    public void deleteSchedule(String scheduleKey) {
        em.getTransaction().begin();
        Schedule schedule = em.find(Schedule.class, scheduleKey);
        em.remove(schedule);
        em.getTransaction().commit();
    }
}[/code]
EntityManager받을 때 디폴트로 데이터를 넣어줘야 합니다(아까 위에서 말했듯이 프로그래밍적으로만 테이블을 생성할 수 있어서 이런 형태로 데이터를 넣어줘야합니다ㅠㅠ)

일단 실행해보고 데이터가 잘 생성되었는지 보려면 아래와 같은 주소로 접속해보면 됩니다.
http://localhost:8888/_ah/admin
일단 보고 삭제까지는 되는데, 테이블 생성같은 건 안되더라구요. 그리고 여기서 보여지는데에는 한글이 깨지는데 나중에 출력해보면 잘 나오니 걱정마시길-_-
사용자 삽입 이미지
8. Service 클래스 생성
com.mudchobo.sosischedule.service.SosiService.java
[code]package com.mudchobo.sosischedule.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mudchobo.sosischedule.dao.SosiDao;
import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;

@Service
public class SosiService {
   
    @Autowired
    private SosiDao sosiDao;
   
    public List<Sosi> getSosiList()
    {
        return sosiDao.getSosiList();
    }
   
    public Sosi getSosi(Long sosiId) {
        return sosiDao.getSosi(sosiId);
    }
   
    public List<Schedule> getScheduleList(Long sosiId) {
        return sosiDao.getScheduleList(sosiId);
    }
   
    public void deleteSchedule(String scheduleKey) {
        sosiDao.deleteSchedule(scheduleKey);
    }

    public void addSchedule(Long sosiId, String program) {
        sosiDao.addSchedule(sosiId, program);
    }
}[/code]
Service에서 하는 역할은 뭐 없네요-_-

9. Controller생성
스프링3.0에서 새로 추가된 기능인 REST기능입니다.
com.mudchobo.sosischedule.controller.SosiController.java
[code]package com.mudchobo.sosischedule.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.mudchobo.sosischedule.entity.Schedule;
import com.mudchobo.sosischedule.entity.Sosi;
import com.mudchobo.sosischedule.service.SosiService;

@Controller
public class SosiController {
    private static String PREFIX = "/sosischedule";
   
    @Autowired
    private SosiService sosiService;
   
    @RequestMapping(value="/", method=RequestMethod.GET)
    public String index(Model model) {
        List<Sosi> sosiList = sosiService.getSosiList();
        model.addAttribute("sosiList", sosiList);
       
        return "index";
    }
   
    @RequestMapping(value="/schedule/{sosiId}", method=RequestMethod.GET)
    public String getSchedule(
            @PathVariable("sosiId") Long sosiId,
            Model model) {
        Sosi sosi = sosiService.getSosi(sosiId);
        List<Schedule> scheduleList = sosiService.getScheduleList(sosiId);
        model.addAttribute("scheduleList", scheduleList)
            .addAttribute("sosi", sosi);
       
        return "sosi";
    }
   
    @RequestMapping(value="/schedule/{sosiId}/add", method=RequestMethod.POST)
    public String addSchedule(
            @PathVariable("sosiId") Long sosiId,
            @RequestParam("program") String program,
            Model model
            ) {
        sosiService.addSchedule(sosiId, program);
       
        return "redirect:" + PREFIX + "/schedule/" + sosiId;
    }
   
    @RequestMapping(value="/schedule/{sosiId}/{scheduleKey}", method=RequestMethod.GET)
    public String removeSchedule(
            @PathVariable("sosiId") Long sosiId,
            @PathVariable("scheduleKey") String scheduleKey,
            Model model) {
        sosiService.deleteSchedule(scheduleKey);
       
        return "redirect:" + PREFIX + "/schedule/" + sosiId;
    }
}[/code]

10. View jsp파일 생성
소시 리스트를 보여주는 index파일 입니다.
war/WEB-INF/jsp/index.jsp
[code]<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>소녀시대 스케줄</title>
</head>
<body>
    <div>
        스케줄 확인하기
        <ul>
        <c:forEach var="sosi" items="${sosiList}">
            <li><a href="/sosischedule/schedule/${sosi.key.id}">${sosi.key.id}. ${sosi.sosiName}</a></li>
        </c:forEach>
        </ul>
    </div>
</body>
</html>[/code]

해당 소시의 스케줄을 보여주는 스케줄 파일입니다.
war/WEB-INF/jsp/sosi.jsp
[code]<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>소녀시대 스케줄</title>
</head>
<body>
    <div>
        스케줄 확인하기
        <ul>
        <c:forEach var="sosi" items="${sosiList}">
            <li><a href="/sosischedule/schedule/${sosi.key.id}">${sosi.key.id}. ${sosi.sosiName}</a></li>
        </c:forEach>
        </ul>
    </div>
</body>
</html>[/code]
리다이렉트를 위한 파일입니다. 기존 index.html파일 지우시고, index.jsp파일 생성
index.jsp
[code]<% response.sendRedirect("/sosischedule/"); %>[/code]

앱엔진에 올려보았습니다.
http://2.latest.mudchobosample.appspot.com/sosischedule/

잘 되는 것 같네요.
 
Posted by 머드초보

댓글을 달아 주세요

  1. 2010.02.08 20:00  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • 머드초보 2010.02.12 00:05  댓글주소  수정/삭제

      안녕하세요~ 답변이 늦었네요 ㅠㅠ
      근데, 파일 다 올린 것 같은데...
      저도 만들어놓고 그냥 올린거다보니 ㅠㅠ
      뭐가 빠진건가요? ㅠㅠ

  2. BlogIcon 아따따따뚜겐 2012.03.08 17:07  댓글주소  수정/삭제  댓글쓰기

    우왕 짱입니당

  3. 나그네 2012.11.21 16:26  댓글주소  수정/삭제  댓글쓰기

    안녕하세요.. 구글 앱 엔진 검색하다 들렀습니다
    죄송한데 혹시 괜찮다면 위에서 보여주신 소스를 좀 부탁드려도 될까요??
    가능하시면 actors00@nate.com 으로 부탁좀 드릴게요

  4. BlogIcon timberland españa tiendas 2012.12.24 09:24  댓글주소  수정/삭제  댓글쓰기

    Bruxelles célèbre par une rétrospective de grande ampleur l'expressionniste flamand Constant Permeke (1886-1952). Cet Anversois aimait à dessiner et peindre les marins et paysans des Flandres, http://timberlandbotases.com timberland mujer 2012, qu'il représentait en athlètes aux corps anguleux et massifs et leurs femmes, nues et charnues, http://timberlandbotases.com timberland pro, tout en rondeurs. Il aimait aussi les paysages plats et les cieux de son pays natal. Dans tous les cas, il allait à l'essentiel avec une rare vigueur et sans craindre la provocation. L'accrochage met en valeur ces qualités et propose d'inattendues et justes comparaisons avec deux artistes actuels, Marlene Dumas c?té nus et Thierry de Cordier c, http://timberlandbotases.com timberland baratas?té nuées. Retrouvez cet article sur lemonde.frAnne Frank, passion nippone'Lawrence d'Arabie' en blu-rayLa belle pagaille de Skip & DieFiguration de gauche, abstraction de droiteLa couleur d'une affiche dévoile-t-elle tout d'un film?? Inscrivez-vous aux newsletters du Monde, http://timberlandbotases.com timberland españa catalogo 2011.frDevenez fan de Yahoo, http://timberlandbotases.com timberland earthkeepers! Actu sur Facebook et suivez-nous sur Twitter, http://timberlandbotases.com botas timberland mujer.
    Related articles:


    http://sanmarinosd.com/forums/topic.php?id=967873&replies=1#post-1031745 http://sanmarinosd.com/forums/topic.php?id=967873&replies=1#post-1031745

    http://www.renaissancemoms.com/forums/topic.php?id=595981&replies=1#post-634156 http://www.renaissancemoms.com/forums/topic.php?id=595981&replies=1#post-634156

    http://www.networkleisure.com/social/blog_entry.php?user=fanshuan9441&blogentry_id=945812 http://www.networkleisure.com/social/blog_entry.php?user=fanshuan9441&blogentry_id=945812

 
SpringFramework가 되는지 삽질하던 중 데모에 있는 샘플을 하나잡아서 convert를 시켰습니다-_-
놀랍게도 잘 되네요. 하는 도중 약간의 혈압이 상승했지만요-_-

우선 샘플주소입니다.
http://springguestbook.appspot.com

소스코드 주소입니다. trunk/SpringGuestBook입니다^^
http://my-svn.assembla.com/svn/mudchobosample

마치...그냥 앱엔진에서 제공하는 샘플이랑 같아보여서 사기를 치는 것 같지만, Model2방식의 예제입니다ㅠ

우선 하면서 가장 처음에 겪는 문제점입니다.
Your Web Application Project must be configured to use a JDK in order to use JSPs.

JSP를 쓰려면 jdk를 설정해야한다는 뜻인데요. 보통 JDK를 깔고, 이클립스를 실행하면 디폴트로 JRE가 잡혀있어요. 이걸 JDK로 추가해서 바꿔주시면 돼요.

이클립스에서 Window -> Preferences -> Java -> Installed JREs선택.
Add -> Standard VM -> JRE home에서 Directory선택해서 JDK주소를 찾으세요.
디폴트로 설치하셨다면 C:\Program Files\Java\jdk1.6.0_12 여기에 있을겁니다.
폴더만 선택하고, Finsh를 누르면 추가가 되었습니다. 체크박스를 jdk로 옮겨주세요. 그러면 저 위에 에러 안날꺼에요.

그다음으로 겪는 문제점은....-_- 앱엔진에서 지원안하는 클래스를 쓰는 곳이 있는 것 같아요.
spring mvc를 사용하려면 spring.jar하고 spring-webmvc.jar 두개만 있으면 되는데요. 이거 두개 lib폴더에 넣어놓고 서버에 디플로이 시키면
exception is java.lang.NoClassDefFoundError: javax/naming/NamingException
App engine로그를 볼 수 있는데, 거기서 로그를 보면 클래스를 찾을 수 없다고 나와요. spring-orm.jar에서 쓰는 것 같더라구요. 어차피 구글앱엔진은 jdo만 지원해서 jdo only라이브러리가 있습니다-_- 그걸로 바꿔주시면 돼요.
전 라이브러리복사할 때
spring-beans.jar, spring-context-support.jar, spring-context.jar, spring-core.jar, spring-jdbc.jar, spring-orm-jdo-only-2.5.6.jar, spring-test.jar, spring-tx.jar, spring-web.jar, spring-webmvc.jar를 복사했네요.
여기서 spring-orm-jdo-only-2.5.6.jar는 저도 어디서 받은거라.....-_-
그러고 디플로이하면 잘 됩니다.

또 한가지 문제점은 eclipse에서 제공하는 dynamic web project에서는 WEB-INF/lib에 library파일을 복사하면 자동으로 클래스를 코드힌트로 쓸 수 있는데, 이놈은 코드힌트를 할 수 없어요-_- 그래서 수동으로 추가를 해줘야해요.
프로젝트 이름에 Properties를 선택하고, Java Build Path에서 Add JARs에서 추가한 spring파일 등을 선택해서 추가해줘야 에러가 안나네요^^(이건 뭐 다른 방법이 있을 지도.....-_-저에게 최선의 방법이였다는 ㅠ)

또 JDO라는 걸 전혀 몰라서 조금 고생했는데, Hibernate같은 orm이더군요. 사실 아직도 잘 모르겠습니다. 좀 더 알아봐야할 것 같네요. orm하면 Hibernate랑 JPA밖에 없는 줄 알았는데, 뭐 디게 많네요ㅠ

또.....-_- localhost에서 Datastore테스트를 하면 war/WEB-INF/appengine-generated라는 폴더가 생겨요. 디비가 저장되는 것 같은데, 저게 있는 상태에서 디플로이하면 안돼요. 지우고 하면 됩니다.

또 이런저런 문제가 있었는데, 기억이 안나네요. 그래도 정말 대단한 것 같습니다. 대세는 클라우드-_-

참고자료
http://peterbacklund.blogspot.com/2009/04/running-spring-on-google-app-engine.html
http://groups.google.com/group/google-appengine-java/browse_thread/thread/f1a541fe52e172dd

 
Posted by 머드초보

댓글을 달아 주세요

  1. BlogIcon 이학도 2009.05.22 10:24  댓글주소  수정/삭제  댓글쓰기

    좋은 자료 감사.^^

  2. BlogIcon 이학도 2009.05.22 12:07  댓글주소  수정/삭제  댓글쓰기

    svn repo는 www.assembla.com에서 돈주고 호스팅 받았어요?

    • 머드초보 2009.05.23 23:52  댓글주소  수정/삭제

      저기assembla는 svn이랑 trac같은 개발환경을 제공하는데요.
      public공간으로 만들면 무료이고, private공간을 만들면 돈들어가요.
      다 오픈하면 무료에요 ^^

  3. realmove 2010.12.27 16:07  댓글주소  수정/삭제  댓글쓰기

    jdk 설정하라는 말이 무슨 말인지 몰랐는데, 덕분에 해결했네요.
    감사합니다.

  4. 설거지의달인 2011.01.14 10:14  댓글주소  수정/삭제  댓글쓰기

    앱엔진 호스팅을 받아서 스프링을 돌려보려는 사람입니다;
    디플로이 중에 다음과 같은 에러가;;
    403 Forbidden
    You do not have permission to modify this app
    이건 어떻게 해결하면 좋을까요;;

  5. 자바개발자 2011.07.29 15:36  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다.

 
구글 앱 엔진이 자바를 지원하기 시작했습니다.
전 세계적으로 가장 인기있는(?) 언어인 자바를 지원하다니 대단합니다-_-(사실...파이썬 보다 자바나 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 머드초보

댓글을 달아 주세요

  1. BlogIcon 지돌스타 2009.04.28 15:53  댓글주소  수정/삭제  댓글쓰기

    이런게 있는지 처음 알았군요.
    구글의 리소스를 내가 직접 사용하는 것 같은 애플리케이션을 만들 수 있다는것에 꽤 흥미를 느끼게 되는군요. 내용 잘 봤습니다.

    • 머드초보 2009.04.30 09:55  댓글주소  수정/삭제

      전에 구글코리아에서 설명을 들었을 때
      구글에서 사용하는 서비스와 동일한 것이라고 하더군요.
      구글은 언제나 개발자를 놀래키죠-_-

  2. BlogIcon 김석영 2009.05.07 23:28  댓글주소  수정/삭제  댓글쓰기

    그냥 고마울 따름이네요...

    • 머드초보 2009.05.11 00:46  댓글주소  수정/삭제

      "구글 앱 엔진 한국 개발자 토론 그룹"에서 본 것 같은데 반갑습니다^^

 
사실 어떤 블로그를 보고 구글에서 세미나 한다고 해서 가보고 싶어서 신청했는데, 되서 가게 되었는데....난....App Engine이 뭔지도 모르고....OpenSocial은 또 뭐고.....-_-; 아무것도 모르는 상태에 가서 세미나를 들었습니다. 역시나......뭔소린지 하나도 모르고 그냥 돌아왔습니다 ㅠ

우선 처음에 가니....구글코리아가 여기 강남에 있었군요-_-; 참 색다른 경험이였습니다-_-; 알록달록한 것이 참 이쁘네요. 암튼, 시간이 좀 늦어져서 좀 늦게 20분 후에 시작했던 것 같네요.

Making Money with OpenSocial

간단하게 오픈소셜로 수익을 얻을 수 있는 것을 발표했습니다. 그 첫번째로 광고구요. 광고는 인터넷에서 필수적인 수익모델이죠^^ Buddy Poke라는 것이 가장 유명한 것 같은데, 지금 방금 실행해보니....대체 뭐하는 건지 모르겠습니다-_-; 전 친구가 하나도 없어서 그런가요?-_-; 그냥 어떤 놈이 나와서 저한테 손만 흔드는군요-_-; 왠지 플렉스로 만든 것 같습니다. 플렉스 컴포넌트들이 막 보이네요.
http://www.buddypoke.com/

두번째로는 Virtual Currency네요. 이건 국내에서 게임 업체나 커뮤니티업체들이 많이 하는 모델이죠. 아바타 사려면 돈을 결제해야하는 그런...cyworld에 도토리 보내 달라고 하는 복혜은이 생각나네요(친구입니다-_-).

세번째는 offers인데요. 어떤 요구사항을 들어주고, 돈이나 Point를 받는거죠. 이것도 국내에서 많이 하는..-_-; OK CashBag모을 때나 던전앤파이터를 하는데, 캐쉬가 모자라서 창고를 못살 때 쓰는 좋은 방법이죠-_-; 아래는 Mobsters라는 건데, 게임인 듯 한데, 뭔가 복잡하군요. 이곳에서 쓰이는 돈을 받기위해서 어딘가 회원가입을 해서 Cash를 모아야하나 봅니다-_-;
http://profile.myspace.com/Modules/Applications/Pages/Canvas.aspx?appId=104283

네번째는 Brand Marketing이라고 하는데, 뭘 말하는건지 모르겠네요.

위에 사례를 들어보니...오픈소셜 애플리케이션을 만들고 싶군요. 마이스페이스같은 SNS서비스에 APP를 만드는 것인 것 같습니다. 한번 알아봐야하겠습니다(뒷조사를..-_-)


Google App Engine

아....외국인입니다...뭔말하는지 못알아 듣겠군요. 다행히 통역해주시는 분이 계셨습니다만, 몇마디는 생까고 해주신 것오늘 가장 큰 깨달음은 영어공부를 해야한다였습니다-_-; 영어공부를 해야합니다...ㅠ
오늘 대충 얘기를 들어보니 App Engine은 구글에서 서버사이드환경을 제공하며 구글이 제공하는 Framework를 이용해서 손쉽게 웹애플리케이션을 구축할 수 있는 것 같습니다. 즉, 웹애플리케이션을 구동시키기 위한 서버 환경셋팅과정은 생까고, 구글에서 제공하는 서버환경 및 Database를 사용할 수 있는 것입니다. 뭐 단점이라면 지원언어가 Python밖에 없는 합니다. 아직 사용해보지는 않았지만, 이걸 사용한다면 서버 비용 절감 및 개발 시간 단축정도가 되겠네요. 게다가 구글인증을 사용해서 구글서비스와 손쉽게 연동이 되는 듯 하네요.

우선 처음에 얘기해준게 역시나 이거였습니다. 웹 애플리케이션 개발 시 문제점! 서버셋팅이죠. 서버머신도 있어야하고, 그곳에 여러 제품(Linux, Database 등)의 셋팅 등의 어려움이 있는데, App Engine에서는 이 모든 것을 하나에 담아서 제공합니다(아놔.....오늘부터 파이썬 파야하나....-_-)

또한 장점으로 쉽게 시작할 수 있고(파이썬 아닌사람이나-_-), 쉽게 변경이 가능하다고 하네요. 또한 구글과 같은 Infra를 사용해서인지 구글규모의 대규모 서비스도 가능하다고 하네요. 아...BigTable설명하면서 Database관련된 것을 보여줬는데, GQL(당연히 Google Query Language겠지-_-)라는 것을 이용해서 쿼리를 날립니다. SQL과 비슷한 문법으로....마치 HQL과 같은 형태로 App Engine에 맞게 최적화시킨 듯 합니다.

데모를 보여줬는데, 간단한 Hello World찍는 건데, 있다가 한번해봐야겠습니다. 설정할 수 있는 파일인 yaml(야믈이라고 읽더군요-_-)을 이용해서 뭐 하는 것 같은데...암튼, 방명록같은 것도 손쉽게 만들 수 있는 것 같습니다. 게다가 셋팅이 필요없는 개발환경을 제공하는 점이 너무 좋은 것 같네요. Java로 방명록 만드려면, 톰캣깔고, MySQL깔고, 뭐 그래야하는데, 이건 뭐 그런게 필요없는 듯 합니다. 좋아요~


App Engine + OpenSocial

뭐 두개를 이용해서 애플리케이션을 만들 수 있는 것 같은데, 둘 다 전혀 모르는 거라...그냥 멍하니 보다가 왔습니다.

아....보니까 OpenSocial애플리케이션 만드는 법이 Google에 Gadget(외국인들은 개짓이라고 발음합니다. 개짓하고있네-_-)만드는 거랑 같은 코드인 것 같네요. Module들어가고...전에 다음위젯뱅크 좀 보다가 본 건데, Javascript로 개발하는 듯 합니다. 지금 0.8버전까지 나왔는데, 지금은 기존처럼 Javascript형태로 개발이 가능한데, 나중에 템플릿기반의 개발이 가능한 듯 합니다. HTML태그를 입력하는 형태로 개발을 할 수 있는 듯 합니다. 마치 Flex에서 xml로 코딩할 수 있는 것 처럼이랑 비슷한 것 같습니다. 차후버전인 0.9에서 지원한다고 하네요.

아무것도 모르는 상태에서 글을 쓰려니 저도 뭔소리 한지도 모르겠네요. 그냥 들은 거랑 제 생각을 좀 포함해서 쓴겁니다. 잘못된 내용이 있을 수도 있습니다. 돌은 던지지 마시구요-_-;
사용자 삽입 이미지

제가 좋아하는 공책과 펜이군요. 공책과 펜을 너무 좋아합니다ㅠㅠ


 
Posted by 머드초보

댓글을 달아 주세요