'Technical Note/SPRING'에 해당되는 글 12건

Technical Note/SPRING

Spring을 가지고 개발을 하다보면

가장어려운것이 클래스 네이밍과 MVC 패턴 설계이다

복잡한 기능을 구현하다 보면 Service의 범위는 어떻게 해야 하는건지, Service 에서 다른 Service를 호출해야 하는건지 등등 고민하게 된다

그래서 요즘은 스프링 개발자 구글 구룹스( https://groups.google.com/forum/#!forum/ksug )에 많이 들리곤 한다.

여기서 Page Controller라는 것을 알게되었다. 



An object that handles a request for a specific page or action on a Web site.

For a full description see P of EAA page 333

Most people's basic Web experience is with static HTML pages. When you request static HTML you pass to the Web server the name and path for a HTML document stored on it. The key notion is that each page on the Web site is a separate document on the server. With dynamic pages things can get much more interesting since there's a much more complex relationship between path names and the file that responds. However, the approach of one path leading to one file that handles the request is a simple model to understand.

As a result, Page Controller has one input controller for each logical page of the Web site. That controller may be the page itself, as it often is in server page environments, or it may be a separate object that corresponds to that page.



Technical Note/SPRING

두번째로 AJAX 를 사용해서 파일 업로드 기능을 구현하는 방법입니다


설정은 앞의 스프링 파일 업로드와 거의 유사합니다


AJAX로 업로드를 한 다음 JSON 형식으로 응답을 해주기 위해서

스프링 설정을 좀 추가/수정 해줘야 됩니다


[스프링 설정파일 servlet-context.xml]

<bean id="viewResolver" 

      class="org.springframework.web.servlet.view.InternalResourceViewResolver"

      p:prefix="/WEB-INF/view/" p:suffix=".jsp" p:order="2" />

<bean id="beanNameViewResolver

class="org.springframework.web.servlet.view.BeanNameViewResolver">

<property name="order">

<value>1</value>

</property>

</bean>

<bean name="JSON" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />


스프링에는 @ResponseBody 라는 기능도 있지만 저는 MappingJacksonJsonView 객체를 사용했습니다

Controller에서 리턴해줄 View 를 JSP 대신에 MappingJacksonJsonView 를 사용하는거죠


JSP 페이지로 뿌려준 다음 그 값을 받아도 상관은 없지만.. 

매우 번거로워 지기 때문에 MappingJacksonJsonView를 많이 사용합니다


요놈을 사용하면 매우 편리하게 JSON 형태의 문자열로 변환한 다음 AJAX CallBack 함수로 전달해줄 수 있습니다

JSON 형태의 문자열을 만들기 위해서 JSONObject / JSONArray 등을 따로 사용하지 않아도 됩니다


JSON 이라는 이름을 가진 Bean 객체를 View로 사용해야 하기 때문에 BeanNameViewResolver를 선언해줍니다

처리하는 우선순위는 InternalResourceViewResolver 보다 낮게 지정해야 하구요

그래서 위쪽의 viewResolver는 order를 2로 beanNameViewResolver는 order를 1로 지정했습니다


Service 부분은 앞의 예제를 그대로 사용하시면 됩니다


Controller와 JSP도 살짝 수정해줍니다


[Controller]

@RequestMapping(value="fileUploadAjax.do", method=RequestMethod.POST)

public ModelAndView fileUploadAjax(MultipartHttpServletRequest mRequest) {

ModelAndView mav = new ModelAndView();

if(boardService.fileUpload(mRequest)) {

mav.addObject("result", "SUCCESS");

} else {

mav.addObject("result", "FAIL");

}

mav.setViewName("JSON");

return mav;

}

소스를 보면 앞에서 만든 Controller와 거의 같습니다

View만 JSON 이라고 변경했습니다


[JSP]

<script src="/js/jquery-1.10.2.min.js"></script>

<script src="/js/jquery.form.js"></script>

<script>

$(document).ready(function() {

$("input[type=submit]").bind("click", function() {

$("form").ajaxSubmit({

success : function(data) {

alert(data.result);

},

error : function(error) {

alert("요청 처리 중 오류가 발생하였습니다.");

}

});

return false;

});

});

</script>

jquery.form.js 플러그인을 사용합니다


jquery의 플러그인이므로 임포트 하기 전에 

<script src="/js/jquery-1.10.2.min.js"></script> 이 구문을 반드시 먼저 써줘야 합니다

jquery.form.js 플러그인의 사용방법은 일반 jquery 의 ajax 구문과 거의 같습니다


form 자체에 action 주소가 입력되어 있기 때문에 따로 url을 지정하지 않았지만 

혹시 변경을 하고 싶다면 url : "주소" 이런식으로 추가해주시면 됩니다


가장 아래쪽에 return false; 이 구문을 반드시 추가해주셔야 원래 submit 버튼의 기능을 막아줍니다

추가하지 않으면 ajax로 결과를 받는것이 아니라 다음 페이지로 넘어가서 JSON 문자열을 출력해버립니다

Technical Note/SPRING

Spring Framework는 Scheduling 서비스를 제공하기 위해서 다음과 같이, JDK 1.3이후 제공되는 Timer Scheduler와 Quartz Scheduler( http://www.opensymphony.com/quartz/ )를 제공한다. 

Quartz는 오픈 소스 작업 스케줄링 프레임워크이다. Quartz는 완전히 자바로 작성되어 있으며 매우 유연하고 단순한 구조를 제공하여 간단한 작업은 물론 복잡한 작업 모두에 대한 스케줄링을 작성할 수 있다. 또한 EJB, JavaMail 등을 위한 데이터베이스 지원, 클러스터링, 플러그 인, 미리 내장된 작업들을 포함하고 있다. 

Anyframe Core에서는 JDK의 Timer Scheduler보다 Quartz Scheduler 사용을 추천한다. Quartz Scheduler는 JDK Timer Scheduler보다 더 유동성있고 성능이 좋다. 자세한 내용은 Spring 매뉴얼의 Scheduling 부분 을 참고하도록 한다.

Quartz Scheduler

Quartz는 Job과 Trigger 그리고 JobDetail을 사용하여 스케줄링 기능을 수행한다. Quartz에 대한 자세한 내용은http://www.opensymphony.com/quartz 를 참고한다.
  • Job은 실행해야 할 작업으로, 자동 문자메시지 전송 기능이나 어플리케이션의 자동화된 작업들이 그 예이다. Job은 언제 실행되는지에 대한 정보 없이 실행 작업의 단위로만 작성된다.
    Job은 Spring Framework에서 제공하는 QuartzJobBean을 상속받아서 작성할 수도 있고, 특정 API에 종속되지 않은 POJO 형태의 자바 클래스로 작성할 수 있다. 또한 Stateful한 Job 클래스를 사용하기 위해서 Quartz에서 제공하는 StatefulJob 인터페이스를 구현하여 Job을 작성할 수도 있다. Stateful 인터페이스를 구현하여 작성된 Job 클래스 이외의 모든 Job 클래스는 기본적으로 Stateless한 Job 클래스로 동작한다. Stateful한 Job의 경우에만 반복되는 Job 수행 시 특정 데이터 값을 공유하여 변경할 수 있다.
  • Trigger는 Job을 실행시키기 위한 조건으로 작업 실행 시간, 반복 횟수 그리고 실행 간격 시간 등이 조건에 해당된다. 다수의 Trigger는 동일한 Job을 공유하여 지정할 수 있으나, 하나의 Trigger는 반드시 하나의 Job을 지정해야 한다.
  • JobDetail은 Job을 실행하기 위해 필요한 정보를 가지고 있는, 즉 Job Instance에 대한 상세 속성 정보를 가지고 있는 객체로 Trigger가 JobDetail을 이용하여 Job을 수행시킴으로써 Quartz 기반의 스케줄링 기능이 수행된다.
  • Scheduler는 SchedulerFactory에 의해 생성되는데, JobDetail들과 Trigger들을 관리하며 해당 Trigger에 연관된 Job을 수행시키는 Scheduling 서비스의 핵심 역할을 담당한다.

아래 예제에서는 JobDetailBean, MethodInvokingJobDetailFactoryBean, SimpleTriggerBean, CronTriggerBean, TriggerListener, SchedulerFactoryBean 등을 이용하여 일정한 시간 간격 마다 특정 메소드를 실행시키는 방법을 보여주고 있다.
  • JobDetailBean : Spring Framework은 JobDetailBean이라고 불리는 클래스를 제공하는데, Job을 실행시키기 위해 필요한 정보를 가지고 있다.
  • MethodInvokingJobDetailFactoryBean : Job API에 종속적이지 않게 POJO 형태의 Job 클래스를 작성하여 Scheduler에 따라 해당 클래스의 메소드를 호출할 수 있도록 해주는 역할을 수행한다. 
    Job과 Trigger에 관련된 정보를 DB를 통해 관리하는 경우, 즉 JDBC Job Store 방식을 사용하는 경우에는 MethodInvokingJobDetailFactoryBean이 동작하지 않으므로 사용할 수 없음에 유의하도록 한다.
  • SimpleTriggerBean, CronTriggerBean : Spring Framework에서 Quartz를 손쉽게 사용할 수 있도록 2개의 TriggerBean을 제공한다. SimpleTriggerBean과 CronTriggerBean은 Trigger로써 동작하는 것은 동일하나 CronTriggerBean의 경우, 시간 실행 조건을 cron expression을 이용하여 작성하는 것이 차이점이다. SimpleTrigger보다 상세한 스케줄링 실행 시간 조건을 설정할 수 있으면서도 설정 방법이 복잡하지 않다.
  • TriggerListenerBean : Trigger가 fire->execute->complete 혹은 misfire되는 시점에 특정 일을 수행하고자 할때 Scheduler에 TriggerListener를 설정한다.
  • SchedulerFactoryBean : 사용되는 Trigger를 등록시켜주는 역할을 담당하므로 Trigger들을 triggers 속성의 <list> 태그 하위로 등록시킨다. Trigger에 적용할 Listener 등 여러 속성들을 추가 설정할 수 있다.


Technical Note/SPRING

Java에서 스케줄링을 할 때 Quartz를 많이 사용합니다. Quartz에서 사용하는 Trigger는 SimpleTrigger와 CronTrigger가 있는데요. 간단하게 특징을 보면 다음과 같습니다.

SimpleTrigger : 간단하며 interval, delay, repeat times 등을 설정할 수 있습니다.

CronTrigger : Linux에서 사용하는 cron과 같은 표현(expression)을 사용하며, 특정 시간에 작동하도록 설정할 수 있습니다.

이 중에서 많이 사용하는 CronTrigger가 cron expression이 약간 복잡해서 헷갈리는 경우가 많이 있습니다. 각 필드가 어떤 것을 표현하는지와 예제, 주의할 점 등을 알아보겠습니다.

 

Field 설명

Cron expression은 공백(space)으로 구분된 6~7개의 문자(숫자, 영문자, 기호)를 포함합니다.

 필드 명

 필수

허용 값 

Special characters

 초(seconds) Yes 0-59 , - * /

 분(minutes) Yes 0-59 , - * / 

 시(hours) Yes 0-23  , - * /

 날짜(day of month) Yes 1-31  , - * / ? L W

 월(month)

 Yes 1-12 or JAN-DEC  , - * /

 요일(day of week) Yes 1-7 or SUN-SAT  , - * / ? L #

 년(year) No empty, 1979-2099  , - * /

 

Special Characters 설명

* : 모든 값을 의미합니다. 만약 초에 사용하면 0초~59초까지를 의미합니다.

? : 특정 값을 정하지 않은 것입니다. 일과 요일에서 사용가능한데 일에 사용할 경우 어떤 요일도 상관 없는 것 입니다.

- : 범위를 의미합니다. 예를 들어 0-10이면 0부터 10까지입니다. 여기서 주의할 것은 마지막 값인 10이 포함된다는 것입니다.

, : 값을 추가할 때 사용합니다. 0-10,20-30은 0부터 10까지, 그리고 20부터 30까지를 의미합니다.

/ : 증분을 의미합니다. 예를 들어 초에 0/15를 사용하면 15초마다(0, 15, 30, 45) triggering합니다.

L : 마지막을 뜻합니다. 날짜에 사용하면 월의 마지막 날을 의미합니다. 31, 30 또는 28(윤달에는 29)일입니다.

W : 주중(weekday)를 의미합니다. 날짜와 같이 쓰면 그 날짜가 주중인 날을 의미합니다. 

# : n번째를 의미합니다. 그 달의 몇번째 무슨 요일을 설정할 때 사용합니다. 예를 들어 3번째 월요일은 "2#3"으로 설정합니다.

 

Example

여기서 사용한 예는 Quartz 사이트의 CronTrigger Tutorial에서 차용했습니다.

Expression Meaning

0 0 12 * * ? 매일 12시(정오)

0 15 10 ? * * 매일 오전 10시 15분

0 15 10 * * ? 매일 오전 10시 15분

0 15 10 * * ? * 매일 오전 10시 15분

0 15 10 * * ? 2005 2005년에 매일 아침 10시 15분

0 * 14 * * ? 매일 오후 2시 0분 ~ 59분

0 0/5 14 * * ? 매일 오후 2시부터 2시 55분까지 5분마다

0 0/5 14,18 * * ? 매일 오후 2시부터 2시 55분까지 5분마다, 6시부터 6시 55분까지 5분마다

0 0-5 14 * * ? 매일 오후 2시부터 2시 5분까지 매분

0 10,44 14 ? 3 WED 매년 3월의 수요일마다 오후 2시 10분과 2시 44분

0 15 10 ? * MON-FRI 월요일부터 금요일까지 오전 10시 15분

0 15 10 15 * ? 매달 15일 오전 10시 15분

0 15 10 L * ? 매달 마지막 날 오전 10시 15분

0 15 10 ? * 6L 매달 마지막 금요일 오전 10시 15분

0 15 10 ? * 6L 2002-2005 2002년부터 2005년까지 매달 마지막 금요일 오전 10시 15분

0 15 10 ? * 6#3 매달 3번째 금요일 오전 10시 15분

0 0 12 1/5 * ? 매달 첫날부터 5일마다 12시(정오)

0 11 11 11 11 ? 매년 11월 11일 오전 11시 11분


Technical Note/SPRING
스프링mvc에서
post요청 응답을 리다이렉트로 처리할때
ModelAndView반환형식으로 처리하면
request의 모든 attribute가 쿼리스트링에 다다다닥 달라붙어서 주소창에 출력된다.

필요없는 파라메터값들이 get값으로 줄줄이 붙어나오길래
어디서 붙이는지 찾아봤더니 form컨트롤 post요청시 리다이렉트로 처리하면
그렇게 된다는걸 구글뒤져서 겨우 발견...

보통

return new ModelAndView("redirect:/test.do");

식으로 작성하는데 요걸

RedirectView rv = new RedirectView("/test.do");
rv.setExposeModelAttributes(false);
return new ModelAndView(rv);

형식으로 처리해주면 쿼리스트링에 붙어나오는 attribute들을 지울 수 있다.


1 2 3
블로그 이미지

zzikjh