Clean Code that Works.

root-context 설정에서
context-component scan 에서 자꾸 스프링 MVC 설정(@Configuration으로 되어있는)을 읽어가서.. 조금 살펴 보던 중에...


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}

위에껄 발견...OTL

@Configuration 이 @Component를 가지고 있어서...@Configuration은 스캔되는게 당연하다. 제외 하고 싶으면 exclude 로 빼면 된다.

별것도 아니었는데 -ㅅ-;;


신고

Comment +0

회사에 간단히 포스팅한 것.

2, 3번 변경점이 굉장히 마음에 든다 :)



주요 변경점으론

1. Spring Data 지원

-> Spring Data는 스프링에서 NoSQL 관련 데이터베이스들 관련해서 쉽게 개발하기 위해 생성된 프로젝트 인데. 지원이 된다고 합니다.

Neo4j나 MongoDB를 지원하는 ItemReader, Writer 등등을 지원 합니다.

 

2. 자바 설정 지원 

-> 스프링 3.1 버전 부터였나.. xml 설정 보다는 자바 설정을 더 추천하고 있는데요.

이번 스프링 배치 버전부터 자바 설정을 지원 합니다!! 

기존에 XML로 만들었던 설정들을 자바 설정을 통해서 지원이 되기때문에.. XML 보느라 눈 빠지는 일이 줄어들것 같네요.

 

3. 유니크 하지 않는 Job 파라미터 지원

-> 이전 버전 스프링 배치 사용해보신분들은 아시겠지만, 배치 잡 실행시키기 위해서는 매번 다른 Job 파라미터들을 전달해 주어야 했습니다. 

이번 버전부터는 매번 새로 생성하지 않아도 된다고 하네요.

이때문에 job repository 스키마가 일부분 변경되었고.. 다행히 마이그레이션 스크립트도 제공 한다고 합니다.

 

4. AMQP 지원

-> 메세징 서비스 미들웨어중 하나인 AMQP 지원 한다고 합니다.

 

5. SQLFIRE 지원

-> 이것도 지원 한다는데.. 뭔지 모르겠네요. :(

아시는분이 회신해주시면 좋을것 같습니다.

 

6. 스프링 상위 버전 지원

-> 3.2.x 버전 스프링을 지원합니다.(Hibernate 4 지원)

 

7. 기타 등등

-> 여러 버그와 성능 향상이 있었다고 하네요.

 

원문 뉴스 : http://www.springsource.org/node/22625

신고

Comment +0

보통 Spring에서 스케쥴링 기능을 사용할 때, @Scheduled 애노테이션을 사용한다. 

쉽고 간편하다. <task:annotation-driven /> 설정을 해주거나 3.1 부터 추가된 @EnableScheduling을 설정 클래스에 추가해주면 된다.


그럼 이 annotation은 spring이 어떻게 감지 해서 동작하는 것일까?

ScheduledAnnotationBeanPostProcessor를 살펴보면 답이 나와있다.

이 Bean post-processor가 @Scheduled 애노테이션이 붙어있는 메서드들을 다 찾아서 TaskScheduler에다가 다 등록을 해준다.

주석엔 아래와 같이 설명이..

Bean post-processor that registers methods annotated with @{@link Scheduled}

to be invoked by a {@link org.springframework.scheduling.TaskScheduler} according

to the "fixedRate", "fixedDelay", or "cron" expression provided via the annotation.


사실 갑자기 왜 이걸 보게 되었냐면.....

@Scheduled 옵션을 사용할때 고려되는 문제점이 cron 옵션으로 동작하게 할 수 있는데, 이때 서로 다른 서버에서 같은 동작을 하는 작업을 할 때 cron 식을 달리 하고 싶은 경우가 많다. spring batch 호출 메서드를 각 서버마다 다른 시간으로 호출 하고 싶은경우...

해서, ScheduledAnnotationBeanPostProcessor 살펴보니 여기서 @Scheduled 애노테이션의 cron 식 설정을 불러다가 CronTask를 만드는데 사용을 하고 있는걸 확인할 수 있었다. cron에 cron 식이 들어 오면 그대로 쓰고 설정값('${batch.run.cron}') 형식이 들어오면 프로퍼티 파일에서 읽어다가 쓰는 방식.


그럼 @Scheduled 를 상속 하거나 약간 수정해서 프로퍼티 파일에서 값을 읽는 부분을 수정(동작할 때 서버의 host 명을 가지고 와서 이 host 명 + .batch.run.cron ' 식으로 cron 값을 서버별로 읽어 들이는) 하는 방식으로 말이다.

이렇게 동작 시키기 위해서 ScheduledAnnotationBeanPostProcessor 를 참조 하여 별도의 BeanPostProcessor(별도라고는는 하지만, 설정파일 읽는 부분만 변경 하면된다)를 만들고 이를 bean으로 등록 해주면 간단히 구현이 가능해진다.


ScheduledAnnotationBeanPostProcessor 를 3.0 버전 3.1 버전 3.2 버전 별로 살펴보면 조금씩 리팩토링을 해 나간것을 볼 수 있다. (이런거 살펴보는것도 나름 소소한 재미 인듯, 다른 사람 소스도 살펴보고)  바뀐 부분은 ScheduledTaskRegistrar 에다가 cronTasks, fixedDelayTasks, fixedRateTasks 세팅하는 부분이 좀더 캡슐화 되어 보기 더 편해졌다는 정도?

before

if (!"".equals(cron)) {

processedSchedule = true;

if (embeddedValueResolver != null) {

cron = embeddedValueResolver.resolveStringValue(cron);

}

cronTasks.put(runnable, cron);

}


after

if (!"".equals(cron)) {

processedSchedule = true;

if (embeddedValueResolver != null) {

cron = embeddedValueResolver.resolveStringValue(cron);

}

registrar.addCronTask(new CronTask(runnable, cron));

}




신고

Comment +0

간만에 spring security 로 ip 필터링을 할 부분이 있어서 적용중에...


문서를 보면 hasIpAddress(10.54.100.0/24)  이런 부분이 있다.

음..딱 보면 10.54.100.0~24 까지 ip 필터링을 하는가 보다... 라고 생각하고 그렇게 했는데. 

이 뜻이 아니다. -ㅁ-;;


http://forum.springsource.org/showthread.php?102783-How-to-use-hasIpAddress

위 블로그에 똑같은 질문을 했는데, 친절하게 답변을 해줘서 이해가 쉬웠다.


만약 10.54.100.0 ~255 까지 ip를 블럭 하고 싶으면, 

10.54.100.0/24 이렇게 쓰면된다. 그런데 뒤에 /24는 무엇이란 말인가.

24가 의미하는것은 ip 주소의 subnet mask의 바이너리 값을 더 한것이다.


일반적으로 윈도우나 리눅스에서 ipconfig를 쳐보면 sutnet mask(mask)를 확인할 수 있다.

255.255.255.0

255의 바이너리 값이 11111111 이 되므로

(11111111) * 3 = 24, 이 24가 위 표현에서 /24가 되는것이다.


헐~ 역시 스프링 시큐리티 문서는 아직도 불친절해 -ㄴ-

신고

Comment +0

http://blog.springsource.org/2012/08/29/integrating-spring-mvc-with-jquery-for-validation-rules/

위에 있는 내용 간단히 번역 및 소스 만들기


컨트롤러들에서 리퀘스트 맵핑, 어노테이션을 통한 리퀘스트 데이터 추출, 데이터 바인딩, 파일업로드 등등  전형적인 Spring MVC 의 특징들을 볼 수 있다.

반면에 JSP 안에서는 대부분의 HTML들이 기본적으로 존재 하고 있다.(Spring MVC 태그에 의해 생성되기를 반대하는) 더욱이 Spring MVC 태그 라이브러리들은 어떤 자바스크립트 코드도 생성 하지 않는다.

처음으로 상의 해야 할 내용은 어떻게 Spring MVC와 Jquery 그리고 Bean Validatin을 통합할 것인가 이다. 어떻게 JSP를 줄일 수 있는지 살펴보자

BEAN VALIDATION?

JSR 3030 Bean Validataion은  포괄적인 방법으로 선언적 Validation 방법을 제공한다. 

아래예제를 살펴 보자.

public class DiningForm {
  @Pattern(regexp="\\d{16}")
 
  private String creditCardNumber;
 
  @Size(1)
  private String merchantNumber;
 
  @Min(0)
  private double monetaryAmount;
 
  @NotNull
  private Date date;
 
  ...
 
}

유효성 검증이 호츨 되면 DiningForm의 인스턴스는 위의 Annontations에 의해 유효성이 검증 된다.

Spring 3.0에서, Spring MVC는 유효성 검증을 위한 Bean Validation을 통합했다.(위 방식의 @MVC의 유일한 방법은 아니나 명백하게 가장 대중적인 접근 방법이다.)

컨트롤러 메소드에서 아래와 같이 @Valid를 사용할 수 있다.

@RequestMapping(value="/update", method=RequestMethod.POST)
  public String update(@Valid DiningForm diningForm, BindingResult result) {
 
    if (result.hasErrors()) {
      return “rewards/edit”;
    }
 
    // continue on success...
 
  }
}

JSP 화면에서 에러메세지는 <form:errors /> 를 사용해서 표시될 수 있다.

<form:form modelAttribute="diningForm">
  <form:input path="firstName"/>
  <form:errors path="firstName"/>
  
</form:form>

위의 코드는 잘 작동하고 매우 심플하다. 하지만 어떠한 자바스크립트 코드도 생성하지 않는다. 따라서 부분적인 렌더링이나 클라이언트 측 유효성검사를 하지 않는다. 이 방법을 어떻게 행상시키는지 보도록 하자!


부분 렌더링을 위한 자바스크립트 추가.


"first name" 부분이 비어 있을때 무슨일이 발생하는지 살펴보자.

이전 예제에서 form 이 전송될 때 마다 모든 페이지가 전부 새로고침된다.

응답받은 HTML 소스는 아래와 같다.

우리의 목표는 응답 사이즈를 최소화 하는 것이다. JSON 방식을 사용해서 할 수 있다.

{"status":"FAIL","result":[{"fieldName":"firstName","message":"firstName  may not be empty"}]}

먼저 from 유효성 검증을 위해 jQuery form 전송을 사용할 것이다. form 이 유효성 검증을 통과할 때 form 일반적인 HTML form 전송 방식을 통해 전송된다.(이런식으로 다른 페이지로 redirect될 수 있다.)

간단한 ValidatationResponse 클래스를 만들어 보자

public class ValidationResponse {
 private String status;
 private List errorMessageList;
 
 public String getStatus() {
   return status;
 }
 public void setStatus(String status) {
   this.status = status;
 }
 public List getErrorMessageList() {
   return this.errorMessageList;
 }
 public void setErrorMessageList(List errorMessageList) {
   this.errorMessageList = errorMessageList;
 }
}

controller 클래스에서 action method를 추가하자.

@RequestMapping(value="/user.json")
public @ResponseBody ValidationResponse processForm (Model model, @Valid User user, BindingResult result ) {
 ValidationResponse res = new ValidationResponse();
 if(!result.hasErrors()){
   res.setStatus("SUCCESS");
 }
 // …
 return res;
}

@ResponseBody annotation에게 감사를 돌린다. 응답하는 오브젝트는 아래 다이어그램에서 설명하는 것처럼 JSON  으로 변경된다.

JSP에서 에러 메시지가 도착했을 경우 이것을 파싱해서 화면에 표시 해야 한다. 이 링크에서 좀 더 자세한 자바스크립트 소스를 볼 수 있다.

진보적인 향상 모범사례에 따르면 모든 자바스크립트 코드는 HTML form 바깥에 위치 해야 한다. 클라이언트 브라우저에서 자바스크립트가 사용불가로 되었을때 form은 모든 페이지 리프레시가 되도록 지원 해야 한다.

지금 부분적인 갱신작업을 위한 유요성 검증 작업을 진행하고 있는데, 2가지 개선 포인트가 있다.

  • 페이지 화면이 구리다.
  • 이 hello-world-style 페이지는 이미 100라인이나 된다. 이것을 줄일 방법이 필요하다.


BOOTSTRAP을 사용하여 포장 하기


이것은 Spring MVC와 연관되어 있지는 않지만 이런 허접한 UI 디자인가지곤 샘플 애플리케이션이라 하기가 어려웠다. 아직 들어 본적이 없는 경우에 트위터 Bootstrap 은  CSS 프레임워크처럼 되고 있다. 많은 개발자들이 이것을 좋아하는데 그 이유는 작은 노력으로 만족할만한 웹사이트를 만들 수 잇기 때문이다. Bootstrap CSS와 이미지들을 복사하고 난 후에 사용하면 된다(상세 코드는 이 링크). form 이 아래와 같은 모습으로 변경되었다.


"JSP SOUP"를 방지하기 위한 커스텀 태그 사용.

여기가 정말 재미있어지는 부분이다. 이미 작동하는 몇가지 코드가 있기는 하지만 이것을 읽기가 좀 어렵다. HTML, Javascript, CSS 와 JSP EL을 서로 섞을 것이다. 아래 코드처럼 좀 더 읽기가 편한 JSP 코드가 될 것이다. 

<html:form modelAttribute="user"  id="add-user-form" formUrl="/userAjaxCustomTag.htm">
 <html:inputField name="firstName" label="Enter your first name:" />
 <html:inputField name="lastName" label="Enter your last name:" />
 <div>
   <button type="submit">Save changes</button>
   <button type="reset">Cancel</button>
 </div>
</html:form>

커스텀 태그는 JAVA EE 의 한 부분이고 아파치 톰캣에서 완벽하게 동작한다. 놀랍게도 커스텀 태그를 만드는 일은 매우 쉽다. form input 필드를 사용하는 간단한 예를 보자. 아래 8라인의 코드를 보자.

<div id="firstName">
 <label>Enter your first name:</label>
 <div>
   <form:input path="firstName" />
   <span>
     <form:errors path="firstName" />
   </span>
 </div>
</div>

우리 목표는 이것을 1라인으로 표시하는 것이다.

<html:inputField name="firstName" label="Enter your first name:" />

WEB-INF 폴더에다가 아래처럼 새로운 태그 파일을 작성한다.

이 내용은 아래와 같다.

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ attribute name="name" required="true" rtexprvalue="true" %>
<%@ attribute name="label" required="true" rtexprvalue="true" %>
<div id="${name}">
 <label>${label}</label>
<div>
  <form:input path="${name}"/>
  <span><form:errors path="${name}"/></span>
</div>

userForm.jsp 파일로 돌아와서 커스텀 태그를 사용하기 위해 tag 폴더를 선언해준다.

<%@ taglib prefix="html" tagdir="/WEB-INF/tags/html" %>

아래처럼 새롭게 생성된 태그가 사용 가능 하다.

<html:inputField name="firstName" label="Enter your first name:" />

커스텀 태그는 이클립스나 STS 에 잘 통합되어 있어 코드 자동완성으로 접근이 가능하다.

같은 모양으로 자바스크립트 코드를 태그로 끄집어 내서 아래처럼 한줄로 호출 할 수 있다.

<ajax:formPartialRefresh validateUrl="/userAjaxBootstrap.json" formName="add-user-form"/>

결론

Spring MVC와 폼 유효성 검증에 대한 부분적인 렌더링에 대해서 알아 봤다. 겨우 몇분만에 JSP soup 을 좀더 간단하고 이해하기 쉬운 방법으로 변경 하였다. 

샘플 코드는 이 github에서 확인할 수 있다.









신고

Comment +0

http://blog.springsource.org/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+SpringSourceTeamBlog+%28SpringSource+Team+Blog%29

Posted on May 8th, 2012 by Rossen Stoyanchev in Spring.


이전 포스트에서 new Servlet 3에 대해 소개 하면서 spring mvc 3.2 m1 에 보합된 긴~~ 요청에 대한 비동기 지원에 대해서 설명했다. 비동기 처리에 대한 두번째 매우 중요한 동기는 브라우저들은 실시간으로 요청에 대한 업데이트를 원한다는것이다. 예를 들어 채팅을 포함한 브라우저, 주가 지수, 상태 업데이트, 스포츠 생중계 등등. 모든 예들이 지연에 대해서 동일하게 민갑하지는 않지만 모든것들은 비슷한 요구가 있다.

HTTP request-response에 대한 표준으로는 브라우저가 요청을 시작하고 서버가 결과를 응답한다. 이 뜻은 서버는 브라우저로 부터 요청이 오면 새로운 전달 할 수 없다. 몇가지 방법들이 진화 하고 있는데 전통적인 polling 방식, long polling, HTTP streaming과 가장 최근에 나온 WebSocket protocol을 들 수 있다.

Traditional Polling

브라우저가 새로운 정보가 있는지 확인하고 서버는 매번 즉각적으로 응답한다. 예를들어 메일 클라이언트는 새로운 메세지를 10분마다 체크한다. 간단하고 동작하지만 새로운 정보는 가능한한 최대한 빨리 표시 되어야 하기 때문에 이 접근 방식은 비효율적인 방식이다. 

Long Polling

브라우저는 요청 정보를 유지하고 있지만 서버는 전송할수 있는 새로운 정보가 있을때까지 응답 하지 않는다. 클라이언트 관점에서 이것은 traditional polling과 같은 방식이다. 서버 관점에서는 long-running request와 매우 비슷하고 Part1에서 논의했던 기술을 가지고 확장할 수 있다.

응답에 대해서 얼마나 길게 대기할 수 있을까? 브라우저들은 5분정도 타임 아웃을 설정 하고 프록시들은 가능한한 빨리 끈어 버린다. 그래서 만약 새로운 정보가 도착하지 않는다면, long polling 요청은 브라우저에게 정기적으로 새 요청을 보낼 수 있도록 작성해야 한다. 


신고

Comment +0


http://blog.goyello.com/2011/12/16/enhancements-spring-mvc31/

역시 취미 삼아 ..

Spring 3.1이 개발된지 수개월이 지난 지금 드디어 릴리즈 됬다. 이번 배포 버전은 캐쉬 추상화, 빈 프로파일, 간단한 컨테이너 설정 등 몇가지 재미난 기능을 포함하고 있다. 아무튼 이 블로그 포스팅에서 스프링 3.1에서 내가 생각하는 TOP 5 개선에 대해서 설명할 것이다.

1. Flash Attributes support
플래쉬 어트리뷰트들은 요청 사이의 

2. @Validated annotation with support for JSR-303 validation groups.

스프링 MVC bean validation은 JSR303 그룹 벨리데이션을 지원하는 새로운 @Validated annotation을  지원한다. 이 그룹은 주어진 객체에 대해 검증을 하고 제약의 하위 집합을 정의 한다. 각 제약 조건에 대한 선언은 그룹이나 그것이 속한 그룹의 목록을 정의할 수 있다.


public class User {
    @NotNull
    private String name;
 
    @NotNull(groups = { Simple.class })
    private String address;
 
    @NotNull(groups = { Simple.class, Extended.class })
    private String licenceType;
 
    @NotNull(groups = { Extended.class })
    private String creditCard;
}



public interface Simple {
 
}
 
public interface Extended {
 
}

새로운 @Validated annotation에 대한 사용은 아래 예제에 나와 있다.


@Controller
public class MyController {
 
    @RequestMapping(value = "/user/default", method = RequestMethod.GET)
    public String createDefaultUser(@Validated({ Default.class }) User user, BindingResult result) {
        if(result.hasErrors()) {
            // Validation on 'name'
        }
        return null;
    }
 
    @RequestMapping(value = "/user/simple", method = RequestMethod.GET)
    public String createSimpleUser(@Validated({ Simple.class }) User user, BindingResult result) {
        if(result.hasErrors()) {
            // Validation on 'licenceType' and 'address'
        }
        return null;
    }
 
    @RequestMapping(value = "/user/extended", method = RequestMethod.GET)
    public String createExtendedUser(@Validated({ Simple.class, Extended.class }) User user, BindingResult result) {
        if(result.hasErrors()) {
            // Validation on 'creditCard' and 'licenceType' and 'address'
        }
 
        return null;
    }
}

스프링 3.1에 추가된 이 그룹 벨리데이션은 정말 편리하다. 이 벨리데이션 그룹에 대해서 더 많은 자료는 download and read the JSR 303 specification.

3. Support @Valid on @RequestBody method arguments

@RequestMapping 핸들러 메서드는 HTTP request body에 접근할 수 있는 @RequestBody 어노테이션을 지원한다. 변환이 가능한 메시지는 메시지 컨버터를 통해 변환이 이루어진다. FormHttpMessageConverter(application/x-www-form-urlencoded), MarshallingHttpMessageConverter(application/xml), MappingJacksonHttpMessageConverter(appliction/json) 그리도 다른 converter들도. 하지만 @RequestBody 어노테이션이 붙은 변수들은 자동적으로 벨리데이션체크를 하지 않는다. 수동으로 체크해주는 로직이 필요.


@Controller
public class MyController {
 
    @Autowired
    private Validator validator;
 
    @RequestMapping(value = &quot;&quot;, method = RequestMethod.PUT)
    @ResponseStatus(value = HttpStatus.CREATED)
    @Secured(&quot;ROLE_ADMIN&quot;)
    @Transactional
    public void save(@RequestBody User user) {
        validate(user);
        dao.save(user);
    }
 
    private void validate(User user) {
        // perfom validation using injected validator
    }
}

스프링 3.1에서 @RequestBody 메서드 어노테이션은 @Valid 메서드를 통해 자동으로 벨리데이션 체크를 할 수 있다. 이 방법은 코드를 심플하게 만들어 준다.

@Controller
public class MyController {
 
    @RequestMapping(value = "/user", method = RequestMethod.POST)
    @ResponseStatus(value = HttpStatus.CREATED)
    @Transactional
    public void save(@Valid @RequestBody User user) {
        dao.save(user);
    }
 
    @ExceptionHandler
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ResponseBody
    public String handleMethodArgumentNotValidException(
            MethodArgumentNotValidException error) {
        return "Bad request: " + error.getMessage();
    }
}


위의 예제에서 스프링은 자동으로 유효성검사를 수행하고 에러가 발생할 경우 MethodArgumentNotValidException을 던져준다. 추가적으로 @ExceptionHandler 메서드는 이러한 유형의 에러 처리에 대한 사용자 지정 동작을 추가하여 만들 수 있다.

4. Supporting PUT request with form encoded data

서브릿 구현의 한계는 인코딩된 HTTP PUT 요청에 대한 처리를 하지 않는 다는 것이다. 새롭게 소개되는  HttpPutFormContentFilter는 이 문제를 해결 했다. 스프링 3.1에서 RESTfull or RESTLike API 는 좀 더 심플하게 만들 수 있다. 이것에 대한 샘플은 이전 포스팅에서 찾아볼수 있다.
previous post to read more about the usage of HttpPutFormContentFilter

5. Java based configuration

기존의 Spring MVC 애플리케이션의 XML 설정은 완벽하게 자바 기반의 설정으로 변경할 수 있다. 가장 간단한 웹 애플리케이션의 설정은 @EnableWebMvc 어노테이션을 사용하는 것이다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.example" }, excludeFilters = @Filter(type = FilterType.ANNOTATION, value = Configuration.class))
@Import(PersistanceContextConfiguration.class)
public class ServletContextConfiguration extends WebMvcConfigurerAdapter {
 
    @Bean
    public TilesViewResolver configureTilesViewResolver() {
        return new TilesViewResolver();
    }
 
    @Bean
    public TilesConfigurer configureTilesConfigurer() {
        TilesConfigurer configurer = new TilesConfigurer();
        configurer.setDefinitions(new String[] { "/WEB-INF/tiles/tiles.xml",
                "/WEB-INF/views/**/views.xml" });
        return configurer;
    }
 
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("login");
    }
 
    @Override