본문으로 건너뛰기

MomentJS 활용법

· 약 2분

java에 joda-time이 있듯 javascript에는 moment가 있다. 기초적인 moment 사용법은 알고 있다고 가정한다.

calendar

현재시각과 비교해 날짜를 어제 오후 12:31처럼 표시하고 싶은 경우 사용한다.

소스

moment(date).calendar(today, { sameElse: "YYYY-MM-DD HH:mm:ss" });

date는 비교할 날짜, today는 현재시각 값이다. 일주일 이하일 경우 어제.. 그저께.. 등으로 반환되고, 이상일 경우 sameElse에 등록된 포맷으로 반환된다.

global locale 설정을 지정하지 않았을 경우 sameElse가 들어가는 option object 안에 locale을 커스터마이징 할 수 있다.

기타 옵션은 API 참조

diff

A에서 B의 차이를 구할 때 쓰는 diff method를 쓰다가, 월 또는 년도의 차이를 계산하는 경우가 생긴다.

소스

worst case

moment("2016-06").diff("2015-01", "month");

이렇게 처리하면 되지 않을까? 동작은 하지만 오류가 날 수 있다고 console.warning 이 찍힌다.

good case

moment([2016, 6]).diff([2015, 1], "month");

실행이 잘되지만, YYYY-MM을 split해서 넣어줘야하는 번거로움이 있다.

best case

moment("2016-06", "YYYY-MM").diff("2015-01", "month");

moment 형식으로 변환시 두번째 파라미터에 포맷을 지정하면 console.warning도 없고 번거로움도 사라진다!

Materialize pickadate 설정

· 약 2분

기본예제는 type="date" 로만 설정이 되있어서 type="text"에도 적용 가능하게 onSet callback 을 설정했고, 한글로 보이게 수정했다.

소스

<input type="text" name="date" class="date" />

<script>
$(function () {
// pickadate 옵션 전역설정
$.extend($.fn.pickadate.defaults, {
monthsFull: [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월",
"7월",
"8월",
"9월",
"10월",
"11월",
"12월",
],
monthsShort: [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월",
"7월",
"8월",
"9월",
"10월",
"11월",
"12월",
],
weekdaysFull: ["일", "월", "화", "수", "목", "금", "토"],
weekdaysShort: ["일", "월", "화", "수", "목", "금", "토"],
selectMonths: true,
selectYears: 140,
showMonthsShort: false,
showWeekdaysFull: false,
close: "닫기",
clear: false,
today: "오늘",
format: "yyyy-mm-dd",
formatSubmit: "yyyy-mm-dd",
max: true, // 이 옵션이 ture면 오늘까지밖에 날짜 선택을 못한다
closeOnSelect: true,
onSet: function (e) {
if (e.select) {
this.close();
}
},
});

// 활성화
$(".date").pickadate();
});
</script>

결과

image from hexo

Express 환경에서 node_modules 안의 script 사용

· 약 1분

앵귤러 또는 다른 브라우저에 필요한 스크립트를 npm 으로 설치하고 node_modules 안에 있는 스크립트로 참조하고 싶을 때 다음과 같이 라우팅을 추가한다.

소스

// scripts 경로로 접근시 node_modules을 사용할 수 있게 설정
app.use("/scripts", express.static(path.join(__dirname, "node_modules")));
<!-- 결과 -->
<script src="/scripts/angular/angular.min.js"></script>

Windows10에서 NodeJS MariaSQL 모듈 설치

· 약 3분

오류

mariasql package 설치 명령어 실행시 오류를 내뿜으며 node-debug.log 를 확인하라고 명령어가 나올 경우 아래와 같이 하면 된다.

debug log 에는 node-gyp rebuild 를 하라고 나오는데, 이 오류메세지와는 아무 관련이 없다.

해결

Python 2.7 설치

윈도우에 Python 2.7 버전이 설치되어있지 않으면 설치해야한다. 파이썬 2 이상 3 미만 버전을 쓰면 되는데, 2.7 을 강조하니 쓰자.

여기서 다운로드 한다. 설치시 Window PATH 등록 옵션을 꼭 선택해야한다.

Python 경로를 npm 에 등록

npm config set python "/the/python/path" --global

the/python/path 에 자신의 python 설치 경로를 넣어주자.

Microsoft Visual Studio Community 2015 설치

왜 VS 2015 를 설치해야하지? 라고 생각이 들텐데, **Visual C++**을 사용하기 때문이다.

여기서 다운로드한다. 설치시 프로그래밍언어 탭에서 Visual C++을 꼭 선택해서 설치해야한다.

기존에 VS2015 가 설치되어있는 경우, 프로그램 추가/삭제에서 선택 후 수정 메뉴를 눌러 Visual C++ 옵션을 추가한 뒤 업데이트해준다.

2017 년 기준 위 링크가 만료되어 cpp-build-tools를 설치해야한다

Visual Studio 버전을 npm 에 등록

npm config set msvs_version "2015" --global

MariaSQL Package 설치

npm install mariasql --save

여담

Windows10 에서 mariasql package 설치시 C++ 컴파일이 필요하니, VS2015 로 C++ 컴파일러를 설치해야된다라는 걸 msdn 이나 npm 에 친절히 남겨줬으면 이렇게까지 시간을 날리지 않았을텐데...

최근 해결방법

빠르고 위의 오류가 절대 발생하지 않는 mysql2 패키지를 사용하면 된다.

image from hexo

Cannot find module '../build/Release/bson'

· 약 2분

mongoose-post-find 모듈 사용시 bson 라이브러리를 찾지 못해 설치가 안되는 경우가 있다.

오류

{ Error: Cannot find module '../build/Release/bson'
at Function.Module._resolveFilename (module.js:440:15)
at Function.Module._load (module.js:388:25)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
// 여기서 오류가 발생한다
at Object.<anonymous> (your project\mongoose-post-find\node_modules\bson\ext\index.js:15:10)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
at Object.<anonymous> (your project\mongoose-post-find\node_modules\bson\lib\bson\index.js:3:24)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32) code: 'MODULE_NOT_FOUND' }
js-bson: Failed to load c++ bson extension, using pure JS version

해결

해당 패키지 경로의 15번째 줄을 따라가보면 bson 패키지의 경로를 지정해주는 부분이 있는데, 이 부분을 같은 패키지 내의 bson 경로로 일치시켜주면 된다.

bson/index.js
let bson = null;

try {
// Load the precompiled win32 binary
if (process.platform == "win32" && process.arch == "x64") {
bson = require("./win32/x64/bson");
} else if (process.platform == "win32" && process.arch == "ia32") {
bson = require("./win32/ia32/bson");
} else {
bson = require("../build/Release/bson");
}
} catch (err) {
// Attempt to load the release bson version
try {
// 여기의 상대경로를 같은 패키지의 bson의 경로로 일치시켜주면 된다.
bson = require("../browser_build/bson");
} catch (err) {
console.dir(err);
console.error(
"js-bson: Failed to load c++ bson extension, using pure JS version",
);
bson = require("../lib/bson/bson");
}
}

React 시작하기

· 약 4분

ES6 과 this binding 에 대한 이해

ES5 스타일로 React 를 사용할 수 있지만 JSX 를 사용하기에 한 번은 컴파일이 필요하다. 따라서 ES6 의 문법을 사용하는게 낫다. (직관적이기도 하고) 그래서 ES6 의 문법이 익숙해져야하고, javascript 에서 this 를 왜 바인딩 하는지에 대한 이해가 필요하다.

JSX 이란

React 를 제대로 사용하기 위해서는 JSX 라는 새로운 구문(확장자)로 javascript 를 짜야하는데, JSX 는 XML 스타일의 자바스크립트 표현식이라고 생각하면 된다. 브라우저에서 돌아가게 하려면 순수한 자바스크립트 형태가 되어야 하기 때문에 컴파일이 필요하다.

React 구버전은 JSXTranspiler 를 통해 변환을 했는데, 지금은 지원하지 않고 Babel을 사용해 컴파일 해야한다.

Babel 이란

Babel 은 ES6 의 구문을 구버전의 브라우저에서 사용할 수 있게 컴파일해주는 자바스크립트 컴파일러라고 생각하면 된다. 추가적으로 JSX 도 컴파일해준다.

NodeJS 환경에서는 Gulp 를 이용해 자동으로 컴파일이 되게 설정할 수 있지만, 브라우저에서 단독으로 사용할 수 있게 해보는 방법을 알아보자.

설치

## bower
$ bower install babel-standalone --save
## npm
$ npm install babel-standalone --save

또는 여기서 직접 받는다.

React

설치

## bower
$ bower install react --save
## npm
$ npm install react --save

또는 여기서 직접 받는다.

실행

<script src="/bower_components/babel-standalone/babel.min.js"></script>
<script src="/bower_components/react/react.min.js"></script>
<script src="/bower_components/react/react-dom.min.js"></script>

<script type="text/babel" src="/react_login_form.jsx"></script>

babel 과 react, 데이터 바인딩을 위한 react-dom 을 가져온다.

그리고 react_login_form.jsx 를 text/babel 타입으로 가져오면 된다.

예제

// 리액트에 넣을 모듈을 선언한다.
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = { id: "", pw: "" };
}

// input의 데이터가 변할 때 state의 값이 변경할 수 있게한다
handleChange(key, event) {
this.state[key] = event.target.value;
this.setState(this.state);
}

handleSubmit(event) {
console.log(this.state);
// 여기에 ajax 호출을 구현하면 된다
// $.ajax().then(function(){
// this.setState와 같은 상태변경 처리
// }.bind(this));
event.preventDefault();
}

render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
아이디 :
<input
type="text"
value={this.state.id}
onChange={this.handleChange.bind(this, "id")}
/>
비밀번호 :
<input
type="password"
value={this.state.pw}
onChange={this.handleChange.bind(this, "pw")}
/>
<input type="submit" value="Submit" />
</form>
);
}
}

// LoginForm class를 id="login"에 render
ReactDOM.render(<LoginForm />, document.getElementById("login"));

여담

주관적으론 데이터 바인딩을 위해서만 사용하려면 Vue를 사용하는게, 완벽한 SPA 를 만들고 싶다면 역시 Angular2가 답인듯 싶다.

추가로 React 와 Angular2 의 비교를 보길 원한다.

CentOS Maria DB 설치

· 약 4분

Maria DB 를 써야하는 이유는 MySQL 이 지원이 끝났기 때문이고, 오라클이 소유하고 있어 언제 유료화가 될지 모르고, Thread Pool, 강화된 스토리지 엔진 (InnoDB -> XtraDB), 새로운 스토리지 엔진 (Aria, Cassandra)과 HandlerSocket, Virtual Column 등의 새로운 기능이 있기 때문이다.

설치를 시작해보자!

버전 확인 후 yum repo 추가

버전 및 bit 확인

## get version
$ cat /etc/*release*
## get bit
$ getconf LONG_BIT

yum repo 복사

maria로 이동해 맞는 버전을 추가한다.

image from hexo

yum repo 추가

vi /etc/yum.repos.d/MariaDB.repo

명령어로 MariaDB repository 를 생성한 뒤 복사한 내용을 붙히고 저장한다.

설치

yum install -y MariaDB-server MariaDB-client

혹여 설치가 안되면 maria 문서를 참고해서 따라해보자 (영어)

부팅 서비스 등록

$ chkconfig mysql on
## 또는
$ chkconfig --add mysql
$ chkconfig --level 345 mysql on

## 등록 확인
$ chkconfig --list mysql

maria에서는 345 레벨을 on 하라고 했는데, chkconfig mysql on 으로 실행시켜 2345 레벨을 모두 on 시켰다. 2 레벨은 not networking 이라 DB 의 원격지 접속이 안될테니 off 시켜도 무관하다.

서비스 실행

service mysql start

Starting MySQL.... [ OK ]

Maria 의 서비스명은 MySQL 로 뜬다.

Config 파일 수정 및 통합

처음 설치시 my.cnf 에서 my-server, my-client 등의 파일을 임포트해 분할 관리하게 되어있는데, 하나로 합쳐보자.

MariaDB 설치 폴더를 들어가면 My innoDB Huge 라는 config 파일이 존재한다. 이걸 그대로 사용해도 되고, 사용자 환경에 맞게 커스터마이징해서 사용해도 된다.

서버의 메모리가 8 GB 이상, innoDB 환경에서 사용가능한 config 파일을 첨부하니 이걸 써도 된다.

Thread Pool 기능을 사용하기 위해 extra_port 를 3307 로 줬다.

소스

my.cnf
[client]
port = 3306
socket = /var/lib/mysql/mysql.sock

[mysqld]
port = 3306
socket = /var/lib/mysql/mysql.sock

character-set-server = utf8mb4
collation_server = utf8mb4_general_ci

back_log = 100
max_connections = 100
max_connect_errors = 10
table_open_cache = 2048
max_allowed_packet = 16M

binlog_cache_size = 4M
binlog_format = row

max_heap_table_size = 16M

read_buffer_size = 2M
read_rnd_buffer_size = 16M
sort_buffer_size = 8M
join_buffer_size = 8M

query_cache_type = 0
default-storage-engine = InnoDB
thread_stack = 256K
tmp_table_size = 16M

secure_auth =1

skip_external_locking
skip_symbolic_links

## Replication related settings
server-id = 1
expire_logs_days = 3
log_slave_updates

## MyISAM Specific options
key_buffer_size = 32M
bulk_insert_buffer_size = 64M
myisam_sort_buffer_size = 8M
myisam_max_sort_file_size = 16M
myisam_repair_threads = 1
myisam_recover = FORCE,BACKUP

## INNODB Specific options
innodb_additional_mem_pool_size = 16M
innodb_buffer_pool_size = 2G
innodb_data_file_path = ibdata1:10M:autoextend
#innodb_data_home_dir = <directory>
innodb_thread_concurrency = 16
innodb_flush_log_at_trx_commit = 0

innodb_log_buffer_size = 32M
innodb_log_file_size = 1024M
innodb_log_files_in_group = 2
#innodb_log_group_home_dir

innodb_max_dirty_pages_pct = 75

[mysqldump]
quick
max_allowed_packet = 16M
default-character-set = utf8

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 512M
sort_buffer_size = 512M
read_buffer = 8M
write_buffer = 8M

[mysqlhotcopy]
interactive-timeout

[mysqld_safe]
open-files-limit = 8192

[mariadb]
## thread pool
thread_handling=pool-of-threads
thread_pool_idle_timeout = 3600
thread_pool_stall_limit = 100
extra_port = 3307
extra_max_connections=10

MySQL Dump 명령어

· 약 1분

MySQL Dump 명령어 사용법

스크립트 생성

vi dump.sh

dump.sh 파일을 만들고 아래 내용을 추가해 준다.

mysqldump -u 유저명 -p비밀번호 데이터베이스명> 경로`date+%y%m%d%H`.sql

스크립트를 원하는 시간대로 cron 에 등록한다.

예제

ID : test, PW: test, DB : test 의 dump 를 생성하고 싶을 때

mysqldump -u test-ptest test> /home/test/dump/`date+%y%m%d%H`.sql

Database 유저 생성 및 권한 설정

· 약 1분

유저 생성

CREATE USER '유저명'@'%' IDENTIFIED BY '비밀번호'; -- 모든 아이피 접근
CREATE USER '유저명'@'localhost' IDENTIFIED BY '비밀번호'; -- 로컬호스트 접근
CREATE USER '유저명'@'127.0.0.1' IDENTIFIED BY '비밀번호'; -- 로컬호스트 접근

데이터베이스에 모든 권한 부여

-- 해당 디비명의 유저의 모든권한 설정
GRANT ALL PRIVILEGES ON 디비명.* TO '유저명'@'%' WITH GRANT OPTION;

권한 적용

FLUSH PRIVILEGES;

권한 확인

SHOW GRANTS FOR '유저명'@'%';

여담

권한 부여는 쉘상에서 접근해야지 오류가 없다.

부분 권한 또는 부분 테이블로 권한을 제한하고 싶다면, MySQL Grant Syntax를 참조한다.

MySQL에서 MariaDB 이관시 서브쿼리의 정렬이 바뀔 때

· 약 2분

@Rownum 변수를 사용해 페이징 쿼리를 구현했는데, MySQL 에서는 정상적으로 정렬이 되다가 Maria 로 이관 후에 정렬이 반대로 나오는 경우가 있다.

오류

쿼리

SELECT SQL_CALC_FOUND_ROWS @RNUM:=@RNUM+1 AS ROWNUM, R.* FROM (
SELECT @RNUM:=0, Q.* FROM (

SELECT * FROM TABLE1
WHERE ID = '1'
ORDER BY REG DESC
) Q
) R
LIMIT 0,10

설명

Rownum 변수를 사용해 TABLE1 에서 최신 날짜 순으로 데이터를 가지고 온다.

해결

LIMIT 2^64-1를 서브쿼리 내에 추가해준다.

LIMIT 의 최댓값은 unsigned 64bit-1 이므로 해당 값을 날려준다.

쿼리

SELECT SQL_CALC_FOUND_ROWS @RNUM:=@RNUM+1 AS ROWNUM, R.* FROM (
SELECT @RNUM:=0, Q.* FROM (

SELECT * FROM TABLE1
WHERE ID = '1'
ORDER BY REG DESC

LIMIT 18446744073709551615
) Q
) R
LIMIT 0,10

원인

Optimizer 가 임시테이블을 만든 후 filesort 하기 때문에 발생한다.