2013년 6월 20일 목요일

Software caused connection abort: recv failed 오류에 대한 고찰


디비 이전 관련해서 발생한 이슈에 대한 해결 방안


원인을 파악하기 위해 조사를 하다가 발견한 사항입니다.

특정 DB 오라클 뿐만이 아니라 대부분의 DBMS의 경우 DB측에서 클라이언트로부터 정기적인 요청이 없는 경우(장시간 요청이 없는 경우)
클라이언트로부터 요청 받았던 DB connection closed한다고 합니다.
java.net.SocketException: Software caused connection abort: recv failed
java.net.SocketException: Connection reset by peer: socket write error
위의 오류의 경우 클라이언트가 DBMS에서 접근하면서 오류가 발생한 것인데 클라이언트가 DBMS와 맺었던 connection을 찾지 못해 발생한 것으로 판단됩니다.

원인 조사와 동시에 해결책에 대하여 찾아보았고
본 시스템의 경우에는 아파치 common 라이브러리 중 org.apache.commons.dbcp.BasicDataSource 라이브러리를 사용 중입니다.
위의 원인으로 발생하는 것이 정확하다면 클라이언트에서 DBMS로 커넥션을 연결 맺고 시간이 지난 후 데이터를 요청하려 할 때 맺었던 connection에 대한
Check를 하는 방법이 있을까? 하는 의문이 들어 해당 라이브러리에 대하여 조사를 진행하였습니다.

관련 라이브러리 옵션 중에 validationQuery 속성이 제가 원하는 기능을 할 수 있을 것이라 판단되어
WAS config에 설정을 하고 테스트를 하였습니다.

테스트는 운영서버 1대를 빼서 validationQuery 속성을 추가하지 않은 상태로 두고 저희 로컬PC에는 validationQuery 속성을 추가하고
동일한 페이지를 일정 시간을 두고 접속을 해보는 것으로 진행하였습니다.

그 결과 운영서버 쪽은 오류가 발생하였지만 로컬PC 쪽에서는 정상적으로 접속되는 것을 확인하였습니다.

validationQuery 속성이 하는 일은 기존 맺었던 connection에 대하여 유효성을 판단하는 기능인데 단순히 “select 1 from dual” 쿼리를 이용하여 확인을 합니다 ^^
클라이언트에서 서비스 쿼리를 DBMS에 날리기 전에 먼저 실행하는 것이고 오류가 발생할 경우 다시 connection을 맺는 것으로 판단됩니다.

추가적으로 재미있는 것은 만일 위와 같은 사항이 상용에서는 일어날까?
제 판단으로는 상용에서는 일어나지 않을 것 같습니다. 이유는 본 서비스는 장시간 DBMS에 데이터를 요청하지 않는 경우가 없기 때문입니다.
하지만 돌다리도 두르려 본다는 심정으로 DB connection 관련 속성 중에 validationQuery와 같은 옵션을 통해 보다 안정적인 DB Connection을 보장해 줄 수 있지 않을까 생각합니다.

Oracle에서의 Software caused connection abort: recv failed 오류가 발생했을 때

오라클 서버 이전을 하게 되었다.
물리적 장비를 사용하다가 이번에 가상화 장비로 이전을 하게 되었고 데이터를 이전 한 후
기존 웹 서비스에 물려 테스트를 하게 되었다.

헌데 그전에는 발견하지 못했던 오류가 발생했다.

Software caused connection abort: recv failed

위의 오류는 웹 서버를 구동한 후 서비스가 활성화 되고 서비스에서 디비 서버 측에 데이터 요청을 하지 않으면 디비 서버에서 커넥션을 close해서 발생하는 문제 였다.

내가 관리하는 웹 서비스는 spring3 framework를 사용하고 있다.
디비에 접속하는 DataSource는 org.apache.commons.dbcp.BasicDataSource를 사용 중이다.

org.apache.commons.dbcp.BasicDataSource 라이브러리에서 위의 오류를 발생하지 않도록 하는 방법이 있을 것 같아 찾아 보았다.

오라클의 경우에는 BasicDataSource 내에 validationQuery 속성이 있고
이 속성은 DB를 연결하기 전에 해당 Connection이 정상적인지 유효성 판단을 한다.

사용 방법은 아래와 같다

<bean id="transactionCPSDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>${txcps.jdbc.driver}</value></property>
        <property name="url"><value>${txcps.jdbc.url}</value></property>
        <property name="username"><value>${txcps.jdbc.username}</value></property>
        <property name="password"><value>${txcps.jdbc.password}</value></property>
        <property name="defaultAutoCommit"><value>${txcps.jdbc.commit}</value></property>
        <property name="maxActive"><value>${txcps.jdbc.active}</value></property>
        <property name="maxIdle"><value>${txcps.jdbc.idle}</value></property>
        <property name="validationQuery" value="select 1 from dual"></property>
    </bean>

위의 붉은 색 글씨 부분 처럼 넣어주면 된다.

끝!! 머리 아팠는데 우하하

2013년 4월 21일 일요일

Oracle에서 like와 substr 중 어느 것이 빠를까?

업무 중에 메뉴코드를 만들며 설계를 하다가 메뉴코드 조합 상 어쩔 수 없이

LIKE 나 Substr을 사용하게 되었다.

비슷한 기능을 하는 것으로 알고 있는 위의 방식 중 어느 것이 더 빠를까?

여기저기 찾아본 결과 LIKE가 빠르다고 한다.

물론 LIKE 'searce%' 이 형식이 빠르다는 것이다.

근데!! 여기서 Substr로 빠르게 할 수 있는 방법은 없을까? 고민하다가 이런 생각을 했다

ORACLE의 FBI를 사용하면?

그렇다! FBI(Founction Based Index)를 이용하면 속도(Cost)가 빨라진 다는 것을 찾았다!

그럼 어떻게 쓰는 걸까?


CREATE INDEX jini_substr_idx
    ON JINI_TABLE( substr( field,1,6 ) );


위와 같이 인덱스를 생성하면 되고 아래와 같이 사용하면 된다.


SELECT ... FROM ... WHERE substr(field,1,6) = 'search';


끝!

2013년 4월 4일 목요일

Spring3를 이용하여 RESTFul web service 생성하기 - XML, ATOM

Restful 웹 서비스 Build

이전 시간에는 JSON 타입으로  변환하는 것을 공부했다.
이번 시간은 XML과 ATOM 타입으로 변환하는 것을 공부하려고 한다.

XML

Spring3의 내장 변환기인 MarshallingHttpMessageConverter는 Object와 XML 사이에 매핑하는데 사용한다.

==> MarshallingHttpMessageConverter 구성

--------------------------------------------------<bean id="marshallingConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
    <constructor-arg ref="jaxbMarshaller" />
    <property name="supportedMediaTypes" value="application/xml"/>
</bean>

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
         <list>
              <value>jini.web.study.bean.User</value>
              <value>jini.web.study.bean.UserList</value>
         </list>
    </property>
</bean>
--------------------------------------------------

앞서 공부한 소스 내용 중 @RequestBody Annotation 속성에서 headers="Accept=application/json, application/xml 을 추가만 하면된다.

ATOM Feed

==> AtomFeedHttpMessageConverter 구성

--------------------------------------------------
<bean id="atomConverter" class="org.springframework.http.converter.feed.AtomFeedHttpMessageConverter">
    <property name="supportedMediaTypes" value="application/atom+xml" />
</bean>
--------------------------------------------------


==> TestController에서 정의된  ATOM Feed 요청 처리

--------------------------------------------------
@RequestMapping(method=RequestMethod.GET, value="/users"headers="Accept=application/atom+xml")

public @ResponseBody Feed getUsersFeed() {    
    List<User> users = userDao.getAll();   
    return AtomUtil.employeeFeed(users, jaxb2Mashaller);



public static Feed userFeed(
List<User> users, Jaxb2Marshaller marshaller) {

    Feed feed = new Feed();

    feed.setFeedType("atom_1.0");

    feed.setTitle("Employee Atom Feed");

                       

    List<Entry> entries = new ArrayList<Entry>();
    for(User e : users) {
        StreamResult result = new StreamResult(new ByteArrayOutputStream());
        marshaller.marshal(e, result);
        String xml = result.getOutputStream().toString();
                                    
        Entry entry = new Entry();
        entry.setId(Long.valueOf(e.getId()).toString());
        entry.setTitle(e.getName());
        Content content = new Content();
        content.setType(Content.XML);
        content.setValue(xml);
           
        List<Content> contents = new ArrayList<Content>();
        contents.add(content);
        entry.setContents(contents);
        entries.add(entry);
    }

    feed.setEntries(entries);
    return feed;
}
--------------------------------------------------
  • getUserFeed() method는 앞선 JSON 코드에서의 getAllUsers()와 동일한 URI로 매핑되지만, header에서 Accept 항목이 다르다.
  • userFeed() method를 통해 User Object를 XML로 변환하고 이를 Feed 항목의 content 요소로 추가하는 것을 볼 수 있다.
끝!!


2013년 4월 3일 수요일

Spring3를 이용하여 RESTFul web service 생성하기 - JSON

Restful 웹 서비스 Build

오늘은 Android App을 개발하기 위해서 Application이 아닌 Server에 대한 학습을 했다.
수많은 Application 중에 단독으로 수행하는 App들도 있지만 대부분은 Server와 통신을 통해 데이터를 주고 받아 서비스하는 것이 많다.

Spring3에서 Restful 웹 서비스를 구현하기 위해서는 HttpMessageConverter를 구성해야 한다. HttpMessageConverter 인스턴스를 사용자가 정의하여 오브젝트를 서로 다른 매체로 변환하여 사용할 수 있다. 매체 유형으로는 JSON, ATOM 그리고 XML이 있다.

첫 번째 시간에는 JSON으로 변환하는 것을 공부하려고 한다.

JSON

아래는 간단한 예제다. JSON은 작은 데이터를 Server와 Client 간에 주고 받기에 쉽다. 여기에서 Client는 Application이다.

==> spring-servlet.xml에서 HttpMessageConverter 구성
--------------------------------------------------------------------
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
   <property name="messageConverters">
       <list>
           <ref bean="jsonConverter" />
           <ref bean="marshallingConverter" />
           <ref bean="atomConverter" />
       </list>
   </property>
</bean>

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="supportedMediaTypes" value="application/json" />
</bean>
--------------------------------------------------------------------

위의 내용에서 MappingJacksonHttpMessageConverter는 오브젝트를 JSON으로 변환하고 JSON 유형을 그 반대로 변환하는 경우에 사용된다

==> TestController에서 정의된 JSON 요청 처리
--------------------------------------------------------------------
@RequestMapping(method=RequestMethod.GET, value="/user/{id}", headers="Accept=application/json")
public @ResponseBody User getUser(@PathVariable String id) {
    User user = userDao.get(Long.parseLong(id));
    return user;
}
           
@RequestMapping(method=RequestMethod.GET, value="/users", headers="Accept=application/json")
public @ResponseBody UserList getAllUsers() {
     List<User> users = userDao.getAll();
     UserList userList = new UserList(users)
     return userList;
}
--------------------------------------------------------------------

@ResponseBody Annotation은 리턴 Object(User 또는 UserList)를 응답하여 정보를 전달하는 데 사용되고, 이것은 MappingJacksonHttpMessageConverter를 통해 JSON으로 맵핑된다.

HttpMessageConverter와 @ResponseBody Annotation을 사용하여 Spring의 View 방식을 사용하지 않고 여러 유형의 데이터를 생성하거나 전달할 수 있다.








Eclipse에서 Android Project를 만들어보자!!!

이번엔 이클립스에서 안드로이드 Project를 어떻게 생성하는지 공부하려고 한다.
이전 블로그 글에 환경 셋팅을 위해 안드로이드 개발자 페이지에서 SDK를 다운 받으면 패키지로 이클립스도 함께 다운로드를 받을 수 있다.
다운 받은 이클립스를 기반으로 안드로이드 Project를 만들어보려고 한다.

첫번째툴바 메뉴에서 클릭을 한다.

두번째. 툴바 메뉴를 클릭하면 다음과 같은 화면이 나타난다.
개발을 하고자 하는 안드로이드 프로젝트 유형을 선택하여 Next 한다.
여기서는 Android Application Project 유형을 선택하여 진행한다.















세번째. 위 화면에서 Next를 클릭하면 다음과 같은 화면이 나타난다.
새로운 안드로이드 Application에 대하여 Application Name, Project Name, Package Name을 입력한다. Application Name에 jini First App으로 입력을 하면 자동 완성으로 통해 Project Namer과 Package Name이 만들어진다. 아래 표기되는 Minimum Required SDK와 Target SDK, Compile With, Theme는 Application을 테스트하는 Device에 따라서 적당하게 선택하면 된다.
디폴트의 경우는 현재 release 된 최상위 버전 형태로 셋팅된다.
Next를 버튼을 눌러 다음으로 진행한다.




네번째. 기본으로 Launcher Icon을 생성할 것인지, activity를 생성할 것인지, 임의로 선택한 workspace에 프로젝트를 생성할 것인지에 대한 확인을 하는 화면이 나타난다. 기본 선택된 항목을 확인하고 Next 버튼을 눌러 다음으로 진행한다.

다섯번째. Launcher Icon에 대한 구성을 셋팅하는 화면이 나타난다. 일단 Next 버튼을 눌러 다음로 진행한다.

여섯번째. Activity를 생성하는 화면이 나타난다. 이 부분은 초기 Application의 UI layout을 어떻게 셋팅할지에 대해서 선택하는 부분이다.
Blank Activity, Full Screen Activity, Master/Detail Flow를 선택할 수 있고 그에 맞는 Template이 생성된다. 여기서는 기본으로 Blank Activity를 선택하여 진행한다.

일곱번째. Blank Activity를 선택하고 Next 버튼을 누르면 Activity Name, Layout Name, Navigation Type을 선택하는 화면이 나타난다.
여기에서 Navigation Type은 화면의 이동 방법을 선택하는 부분으로 지금은 none으로 선택한고 진행한다.

여덟번째. 마지막 Finish 버튼을 눌러 Project를 생성한다. 아래는 프로젝트를 생성한 최종 화면이다.


이번 시간에는 이클립스를 이용하여 Android Project를 생성하는 방법에 대하여 알아보았다. 다음 시간에는 생성된 Project에 대하여 알아보는 시간을 갖으려고 한다.

여기까지는 참 쉽네요~ 근데 앞이 깜깜하네요~
으악!!!!





2013년 4월 2일 화요일

Mac에서 Andriod 개발 환경 셋팅

mac에서 안드로이드 개발 환경을 셋팅하는 방법을 찾다가 결국 내 스스로 정리하기로 결정했다. 어려운건 아닌지라 그냥 주저리주저리 써내려가려고 한다.

자바 개발에서 안드로이드에 대한 개발을 위한 첫 걸음으로 천천히 배우고 습득하려한다.

안드로이드 개발 환경은 안드로이드 개발자 사이트에 자세히 잘 나와 있어서 기본적인 것을 배우는 것은 어려움이 없을 것 같다.

- 개발 환경 셋팅
http://developer.android.com/training/basics/firstapp/index.html
안드로이드 개발자 사이트에서 위와 같은 페이지로 이동하면 개발에 필요한 sdk와 eclipse를 다운로드 받을 수 있다.

- 프로젝트를 생성하는 방법은 보여주는 페이지
http://developer.android.com/training/basics/firstapp/creating-project.html

엡실행에 대한 가이드
http://developer.android.com/training/basics/firstapp/running-app.html

기본 UI 구성
http://developer.android.com/training/basics/firstapp/building-ui.html

개발 환경을 셋팅하면 이클립스와 sdk가 설치된다. 
여기 이클립스를 실행하면 첫 화면에 activity_main.xml과 strings.xml 에디터가 열려있다.

이것을 이해하면 basic UI는 구성할 수가 있게 된다고 한다.

난 아직 그냥 실행만 해봤다 ㅋㅋ

일단 여기까지 기본 셋팅 방법에 대해 공부한 것을 기술해 보았다.

이제 어떻게 진도를 나갈까 고민 중인데 책으로 할것인가? 아니면 웹을 찾아다니며?
그냥 책으로 하려고 한다..

시작이 반이라고 했다. 고고싱!!!!




2013년 3월 31일 일요일

간단 정리!! Freemarker 사용법!

FreeMarker는 Velocity와 마찬가지로 templating 언어이다.
우리가 Jsp를 코딩하다보면 날코딩으로 생산성이 떨어진다. 그래서 우리는 좀더 편리하게 사용하기위해서 템플릿 엔진을 사용한다.
그리고 가장 큰 장점은 아래의 1번에서 보듯이 매크로 기능으로 기능을 만들어서 사용할 수 있다는 점이다. 다음은 FreeMarker의 사용 방법을 기술했다.


1. @macro
- 프리마커 템플릿 전역에서 공통으로 사용되는 UI 디펜던트한 함수는 매크로로 만들어 여러 ftl에서 사용할 수 있도록 해준다. 샘플을 참고하도록 한다.
- 형식 : <@매크로명 변수1, 변수2, ... />
- 샘플1) 긴 문자열을 적당한 크기로 자르는 기능의 매크로
*사용법 : <@trimX ${item.title}, 20 />
*매크로 :
<#macro trimX src max><#compress>
<#if src?length &gt; max>
${src[0..max-1]}..
<#else>
${src}
</#if>
</#compress></#macro>


- 샘플2) YYYYMMDD 형식의 문자열을 YYYY.MM.DD 형식으로 변환하는 매크로
*사용법 : <@parseDay ${item.regdate} />
*매크로 :
<#macro parseDay src><#compress>
<#if src?length == 8>
${src[0..3]}.${src[4..5]?number}.${src[6..7]?number}
<#else>
${src}
</#if>
</#compress></#macro>


2. #list
- 배열 형식의 오브젝트를 루핑 처리할때 사용하는 프리마커 지시자이다. “로컬엘리어스_index” 라는 변수는 0부터 시작하는 시퀀스번호이다.
- 형식 : <#list 배열객체 as 로컬엘리어스명></#list>
- 샘플1)
<#list LIST as item>
번호 : ${item_index+1} | 이름 : ${item.name} | 아이디 : ${item.id}
</#list>


3. #if
- 프리마커 조건문에 사용되는 지시자이다.
- 형식 : <#if 조건식></#if>
- 샘플1) string 비교
<#if ENTITY.usergrade == “A” >......</#if>
- 샘플2) number 비교
<#if ENTITY.userclass?number == 3>.....</#if>
- 샘플3) boolean 비교
<#if ENTITY.isAuth()>.....</#if>


4. #break
- Loop문을 중단하고 다음 스크립트로 넘어가려고 할때 사용되는 지시자이다.
- 형식 : <#break>
- 샘플1) 루프문을 실행하는 중 5번째에서 escape 하는 예
<#list LIST as item>
<#if item_index &gt; 3><#break></#if>
</#list>


5. #assign
- 프리마커내에서 사용자 정의 로컬변수가 필요할 때 사용하는 지시자이다.
- 형식 : <#assign 로컬변수명 = 초기화값>
- 샘플1) <#assign CHECK = item_index>


6. [x...y]
- 문자열의 일정 범위를 자를때 사용하는 함수
- 형식 : ${문자열[1..5]}
- 샘플1) ${item.name[1..5]}


7. ?has_content
- 리스트형 오브젝트가 null이 아니고 최소 1개 이상의 컨텐츠를 가지고 있는지 체크하는 함수로써 ?has_content는 ?exists와 ?size>0 두가지 체크를 동시에 해주는 함수이다.
- 형식 : 리스트오브젝트?has_content
- 샘플1) <#if LIST?has_content>.....</#if>


8. ?exists
- NULL체크 함수. if_exists는 <#if 지시자 없이도 사용할 수 있게 해주는 표현식이다.
- 형식 : 오브젝트?exists
- 샘플1) <#if ENTITY.username?exists>${ENTITY.username?substring(0, 5)}</#if>
- 샘플2) <#if LIST?exists && LIST?size &gt; 0>.....</#if>
- 샘플3) ${ENTITY.username?if_exists}


9. ?default
- NULL값을 대체해주는 함수
- 형식 : 오브젝트?default(디폴트값)
- 샘플1) ${item.userclass?default(“99”)}
- 샘플2) ${item.age?default(20)}


10. ?string
- 문자열로 형변환하는 함수
- 형식 : 오브젝트?string
- 샘플1) <#if item.age?string == “29”>.....</#if>
- 샘플2) ${item.regdate?string(“yyyy/MM/dd HH:mm”)}
- 샘플3) 숫자를 통화표시로 나타내는 예
<#assign MONEY = 1234567>
${MONEY?string(",##0")}


11. ?number
- 숫자로 형변환하는 함수
- 형식 : 오브젝트?number
- 샘플1) <#if item.userclass?number &gt; 3>.....</#if>
- 샘플2) ${LIST_POINTS[item.gid?number].entityname?default(“”)}


12. ?js_string
- 문자열을 자바스크립트에 유효하도록 필터링해주는 함수. 문자열내에 싱글쿼테이션(‘)등이 포함되어 스크립트에 오류가 나는것을 방지하기 위하여 사용되는 함수이다. 화면상에는 HTML 태그로 취급된다.
- 형식 : 오브젝트?js_string
- 샘플1) 문자열 <img src=’/image/enterprise.gif’>을 js_string으로 처리했을때 소스보기를 하면 <img src=\’/image/enterprise.gif\’>으로 출력된다.
- 샘플2) <a href=”javascript:getName(‘${item.homeurl?js_string}’);”>


13. ?html
- 문자열을 HTML Symbolic Entity로 필터링해주는 함수. 문자열내의 HTML태그등을 깨뜨려 화면상으로 출력되도록 할때 사용하는 함수이다. 화면상에 HTML태그가 아닌 일반 문자열로 취급된다.
- 형식 : 오브젝트?html
- 샘플1) 문자열 <img src=’/image/enterprise.gif’>을 html로 처리하면 화면상에 <img src=’/image/enterprise.gif’> 로 출력되고 소스보기를 하면 &lt;img src=’/image/enterprise.gif’&gt;로 출력된다.


14. ?index_of
- 특정 문자(열)가 시작되는 위치를 정수형으로 반환한다. 인덱스는 0부터 시작됨.
- 형식 : 오브젝트?index_of(특정문자)
- 샘플1) “abcde”?index_of(“c”) 는 2를 반환한다.


15. ?replace
- 문자열의 일부를 주어진 문자로 대체하는 함수
- 형식 : 오브젝트?replace(찾을문자열, 대체할문자열)
- 샘플1) ${item.content?replace(“>”, “&gt;”)}


16. item_has_next
-리스트 객체의 다음 컨텐츠가 존재하는지(EOF) 체크하는 함수
-형식 : 리스트엘리어스이름_has_next
-샘플1) 이름과 이름사이에 , 를 찍어주되 마지막은 찍지 않는 경우의 예
<#list LIST as item>
${item.name?default(“”)}<#if item_has_next>,</#if>
</#list>

Spring3.x에서 JQuery를 이용한 Ajax 사용하기(Spring3.x from Ajax using JQuery to use)

나는 Spring3.x framework에서 JQuery를 이용한 Ajax 사용 환경을 구축하려고 한다.
페이지에서 클릭 이벤트가 일어났을 때 서버에서 적당한 값을 가져와 노출하는 서비스를 만들려고 한다. 아주 단순한 예제이지만 기본 개념을 이해하는데는 무리가 없을 것이다.

준비사항은 Spring3.x framework, JQuery, Ajax에 대한 기본적인 이해를 하고 있다는 가정하에 시작한다는 것을 잊지 말아야 한다.

AjaxTestContorller.java

package study.web.jini.sample.ajax;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class AjaxTestController {

@RequestMapping(value = "sample/ajax/test.jws", method=RequestMethod.GET )
public ModelAndView ajaxTestMethod(HttpServletRequest req, HttpServletResponse res ) throws Exception {
return new ModelAndView("sample/ajaxtest");
}

  /**
     * Ajax - @ResponseBody 어노테이션을 이용해 보자.
     * @param request
     * @return
     * @throws Exception
     */
    @RequestMapping(value="sample/ajax/click.jws", method=RequestMethod.POST)
    public @ResponseBody String clickMethod (HttpServletRequest request) throws Exception   {
         
        String str = "CLICK TEST success!!";
         
        return str;
    }
}

"sample/ajax/test.jws" 를 호출 할 경우 JQuery를 사용한 ftl(freemarker) 페이지로 이동하도록 controller를 생성한다.
그리고 Ajax를 사용하기 위해 @ResponesBody Annotation을 이용하여 Ajax 이벤트 이후에 수행할 process에 대한 메소드를 정의한다.

아래는 Ajax가 실행되는 페이지 ftl 이다.

<title>Ajax Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<script type="text/javascript" src="/js/jquery-1.4.4.js"></script>
<script type="text/javascript">
    /*
     * jQuery $.ajax()
     */
    function doAjaxAction() {
        $.ajax({
            type: "POST",
            url: "/sample/ajax/click.jws",
            //data: ({Id:$("#Id").val(), Pwd:$("#Pwd").val()}),
            //contentType: "text/plain; charset=euc-kr",
            success: function(data) {
                if(data != null)    {
                    $("#RsltTblAjax").html(data);
                } else {
                    $("#RsltTblAjax").html("null 입니다.");
                }
            },
            error: function(e){
            alert('error' + e);
            }
        });
    }
 </script>

<!-- HTML -->
<br>
<h3>Ajax Test !!</h3>
<br>
<br>
<br>

<a href="#" onclick="doAjaxAction();">CLICK!!</a>

<p id="RsltTblAjax"></p>

페이지 내에 CLICK!! 링크를 클릭할 경우 "/sample/ajax/click.jws"를 호출하여 ajax 연동을 하게 된다. 위의 내용은 성공 할 경우 Controller내의 clickMethod를 호출하고 결과 값으로 "CLICK TEST success!!"를 리턴하는 내용이다.

아래는 Spring3.x Framework의 servelt-context.xml 내용이다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<beans:bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<beans:property name="order" value="2" />
    <beans:property name="cache" value="true"/>
    <beans:property name="prefix" value=""/>
    <beans:property name="suffix" value=".ftl"/>
    <beans:property name="contentType"><beans:value>text/html; charset=euc-kr</beans:value></beans:property>
        <beans:property name="exposeSpringMacroHelpers"><beans:value>true</beans:value></beans:property>
</beans:bean>

<context:component-scan base-package="study.web.jini" />

</beans:beans>