2013년 4월 18일 목요일

[Spring] DWR

웹을 이용하다보면 사용자에게 편리하고 유용한 기술이 Ajax란 것을 느낄 수 있다. 그렇지만 동시에 개발자에게는 번거로운 작업이기도 하다. 자바스크립트에서 이벤트를 발생시키고 필요한 데이터를 서버에 전송하여 원하는 결과 값을 json이나 다른 형태의 데이터 포맷으로 가져오는 것이 단순히 웹을 리로딩시키는 것보다는 할 일이 많기 때문이다.

그런데 스프링에서는 굉장히 유용한 기술이 있다. DWR이 그것이다. DWR(Direct Web Remote)은 Ajax를 이용해서 자바스크립트에서 원격으로 서버의 자바객체를 호출할 수 있도록 해주는 자바 기반의 RPC라이브러리다. 자바스크립트에서 자바의 메서드를 호출한다는 것만으로도 대단한 기술이다.

또한 DWR은 서버 측의 결과 객체를 JSON형식으로 변환해 주기 때문에 더더욱 편리하다!

그렇지만 처음 사용하는 것 역시 어려움이 따르므로 어떠한 순서로 DWR을 적용시켜나가는지 살펴보도록 하자.

우선 dwr.jar라이브러리가 필요하다. dwr.jar파일을 추가하면 관련 코드를 xml에 추가해 주어야한다.

xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd

xml설정 파일에는 자바스크립트로부터의 요청을 처리할 DWR컨트롤러를 <dwr:controller>태그를 이용해 설정해주어야한다. 그리고나서 컨트롤러가 처리할 요청에 대해 매핑이 필요한데 자세한 코드는 다음과 같다.

<!-- DWR Setting -->
<dwr:controller id="dwrController" debug="true">
<dwr:config-param name="crossDomainSessionSecurity" value="false"/>
</dwr:controller>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true"></property>
<property name="mappings">
<props>
<prop key="/dwr/engine.js">dwrController</prop>
<prop key="/dwr/**/*">dwrController</prop>
</props>
</property>
</bean>
<bean id="handlerMapping2" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean>

톰켓 7버전부터 단순히 <dwr:controller>를 이용한 컨트롤러 설정이 되지 않는다. 그 이유는 세션 보안과 관련한 문제를 발생시키기 때문이다. 그래서 <dwr:config-param>태그에 속성을 위와 같이 설정해 주어야한다.

그 다음으로 핸들러 매핑 객체를 만들고 있다. dwr을 사용하기 위해서 SimpleUrlhandlermapping클래스를 이용하여 핸들러를 사용할 것이다. 특히 <prop>태그에 경로를 항상 engine.js가 필요하다는 것을 명심해야 한다.

마지막으로 한가지 설정해주어야 할 것이 남았다. 지금까지 스프링을 활용하여 웹 어플리케이션을 제작하면서 @어노테이션 방식으로 컨트롤러를 등록하고 응답에 대한 핸들러를 등록하는 등 많은 설정을 처리해 주었는데 위와같이 SimpleUrlhandlerMapping이라는 매핑을 따로 설정해 줌으로써 기본적인 어노테이션 핸들러 매핑도 함께 설정해 주어야한다. 이렇게 해야만 기존에 사용하고 있던 어노테이션 설정을 변함없이 사용할 수 있으므로 꼭 기억해두자.

마지막 설정으로는 자바스크립트와의 실제 데이터를 주고 받을 클래스인 Dwr 객체를 만들어 주고 이 Dwr을 자바스크립트에서 사용할 수 있도록 <dwr:remote>라는 원격 태그를 지정해 준다. 

        <dwr:configuration>
<dwr:convert type="bean" class="kosta.model.Admin"></dwr:convert>
</dwr:configuration>
<bean id="adminDwr" class="kosta.dwr.AdminDwr">
<property name="admindao" ref="adminDao"></property>
<dwr:remote javascript="adminDwr"></dwr:remote>
</bean>

우선 <dwr:configuration>태그를 이용하여 자바객체를 원하는 형태로 변경할 수 있다. 위에서 보면 Admin클래스를 bean객체로 변환하라는 의미이고 dwr에서는 변환된 bean객체를 다시 JSON으로 변환하여 자바스크립트로 보낼 것이다.
<dwr:remote>태그를 보면 javascript속성을 확인 할 수 있는데 이 속성에 adminDwr이란 값을 넣어주었다. 이렇게 함으로써 자바스크립트에서는 adminDwr로 Dwr과 데이터 교환이 가능하다.

<script type="text/javascript" src="/spring_dwr_practice/dwr/engine.js"></script>
<script type="text/javascript" src="/spring_dwr_practice/dwr/interface/adminDwr.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
adminDwr.adminList(show);
function show(data){//결과값이 도착하면 자동으로 호출되는 콜백함수
$.each(data, function(index, member){
var html = "<tr><td>" + member.mem_id + "</td><td>" + member.mem_name + "</td></tr>";
$("table tbody").append(html);
});
}
});
</script>

이제 자바스크립트에서 dwr을 호출할 수 있게 되었다. 먼저 <script>에 xml에서 컨트롤러에게 매핑해 주었던 engine.js와 javascipt에서 지정한 adminDwr라는 이름의 js도 지정해 주도록한다. 이렇게 프로젝트 경로로 매핑을 시킨 것이 SimpleUrlHandlerMapping방식이다.

이렇게 설정이 다 되었으면 이제부터 단순히 자바스크립트 코드에 adminDwr을 이용하여 AdminDwr클래스에 존재하는 메서드나 멤버변수를 호출할 수 있다.

adminDwr.adminList(show) 는 AdminDwr클래스의 adminList함수를 호출하는 것이고 인자로 show라는 함수를 넣어준다는 것을 기억하자. show함수는 콜백함수로써 adminList()메서드의 결과값을 자동적으로 리턴받아 처리할 수 있다. 이때 얻은 결과값은 앞서 언급했던 JSON데이터 포맷을 가지고 있음으로 키와 값으로 데이터를 접근할 수 있다.

2013년 4월 14일 일요일

[Spring] ibatis

앞에서 스프링을 이용하여 좀 더 쉬운 DB연동을 살펴 보았다. 상당히 많은 양의 중복 코드를 줄인 것을 알 수 있다.

그러나 지금 언급하고자 하는 ibatis는 DB와의 연동 시 코드의 양을 더욱 많이 줄여줄 수 있다! 단순히 XML을 사용하여 SQL statement에 매핑이 가능하다. 때문에 JDBC로만 프로그래밍 할때의 번거로움이 상당히 줄어드는 것이다.

그만큼 유용한 프레임워크인 ibatis에 대해 알아보도록하자.

ibatis는 sql 실행 결과를 자바빈즈 혹은 Map객체에 매핑해 주는 솔루션으로 sql을 소스코드가 아닌 XML로 따로 분리해 관리하도록 지원한다. 따라서 복잡한 sql을 작성하기가 수월하고 코드의 분리로 유지보수가 좀 더 간편하다. 왜냐하면 DAO자바 코드에서는 순수하게 자바 코드만을 관리하고 sql문은 따로 XML파일로 관리할 수 있기 때문에 서로의 관계를 느슨하게 만들 수 있기 때문이다.

ibatis를 사용하기 위해서는 ibatis라이브러리를 자신의 웹 어플리케이션 lib폴더에 넣어두는 것을 잊지말자. 그런다음 ibatis 사용을 위한 xml파일을 설정해 주어야한다.

2가지의 XML파일만 설정하면 된다.
첫 번째는 DataBase의 환경을 설정하는 XML이고 두 번째는 사용될 Query를 저장하는 XML파일이다. 우선 Database 환경 설정 XML파일에 <sqlMapConfig>태그를 안에 <transactionManger>태그를 사용하고 속성으로 type을 준다.
예)//////////////////////////////DB설정 XML/////////////////////////////////////////

<sqlMapConfig>

  <transactionManager type="JDBC" commitRequired="false">
    <dataSource type="JNDI">
    <property name="DataSource" value="java:comp/env/jdbc/oracle"/>
    </dataSource>
  </transactionManager>

  <sqlMap resource="kosta/ibatis/Board.xml"/>

</sqlMapConfig>

위 코드는 JDBC타입으로 JNDI네이밍 방식을 사용한다. sqlMapConfig는 ibatis에서 JDBC를 처리하기 위해 필요한 사항을 설정하며 Transaction 관리 정보, DataSource Factory와 sqlMap 파일의 위치를 기술하게 된다.

다음으로는 Query를 지정한 XML파일을 로드해 주어야 하는데 <sqlMap>이라는 태그를 사용하여 루트를 지정해 준다.

예)//////////////////////////////SQL문 설정 XML//////////////////////////////////////

<sqlMap>

<typeAlias alias="Board" type="kosta.model.Board"/>
<typeAlias alias="Search" type="kosta.model.Search"/>

<insert id="insertBoard" parameterClass="Board">
insert into Board values(
board_seq.NEXTVAL,
#title#,
#writer#,
#contents#,
sysdate,
0)
</insert>

<select id="searchBoard" parameterClass="Search" resultClass="Board">
select * from board
<dynamic prepend="where">
<iterate property="areas" conjunction="or" open="(" close=")">
$areas[]$ like #searchKey#
</iterate>
</dynamic>
order by seq desc
</select>

</sqlMap>

위의 sql문을 설정한 XML파일의 내용이다. DTO에 쿼리 결과를 담기 위해서는 위에 보이는 것과 같이 해당 클래스의 <typeAlias>를 지정해야한다. 그런다음 SQL문 태그들을 이용하여 데이터베이스의 데이터들을 관리할 수 있게 된다.

sql문을 사용하기 위한 태그를 살펴보면 태그의 속성에 id와 parameterClass, resultClass가 존재한다는 것을 알 수 있다. id는 Dao에서 호출할 sql문의 이름이다. parameterClass는 입력될 객체를 의미한다. ibatis에는 객체나 프리미티브 타입, 해쉬맵 등의 데이터를 인자값으로 넘겨 줄 수 있다. resultClass는 query의 결과를 담을 데이터를 말하며 resultClass일 경우 객체로 결과를 담는다는 것이다. resultMap을 이용하여 객체를 받을 수 있는데 특히 데이터베이스의 컬럼명과 클래스의 멤버변수명이 다를 때 그 이름을 새롭게 패핑하여 결과값을 얻을 때 사용한다.

위의 이러한 과정을 그림으로 나타내면 다음과 같다.




요약하자면 SqlMapConfig설정파일을 통해 데이터베이스의 Resource를 구하고 사용할 sql문과 sql문의 입력된 데이터와 출력데이터간의 매핑을 처리해주도록 설정한 SqlMap파일을 로드하도록 한다.

그런다음 설정한 SqlMap을 사용하기 위해 SqlMapClient interface를 얻도록 해야한다. 그 코드는 아래와 같다.







Reader reader = Resources.getResourceAsReader("로드할 SqlMapConfig파일 위치");
sqlMapper = SqlMapClientBuilder.buildSqlMapClient(reader);

동적쿼리문
디비를 활용하다보면 로직에 따라 sql문이 수시로 변경되어야할 경우가 많다. ibatis에서는 로직에 따른 동적쿼리문에 대한 태그를 제공한다.

<dynamic>태그
가장 상위의 태그이고 접두/접미 구문을 위한 수단을 제공한다.
- prepend : 맨 앞에 접두 구문을 붙인다.
- open : body의 내용 앞에 붙여짐. body의 내용이 없을 경우 생략. prepend와 동시에 정의될 경우 prepend 다음에 나타남.
- close : body의 내용 뒤에 붙여짐. body의 내용이 없을 경우 생략.

비교태그
주어진 parameter 객체간의 property값을 비교한다.
- property(필수) : parameter 객체의 property, compareValue 또는 compareProperty를 이용해 데이터 비교
- prepend(옵션) : 접두 구문 추가. 다만 생략되는 경우가 있다. 1. body의 내용이 없는 경우 2. 부모 태그의 속성이 removeFirstPrepend = "true"이고 현재 부모 태그가 부모 body의 첫 번째 요소인 경우
- open(옵션) : <dynamic>태그와 동일
- close(옵션) : <dynamic>태그와 동일
- removeFirstPrepend(옵션) : 첫 번째 자식 태그의 prepend를 생략시킴
- compareProperty : property와 비교할 property
- compareValue : property속성에 의해 비교되는 값(상수)
- <isEqual> : property속성과 compareProperty / compareValue속성이 같은지 비교
- <isNotEqal> : 다른지 비교
- <isGreaterThan> : 큰지 비교
- <isGreaterEqual> : 크거나 같은지 비교
- <isLessThan> : 작은지 비교
- <isLessEqual> : 작거나 같은지 비교

단항태그
주어진 특정 property에 대한 태그
- <isPropertyAvailable> : 특정 property가 존재하는지 체크(Map의 경우 key가 존재하는지 체크)
- <isNotPropertyAvailable> : 특정 property가 존재하지 않는지 체크
- <isNull> 특정 property가 null인지 체크
- <isNotNull> 특정 property가 null이 아닌지 체크
- <isEmpty> 특정 property가 null이거나 비어있는지 체크
- <isNotEmpty> 특정 property가 null이 아니고 비어있는지 체크

Parameter 태그
- <isParameterPresent> : 파라미터가 존재하는지 체크
- <isNotParameterPresent> : 파라미터가 존재하지 않는지 체크

interate태그
Collection 형태의 property로써 sql문의 반복적인 구간 생성
- conjunction : 반복되는 sql문 사이에 구분자로 들어감 (예: ',' or, and 등등)


[Spring] validator

프로그램을 제작하다보면 유효성검사를 할 경우가 굉장히 많다. 특히 웹 어플리케이션에서 사용자의 입력을 받는 경우에 유효성검사를 많이 필요로한다.

생각해보자. 항상 사용자가 개발자가 원하는 데이터값을 입력할까????? 그건 전혀 예측할 수 없는 일이다. 개발자가 무엇을 생각하고 무엇을 요구하는지 사용자는 알고 싶어하지 않는다. 이럴경우 유효성검사가 참 유용하다. 그리고 웹에서 국제화를 위해서도 사용된다. 영어, 일어, 중국어 등 다양한 언어로 서비스를 제공하고 싶다면 유효성 검사방법을 잘 알아두도록 하자.

스프링에는 유효성 검사를 위한 기능을 제공하고 있다. 우선 validator 인터페이스를 implements 한 자바 클래스가 필요하다. 이 클래스를 활용하여 form에서 넘어온 데이터의 유효성을 검사할 것이다. 코드는 다음과 같다.
예)
public class BoardValidator implements Validator {

@Override
public boolean supports(Class<?> arg0) {
// TODO Auto-generated method stub
if(Board.class.isAssignableFrom(arg0)){
return true;
}
return false;
}

@Override
public void validate(Object arg0, Errors errors) {
// TODO Auto-generated method stub
Board board = (Board)arg0;

if(board.getTitle() == null || board.getTitle().length() < 6){
errors.rejectValue("title", "required");
}
if(board.getWriter() == null || board.getWriter().length() < 6){
errors.rejectValue("writer", "required");
}
}
}


 우선 폼으로부터 넘어온 객체가 맞는지 확인한다. 여기서 ture를 반환하면 아래 validate함수를 수행하여 휴효성을 검사하게 된다. 여기서 만약 에러를 반환한다면 미리 지정해둔 메세지를 가지고 폼으로 돌아가도록 설정할 것이다. 일단 메세지 등록에 대해 살펴보자.
예)
required.title = bad title
required.writer = bad writer


properties파일에 등록한 간단한 메세지이다. 이 메세지를 얻기 위해 앞서 설명한 코드에서 rejectValue()의 인자로 해당하는 메세지의 문자열을 넘겨준 것이다.

여기까지는 단순한 로직처리일 뿐이다. 스프링에서 이 로직들을 처리하기 위해서는 항상 DispatcherServlet에 bean으로 객체를 등록해 주어야한다는 것을 잊지말자.
예)
<!-- VALIDATOR -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="message.validation"></property>
</bean>

<bean id="boardValidator" class="kosta.validator.BoardValidator"></bean>


ResourceBundleMessageSource클래스의 객체를 이용해 메세지를 읽도록 하고 유효성검사를 하는 validator도 객체로 만들어 둔다. 이 객체를 사용할 DispatcherServlet에다가 넣어주고 있다.

마지막으로 에러가 발생했을 때 해당하는 메세지를 가지고 화면에 뿌려주도록하기 위해서 spring에서 제공하는 태그를 이용한다.
예)
<spring:hasBindErrors name="commend"></spring:hasBindErrors>
<center>
<h1>글쓰기폼</h1>
<form action="board_insert.do" method="post">
작성자:<input type="text" name="writer"/><form:errors path="commend.writer"></form:errors><br>
&nbsp;제목:&nbsp;&nbsp;<input type="text" name="title"/><form:errors path="commend.title"></form:errors><br>
내용<br><textarea name="contents" rows="6" cols="30"></textarea><br>
<input type="submit" value="등록"/><br>
</form>
</center>


2013년 4월 11일 목요일

[Sping] Spring DB연동

스프링에는 데이터를 얻거나 객체와의 연동을 할 때 꼭 한가지 방법만 존재하는 것은 아니다. DB와의 연동도 마찬가지도 여기서는 jndi네이밍방식으로 DataSource를 구한다음 JdbcTemplet을 객체를 이용하여 DB를 연동해보도록 하겠다.


DataSource를 가져오기위해 우선 server에서 server.xml 설정파일에 DB를 연동하고자 하는 어플리케이션 context에 다음과 같은 코드를 넣어주어야한다.

<Resource auth="Container" driverClassName="oracle.jdbc.driver.OracleDriver" maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/oracle" password="1234" type="javax.sql.DataSource" url="jdbc:oracle:thin:@localhost:1521:XE" username="board"/>


<!-- DB Setting -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/oracle"></property>
<property name="resourceRef" value="true"></property>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>

위에보면 빈 객체가 두개 있는 것을 알 수 있는데 처음에 필요한 객체는 dataSource객체이다. JndiObjectFactoryBean클래스로 만들어진 객체로써 속성으로 jndiName과 resourceRef가 있는데 jndiName에는 자신이 사용하고 있는 데이터베이스의 이름이고 resourceRef는 true로 값을 지정해주어야한다.

이렇게 하여 JdbcTemplate 객체를 얻을 수 있는데 이 객체를 이용하여 DB에 SQL문을 실행할 수 있게 된다. 그러므로 당연히 DB와의 연동이 필요한 Dao클래스에 JdbcTemplate 객체를 bean을 통해 의존 관계를 설정해 주어야겠다.

그리고 마지막으로 Dao를 직접적으로 호출할 Controller에도 dao 객체를 넣어주는 것을 잊지말자!


2013년 4월 10일 수요일

[Spring] MVC 흐름

이번에는 스프링을 이용하여 모델 2방식인 MVC의 흐름을 알아보도록 하자.

위의 그림은 MVC의 흐름을 한눈에 살펴볼 수 있도록 되어있다.

순서대로 하나씩 따라가보자.
1. Client의 요청은 항상 DispatcherServlet으로 전달되며 MVC에 있어서 컨트롤타워라고 생각하면 된다. DispatcherServlet이 MVC의 흐름을 총괄하며 다른 컴포넌트에게 해야할 일을 위임한다.
2. 1번으로부터 받은 Client의 요청에 대해 DispatcherServlet은 HandlerMapping을 통해 어떠한 Controller에게 비즈니스로직을 처리해야하는지 문의하게 된다.
3. HandlerMapping을 통해 해당하는 로직을 처리할 Controller에게 요청을 전송하고 Controller는 요청을 처리한다.
4. Controller에 의해 처리된 그 결과를 ModelAndView객체에 실어 응답한다.
5. ViewResolver에 의해 어떠한 뷰를 보여줄 것인지 결정한다.
6. 해당하는 결과를 화면에 표현한다.

위와 같은 일련의 과정을 잘 이해하도록하자!!! 이러한 흐름을 잘 이해하면서 실제로 MVC패턴을 이용한 어플리케이션을 만들어보자.
1. 가장 먼저 web.xml 설정 파일에 웹 어플리케이션에서 사용한 DispatcherServlet을 등록해야한다. 그리고 만약 DispatcherServlet 설정파일이 springapp-servlet.xml이라면 파일이름 중 앞단어를 이용하여 등록시켜야 한다.
예)
<servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
</servlet>

이어서 어떤 요청에 대해 DispatcherServlet이 처리할 것인가를 명시해 줄 필요가 있다. 따라서 매핑의 과정이 추가된다.
<servlet-mapping>
    <servlet-name>springapp</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

이렇게 함으로써 .do라는 요청들은 모두 DispatcherServlet이 처리할 것이라는 설정이 완료된다.
2. DispatcherServlet 클래스를 만들어 어노테이션 방식으로 @Controller를 등록하고 WebApplicationContext 설정파일을 이용하여 필요한 객체를 DI기법으로 얻는다.
3. DispatcherServlet 클래스에 어노테이션 방식을 이용하여 @RequestMapping로 요청에 대한 Controller(메소드)를 구현하고 매핑한다. (지금은 디폴트 어노테이션 핸들러 매핑 방식을 사용하겠지만 스프링에는 더 다양한 방법이 여러개 존재한다는 것을 알아두자)
4. Controller를 통해 처리된 데이터는 ModelAndView 객체에 담고 ViewResolver를 통해 뷰를 선택한다.
5. 결과를 출력한다.

만약 여러개의 DispatcherServlet을 설정해야 한다.면 ContextLoaderListener로 설정한다.

2013년 4월 8일 월요일

[Spring] AOP(Aspect Oriented Programming)

로직 중에는 핵심적으로 수행되는 로직과 공통으로 수행되는 로직이 존재한다. 특히 공통적으로 사용되는 기능은 로깅, 트랜잭션, 보안 등이 존재한다.

공통적으로 수행되는 로직은 아무리 단순할지라도 많은 곳에서 사용되어지면 그만큼 중복된 코드가 많아지게되고 관계가 복잡해 진다. 이러한 현상을 극복하기 위해 AOP가 등장하였다.

AOP를 가장 잘 설명해 주는 그림이다. CourseService, StudentService 그리고 MiscService가 핵심 관심 사항이고 항상 보안, 트랜잭션 등의 공통 관심 사항에 필요한 로직을 셋 다 수행하도록 되어있다.
만약 핵심 관심 사항이 늘어나거나 공통 관심 사항이 늘어날 경우에 굉장히 불필요하고 번거로운 작업이 많이 생기게 된다. 예를 들어 각각의 핵심 관심 사항에 일일이 공통 관심 사항을 설정한다는 것은 엄청난 시간과 에너지 소비일 것이다.

그러나 AOP에서는 핵심 로직을 구현한 클래스를 실행하기 전, 후에 공통 로직을 여러클래스에 미리 적용시켜 놓음으로써 번거로운 작업을 줄일 수 있다.

우선 공통 관심 사항을 구현해보자.
예)

public class LoggingAspect {
private Log log = LogFactory.getLog(getClass());

public Object logging(ProceedingJoinPoint jointPoint) throws Throwable{
log.info("기록시작");//proceed 이전에 실행
StopWatch stopWatch = new StopWatch();
try{
stopWatch.start();
Object obj = jointPoint.proceed();//실제 비지니스 메서드 호출 시점
return obj;
}catch(Throwable e){
throw e;
}finally{
stopWatch.stop();//proceed 이후에 실행
log.info("기록 종료");
log.info(jointPoint.getSignature().getName() + "메서드 실행 시간 : " + stopWatch.getTotalTimeMillis());

}
}
}
위와 같은 코드로 원하는 모든 핵심 로직에 기록을 시작하고 종료할 수 있다. jointPoint.proceed()는 핵심 로직이 수행되는 시점이다.

위에 구현한 클래스를 적용시키기 위해 XML파일 설정이 필요하다.

예) AOP설정 파일(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"
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">

<bean id="logAspect" class="kosta.LoggingAspect"></bean>

<aop:config>
<aop:pointcut expression="execution(public * kosta..*ServiceImple.*(..))"
id="servicePointcut" />
<aop:aspect id="loggingAspect" ref="logAspect">
<aop:around method="logging" pointcut-ref="servicePointcut" />
</aop:aspect>
</aop:config>

</beans>
이미 구현한 로깅 공통 관심 사항 객체를 설정한다.
aop태그를 통해 로깅의 대상이 될 메소드의 범주를 설정하고 로깅 객체를 참조한다. 그리고 대상 메소드가 호출될 때 로깅 메소드가 호출될 시점을 설정한다.

코드만으로 이해하기 어려울 수 있으니 AOP용어에 대해 살펴보자.
Aspect : 공통 관심 사항(예 : 트랜잭션, 로깅, 보안 등)
JoinPoint : Aspect가 적용 될 수 있는 지점(예: 메소드, 필드)
Poincut : 공통 관심 사항이 적용될 JoinPoint
Advice : 어느 시점에 어떤 공통 관심 기능을 적용할지 정의
Weaving : 어떤 Advice를 어떤 Pointcut에 적용시킬 것인지에 대한 설정



[Spring] DI(Dependency Injection)

DI는 스프링 컨테이너가 지원하는 핵심 개념 중 하나이다. 객체 간의 의존 관계를 객체 자신이 아닌 외부의 조립기가 수행해 준다는 개념이다.

예를 들면 A라는 클래스에서 B라는 클래스의 객체가 필요한 경우 보통은 A클래스 안에서 B라는 객체를 new키워드로 생성하거나 singleton방식으로 객체를 얻는 방식을 많이 사용한다.

하지만 문제점은 이들 A와 B의 결합도가 높아진다는 것이다. 이로 인해 의존하는 클래스 B가 변경되는 경우 A의 코드를 변경해야 하는 문제가 있다. 이처럼 하나의 변경으로 인해 의존하는 다른 부분들의 수정이 불가피한 경우가 많을 수록 서로의 의존도, 즉 결합도가 높다는 것이다.

new키워드의 문제점이 의존 클래스가 변경되면 코드를 변경하는 것이고 또한 단위 테스트를 하기 위해서는 실행에 필요한 올바른 객체가 존재해야한다. (단위 테스트는 코드의 품질을 향상시키고 개발 속도를 증가시키는데 필요하다.)
singleton방식에서는 의존 클래스의 변경에 의한 문제점은 해결할 수 있지만 new키워드와 같이 올바르게 동작하는 객체가 있어야만 단위 테스트가 가능하다는 문제가 존재한다.

이러한 문제점들을 해결하기 위해 DI개념을 사용하는 것이다.

객체간의 의존관계를 객체가 아니라 외부의 조립기가 수행하는 것을 의미한다. 이 의존관계는 클래스의 변경으로 인한 수정이 필요하지 않고 구현 클래스에 대한 차이를 모르는 채 서로 다른 구현으로 대체가 가능하다는 점에서 모든 문제를 해결할 수 있다.

스프링 DI
스프링은 설정 파일과 어노테이션을 이용하여 객체 간의 의존 관계를 설정하는 기능을 제공하여 객체 조립기를 사용할 수 있다.

예) 스프링 설정 파일(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-2.5.xsd">

<bean id="dao" class="kosta.MySQLDao"></bean>

<bean id="service" class="kosta.WriteServiceImple">
<constructor-arg ref="dao"/>
</bean>
</beans>

스프링 설정 파일은 Application에서 사용할 Spring 자원들을 설정하는 파일이며 XML기반이다.

위에 코드는 bean태그를 이용하여 객체를 설정해주고 있다. 특히 constructor-arg 태그를 이용하여 생성자에 이미 설정해둔 dao객체를 전달해 줌으로써 의존 관계를 설정하고 있다.

<bean>태그 기본속성
name - 호출할 이름 설정
id - 호출할 이름 설정
class - 생성될 객체의 클래스
factory-method : singleton패턴으로 작성된 객체의 factory메소드 호출 시

이렇게 설정파일을 작성한 뒤 스프링을 이용하여 설정 파일을 로딩하고 객체를 얻는다.

예) 스프링 설정 파일을 로드하고 BeanFactory를 생성한 뒤, 필요한 객체를 가져오는 코드-------

public class Main {
public static void main(String[] args){
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
Service service = (Service)factory.getBean("service");
service.insert();
}
}
factory.getBean("id")로 설정 파일에서 이미 설정해둔 빈 객체들을 가져올 수 있다. 이러한 방법을 통해 느슨한 의존 관계를 설정하게 되고 이는 코드의 변경이나 테스트의 어려움을 줄이는데 유용한 개념이다.

[Spring] 스프링 프레임 워크

2주간 프로젝트를 마치고 이어서 스프링 프레임 워크에 대해 알아보자. 처음 공부하기는 상당히 어려운 부분이 많고 특히 혼자서 이해하기가 난해한 부분이 없지 않다. 그렇지만 스프링의 핵심기술 DI, AOP, MVC를 꼭 이해하도록 하자. 이를위해 우선 스프링에 대해 전반적으로 살펴보도록 하겠다. 그리고 조금씩 심화시켜나가면서 스프링에 대해 알아갈 것이다.

기존에는 JSP를 활용한 모델 1방식으로 프로젝트를 진행해보았다. 모델 1방식은 JSP와 Java Bean을 이용하여 웹 어플리케이션을 개발하는 방법을 말한다.
모델 1방식으로 개발하면 배우기가 쉬워 누구가 쉽게 만들 수 있고 때문에 개발 속도가 향상되는 장점이 있지만 큰 문제점은 JSP에서 너무 많은 코드들이 혼재되어 있고 따라서 JSP가 처리해야하는 일이 많아진다. 따라서 개발자는 유지보수의 어려움을 겪게되는 문제가 있다.

한번 만들어진 프로젝트는 오랜시간동안 서비스를 하기위해 유지보수가 필수이다. 이 유지보수를 어렵게 만든다는 점에서 개발을 위한 새로운 방법이 필요했다.

이러한 문제점 때문에 웹 어플리케이션이 복잡해지고 사용자 요구가 증가함에 따라 새로운 개발방식을 요구하게 되는데 그것이 현재 모델 2방식이다.


모델 2방식
어플리케이션을 Model - View - Controller로 분리하여 개발하는 방식을 말한다.
Model : 비즈니스 로직을 담당하며 Java Bean과의 연동을 통해 로직을 처리한다.
View : JSP로 Client에게 응답을 처리한다. 즉, 모델 1방식에서 가장 많은 역할을 해야했던 JSP는 오로지 요청에 대한 응답 페이지의 출력을 목적으로만 사용한다.
Controller : 서블릿을 이용하여 클라이언트의 요청을 받아 Model과 View사이에서 일의 흐름을 조정한다.

모델 2방식에서는 컨트롤러의 역할이 중요하다. 때문에 컨트롤러의 역할을 살펴보자면
1. 클라이언트의 요청을 받아 클라이언트가 보낸 데이터를 읽고 검사한다.
2. 모델에게 비즈니즈 로직을 처리해달라고 요청한다.
3. 모델의 처리 결과에 맞는 뷰에게 응답을 요청한다.

그렇다면 모델 2방식의 장단점에 대해 알아보자.
장점 : 비즈니스 로직과 프레젠테이션의 분리로 인해 어플리케이션이 명료해지며 유지보수와 확장이 용이하다. 따라서 디자이너와 개발자의 작업을 분리해 줄 수 있다.
단점 : 개발을 위한 설계로 인해 개발 기간이 늘어나고 MVC 구조에 대한 이해가 동반된다.

자 이제 왜 모델 2방식을 이용한 웹 어플리케이션이 필요한지 어느정도 감이 올 것이다. 스프링은 모델 2방식인 MVC구조에 대한 프레임워크를 제공하고 있으며 나아가 다양한 프레임워크와 연동을 지원하기 때문에 많은 개발자들이 배우고 있는 프레임워크이다.

그렇다면 프레임워크는 무엇이며 라이브러리와는 어떤 차이가 있을까?

라이브러리는 개발자가 원하는 목적을 위해 사용되는 API들의 묶음으로 개발자가 자신에게 필요한 것을 스스로 설정하면서 프로그램을 구현해나갈 수 있는 유용한 자료이다. 프레임 워크는 개발에 있어서 어느정도의 틀을 미리 제공하고 있다. 따라서 개발자가 처음부터 모든 것을 구현할 필요가 없다. 어느정도의 프로세스가 이미 정해져있다는 것이다.

개발자에게 있어서 프레임워크는 어떤 존재인지 생각해보자. 지금처럼 대규모의 프로젝트가 산적해있는 상황에서는 개발의 속도가 필요하다. 그렇기 때문에 하나하나씩 모든 것을 구현해 나가며 단독으로 프로젝트를 진행하는 것은 의미가 없다. 빠르게 많은 코드를 제작해 나가야 함에 있어서 프레임워크가 필수적이고 개발자마다 다른 코드 스타일을 적응해가면서 개발하는 것도 쉽지 않다. 하지만 이렇게 정해진 틀이 제공된다면 대규모 프로젝트를 진행하는데 도움이 될 것이라는 것은 당연하다.

현재 웹 어플리케이션 제작에 있어서 가장 많이 사용되는 프레임워크가 스프링이다.

스프링이란 오픈 소스 프레임워크로써 엔터프라이즈 어플리케이션 개발의 복잡성을 줄여주고 필요한 기능을 제공하기 위한 목적으로 만들어졌다. 특히 과거에 많이 사용되던 EJB의 복잡성과 느린 속도를 대처하기 위해 등장하였다.

스프링 장점
- 경향 컨테이너로써 객체의 라이프 사이클을 관리, JEE구현을 위한 다양한 API제공
- DI 지원, 설정 파일이나 어노테이션을 통해서 객체 간의 의존 관계를 설정
- AOP지원, 트랜잭션이나 로깅, 보안과 같은 공통으로 필요한 기능들을 분리해서 원하는 모듈에 적용
- POJO지원, 특정한 인터페이스를 구현하거나 클래스를 상속받지 않아 기존에 작성한 코드를 그대로 사용
- JDBC를 위한 다양한 API지원
- Transaction 처리를 위한 일관된 방법제공
- 다양한 API와의 연동 지원

장점을 보면 DI나 AOP 등등 처음 보는 개념을 많을텐데 하나씩 알아가도록하자. 개발자를 위해서 제공되는 아주 좋은 기술이다!