'ITWeb/개발일반'에 해당되는 글 490건

  1. 2012.03.12 java interface 왜 사용하나요?
  2. 2012.03.12 2. Spring MVC 에 MyBatis 적용해 보기. 2
  3. 2012.03.09 [링크공유] mybatis + spring from 구글.
  4. 2012.03.09 [링크공유] Spring MVC tutorial
  5. 2012.03.09 [기초] Spring MVC 구성해 보기.
  6. 2012.03.08 Spring Framework MVC + MyBatis Empty 설정 맛보기.
  7. 2012.03.08 Spring Framework 설정관련 기초.
  8. 2012.03.06 VIM no indent 설정.
  9. 2012.03.06 java classpath setting
  10. 2012.03.05 Spring Security Role 정의

java interface 왜 사용하나요?

ITWeb/개발일반 2012. 3. 12. 11:18
[interface 는 왜 사용하나요?]
- 요기에 토론이 있내요. : http://www.okjsp.pe.kr/seq/161248 


[개인적인 의견]

interface 를 사용하는 건 개인적으로
- 개발한 코드의 종속성을 줄이고 유지보수성을 높이기 위함이 아닐까 싶습니다.
- 뭐 설계를 잘해야 하는건 당연한 말이겠지만 가져다 사용하는 사람 입장에서 뒤에 뭐가 바뀌었다고 앞에 뭐를 고쳐야 한다고 하면.. 이게 삽질이 아니고 뭐겠습니까...

암튼 전 어려운말 별로 안좋아 해서.. 그냥 유지보수의 편의성이라고 우겨 봅니다. ㅎㅎ 



[Interface 의 다중 type 이해]

직접 인터페이스를 선언해서 사용해 보자.

public interface Book{

    private String author;

    private String title;

    public void publish(){

        //출판

    }

}


public class Cartoon implements Book{

    //author와 tittle에 접근 할 수 있음

    public void publish(){

        // 꼭 구현해야함

    }

}


public class Novel implements Book{

    //author와 tittle에 접근 할 수 있음


    public void publish(){


        // 꼭 구현해야함


    }

}


이제 부터 진짜 중요한 부분이다. 이 부분을 이해해야 객체 지향의 진정한 의미를 알게 되는 것이다.


Cartoon c = new Cartoon();

Novel n = new Novel();


보통 일반적으로 저렇게 많이 선언해서 사용한다.

하지만 이렇게 한 번 해보자.

Book c = new Cartoon();

c.publish();//만화책 출판


Book n = new Novel();

n.publish();//소설책 출판


위에 의미를 이해 하겠는가? 클래스 형식이 인터페이스 형식인것이다.

Type이 인터페이스가 될 수 있다. 이렇게 됐을 때 인터페이스의 메소드를 호출하게 되면 실제는 생성된 클래스의 구상 메소드가 호출된다.

인터페이스라는 것을 통해서 클래스의 기본 틀을 얻을수 있으며 구상 클래스들에 접근할수 있다는 것을 보았다.


이렇게 하면 좋은 점이 무엇이냐 하면 구상 클래스에 의존하지 않은 인터페이스에 의존하는 프로그램을 작성할 수 있다는 것이다. 인터페이스에 의존한다는 것은 쉽게 말해서 고정된 틀에 얽매이지 않아도 되는 것이다. 물론 인터페이스의 틀에는 얽매이겠지만 적어도 공통된 틀이기 때문에 어느 클래스에도 접근할 수 있다는 것이다.



[Polymorphism]

0. 개요

지금껏 객체지향의 꽃은 '다형성'이라는 말을 많이 들어봤을 것이다. Java 내에서도 이 다형성이라는 놈을 구현하기 위해 여러 가지 장치를 마련해놓았다. 사실 다형성이란 단어를 한 마디로 압축해서 정의하기는 어렵지만, 필자가 지금껏 Java를 공부하면서 느낀 '다형성'은 '융통성', '확장성'과 일맥상통한다고 말하고 싶다. 이번 강좌는 '융통성(확장성)'에 촛점을 두고 다형성에 대한 이야기를 풀어나가고자 한다.

1. 사전적 의미
다형성에 대해 백과사전에서 찾아보면 동질이상, 즉 화학적인 조성은 같은데 결정구조에 따라 형태가 달라지는 현상을 언급하고 있다. 이를테면 CaCo₃과 같이 화학식은 같은데, 입체적인 구조에 따라 방해석과 아라고나이트로 형태가 달라지는 식이다. 이러한 내용을 정확히 프로그래밍에 대입하기는 어렵겠지만, 프로그래밍에서 넓은 의미의 다형성이라고 한다면 '한가지 표현 방식으로 여러 가지 기능을 수행할 수 있는 것'이라고 표현할 수 있다.

2. Interface
넓은 의미에서의 인터페이스란 외부와의 의사 소통을 위한 매개체이다. 의사 소통을 위해서는 외부와의 정해진 약속이 있어야 할 것이다. 이를 강조하는 의미에서 예전 강좌에서 인터페이스를 '표준 규격'이라고 설명한 적이 있다.

인터페이스를 정의하고 활용하는 이유는 물론 인터페이스를 구현하는 부품들이 중구난방이 되지 않기 위한 최소한의 규약을 정하기 위해서이지만, 이를 약간 넓게 생각해본다면 확장의 여지가 있는 부분을 클래스로 제작해 닫아버리기보다는 인터페이스로 선언하여 최소한의 선을 정해놓고 융통성을 발휘하고자 하는 의도도 포함되어 있다.

(1) 표준 규격

간단한 예로 컴퓨터에 키보드나 마우스를 연결한다고 생각해보자. 우리는 단지 키보드와 컴퓨터를 연결하는 단자가 PS/2 형식인지, 혹은 USB 형식인지를 확인하면 된다. 여기서 말하는 PS/2나 USB 포트는 일종의 규격이며, 형식에 맞게 제작된 키보드나 마우스는 해당 단자에, 구멍에 맞게 끼우기만 하면 어느 회사에서 만들었든간에 아무런 문제 없이 사용이 가능하다. 예전에 beginning 강좌에서 들었던 220V 콘센트의 예도 마찬가지일 것이다. Java 프로그래밍에서의 인터페이스의 기본 개념도 이러한 예들과 흡사하다.

인터페이스의 기본적인 의미는 인터페이스를 구현한 클래스들을 그룹화하고, 해당 그룹의 필수 메서드들을 선언함으로써 그룹을 형성하는 클래스들에게 외부와의 대화 방침을 대내외적으로 알리고자 하는 것이다. 인터페이스는 개발자에게는 인터페이스의 내용을 충실히 구현할 의무를 부여하고, 사용자에게는 인터페이스의 내용만 알면 해당 그룹의 클래스를 세부 명세 없이도 인터페이스 명세에 따라 사용할 수 있다는 메리트를 제공한다. 더 깊이 생각해보면 인터페이스는 본질적으로 encapsulation과 이어져 있다. 즉, 외부와의 대화를 인터페이스를 통해서만 할 수 있도록 하는 것이다.

(2) 확장성

사실 인터페이스는 공동 작업을 위해 존재한다. 혼자서 프로그램의 모든 부분을 코딩하고 수정하는 수준의 작은 규모의 작업이라면 인터페이스는 그다지 필요가 없다. 그래서 표준 규격이라는 비유가 적절한 것인지도 모르겠다. 실제로 Java에서 제공하는 기본 API를 살펴보면 이들 사이 인터페이스의 체계적인 모습에 감탄하게 될 것이다. 그러나 인터페이스는 단순히 규격을 정하는 데에서 그 의미를 다하지 않는다. 잘 선언된 인터페이스는 항상 확장성을 염두에 두고 있다.

예를 들자면 Review 강좌의 두번째 글의 예와 같을 것이다. logging에 대한 출력을 콘솔, 파일, DB, Mail 등 여러 가지 방식으로 할 수 있는데, 여기에 신속한 장애 대처를 위해 ERROR 레벨 로그를 관리자에게 SMS로 보내는 방법을 추가하고자 하는 상황이 있을 수 있다. 이때 logging 출력 라이브러리들을 인터페이스로 그룹화해서, 이들이 공통으로 구현해야 하는 로그 찍기 메서드를 선언만 해두었다면, SMS 출력용 클래스를 logging 인터페이스에 맞게 구현만 하면 간단하게 확장이 될 것이다.

(3) 인터페이스와 형변환, 그리고 다형성

흔히 상속, 인터페이스와 관련해서 다형성을 설명할 때 '상위 클래스 타입의 객체 참조 변수에 하위 클래스 인스턴스를 연결할 수 있다'고 말한다. 이제 위에서 설명한 내용을 생각해보면서 이 문장을 구체적으로 살펴보도록 하자.

// 인터페이스 Eproduct : 가전제품을 총칭하는 인터페이스
interface Eproduct { void disp(); }

// 가전제품 인터페이스를 구현하는 클래스들
TV implements Eproduct {

   int channel = 11;
   public void disp() { ... 저장된 채널값을 바탕으로 해당 채널을 TV 화면에 보여주는 내용 ... }
   public int setChannel(int ch) { this.channel = ch; }
   ... 다른 구현부

}

CDplayer Implements Eproduct {

   int cdNumber = 1;
   public void disp() { ... 오디오 CD의 현재 곡 번호를 액정에 표시하는 내용 ... }
   public int setCdNumber(int cdNum) { this.cdNumber = cdNum; }
   ... 다른 구현부

}

TV와 CD플레이어 클래스는 모두 가전제품 인터페이스를 구현하고 있다. 이들 클래스에서 인스턴스를 뽑아내는 방법은 다음의 두가지이다.

(a) TV tv = new TV(); CDplayer cdp = new CDplayer();
(b) Eproduct tv = new TV(); Eporduct cdp = new CDPlayer();

disp() 메서드를 활용하는 리모콘을 구현하는 메서드를 다음과 같다고 하자.

   remocon(Eproduct thing) { thing.disp(7); }

이제 remocon() 메서드에 tv와 cdp가 매개변수로 들어가는 경우를 나누어서 생각해보자.

(a) 자손형 객체변수를 인터페이스형 파라미터 공간에 대입하게 되면, 임시 upcasting이 일어난다. 즉, 매개변수 thing은 Eproduct형이지만, 결론적으로는 자손형 인스턴스를 참조할 수 있다.
(b) (a)에서 임시로 형변환이 이루어지는 과정을 아예 인스턴스 생성 부분에서 표현하고 있다. 즉, Eproduct 타입인 tv 객체 참조 변수로 TV 타입 인스턴스를 참조하고 있는 것이다. 이 경우 tv 변수로 TV 인스턴스의 setter 메서드인 setChannel()에 접근할 수 없다. (a)와 같은 경우에도 remocon 메서드 안에서 thing 지역 변수는 절대로 setChannel()이나 setCdNumber()에 접근할 수 없다.

(c) 그렇다면 다음과 같은 예는 어떠한가?

Eproduct tv = new TV();
TV realTV = (TV)tv;
realTV.setChannel(9);

결론만 이야기하자면 realTV 변수는 tv가 가리키는 인스턴스의 모든 것을 다시금 접근할 수 있게 된다. tv는 단지 Eproduct형 객체 참조 변수이기 때문에 TV 인스턴스의 고유 메서드에 접근할 수 없을 뿐이지, 인스턴스 자체에 손실이 있는 것은 아니다. 따라서 TV형 참조 변수를 이 인스턴스에 연결하는 것도 합법이며, RealTV는 아무런 손실 없이 tv가 가리키고 있던 TV형 인스턴스의 고유 메서드를 모두 사용할 수 있게 된다. 위와 같은 예를 downcasting이라고 하는데, (b)와는 달리 강제로 형변환하지 않으면 대입 자체가 불가능해진다.

(d) 확장성과 연관지어 생각해보자면, 위의 리모콘 메서드는 가전제품 인터페이스를 구현하는 두 종류의 인스턴스를 매개변수로 받고 있다. 가전제품 인터페이스를 구현하는 다른 클래스, 이를테면 MicowaveOven이라던가 AirConditioner와 같은 새로운 클래스를 제작하게 되더라도 리모콘 메서드에 변화를 주지 않고 Eproduct형으로 인스턴스를 받을 수 있을 것이다. 가전제품 인터페이스를 활용하는 개발자 입장에서는 전자렌지나 에어컨이 구현하는 인터페이스의 내용 disp()의 세부 구현 사항을 알 필요가 없다. 그저 이들의 disp()를 호출했을 때 '액정이나 화면에 핵심 정보를 출력하는 기능'을 수행한다는 인터페이스 명세서를 가지고 있으면 된다.

3. 상속, 인터페이스에서의 유의점 몇 가지
복습하는 김에 몇 가지 정리해보고 가자.

(1) 상속 (extends)

□ 기능 확장, 코드 재사용의 개념이다. 필드와 메서드를 상속받는다. 생성자는 상속되지 않는다.
□ 하위 클래스의 인스턴스가 생성될 때 자동으로 상위 클래스의 default 생성자가 호출된다. (super();)
□ 상위 클래스에 default 생성자를 기술하지 않았다면 다른 매개변수를 갖는 상위 생성자를 반드시 호출해야 한다.
□ 하위 클래스의 생성자에서 상위 클래스의 인수를 갖는 생성자를 호출하기 위해서 super(arg0, ..., argn);를 기술한다.
□ 메모리에는 상위 클래스의 메서드와 하위 클래스의 메서드가 모두 저장되어 있다.
□ 메서드 오버라이딩 시에 하위 클래스의 메서드가 우선권을 가진다. 상위 클래스의 메서드에 접근할 때에는 super를 써야 한다.
□ C++에서는 메서드 오버라이딩 시 상위 함수에 virtual 키워드를 적용해야 Java와 같은 방식의 메서드 동적 호출이 가능해진다.
□ 오버라이딩 시 하위 클래스 메서드의 접근 지정자는 부모 클래스 메서드의 접근 지정자 범위보다 크거나 같아야 한다.
□ 위 범위 공식은 메서드가 throws로 예외를 던질 때 예외 값의 범위에도 그대로 적용된다.

(2) 추상클래스 (abstract)

□ 추상메서드를 포함한다. (구현x) => 인스턴스 생성 불가, 상속받은 클래스를 통해 인스턴스를 생성한다.
□ 상속된 하위 클래스의 인스턴스 생성 시에 다형성 구현이 가능하다. 추상클래스형 변수 = new 하위클래스형 인스턴스;
□ 상속된 하위 클래스에서 추상 메서드를 반드시 재정의한다.

(3) 인터페이스 (interface)

□ 상수 필드 + 추상 메서드의 구조이다. 상수는 public static final, 추상 메서드는 public이며 생략해도 자동으로 추가된다.
□ 인터페이스를 상속받는 인터페이스 작성 가능 -> extends를 사용한다.
□ 인스턴스 생성 불가. 구현(상속) 클래스를 통해 인스턴스를 생성한다. 추상클래스와 마찬가지로 다형성 구현이 가능하다.
□ 추상으로 선언되어 구현되지 않은 모든 메서드는 인터페이스 제작자의 의도인 셈이다. 모든 메서드를 반드시 재정의할 것.
□ 인터페이스 선언 시에 생성자를 명시하지 않고 구현 클래스 또한 기본 생성자가 없는 경우 default 생성자가 자동 생성된다.
□ 그러나 구현 클래스에서 매개변수가 있는 생성자를 만들고 default 생성자를 구현하지 않으면 상속과 마찬가지로 error 발생.

4. Generics
Generics에 관한 내용을 첨가할까 말까 하다가 간단히만 설명하고 넘어가기로 결정했다. 자세한 내용은 추후에 다시 다뤄볼 생각이다. Generics는 C++의 템플릿과 같은 개념이다. (C#에서는 아예 Template이 Generics로 바뀌었으니 일치하는 내용이라고 봐도 무관할 것이다) Generics를 설명할 수 있는 가장 쉬운 예로는 Collection 계열 클래스에서 흔히 사용되는 List와 같은 컨테이너 인터페이스가 있다.

List myIntList = new LinkedList();
myIntList.add(new Integer(0));
Integer x = (Integer).myIntList.iterator().next();

myIntList는 List 인터페이스 타입으로 LinkedList 인스턴스를 생성하고 있다. Integer(0)은 정수 0을 Integer 클래스로 객체화되어 감싸진다.(wrapping) myIntList에 이 인스턴스를 넣고, 다시 Iterator로 뽑아내고 있다. 이 과정에서, List 인터페이스의 add는 Object형 매개변수를 받고 있으므로 Integer(0)은 upcasting이 되어 myIntList라는 컨테이너에 들어가고, Iterator에 의해 나올 때에도 Object형으로 리턴된다. 3행에서 리턴된 값을 (Integer)로 형변환하는 것을 주목해보자. 이렇게 downcasting해주지 않으면 Integer x 에 대입할 수가 없다.

문제는 바로 여기서 발생한다. 3행에서의 강제 형변환은 프로그램을 난잡하게 할 뿐만 아니라, 런타임 에러의 가능성을 발생시킨다. 위의 코드조각에서는 (Integer) 강제 형변환으로 해결하고 있지만, 사실 프로그래머의 의도대로 돌아가기 위해서는 컨테이너 차원에서 "이 컨테이너는 Integer형 인스턴스만을 저장할 수 있다"라고 명시하는게 논리적일 것이다. 애초에 리스트에 특정 타입만 들어갈 수 있도록 강제하는 것, 이것이 Generics의 핵심 개념이다. Generics를 이용해서 위의 코드를 바꾼다면 아래와 같을 것이다.

List<Integer> myIntList = new LinkedList<Integer>();
myIntList.add(new Integer(0));
Integer x = myIntList.iterator().next();

이제 강제 형변환 없이 논리적으로 리스트를 규정하고 활용하는 코드 조각이 완성되었다. 이러한 경우 List는 Integer를 받는 generic 인 터페이스라고 한다. 이 글에서 Generics에 관해 간략히 언급하고 넘어가는 이유는, 인터페이스와 관련된 형변환이 주로 컨테이너 클래스를 사용할 때 빈번히 일어나기 때문이다. 다형성과 연관지어 이런 내용이 있다는 정도만 알아두고, 나중에 generic 인터페이스를 작성하는 방법에 대해 구체적으로 살펴보도록 하자.

5. 광의의 다형성
우리가 보통 Java의 다형성을 이야기할 때 위의 내용을 주로 언급하지만, 넓은 의미로 살펴보면 보다 많은 다형성의 예를 살펴볼 수 있다. 이를테면 메서드의 매개변수의 다양성을 보장해주는 Overloading 또한 넓은 의미의 다형성 범주에 포함될 것이다. 예전 beginning 강좌 초반에 다형성의 예로 오버로딩을 든 것은 보다 쉽게 다형성의 의미를 심어주기 위함이었지만, 사실 Java에서의 다형성의 핵심은 상속과 인터페이스에서의 메서드 오버라이딩이라는 것을 이제는 알 수 있을 것이다.

:

2. Spring MVC 에 MyBatis 적용해 보기.

ITWeb/개발일반 2012. 3. 12. 10:36
Spring + Mybatis 연동은 sts 와 mybatis 문서를 기반으로 작성 하였습니다.

[소스코드]

- Eclipse import 하시면 프로젝트 확인 가능 합니다.


※ import/export 방법은 아래 글 참고하세요.
http://jjeong.tistory.com/564 


1. Spring MVC 구성해 보기.
2. Spring MVC 에 MyBatis 적용해 보기.
3. Spring MVC 에 Spring Security 적용해 보기. 
4. Spring MVC 에 Hibernate 적용해 보기. 
5. 2+3번 적용해 보기.
6. 3+4번 적용해 보기. 


- 소스코드를 첨부 하였으므로 요약 정보만 기술 합니다.

[pom.xml]

<!-- spring framework jdbc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-jdbc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- mysql -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>5.1.18</version>

        </dependency>


<!-- mybatis -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>3.0.6</version>

        </dependency>


<!-- mybatis spring -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis-spring</artifactId>

            <version>1.0.2</version>

        </dependency>


<!-- apache commons dbcp-->

        <dependency>

            <groupId>commons-dbcp</groupId>

            <artifactId>commons-dbcp</artifactId>

            <version>1.2.2</version>

        </dependency> 

- pom.xml 에서는 필요한 package depedency 를 작성해 줍니다.


[web.xml]

  <context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>

        /WEB-INF/spring/root-context.xml

        classpath:context/**/applicationContext*.xml

        </param-value>

  </context-param>

- spring framework 이 처음 로딩 될때 읽어 들여야 하는 설정파일들에 대한 path 를 잡아 줍니다.


[applicationContext-mybatis.xml]

    <bean id="propertyPlaceholderConfigurer"

        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="locations">

            <value>classpath:configuration/mybatis/config.properties</value>

        </property>

    </bean>


    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"

        destroy-method="close">

        <property name="driverClassName" value="${jdbc.driverClassName}" />

        <property name="url" value="${jdbc.url}" />

        <property name="username" value="${jdbc.username}" />

        <property name="password" value="${jdbc.password}" />

    </bean>



<!-- http://groups.google.com/group/ksug/browse_thread/thread/766cd1fd8ba39c96 -->

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />

        <property name="mapperLocations" value="classpath*:sql/mybatis/mapper/**/*.xml" />

    </bean>
.... 중략

    <bean id="boardContentViewDAO" class="proto.board.dao.BoardContentViewDAOImpl">

        <property name="sqlSession" ref="sqlSession" />

    </bean> 

- dbcp 설정과 dao 에서 사용할 sqlSession 설정을 합니다.


[board.xml]

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="proto.board.mapper">


    <select id="getBoardContentView" resultType="proto.board.domain.BoardContentVO">

    SELECT

        document_srl,

        title,

        content,

        user_id,

        nick_name,

        email_address,

        regdate

    FROM

        xedemodb.xe_documents

    WHERE

        document_srl=66

    </select>

</mapper>

- 사용한 테이블은 xpressengine 이 설치 되면 기본 생성되는 xe_documents 의 테이블 입니다.
- 기본 CRUD 에 대한 내용은 mybatis 문서를 참고 하시면 아주 쉽습니다.



[config.properties]

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/xedemodb?autoReconnect=true

jdbc.username=root

jdbc.password=1234

※ jdbc url structure 참고

- 각자 접속 정보에 맞게 설정 하시면 됩니다.


[Class Flow - 초간단버전임]

http://localhost:8080/board/boardContentView

[BoardContentViewController.java]

    @Autowired

    private BoardContentViewService boardContentViewService;
    ...
    boardContentViewService.getBoardContentVO() 


[BoardContentViewServiceImpl.java]
- BoardContentViewService.java 는 interface 이므로 구현체인 BoardContentViewServiceImpl.java 확인

    @Autowired

    private BoardContentViewDAO boardContentViewDAO;


    public BoardContentVO getBoardContentVO() {

        return (BoardContentVO)boardContentViewDAO.getBoardContentVO();

    }

 

[BoardContentViewDAOImpl.java]
- BoardContentViewDAO.java 는 interface 이므로 구현체인 BoardContentViewDAOImpl.java 확인

    private SqlSession sqlSession;


    public void setSqlSession(SqlSession sqlSession) {

        this.sqlSession = sqlSession;

    }


    public BoardContentVO getBoardContentVO() {

        //boardContentVO.setContent("CONTENT");

        return (BoardContentVO) sqlSession.selectOne("proto.board.mapper.getBoardContentView");

    }


[board.xml]

<mapper namespace="proto.board.mapper">

    <select id="getBoardContentView" resultType="proto.board.domain.BoardContentVO">

    SELECT

        document_srl,

        title,

        content,

        user_id,

        nick_name,

        email_address,

        regdate

    FROM

        xedemodb.xe_documents

    WHERE

        document_srl=66

    </select>

</mapper>


[BoardContentViewVO.java]

public class BoardContentVO {

    private int documentSrl;

    private String title;

    private String content;

    private String nickname;

    private String email;

    private String regdate;


    public int getDocumentSrl() {

        return documentSrl;

    }

.... 중략

    public void setRegdate(String regdate) {

        this.regdate = regdate;

    }

}



자, 그럼 여기까지 아주 초간단 spring framework 과 mybatis 를 이용해서 SELECT 하는 것 까지 테스트 해봤습니다.
완전 기초 이니, 걍 참고만 하세요..
:

[링크공유] mybatis + spring from 구글.

ITWeb/개발일반 2012. 3. 9. 18:10
일단 시간이 부족한 관계로 링크만 오픈.

http://code.google.com/p/mybatis/wiki/Spring

[원본글]

Introduction to MyBatis-Spring

MyBatis-Spring helps you integrate your MyBatis code seamlessly with Spring. Using the classes in this library, Spring will load the necessary MyBatis factory and session classes for you. This library also provides an easy way to inject MyBatis data mappers into your service beans. Finally, MyBatis-Spring will handle transactions and translate MyBatis exceptions into Spring DataAccessExceptions.

Quick Setup

To use MyBatis with Spring you need at least two things defined in the Spring application context: an SqlSessionFactory and at least one data mapper class. In MyBatis-Spring, an SqlSessionFactoryBean is used to create an SqlSessionFactory. To configure the factory bean, put the following in the Spring XML configuration file:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 
<property name="dataSource" ref="dataSource" />
</bean>

Notice that the SqlSessionFactory requires a DataSource. This can be any DataSource and should be configured just like any other Spring database connection.

Assume you have a data mapper class defined like the following:

public interface UserMapper {
 
@Select("SELECT * FROM user WHERE id = #{userId}")
 
User getUser(@Param("userId") String userId);
}

This interface is added to Spring using a MapperFactoryBean like the following:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
 
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
 
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

Note that the mapper class specified must be an interface, not an actual implementation class. In this example, annotations are used to specify the SQL, but a MyBatis mapper XML file could also be used.

Once configured, you can inject mappers directly into your business/service objects in the same way you inject any other Spring bean. The MapperFactoryBean handles creating an SqlSession as well as closing it. If there is a Spring transaction in progress, the session will also be committed or rolled back when the transaction completes. Finally, any exceptions will be translated into Spring DataAccessExceptions.

Calling MyBatis data methods is now only one line of code:

public class FooServiceImpl implements FooService {

   
private UserMapper userMapper;

   
public void setUserMapper(UserMapper userMapper) {
       
this.userMapper = userMapper;
   
}

   
public User doSomeBusinessStuff(String userId) {
       
return this.userMapper.getUser(userId);
   
}

}

More info?

Download the pdf manual. You can find it in downloads. http://code.google.com/p/mybatis/downloads/list?can=3&q=Product%3DSpring

And have a look at JPetStore 6 that is built on top of MyBatis, Spring and Stripes: http://code.google.com/p/mybatis/downloads/list?can=3&q=Product%3DSample

Installation

MyBatis-Spring code and detailed documentation is available at the downloads section.

To use the MyBatis-Spring module, you just need to include the mybatis-spring jar file and its dependencies in the classpath.

If you are using Maven just add the following dependency to your pom.xml:

<dependency>
 
<groupId>org.mybatis</groupId>
 
<artifactId>mybatis-spring</artifactId>
 
<version>1.0.2</version>
</dependency>


 
:

[링크공유] Spring MVC tutorial

ITWeb/개발일반 2012. 3. 9. 14:34
Spring MVC 관련해서 발견한 괜찮은 사이트

※ 좋고 나쁨의 차이는 개인의 needs 에 따라 다르니 판단은 각자.. ㅎㅎ
- 삽질의 해결 실마리를 제공해준 사이트라 올려 봅니다. ㅋㅋ 
:

[기초] Spring MVC 구성해 보기.

ITWeb/개발일반 2012. 3. 9. 14:24
기냥 기초 부터 다시 작성해 보려 한다.

1. Spring MVC 구성해 보기.
2. Spring MVC 에 MyBatis 적용해 보기.
3. Spring MVC 에 Spring Security 적용해 보기. 
4. Spring MVC 에 Hibernate 적용해 보기. 
5. 2+3번 적용해 보기.
6. 3+4번 적용해 보기. 



[준비물]

- SpringSourceTool Suite 에서 Spring Project Template 중 MVC 로 기본 프로젝트 생성.
- 괜히 노가다 한다고 시간 빼지 말자.
- Eclipse 또는 STS
- JDK 1.6
- Maven
- Tomcat 

 

[pom.xml]
- 내가 가지고 있던 sts 버전땜시 spring framework 버전을 수정함. (3.0.6 -> 3.1.0)

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>proto.ncms</groupId>

    <artifactId>board</artifactId>

    <name>board</name>

    <packaging>war</packaging>

    <version>1.0.0-BUILD-SNAPSHOT</version>

    <properties>

        <java-version>1.6</java-version>

        <org.springframework-version>3.1.0.RELEASE</org.springframework-version>

        <org.aspectj-version>1.6.9</org.aspectj-version>

        <org.slf4j-version>1.5.10</org.slf4j-version>

    </properties>

    <dependencies>

        <!-- Spring -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>${org.springframework-version}</version>

            <exclusions>

                <!-- Exclude Commons Logging in favor of SLF4j -->

                <exclusion>

                    <groupId>commons-logging</groupId>

                    <artifactId>commons-logging</artifactId>

                 </exclusion>

            </exclusions>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-webmvc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


        <!-- AspectJ -->

        <dependency>

            <groupId>org.aspectj</groupId>

            <artifactId>aspectjrt</artifactId>

            <version>${org.aspectj-version}</version>

        </dependency>


        <!-- Logging -->

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>${org.slf4j-version}</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>jcl-over-slf4j</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-log4j12</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.15</version>

            <exclusions>

                <exclusion>

                    <groupId>javax.mail</groupId>

                    <artifactId>mail</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>javax.jms</groupId>

                    <artifactId>jms</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jdmk</groupId>

                    <artifactId>jmxtools</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jmx</groupId>

                    <artifactId>jmxri</artifactId>

                </exclusion>

            </exclusions>

            <scope>runtime</scope>

        </dependency>


        <!-- @Inject -->

        <dependency>

            <groupId>javax.inject</groupId>

            <artifactId>javax.inject</artifactId>

            <version>1</version>

        </dependency>


        <!-- Servlet -->

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>servlet-api</artifactId>

            <version>2.5</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet.jsp</groupId>

            <artifactId>jsp-api</artifactId>

            <version>2.1</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

            <version>1.2</version>

        </dependency>


        <!-- Test -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.7</version>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <configuration>

                    <source>${java-version}</source>

                    <target>${java-version}</target>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-war-plugin</artifactId>

                <configuration>

                    <warName>abc</warName>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-dependency-plugin</artifactId>

                <executions>

                    <execution>

                        <id>install</id>

                        <phase>install</phase>

                        <goals>

                            <goal>sources</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-resources-plugin</artifactId>

                <version>2.5</version>

                <configuration>

                    <encoding>UTF-8</encoding>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>



[기타설정]

WEB-INF/web.xml
WEB-INF/spring/root-context.xml
WEB-INF/spring/appServlet/servlet-context.xml 

일단 다른 애덜이랑 연동할 일이 없으니까 그냥 default 설정으로 놔둬도 된다. 

 

※ 추가 작성할 패키지는 향후 MyBatis 와 연동 하기 위한 구조로 작성함.

proto.board
proto.board.web : Controller
proto.board.service : Biz logic
proto.board.domain : VO
proto.board.dao  : Data Access Object



[Controller 작성]
- 기본 HomeController.java 가 있으니 작성하기 전에 이게 잘 뜨는지 확인

[BoardContentViewController.java]

package proto.board.web;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

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

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


import proto.board.service.BoardContentViewService;


@Controller

public class BoardContentViewController {


    private static final Logger logger = LoggerFactory.getLogger(BoardContentViewController.class);


    @Autowired

    private BoardContentViewService boardContentViewService;


    @RequestMapping(value = "/boardContentView", method = RequestMethod.GET)

    public String boardContentView(Locale locale, Model model) {

        logger.info("Welcome home! the client locale is "+ locale.toString());

        logger.info("Autowired :  "+ boardContentViewService.getBoardContentVO());


        model.addAttribute("val", boardContentViewService.getBoardContentVO() );


        return "boardContentView";

    }

}


[boardContentView.jsp]

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page session="false" %>

<html>

<head>

    <title>BoardContentView</title>

</head>

<body>

<h1>

    BoardContentView

</h1>


<P>  The Request is ${val.content}. </P>

</body>

</html>  



[Domain 작성]

[BoardContentVO.java]

package proto.board.domain;


public class BoardContentVO {

    private int documentSrl;

    private String title;

    private String content;

    private String nickname;

    private String email;

    private String regdate;


    public int getDocumentSrl() {

        return documentSrl;

    }


    public void setDocumentSrl(int documentSrl) {

        this.documentSrl = documentSrl;

    }


    public String getTitle() {

        return title;

    }


    public void setTitle(String title) {

        this.title = title;

    }


    public String getContent() {

        return content;

    }


    public void setContent(String content) {

        this.content = content;

    }


    public String getNickname() {

        return nickname;

    }


    public void setNickname(String nickname) {

        this.nickname = nickname;

    }


    public String getEmail() {

        return email;

    }


    public void setEmail(String email) {

        this.email = email;

    }


    public String getRegdate() {

        return regdate;

    }


    public void setRegdate(String regdate) {

        this.regdate = regdate;

    }

} 



[Service 작성]

[BoardContentViewServiceImpl.java]

package proto.board.service;


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

import org.springframework.stereotype.Service;


import proto.board.dao.BoardContentViewDAO;

import proto.board.domain.BoardContentVO;


@Service

public class BoardContentViewServiceImpl implements BoardContentViewService {


    @Autowired

    private BoardContentViewDAO boardContentViewDAO;


    public BoardContentVO getBoardContentVO() {

        return (BoardContentVO)boardContentViewDAO.getBoardContentVO();

    }

}


[BoardContentViewService.java]

package proto.board.service;


import proto.board.domain.BoardContentVO;



public interface BoardContentViewService {

    BoardContentVO getBoardContentVO();

}



[DAO 작성]

[BoardContentViewDAOImpl.java]

package proto.board.dao;


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

import org.springframework.stereotype.Repository;


import proto.board.domain.BoardContentVO;


@Repository

public class BoardContentViewDAOImpl implements BoardContentViewDAO {


    private BoardContentVO boardContentVO = new BoardContentVO();


    public BoardContentVO getBoardContentVO() {

        boardContentVO.setContent("CONTENT");


        return boardContentVO;

    }

}


[BoardContentViewDAO.java] 

package proto.board.dao;


import proto.board.domain.BoardContentVO;


public interface BoardContentViewDAO {

    BoardContentVO getBoardContentVO();

} 



※ 자 그럼 build 를 하고 실행을 하봅시다.
[Eclipse Console 로그확인]
- 아래 로그는 실제 servlet-context.xml 에서 component-scan 일 잘 되었는지 확인하기 위함 이다.
- 이게 정상적으로 나오지 않을 경우는 "not found url mapping" 어쩌구 에러가 발생 합니다.

INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String proto.board.HomeController.home(java.util.Locale,org.springframework.ui.Model)

INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/boardContentView],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String proto.board.web.BoardContentViewController.boardContentView(java.util.Locale,org.springframework.ui.Model)



[Tomcat 실행결과]



:

Spring Framework MVC + MyBatis Empty 설정 맛보기.

ITWeb/개발일반 2012. 3. 8. 17:19
※ 본 설명은 sts (SpringSource Tool Suite) 에서 spring mvc 프로젝트를 생성 한후 수행한 내용 입니다.

[Project 생성]

1. Spring Template Project 에서 Spring MVC Project 를 선택 합니다.
- 아래 이미지는 Next 후 Setting 화면 입니다.

 

2. pom.xml 수정

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.prototype</groupId>

    <artifactId>board</artifactId>

    <name>prototype.board</name>

    <packaging>war</packaging>

    <version>1.0.0-BUILD-SNAPSHOT</version>

    <properties>

        <java-version>1.6</java-version>

        <org.springframework-version>3.1.0.RELEASE</org.springframework-version>

        <org.aspectj-version>1.6.9</org.aspectj-version>

        <org.slf4j-version>1.5.10</org.slf4j-version>

    </properties>

    <dependencies>

        <!-- Spring -->

<!-- spring framework context 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>${org.springframework-version}</version>

            <exclusions>

                <!-- Exclude Commons Logging in favor of SLF4j -->

                <exclusion>

                    <groupId>commons-logging</groupId>

                    <artifactId>commons-logging</artifactId>

                 </exclusion>

            </exclusions>

        </dependency>


<!-- spring framework mvc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-webmvc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- spring framework jdbc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-jdbc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- mysql -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>5.1.18</version>

        </dependency>


<!-- mybatis -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>3.0.6</version>

        </dependency>


<!-- mybatis spring -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis-spring</artifactId>

            <version>1.0.2</version>

        </dependency>



        <!-- AspectJ -->

        <dependency>

            <groupId>org.aspectj</groupId>

            <artifactId>aspectjrt</artifactId>

            <version>${org.aspectj-version}</version>

        </dependency>


        <!-- Logging -->

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>${org.slf4j-version}</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>jcl-over-slf4j</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-log4j12</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.15</version>

            <exclusions>

                <exclusion>

                    <groupId>javax.mail</groupId>

                    <artifactId>mail</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>javax.jms</groupId>

                    <artifactId>jms</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jdmk</groupId>

                    <artifactId>jmxtools</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jmx</groupId>

                    <artifactId>jmxri</artifactId>

                </exclusion>

            </exclusions>

            <scope>runtime</scope>

        </dependency>


        <!-- @Inject -->

        <dependency>

            <groupId>javax.inject</groupId>

            <artifactId>javax.inject</artifactId>

            <version>1</version>

        </dependency>


        <!-- Servlet -->

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>servlet-api</artifactId>

            <version>2.5</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet.jsp</groupId>

            <artifactId>jsp-api</artifactId>

            <version>2.1</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

            <version>1.2</version>

        </dependency>


        <!-- Test -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.7</version>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <configuration>

                    <source>${java-version}</source>

                    <target>${java-version}</target>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-war-plugin</artifactId>

                <configuration>

                    <warName>abc</warName>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-dependency-plugin</artifactId>

                <executions>

                    <execution>

                        <id>install</id>

                        <phase>install</phase>

                        <goals>

                            <goal>sources</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-resources-plugin</artifactId>

                <version>2.5</version>

                <configuration>

                    <encoding>UTF-8</encoding>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>


3. web.xml 수정

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">


    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            /WEB-INF/spring/root-context.xml

            classpath:context/applicationContext-root.xml

        </param-value>

    </context-param>


    <!-- Creates the Spring Container shared by all Servlets and Filters -->

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>


    <!-- Processes application requests -->

    <servlet>

        <servlet-name>appServlet</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

    </servlet>


    <servlet-mapping>

        <servlet-name>appServlet</servlet-name>

        <url-pattern>/</url-pattern>

    </servlet-mapping>


</web-app>


4. mybatis 의 applicationContext 설정
- src/main/resources 하위에 아래와 같은 폴더와 파일을 만듭니다.


5. applicationContext-root.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-3.0.xsd">


    <!-- Application Root Context: defines shared resources visible to all other web components -->

    <import resource="applicationContext-mybatis.xml" />

</beans>


6. applicationContext-mybatis.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:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


    <bean

        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="locations">

            <value>classpath:configuration/mybatis/jdbc.properties</value>

        </property>

    </bean>


    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">

        <property name="driverClass"        value="${jdbc.driverClass}" />

        <property name="url"                value="${jdbc.url}" />

        <property name="username"           value="${jdbc.username}" />

        <property name="password"           value="${jdbc.password}" />

    </bean>


    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />

<!--         <property name="configLocation" value="classpath:configuration/mybatis/config.xml" /> -->

<!--         <property name="mapperLocations" value="classpath:sql/mybatis/**/*.xml" /> -->

    </bean>


    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

        <constructor-arg ref="sqlSessionFactory" />

    </bean>


    <bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

    </bean>


    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

        <property name="transactionManager" ref="transactionManager" />

    </bean>

</beans>


7. mybatis/config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

    <settings>

        <setting name="cacheEnabled" value="true" />

        <setting name="lazyLoadingEnabled" value="true" />

        <setting name="multipleResultSetsEnabled" value="true" />

        <setting name="useColumnLabel" value="true" />

        <setting name="useGeneratedKeys" value="false" />

        <setting name="enhancementEnabled" value="false" />

        <setting name="defaultExecutorType" value="SIMPLE" />

        <setting name="defaultStatementTimeout" value="25000" />

        <setting name="defaultListResultHandlerType" value="java.util.ArrayList" />

        <setting name="defaultMapResultHandlerType" value="java.util.HashMap" />

    </settings>


<!--  -->

<!--     <typeAliases /> -->


<!-- 상위 mybatis.xml 에서 mapperLocations 설정 시 하위 설정은 필요 없음  -->

<!-- mybatis 에서 작성한 SQL 문이 정의된 파일 지정 -->

<!-- Using classpath relative resources : <mapper resource="sql/com.proto.board.List.xml" /> -->

<!--     <mappers /> -->

</configuration>


8. mybatis/jdbc.properties

jdbc.datasource=jdbc/DataSource

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis?autoReconnect=true

jdbc.username=root

jdbc.password=1234


9. web.xml 에 applicationContext-root.xml 추가 (3번과 중복)

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            /WEB-INF/spring/root-context.xml

            classpath:context/applicationContext-root.xml

        </param-value>

    </context-param>


10. Empty 설정이 잘 되었는지 확인하기
SpringMVC 템플릿의 경우 기본 HelloWorld 가 포함 되어 있으므로 서버 등록 후 정상적으로 동작 하는지 확인 하면 됩니다.
- Server 등록은 아래 처럼


11. 서버 실행이 잘 되었다면. Hello World 를 확인 할 수 있습니다.



※ 이제 empty project template 을 만들었으니 기본적인 게시판 모듈 구현을 시작하면 되겠습니다.
- 급하게 시작 하셔야 하는 분은 아래 링크 참고 하세요.




:

Spring Framework 설정관련 기초.

ITWeb/개발일반 2012. 3. 8. 11:20
[spring framework 에서 기본 설정의 시작]

web.xml



[web.xml 에서 contextConfigLocation]

[contextConfigLocation]

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            classpath:applicationContext-business.xml

            /WEB-INF/applicationContext-security.xml

        </param-value>

    </context-param>


[classpath 의 path 는 어디 일까?]

- eclipse 에서 package explorer 로 보게 되면 해당 project 의  
    src/main/resources
에 해당한다.

- build 를 하게 되면 webapp 하위에
    /WEB-INF/classes
에 해당한다.

위에 src/main/resources 에 파일을 하나 생성해 놓고 빌드를 해보면 생성한 파일이 WEB-INF/classes 에 들어가 있는걸 볼 수 있다.  



[<import resource="" /> 의 Path]

예를 들면)
web.xml 에 아래와 같이 정의 되어 있다.
- web.xml 은 기본 /WEB-INF/web.xml 에 위치한다.

[Case 1]
<import resource="root-context.xml" />
이 경우 /WEB-INF/root-context.xml 을 찾는다.

[Case 2]
<import resource="context/root-context.xml" /> 
이 경우 /WEB-INF/context/root-context.xml 을 찾는다. 

[Case 3]
<import resource="/context/root-context.xml" /> 
이 경우 /WEB-INF/context/root-context.xml 을 찾는다. 
case 2 와 동일 하다. 



[참고URL]
 
:

VIM no indent 설정.

ITWeb/개발일반 2012. 3. 6. 17:21
[참고사이트]
http://vim.wikia.com/wiki/How_to_stop_auto_indenting


[명령어]
set noai nocin nosi inde=
:

java classpath setting

ITWeb/개발일반 2012. 3. 6. 15:03
[참고사이트]
http://docs.oracle.com/javase/tutorial/essential/environment/paths.html
http://javarevisited.blogspot.com/2011/01/how-classpath-work-in-java.html


[Windows 에서 Classpath 설정]
sdkTool -classpath classpath1;classpath2...

-or-

set CLASSPATH=classpath1;classpath2...

javac -classpath a.jar;b.jar example.java
javac -classpath C:\java\MyClasses;C:\java\OtherClasses example.java



[Linux 에서 Classpath 설정]
export CLASSPATH="your classpath" from either your .bash_profile or .bashrc

javac -classpath a.jar:b.jar example.java
javac -classpath /home/hadoop/app/hadoop example.java


[javac -help]
ubuntu:~/app/hadoop-0.21.0$ javac -help
Usage: javac <options> <source files>
where possible options include:
  -g                         Generate all debugging info
  -g:none                    Generate no debugging info
  -g:{lines,vars,source}     Generate only some debugging info
  -nowarn                    Generate no warnings
  -verbose                   Output messages about what the compiler is doing
  -deprecation               Output source locations where deprecated APIs are used
  -classpath <path>          Specify where to find user class files and annotation processors
  -cp <path>                 Specify where to find user class files and annotation processors
  -sourcepath <path>         Specify where to find input source files
  -bootclasspath <path>      Override location of bootstrap class files
  -extdirs <dirs>            Override location of installed extensions
  -endorseddirs <dirs>       Override location of endorsed standards path
  -proc:{none,only}          Control whether annotation processing and/or compilation is done.
  -processor <class1>[,<class2>,<class3>...]Names of the annotation processors to run; bypasses default discovery process
  -processorpath <path>      Specify where to find annotation processors
  -d <directory>             Specify where to place generated class files
  -s <directory>             Specify where to place generated source files
  -implicit:{none,class}     Specify whether or not to generate class files for implicitly referenced files
  -encoding <encoding>       Specify character encoding used by source files
  -source <release>          Provide source compatibility with specified release
  -target <release>          Generate class files for specific VM version
  -version                   Version information
  -help                      Print a synopsis of standard options
  -Akey[=value]              Options to pass to annotation processors
  -X                         Print a synopsis of nonstandard options
  -J<flag>                   Pass <flag> directly to the runtime system

:

Spring Security Role 정의

ITWeb/개발일반 2012. 3. 5. 18:03
내가 궁금했던건 이거다.

"ROLE_XXXX" 라는 걸 어디서 정의 하는 거냐?

별로 어렵지도 않은 내용인데.. 직관적인 설명을 잘 찾지 못했다.
결론을 정리 하면.. 바로 spring security 의 설정 부분인 아래 코드이다.
- 막상 내가 보니 어떤 파일인지 궁금해 하시는 분이 계실 것 같아..추가 합니다.
- web.xml 에서 추가한 security 관련 context 파일이 되겠습니다.

[web.xml]

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            classpath:applicationContext-business.xml

            /WEB-INF/applicationContext-security.xml

        </param-value>

    </context-param>


[applicationContext-security.xml]

// 바로 아래 코드가 되겠구요.


<authentication-provider>
        <password-encoder hash="md5"/>
        <user-service>
            <user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>


설정에서 보면.. 빨간색 부분이 정의를 하는 부분이다.
소스코드에서는 아래 파일 이다.

- RoleVoter.java 

/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


package org.springframework.security.access.vote;


import java.util.Collection;


import org.springframework.security.access.AccessDecisionVoter;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.GrantedAuthority;


/**

 * Votes if any {@link ConfigAttribute#getAttribute()} starts with a prefix

 * indicating that it is a role. The default prefix string is <Code>ROLE_</code>,

 * but this may be overridden to any value. It may also be set to empty, which

 * means that essentially any attribute will be voted on. As described further

 * below, the effect of an empty prefix may not be quite desirable.

 * <p>

 * Abstains from voting if no configuration attribute commences with the role

 * prefix. Votes to grant access if there is an exact matching

 * {@link org.springframework.security.core.GrantedAuthority} to a <code>ConfigAttribute</code>

 * starting with the role prefix. Votes to deny access if there is no exact

 * matching <code>GrantedAuthority</code> to a <code>ConfigAttribute</code>

 * starting with the role prefix.

 * <p>

 * An empty role prefix means that the voter will vote for every

 * ConfigAttribute. When there are different categories of ConfigAttributes

 * used, this will not be optimal since the voter will be voting for attributes

 * which do not represent roles. However, this option may be of some use when

 * using pre-existing role names without a prefix, and no ability exists to

 * prefix them with a role prefix on reading them in, such as provided for

 * example in {@link org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl}.

 * <p>

 * All comparisons and prefixes are case sensitive.

 *

 * @author Ben Alex

 * @author colin sampaleanu

 */

public class RoleVoter implements AccessDecisionVoter<Object> {

    //~ Instance fields ================================================================================================


    private String rolePrefix = "ROLE_";


    //~ Methods ========================================================================================================


    public String getRolePrefix() {

        return rolePrefix;

    }


    /**

     * Allows the default role prefix of <code>ROLE_</code> to be overridden.

     * May be set to an empty value, although this is usually not desirable.

     *

     * @param rolePrefix the new prefix

     */

    public void setRolePrefix(String rolePrefix) {

        this.rolePrefix = rolePrefix;

    }


    public boolean supports(ConfigAttribute attribute) {

        if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) {

            return true;

        }

        else {

            return false;

        }

    }


    /**

     * This implementation supports any type of class, because it does not query

     * the presented secure object.

     *

     * @param clazz the secure object

     *

     * @return always <code>true</code>

     */

    public boolean supports(Class<?> clazz) {

        return true;

    }


    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {

        int result = ACCESS_ABSTAIN;

        Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);


        for (ConfigAttribute attribute : attributes) {

            if (this.supports(attribute)) {

                result = ACCESS_DENIED;


                // Attempt to find a matching granted authority

                for (GrantedAuthority authority : authorities) {

                    if (attribute.getAttribute().equals(authority.getAuthority())) {

                        return ACCESS_GRANTED;

                    }

                }

            }

        }


        return result;

    }


    Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {

        return authentication.getAuthorities();

    }

}


이넘들의 각 Class 간 flow 를 보면.. 아래 그림과 같다.
참고사이트 :  http://static.springsource.org/spring-security/site/docs/3.0.x/reference/authz-arch.html 

이미지 출처 :  http://whiteship.me/?tag=spring-security 



이제 어디서 정의 하는지는 확인을 했으니 이걸 매번 설정파일에 등록해 줄 수는 없으므로 jdbc-user-service 설정을 하는 걸 보도록 하자.

[참고사이트]
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html 
-  http://www.mularien.com/blog/2008/07/07/5-minute-guide-to-spring-security/ 

2.2.3 Using other Authentication Providers

In practice you will need a more scalable source of user information than a few names added to the application context file. Most likely you will want to store your user information in something like a database or an LDAP server. LDAP namespace configuration is dealt with in the LDAP chapter, so we won't cover it here. If you have a custom implementation of Spring Security's UserDetailsService, called "myUserDetailsService" in your application context, then you can authenticate against this using

  <authentication-manager>
    <authentication-provider user-service-ref='myUserDetailsService'/>
  </authentication-manager>
  
        

If you want to use a database, then you can use

  <authentication-manager>
    <authentication-provider>
      <jdbc-user-service data-source-ref="securityDataSource"/>
    </authentication-provider>
  </authentication-manager>
  
        

Where securityDataSource is the name of a DataSource bean in the application context, pointing at a database containing the standard Spring Security user data tables. Alternatively, you could configure a Spring Security JdbcDaoImpl bean and point at that using the user-service-ref attribute:

  <authentication-manager>
    <authentication-provider user-service-ref='myUserDetailsService'/>
  </authentication-manager>

  <beans:bean id="myUserDetailsService"
      class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <beans:property name="dataSource" ref="dataSource"/>
  </beans:bean>
  
        


A.1 User Schema

The standard JDBC implementation of the UserDetailsService (JdbcDaoImpl) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user.

  create table users(
      username varchar_ignorecase(50) not null primary key,
      password varchar_ignorecase(50) not null,
      enabled boolean not null);

  create table authorities (
      username varchar_ignorecase(50) not null,
      authority varchar_ignorecase(50) not null,
      constraint fk_authorities_users foreign key(username) references users(username));
      create unique index ix_auth_username on authorities (username,authority);

A.1.1 Group Authorities

Spring Security 2.0 introduced support for group authorities in JdbcDaoImpl. The table structure if groups are enabled is as follows:

create table groups (
  id bigint generated by default as identity(start with 0) primary key,
  group_name varchar_ignorecase(50) not null);

create table group_authorities (
  group_id bigint not null,
  authority varchar(50) not null,
  constraint fk_group_authorities_group foreign key(group_id) references groups(id));

create table group_members (
  id bigint generated by default as identity(start with 0) primary key,
  username varchar(50) not null,
  group_id bigint not null,
  constraint fk_group_members_group foreign key(group_id) references groups(id));
        



Database-Backed Authentication

In my case, my application was already configured to use a JDBC DataSource, so pointing Spring Security at my JDBC data source was as easy as modifying the authentication-provider element to reference my already configured Spring bean:

    <authentication-provider>
	    <jdbc-user-service data-source-ref="dataSource"/>
    </authentication-provider>

Now, the immediate question I asked is – OK, what does the convention over configuration assume my database tables look like? If you look at the documentation of the JDBC authentication provider, you would expect to see that information there, but you’d be wrong.

Instead, you have to look at the SQL queries that are hard-coded in the JdbcDaoImpl class and infer the schema structure for yourself. This article has a graphical depiction of the basic schema down in section 5.4.

If you want to configure the queries that are used, simply match the available attributes on the jdbc-user-service element to the SQL queries in the Java class I referenced above. In my example, I wanted to simplify my schema by adding the user’s role directly to the user table. So I modified the XML configuration slightly as follows:

  <jdbc-user-service data-source-ref="dataSource" 
    authorities-by-username-query="select username,authority from users where username=?"/>

This allowed me to put values in the ‘authority’ column like ‘ROLE_ADMIN’ or ‘ROLE_USER’, which translate directly into Spring Security roles!


: