REF-spring  REF-etc     Validataion-Group



spring 에는 annotation으로 form 필드를 자동으로 체크할 수가 있다.


일반적으로는 

xxForm.java 파일을 하나 만들고 그 안에 Form과 일치하도록 모든 Field를 정의한 다음에...


각 필드별로 여러가지 constraint를 정의할 수 있다. 


@Pattern :  Regex패턴 체크.

@NotNull  @Null 

@Size(min=2, max=30) 

@Past (지난 날짜) @Future

@Max @Min @DecimalMax @DecimalMin 2Digits

@AssertFalse @AssertTrue


<기본사용>


예제)
public class MyForm {

@NotNull(message = "{error.not_input}")
@Length(max = 3, message = "{error.max_length}")
private String age;

@NotNull(message = "{error.not_input}")
@Length(max = 255, message = "{error.max_length}")
private String name;

@Pattern(regexp = MyConstant.MAIL_ADDRESS, message = "{error.mail_address_format_error}")

private String email;


}

 

컨트롤러에서 아래와 같은 형태로 값을 받는다.

public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult)




==========1=====================

간단히 Override로 Custom Validator를 만들 수 있다.

@Data
@NoArgsConstructor
@CmsMemberMailValidator(newMailAddressField = "newMailAddress", mailConfirmField = "mailConfirm")
public class CmsMemberMailModifyForm {

private Long id;

private String displayName;

private String status;

private String organizationName;

private String mailAddress;

@NotNull(message = "{error.mail_address_null_error}")
@Pattern(regexp = WebConstantShared.MAIL_ADDRESS, message = "{error.mail_address_format_error}")
private String newMailAddress;

@NotNull(message = "{error.mail_address_null_error}")
private String mailConfirm;

public static CmsMemberMailModifyForm of(CmsMemberDetail cmsMemberDetail) {
CmsMemberMailModifyForm form = new CmsMemberMailModifyForm();
BeanUtils.copyProperties(cmsMemberDetail, form);
return form;
}
}

 


@Target({ TYPE }) @Documented
@Retention(RUNTIME)
@Constraint(validatedBy = Validator.class)
public @interface CmsMemberMailValidator {
String message() default "{error.mail_address_format_error}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String newMailAddressField();
String mailConfirmField();
class Validator implements ConstraintValidator<CmsMemberMailValidator, Object> {
private String message;
private String newMailAddressField;
private String mailConfirmField;
@Override
public void initialize(CmsMemberMailValidator constraintAnnotation) {
message = constraintAnnotation.message();
newMailAddressField = constraintAnnotation.newMailAddressField();
mailConfirmField = constraintAnnotation.mailConfirmField();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
String newMailAddressValue = (String) beanWrapper.getPropertyValue(newMailAddressField);
String mailConfirmValue = (String) beanWrapper.getPropertyValue(mailConfirmField);
//check only different case (null & blank Error_Message is processed on @NotNull annotation)
if (newMailAddressValue != null && StringUtils.isNotBlank(newMailAddressValue)
&& mailConfirmValue != null && StringUtils.isNotBlank(mailConfirmValue) && !mailConfirmValue
.equals(newMailAddressValue)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(message)
.addPropertyNode(mailConfirmField)
.addConstraintViolation();
return false;
}
return true;
}
}
}


==========2===================

위보단 약간 복잡하지만 좀 더 많은 기능이 있는 @InitBinder를 이용해

Custom Validator를 만들 수 있다.


Custom Validator: spring-REF   Ref-InitBinder

Custom Validation Class를 만들 수도 있다.

.  



< Valid vs Validated >  REF1simple, REF2,


Validated는 spring 소속이고, Valid는 java소속인데

Validated가 Validataion-Group을 지정할 수 있다.



 에러메시지도 출력가능하다.   REF




Posted by yongary
,

javascript로 이메일 verification하는 스크립트가 왜케 복잡한 것만 있는지..


인터넷에 마음에 드는 게 없어서 새로 만들어 보았다.



//check if mail address is xx@xx.xx (xx: contains "." & "_" & "-" & "alphanumeric" )
function validateEmail(email) {
var re = new RegExp("^[-a-zA-Z0-9._]+@[-a-zA-Z0-9._]+\\.[-a-zA-Z0-9._]+$");
return re.test(email);


코멘트 처럼  xx@xx.xx  폼을 체크하는데  xx 는  - . _ 알파뉴메릭  으로 이루어진다. 



조금 더 발전하면.. (이건 다른사람 꺼)

"[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})";


Posted by yongary
,

Selenium 을 이용하면 여러 브라우저를 직접구동시켜 다양한 테스트를 수행하므로

고급 웹서비스에서는 이 방식을 사용하는 것이 좋다.


하지만 간단한 웹페이지라면 이런방식이 부담이 될 수 있는데,

간단한게  spring의  HtmlUnit을 이용하면 되지만(REF) 약간 부족한 부분을

Selenium의 WebDriver만 이용하는 방법이 있다.    이경우 Selenium서버는 필요없다. REF


<비교설명> REF  챕터2.

Posted by yongary
,

MockMvc

Spring 2017. 1. 6. 15:26

영문 spring test 환경 (MockMVC+Junit) 기본설명  : REF


영문Test Guide URL



Spring에서 지원하는 MockMvc로도 거의 모든 테스트가 가능하다.

(가끔 Mockito가 필요하면 둘을 섞어서 쓰면 되는 정도로 보인다)



이전엔 Mockito가 많이 필요했지만, 필요성이 조금 줄어든 것 같다.



아래는 MockMvc로 컨트롤러를 테스트 하는 예제이다. 

  - Controller Test annotation (spring-boot 1.4 부터 지원:)  REF




<MockMVC 기본>  REF

1. Request

-perform

-accept

-with

-param

-cookie

-sessionAttr


2. Response

-andExpect

-andDo

-andReturn



<andExpect> 에서 여러가지 확인이 가능한데.. 주로 많이 쓰는 것들은

.andExpect(status().isOk())
.andExpect(content().json(expected));
.andExpect(status().is3xxRedirection());

.andExpect(view().name("list"))
.andExpect(MockMvcResultMatchers.model().size(1));

등등이다.



ModelAndView: 데이타가 복잡할 경우에도 테스트가 가능한데....  

        View name = redirect:view

             View = null

        Attribute = MyTicketReserveResult

            value = MyTicketReserved(code=0009, msg=nulll)

           errors = []


와 같은 json을 확인하려면.. (아직 확인 중)


.andExpect(jsonPath("$[1].rtncd").value("0009"))


Posted by yongary
,


Spring 에서  web Test시에 user를 mock하는 방법으로 2가지를 현재 보고 있는데,

차이점이나 장단점에 대해서는 좀 더 공부를 할 예정이다.



1. import org.springframework

        .security.authentication.UsernamePasswordAuthenticationTokenREF


  

UserDetails user = this.userDetailsService.loadUserByUsername(username);

        UsernamePasswordAuthenticationToken authentication = 
                new UsernamePasswordAuthenticationToken(
                        user, 
                        user.getPassword(), 
                        user.getAuthorities());



2. import static org.springframework

         .security.test.web.servlet.request

         .SecurityMockMvcRequestPostProcessors.user;


  RequestBuilder request = get("/my_web_url")

  .with(user (myUser));



AuthenticationManager 참고: REF

Posted by yongary
,

Mockito 사용법

Spring 2016. 12. 28. 18:09

javadoc   한글개요   goodTutorial



Mockito에서   @Mock @InjectMocks @Spy 의 차이점:

(작성 중: 현재 정확하지 않음)


@InjectMocks를 우선 사용해서 서비스/Controller등을 만들고

컴포넌트를 @Mock를 이용해서 삽입한다.  REF


둘을 하나의 object에 동시에 사용하고 싶을 경우, 동시에 사용할 수 없기 때문에

@InjectMocks와 @Spy를 동시에 사용할 수 있는데

이경우  when()함수를 사용하면 실제 함수를 호출하기 때문에  doReturn함수를 사용한다.  Ref



<검사함수들>

when  :  mock객체는 기본값을 return하기 때문에 Stubbing을 통해 원하는 값을 리턴한다.      REF

 - when(mockedGenerator.getNextId()).thenAnswer(new Answer<Integer>(


assertTrue

  assertNotNull


doReturn  Ref   -override도 가능.

  doThrow  -  void type을 stub할때, when이 java문법에 맞지않아서  
                    doThrow(new Exception()).when(mock).method() 이렇게 사용.

  doNothing

           ex) doNothing().when(authenticationManager).authenticate(Matchers.any(Authentication.class)); 

  doAnswer 

           ex) 

doAnswer(new Answer<Authentication>(){

@Override
public Authentication answer(final InvocationOnMock invocation) throws Throwable {


//case token

ObjectPostProcessor<Object> objPostProc = (
new ObjectPostProcessor<Object> () {
public Object postProcess(Object bean) throws BeansException {
System.out.println("BeforeInitialization : " );
return bean; // you can return any other object as well
}
});

final PreAuthenticatedAuthenticationToken token = (PreAuthenticatedAuthenticationToken)(invocation.getArguments())[0];
Authentication authentication = (new AuthenticationManager(){
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
return (new AuthenticationManagerBuilder(objPostProc)).getOrBuild().authenticate(authentication);
}
}).authenticate(token);
return authentication;
}

}).when(authenticationManager).authenticate(Matchers.any(Authentication.class));



Verify 사용법 : test된 코드들의 횟수체크.. . REF

  - verify ( object,  atMost/never/times/atLeast/timeout ).함수명(  any(param) OR eq(param) ) 등.


InOrder  :  object간 순서 체크. 

verifyNoMoreInteractions : mock의 행동 다 검증했는지 확인.


Posted by yongary
,

thymeleaf 기본.

FRONT-END 2016. 12. 19. 22:18

REF-Tutorial

REF기본:

REF-dateForamtter등 발전된기능  {{}}:dateFormatter

(단, 이경우는 WebMvcConfig.java나 xml등에 addFormatter override나, formatter지정이 필요. Ref안에 xml은 있음)


spring의 thymeleaf를 통해  java의 EL을 html에 사용하는 듯한 느낌으로 사용할 수 있다.


@{ }로 사용하는 Variable expression은 java의 EL과 동일하고,

그 외에도 다음과 같은 것들이 있다.


  • ${...} : Variable expressions     - iterator처럼 반복도 지원된다.
  • *{...} : Selection expressions.   - th:object = ${book}과 같이 $로 선택된 object내에서 동작한다.  
  • #{...} : Message (i18n) expressions. - 다국적 메시지 지원.
  • @{...} : Link (URL) expressions.  -변수 파라미터도 가능하고, 상대경로 URL도 가능
            ex)  th:href="@{'/app/user/'+${user.id}+'/bustickets'}
  • ~{...} : Fragment expressions.  - 주로 div안으로 삽입 가능.


thymeleaf 로 form을 submit할 때는 다음과 같다.   REF

<form action="#" th:action="@{/greeting}" th:object="${greeting}" method="post">
    	<p>Id: <input type="text" th:field="*{id}" /></p>
        <p>Message: <input type="text" th:field="*{content}" /></p>
        <p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
    </form>

@{/greeting} : 처리할 URL

${greeing} : model형태로 넘길 object

th:text 보다는 th:field를 써야 object매핑이 되겠군요.



<table if  사용법>   REF

<td th:if="${member.status} == '1'" th:text="Active"></td>
<td th:unless="${member.status} == '1'" th:text="Inactive"></td>

<a th:if="${history.myProject.payType eq 'credit_card'}"

==> { }안에서 string비교시 eq도 사용가능.



<switch >

<td class="col-sm-2" th:switch="${ticket.status}">
<span th:case = 'unused'> "Unused"</span>
<span th:case = 'used'> "Used"</span>
<span th:case = 'unknown'> "Unknown"</span>
</td>


<enum사용시>

<td class="col-sm-1" th:if="${ticket.type == T(my.constant.TicketType).PAID}" th:text="Paid"></td>

${ticket.isExpired()}와 같이 public 함수도 사용이 가능하다. 


==고급===

[[ ]]  in-line 프로그래밍.  REF

${{ }} 자동변환.  REF


==th 함수==

${#strings.isEmpty(...))}

${#lists.size(...)}


th:block  - 매우 유용. 전체 block을 if로 묶어서 나타내거나 숨길 수 있음.

  <th:block th:if="${@environmentHelper.isBeta()}">
   각종 javascript등.. 코드

</th:block>


Posted by yongary
,

spring boot

springBoot gradle 2016. 12. 18. 01:07

설치는 SDKMAN 이나 Brew등으로 가능.

$spring --version 으로 버전확인 가능.

$spring shell  :  sh도 제공


하지만, 대부분 IDEA를 이용하므로,

IntelliJ를 이용할 경우, gradle프로젝트를 만들고, springboot는 dependency로 삽입하면 된다. REF




<어노테이션>

@SpringBootApplication : component-scan 과 자동config제공.

  - @Conditional 도 가능( jdbcTemplate과 같이 dataSource존재여부에 따라...조건부 Bean제공 가능)

한데 자동 config은 이런식으로 Tomcat, ORM, web매핑(/static) 등으로 classpath등을 보고 자동판단한다.


*물론 이러한 자동config도 override를 통해  수정할수 있다.(@Configuration)


<빌드 & run - gradle 사용시>

 $ gradle bootRun : 빌드와 run동시 수행.

    = $gradle build + $java -jar build/libs/..-0.0.1-SNAPSHOT.jar(or war)


maven :  $spring-boot:run

               

             ($ mvn package ) : just package



 <설정>

application.properties는 첨엔 비어있으므로 필요한걸 추가하면 됨.

dependency가 2개가 있는데(gradle.plugin 등)

  - 위에껀 spring boot plugin dependency이고

  - 밑에껀 starter dependency 이다.   (참고로 maven은  순서가 바뀌어있지만.. plugin tag보면 알수 있음)


  - dependency 일부를 제거하고 싶을 땐,  exclude group등으로 가능.


 


 <TEST용 어노테이션>

@WithMockUser

@WithUserDetails


@WebIntegrationTest     


@Value (${local.server.port}) 등도 spring에서부터 사용가능.


물론 웹은 Sellenium과 연동테스트 된다.




<groovy> - C L I 와 궁합이 잘 맞음

Grabs.groovy 파일에 아래 3줄만 넣으면 spring-boot가 자동으로  못한 것들도, startup 시에 dependency를 자동으로 넣으면서 구동 가능. 

  @Grab("h2")

  @Grab("spring-boot-starter-thymeleaf")

  class Grabs {}  


==> 그 후에  $ spring run .  


 

Groovy로 test unit작성 시에는.. 

 $ spring test tests/myTest.groovy   로 하나 실행 혹은

 $ spring test tests  로 폴더통째로 실행 가능.



<패키징>

 $ spring jar MyProject.jar 하면 jar로 패키징 됨.. 


   war는 ?

   -gradle 의 경우 

      war {

baseName = 'readinglist'

version = '0.0.1-SNAPSHOT'

}

  - maven 의 경우

    <packaging> war </packaging>  

  

 만 추가하면 된다.



<Actuator>

CLI 환경에선 @Grab('spring-boot-starter-actuator') 추가하는 방법이 간단함.


그리고 Actuator중에선 아래 3가지가 특히 유용하다. . 

https://localhost:8080/beans  - 모든 bean과 dependency.  

https://localhost:8080/dump  - 모든thread 현황 

https://localhost:8080/trace   


그 외 enable을 시킨후에

curl -X POST http://localhost:8080/shutdown 명령어로 CLI상에서 shut-down도 가능하다. 



SSH 로도 actuator접속이 가능한데

@Grab("spring-boot-starter-remote-shell")  이런형태로나 maven/gradle에 dependency추가 후

$ ssh user@localhost -p 2000 하면 된다.






Posted by yongary
,

six2six FixtureFactory

java core 2016. 12. 12. 17:47

Unit 테스트시에 가짜 object를 만든다.

Template을 이용해서, class를 기본으로 object 데이타를 만든다.  REF




 Template을 이용하거나

  

     ClientTemplateLoader implements TemplateLoader{


@Override

public void load(){


}


Fixture.of(My.class).addTemplate("valid", new Rule(){{

}});

     }




 Fixture class안에서 ObjectFactory를 이용하게 되고.


     class Fixture {

         

        @Override

         ObjectFactory from(class<?> class){

    return new ObjectFactory(of(clazz)); 

}




Test시에는 아래와 같은 방법으로..  object를 만들어서 사용할 수 있게 된다.


  Fixture.from(My.class).gimme("new")    



- (물론)위처럼 소스에서 하나씩 생성할 수 있지만...


- Regex를 이용한 Rule을 이용해서도 만들 수도 있다. 

- Fixture 를 YAML로 저장해 놓고 일괄 생성할 수도 있다.



Posted by yongary
,

google Guava

java core 2016. 12. 8. 23:53

guava-api


Guava는 열대과일로서 분홍색 빛을 띤 주스로 즐기기기도 하는데,

구글에서는 guava library를 통해, java 에 없는 편리한 기능들을 진작부터 만들어왔고,

일부가 java7, java8등에 반영되기도 하였다.


거론되는 장점들은 다음과 같다. (추후 test후 재정리 예정)


1. MultiMap

 - 기존 Map이 <key,value>인데 반해,  MultiMap은 <key,v1,v2,v3,v4...>라고 볼 수 있다. 

   여러모로 편리하다. 속도도 구글이 만들었으니 빠를것 같긴 한데...   


2. ImmutableMap  : 

  - ImmutableMap.of( "A", ImmutableMap.of("A-1","A-2") )  ; 

  이런식으로 사용해서, data가 바뀌지 않는 Map 이 있어 test시에 유용하다.

    

  => ImmutableList.of("A","B"); 도 유용하다. (이거도 guava)


3. Ordering이 아주 편리하다고 한다. 



4. Maps.uniqueIndex  - 중복없는 Index 제공해주므로 편리.

    Maps.newHashMap() - nested Map 을 한번에 생성해서 편리.  REF (이전글이라 test필요) 



5. CharMatcher 가 아주편리하다고 한다.  regex를 대체할 수 있나 본데....



스트림에서 유용

 .stream().collect(GuavaCollectors.toImmutableMap

Posted by yongary
,