27 Apr 2017
|
atom
regex
Atom을 쓰다보면 문자열 치환을 자주 쓰게 되는데 이 포스팅은 정규표현식을 사용하여 치환하는 방법을 소개합니다.
Atom에서 Ctrl+f를 누르게 되면 아래 그림과 같이 Find/Replace 창이 나타나는에 우측에 .*표시를 누르면 정규표현식 검색이 활성화 됩니다.

이제 Find영역에 정규표현식을 통해 검색하게 되면 문서에 검색된 부분이 표시가 됩니다.

수정할 내용으로 Replace영역에 넣고 Replace,Replace All로 바꿀수 있습니다.

이 때 검색된 내용을 버퍼로 사용하여 수정할 수 있는데 방법은 아래와 같습니다.
- Find의 정규표현식에 버퍼로 둘 검색 부분을 괄호
()처리
- Replace 영역에 버퍼를 달러
$로 지정하여 사용
- 예시 : Find :
^([a-z]+)[0-9] , Replace : Word $1
아래 그림과 같이 버퍼를 이용하여 수정할 경우 기존 검색 내용의 일부를 그대로 사용할 수 있습니다.

26 Apr 2017
|
springboot
ehcache
logback
yaml
yml
configurationProperties
Springboot는 개발속도를 향상 시켜주는 많은 장점을 가지고 있습니다.
application.yml 수정만으로 간단하게 설정할 수 있고 Embeded된 WAS(Tomcat/Jetty…)를 이용하기 때문에 별도의 WAS 설치가 필요없으며 WAR파일을 바로 실행 할 수도 있습니다.
빠르게 개발/배포 하기 위해 Springboot를 자주 쓰는데 WAR파일 형태로 배포후 쉘 스크립트를 통해 실행하는 로직을 주로 쓰다보니 이미 설치된 프로그램에 간단한 설정을 바꿀때마다 다시 WAR파일을 묶어야 하는 불편함이 있었습니다.
변경 사항 발생시 설정파일만 수정하고 재시작만 하면 반영되도록 각 설정들을 외부로 뺀 방법을 정리해봅니다.
외부 경로 참조
classpath 외부의 파일을 참조할 수 있도록 프로그램 시작시 System Property에 특정 경로를 넣어줍니다.
application.yml
Springboot 기본 설정파일에는 아래와 같은 원칙으로 설정을 남겨두었습니다.
- 프로그램 코드 수정이 필요한 경우에만 수정된 설정
- 운영/개발/테스트 시 마다 다른 설정이 필요한 경우
Springboot는 spring.profiles.active 옵션에 따라 기본 설정파일을 아래와 같이 사용 가능합니다.
| spring.profiles.active |
참조 application 파일 |
| 미설정 |
application.yml application-default.yml |
| 설정(ex: dev) |
application-dev.yml |
| 설정(ex: real) |
application-real.yml |
그 외 설정
위 application.yml에 해당되지 않는 변경 가능한 다른 설정은 외부(ex:conf.home하위)에 위치하고 WAS로딩시 해당 설정을 읽도록 하였습니다.
저의 경우 yml파일만 사용하도록 통일하였기 때문에 아래와 같이 해당 경로의 모든 yml파일을 읽어와 PropertySource로 사용하도록 하였습니다.
- yml과 xml을 같이 사용했더니 인코딩 문제 때문에 잘 안되더군요. (해결을 못했습니다.)
- 아래 메소드가 static이기 때문에
@Value어노테이션을 이용하여 가져 올 수가 없어 System.getProperty를 사용하였습니다.
@Configuration
public class PropertyConfiguration
{
private static String confHome = System.getProperty("conf.home");
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() throws IOException
{
FileSystemResource[] list = Files.list(Paths.get(confHome))
.filter(path -> {
File file = path.toFile();
return file.exists() && file.isFile()
&& ... // file이 yml / yaml 확장자인지 검사
})
.map(path -> new FileSystemResource(path.toFile()))
.toArray(size -> new FileSystemResource[size]);
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(list);
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
}
yml파일을 PropertySource로 사용하기 위해서는 YamlPropertiesFactoryBean을 사용해야하며 위와 같이 설정시 각 설정값을 List<T>나 Map<K,V>와 같은 컬렉션 형태로 받아 올 수 있습니다.
yml파일이 아래와 같을 경우
custom:
custom-info:
name :
- name1
- name2
phone :
- 010-123-1234
- 010-111-2222
...
아래와 같이 @ConfigurationProperties어노테이션을 이용하여 받아올 수 있습니다.
@Component
@ConfigurationProperties(prefix = "custom")
public class CustomProperties
{
private Map<String, List<String>> customInfo = new HashMap<>();
}
주의사항으로 SpringSecurity와 같이 사용할 경우 security prefix는 이미 SpringSecurity에서 사용하고 있으며 SecurityProperties Bean이름 역시 미리 정의 되어 있으니 주의 하시기 바랍니다.
Logging 설정(logback)
Logback의 경우 application.yml에서 경로를 지정하여 외부파일을 참조하게 할 수 있습니다.
이 때 위에서 System Property에 설정 한 외부경로를 사용 할 수 있습니다.
logging.config: ${conf.home}/logback.xml
Cache설정(ehcache)
Cache의 경우 종류에 따라 각각 설정방법이 다른데 EhCacheManagerFactoryBean을 이용하여 외부 파일을 참조하는 방법을 써 보았습니다.
@Configuration
@EnableCaching
public class EhCacheConfiguration
{
@Value("${conf.home}") private String confHome;
@Bean
public CacheManager cacheManager()
{
return new EhCacheCacheManager(ehCacheCacheManager().getObject());
}
@Bean
public EhCacheManagerFactoryBean ehCacheCacheManager()
{
EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
cmfb.setConfigLocation(new FileSystemResource(Paths.get(confHome + "/ehcache.xml").toFile()));
cmfb.setShared(true);
return cmfb;
}
}
04 Apr 2017
|
docker
apache
ssl
Dockerfile을 이용하여 자동화 하여 모든 배포를 끝내려했으나 아래와 같은 이유로 한방 배포가 불가능했습니다.
- certbot 실행시 입력 커맨드 처리 불가
- 중간에 Y/N을 입력하는 처리가 나오는데 자동으로 처리 불가
- apache 자동실행 불가
- service의 start 커맨드가 불통
- docker run 실행으로 컨테이너 생성시 FOREGROUD 로 실행하도록 인자값을 추가할 경우 컨테이너가 stop된 이후에 다시 start하면 이미 httpd가 떠있다고 오류 메시지를 뱉으며 실행되지 않는다.
아마 다른 해결책이 있을것 같긴한데 찾지 못해서 위 두가지 문제를 해결하기 위해 다음과 같은 방식으로 생성하였습니다.
Dockerfile build
[Dockerfile]
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y apache2
RUN apt-get install -y software-properties-common
RUN add-apt-repository -y ppa:certbot/certbot
RUN apt-get update
RUN apt-get install -y python-certbot-apache
RUN a2enmod ssl
RUN service apache2 start
RUN cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-available/[DOMAIN].conf
RUN sed -i 's/\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/\/etc\/letsencrypt\/live\/[DOMAIN]\/cert.pem/g' /etc/apache2/sites-available/[DOMAIN].conf
RUN sed -i 's/\/etc\/ssl\/private\/ssl-cert-snakeoil.key/\/etc\/letsencrypt\/live\/[DOMAIN]\/privkey.pem/g' /etc/apache2/sites-available/[DOMAIN].conf
RUN sed -i 's/#SSLCertificateChainFile/SSLCertificateChainFile/g' /etc/apache2/sites-available/[DOMAIN].conf
RUN sed -i 's/\/etc\/apache2\/ssl.crt\/server-ca.crt/\/etc\/letsencrypt\/live\/[DOMAIN]\/fullchain.pem/g' /etc/apache2/sites-available/[DOMAIN].conf
EXPOSE 22 80 443
수작업을 최소화 하기 위해 Dockerfile에서 할 수 있는 모든 작업을 미리 하고 build명령을 통해 image를 생성합니다.
$sudo docker build --tag [REPOSITORY]:[TAG] [Dockerfile PATH]
Container 수작업 후 commit
docker run 커맨드를 통해 컨테이너를 생성하고 추가 작업을 진행합니다.
$sudo docker run -it -p 80:80 -p 443:443 --name [CONTAINER_NAME] [REPOSITORY]:[TAG] /bin/bash
컨테이너 안에서 아래 명령을 실행합니다.
$certbot --apache -d [DOMAIN] -m [E-MAIL] --agree-tos
$a2ensite [DOMAIN]
$service apache2 reload
‘https://[DOMAIN]/’ 에 접속하여 Apache가 정상적으로 뜨는지 확인하고 docker commit 명령을 통해 변경된 Image를 생성합니다.
$sudo docker commit -a [AUTHOR_INFO] -m [MESSAGE] [CONTAINER_NAME] [REPOSITORY]:[TAG]
생성된 이미지를 통해 Docker 실행및 Apache 실행
docker run 커맨드를 통해 컨테이너를 생성하되 Apache 자동실행 옵션은 start/stop 시에도 오류없이 동작하기 위해 추가 아규먼트 없이 기본 생성후 컨테이너를 내리고 실제 컨테이너 부팅시 start 커맨드와 함께 exec 커맨드를 통해 추가로 Apache를 실행할 수 있도록 shell 스크립트 파일을 만들었습니다.
[create-container.sh]
#!/bin/bash
sudo docker run -it -d --name [CONTAINER_NAME] -p 80:80 -p 443:443 [REPOSITORY]:[TAG]
sudo docker stop [CONTAINER_NAME]
[run-container.sh]
#!/bin/bash
nohup sudo docker start [CONTAINER_NAME] > /dev/null 2>&1
sudo docker exec -d [CONTAINER_NAME] /bin/bash -c '/usr/sbin/apache2ctl -D FOREGROUND'
참고
certbot : https://certbot.eff.org/#ubuntutrusty-apache
[Docker] Container run 이야기 : https://bestna.wordpress.com/2014/11/10/docker-container-run-%EC%9D%B4%EC%95%BC%EA%B8%B0/
28 Mar 2017
|
recursive
hanoi
재귀호출 알고리즘중 대표격인 하노이탑 알고리즘에 대한 Java 샘플입니다.
하노이탑에 대한 설명은 워낙 많기 때문에 아래 링크로 대체합니다.
하노이탑 - 위키백과
문제 풀이 방식
다양한 원리와 방식에 대한 설명들이 많은데 저는 다음과 같이 단순히 생각해보았습니다.

위와 같은 하노이탑중 4번 블럭을 3번째 위치로 옮기기 위해서는 아래와 같이 1,2,3번블럭을 모두 2번째 위치로 옮겨두면 가능합니다.

그리고 위 그림처럼 3번 블럭을 2번째 위치로 옮기기 위해서는 1,2,번블럭을 아래와 같이 3번 위치에 옮기면 됩니다.

위와 같이 하나의 블럭을 옮기기 위한 원리는 “해당 블럭 위에 있는 블럭을 임시 위치에 두고 해당 블럭을 옮긴다”가 되며 그 원리를 구현한 소스는 아래와 같습니다.
public static void move(Integer target, Stack<Integer> srcStack, Stack<Integer> destStack, Stack<Integer> bufferStack)
{
if (target == 1)
{
moveBlock(srcStack, destStack);
return;
}
move(target-1, srcStack, bufferStack, destStack);
moveBlock(srcStack, destStack);
move(target-1, bufferStack, destStack, srcStack);
}
private static void moveBlock(Stack<Integer> srcStack, Stack<Integer> destStack)
{
destStack.push(srcStack.pop());
}
위 로직을 실행하면 아래와 같이 동작하게 됩니다.

전체소스 경로 : (https://github.com/jistol/sample-algorithm/tree/master/hanoi)[https://github.com/jistol/sample-algorithm/tree/master/hanoi]
27 Mar 2017
|
markdown
jekyll
기존 Github Page에서 코드라인의 문법 하이라이팅 방법은 아래 방법을 사용했었습니다.
{% highlight java %}
public static void main(String… args)
{
System.out.println(“Hello World.”)
}
{% endhighlight %}
위 방식은 Jekyll에서 사용할 수 있는 liquid tag 방식으로 이렇게 사용할 경우 Jekyll서버상에서는 예쁘게 변경되어 보이나, 문서 작업시 Atom Editor의 미리보기에서는 아래와 같이 문자열로 보이게 됩니다.

Atom Editor 미리보기에서도 하이라이팅된 코드를 보고 싶을 경우 아래와 같이 코드블럭을 통해 쓸 수 있습니다.
```java
public static void main(String… args)
{
System.out.println(“Hello World.”)
}
```

사용가능한 하이라이팅 포맷은 c, java, bash, sql, html, js, scala, xml… 등 다양하며 전체 포맷은 Syntax highlighting in markdown 링크를 참고 하시기 바랍니다.