- notice 스킨변경~
[스프링프레임워크]검색결과, 16건
- [Java] Google App Engine에서 Spring3 + JPA 사용한 소녀시대 예제 2010/01/31 (2)
- [Spring/Flex] Spring BlazeDS Integration AppEngine위에서 간단히 구동 후기 2009/09/28 (4)
- [머드초보의 일상] KSUG 2차 스프링 강의에 대한 후기 및 소감 2009/09/27
- [Spring, Java] Javamail API를 이용해서 gmail, daum메일을 전송해봅시다. 2008/08/19
- [NetBeans6.1] SpringFramework 어노테이션(Annotation)을 이용한 HelloSpring예제 2008/06/18
[Java] Google App Engine에서 Spring3 + JPA 사용한 소녀시대 예제
Posted in 자바(Java) // Posted at 2010/01/31 20:50암튼, "구글 앱 엔진"에서는 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
<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>일단 sosischedule/*요청은 spring이 받습니다.
4. dispacher-servlet.xml파일과 persistence.xml파일 생성
war/WEB-INF/폴더에 생성
dispatcher-servlet.xml
<?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>src/META-INF/ 폴더에 생성
persistence.xml
<?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>5. EMF클래스 생성.
이제 jpa접근할 수 있는 EntityManagerFactory클래스(EMF)를 생성해봅시다.
com.mudchobo.sosi.sosischedule.dao.EMF.java
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();
}
}6. Entity클래스 생성
일단 Sosi와 Schedule이라는 Entity를 생성할 건데요. 둘의 관계는 1:N관계입니다.
com.mudchobo.sosischedule.entity.Sosi.java
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;
}
}com.mudchobo.sosischedule.entity.Schedule.java
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;
}
}일단 App Engine용 JPA에서는 ID 타입이 Long이면 관계형태를 사용할 수 없더라구요. 그래서 앱엔진에서 제공하는 Key타입이 있는데, 이걸 이용해야합니다.
7. Dao만들기
com.mudchobo.sosisochedule.SosiDao.java
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();
}
}EntityManager받을 때 디폴트로 데이터를 넣어줘야 합니다(아까 위에서 말했듯이 프로그래밍적으로만 테이블을 생성할 수 있어서 이런 형태로 데이터를 넣어줘야합니다ㅠㅠ)
일단 실행해보고 데이터가 잘 생성되었는지 보려면 아래와 같은 주소로 접속해보면 됩니다.
http://localhost:8888/_ah/admin
일단 보고 삭제까지는 되는데, 테이블 생성같은 건 안되더라구요. 그리고 여기서 보여지는데에는 한글이 깨지는데 나중에 출력해보면 잘 나오니 걱정마시길-_-
com.mudchobo.sosischedule.service.SosiService.java

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);
}
}Service에서 하는 역할은 뭐 없네요-_-
9. Controller생성
스프링3.0에서 새로 추가된 기능인 REST기능입니다.
com.mudchobo.sosischedule.controller.SosiController.java
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;
}
}10. View jsp파일 생성
소시 리스트를 보여주는 index파일 입니다.
war/WEB-INF/jsp/index.jsp
<%@ 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>해당 소시의 스케줄을 보여주는 스케줄 파일입니다.
war/WEB-INF/jsp/sosi.jsp
<%@ 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>리다이렉트를 위한 파일입니다. 기존 index.html파일 지우시고, index.jsp파일 생성
index.jsp
<% response.sendRedirect("/sosischedule/"); %>앱엔진에 올려보았습니다.
http://2.latest.mudchobosample.appspot.com/sosischedule/
잘 되는 것 같네요.
-
-
머드초보
안녕하세요~ 답변이 늦었네요 ㅠㅠ
근데, 파일 다 올린 것 같은데...
저도 만들어놓고 그냥 올린거다보니 ㅠㅠ
뭐가 빠진건가요? ㅠㅠ
-
[Spring/Flex] Spring BlazeDS Integration AppEngine위에서 간단히 구동 후기
Posted in 스프링(Spring) // Posted at 2009/09/28 01:26이번 Spring BlazeDS Integration 1.0.1릴리즈 기념과 Spring교육 끝난 기념으로 간만에 삽질해봤습니다.
하지만, messaging 등의 심화적인 것은 못해보구요. 우선 서비스를 가져오는지만 해봤습니다.
삽질환경
- IDE
Eclipse3.5와 구글앱앤진 플러그인 - http://code.google.com/intl/ko-KR/eclipse/docs/download.html
Flex Builder 3.0.2
JDK 1.6.0 U14
- 라이브러리
Spring Framework 2.5.6
BlazeDS 3.2.0.3978
Spring BlazeDS Integration 1.0.1
Jackson 1.2.0
Cglib 2.1.3
1. App Engine 프로젝트 생성
프로젝트 생성하고 나서 라이브러리들을 다 복사합니다. 저는 아래와 같이 라이브러리를 복사했습니다.
기존App Engine lib, spring.jar, spring-webmvc.jar, blazeds.war에 있는 lib, jackson-core-lgpl-1.2.0.jar, jackson-mapper-lgpl-1.2.0.jar, cglib-nodep-2.1_3.jar, org.springframework.flex-1.0.1.RELEASE.jar
그리고, appengine-web.xml파일에 한줄 추가합니다.
<sessions-enabled>true</sessions-enabled>이거 필요한건지는 잘 모르겠군요-_-
WEB-INF폴더아래 blazeds.war파일에 들어있는 flex폴더를 복사합니다(*-config.xml의 파일이 있는 것)
2. 서비스 클래스 생성
이제 서비스를 만들어봅시다. 초간단 헬로우서비스를-_-
src폴더에 만들어봅시다. 전 com.mudchobo.springblazedsserver.service패키지에 HelloService클래스를 생성했음!
HelloService.java
package com.mudchobo.springblazedsserver.service;
public class HelloService {
public String sayHello(String name) {
return "Hello, " + name;
}
}3. 설정파일 생성 및 설정
스프링관련 설정을 해야해요. web.xml에서 디폴트로 설정된 servlet설정을 지우고 아래를 추가
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/*-context.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- SpringDispatcherServlet -->
<servlet>
<servlet-name>flex</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>flex라는 이름의 서블릿을 만들었으니 스프링 설정파일이름인 flex-servlet.xml을 생성합니다.
flex-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:flex="http://www.springframework.org/schema/flex"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/flex
http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">
<flex:message-broker />
<flex:remoting-destination ref="helloService"/>
</beans>flex라는 네임스페이스를 제공하는데요. <flex:message-broker />이 한줄로 모든 설정이 되어버립니다. M1 삽질했을 때에는 네임스페이스 없어서 bean써주고, 다 설정했던 기억이 나네요. 네임스페이스로 한줄로-_-
remoting-destination태그는 destination을 설정하는 건데, 해당 bean을 ref하면 해당 bean이름으로 destination으로 flex에서 가져올 수 있어요.
그럼 서비스를 설정할 설정파일을 생성해봅시다. configlocation을 /config/*-context.xml을 잡았는데, /config/services-context.xml파일을 만들어봅시다^^
services-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="helloService" class="com.mudchobo.springblazedsserver.service.HelloService" />
</beans>방금 만든 HelloService를 bean으로 설정.
마지막으로 flex/services-config.xml에서 default-channels를 추가합시다.
<services>
<service-include file-path="remoting-config.xml" />
<service-include file-path="proxy-config.xml" />
<service-include file-path="messaging-config.xml" />
<default-channels>
<channel ref="my-amf"/>
</default-channels>
</services>그리고 이것도 추가해야해요.
<system>
<manageable>false</manageable>
....
</system>이거 추가안하면 앱엔진에서 이런 에러로그를 뿜음-_-
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_messageBrokerDefaultHandlerMapping': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '_messageBroker': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanInitializationException: MessageBroker initialization failed; nested exception is java.lang.NoClassDefFoundError: java.lang.management.ManagementFactory is a restricted class. Please see the Google App Engine developer's guide for more details.
관리자 기능이라고 하는 것 같은데, 정확히 뭔지는 잘 모르겠지만, 끄면 잘 됩니다-_-
4. 클라이언트 프로젝트 생성
flex project를 생성할 때 이렇게 생성해주면 편합니다.
Flex Project선택 -> Project name쓰고, Application server type은 J2EE, Create combined Java~~는 체크해제, Use remote object access service는 체크하고, Next.
그 다음 Serverlocation 셋팅을 Root folder는 AppEngine의 war폴더를 지정해주면 되구요.
Root URL은 앱엔진 기본 실행 경로인 http://localhost:8080하면 되구요. Context root는 /로 지정하면 됩니다.
그러면 디버그나 Run시에 localhost:8080/프로젝트명/프로젝트명.html로 실행이 돼요.
코드는
SpringBlazeDSClient.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:RemoteObject id="srv" destination="helloService" />
<mx:TextInput id="inputName" />
<mx:Button label="전송" id="btnConfirm" click="srv.sayHello(inputName.text)" />
<mx:Label id="labelResult" text="{srv.sayHello.lastResult}" />
</mx:Application>이 코드 너무 활용하는 것 같아-_- 암튼 destination은 helloService로 설정했기 때문에 이걸로 지정하면 됩니다.
5. 이제 배포 및 실행
이제 swf파일도 appengine프로젝트에 생성하고, AppEngine을 배포하고 실행하면 또다른 에러를 보실 수 있습니다-_-
[RPC Fault faultString="Detected duplicate HTTP-based FlexSessions, generally due to the remote host disabling session cookies. Session cookies must be enabled to manage the client connection correctly." faultCode="Server.Processing.DuplicateSessionDetected" faultDetail="null"]
와....미쳐버립니다. 이건 뭔가....검색해보니 앱엔진이 여러 서블릿배포할 때 1개의 클라이언트 정보를 동일하게 배포를 해서 어쩌구 라고 번역기를 돌리니 써있네요-_- 이걸 픽스한 jar파일이 돌아다닙니다-_-
기존 flex-messaging-core.jar파일을 위 파일로 교체해주면 되더군요.
이제 실행하면 잘 될겁니다.
실행주소입니다.
http://mudchobo1.appspot.com/SpringBlazeDSClient/SpringBlazeDSClient.html


스크린샷.....
참고사이트
http://www.adobe.com/jp/devnet/flex/articles/google_app_eng_w_beazeds_p2.html
http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html
-
빠방
좋은 예제 감사드립니다 (꾸벅)
덕분에 spring blazeds intergration 1.0.1과 ibatis 연동에 성공했습니다.
이전에 올려주신 연동예제와 새로 릴리즈된 1.0.1 예제가 아니었으면 짧은 영어실력때문에 도저히 알아먹지 못해고 포기해버렸을꺼에요 ㅠㅠ -
-
-
3차 강의신청도 10월중순쯤에 받고, 11월에 시작된다고 하니 관심있으신 분들은 KSUG 메일링 리스트에 가입을 하세요~^^
3차 강의에 관심있으신 분들을 위해-_- 후기를 남깁니다-_-(뭐 전 KSUG랑 관계없는 사람이구요-_- 그냥 강의가 좋아서 글을 남깁니다-_- 어차피 선착순이고 하루이틀이면 다차기 때문에 빨리하지 않으면 손해임 ㄷㄷ)
그리고, 강의를 들으시는 분들은 스프링을 한번쯤 사용해보신 분이 가장 적당한 것 같습니다^^ 그냥 멋도 모르고 사용해보신 분이면 더 좋구요(저처럼-_-). 그런 분들은 왜 이렇게 사용하지? 이런걸 알게 되는 좋은 기회일테니까요^^
Korea Spring User Group http://groups.google.com/group/ksug
스프링을 국내에 널리 알린 KSUG에서 하는 강의라 역시 스프링강의 중에는 최고입니다. 그냥 책을 보면서 스프링을 익히는 것 보단 스프링에 대해서 정말 잘 알고 관심있어하시는 분께 강의를 들으니 이해가 가지 않았던 개념도 많이 잡히더군요.
1주차 - IoC / DI
전 1주차 때가 역시...맘에 듭니다. 의존성을 개선하는 좋은 예제와 Junit을 이용한 테스트를 하는 것을 배우게 될 것입니다. 의존성을 개선하는 과정에서도 테스트는 항상 같기 때문에 항상 통과해야합니다. 테스트는 리펙토링을 할 때 매우 유용하더군요.
또한 예제를 준비해오셨는데, IoC/DI개념을 이해하기 좋을만한 예제를 준비해서 쉽게 실습합니다. 셋팅 관련된 것은 거의다 만들어오시고, 실제 중요한 로직만 코딩하는 방식으로 주로합니다. ^^
2주차 - JDBC
스프링에서 제공하는 JdbcTemplate을 처음부터 만들어봅니다. 이걸 만드는 이유는 Spring에 있는 Template류의 구현 패턴을 이해하기 위함이였습니다. JDBC Template를 만들면서 느끼는 점은 스프링이 참 대단하구나 라는 것을 느끼게 됩니다-_- Strategy pattern을 이용해 중복코드는 제거해가는 것을 직접해보는데, 이클립스의 강력한 기능인 리펙토링(사실 개발하면서 써본적 없음 ㅠㅠ)을 이용해서 합니다. 이클립스 리펙토링기능도 많이 알게 되는 좋은 시간이였던 것 같습니다. 덕분에 이클립스의 많은 기능을 배웠던 것 같아요^^
3주차 - Transaction & Advanced JDBC
전 대규모프로젝트나 트랜잭션이 필요한 프로젝트를 해본적이 거의 없어서-_- 트랜젝션에 대한 개념이 조금 전무했었습니다. 그냥 두개의 테이블에 데이터를 넣는데, 두번째가 실패하면 첫번째도 롤백이라는 간단한 개념만 알고 있었죠-_- 업무단위라고 주로하죠^^
이번 강의도 트랜젝션을 적용하기 위해선 업무로직과 섞이기 마련인데요. 이걸 트랜젝션만 따로 빼주는 Transaction Template을 만들어봅니다^^ 그러면 업무로직에만 집중할 수 있는 걸 보여주죠^^
이것보다 더 편한 AOP를 이용한 선언적 트랜젝션도 배우고요^^
그리고, 트랜젝션하면서 이건 대체 뭐하는 거지 라고 생각된 Propagation에 대해서도 잘 설명해줍니다^^ 재미있는 사례와 함께요^^
4주차 - Web MVC
전 웹에 관심이 많다보니 MVC가 역시 ^^ 여기서도 SpringDispatcherSerlvet이 어떤식으로 동작하는지를 알기 위해 FrontController라는 DispatcherServlet과 비슷한 걸 만들어보는 실습을 하게 됩니다^^ 이런 원리를 알고 사용하면 역시나 나머지에 대한 이해가 참 빨라집니다^^
이것 외에는 MVC쪽은 많이 삽질을 해봐서 복습한다는 내용으로 많이 들었던 것 같네요.
5주차 - Annotation-style Programming
1~4주차까지 한 내용을 다 애노테이션으로 바꿉니다-_- 지금까지 한 내용들은 애노테이션을 사용하기전에 개념과 원리를 잡기 위한 내용이였다고 보면 되구요. 애노테이션으로 바꾸면서 이것들을 매우 쉽게 사용할 수 있게 되었습니다. 설정에 들어가는 XML도 줄어들구요.
이거 처음부터 애노테이션을 사용해서 배워버리면 이게 왜 이렇게 되는지 알기 힘들고, 사용법만 배우는 건 완전 겉핥기가 되버리기 때문에 이렇게 강의를 구성한 것 같아요. 좋아요^^
6주차 - Security
Security는 역시 보안, 인증관련된 부분이라 어려운 것이라고 하더군요. 예전부터 로그인할 때 인증하는 것이라고만 알고있어서 더 알고 싶었던 것도 있었는데요. 근데, 역시나 하루만에 많은 걸 가르칠 수 없었기에 웹인증과 권한관련된 내용만 했습니다.
그래도 유용했던 것은 그 전 Acegi때 했던 필터 기반을 먼저 보여주고, 네임스페이스 기반을 보여줘서 원리에 대해서 잘 알았던 것 같네요. 그리고, 사실 어떻게 쓰는 줄 몰라서 못해봤었는데, 사용법도 알게 되어서 좋았네요^^
덕분에 많은 것을 배웠던 것 같네요. 강사님이 중간중간 현장 얘기도 좀 해주시고, 스프링관련 얘기도 해주시고 그래서 더욱 재미있었던 것 같네요.
3차 신청하시는 분들 참고하세요-_-
[Spring, Java] Javamail API를 이용해서 gmail, daum메일을 전송해봅시다.
Posted in 스프링(Spring) // Posted at 2008/08/19 19:52naver는 지원하긴 하지만, 조낸 써야지 smtp를 사용할 수 있습니다.
저는 일반사용자인데 으뜸사용자가 되야하는 듯 합니다.
그래서 그냥 지원해주는 gmail이랑 daum메일로 테스트를 해봤습니다. 잘 되는군요.
기존에 25포트가 디폴트로 메일을 사용했는데 보안 때문에 SSL을 사용하고, smtps라는 프로토콜로 465번포트로 하는군요.
이건 좀 더 공부를 해봐야할 듯 싶네요. 그냥 기존의 ssl을 사용하지 않는 메일은 host랑 id랑 password만 지정해주면 돼요.
우선 설정파일입니다.
applicationContext.xml
<?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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="mailtest" />
<!-- 일반용
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="STMP서버주소"
p:username="아이디"
p:password="비밀번호" />
-->
<!-- gmail, hanmail 용 -->
<bean id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="한메일: pop.hanmail.net, 지메일:smtp.gmail.com"
p:port="465"
p:protocol="smtps"
p:username="아이디"
p:password="비밀번호">
<property name="javaMailProperties">
<props>
<prop key="mail.smtps.auth">true</prop>
<prop key="mail.smtps.startls.enable">true</prop>
<prop key="mail.smtps.debug">true</prop>
</props>
</property>
</bean>
<bean id="templateMessage"
class="org.springframework.mail.SimpleMailMessage"
p:from="송신자 주소"
p:to="수신자 주소"
p:subject="안녕!" />
</beans>
templateMessage는 임시로 메세지를 지정해주는 것으로 미리 지정할 껀 지정하는 겁니다.
물론, 나중에 java코드에서 수정이 가능합니다.
서비스부분입니다.
MailTestService.java
package mailtest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
@Service
public class MailTestService
{
@Autowired
private MailSender mailSender;
@Autowired
private SimpleMailMessage simpleMailMessage;
public void sendEmail()
{
SimpleMailMessage msg = new SimpleMailMessage(this.simpleMailMessage);
msg.setText("난 종천이라고해!");
this.mailSender.send(msg);
}
}
저기서 simpleMailMessage를 받아와서 text만 설정해줍니다. 저기서 msg.setTo하면 수신자도 설정할 수 있죠. 그리고 그냥 send메소드만 호출해주면 메일이 전송됩니다.
package mailtest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MailTest
{
public static void main(String[] args)
{
String configLocation = "applicationContext.xml";
ApplicationContext context =
new ClassPathXmlApplicationContext(configLocation);
MailTestService mailTestService =
(MailTestService) context.getBean("mailTestService");
mailTestService.sendEmail();
}
}
더욱 심화된 기능은 reference를 참조하세요
http://static.springframework.org/spring/docs/2.5.x/reference/mail.html
[NetBeans6.1] SpringFramework 어노테이션(Annotation)을 이용한 HelloSpring예제
Posted in 스프링(Spring) // Posted at 2008/06/18 18:59넷빈즈는 초보자들이 쉽게 적응할 수 있도록 QuickStart를 제공합니다.
일종의 튜토리얼 같은 건데 참 잘 되어 있습니다.
스프링프레임워크에 관해서도 QuickStart가 있는데 어노테이션을 사용해서 더욱 쉽게 접근할 수 있도록 바꿔봤습니다.
http://www.netbeans.org/kb/61/web/quickstart-webapps-spring.html
요게 원문입니다. 영어지만, 그냥 코드만 보고 따라하셔도 스프링의 기초를 이해하실 수 있을껍니다.
이 예제를 조금 변경해봤습니다. 어노테이션을 이용한 HelloSpring으로-_-;(똑같이 하면 왠지 안될것같아서-_-)
우선 NetBeans6.1, JDK 5 or 6, GlassFish or Tomcat이 필요해요.
우선 처음에 프로젝트를 만듭니다.
New Project(Ctrl-Shift-N)을 선택해서 Web -> Web Application을 선택합니다.
프로젝트이름은 HelloSpring이라고 하고, Steps 4단계에서 Spring Web MVC 2.5를 선택하세요.
그리고 Finish를 클릭하세요.
그리고 F6을 누르면 GlassFish가 실행이 되고, 웹페이지가 뜨면서 아래와 같은 화면이 나올껍니다.

저 페이지는 index.jsp파일인데요. web.xml파일에 보면 welcome-file이 redirect.jsp로 되어있습니다. redirect.jsp파일을 열어보게 되면, index.htm을 요청하게 되어있습니다.
또 web.xml에서 servlet태그를 보면 *.htm요청으로 들어오는 놈들은 DispatcherServlet으로 넘기게 되어있습니다.
이 놈은 서블릿이름-servlet.xml파일을 설정파일을 사용합니다.
그러면 dispatcher-servlet.xml파일을 보게 되면, urlMapping이라는 bean이 있는데, 이 놈에서 mappings를 보면 index.htm이 요청일 경우 indexController를 실행하게 되어있습니다.
indexController는 아래에 bean으로 정의가 되어있죠.
indexController는 ParameterizableViewController클래스인데 이 클래스는 p:viewName값이 index인 것을 보여주는것이죠. index는 viewResolver bean에 의해서 /WEB-INF/jsp/index.jsp파일이죠.
그래서 index.jsp파일이 보여지는 것이죠.
초간단 설명을 마치고-_-; 폼에다가 이름을 입력하고, 전송하면 "Hello 이름!"을 리턴하는 프로그램을 만들어봅시다.
설정파일을 조금 변경해야합니다.
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
요런 bean이 있는데, 이건 Controller의 클래스명으로 url매핑을 하는 겁니다. 즉 HelloController로 선언을 시켰으면 hello.htm요청으로 해당 컨트롤러를 호출할 수 있게 하는겁니다.
근데 이건 어노테이션을 사용하면 안 먹힙니다-_-; 걍 지워버립시다.
그리고, beans에 xmlns:context="http://www.springframework.org/schema/context"를 추가합니다.
그리고, xsi:schemaLocation에도
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
이렇게 추가합니다. 이는 <context: 를 사용하기 위함입니다.
그리고, 이 아래에 이걸 추가합니다.
<context:component-scan base-package="hellospring" />
이건 객체를 스캔하는 건데 @Service, @Controller, @Component 등의 어노테이션이 base--package아래있는 클래스들 전부 적용하게 합니다. 빈이름은 클래스명에 따라서 정해집니다. 예를 들어 HelloController이면 helloController라고 자동으로 등록됩니다.
그리고, urlMapping bean에다가 우리가 만들 HelloController를 등록합니다.
<prop key="/hello.htm">helloController</prop> 이렇게 한줄을 추가하면 됩니다.
바뀐 dispatcher-servlet.xml 파일입니다.
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="hellospring" />
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/index.htm">indexController</prop>
<prop key="/hello.htm">helloController</prop>
</props>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<bean name="indexController"
class="org.springframework.web.servlet.mvc.ParameterizableViewController"
p:viewName="index" />
</beans>
우선 Service를 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 HelloService라고 하고, Package에다가 hellospring.service라고 합시다.
package hellospring.service;
@Service
public class HelloService {
public String sayHello(String name) {
return "Hello " + name + "!";
}
}
초간단 메소드입니다. name을 넣으면 Hello name! 을 리턴하게 하는 서비스입니다.
그 전에 폼으로 부터 데이터를 가져오는 bean을 하나 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 Name이라고 하고, Package에다가 hellospring.domain라고 합시다.
package hellospring.domain;
public class Name {
private String value;
}
여기서 getter, setter만드는 방법이 2가지가 있어요.
첫번째 방법은 Alt + Insert키를 누르면 Getter and Setter를 선택하면 해당 멤버변수에 대해서 나오는데 체크를 하고 Generate하면 됩니다.
두번째 방법은 소스에디터의 value에다가 마우스 오른쪽버튼을 클릭하고, Refactor -> Encapsulate선택하면 얘는 좀 더 상세하게 설정할 수 있습니다. 접근자를 수정할 수 있어요.
getter, setter가 완성이 되었습니다.
그 다음은 컨트롤러를 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 HelloController라고 하고, Package에다가 hellospring.controller라고 합시다.
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
private String formView = "nameView";
private String successView = "helloView";
@RequestMapping(method = RequestMethod.GET)
public String hello() {
return formView;
}
@RequestMapping(method = RequestMethod.POST)
public String onSubmit(Name name, ModelMap model) {
model.addAttribute("helloMessage", helloService.sayHello(name.getValue()));
return successView;
}
}
여기서 보면 HelloService는 @Service라는 어노테이션을 사용해서 객체스캔으로 helloService라는 bean이름으로 등록이 되어있습니다. 그래서 @Autowired해버리면 helloService랑 자동으로 연결이 되죠.
그래서 helloService를 사용할 수 있습니다.
여기서 신기한 점은 @RequestMapping어노테이션이 있는데, GET방식이면 hello메소드를 호출하라는 겁니다.
그래서 처음에 form action을 하지 않은 상태에서는 hello메소드가 호출이 됩니다.
Controller어노테이션의 신기한점은 메소드의 리턴값이 String인데 이 값이 view이름이 됩니다.
formView는 nameView라고 적어놨는데, 이것은 viewResolver에 의해 nameView.jsp파일을 호출하게 됩니다.
더욱 신기한 점은 onSubmit메소드입니다. 값을 받아서 알아서 맞는 곳에다가 넣는 것 같습니다.
그리고 view에다가 값을 던져줄 때는 ModepMap이라는 클래스로 메소드파라메터에 넣고, 여기에 addAttribute를 해서 helloMessage값을 넣으면 됩니다.
이제 View를 만들어봅시다.
Web Page -> WEB-INF -> jsp를 선택하고 오른쪽 버튼 클릭, New해서 jsp선택.
formView이름을 nameView로 지었기 때문에 JSP File Name에 nameView라고 합니다.
<body>
<h2>Enter your name</h2>
<form action="hello.htm" method="post">
Name:
<input type="text" name="value" />
<input type="submit" value="OK" />
</form>
</body>
action에서 hello.htm을 요청하는데 input필드는 한개입니다. 이름은 value입니다.
근데 신기하게도 우리가 만든 Controller를 보면 onSubmit에서 파라메터로 Name클래스로 받는 곳이 있습니다. 여기에 value멤버변수가 있는데 이름을 똑같이하면 그냥 Name클래스의 value값에 들어가버립니다-_-;
그럼 successView를 생성해봅시다.
Web Page -> WEB-INF -> jsp를 선택하고 오른쪽 버튼 클릭, New해서 jsp선택.
successView는 "helloView"라고 했기때문에 helloView라고 합니다.
<h2>${helloMessage}</h2>
라고 합니다. onSubmit메소드에서 넘겨주는 helloMessage값입니다.
그럼 이제 실행을 해봅시다.
http://localhost:8080/HelloSpring/hello.htm 라고 요청을 해봅시다.
그러면 Enter your name에다가 이름을 입력합시다.
이름이 나올껍니다.


아....자꾸 딴짓하네-_-; 일해야하는데-_-;


flex-messaging-core-FIXED_1.jar