회사에서 팀에서 스터디겸 프로젝트로 하나 진행하고 있는 것이 있다.

새로운것들을 마구마구 적용해서 공부도 하면서 비지니스에 뭔가 도움이 될만한 재미있는 것을 만들자는 것이 목적인데...


현기형님께서 워낙 이런 기술습득이나 적용에 월등하게 빠르셔서.. 그냥 설정해주신 내용을 가지고 따라 쓰기도 바쁜 상태였었다. 빌리님께서 셋팅하신 스프링 배치도 마찬가지고... git빼고는 해본게 아무것도 없는 설정이라 더욱 곤욕...ㅋ


그래서, 그래도 프로젝트 초반에 한번 직접 셋팅이라도 해보지 않으면 나중에 더 힘들어질듯하여..

예전에 봤던 책 내용들을 다시 되새기면서(구글링하면서...) 셋팅을 해보았다.


막셋팅이라 최적화와는 거리가 멀겠으나 일단 테스트케이스까지 만들어보는 것 성공...

그 내용을 이제 맥북프로를 받으시면 똑같이 해보셔야하는 계춘님을 위해 정리 ㅋㅋ


1. build.gradle


많은 부분을 현기형님이 작성하진 build.gradle에서 차용.. 아직 gradle이 익숙하지 않은데.. 이번에 이거 셋팅하면서 이것저것 만지작 거렸더니 조금 감이온다.  ${target}은 Default로 "local"이 셋팅된다.

또한 allprojects에서 target의 값에 맞춰서 sourceSets을 정의하도록 하였다. 이에 맞춰서 build시에 resources-${target} 의 파일들이 processResouces에 의해서 target directory로 이동된다



2. applicationContext-dao.xml


대부분의 설정이 들어간다. 하이버네이트 관련 설정은 persistence.xml에 위치시키고 여기서는 entityManagerFactory bean 생성시 참조하도록 하였다. 그리고, local에서는 HSQL DB가 같이 startup 될 수 있도록 "jdbc:embedded-database"로 설정을 추가하였고, 이때 사용 할 schema와 testData sql은 별도로 만들어 위치를 지정하였다.



3. schema.sql, test-data.sql


HSQL용 ddl sql과 테스트 데이터를 위한 insert sql 문장.



4. jdbc.properties



profile별로 설정 할 수 있게....



5. persistence.xml


hibernate.dialect 설정에 HSQL관련 설정이 있음.



6. User.java


Entity로 사용될 User 클래스. 특별한것은 없다..



7. UserDao.java


CrudRepository를 사용한 인터페이스. CrudRepository를 extends하면서 기본적인 CRUD 메서드가 제공된다. (find, findAll 등등)



8. UserDaoTest.java



Mockito등을 사용해서 실제 데이터베이스와의 연결을 단위테스트에서는 하지 않기도 하지만, 이번에는 설정들이 잘 되어 UserDao의 동작을 실제로 보기위해서 Mockito는 사용하지 않았다. save() 메서드에서 하나의 user 객체를 save하였는데, findAll에서는 2개의 User 객체가 return된다. 위 jdbc:embedded 설정에 의해서 하나의 테스트 데이터가 이미 들어가 있는 상황임을 알 수 있다.


9. UserDaoJpaRepository.java


JpaRepository를 상속한 인터페이스도 한번 추가해보았다. CrudRepository와 JpaRepository의 차이점은 이곳에..

(http://stackoverflow.com/questions/14014086/what-is-difference-between-crudrepository-and-jparepository-interfaces-in-spring)

요약하면 "JpaRepository will have all the functions of CrudRepository and PagingAndSortingRepository" 이다. 

즉, JpaRepository는 PagingAndSortingRepository를 상속하고 있고, PagingAndSortingRepository는 CrudRepository를 상속하고 있다.



10. UserDaoJpaRepositoryTest.java



findAll() 메서드에서 캐스팅이 필요없는 것을 참고.


11. 프로젝트 구조









현재 진행중인 팀프로젝트에는 Query DSL까지 들어가있다. 처음에 Spring-data도 모르는 상황에서 팀프로젝트의 설정을 보니 어디까지가 spring-data이고 어디부터가 Query DSL인지도 모르겠더라... 그만큼 잘 녹아있기도하고.. 그래서 일부러 이번에 설정할때는 Query DSL을 제외하고 설정을 해보았다.. 
해보니 좀 알겠다....;;

원래 모든 설정을 모두 이해하고 사용하는것이 올바르고 정확하겠으나...
우선 한번 부딫혀보는걸로...... ㅎㅎㅎ


근데 이클립스에서 테스트케이스 돌리면 잘 도는데..

gradle build 커맨드를 통한 테스트케이스 실행은 Entity가 관리 대상이 아니라면서 에러가 나는데..

이거 이유를 잘 모르겠다..;

저작자 표시 비영리 변경 금지
신고
Posted by 용식

http://stackoverflow.com/questions/14014086/what-is-difference-between-crudrepository-and-jparepository-interfaces-in-spring

저작자 표시 비영리 변경 금지
신고
Posted by 용식

토비의 스프링 3.0에서 ..



저작자 표시 비영리 변경 금지
신고
Posted by 용식

jvm 실행 시 -D 옵션으로 주는 값에 대해서 

아래와 같이 읽을 수 있다.


@Value("#{systemProperties['key'] == null ? 'real' : systemProperties['key']}")
private String mode = null;


el expression을 그대로 사용 가능한 것 같다.

위와 같은 형태로 작성하면 default 값을 지정한것과 같은 효과를 줄 수 있음.

저작자 표시 비영리 변경 금지
신고
Posted by 용식

[Spring] Scheduled

Spring 2013.01.10 18:40

로그분석기를 개편하면서 (회사내 개인 프로젝트)

기존에 cron으로 돌리던 job을 quartz + spring으로 바꾸려고 이것저것 찾아보다보니

spring 3.1 부터는 어노테이션으로 이게 가능해진것을 알았다.


간단히 테스트해본 내용을 올려봅니다.


우선, applicationContext.xml에 아래와 같은 설정이 필요합니다.




task에 대한 namespace 선언이 필요하며 

<context:component-scan base-package="com.tistory.devyongsik"></context:component-scan>
<task:scheduler id="taskScheduler"/>
<task:executor id="taskExecutor" pool-size="1" />
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler" />

설정이 필요합니다.
실제 스케쥴에 의해서 실행될 job 클래스는 아래와 같이 구현합니다.



@Service나 @Component나 spring에서 어노테이션으로 스캔하여 bean으로 등록될 수 있으면 상관은 없는듯하며
@Scheduled 어노테이션으로 cron 형태로 스케쥴을 정할 수 있습니다.
다만 맨 앞이 초입니다. 0 34 18 * * *의 경우 매일 18시 34분 0초에 실행한다는 뜻입니다.

그리고 fixedDelay도 있는데 이건 ms단위로 실행 주기입니다. 위와 같이 500으로 설정할경우 500ms에 한번씩 실행됩니다.


저작자 표시 비영리 변경 금지
신고
Posted by 용식
관리가 편할 것이라는
풍주대리님 얘기를 듣고..
작업해 놓은 rmi를 httpInvoker로 변경.

만들어 놓은 인터페이스는 그대로 사용하고
설정만 수정하였다..

spring에서 제공되는 클래스를 사용하고...
똑같이 클라이언트 인터셉터를 사용한다.


따로 포트 관리 할 것도 없고
확실히 편하다는 느낌이 든다.

이걸로 결정~!!
저작자 표시 비영리 변경 금지
신고
Posted by 용식

스프링에서는 객체를 컨테이너에서 관리 하는데 이 컨테이너와 관련된 인터페이스가
BeanFactory 인터페이스이다.

BeanFactory <- AppilcationContext <- WebApplicationContext 

이렇게 구성되어있다. (implements 하고 있음..)

BeanFactory 인터페이스는 가장 기본이 되는 것으로
일반적인 Application에서의 사용 되는 예를 보면

applicationContext.xml 파일에 빈 정보를 설정하고

pulbic class BeanFactoryMain {
 public static void main(String[] args) {
  Resource resource = new ClassPathResource("applicationContext.xml");
  BeanFactory beanFactory = new XmlBeanFactory(resource);
  SomeService ss = (MoreSomeService) beanFactory.getBean("svcname");
  ss.doSomething();
 }
}

이렇게 사용 할 수 있다.
어??? 스프링인데 웹 어플리케이션이 아닌 상태에서도 작동을 하네???

컨테이너라는 것을 웹컨테이너와 굳이 연관 짓지 말고 개념적으로 POJO 클래스들을 한곳에 모아서
관리 할 수 있는 공간이라고 생각해도 될지 모르겠다.

XmlBeanFactory는 BeanFactory 인터페이스를 구현한 클래스이다.

(Resource 구현 클래스에 대해서는 최범균님께서 쓰신 "스프링 2.5 프로그래밍 - 가메출판사" 를 보면 리스트가 나와있다.)

ApplicationContext 인터페이스는 BeanFactory 인터페이스를 상속 받은 하위 인터페이스이다. 기본 빈 관리 기능에 몇가지 추가 기능을 가지고 있다.

WebAppilcationContext 인터페이스는 바로 웹 어플리케이션을 위한 ApplicationContext이다. 하나의 ServletContext 마다 하나의 WebApplicationContext가 존재한다.

web.xml 의 설정을 사용하지 않고 직접 사용하는 예를 보면

String xmlDir = "applicationContext.xml"; // WEB-INF/
ApplicationContext ac = new ClassPathXmlApplicationContext(xmlDir);
SomeService ss = (MoreSomeService) ac.getBean("beanName");

이렇게 된다.

그리고 XmlWebApplicationContext 클래스가 있는데, web.xml 파일 설정을 통해 이 객체가 자동으로 생성되고 사용된다. (WebapplicationContext를 구현한 클래스중 하나이다.)

web.xml 에서 설정해 놓은

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /WEB-INF/spring/config/applicationContext*.xml
  </param-value>
 </context-param>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

이 설정에 의해 ContextLoaderListener를 서블릿 컨텍스트로 등록해 놓으면
XmlWebApplicationContext 객체가 생성된다. (ContextLoaderListener가 웹 어플리케이션을 초기화 할 때 사용한다)

이렇게 생성된 XmlWebApplicationContext는
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); // jsp 내장객체 ServletContext application = pageContext.getServletContext();
로 가져올 수 있다.

WebApplicationContext를 구현한 클래스들은
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext도 있는데 결국 XML 빈 설정 파일을 가져와서
WebApplicationContext를 생성 하는 것들이다.

웹어플리케이션상이 아닌 테스트 등을 진행 할 때 유용하게 사용 할 수 있을 것이다.
저작자 표시
신고
Posted by 용식
TAG Spring

빈의 생명주기에서 스프링은 초기화와 소멸과정을 지원한다.

각각 2가지의 방법이 있는데 하나는 스프링에서 제공되는 인터페이스를 구현하는 방법과

하나는 메서드를 만든 후 그 메서드를 설정 파일에 명시해 주는 것이다.

우선 초기화 과정 지원을 보자.

일단, InitializingBean 인터페이스를 implements 하여

public void afterPropertiesSet() 메서드를 구현하여 주는 것이다.

또 하나는 클래스에 임의의 메서드를 만들고나서

예를 들면 public void init() {..}

설정 xml에

<bean id="" class="......UserServiceImpl" init-method="init">

이렇게 init-method 속성으로 추가해주면 된다.

소멸과정을 지원하는 메서드로는

일단, DisposableBean 인터페이스를 implements하여 destroy() 메서드를 구현해주는 방법과

임의의 메서드를 만들어서

설정 xml파일에 destroy-method 속성에 메서드명을 추가해주면 된다.

2.5 버젼에서는 뭔가 더 있을지도 모르겠다 -_-

신고
Posted by 용식

스프링을 다시 공부하고 있다..

스프링에서 웹 요청을 처리하기 위해서는 일단 web.xml에 아래와 같은 설정을 해줘야 한다.

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

그리고, 스프링 설정 xml인 dispatcher-servlet.xml에는 아래와 같은 설정을 해줘야 한다.

<bean name="/greeting/hello.htm" class="kame.spring.chap04.controller.HelloController" p:me="yongseok" />

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

그렇게 되면 사용자가

http://xxxxxxx/greeting/hello.htm 을 요청하게 되면

바로 handlerMapping에 의해서 /greeting/hello.htm의 이름을 가진 컨트롤러를 사용하게 된다.

자, 여기서 만약

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />

이부분을 삭제한다면? 어떻게될까..

답은 정상적으로 작동한다이다. log4j 로거 레벨을 debug로 해놓고 서버를 올려보면, 자동적으로

위 맵핑 클래스를 가지고 올라간다.

DEBUG DispatcherServlet [2008-08-21 14:24:42,171] - Testing handler map [org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping@5b0668] in DispatcherServlet with name 'dispatcher'

그렇다면, 맵핑 클래스를 바꾸고 싶다면 어떻게 할까?

<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="mappings">
<props>
<prop key="/content/**/*.htm">helloController</prop>
<prop key="/greeting/hello.htm">helloController</prop>
</props>
</property>
</bean>

이런식으로 설정해주면 디폴트로 SimpleUrlHandlerMapping을 사용하게 된다.

더 정확하게 얘기하자면 dispatcher-servlet.xml에

<bean name="/greeting/hello.htm" class="kame.spring.chap04.controller.HelloController" p:me="yongseok" />

<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="mappings">
<props>
<prop key="/content/**/*.htm">helloController</prop>
<prop key="/greeting/hello.htm">helloController</prop>
</props>
</property>
</bean>

이렇게 /greeting/hello.htm을 중복되게 해놓고 호출하게 되면 SimpleHandlerMapping을 사용하게 되고 따라서

<bean id="helloController" class="kame.spring.chap04.controller.HelloController" p:me="simple" />

이 설정을 추가해줘야 한다.

BeanNameUrlHandlerMapping는 bean name과 url을 맵핑하여 바로 controller를 찾아갔지만 SimpleUrlHandlerMapping 을 사용 할 경우

helloController를 xml에서 찾기 때문에 추가해줘야 하는 것이다.

위 부분에서 bean id="handlerMapping" 부분의 id 이름을 다른 것으로 줘도 동일하게 작동한다.

만약에,

<bean name="/greeting/hello2.htm" class="kame.spring.chap04.controller.HelloController" p:me="yongseok" />

<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
<property name="mappings">
<props>
<prop key="/content/**/*.htm">helloController</prop>
<prop key="/greeting/hello.htm">helloController</prop>
</props>
</property>
</bean>

이렇게 설정을 해놓고 /greeting/hello2.htm을 호출 할 경우에는 404 에러가 발생하게 된다.
이미 , SimpleUrlHandlerMapping 클래스를 사용하고 있기 때문에, 디폴트로 물고 올라갔던 BeanNameUrlHandlerMapping는 무시되는 듯 하다. 같이 사용하고 싶으면 order를 주는 방법이 있을듯..


아무튼 디폴트로 사용되는 맵핑 클래스가 있다는 것이... 새로 알게된 사실..

신고
Posted by 용식
TAG MVC, Spring

[spring] spring 기초

Spring 2008.05.26 10:21

빈의 설정 정보 관리 파일이 xml이라고 보면

 

xml에서는

 

<bean id ="UserDAO" class="net.javajigi.user.dao.MySQLUserDAO" />

 

<bean id="userService" class="net.javajigi.user.service.UserServiceImple">

  <property name="userDAO">

      <ref local="userDAO"/>

  </property>

</bean>

 

이런식으로 설정이 되어 있다.

 

실제 소스에서는

 

public class UserServiceImpl implements USerService {

   private UserDAO userDAO;

 

public void setUserDao(UserDao newUSerDAO) {

    this.userDAO = newUSERDAO;

}

 

 

int result = userDAO.insert(user);

 

...

 

 

이처럼 UserDAO에 대한 정의나 생성이 아무것도 없이 사용 할 수 있는데 xml에 설정되어 있기 때문이다.

 

bean태그 아래 property 태그의 이름이 userDAO라면 위 예제 클래스의 setUserDAO를 통하여 자동으로

 

xml에서 설정되어 있는 MySQLUSerDAO의 객체를 해당 인스턴스에 전달하게 되는 것이다.

 

이렇게 의존관계가 형성될 때 setter메소드를 이용하는 것을 Setter Injection이라고 한다.

 

 

그렇다면 Construcetor Injection은?

 

public UserServiceImpl (UserDAO newUserDAO) {

 this.userDAO = newUSerDao;

}

 

 

<bean id=....>

   <constructor-arg>

      <ref local="userDAO" />

   </constructor-arg>

</bean>

 

이렇게..사용된다

신고
Posted by 용식
TAG Spring