2010년 5월 31일 월요일
Java Decompiler jad
[오라클]SGA/PGA 개념
SGA 메모리 구성은 위와 같다. 다수의 사용자가 접속하기에 DISK I/O를 줄여서 그 성능을 높이고자 제공되는 공유메모리인 것이다.
간단하게 구성되는 메모리 구조를 살펴보자
1. Shared Pool
DB에서 사용되는 모든 SQL문을 처리하는 영역
2. Data Buffer Cache
SQL문이 DML일 때 사용되는 영역
3. Redo LogBuffer
로그를 기록하는 영역, DML 문 실행 이전에 백업을 담당한다.
4. Large Pool
DB 백업 및 복원 작업 지원을 위해 사용되는 대용량 메모리 영역
5. Streams Pool
Oracle Streams가 사용하는 영역
6. Java Pool
자바로 작성된 프로그램
사용할 때 실행 계획을 저장하는 영역
PGA 메모리 구성은 위와 같다. 오라클은 개개의
사용자가 DB 접속 시 Server process를 생성하며, 이 프로세스의 대한 Data와 제어정보를 저장하는 메모리
영역이다.
참고사이트
펼쳐두기..
dynamic,static sql 구분하다
dynamic,static sql 을 구분
1. 우선 자신의 작성한 프로그램을 수행 합니다.
2. SELECT hash_value, piece, sql_text
FROM V$SQLTEXT
WHERE hash_value IN (SELECT
hash_value
FROM
V$SQLTEXT
WHERE sql_text like
'%프로그램내에기술된 테이블명%'
GROUP BY
hash_value)
GROUP BY hash_value, piece, sql_text
3.결과를 보고 조건절에 WHERE a = :a0 라고 되어 있는지 아니면 WHERE a = '1'
이런식으로 되어 있는지를 확인합니다.
이때 전자를 Static SQL 후자를 Literal SQL 이라고 합니다.
전자는 라이브러리 캐쉬를 공유 하므로 라이브러리 캐쉬에 Keep 을 하고 Parsing 하는데
어려움이 없지만 후자는 매번 메로리 Keep 과 Parsing 을 하게 되므로 성능에 치명 적입니다.
2010년 5월 19일 수요일
2010년 5월 18일 화요일
pojo란!!무엇인가!!
Java진영에서 어느날 갑자기 등장하여 개발자들을 모호하게 만들어 버렸던
POJO!!
이 녀석이 당췌 뭐야?
많은 사람들은 그럴싸한 이론으로 POJO를 포장하려 한다.
실제 강의나 책을 통해서 설명되는 POJO는 이해하기 힘듬. ㅜㅜ
본인 또한 처음 POJO란 용어를 접했을때 이게 뭐지?
직역하면 명백히 오래된 자바 객체?
아쒸 명백히 오래된 자바객체가 한두개야?
jdk 1.0 버전때 부터 제공되던 수 많은 클래스들을 통해 생성하는 객체들이 그럼 다 POJO야?
POJO는 2000년 9월에 열린 컨퍼런스(어떤 컨퍼런스인지는 모름)에서
Rebecca Parsons, Josh MacKenzie, Martin Fowler 가 처음 사용한 용어이다.
다른 개념 다 버리고
POJO = Java Beans
여기서 Java Beans는 Sun의 Java Beans나 EJB의 Bean을 뜻하는것이 아닌
순수하게 setter, getter 메소드로 이루어진 Value Object성의 Bean을 말한다.
예를 들면 아래와 같다.
public class SimpleBean {
private String name;
private String age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setAge(String age) {
this.age = age;
}
public String getAge() {
return this.age;
}
}
우리가 열심히 코딩하거나 이클립스를 통해 자동으로 생성하던
그 깡통 빈 클래스!! 를 통해서 생성된 객체!
맞다 바로 이것이 POJO 다.
그럼 왜 이전 부터 사용하던 Beans라고 말하지 않고
사람들 헤깔리게 POJO 새로이 불렀을까?
이유인즉, Beans라는 용어로 위의 깡통 빈 클래스를 정의하기에는
Java Beans나 EJB의 Beans와 구분이 모호하고 또한 Beans라는 용어로
정의되는 여타 다른 개념들과의 확실한 분리를 위해
POJO라는 용어를 사용한것이라 볼 수 있다.
Java GAE 시작하기下 (Datastore) [펌]
이번엔 시작하기(上)에 이어, 데이터스토어에 대해 정리해 보려고 합니다.
앱 엔진 자바 룩은 썬 마이크로시스템즈의 최고 오픈소스 임원으로부터 한 마디 핀잔을 들은 것 처럼, 자바 6를 지원하기는 하지만 전체 집합을 모두 지원하지는 않습니다.(꼭 핀잔을 들을 일이었는지는 모르겠지만.. 입장 차이겠죠?^^;)
예를 들어 java.io.FileInputStream을 지원하긴 하는데, java.io.FileOutputStream을 지원하진 않습니다. 얼핏 드는 생각으로는 구글 서버에 외부로부터의 파일이 유입되거나 악의적인 코드가 작성되면 골치아프다는 측면에서 빼버린 것 같다는 생각도 듭니다만, 이런저런 이유들이 있겠죠.
그래서 앱 엔진이 제공하는 인프라 자체에 데이터를 누적하는 방법이 상당히 제약적인데, 결국 앱 엔진이 제공하는 데이터스토어(Datastore)에 의지할 수 밖에 없습니다.
몇 가지 슬픈 점을 정리해보면, 우리가 매우 익숙한 create table 같은 DDL로 엔티티를 정의하고 insert into 문장이나 update set 문장으로 데이터를 추가/수정할 수 없습니다.
하지만 기쁜 점이 여전히 남아있기에.. 시도하지 않을 수 없습니다. 무료잖아요. 꽤 많은 저장공간과 꽤 많은 트래픽이 무료.. 무료...!! -ㅅ-;;
도무지 희망찬 일인지 잘 모르겠지만 아무튼 앱 엔진은 데이터스토어의 저수준 API만 제공하는 것이 아니라, JDO(Java Data Objects)와JPA(Java Persistence API) 인터페이스를 함께 제공합니다.
내공 깊은 시스템 프로그래머 같은 분이 아니라면 왠만하면 저수준 말고 제공해주는 도구를 쓰게 되는 게 자연스러운 심리인 것 같습니다.
처음엔 익숙치 않은 JDO 쓰래서 살짝 심술이 났지만, 제공되는 샘플 보니까 OOP 개념을 알고 있으면 쉽게 적용할 수 있는 방식인 것 같아서 마음이 편해졌습니다.
JDO의 세계에서는 create table 같은 액션을 클래스 작성으로 대신할 수 있습니다.
Employee.java
import java.util.Date;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Employee {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private String firstName;
@Persistent
private String lastName;
@Persistent
private Date hireDate;
public Employee(String firstName, String lastName, Date hireDate) {
this.firstName = firstName;
this.lastName = lastName;
this.hireDate = hireDate;
}
// 아래는 필드 접근을 위한 메소드들. JDO는 이 메소드들을 사용하지 않지만, 우리의 애플리케이션에서 필요해요.
public Long getId() {
return id;
}
public String getFirstName() {
return firstName;
}
// ... other accessors...
}
좋은 샘플이죠.~
@PersistenceCapable은 작성 중인 설계가 데이터가 되었을 때 지속범위 정도가 될까요?
IdentityType.APPLICATION은 이 데이터가 구글 앱 엔진 범위 내에서 유효하다는 것을 의미하고 IdentityType.DATASTORE가 구글 앱 엔진 대시보드에서 조회도 가능하고 외부에서 접근할 수 있게(멋대로 추측 중) 하는 범위를 뜻하는 것 같습니다. 저는 .APPLICATION으로만 테스트했고, DATASTORE로 하고 싶은 간절한 소망은 아직 지원하지 않는다고 해서 잠시 마음 한 구석에 접어 두었습니다.
한 번 훑으면서 이해하셨겠지만 @Persistent는 테이블 개념에서 컬럼을 나타내고, @PrimaryKey로 주 키 설정,IdGeneratorStrategy.IDENTITY로 아이덴티티를 설정해줄 수 있는 것을 볼 수 있습니다.
이제 엔티티 선언을 살펴봤으니 자료를 조회하고 쓰는 쪽을 봐야겠죠?
우리는 PersistenceManagerFactory 객체에서 얻을 수 있는 PersistenceManager라는 녀석으로 데이터스토어와 친하게 지낼 수 있습니다. 명세를 자세히 보시면 나오지만 PersistenceManagerFactory는 메모리에 활성화하는데 비용도 크고 애플리케이션 주기 동안 딱 한 번 만들어낼 수 있어서, 이 녀석을 static final로 넣어두고 실제 일을 도와줄 PersistenceManager만 땡겨 씁니다.
PMF.java
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
public final class PMF {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
private PMF() {}
public static PersistenceManagerFactory get() {
return pmfInstance;
}
}
자, 말씀드린 내용에 대한 샘플입니다. 필요한 static 메소드와 필드가 정의되어 있습니다. 그리고 아래처럼 활용이 가능합니다.
import java.util.Date;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import Employee;
import PMF;
// ...
Employee employee = new Employee("Alfred", "Smith", new Date());
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(employee);
} finally {
pm.close();
}
new Employee(...)와 같은 방법으로 데이터를 설정해주고 PersistenceManager의 makePersistent 메소드에 데이터를 넘겨서 insert할 수 있습니다. 만일 PrimaryKey가 같은 데이터가 이미 존재한다면 insert 대신 update를 합니다. 간단하죠?
그리고 JDO는 SQL 사촌 같은 이름을 가진 JDOQL을 제공합니다.
import java.util.List;
import Employee;
// ...
String query = "select from " + Employee.class.getName() + " where lastName == 'Smith'";
List<Employee> employees = (List<Employee>) pm.newQuery(query).execute();
어떤가요? 쉽죠? 보통 select 문과 좀 달라보이는 건, object를 얻어내기에 필드를 임의로 지정하지 못합니다. 그냥 다 가져와서 쓰면 됩니다. 비교문이 사실.. SQL 표준에 비하면 많이 빈약한데, 그래도 lastName like '%멍미%' 까지는 아니더라도 lastName like '멍미1%' 정도는 lastName >= '멍미1' and lastName < '멍미2' 정도로 표현해볼 수 있습니다.
이제 기본적인 사항들에 대해 어느 정도 살펴본 듯 한데, 지금 시점에서의 몇 가지 명세를 더 살펴봤습니다.
우리가 클래스로 정의했던 데이터 객체는 우리에게 친숙한 엔티티(entity) 정도로 볼 수 있고, 엔티티는 하나 이상의 프로퍼티를 가질 수 있습니다. 정수, 실수, 문자열, 날짜, 바이너리 등 여러가지가 될 수 있죠.
그리고 각각의 엔티티는 유일하게 구분할 수 있는 키를 가집니다. 위 샘플에서 본 것 처럼 1)데이터스토어가 제공해주는 숫자생성키를 사용하거나 2)애플리케이션에서 직접 문자열로 키를 지정해줄 수 있습니다.
JDOQL을 이용해서 특정 프로퍼티를 기준으로 정렬해서 데이터를 불러올 수 있고, 애플리케이션을 deploy하기 전에 텍스트 설정 파일을 통해 직접 인덱스를 설정해줄 수 있습니다.
트랜잭션과 관련해서 데이터스토어는 optimistic concurrency를 적용해서, 특정 애플리케이션 인스턴스가 엔티티를 수정하려는 시도를 하고 있는 동안은 다른 모든 인스턴스의 수정 시도가 실패하거나 재시도를 할 수 있습니다.
또한 어느 정도 기능과 사용량에 제약이 있으니 애플리케이션 개발에 나서기 전에, 요구사항을 충족할 수 있는지 살펴보는 것이 안전하겠습니다.
기능 부문
- 위에 언급한 것과 같이 지금은 IdentityType.APPLICATION만 지원하며 IdentityType.DATASTORE는 지원 예정,
- 조인이나 그룹핑 등 일부 구문,
- 그 외 아래 연결 주소 참조
사용량 부문
- 한 엔티티(row / record)의 최대 크기: 1MB,
- 한 엔티티를 위한 인덱스 값은 최대 1000개,
- 배치로 한 번에 넣고 지울 수 있는 엔티티 수는 최대 500개,
- 불러올 수 있는 건 2배인 1000개.
[펌]Java GAE 시작上 (Datastore)
- http://code.google.com/intl/ko-KR/appengine/
- http://code.google.com/intl/ko/appengine/downloads.html
- http://code.google.com/eclipse/docs/download.html
- http://code.google.com/intl/ko/appengine/docs/java/gettingstarted/
DataNucleus Enhancer (version 1.1.0) : Enhancement of classes
DataNucleus Enhancer completed with success for 0 classes. Timings : input=31 ms, enhance=0 ms, total=31 ms. Consult the log for full details
DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
Google App Engine에서 Spring3 + JPA 사용한 소녀시대 예제
암튼, "구글 앱 엔진"에서는 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/"); %>