spring에서 이전페이지로 복귀는 request의 referer를 이용해서 가능하다.


이전 페이지에 추가적인 데이타를 보내고 싶다면

addFlashAttribute로 가능하다. 


import javax.servlet.http.HttpServletRequest;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

String myFunction(HttpServletRequest request,
RedirectAttributes redirectAttributes,
) {

redirectAttributes.addFlashAttribute("okList", "AA BB CC");

String referer = request.getHeader("Referer");
return "redirect:"+ referer;
}


Posted by yongary
,

MEAN, LAMP & Others

IT 2017. 3. 16. 18:30

LAMP stack: Linux, Apache, MySql, PHP (Perl/Python)

  REF

MEAN stack: MongoDB, ExpressJS, AngularJS, NodeJS

         - ExpressJS:  Node.js Web application framework. 

         - NodeJS: event-driven I/O server-side JavaScript Environment.




Play-framework :  Scala & java 용 프레임워크.  REF

- 이게 spring처럼 널리 이용된다면 scala도 그만큼 역량을 키워가겠네요.  

- JSON과 xml을 First-class 고객으로 모시는 프레임워크인만큼 계속 영향력이 커지지 않을까요..










Posted by yongary
,

bootstrap을 이용해서 table도 쉽고 이쁘게 만들 수 있지만

팝업도 간단히 이쁘게 만들 수 있다.


게다가 팝업이 약간씩 멋지게 움직이는 효과도 있어 심미적으로 만족감도 상당하다.


팝업은 modal ( 팝업이 뜨면서 팝업안에서만 작업이 되는 팝업을 일컫는 단어) 을 이용하면 되고

팝업이 나타나면서 움직이는 효과는 aria-hidden을 이용하면 된다..  REF



bootstrap.min.css  LINK 및 

bootstrap.min.js 정도추가하면 되고.. 및


modal DIALOG의 구조는 아래와 같은 구조.

<div class="modal fade" role="dialog" aria-hidden="true">

<div class="modal-dialog" role="document">
<div class="modal-content">

<div class="modal-header">
<div class="modal-body"> 
<div class="modal-footer">



TEXT Color

<p class="text-muted">...</p> //grey
<p class="text-primary">...</p> //light blue
<p class="text-success">...</p> //green
<p class="text-info">...</p> //blue
<p class="text-warning">...</p> //orangish,yellow
<p class="text-danger">...</p> //red


Posted by yongary
,

웹상에서 간단히 날짜 선택창을 만들고 싶다면

jQuery의 DatePicker모듈을 이용하는 것이 좋아 보인다.


REF   (우측 상단에 예제 있음)



TimePicker도 시간입력용으로 좋은데,

시간을 step단위로 지정이 가능하다.  REF


var timeFix;

function timeFixClick(minutes) {
timeFix.val(minutes);
$('#timeModal').modal('show');
}

$(document).ready(function () {
timeFix = $('#timeFix');

datePicker.datepicker({
format: "yyyy-mm-dd",
viewMode: "days",
minViewMode: "days",
});

timePicker.timepicker();
timePicker.timepicker('option', 'step', '30'); //30분 단위로 시간 선택가능.

<html>

<input name="expireTime" class="form-control" data-time-format="H:i:s" id="timePicker" type="text" size="8" />
<a th:onclick="'javascript:timeFixClick(\'' + ${ticket.minutes} + '\');'" th:text="修正" />



<js 시간 Library> -   REF: https://momentjs.com/



  <script type="text/javascript" th:src="@{js/moment.min.js}"></script>  한 후에..


(사용 예)

  var date = moment(dateData).format('YYYY-MM-DD');

  var time = moment(dateDate).format('HH:mm:ss');


Posted by yongary
,

Jms + ActiveMQ

Spring 2017. 3. 13. 16:34

spring에서 msg를 전달하는 가장 흔한 방법은

JMS(+jmsTemplate)과 ActiveMQ(by apache)를 이용하는 방법이다. 물론 ASYNC 메시징이다.


ActiveMQ를 사용하고자 하면, ActiveMQConnectionFactory가 JMSConnectionFactory로써 제공된다.


 -디폴트 포트: 61616 



<Send>

ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616";

Connection conn = cf.createConnection();


session = conn.createSession(..);


MessageProducer producer = session.createProducer(destination);


producer.send( session.createTextMessage('hello')..)




<Receive>

MessageConsumer consumer = session.createConsumer(destination);
Message message = consumer.receive();



<JmsTemplate을 사용하면 좀더 간단해진다>


jmsOperations.send( new MessageCreator() { ......blabla }

또는 컨버팅 필요시

 

jmsOperations.convertAndSend


Posted by yongary
,

REF


위의 REF를 참조해서 아래와 같이 string으로 변경하면

mySql에서 바로 사용이 가능하다. 



Clock clock;

DateTimeFormatter DB_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String alarmTime = dateTime.format(DB_TIME_FORMAT);



String alarm2 = LocalDateTime.now(clock).format(DB_TIME_FORMAT)


그리고, LocalDateTime을 바로 MySQL에 저장도 가능한데.. (음 이게 더 나아보인다)


단, 이때 String 을  LocalDateTime으로 변환필요시가 있을때에는

"yyyy-MM-ddTHH:mm:ss") 형태를 사용해야 한다.   ( T가 중요)

Posted by yongary
,

몇몇 Annotation

Spring 2017. 3. 9. 18:48

 @ModelAttribute on a method argument -  indicates the argument will be retrieved from the model. If not present in the model, the argument will be instantiated first and then added to the model.


@Retryable (a.Exception, b.Exception 지정가능. 미지정시 상시.. )


@Recover (a.Exception) : a.Exception으로 실패시에에만 호출되어서.. 특별한 뒷처리 및 로그작업등 가능.



@Component( name부여가능 )


@Profile("profile_name")  - name에 해당하는 profile이 active일 때만, Bean이 생성됨. dev test등 주로 이용.


@Conditional - 조건부 Bean생성. 


@GatherJob    (USER_Defined)

  - 나중에 모으고 싶은 것들을 임의로 선언한다. (class는 있어야 죠 , 간단한 빈깡통 Interface면 됨.)

Set<Class<?>> gather = New Reflections(My.class.getPackage().getName())

.getTypesAnnotatedWith(GatherJob.class);


@Qualifier("my name") - 

Posted by yongary
,

REF


Mokito의 ArgumentCaptor를 사용해, insert/update같은 동작을 간단하게  hooking할 수 있다.


(예제)

final ArgumentCaptor<Ticket> logCaptor = ArgumentCaptor.forClass(Ticket.class);
verify(chatTicketRepository).update(logCaptor.capture());
Ticket ticket = logCaptor.getValue();

assertThat(ticket.getStatus(), is(TicketStatus.EXPIRED));



좀 더 복잡한 경우는, ArgumentMatcher를 이용해 복잡한 비교를 할 수 있다. 



파라미터를 hooking하는 다른방법: REF

when(mockObject.myMethod(any(parameterClass.class))).thenAnswer(
                invocation -> invocation.getArgumentAt(0, parameterClass.class));


Posted by yongary
,

MySQL 시간 비교

BACK-END 2017. 3. 2. 16:30

REF


시간비교시에는 MySQL의 INTERVAL 을 이용하는 것이 가장 편한 것으로 보인다.


예)

WHERE

myTable.datetimefield > now() - INTERVAL 3 DAY (or MONTH or WEEK ) 

==> 그러나, 날짜간에는 빼기 보다는  DATE_SUB를 사용해야 하고.


BETWEEN도 사용이 가능하지만,.. 작은 날짜를 앞에 써야 한다.

WHERE my_date BETWEEN DATE_SUB(now(), INTERVAL 1 WEEK) AND now()

참) 그리고 NULL을 비교할때는,  IS NULL   또는  IS NOT NULL 을 사용해야 한다.



그 외 Doma라는 ORM에서 IF와 같이 쓰는 경우엔 다음과 같이 섞어서 사용할 수도 있다.

service.service_code
/*%if sortKey == @com.linecorp.fortune.constant.ServiceSortKey@NEW */
, IF ( NOW() - INTERVAL 1 WEEK < forum_service.published_at, 1, 0) as is_new
/*%elseif sortKey == @com.linecorp.fortune.constant.ServiceSortKey@ANSWER_TIME */
, IF (forum_service_condition.average_answer_time = 0, 12, forum_service_condition.average_answer_time) as answer_time
/*%end*/


Posted by yongary
,

스프링으로 주기적으로 도는 함수를 만들고 싶으면... 


아주 간단하게


public 함수위에 

@Scheduled(cron = "0 39 */2 * * *")와 같이 선언하면 된다.



아래는 매일 2시 49분에 도는 함수!


@Scheduled(cron = "0 49 2 * * *")

참고:  제일앞자리는 cron에 없는거네요.. 용도는?  초.   */30 이러면 매 30초마다임.  REF

   

초 0-59 , - * / 

분 0-59 , - * / 

시 0-23 , - * / 

일 1-31 , - * ? / L W

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

요일 1-7 or SUN-SAT , - * ? / L # 

년(옵션) 1970-2099 , - * /

* : 모든 값

? : 특정 값 없음

- : 범위 지정에 사용

, : 여러 값 지정 구분에 사용

/ : 초기값과 증가치 설정에 사용

L : 지정할 수 있는 범위의 마지막 값

W : 월~금요일 또는 가장 가까운 월/금요일

# : 몇 번째 무슨 요일 2#1 => 첫 번째 월요일



<cron 은    REF 참조>


crontab 파일 형식
------    --------  ---------------------------------------------------
필  드    의  미    범  위
------    --------  ---------------------------------------------------
첫번째    분        0-59
두번째    시        0-23
세번째    일        0-31
네번째    월        1-12
다섯번째  요일      0-7 (0 또는 7=일요일, 1=월, 2=화,...)
여섯번째  명령어    실행할 명령을 한줄로 쓴다.
------    --------  ---------------------------------------------------


예) 5  */2 *  *  * 명령어 => 매일 2시간간격으로 5분대에 

Posted by yongary
,

mysql Enum

BACK-END 2017. 2. 20. 15:35

(테이블 생성시)

  `type` ENUM('paid', 'free') NOT NULL,


(Insert 시) 'String'을 넣거나 index 숫자를 넣을 수도 있음.




Enum 전반적인 설명-REF1:

   

  - 잘못된 값 삽입시 "" 이 삽입됨. index=0

  - NULL은 index도 null임

  - 일반적인 index는 1부터 시작됨. 



Enum을 Where절에 사용:  REF


  -  index 사용시에는 잘 되지만, 일반적으로 사용시에는 string순서로 비교된다.


Posted by yongary
,

MySql Row Lock

Spring 2017. 2. 19. 23:14

InnoDB Lock: REF



엔진확인 

   mysql> show engines;

   mysql> show variables;   (autocommit등의  Variables 확인) 



Spring 의 @Transactional과 함께 사용하면 autcommit이 일반적으로는 자동으로 풀렸다가 다시 설정 된다..  REF(Stack-overFlow)  REF



=======================================


Mysql에서 엔진이 innodb(요즘 보통다 이러함)일 경우, row level lock이 지원된다.REF


- start transaction   -> 작업 ->  commit 순으로 수행하면 된다.


start transaction;

select * from sales_item where id=99  lock in share mode;

commit; 



transaction도중에 다른 작업이 또 들어오면

  1. wait이 되거나 (위 REF 참조)

  2. 자동으로 에러가 나서 거절이 되는데..  

(1,2번 중 원하는 데로 선택을 어떻게 하는지 ... 연구 중)



 select for update도 있긴한데.. 한 문장 밖에 안되므로 좀 활용도가 떨어지지만
 spring의 @Transactional과 같이 사용하기에 유리하다.    REF


일단 설정 파일에서
init_connect = 'set autocommit=0'
으로 설정하여 오토커밋을 해제합니다. 기본적으로 mySQL 설치 시엔 오토커밋일 설정되어 있습니다



innodb_lock_wait_timeout 확인 방법.

show variables like '%wait_timeout%';

Posted by yongary
,

MockMvc결과가 문자열 json일 때 쉽게 체크하는 법은 jsonPath를 사용하는 방법. REF



그러나, 결과가 Attribute내에 Object 등으로 오는 경우가 많은데..

이럴 경우에는 org.hamcrest.Matchers 를 사용하면 좋다.



<Attribute가 단순 String일 경우>

.andExpect(model().attribute("ReserveResult", org.hamcrest.Matchers.containsString("rtncd=0000")));



<(result내의 Model)  AttributeJson Object일 경우> org.hamcrest.Matchers.CustomMatcher를 사용한다.

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

//Check if rtncd="0000"
Matcher< ResultClass > resultMatcher = new CustomMatcher< ResultClass >("") {
public boolean matches(Object object) {
return ((object instanceof ResultClass) && ((ResultClass) object).getRtncd().equals("00"));
}
};

mockMvc.perform(request)
.andDo(print())
.andExpect(status().is3xxRedirection())
.andExpect(model().attribute("reserveResult", resultMatcher));


Posted by yongary
,

<module-js> REF

Single Page Web Application에서 표준화를 해주는 라이브러리이다.

아래의 browserify와 함께 스면 좋다. 




<browserify> REF


  node코드들을 browser에서도 쓸 수 있게 해주는 library이다.


    간단히 설치:

    $npm install -g browserify 


  대표적으로   require('modules') 코드를 script 안에서 많이 쓴다.


Posted by yongary
,


========node와 연계해서 빌드도 가능===========REF

spring과 npm을 연계해서 빌드시에,


$npm run build:js  등으로 package.json을 이용해 직접 build명령을 내릴 수도 있다.



npm  REF

  - npm은 필요모듈 설치시, 글로벌설치/로컬설치 가능. 일반적으로는 로컬설치가 좋지만 선택이 어려울경우가 있다.

   

npm 환경설정 npm   


각종  npm 패키지 명령:  REF

   - npm list browserify

   - npm view browerify version ( 최신버전확인)

   - npm remove browserify

   - npm install (-g) browserify   (-g: global)




<빌드 LifeCycle>: REF

default 빌드 LifeCycle은 다음과 같다.

  • validate - validate the project is correct and all necessary information is available
  • compile - compile the source code of the project
  • test - test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package - take the compiled code and package it in its distributable format, such as a JAR.
  • verify - run any checks on results of integration tests to ensure quality criteria are met
  • install - install the package into the local repository, for use as a dependency in other projects locally
  • deploy - done in the build environment, copies the final package to the remote repository for sharing with other developers and projects.


아래와 같이 springBoot 실행도 가능.

$mvn springboot run  REF


------------------------------------------------------------------------------------------------------------


=====maven 확인========  REF

$mvn -version


없으면 mac의 경우에는 brew install maven



=======BUILD+package=============== REF

$mvn package


빌드 에러메시지를 상세히 보고 싶다면


$mvn -e -X package  




===기본설명===

spring 에서   pom.xmL을 이용해 maven 의존성 관리를 한다.


maven을 직접사용하는 방법도 있는데

maven 설치 후


mvn archetype:generate     해서 각종 값을 넣고 나면 (주로  package 명으로 넣으면된다)

pom.xml까지 자동 생성이 되며,


mvn compile exec:java -Dexec.mainClass=com.ky.App

 으로 바로 커맨드 상에서 실행한다.


매우 유용하다. 



=== MOJO ============


MOJO : Maven plain Old Java Object 이다.    REF

            - maven의 java-plugin을 만드는데 사용된다.


만들때는 @Mojo를 써서 간단히 만들 수 있다는데, 만들일 은 잘 없고.. 쓸 일은 많으니.. .. 쓸 때 위주로 보면.


groupIdThis is the group ID for the plugin, and should match the common prefix to the packages used by the mojos
artifactIdThis is the name of the plugin
versionThis is the version of the plugin
packagingThis should be set to "maven-plugin"
dependenciesA dependency must be declared to the Maven Plugin Tools API to resolve "AbstractMojo" and related classes


plugin내의  mojo를 실행시키려면  

  - "$mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi" 로도 가능하다.

       ($mvn groupId:artifactId:version:goal )


Posted by yongary
,

RestOperations

springBoot gradle 2017. 2. 6. 21:59

spring 컨트롤러나 서비스 등의 안에서, 웹 서비스를 접속할 필요가 있을경우 RestTemplate(혹은 RestOperation)을 이용하면 편리하다.

REF


get/post

    For

Object/Entity 의 형태로 함수명이 존재한다.


즉 결과를 Object형태로 받을 수도 있고, Entity형태로 받을 수도 있다. 


파라미터로

-Object, Map, ClassType 등을 다양하게 이용할 수 있다.



patch/update/delete/option 함수들도 존재한다. 

Posted by yongary
,

간단한 테이블 디자인은 bootstrap css 에서 가져다 쓰는게 최선인것 같다.


기본적으로 column은 12column을 기본으로 하므로,  12안에서 나누어쓰면 된다.

관련해서 bootstrap은 크기별 이름명명 규칙이 있다.   REF



테이블 디자인 class도 사전에 정의되어 있다.  REF

Posted by yongary
,

@Cacheable

springBoot gradle 2017. 1. 21. 22:42

REF   REF한글


REF_NEW(good config)


spring에서

@Cacheable


@Cacheevict


@Cacheput 


을 이용해서 각종 조건을 지정하면서... 함수 리턴결과 등을 cache할 수 있다.


단, Cacheable등은 proxy형태의 AOP이므로, 별도 class를 만들어서 추가해야 한다.


@CacheConfig(cacheNames = CacheManagerConfig.DEFAULT_CACHE_NAME) public class ForCacheService {

@Cacheable(key = "'myCache'")
public Optional<Something> findSomething(){
return db.findSomething();
}

@CacheEvict(key = "'myCache'")
public void clearCache() {
log.info("clear cache: key=myCache");
}

}

 ==> 음 Optional은 serialize가 안되서 Cache가 안되는 문제 발견.

일반 class 일 경우에도 implements Serializable을 해야 한다.




null Value가 cache가 안되도록 하려면  다음과 같이 #unless를 이용하면 된다.  REF

  (unless는 함수가 실행된 이후에 평가됨.  즉, cache가 있을때는 상관없이 pass.)


@Cacheable( key="'myCache'", unless="#result == null")
public Person findPerson(int pk) {
   return getSession.getPerson(pk);
}


null Value도 cache가 되도록 하고 싶으면? ==>안됨.


Posted by yongary
,

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
,

jackson (ObectMapper)

java core 2016. 12. 7. 17:49

Java 용 json parser로 가장 많이 사용되는 것이 jackson이 아닐까 싶다. : REF

 

jackson2 가 spring 4에 포함되면서,  RestController같은 경우 Object만 return 하면 자동으로

    MappingJackson2HttpMessageConverter에 의해 json으로 변환된다. : REF 

    ( 단, 모든 member변수에 gettersetter가 있어야 한다 - 이게 귀찮으니.. Lombok이 쓸만하다)

 

 

(복잡한 List<Object> 사용시에는 는)

     itemList = objectMapper.readValue(StringData, new TypeReference<List<MenuItemVo>>() {});

 

 

 

간단한 사용법은 다음과 같다. 

 

 

클래서 선언이 다음과 같을 때,

class MyObject{

String name;

int age;

}

 

import com.fasterxml.jackson.databind.ObjectMapper;

<json ->  java Object 방법>

 

   ObjectMapper mapper = new ObjectMapper();

   MyObject my = mapper.readValue ( file or URL or String , myObject.class);

  

   

 

<java Object -> json 방법>

  

  MyObject my = new MyObject("name", 12 );

  String jsonStr = mapper.writeValueAsString ( myObject )

  

  결과는 

  {"name":"name", "age":12 } 로 되는데

 

  좀 이쁘게 개행도 포함하고 싶으면

  String jsonStr = mapper.writeWithDefaultPrettyPrinter().writeValueAsString ( myObject );   으로 한다.

 

 

<변수명이 좀 다를때>

objectMapper.setPropertyNamingStrategy(     PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);

20년에 위에껀 deprecated되고. 아래와 같이 하면 snake_case 를 camelCase로 변환됨. 단 snake_case는 소문자임.

    @Data
    public static class Camel {
        String userName;
    }

    @Test
//    @Tag("excludeBuild") //테스트시 comment 필요.
    public void mapperTest() throws Exception{
        
        ObjectMapper mapper1 = new ObjectMapper().setPropertyNamingStrategy(
                PropertyNamingStrategy.SNAKE_CASE);
        Camel camel1 = mapper1.readValue ("{\"user_name\":\"Kim\"}", Camel.class );

        log.info("Camel1:" + camel1);

개선: 아래로 하면 대문자도 되는 듯

+        mapperDome.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());

 

 

spring등에선 @JsonProperty로 변환용 변수명을 설정할 수 있지만,여러개일 경우 PropertyNameStrategy 설정이 매우 유용하다.

<null은 제외>

@JsonInclude(JsonInclude.Include.NON_NULL) 

<LocalDateTime 변환>

@JsonSerialize(using = LocalDateTimeJsonSerializer.class) : Custom Serializer 이용. 

public class LocalDateTimeJsonSerializer extends JsonSerializer<LocalDateTime> {
    private static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS =
            DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");

    @Override
    public void serialize(LocalDateTime localDateTime,
                          JsonGenerator jsonGenerator,
                          SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(localDateTime.format(YYYY_MM_DD_HH_MM_SS));
    }
}

 

<Object Copy>

import org.apache.phoenix.shaded.org.apache.commons.beanutils.BeanUtils;

 

try {

 //멤버type과 이름이 딱맞는 애들만 쭉 copy해준다.

BeanUtils.copyProperties(destObj, srcObj);  

} catch (Exception e) {

e.printStackTrace();

Posted by yongary
,

Service-as-a-VM & Docker

Spring 2016. 12. 3. 03:34

서비스를 개발하다 보면, 여러개의 서브-서비스로 나누어지게 되고 개발도 따로 하게되는 문제가 있지만,

배포에서 큰 문제가 된다. java version이 다르다던가 하는 사소한 문제부터 복잡한 수많은 문제가 생기게 되면서

배보다 배꼽이 큰, 즉 개발보다 deploy가 더 어려워지는 경우도 발생이 되기 때문에,


이런문제를 해결하는 개념으로 Service-as-a-VM 이 등장하였다.

(넷플릭스에서는  AMI 패키지 방식으로 아마존EC2에 배포를 한다) AMI=아마존 머신 이미지.



 그러나, 

VM자체도 부하가 크고 배포도 상당히 어렵기 때문에,  

간단한 파일로 배포를 하고, 프로세스 형태로 동작하는 가벼운  Docker 가 훨씬 더 유리하게 되면서

spring-boot 에 Docker를 결합한 방법이 많이 사용되고 있다.  REF(source 포함)




<Docker>한글REF REF

 


Docker image는 read-only 파일시스템이다. 

   layer  구조라서 배포시에 없는 layer만 배포하면 되고, 이미지 생성도 필요한 것만 되므로 매우 빠르다


Docker container 는 1개 또는 몇개의 sandboxed process로 이루어진  running image이다.  즉 프로세스라고 보면 된다.

  container 단위로  포트 등이 격리가 된다.  



Posted by yongary
,