달력

3

« 2024/3 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2014. 8. 4. 12:03

[펌] Spring 4.0에서 간단한 Rest 서버 구축하기 2014. 8. 4. 12:03

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

2014. 2. 10. 10:06

[펌] Spring camp 발표 영상 I.lib()/I.lib(Spring)2014. 2. 10. 10:06

.. .. ..

 

[펌] : https://groups.google.com/forum/#!topic/ksug/QNiYQbJI-2I

[문제가 있을시 삭제하겠습니다.]

 

안녕하십니까, KSUG 일꾼단 김지헌입니다.

지난 해에 발표한 영상이 편집되어 유투브에 기재되었습니다.
이에 내용을 정리해서 공유합니다.

즐거운 설명절 무사히~ 즐겁게~ 보내시길 바랍니다. ^^ 

@ Track A

  1. DSL 로 만나는 Groovy (장시영)

  2. 무식하게 배우는 Gradle! (김지헌)

  3. Cloud Foundry 를 활용한 PaaS 구축기 (안병현)

  4. TDD 라이브 (최범균)

  5. Spring MVC Test 어렵지 않아요! (최용은)


@ Track B

  1. 좌충우돌 SNS 솔루션 만들기 (김성박)

  2. Java Configuration 없인 못살아! (박용권)

  3. Spring data JPA (김영한)

  4. Spring Security 를 적용한 웹 시스템 구축 사례 (이수홍)

  5. Spring Boot 로 무얼 할 수 있나? (이재일)


@ Track C

  1. JDK 8에 추가된 것들은? (이상민)

  2. ORM 프레임워크를 활용할 때의 설계, 개발 프로세스 (박재성)

  3. 대규모 프로젝트와 Grails (이정택)

  4. Spring Scala : 스프링이 스칼라를 만났을 때 (변정훈)

  5. Scala for Play (최정열)


@ Track D

  1. Effective Scala (이희종)

  2. Java8.next() == Scala (정대원)

  3. Akka 소개 및 Redis 를 활용한 Pub/Sub 시스템 구현 (이장원)

  4. 스칼라가 빅데이터 및 현재 각광 받고 있는 이유 (강지훈)

  5. 스칼로이드: 스칼라 기반의 안드로이드 개발 라이브러리 (이성호)

.
:
Posted by .07274.
2013. 8. 6. 11:56

spring transactionManager 설정 I.lib()/I.lib(Spring)2013. 8. 6. 11:56

.. .. ..

[펌] : http://springmvc.egloos.com/499291

 

 

<tx:annotation-driven />
<aop:config>
<aop:advisor advice-ref="transactionAdvice" pointcut="bean(*Service)" />
</aop:config>

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="exceptionPut" propagation="REQUIRES_NEW" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

전 장에서 <aop>까지 했으니 이제 <tx> 요소에 대해 설명할 차례네요. <tx>는 스프링 트랜잭션 기술의 집약체입니다. 스프링의 트랜잭션 기술은 전장에서도 말했듯이 어노테이션 적용법과 AOP 적용법 2가지가 있으며 위의 예제는 당연히 AOP 적용법입니다.

먼저 <tx:advice>로 트랜잭션 어드바이스를 하나 만듭니다. 여기에 적용한 트랜잭션을 선택하는데 만약 트랜잭션 빈의 이름이 'transactionManager'이라면 위의 'transaction-manager' 속성은 생략될 수 있습니다. 위의 예제에서는 다만 원리를 설명하기 위해 속성을 넣어둔 것 뿐이므로 현재 'transaction-manager'은 생략이 가능하다 할 수 있겠네요.

그다음 <tx:attributes>의 <tx:method>로 세밀하게 메서드별 속성을 조절해주도록 합시다. 우리는 이 부분에서 어느 메서드에 트랜잭션을 적용할 것인지 선택할 수 있으며 속성에는 다음과 같은 값들이 존재합니다.

name - 메서드명
메서드의 이름이며 와일드 문자(*)를 사용할 수 있습니다. 예로 'get*'은 get으로 시작하는 모든 메서드를 가리키며'*get'은 get으로 끝나는 모든 메서드를 가리킵니다.

timeout - 제한시간 (기본값 : -1)
트랜잭션의 제한시간을 설정합니다. DB가 해당기능을 지원해야 하며 기본값으로는 -1인 제한시간 없음이 설정됩니다.

propagation - 전파옵션 (기본값 : REQUIRED)
REQUIRED : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 새로운 트랜잭션을 생성합니다.
REQUIRES_NEW : 부모 트랜잭션을 무시하고 무조건 새로운 트랜잭션이 생성되도록 합니다.
SUPPORT : 부모 트랜잭션 내에서 실행하며 부모 트랜잭션이 없을 경우 nontransactionally로 실행됩니다.
MANDATORY : 부모 트랜잭션 내에서 실행되며 부모 트랜잭션이 없을 경우 예외가 발생됩니다.
NOT_SUPPORT : nontransactionally로 실행하며 부모 트랜잭션 내에서 실행될 경우 일시 정지 됩니다.
NEVER : nontransactionally로 실행되며 부모 트랜잭션이 존재한다면 예외가 발생합니다.
NESTED : 해당 메서드가 부모 트랜잭션에서 진행될 경우 별개로 커밋되거나 롤백될 수 있습니다. 둘러싼 트랜잭션이 없을 경우 REQUIRED와 동일하게 작동합니다.

isolation - 격리수준 (기본값 : DEFAULT)

DEFAULT : DB에서 설정된 기본 격리 수준을 따릅니다.
SERIALIZABLE : 가장 높은 격리수준을 가지며 사용시 성능 저하가 있을 수 있습니다.
READ_UNCOMMITTED : 커밋되지 않은 데이터에 대한 읽기를 허용합니다.
READ_COMMITTED : 커밋된 트랜잭션에 대해 읽기를 허용합니다.
REPEATABLE_READ : 동일한 필드에 대한 다중 접근 시 동일한 결과를 얻을 수 잇는 것을 보장합니다.

read-only - 읽기전용 (기본값 : false)

해당 메서드는 오로지 읽기에만 사용됩니다. INSERT나 UPDATE, DELETE문은 허용되지 않습니다. 만약 쓰기나 삭제가 실행될 경우 에러를 발생시킵니다.

rollback-for - 예외처리 (기본값 : RuntimeException)

특정 예외가 발생했을 경우에 롤백되도록 설정합니다. 설정하지 않을 경우 오로지 RuntimeException을 상속받은 예외에만 롤백처리를 해줍니다.

no-rollback-for - 예외처리 (기본값 : 없음)

특정 예외가 발생하더라도 롤백되지 않도록 설정합니다.

위의 속성과 값들이 <tx:method>에서 설정할 수 있는 전부입니다. 잘 알아본 다음 자신에게 맞는 속성을 설정한 후에 완성된 <tx:advice>를 <aop:config>에 주입하기만 하면 자동프록시검색기가 알아서 <tx>어드바이스와 pointcut을 해석하여 해당 요청을 대신 처리해 줄 것입니다.

이제 거의 막바지에 왔네요. 다음은 <tx:annotation-driven />에 대한 설명입니다. 이 요소가 설정되있다면 트랜잭션을 어노테이션으로 설정 가능하게 합니다. 설정방법은 트랜잭션을 원하는 메서드에 @Transactional이란 어노테이션을 붙이면 그만이며 <aop>설정은 어노테이션과 전혀 무관합니다. 어노테이션 트랜잭션은 오로지 <tx:annotation-driven /> 요소만을 요구합니다.

@Transactional(isolation=Isolation.DEFAULT, propagation=Propagation.REQUIRES_NEW)

어노테이션으로 트랜잭션으로 설정하는 방법은 직관적이고 알기 쉽지만 수정이 필요할 때에는 코드 자체를 수정해야 한다는 단점이 있습니다. 위의 예시처럼 어노테이션도 <tx:method>와 같이 똑같은 옵션설정이 가능합니다. 설정방법은 이클립스의 자동완성기능(CTRL + F1)으로 알아보시면 편리하니 따로 설명하지는 않겠습니다 :D

일단 어노테이션으로 트랜잭션을 설정할 시 주의할 점은 가장 우선적으로 고려되는 순서가 있다는 것입니다. 만약 인터페이스 - 클래스 - 메서드 모두에 트랜잭션 어노테이션이 설정되있다면 스프링은 메서드 어노테이션을 제일 먼저 고려하고 그 다음이 클래스, 인터페이스 순서으로 적용합니다. 개인적으로는 가급적 어드바이스를 활용해 트랜잭션 경계를 설정하는 게 좋다고 생각하는데 어노테이션 트랜잭션을 남발할 경우 작성된 프레임워크의 잦은 수정이 불가피해지기 때문입니다.

트랜잭션도 상황에 따라 자주 설정이 변경되어줘야 하는데 어노테이션으로 설정을 고정해버리고 매번 수정이 필요할 때마다 소스자체를 바꾸다보면 다른 코드에 영향을 줄 수도 있고 이용하는 사람 입장에서도 상당히 불편할 수 있습니다. 가급적 어드바이스로 트랜잭션 경계를 설정하고 정말 불변하는 트랜잭션에 대해서만 어노테이션을 이용하길 권장합니다.


이제 마지막으로 트랜잭션 매니저 설정을 위한 PlatformTransactionManager을 설명하고 끝마치려 합니다 ^^. 스프링은 다양한 플랫폼과 환경에서도 완벽하게 트랜잭션 클래스들의 DI가 가능 하도록 PlatformTransactionManager 인터페이스를 갖고 있다는 사실을 알고 계신가요?

우리가 구현했던 소스에서는 볼 수 없었지만 분명 <tx:advice>를 구성하는 소스에는 PlatformTransactionManager 인터페이스를 통해 구현 클래스의 주입을 요구하고 있습니다. 현재의 소스는 제가 JDBC/MyBatis를 이용하고 있으므로 위의 예제와 같이 DataSrouceTransactionManager 클래스를 이용해 트랜잭션 매니저를 구현했지만 만약 하이버네트나 JTA같은 다른 플랫폼을 이용할 경우에도 소스에 변경 일절 없이 오로지 트랜잭션 매니저만 변경해주면 간편하게 모든 설정을 끝마칠 수 있습니다.

이렇게 트랜잭션에 대한 모든 설명이 끝났네요. 사실 부족한 부분이 많지만 이정도면 스프링에서 어떻게 트랜잭션을 설정하였고 활용방안에 대한 감을 잡을 수 있다는 생각이 듭니다. 부족한 부분이나 이해가 안가시는 부분은 피드백 주시구요. 다음에 좀 더 좋은 포스트로 찾아올게요 ^^
.
:
Posted by .07274.
.. .. ..

[펌] : http://01041741840.tistory.com/40

 

Server 측입니다.

@Path("/") // 이 class가 받는 경로. Web.xml에서 url-pattern으로 /*를 주었을 때 @Path를 Controller마다 다르게 주면 각각 다르게 인식한다.

public class RestServerController {

@POST

@Produces("text/xml")

@Consumes("application/xml")

@Path("users")

public RestServerVO getUsers(RestClientVO rcVO) {

String name = rcVO.getUserName();

RestServerVO rsVO = new RestServerVO();

rsVO.setUserName(name);

rsVO.setAddress("조선");

return rsVO;

}

}

@Path는 Spring에서 @RequestMapping과 같습니다. 어떤 path로 요청하면 받겠다는 설정입니다.

@POST는 다음 메소드가 요청받을 Http Method입니다. POST로 설정하면 POST요청 이외에는 이용할 수 없게 됩니다.

@Produces, @Consumes는 요청, 응답 data type입니다. 설정 값과 어긋나면 type이 맞지 않는다고 Error가 발생합니다.

parameter로 RestClientVO라는것을 받았습니다. 이것은 요청시 RestClientVO로 넘겨준것을 받은것입니다.

이것이 Client에서 요청시에는 자동으로 XML로 바뀌었다가 Server에 와서는 자연스럽게 VO로 바뀐 것입니다.

실제로 이부분을 String 으로 바꾸면 String 형식의 xml로 나타납니다.

그 이후에는 일반적인 작업을 처리하고 결과를 return 하는 부분입니다. 역시나 간단하지 않습니까?

다만, 환경설정시 아시겠지만 Server측은 UrlMapping에 "*.do"가 아니고 "/"로 정의합니다.

그리고 REST를 이용시에는 요청값과 응답값이 무엇이 있는지 서로간에 확인을 해야지만 사용이 가능합니다.

굳이 똑같은 VO가 아니더라도 xml 혹은 json에서 값들을 분리하여 사용이 가능하므로

요청 값들이 String에 무엇인지 int의 무엇인지 정도를 꼭 확인해야 합니다.


굉장히 허접하게 정리해서 이걸 계속 웹에 정리해야 하는지 의문이긴 합니다만, 그래도 저같은 초보들이 조금이나마

도움이 되었으면 좋겠습니다. 다음번에는 Spring 3.0에서 REST구현법을 정리하겠습니다.

.
:
Posted by .07274.
.. .. ..
[펌] : http://msfury.tistory.com/118

스프링에서 기본적으로 지원하는 CommonsMultipartResolver라는게 있는데

이게 파일 여러개를 지원 안한다...

(뭐하나 제대로 되는게 없긔...)

참고 : http://www.egovframe.org/wiki/doku.php?id=egovframework:rte:fdl:file_upload_%EB%AC%B8%EC%A0%9C

방법을 찾던중

발견한 정부프레임워크 URL

1번링크의 2번 솔루션으로 해결했는데.

영어가 참 중요하다고 느낀게...

2번솔루션 대로 하면 여러파일의 업로드가 되는 대신 내가 원한대로

public class FileForm {
private CommonsMultipartFile file;
private MultipartFile[] fileArr;

public CommonsMultipartFile getFile() {
return file;
}

public void setFile(CommonsMultipartFile file) {
this.file = file;
}

public MultipartFile[] getFileArr() {
return fileArr;
}

public void setFileArr(MultipartFile[] fileArr) {
this.fileArr = fileArr;
}
}

요놈 안에 쏙 안들어 간다...

문제1.

 Map multipartFiles = new HashMap();
...
return new MultipartParsingResult(multipartFiles, multipartParameters);
MultipartParsingResult의 생성자 명세가 바뀐건지 아님 저 소스가 착각을 했던지...

첫번째 인자의 class가 HashMap이 아닌

MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();

요렇게 바꿔줘야 한다. 그럼 다음 문제가 발생하는데..

문제2.
// multipart file field
                CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
                if (multipartFiles.put(fileItem.getName(), file) != null) {
                    throw new MultipartException("Multiple files for field name [" + file.getName()
                            + "] found - not supported by MultipartResolver");
                }

MultiValueMap은 키 하나에 여러 Value를 가질수 있게 해주는 Map인데 put이 없다....

set과 add 메소드가 존재하지만 둘다 리턴값이 void라 null비교 구문에서 에러가 난다.

(set은 단일키에 단일 밸류를 입력할수 있게 해주고 add를 쓰게 되면 단일키에 멀티 밸류를 가지게 해준다)

암튼 내가 원하는 대로 처리를 하기 위해 널체크를 따로 했다. 어차피 fileItem.getName()이 널이거나

공백이면 파일 폼은 있었는데 입력을 안해줬다는 얘기니까.

if( fileItem != null && fileItem.getName() != null && !"".equals(fileItem.getName()) ){
multipartFiles.add(fileItem.getFieldName(),file);
}

여기서 중요한게 하나 더 있는데 getName으로 넣은게 아니라 getFieldName을 썼다는것

getName은 파일이름이고 리졸버를 지나간뒤 콘트롤러에서 받을땐 파일 이름이 키가되어 파일을 가져올

수 있다.(이거부터 좀 이상하다...저 소스 의도가 대체 뭔지...음...영어가 딸려서 의도 파악이 잘 안됨;;)

암튼 키를 필드네임으로 바꿔주면

<input type="file" id="fileArr1" name="fileArr" />

로 줬을때 fileArr을 키로 가지고 콘트롤러에 넘겨주게 된다.

그리하면 저 위에 FileForm 클래스에 MultipartFile[] fileArr; 이부분에 배열로 파일을 넣어주게 된다.

그 이후부터는 단일 파일 받았을때처럼 가져와서 처리하고 저장하면 끝~

'I.lib() > I.lib(Spring)' 카테고리의 다른 글

spring transactionManager 설정  (0) 2013.08.06
Spring 2.5 에서 Rest 사용하기 Sample  (1) 2012.09.06
DispatcherServlet 이란?  (3) 2012.03.07
[ViewResolver] ViewResolver  (1) 2012.03.07
Spring 에서 JSON 사용하기  (0) 2012.02.27
.
:
Posted by .07274.
2012. 3. 7. 17:18

DispatcherServlet 이란? I.lib()/I.lib(Spring)2012. 3. 7. 17:18

.. .. ..

[펌] : http://springmvc.egloos.com/504151

이전 장까지 MyBatis와 커넥션풀의 활용, 그리고 트랜잭션에 대해 상세히 알아보았습니다. 개인적으로 이 정도의 환경이라면 소, 중형 서비스 구축에는 문제없을 정도로 환상적인 제작환경이 구축됬다고 할 수 있겠네요. 또 실제로 많은 웹개발자들이 이런 포맷을 사용하고 있구요.

이제 우리가 해야 할 것은 누구나 탐낼만한 좋은 개발환경을 구축했으니 드문드문 처리해야할 애매한 문제들을 하나씩 알아나가보는 과정입니다. 그 중 오늘은 우리가 해결해야할 것은 바로 web.xml에 설정한 DispatcherServlet에 대해 알아가고 발생할 수 있는 문제점을 해결하는 것입니다.

스프링MVC는 DispatcherServlet 등장으로 정말 엄청나게 web.xml의 역할이 축소되었습니다. 예전같으면 서블릿을 URL로 활용하기 위해선 반드시 web.xml에 등록해야 했지만 이젠 DispatcherServlet이 해당 어플리케이션으로 들어오는 요청을 모두 핸들링해주니 말이죠.

물론 아직까지 web.xml의 역할은 중요합니다. <servlet>으로 DispatcherServlet을 등록해줘야 하는데다 이 객체의 URL 적용범위 또한 web.xml에다 설정해야 하구요. 향후 고급서비스를 위해 <filter>나 <listener>를 등록하는 역할 또한 web.xml의 기능으로 남아 있습니다.

대신 앞으로 web.xml에서 가장 주요하고 자주 쓰이는 기능인 <servlet>매핑은 이제 완벽하게 DispatcherServlet으로 넘어갔다고 생각합시다. 우리가 web.xml에 DispatcherServlet의 <url-pattern>을 '/'로 설정함과 동시에 이제 모든 요청은 DispatcherServlet의 영역이 된 셈입니다. 물론 DispatcherServlet을 web.xml에 등록해도 계속 서블릿을 web.xml에 매핑해쓸 수 있긴 합니다만 우리가 이런 옛방식을 버리고 DispatcherServlet을 이용해 웹개발을 한다면 앞으로 서블릿 파일을 만들 필요도 없어짐과 동시에 획기적이고 놀라운 @MVC의 혜택을 얻을 수 있습니다. @MVC에 대해서는 차후 설명하기로 하고 오늘은 DispatcherServlet의 역할에 대해 설명드리겠습니다.

먼저 DispatcherServlet을 이용한다는 것은 스프링에서 제공하는 @MVC를 이용하겠단 뜻입니다. @MVC는 그동안 추상적으로만알아오고 발전했던 MVC(Model, View, Controller) 설계영역을 아예 노골적으로 분할하여 사용자가 무조건 MVC로 어플리케이션을 설계하게끔 유도하는 방식인데요. (스프링이 전략패턴을 Dependency Injection이란 이름하에 유도하는 것과 마찬가지죠.) 이 말인즉 초보건 구루건 모두 @MVC를 이용해 어플리케이션을 개발한다면 99% MVC 설계의 원칙대로 웹어플리케이션이 제작할 수 있게 된다는 뜻입니다.

우리가 @MVC라는 이름 하에 DispatcherServlet 클래스를 web.xml에 등록하는 순간 스프링이 있기 전 힘겹게 배웠던 모델1, 모델2는 이제 완전한 추억거리가 되고 말 것입니다. @MVC는 설계자체를 모델1 방식으로 할 수 없게 만드는 데다 그동안 구현하기는 까다롭지만 활용성이 높다고 배웠던 모델2 방식을 모델1보다 쉽게 만들 수 있도록 환경을 조성해주기 때문입니다. 게다가 정확히 따지자면 @MVC는 모델 2방식의 설계도 아닙니다. 다만 우리가 @MVC로 코드를 작성하는 방식이 모델 2와 비슷해서 모델2 방식이라고 부르는 것 뿐이죠.

그렇다면 @MVC에서 DispatcherServlet가 담당하는 역할이 무엇인지 알아봅시다. 먼저 DispatcherServlet에 대해 간단히 정의해보자면 우리가 각각 분리하여 만든 Model 파트와 Controller파트 View파트를 조합하여 브라우저로 출력해주는 역할을 수행하는 클래스라 할 수 있겠네요.

간단하게 DispatcherServlet이 어떤 식으로 클라이언트의 요청을 처리하고 응답하는지 UML과 비슷한 방식으로 나타내 보았습니다. 아마 DispatcherServlet을 처음 접해본 분이시라면 모델2보다 복잡한 처리과정에 당황하실 수도 있겠네요. 하지만 위의 그림이 아무리 복잡해도 당황하실 필요는 없습니다. 어디까지나 저 처리과정의 대부분은 컨테이너가 대신 작업해주며 사용자가 직접 구현해야 될 분량은 얼마 되지 않으니까요. 먼저 위의 작업흐름을 풀어 자세히 설명하자면 다음과 같습니다.

① 클라이언트가 해당 어플리케이션에 접근하면 접근한 URL 요청을 DispatcherServlet이 가로챕니다. 이렇게 요청을 가로챌 수 있는 이유는 web.xml에 등록된 DispatcherServlet의 <url-pattern>이 '/'와 같이 해당 어플리케이션의 모든 URL로 등록되있기 때문입니다. 만약 특정 URL만 적용하고 싶다면 <url-pattern>의 내용을 바꿔주어 범위를 변경시키주면 됩니다.

② 가로챈 정보를 HandlerMapping에게 보내 해당 요청을 처리할 수 있는 Controller를 찾아냅니다. (스프링은 기본적으로 5가지의 핸들러 매핑을 제공합니다.) 이 부분은 스프링의 디폴트 전략에 의해 BeanNameUrlHandlerMapping과 DefaultAnnotationHandlerMapping이 기본으로 스프링MVC에 탑재되있기 때문에 특별한 경우가 아니라면 따로 설정할 필요가 없습니다.

③ 핸들러매핑이 해당 요청을 처리할 컨트롤러를 찾아냈다면 요청을 컨트롤러에 보내줍니다. 컨트롤러는 사용자가 직접 구현해주는 부분입니다. @MVC는 매우 다양한 코딩방식과 직관적이고 편리한 컨트롤러 작성방법을 제공하므로 이 부분에 대해서는 차후 심층적인 분석하여 자신에게 알맞는 전략을 선정해야 합니다.

④ 컨트롤러를 해당 요청을 처리한 후에 보통 컨트롤러는 요청을 응답받을 View의 이름을 리턴하게 됩니다. (물론 다른 핸들러 매핑 전략을 이용한다면 응답 과정이 다를 수도 있습니다.) 그 때 이 이름을 ViwResolver가 먼저 받아 해당하는 View가 존재하는지 검색합니다.

⑥ 해당 View가 있다면 처리결과를 View에 보낸 후 ⑦ 이 결과를 다시 DispatcherServier에 보낸 후 ⑧ DispatcherServlet은 최종 결과를 클라이언트에 전송합니다.

매우 복잡한 과정으로 처리되긴 하지만 이런 DispatcherServlet 전략에서 사용자가 직접 구현해야할 부분은 컨트롤러와 뷰 밖에 없습니다. 나머지 핸들러 매핑이나 리졸버는 대략적인 흐름만 알고 있다가 나중에 필요할 때 필요한 클래스를 컨텍스트에 등록시키기만 하면 그만입니다.



여기서 하나 문제가 발생했습니다. 디스패처 서블릿이 모든 요청을 컨트롤러에 넘겨주는 방식은 괜찮은데 모든 요청을 처리하다보니 이미지나 HTML 파일을 불러오는 요청마저 전부 컨트롤러로 넘겨버리는 것입니다. 게다가 JSP 안의 자바스크립트나 스타일시트 파일들도 전부 디스패처 서블릿이 요청을 가로채는 바람에 제대로 자원을 불러올 수도 없는 상황입니다. 도대체 어떻게 해야 할까요?


만약 이런 처리를 해주지 않는다면 위와 같은 에러가 로그에 기록될 것입니다. 디스패처 서블릿이 해당 요청을 처리할 컨트롤러를 찾지 못했다는 에러메시지죠. 이 문제를 해결하기 위한 방법이 몇가지 있습니다. 첫번째 방법은 아래와 같이 디스패처 서블릿이 처리할 URL과 자바와 관련없는 리소스들의 영역을 분리시키는 것입니다.

/apps - 클라이언트가 이 URL로 접근하면 앞으로 디스패처 서블릿이 담당
/resources - 이 URL은 디스패처 서블릿이 컨트롤할 수 없는 영역으로 분리

근데 이런 처리방식은 괜찮긴 하지만 상당히 코드가 지저분 해지는데다 form에서 모든 요청을 보낼 때 apps라는 URL을 붙여줘야 하기 때문에 직관적인 설계가 불가능해진다는 점이 있습니다. 두번째로는 진짜 말그대로 모든 요청을 컨트롤러에 등록하는 방법입니다. 허나 이런 방식은 정말 소규모 어플리케이션이 아니라면 절대로 해서는 안될 방법이겠죠.

스프링은 이런 모든 문제에 해결함과 동시에 굉장히 편리한 해결방법을 고안해 냈습니다. 그건은 바로 <mvc:resources />입니다. 만약 이클립스를 통해 저처럼 프로젝트를 Spring Template Project 생성하셨다면 servlet-context.xml에서 다음과 같은 코드를 발견하실 수 있으실 겁니다.

<resources mapping="/resources/-*" location="/resources/" />

이 전략은 다음과 같습니다. 먼저 디스패처 서블릿을 통해 들어온 요청을 처리하는데 만약 디스패처 서블릿이 해당 요청에 대한 컨트롤러가 찾을 수 없다면 2차적으로 위의 설정된 경로를 검색하여 해당 자원을 찾아내게 되는 것이죠. 저같은 경우는 기존의 resources폴더의 Depoloyment Assembly를 변경하여 아래와 같이 설정하는 것으로 문제를 해결했습니다.


만약 이런 비 어플리케이션 자원을 따로 분리하지 않고 어플리케이션 자원과 한데 섞어 작업하신다면 지금부터라도 이렇게 분리해서 작업하시길 권장해 드립니다. 먼저 이런 영역분리는 효율적인 리소스 관리와 확장을 돕기 때문입니다.

현대의 많은 대형 웹서비스들의 비 어플리케이션 자원 URL을 보시면 철저하게 static 성격의 외부 자원들을 분리시켜 사용하고 있습니다. 네이버같은 경우는 http://static.naver.net/란 URL을 통해 이런 자원들을 분리하였으며 페이스북은 http://static.ak.fbcdn.net/과 같은 URL로 분리시켰습니다. 이런 일례를 들어서라도 차후 확장을 위해 비어플리케이션 자원은 반드시 분리해야할 영역이라는 사실을 알려드리고 싶네요.

여기까지 DispatcherServlet에 대한 모든 설명이 끝났습니다. 다음 포스트부터는 슬슬 스프링 시큐리티에 대해 다뤄보려고 하는데 아직 아는 부분이 그렇게 많지 않은데다가 해결되지 않은 의문점이 다소 있어서 바로 포스팅하기는 조금 힘들 것 같네요 ㅠㅠ 문제가 해결되는 즉시 포스팅 하도록 하겠습니다.
.
:
Posted by .07274.
2012. 3. 7. 15:41

[ViewResolver] ViewResolver I.lib()/I.lib(Spring)2012. 3. 7. 15:41

.. .. ..
[펌] : http://linuxp.tistory.com/entry/Spring-Framework%EC%9D%98-ViewResolver

ViewResolver

- 컨트롤러 객체에 의해 반환된 ModelAndView 객체의 View 부분의 논리적 이름에 해당하는 View의 결정을 제공

- JSP, Velocity, FreeMarker, PDF, Microsoft Excel 등 다양한 뷰 지원

- org.springframework.web.servlet.ViewResolver 인터페이스를 구현한 여러가지 ViewResolver 지원


Spring에서 지원하는 View Resolver

1) AbstractCachingViewResolver

- Caching View를 다루는 추상(Abstract) ViewResolver
- 해당 View를 확장(extends)하는 View는 Caching 기능을 제공한다.

2) XmlViewResolver

- Spring의 bean 팩토리처럼 DTD를 가진 XML내 쓰여진 사항을 기초로 동작하는 ViewResolver
- 디폴트 설정 파일은 /WEB-INF/view.xml

3) ResourceBundleViewResolver

- ResourceBundle의 basname 속성에 명시된 bean 정의를 사용하는 ViewResolver
- 다른 ViewResolver와 혼합해서 사용 가능
- 디폴트 설정 파일은 views.properties
- [viewname].class = [viewname].url 형태로 설정

4) UrlBasedViewResolver

- 추가적인 어떤 맵핑 작업을 하지 않고 URL의 상징적인 view 이름을 사용하는 ViewResolver
- 단순 JSP만 사용할 경우 사용이 가능하다.
- 보통 해당 클래스를 확장하여 제공하는 별도의 ViewResolver를 사용한다.

5) InternalResourceViewResolver

- JSP, 서블릿, JstlView, TilesView 같은 View 기능을 제공하는 UrlBasedViewResolver의 편리한 하위 클래스

6) VelocityViewResolver

- Velocity View 기능을 제공하는 UrlBasedViewResolver의 편리한 하위 클래스

7) FreeMarkerViewResolver

- FreeMarker View 기능을 제공하는 UrlBasedViewResolver의 편리한 하위 클래스


ViewResolvers Chaining(혼합 사용)

- 여러개의 ViewResolver가 있을 경우에 혼합해서 사용 가능

- defaultParentView: 상위 ViewResolver의 설정사항을 오버라이드 가능

- order : 여러개의 ViewResolver가 존재할 경우 순서를 결정


UrlBasedViewResolver 사용 예제

<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
< /bean>



ResourceBundleViewResolver 사용 예제

<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<!-- view.properties에 기술 -->
<property name="basename" value="views"/>
<!-- views.properties 파일에 정의되지 않을 경우에는 parentView 에 정의된 사항을 따른다 -->
<property name="defaultParentView" value="parentView"/>
< /bean>

bookView.class = org.springframework.web.servlet.view.JstlView
bookView.url = WEB-INF/jsp/book/bookView.jsp

bookEdit.class = org.springframework.web.servlet.view.JstlView
bookEdit.url = WEB-INF/jsp/book/bookEdit.jsp



InternalResourceViewResolver 사용 예제


<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/spring/"/>
<property name="suffix" value=".jsp"/>
< /bean>



XmlViewResolver 사용 예제

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
< /bean>
< bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/simpleviews.xml"/>
< /bean>

<!-- simpleviews.xml -->
<beans>
<bean name="report" class="org.springframework.example.ReportExcelView"/>
< /beans>
.
:
Posted by .07274.
2012. 2. 27. 18:22

Spring 에서 JSON 사용하기 I.lib()/I.lib(Spring)2012. 2. 27. 18:22

.. .. ..
우선 찾아본 바로는 spring에서 지원하는 json데이타 처리법에는 크게 3가지가 있다.( 물론 더 있는거같다)

1. http://www.ibm.com/developerworks/kr/library/wa-restful/index.html

메세지 컨버터를 이용한 방법.
응답 메시지를 json데이타로 컨버팅하는 방법이다.
젤 간단하고 광역적으로 쓸수 있다.

2. http://whiteship.tistory.com/2297

MappingJacksonJsonView 를 이용한 방법
이 방법은 세번째랑 비슷한데 Jackson에서 제공하는 json뷰를 쓴다는거만 틀리고 같다.
위에꺼랑 맞먹게 간단한데.... 좀더 불편한건 ModelAndView를 만들때마다 jsonView로 만든 뷰의 이름으로 생성해야 된다는거

3.
http://ultteky.egloos.com/10496535

그동안 자주 써왔던 json-lib를 이용한 방법이다.
jackson도 안되던 부분이 이놈 뷰를 쓰니까 됐다....슈발...
2번이나 똑같은데 단지 라이브러리 종류가 틀리다.

[펌] : http://msfury.tistory.com/117





------------------------------------------------------------------------------------------------------
3번 json-lib를 사용하는 방법

서버에서 클라이언트로 리턴할 오브젝트를 Json형태로 변환 하거나 또는 그반대로
Json 데이터를 해당 오브젝트로 변환하는 라이브러리가 필요 합니다. 그중에서
Json-lib를 사용 합니다 .
(해당 사이트에 접속하면 다양한 json 라이브러리를 다운 받을 수 있습니다. ).
여기서 최신 버전으로 다운로드를 받습니다.
다운로드 후 이클립스 프로젝트에
라이브러리를 추가 합니다.
웹 사이트 : http://json-lib.sourceforge.net/
다운로드 : http://sourceforge.net/projects/json-lib/files/
사용법은 해당 사이트를 참고 하시면 됩니다.
  • 스프링 전용 JsonView 다운 받기
아래의 사이트로 접속 후 화면 맨 하단을 보면 "json-lib-ext-spring" 가 있습니다.
거기서 최신 버전의 라이브러리를 다운로드 후 이클립스 프로젝트에
추가 합니다.
다운로드 : http://sourceforge.net/projects/json-lib/files/

  • JsonView 스프링 빈 설정
아래와 같이 JsonView를 빈으로 설정 합니다.
<bean id="jsonView" class="net.sf.json.spring.web.servlet.view.JsonView"/>

  • ViewResolver 설정

JsonView를 인식 하기 위해서 "BeanNameViewResolver"를 설정 합니다.
WebApplication에서는 여러 Resolver가 존재 할수 있기 때문에
우선 순위를 "0"으로 설정해서 최우선으로 설정 합니다.
    <bean id="beanNameResolver"
class="org.springframework.web.servlet.view.BeanNameViewResolver"
p:order="0" />


  • Controller Code
아래의 코드를 보면 매우 평범합니다. 어떤한 라이브러리 참조도
없이 평소처럼 코딩 하면 됩니다. 모든 ajax 처리는 JsonView가
처리 함으로써 단지 JsonView가 선언된 스프링 빈 id를
ModelAndView의 "setViewName" 메서드에 선언만
하면 됩니다.


public final ModelAndView handlerRequest(final HttpServletRequest request,
final HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();

DummyMember dummyMember1 = new DummyMember();
dummyMember1.setId("xxxxxxx");

DummyMember dummyMember2 = new DummyMember();
dummyMember2.setId("yyyyyy");

List list = new ArrayList();
list.add(dummyMember1);
list.add(dummyMember2);

Map resultMap = new HashMap();
resultMap.put("result1", list);
resultMap.put("result2", dummyMember1);

modelAndView.addAllObjects(resultMap);
modelAndView.setViewName("jsonView");
return modelAndView;
}

※ 샘플 도메인
public class DummyMember {
private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}
}


  • 결과 JSON 패킷

{"result2":{"id":"xxxxxxx"},"result1":[{"id":"xxxxxxx"},{"id":"yyyyyy"}]}

customizing이 필요하면 JsonView 클래스를 상속 받은 후에 "renderMergedOutputModel"
메서드를 override 하시거 아니면 직접 다운로드 사이트에서
소스를 받은 후에 수정 후 적용 하시면 됩니다.
.
:
Posted by .07274.
.. .. ..
[펌]       : http://open.egovframe.go.kr/projects/freediscussion/share/2610
[작성자] : 정지범 님

부재 :
이유 없는 "java.lang.ClassNotFoundException : org.springframework.web.context.ContextLoaderListener" 을 더이상 보고 싶지 않은 개발자에게..

전자정부 표준프레임워크 기반을 프로젝트 수행 중에 개발환경에서 "java.lang.ClassNotFoundException : org.springframework.web.context.ContextLoaderListener" 를 한번 보지 못한 사람은 아마도 없을 것이다. 필자역시 표준프레임워크 구축 프로젝트를 수행하면서 업무로직을 구현하고 집으로 칼퇴근 해야 할 아까운 시간에 WTP, Tomcat, M2Eclipse, maven 의 궁합에 대해 고민하는 무의미한 시간을 보내는 쓰디쓴 경험을 한 기억이 있다.


1. Eclipse Upgrage로 해결?

WTP, m2Eclipse로 고민하던 때… 처음으로 시도한 방법은 Eclipse 업그레이드!!
소프트웨어의 업그레이드는 막연한 기대감을 주는데.. 나도 그 유혹에 잘 넘어가는 편이라 문제가 발생하면 먼저 업그레이드 부터 생각한다. 전자정부 표준프레임워크의 개발환경 IDE는 Eclipse 3.4를 기반으로 개발되었다. 현재 Eclipse는 3.7 까지 릴리이즈 되었으니 상당히 구버전이라고 할 수 있다. 테스트는 Eclipse 3.6 에서 수행하였다.
먼저 프로젝트 생성 후 pom.xml에 표준프레임워크 관련 dependency를 설정하고 WTP, Tomcat으로 실행!! 역시 눈에 익은 오류가 보인다.

"java.lang.ClassNotFoundException : org.springframework.web.context.ContextLoaderListener"

maven dependency에 설정한 라이브러리가 배포되지 않아서 발생하는 오류다. 이를 해결하기위해서 "프로젝트 선택 > 우클릭 > properties > Deployment Assembly 메뉴 > Add 버튼 > Java Build Path Entries > Maven Dependencies 선택" 을 한 후 다시 실행하였다. 성공!!

축배를 들고 싶었다. 여기서 더이상 시간을 쓰고 싶지 않았다. 하지만 이 방법은 치명적인 단점이 있었다. 그것은 maven dependency의 scope가 정상적으로 적용되지 않는다는 것이다.

maven은 dependency에 scope란 옵션이 있다. scope는 compile, provided, test 등이 있으며 의미를 가진다.
예를 들어 provided 의 경우, 컴파일 단계에서 클래스 패스에 추가 하여 사용되긴 하지만 배포 모듈에 포함되지는 않는다. 일반적으로 Java EE 의 API 클래스가 이런 옵션을 사용하게 된다.

Eclipse의 Deployment Assembly를 사용하는 경우, war안에 Java EE API가 포함되어 일부 WAS에 뜻하지 않는 오류가 발생하였다.

2. Maven & Jetty
고심끝에 두번째 방법은 WTP와 Tomcat을 버리는 것이었다. 또 한가지 알게된 것은 Maven이 eclipse가 없는 환경에서도 너무나 많은 일을 할 수 있다는 것이다. 유명한 오픈소스 apache camel은 배포 파일에 까지 포함해서 실행시 maven 명령어를 쓰도록 가이드 하고 있다.

WTP와 Tomcat을 대체할 maven의 플러그인은 바로 jetty plugin 이다. jetty 는 www.mortbay.org 에서 관리하는 오픈소스 servlet 컨테이너 이다. 워낙 경량형 이기도 하고 실행 모듈에 포함해서 서블릿 엔진을 따로 설치하지 않아도 사용할 수 있는 제품을 패키징 할때 포함하기도 한다. Google Appengine의 개발환경에서도 log를 통하여 jetty를 사용하고 있다는 사실도 주목할 만 하다.( App Engine에 흠뻑 빠진 요즘 구글이라면 항상 믿음이 간다. )

이러한 경량의 특성을 살려 maven plug-in으로서도 널리 사용된다. jetty maven 플러그인은 (http://docs.codehaus.org/display/JETTY/Maven Jetty Plugin)에서 사용법을 확인 할 수 있다.

적용방법

1. 먼저 전자정부 표준프레임워크 개발환경에서 수행중인 프로젝트의 pom.xml 을 연다.
2. <build> 설정에 아래의 플러그인 설정을 추가한다.

<build>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.2.2.v20101205</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<reload>automatic</reload>
</configuration>
</plugin>
</plugins>
</build>

3. "프로젝트 선택 > 우클릭 > Run As > Maven Build > Goal에 jetty:run 입력 > 확인 " 을 차례로 수행'
4. 웹브라우저 접속 "http://localhost:8080";
5. 성공!!

사실 이 방법은 실행 및 테스트에 있어서 Eclipse의 도움을 거의 받지 않는 방법이다. 이로 인해 integration으로 인한 자잘 한 오류에서 벗어 날수 있었다.
무엇보다도 maven의 특성이 정확하게 적용되는 것으로 인해 개발자 PC의 환경의 pom.xml이 개발서버에서도 일관되게 사용할 수 있어 Continuous Integration 적용에도 큰 도움이 된다.

참고 사이트 : http://docs.codehaus.org/display/JETTY/Maven Jetty Plugin
.
:
Posted by .07274.
.. .. ..

Spring을 쓰는 이유.


10년전이야 몰라도 요즘 세상은 자바로 개발을 하게되면 스케일이 엄청나게 크다. 앞으로도 스케일이 점점 커지게 되고 그렇게 되면 프로젝트 규모도 커지게 된다.
이렇게 되면 많은 개발자들이 한 프로젝트에 달라붙게 되는데 많은 개발자들이 한 프로젝트에 붙어서 서로 분할하여 개발을 하다보면 분명 중복되는 부분도 많고 또 복잡해지고.. 비즈니스 로직은 점점 복잡해지지 요구사항은 점점 늘지...
스프링은 이런 개발을 편하고 알차게 하라고 만들어진 오픈소스 프레임 워크다.
(오픈소스 : 아무나 가져다 써도 되는 것을 의미)
(프레임 워크 : 좀더 개발하기 쉽도록 공통 클레스를 만들어 묶어놓은 것으로 생각하면 됨.)

어떻게 편하게일까?!

비즈니스 로직을 담은 애플리케이션 부분과 엔터프라이즈 기술을 처리하는 부분의 분리(뭐 단계별로 쪼갰다고 생각하면됨. 멋진말로는 모듈화?!) 등이 있다.
위의것 말고도 많은 편하게를 SPRING 이 제공하고 있다. 그걸 주저리 주저리 쓰면 백년이 걸리고 가장 보편적으로 책을봐도 인터넷 검색을 해봐도 나오는 편하게 해주는 것들이 있는데
Ioc, DI, AOP, (여기에 더하면 PSA도 있다.)
스프링이 JAVA 개발을 편하게 해주는 방법은 위가 전부다. 진짜루~

IOC 란

개발자는 JAVA 코딩시 New연산자, 인터페이스 호출, 팩토리 호출 방식으로 객체를 생성하고 소멸시킨다.
IOC란 인스턴스(객체)의 생성부터 소멸까지의 객체 생명주기 관리를 개발자가 하는 대신 스프링(컨테이너)이 대신
해주게 하는것을 말한다.
그럼 이런 의문이 생기겠지 . 이걸 왜 스프링 시켜 내가하면 되는데?!
천재적으로 코딩을 잘하는 개발자라면 쓰지 않아도 된다. Java 상으로 구현하면 되니까.. 하지만
Spring 의 목적에서도 봤듯이 스케일이 커져만 가는 요즘 세상에 그 많은 객체들을 깔끔하게 관리하기도 빡시고
또 자원을 잘 활용해야되는데 이걸 개발자가 하지말고 Spring 시키자!! 이런의미에서 Spring 을 쓰고 이게 IOC 다.
책이나 인터넷 이런곳에서 설명하는것은 좀더 추상적이고 그 말들이 정답이지만 알기 쉽게 설명을해야지 ;;
개념은 위 방식으로 이해하고 그 책들을 읽으면 좀더 이해가 될 것이다.

DI 란?

이건 가장 이해하기 쉬운 개념이다. 레고의 사람을 생각하면 바지를 막 바꿔 낄수 있다. 머리통도 바꿔낄수 있다. 팔에 막 무기도 쥐어줄수 있고 빼서 다른걸 낄수 있다. 이게 DI 이다.
JAVA 상으로 생각해보면 코드를 짜는중에 DB랑 접촉하는 부분(DAO) 이 있는데 생 JAVA로 짜는 사람도 있고(JDBC) iBatis , JPA 등의 프레임 워크를 이용해서 짜는 사람들도 있다. 이때 Spring 을 이용하면 그때마다 필요한 부분을 뺐다 꼈다할수 있다. 여기서 말하는 빼고 끼는것을 주입(인젝션?!)한다고 하는데 뭐 그런의미다. 이게 DI다 쉽게 뺐다꼈다 할수 있는것..

AOP 란?

이놈은 정말 어렵다. 진짜 어렵다.. 백날 공부해도 백날 어렵다. 쉽게 이해하기 위해 그림을 찾다가 발견한것이 아래와 같다.

A B C

 

 



위와같이 A,B,C 클레스가 있다. 안의 색들은 소스들이라는 개념을 가지면 된다.
근데 A,B,C 클레스를 보면 같은 색들이 있는데 이것은 서로 공통되는 소스라고 생각하면 된다.
위와같이 코드를 짜면 공통된것들이 중복되다보니 코드의 가독성도 별로고 개발 속도도 별로다.
그래서 스프링 AOP는 아래와 같이 할수 있게 한다.

A B C

 

 


스프링의 AOP는 저렇게 공통된 애들은 따로 빼두고 필요할때 불러다 쓸수 있도록 해준다.저 공통된 애들중에 하나를 책들에서 설명하는것은 트렌젝션 처리가 있다. 물론 이 외에도 다양한 기능이 있지만 트렌젝션 처리가 AOP를 설명해주기엔 딱이니까..
트렌젝션을 예를 들을때 AOP가 원하는 조건(메소드명에 트렌젝션이라 적기)에 맞춰서 A,B,C 클레스를 개발하면 그 조건에 맞는 메서드가 동작할 시에는 트렌젝션이 그 메서드에 먹는다는거~~ 이게 AOP를 이용한 트렌젝션 개념이다.

AOP에 대해 보통 책을 보면 아래와같이 어렵게 써둔다 (쉽게좀 설명하면 좀좋아 ;;)

관점 지향 프로그래밍(AOP, Apsect-oriented programming)은 핵심 관심사를 분리하여 프로그램 모듈화를 향상시키는 프로그래밍 스타일이다. AOP는 객체를 핵심 관심사와 횡단 관심사로 분리하고, 횡단 관심사를 관점(Aspect)이라는 모듈로 정의하고 핵심 관심사와 엮어서 처리할 수 있는 방법을 제공한다.


위의 설명과 다를거 없다. 이해 안되면 죽어~!


이제 끝이다. 스프링은 저게 다다. 아까 PSA도 있다고 설명했는데 이건 별거 아니다.

환경과 세부 기술의 변화에 관계없이 일관된 방식으로 기술에 접근 할 수 있게 해주는 기술이 PSA(Potable Service Abstraction)이다.

위 말은 이해하기 쉽게 설명하면 환경이 아무리 달라져도 잘 작동할수 있게 도와주는게 SPRING 이다라는 뜻이다.


끝~!
위 설명은 Spring 의 이해하기 쉽게 쓴 개념일 뿐이지 정석은 아니다.그리고 위 개념을 알고 소스로 몇번 쳐봐야 아~ 이래서 이게 이거구나 싶어진다.
Spring 설정에 관련된 XML을 만들다 보면 JAVA 소스보다 XML 파일이 더 많아지기도 한다. 이건 배보다 배꼽이다라고 안쓰고 말지라고 생각할수도 있는데 조금은 큰 프로젝트만 들어가도 이건 대박 편하다. 해보면 안다. 이부분은 심화과정이나 가야 알게되니 지금은 개념만 알고 넘어가면 된다.
.
:
Posted by .07274.