http://cse-mjmcl.cse.bris.ac.uk/blog/2005/12/12/1134408595646.html

사용자 삽입 이미지


I've previously written a small del.icio.us clone using Hibernate where some of the code was generated using Middlegen. I like the Hibernate approach but it sometimes feels like a heavyweight approach for a simple application (e.g. sledgehammer to crack a walnut).

I have looked at using Spring and the JDBCTemplate looks like a nice way to handle JDBC access without the need to write all that tedious connection code and exception handling stuff. However, unless I go to great effort I'd probably end up with SQL hard coded in my Java classes and I'd need to do all the resultset to object mapping by hand.

I discovered iBATIS recently almost by accident. iBATIS used to be a commercial product but has now been donated to the Apache Foundation. iBATIS is an O/RM-like approach. Clinton Begin, iBATIS creator, says that "iBATIS is not an O/RM. It does not bind classes to tables, nor does is it limited to OO languages and/or relational databases" and elsewhere iBATIS has been described as a convenience framework for JDBC. iBATIS does not offer some of the benefits that Hibernate does (database independence etc) but on the plus side it is very simple to use and even more so if you choose to use Spring's SqlMapClientTemplate.

I came across iBATIS as it was one of the technologies included as an example Jetspeed2 Portlet. iBATIS distribute JPetstore as an example of using Struts, DAO layer and iBATIS together. The Jetspeed2 version of the application uses the Struts bridge to convert the application into a portlet. The idea behind iBATIS is that all your SQL is kept in an external XML SQLMapping file. iBATIS then maps the returned result into a domain object.

Spring includes support for iBATIS interaction. I spent a little time studying the iBATIS JPetstore example and a version of this which actually uses Spring is further explored in Bruce Tate and Justin Gehtland's book Better, Faster, Lighter Java (excerpts of which can be found on the OnJava web site [Demonstrating Spring's Finesse, Persistence in Spring]).

There is a Perl script which can be used to generate java-beans sources and sql-map config files generator. There is now also some iBATIS support inside Middlegen tool for the generation of iBATIS SQLMapping XML files and associated domain object POJOs. Looking at the DAO approach used in Better, Faster, Lighter Java and similarly using Spring's iBATIS support it seemed very possible to me that I could extend the existing iBATIS Middlegen Plugin so that it would generate the required DAO classes to implement the architecture shown in the diagram below.


 

The default iBATIS Middlegen plugin generates the CRUD actions needed for the SQL mapping and creates the definition of each domain object. It was relatively straight forward to modify these basic examples to create DAO interfaces, DAO implementation (using Spring SQLMapClientTemplates) and also a Façade interface / implementation.

To do this I had to learn a to use the Velocity Templating Language (VTL) to extend Middlegen code but since I have some shell scripting and XSL experience this is not that daunting a task.

Using the default Middlegen iBATIS plugin you can create an SQL Mapping file and domain object POJO class. For this example I have created a single Table called ITEM with one column containing an ITEM_ID. The generated iBATIS XML SQLMapping file is shown below. Notice how this contains the full range of CRUD operations.

<?xml version='1.0'?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
    "http://www.ibatis.com/dtd/sql-map-2.dtd">

<!-- WARNING: This is an autogenerated file -->

<sqlMap>        
        <typeAlias alias="Item" type="mypackage.domain.Item"/>
        <!--
    <cacheModel id="$table.destinationClassName-cache" type="MEMORY">
        <flushInterval hours="24"/>
        <flushOnExecute statement="insertItem"/>
        <flushOnExecute statement="updateItem"/>
        <flushOnExecute statement="deleteItem"/>
        <property name="reference-type" value="WEAK" />
    </cacheModel>
        -->
    <resultMap class="Item" id="Item-result" >
        <result
                property="itemId"
                javaType="java.lang.String"
                column="ITEM_ID"
        />
    </resultMap>

    <select id="getItem"
        resultClass="Item"
        parameterClass="Item"
        resultMap="Item-result" >
        <![CDATA[
            select
                ITEM_ID
            from
                ITEM
            where
                ITEM_ID = #itemId#

        ]]>
    </select>

    <update id="updateItem"
        parameterClass="Item" >
        <![CDATA[
            update
                        ITEM
            set

            where
                ITEM_ID = #itemId#
        ]]>
    </update>

    <insert id="insertItem"
        parameterClass="Item" >
        <![CDATA[
            insert into ITEM
              (ITEM_ID )
            values
              (#itemId# )
        ]]>
    </insert>

    <delete id="deleteItem" parameterClass="Item"  >
        <![CDATA[
            delete from ITEM where ITEM_ID = #itemId#
        ]]>
    </delete>

</sqlMap>

The default Middlegen iBATIS plugin will generate corresponding transparent domain object class (business objects), one per table. The domain should capture the relationships between the various system entities much as an Entity Relationship Diagram does and this is why we can generate this from the database directly. The generated classes are a "bare" platform into which you should expect to add more sophisticated behaviours. These really should contain behaviour as you'll probably recall from object oriented programming first principles a class should contain data and methods. Obviously the precise behaviour cannot be generically generated as it is likely to be domain object specific. If you do not add additional behaviour at this point you may be guilty of using an Anemic Domain Model.

package mypackage.domain;

import java.io.Serializable;
import java.sql.Timestamp;
import java.math.BigDecimal;
import org.apache.commons.lang.builder.HashCodeBuilder;

/**
 * @author <a href="http://boss.bekk.no/boss/middlegen/">Middlegen</a>
 *
 */
public class Item implements Serializable 
{
    // fields
    /**
     * The itemId field
     */
    private java.lang.String itemId;

    // getters/setters
    /**
     * Returns the itemId
     *
     * @return the itemId
     */
    public java.lang.String getItemId() 
    {
        return itemId;
    }

    /**
     * Sets the itemId
     *
     * @param newItemId the new itemId
     */
    public void setItemId(java.lang.String newItemId) {
        this.itemId = newItemId;
    }


    /**
     *  Implementation of equals method.
     */
    public boolean equals(Object object) 
    {
        if (this == object)
        {
            return true;
        }
        if (!(object instanceof Item))
        {
            return false;
        }
        Item other = (Item)object;
        return
                  this.itemId.equals(other.itemId);      }

     /**
      * Implementation of hashCode method that supports the
      * equals-hashCode contract.
      */
/*
    public int hashCode()
    {
        return
             hashCode(this.itemId);     }
*/
     /**
      * Implementation of hashCode method that supports the
      * equals-hashCode contract.
      */
    public int hashCode() 
    {
        // TODO generate random number following the contract
        HashCodeBuilder builder = new HashCodeBuilder(17,37);
        return builder
            .append(itemId)
            .toHashCode();
    }

    /**
     *  Implementation of toString that outputs this object id's
     *  primary key values.
     */
    public String toString() 
    {
        StringBuffer buffer = new StringBuffer();
        buffer.append("itemId=");
        buffer.append(this.itemId);
            return buffer.toString();
        /*
        return
             this.itemId;           */
    }
}

I created Middlegen iBATIS Plugin extensions to generate the next few classes. This is an example of a generated DAO interface class. There will be one DAO interface class per domain object (i.e. one per table).

package mypackage.iface;

import  mypackage.domain.Item;

public interface ItemDao
{
    public Item getItem( java.lang.String itemId);
    public void insertItem(Item item);
    public void updateItem(Item item);
    public void deleteItem(Item item);

}

This is DAO implementation of the above interface using Spring's SqlMappingClientTemplate, again there will be one of these per domain object (i.e. one per table):

package mypackage.sqlmapdao;

import mypackage.domain.Item;
import mypackage.iface.ItemDao;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

public class SqlMapItemDao extends SqlMapClientDaoSupport implements ItemDao
{
    public Item getItem(java.lang.String itemId){
        Item item = new Item();
        item.setItemId(itemId);
    return (Item) getSqlMapClientTemplate().queryForObject("getItem",item);
    }

    public void insertItem(Item item) {
        getSqlMapClientTemplate().insert("insertItem",item);
    }

    public void updateItem(Item item){
        getSqlMapClientTemplate().update("updateItem",item);
    }

    public void deleteItem(Item item){
        getSqlMapClientTemplate().delete("deleteItem",item);
    }

}

In this most simple example the usage of a façade seems fairly pointless. The idea comes into it's own when you start to have more than one table of data represented in your domain. A façade collects all the publicly accessible DAO methods into a single interface. It also serves as an attachment point for other services, such as transaction support. In writing a Struts Action you would query against the façade rather than trying to obtain a DAO method directly. There will be only one instance of the façade layer interface and implementation it will likely contain references to all the DAO interfaces for every publicly accessible domain object.

See Persistence in Spring for more details about why we might want to generate a façade interface and implementation.

Façade interface:

package mypackage.domain.logic;

import mypackage.domain.Item;

public interface Façade
{

    public Item getItem( java.lang.String itemId);
    public void insertItem(Item item);
    public void updateItem(Item item);
    public void deleteItem(Item item);

}

Façade implementation:

package mypackage.domain.logic;

import mypackage.iface.ItemDao;
import mypackage.domain.Item;

public class FaçadeImpl implements Façade
{

    private ItemDao itemDao;

//-------------------------------------------------------------------------
// Setter methods for dependency injection
//-------------------------------------------------------------------------


    public void setItemDao(ItemDao itemDao) {
        this.itemDao = itemDao;
    }

//-------------------------------------------------------------------------
// Operation methods, implementing the Façade interface
//-------------------------------------------------------------------------



    public Item getItem( java.lang.String itemId){
    	return this.itemDao.getItem(itemId);
    }

    public void insertItem(Item item){
        this.itemDao.insertItem(item);
    }

    public void updateItem(Item item){
        this.itemDao.updateItem(item);
    }

    public void deleteItem(Item item){
        this.itemDao.deleteItem(item);
    }

}

As you can see from the above examples, I have now extended the Middlegen iBATIS Plugin to create a simple version of the entire Spring based DAO layer code. I'm currently looking into generating more complex domain relationship behaviour but this has so far only been slightly hampered by my limited VTL scripting skills but it is certainly possible to do this with Middlegen as the Hibernate and EJB plugins produce something similar. I am hoping to better capture one-to-many relationships in the domain model so that I can detect these and generate appropriate SQLMapping and Java code. For example if we added a new domain object called CATEGORY it might contain many ITEMS and could therefore our Category domain object might contain:

private List items;

public List getItems()
{
    return items;
}

public void setItems(List items)
{
    this.items = items;
}

The following could be generated inside an appropriate XML SQL Mapping file:

<select
    id="getItemsByCategoryCode"
    parameterClass="java.lang.String"
    resultMap="itemMap">        
    select
        item_id,
        item_name,
        category_code
    from
        items
    where
        category_code = #value#;
</select>

* where itemMap is already defined someplace.

The Spring DAO implementation of this could then look something like:

public List findItems(Category category){
    getSqlMapClientTemplate().queryForList("getItemsByCategoryCode",category);
}

public void createCategoryWithItems(Category category){
    getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
         public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                 executor.startBatch();
        for (Iterator it=category.getItems().iterator(); it.hasNext(); ) {
                Item item = (Item) it.next();
                executor.insert("insertItem", item);
            }
                 executor.executeBatch();
                 return null;
         }
 });
}

Nothing that I have generated so far is especially complicated but it is still nice to be able to generate basic business objects and a working DAO layer without much effort. I'd be happy to share the Velocity templates that I used to create these classes.

Comments
 
hello, i think you should take a look at http://ibatis.apache.org/abator.html
Abator looks cool but is there anyway it could be run from Ant as I find Eclipse awkward to use. My preference is to use Netbeans.
"The core code generation functionality of Abator does not require Eclipse, and can be run as a standalone JAR - I'll post some instructions about how to do that if anyone is interested." i tkink you could ask this question on the ibatis list.
Hi Olivier,

I downloaded Abator yesterday and had a little look at. I took a look at the source code and very impressive it was too but from what I have seen so far it did not look very extensible.

Compare iBATIS Abator code that generates the domain bean:

JavaModelGeneratorDefaultImpl.java

with the Middlegen velocity template that does the same job:

iBatis-bean.vm

Middlegen is a free general-purpose database-driven code generation engine which uses Velocity templating. It is used in communities other than iBATIS (including Hibernate) and so therefore has the advantage that it is a little more widely used and tested.

Say for example I wanted to add something to all my insertXXX DAO methods, using Abator I would have to modify the Java generation source code and recompile it. If I wanted to make a change to a particular generated method using Middlegen I would only need to modify a Velocity template file, which is very easy to do.

I'm sure the code that Abator produces is probably a little superior to what the iBATIS Middlegen plugin currently produces but this is easily remedied. I will certainly take a look at the source code that Abator produces once I manage to get it working!

For the reason that it is easily configurable, extensible and more widely used, I would expect in the future I would still choose to use Middlegen rather than iBATIS Abator to generate my iBATIS related code.

First, i have to say thanks for this article. Second, i'm trying to implement ibatis, spring and JSF. Not so hard until now but i have a special requirement, i need to handle the transaction in a EXTERNAL way, like the documentation of iBatis suggest. My quesyion is, Do you know how can i implement iBatis and Spring handling by my own the transaction??. DO i need to configurate something else in the applicationContext.xml or dataAccessContext-xxx.xml?. Anyway, thanks fro your help
Hi Othon,

I started replying to this and it got too large to be a comment, so I've added a new blog entry called Transaction Management with iBATIS and Spring for you.

Hope it helps,

Mark
Thanks for the article Mark, very informative. I was about to use Abator but after some research agree with your conclusions and am also going to go with middlegen - customisation of the generated code is a crucial factor and easier with middlegen at present as you say. Would be very interested in seeing the velocity templates and any java modifications you made to the middlegen ibatis plugin, as I'm about to embark on the same dao-generating exercise. Thanks, John
Hi John,

I have extended Takashi Okamoto's Middlegen/iBATIS plugin modifications. (I'm not actually sure how it differs from the iBATIS plugin currently in the Middlegen CVS).

The following "distribution" contains iBATIS plugin source plus my modifications (I make no claims about production worthiness) and the sample iBATIS/Middlegen application. I have modified the sample application to additionally use Apache Derby and Spring. I've also added one or two extra ant targets so the process would now be:

ant create-tables
ant middlegen
ant compile
ant run

middlegen-2.1.zip [8.2Mb]
Hi very informative but i want to return the primary key of the table during insertion .How is it possible with this arrangement ?
Hi

I have not covered that here. I had the same query, the precise details depend on what database you are using. I am using Apache Derby.

For details of how to do this with Apache Derby see my comment on the following iBATIS wiki page:

How do I use an insert statement? (other DBs are also covered there).

Nice to meet you, Mark. I want to read a source code of your Middlegen/iBATIS plugin. But, I was not able to download it because it's a broken link. Would you revise a broken link? Please thanking you in advance.
Sorry about that, somebody moved my file space without telling me. You should now be able to get it here:

middlegen-2.1.zip

DB2 운영가이드

Posted 2007. 3. 28. 09:58

JSR237

Posted 2007. 3. 27. 19:33
JSR237 - 나온지 3년이나 되었군....
objectA == objectB
objectA.equals(objectB)

이 GAP 이 Relational model에서는 unique identifer column 으로 구분....된다 ( 상속도 있고 다른것도 많지만 )
차이는 이것에서 시작이 된다.

PointCut 예제, Advice등의 모음

Posted 2007. 1. 11. 01:40
클릭
나름 좋아 보임... 정리 잘되었음...

스프링의 Pointcut 아래와 같음 위의 예제는 몇개밖에 없지만 꼭 필요한 것들임
org.springframework.aop.support.ComposablePointcut
org.springframework.aop.support.ControlFlowPointcut
org.springframework.aop.support.DynamicMethodMatcherPointcut
org.springframework.aop.support.JdkRegexpMethodPointcut
org.springframework.aop.support.NameMatchMethodPointcut
org.springframework.aop.support.Perl5RegexpMethodPointcut
org.springframework.aop.support.StaticMethodMatcherPointcut


advice도 5가지 - 이것도 예제 참조
Before Advice : org.springframework.aop.MethodBeforeAdvice
After returning Advice : org.springframework.aop.AfterReturningAdvice
Around Advice : org.springframework.aop.MethodInterceptor
Throws Advice : org.springframework.aop.ThrowsAdvice
Introduction : org.springframework.aop.IntroductionInterceptor



Spring JDBC Template

Posted 2006. 12. 28. 00:36
http://www.oracle.com/technology/global/kr/pub/articles/marx_spring.html
갑자기 패턴 생각이 나서 링크 걸었음.


어제는 친구에게 전화가 와서 대뜸 물어보는것이 ....
친구 : Spring을 쓰면 좋냐 ??
나 : 쓰기 나름이지.... 좋고 나쁘고는 없어....

가끔 느끼는 것이지만.... 아무런 대책도 없이 기술들을 마구 접하고 업무에 적용하다 보면 안쓰는것 보다도 더 안좋다고 생각한다. 즉 땜빵식 기술 접함..... 스터디는 좋다.
이것을 에자일 하다고 표현하는 이가 있기도 하다. 정말 에자일인가 ? 모르겠다. 알아서 생각하면 될듯....

외국 사이트에서  무슨 글을 읽다가 발견한....스프링을 안쓰는 이유가 "몰라서" 라고 한것 같다. 배워도 안되는 것이 있다. 경험인 것이다. 이것을 얼만큼 많은 업무에 써보고 그것을 아는가.... 라는..... 대안은 얼마나 있고..... 어디서 정보를 얻어야 하며....
기타 등등 생각할것이 많은 것이 고민거리이다.....
만일 우리집 홈페이지라면 그냥 암거나 써서 만들겠지만 말야....

친구에게 답해줬다.
"네가 하고 있는 프로젝트에 20% 이상 파일럿을 진행하고...check list 만들고 ....
안되는 것에 대해서 Gap분석을 한후 대안을 찾아.... 어차피 기술이나 아키텍처는 대안 이 매우 중요해서 대안이 없다면  억지로 기술을 적용할 필요는 없어, 최신기술을 쓰려다 비지니스를 서포팅 못한다면...안하느니 못하지....
네가 하고 있는 것에 안 맞을 지도 몰라... 좀더 많은 자원과 시간이 필요 하겠지...공짜가 어디있어...!!... 문서화도 해라... 간단하게 라도 해둬야 나중에 뭐했는지 알꺼 아냐... 나한테 대강 이란말 쓰지마... 그게 재앙을 가져온다....생각할게 얼마나 많은지 알아 ??? 이게 다가 아니라고.... 정말 내 도움이 받고 싶다면 문서화 해서 보내.... "

내가 보기엔 프레임워크가 문제가 아니라.... 사람의 마인드가 문제인듯...
좋다면 무조건 질러버리고 만다는... 지금 그래서 나또한 손해본게 한두개가 아니자나....
여전히 계속...쭈욱.. 그러고 있다. 나도 그러했다.


문서화를 하라는게 아니고 최소한 생각이나 한번은 해봤는지....
부끄럽지도 않은 모양이다..... 그때 그때 머리에서 생각나면 하는게 에자일이라고 우기는 인간도 간간히 있었음....

지금까지 본 몇몇 미신은 이러했다.
DDD면 다 해결 된다. :  네가 말하는 DDD는 국제전화임이 틀림이 없을 것이다.
Spring이면 다 해결된다 . : 봄에 뭐 어쩐다고....
웹서비스가 연동의 모든것이다. 그리고 나선 트렌젠션 어케 하냐고 나에게 묻는다. 질러놓고 보냐 ??
오픈소스는 소스가 공짜여서 맘대로 고치고 피드백도 빠르니깐 적용하고 본다.
IoC를 반드시 적용한다. AOP를 반드시 적용한다.


어떤 이에게는 이렇게 말해주고 싶다.
집에 홈페이지나  그렇게 만드세요..... 회사 피해주지 말공... 집에가셔서.....

javadoc tool 에 관한 또다른 생각중

Posted 2006. 11. 22. 10:15
http://java.sun.com/j2se/javadoc/writingdoccomments/

javadoc tool 에 관한 또다른 생각중

Types of Inversion of Control

Posted 2006. 10. 30. 23:22
이전에 보았던 책인데 다시 보고 조금 정리 중입니다. ^^


Types of Inversion of Control - proSpring에서 인용함.


* Dependency Lookup comes in two types:
  1. Dependency Pull
  2. Contextualized Dependency Lookup (CDL).
* Dependency Injection also has two common flavors:  물론 메서드 인젝션도 있음
  1. Constructor Dependency Injection
  2. Setter Dependency Injection.


1-1. Dependency Pull
public static void main(String[] args) throws Exception {
 
       // get the bean factory
       BeanFactory factory = getBeanFactory();
 
       MessageRenderer mr = (MessageRenderer) factory.getBean("renderer");
       mr.render();
}

EJB개발을 하면서 저런 스타일은 많이 봐온 스타일이다 (JNDI Look Up) . 즉 이미 익숙한 패턴인것이다.
이것을 IOC 입장에서 설명하면 Dependency Pull 이다.


1-2. Contextualized Dependency Lookup (CDL)

public interface ManagedComponent {
 
  public void performLookup(Container container);
}

보는바와 같이 인터페이스에 1-1 처럼 레파지토리가 아니고 Context를 이용하는게 보인다.

2-1 Constructor Dependency Injection
public class ConstructorInjection {
 
  private Dependency dep;
 
  public ConstructorInjection(Dependency dep) {
       this.dep = dep;
  }
}

보는 바와 같이 Constructor를 이용하고 있다.
Constructor의 Argument를 이용하고 있다.
어느때 Constructor IoC를 쓰고 Setting IoC를 이용할지는 http://itgs.tistory.com/71
에 많은 자료를 두었다.

2-2 Setter Dependency Injection.

public class SetterInjection {
 
  private Dependency dep;
 
  public void setMyDependency(Dependency dep) {
       this.dep = dep;
  }
}

Spring Framework에서 가장많이 쓰이는 Injection이다. 일반적으로 java bean의 Set 메서드형태이며 configuration을 이용해서 객체를 할당한다.
http://itgs.tistory.com/71 에 가면 좀더 많은 자료가 있다. 물론 .net버전의 Spring에 대한 자료이지만 개념적으로 좀더 잘 설명이 되어 있어

Lookup 기반의 컴포넌트를 제작하게 되면 나중에 Test하기가 나빠진다.
WAS환경과 똑같이 만들기가 힘들다. 그러나 이미 많은 사람들도 알다시피...
IoC덕택에 pico Container 덕택에 Testing을 자동화하고 가상 객체들을 쓰는데 익숙해지게 된다. 이러한 것이 스프링 프레임워크의 특징이며 컨테이너라는 용어를 가져다 칭할수 있는 것이다.

요즈음 pro Spring을 다시 보고 있다. IT거버넌스를 하는데 pro Spring을 보냐고 묻는 사람들도 많이 있지만.... 일단 재미도 있기도 하고....
자세히 알만한것들은 몇가지 자세히 기술을 알 필요가 있기에 그렇다.
3년전인가... Spring을 이용해서 모 사이트를 구축했는데...
아직도 그것이 잘 이해 되지 않은 상태에서 구축되어 아쉬움이 많이 남는다.
아키텍처가 좋다 나쁘다는 말하기 힘들겠지만....

(실제 나는 나쁜 아키텍처가 존재한다고 생각하지는 않는다.)


Spring Framework은 EJB를 연동시 자신의 메커니즘(스프링이 컨테이너임을 좀더 인지한다면 IoC의 개념을 최대한 사용해야 했었다. )을 최대한 사용해야 한다.


아래의 자료는  DI에 대해서 구체적으로 잘 설명된 자료임.참조자료 ^^




Constructor Injection과 Setter Injection의 차이를 잘 설명하고 있다. 출처는
http://www.codeproject.com/cs/design/DependencyInjection.asp
이며 저 아래 보면
AOP에 대해서 나온다. 이러한 코드에 대한것들은 주로 .NET 이며
현 코드는 Spring .net 이다. java와 거의 다르지 않으므로 좋은 기사가 될듯 ^^


ps : 아래는 Spring java 버전의 글이지만...별다른 다른 점은 없음

Rod Jonson의 홈페이지에도 몇몇 글이 있다. 비교하면서 보면 좋을듯 ^^
(이젠 다른사이트에 블로그를 올린다. 오래된 블로그임)
http://blog.springframework.com/rod/?p=1




Pojo In Action에도 몇몇 글이 나온다. 빈을 어케 하는지에 대해서 나오는데
약간 설명한것 여기 소개하면 여기서는 constructor injection을 쓴다. 이유는 있다.
http://www.developer.com/java/ejb/print.php/3594121
이다.

자러가야지...졸리네...

http://www.theserverside.com/news/thread.tss?thread_id=34167 요것도 좋은글
http://forum.springframework.org/showthread.php?t=23139
링크하나더