Node.js - 설치하기

1. https://nodejs.org/ko/download/ 사이트에서 Windows Binary (.zip) 파일다운로드

2. 다운로드한 파일을 원하는 위치에 압축 해제 ex) K:\node-v12.16.3-win-x64


3. 압축 해제한 폴더를 환경 변수(Path)에 추가



4. cmd 실행하여 버전 정보가 표시되는 확인

Android - 가비지 컬렉션의 특징

1. 가비지 컬렉션이 발생하는 시점에 대해서 제어할 수 없다.
System.gc() 를 호출하여 안드로이드에 명령을 할 수는 있지만, 최종적으로는 달빅 가상머신이 언제 실행할지를 결정한다.

2. 가비지 컬렉션이 실행되는 상황
- GC_FOR_MALLOC : 힙이 가득차서 메모리를 할당하지 못하고, 할당이 계속 이루어질 수 있도록 메모리가 리클레임되어야 할 때 발생
- GC_CONCURRENT : 컬렉션이 시작되는, 보통은 리클레임할 충분한 오브젝트들이 있을 때 발생.
- GC_EXPLICT : system.gc()를 호출해서 가비지 컬렉션을 명백하게 요청할 때 발생
- GC_EXTERNAL_ALLOC : External native memory alloc이 발생하여 메모리가 full인 경우.
- GC_HPROF_DUMP_HEAP : HPROF 파일을 생성할 때 발생

3. 참고
안드로이드 2.3 이후 버전에서는 가비지 컬렉션 작업이 분리된 스레드에서 실행되므로 이전처럼 모든 앱이 정지되는 현상이 발생되지는 않는다.
하지만 가비지 컬렉션이 일어나면 메인 스레드는 여전히 영향을 받는다. (5ms)

Android - 응답성 강화하기

1. 응답성 강화하기
- 일반적으로 100ms에서 200ms가 사용자가 애플리케이션에서 지연을 느낄 수 있는 경계 지점임
- 벡그라운드에서 뭔가 하고 있으면 ProgressBar와 ProgressDialog를 쓸 것
- 특히 게임에서는, 자식 쓰레드에서 움직임에 대한 계산을 할 것
- 멈춘 것 처럼 인식 하지 않도록 할 것

2. 어떻게 ANR을 피할 것인가?
- 메인 쓰레드에서 실행하는 메소드는 최소한의 일을 해야 함
- 특히 onCreate(), onResume()과 같은 핵심 생명주기 메소드 최소한 작은 일을 수행해야 함
- 네트워크, 데이터베이스 오퍼레이션 같은 잠재적으로 긴 것들은 자식 쓰레드에서 수행
- Thread.wait(), Thread.sleep()는 호출 하지 말 것
- 자식 쓰레드가 완료될 때 알려주기 위한 핸들러를 제공해야 함
- 노티피케이션 매니저를 사용할 것

Android - ANR 이란?

1. ANR이란 무엇인가?
Application Not Responding의 약자이다.
어플리케이션이 응답하지 않는 경우 안드로이드 시스템에서 보여주는 에러이다.
메인 스레드(일명, UI 스레드)가 일정시간 동안 잡혀 있으면 발생한다.

2. 언제 ANR이 발생하는가?
- 터치를 통한 사용자 입력이 5초 내에 처리되지 않았을 때
- 브로드캐스트가 10초 내에 처리되지 않았을 때
- 서비스가 20초 내로 처리되지 않을 때

3. 왜 ANR이 발생하는가?
앱이 무한 루프에 빠지거나 OOM(Out Of Memory)가 나야 ANR이 발생하는 것이 아니다.
시간이 좀 걸리는 처리를 해도 ANR이 충분히 발생할 수 있다.

4. ANR을 피하려면?
- 시간이 오래걸리는 작업은 스레드를 통해 처리하도록 권장한다.
- 사용자에게는 프로그레스바 등을 이용해 진행 과정을 안내해 기다리도록 한다.
- 이를 위해, 안드로이드에서 상속받아 사용할 수 있는 다양한 방법을 제공하고 있다.

Java - 파일 쓰기 성능 비교

1. 자바에서 파일 쓰기 구현시 어떤 방법이 빠른지 테스트.
- FileWriter fw = new FileWriter(LOG_HOME+"writer.log");
- BufferedWriter bw = new BufferedWriter(new FileWriter(LOG_HOME+"writer.log"));
- FileOutputStream fos = new FileOutputStream(LOG_HOME+"outputstream.log");
- BufferedOutputStream fos = new BufferedOutputStream(
               new FileOutputStream(LOG_HOME+"bufferedoutputstream.log"));
- FileChannel fc =
       (new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel();
// Byte Buffer 매번 생성
- FileChannel fc =
       (new FileOutputStream(new File(LOG_HOME+"filechannel.log"))).getChannel();
// ByteBuffer 재사용

2. 테스트 결과
                                                           1K    2K      5K     10K      50K
FileWriter                                               31    32      94     203     1281
FileWriter + BufferedWriter                        15    31      94     188     1000
FileOutputStream                                     32    47    109     188     1063
FileOutputStream + BufferedOutputStream    31    47    109     203     1578
FileChannel                                             47    63    109     219     2906
FileChannel + Byte Buffer 재사용                 31    47    188     250     2766

FileWriter와 FileOutputStream의 성능이 높게 나옴.
BufferedWriter 등의 경우 GC를 유발하는 문제가 있기 때문에 성능 저하 요인이 될 수 있으나, 테스트 결과로는 FileWriter + BufferedWriter의 경우가 성능이 제일 좋음.

Android - 웹뷰 성능 향상

1. 캐쉬 사용하지 않기
webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);로 브라우져 캐쉬를 끈다.

2. 하드웨어 가속 기능 사용하기
렌더링에 대해서 하드웨어 가속 기능을 사용할지 여부인데, 3.0 부터 지원.
default는 false이며, 4.0부터는 default가 true.
AndroidManifest.xml에서 android:hardwareAccelrated를 true로 설정

3. 렌더링 우선 순위 높이기
강제적으로 렌더링 기능에 대한 우선 순위를 높이는 방법이다.
webView.getSettings().setRenderPriority(RenderPriority.HIGH)로 설정
API Level 18부터는 deprecated.

Android - 효율적인 코드 작성하기2

1. Constants 를 final로 선언하라
컴파일러는 <clinit>라고 불리는 class initializer method 생성하며 이는 클래스가 처음 생성될 때 실행된다.
final로 설정되지 않은 값들은 reference될 때 field lookup을 사용해서 접근하여 속도가 조금 느린 편이다.
그러나 final로 설정하면 field lookup을 거치지 않고 바로 사용할 수 있어 빠른 편이다.
class와 function도 final로 설정함으로서 약간의 성능 향상을 노릴 수 있다.

2. Enhanced For Loop 문법을 주의하여 사용
반복문을 여러 번 사용할 경우에는 특히 object 생성에 주의해야 한다.
횟수가 기하학적으로 증가할 수 있고, 발견이 어려울 수 있기 때문이다.

3. Enums를 피하라
Enums의 접속 속도가 느리기 때문에 자주 사용하면 성능이 저하될 수 있다.
따라서 Enums를 지속적으로 사용하는 경우에는 local변수로 만들어 사용하는 것이 좋다.

4. 부동소수점(float)을 가능한 피하라

5. 곱셈 연산을 사용하라.
나누기 연산보다는 곱셈 연산을 사용하는 것이 성능에 더 좋다.

Android - 효율적인 코드 작성하기1

1. 오브젝트 생성을 피하라
오브젝트 생성은 메모리를 할당하는 작업으로, 일반 작업에 비해 load가 큰 편.
Java의 GC는 매우 큰 작업으로 구분되는데, 쓸데없는 메모리 할당으로 GC를 초래하게 되면 성능저하를 유발.
반복문에서의 오브젝트 생성은 오버헤드가 크므로 피함.

2. Native Method를 사용하라.
Native Method들은 C/C++ 등으로 구현되어 있어 Java 코드보다 약 10~100배 빨리 실행된다.
따라서 Native Method들을 이용하여 구현하는 것이 성능에 좋다.

3. 내부적인 getters/setters를 피하라
일반적인 OOP개념의 getter/setter는 합리적이나 클래스 내부에서의 변수 접근에도  getter/setter를 사용하는 것은 비효율적이다.

4. Cache Field Loop ups
맴버변수에 접근하는 것은 지역 변수에 접근하는 것보다 훨씬 속도가 느리다.
따라서 맴버변수를 여러 번 사용하는 함수에서는 맴버변수를 지역변수에 할당하여 처리하는 것이 효율적이다.

JavaScript - 성능 향상 (오브젝트)

* 오브젝트 생성
객체를 생성하는 방법으로 리터럴을 사용하는 방법과 생성자를 사용하는 방법이 있음
var obj = {}; // 리터럴
var obj = new Object(); // 생성자
큰 차이는 없으나 리터럴을 사용하는 방법이 조금 더 나은 성능을 보임

* 오브젝트 초기화
객체를 초기화하는 방법으로 .연산자를 사용하는 방법과 []연산자를 사용하는 방법이 있음.
obj.a = 1; // .연산자
obj["a"] = 1; // []연산자
사파리를 제외한 대부분의 브라우저에서 비슷한 성능을 보임. 사파리는 .연산자를 사용하는 방법이 더 좋은 성능을보임.

* 코드 최적화
어느 방법을 사용하더라도 비슷한 성능을 보임

JavaScript - 성능 향상 (배열)

* 배열 생성, 초기화
배열은 생성자 혹은 리터럴 형식을 사용해 객체를 생성할 수 있다.
var arr = new Array(); // 생성자
var arr = []; // 리터럴 형식
리터럴 형식을 사용한 경우 여러 브라우저에서 좀 더 좋은 성능을 보임.

* 배열 데이터 할당
배열에 데이터를 할당하는 방법에는 접근자 []를 사용하는 방법과 push() 메소드를 사용하는 방법이 있다.
arr[i] = 10; // 접근자
arr.push(10); // push 메소드
크롬을 제외한 대부분의 브라우저에서 접근자를 사용한 경우 좀 더 좋은 성능을 보임.

* 코드 최적화
배열 생성시 리터럴 형식을 사용하고, 접근자[]를 사용하여 데이터를 할당하는 것이 최적화된 방법으로 보임

MySql - 논리연산자

* SQL에서 모든 논리 연산자는 TRUE, FALSE 또는 NULL(UNKNOWN)로 계산된다.
MySQL에서는 1 (TRUE), 0 (FALSE) 그리고 NULL로 계산된다.

* NOT, !
논리 NOT. 피연산자가 0이면 1을, 피연산자가 0이 아니면 0을, NOT NULL 일 경우에는 NULL을 리턴.
사용예)
SELECT NOT 10; -> 0
SELECT NOT 0; -> 1
SELECT NOT NULL; -> NULL

* AND, &&
논리 AND. 모든 피연산자가 0이 아니고 NULL도 아니면 1을, 한 개 또는 그 이상의 피연산자가 0이라면 0을, 그렇
지 않을 경우에는 NULL을 리턴.
사용예)
SELECT 1 && 1; -> 1
SELECT 1 && 0; -> 0
SELECT 1 && NULL; -> NULL

* OR, ||
논리 OR. 양쪽의 피연산자가 NULL이 아닌 경우 양쪽의 피연산자가 0이 아니면 1을, 그렇지 않으면 0을 리턴.
NULL 피연산자를 사용하면, 다른 피연산자가 0이 아니면 1을, 그렇지 않으면 NULL을 리턴. 만일 양쪽의 피연산자가 모두 NULL이라면, 결과는 NULL.
사용예)
SELECT 1 || 1; -> 1
SELECT 1 || 0; -> 1
SELECT 0 || 0; -> 0

* XOR
논리 XOR. 피연산자 중의 하나가 NULL이면 NULL을 리턴. NULL이 아닌 피연산자의 경우, 피연산자의 홀수 개수가 0이 아니면 1을, 그렇지 않으면 0을 리턴.
사용예)
SELECT 1 XOR 1; -> 0
SELECT 1 XOR 0; -> 1
SELECT 1 XOR NULL; -> NULL

MySql - 연산자 우선순위

* 연산자 우선순위는 아래와 같으며, 낮은 것 -> 높은 것 순서.
동일한 라인은 같은 우선순위.
:=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >>
-, +
*, /, DIV, %, MOD
^
- (unary minus), ~ (unary bit inversion)
!
BINARY, COLLATE

* NOT에 대한 우선순위는 MySQL 5.0.2 이후에 존재.
이전 버전, 또는 HIGH_NOT_PRECEDENCE SQL 모드가 활성화 되어 있는 경우의 5.0.2 까지는, NOT의 우선 순위는 ! 연산자의 우선순위와 같다.

* 연산자의 우선순위는 수식에 있는 항의 계산 순서를 결정.
우선순위를 무시하고 그룹 항을 명확하게 지정하고자 한다면, 괄호를 사용
사용예)
SELECT 1+2*3; => 7
SELECT (1+2)*3; => 9

MySql - 리플리케이션이란

* MySQL은 단 방향, 즉 비동기 리플리케이션을 지원.
하나의 서버는 마스터로 동작하고, 나머지 한 개 이상의 다른 서버들은 슬레이브로 동작.

* 싱글-마스터 리플리케이션에서, 마스터 서버는 업데이트를 자신의 바이너리 로그 파일에 작성하고 로그 로테이션의 트레이스를 유지하기 위해 이 파일의 인덱스를 유지 관리한다. 바이너리 로그 파일은 다른 슬레이브 서버에 전달되는 업데이트 레코드 역할을 한다. 슬레이브가 자신의 마스터에 연결이 될 때, 마스터 정보를 자신이 마지막으로 업데이트가 성공했을 때 읽었던 로그에 전달한다. 슬레이브는 그 시간 이후에 발생한 모든 사항에 대한 업데이트를 전달 받고, 블록 (block)을 한 후에 마스터가 새로운 업데이트를 알려 주기를 기다리게 된다.

* 슬레이브 서버를 체인드 리플리케이션 서버로 설정하면, 자신이 마스터 역할을 하게 된다.

* 다중-마스터 리플리케이션은 가능하기는 하지만, 싱글-마스터 리플리케이션에서는 발생하지 않는 문제들이 나타나게 된다.

* 리플리케이션을 사용하는 경우, 복제된 테이블에 대한 모든 업데이트는 마스터 서버에서 실행되어야 한다. 그렇지않으면, 사용자가 마스터에 있는 테이블에서 행하는 업데이트와 슬레이브에서 행하는 업데이트간의 충돌을 피하도록 항상 주의해야만 한다.

* 리플리케이션은 견고성, 속도, 그리고 시스템 관리에 많은 혜택을 제공.
- 견고성은 마스터/슬레이브 설정을 가지고 증가된다. 마스터에서 문제가 발생하면, 백업 형태의 슬레이브로 전환할 수 있다.
- 마스터와 슬레이브 서버 간에 클라이언트 쿼리 처리를 분산함으로써 클라이언트에 대해 보다 개선된 응답 시간을 제공해 줄 수 있다. 슬레이브에 SELECT 쿼리를 전달해서 마스터의 쿼리 처리 업무를 줄여 줄 수 있다. 마스터와 슬레이브의 동기화가 끊어지지 않도록 하기 위해 데이터를 수정하는 명령문들은 여전히 마스터에 전달된다. 이러한 로드 밸런싱 전략은 업데이트 하지 않는 쿼리가 압도적으로 많은 경우에 효과적이다.
- 마스터의 방해 없이 슬레이브 서버를 사용해서 데이터베이스 백업을 실행할 수 있다. 마스터는 백업이 진행되는 동안에도 업데이트 프로세스를 지속할 수 있다.

MySql - 테이블 스캔 피하기

* EXPLAIN을 실행하면 MySQL이 쿼리를 해석하기 위해 테이블을 스캔할 때 type 컬럼에 ALL을 보여줌.
이것은 일반적으로 아래 조건 아래에서 발생.
- 테이블이 너무 작아서 키 룩업 (lookup)을 실행하는 것보다 테이블 스캔을 하는 것이 더 빠름. 일반적으로 10개 미만의 짧은 길이의 행을 가진 테이블이 여기에 해당.
- 인덱스된 컬럼에 대해서 사용할 수 있는 제약 사항이 ON 또는 WHERE 구문에 존재하지 않음.
- 인덱스된 컬럼을 상수 값과 비교할 수 있고, MySQL이 테이블 대부분을 커버하고 있는 상수를 계산해서 테이블 스캔이 빠르게 진행되도록 만드는 경우.
- 다른 컬럼을 통해서 낮은 기수 (cardinality)를 가지고 있는 (많은 열이 키 값과 매치가 됨) 행을 사용할 수 있는 경우, MySQL은 많은 키 룩업 (lookup)이 진행이 되고 이에 따라서 테이블 스캔이 보다 빠를 것이라고 가정.

* 작은 테이블의 경우에는 테이블 스캔이 적절할 수도 있을 것이나 대형 테이블의 경우 옵티마이저가 올바르지 않은 테이블 스캔을 선택하지 못하도록 하기 위해서 아래 기법을 사용.
- 스캔이 된 테이블에 대한 키 배포 업데이트 작업은 ANALYZE TABLE tbl_name를 사용.
- 주어진 인덱스를 사용하는 것 보다 테이블 스캔을 하는 것이 보다 비효율적이라고 MySQL에게 지시하기 위해서, 스캔이 된 테이블에 대해서 FORCE INDEX를 사용.
SELECT * FROM t1, t2 FORCE INDEX (index_for_column)
WHERE t1.col_name=t2.col_name;
- 어떠한 키 스캔도 1,000개 이상의 키 검색이 발생하지 않는다고 가정하게끔 옵티마이저를 만들기 위해서, mysqld를 --max-seeks-for-key=1000 옵션과 함께 시작하거나 또는 SET max_seeks_for_key=1000를 사용.

MySql - 인덱스 병합 결합 접근 알고리즘

* 이 알고리즘에 대한 표준은 인덱스 병합 방식 교차 알고리즘과 유사.

* 이 알고리즘은 OR과 결합된 서로 다른 키에서 테이블의 WHERE 구문이 여러 개의 범위 조건으로 변환될 때 적용될 수 있으며, 각 조건은 다음 중에 하나가 된다.
- 아래 형태에서는, 인덱스가 정확히 N 개의 부분을 가짐. (즉, 모든 인덱스 부분 커버)
    key_part1=const1 and key_part2=const2 ... and key_partN=constN
- InnoDB 테이블의 주요 키 (primary key)에 걸친 모든 범위 조건.
- 인덱스 병합 방식 교차 알고리즘을 적용할 수 있는 조건.

예)
SELECT * FROM t1
WHERE key1=1 OR key2=2 OR key3=3;

SELECT * FROM innodb_table
WHERE (key1=1 and key2=2) OR (key3='foo' and key4='bar') and key5=5;

MySql - 인덱스 병합 교차 접근 알고리즘

* 이 접근 알고리즘은 WHERE 구문이 AND와 결합된 서로 다른 키에 있는 여러 개의 범위 조건으로 변환될 때 사용될 수 있으며, 각각의 조건은 아래의 것 중에 하나가 된다.

아래의 형태에서는, 인덱스가 정확히 N 개의 부분을 가진다 (즉, 모든 인덱스 부분이 커버된다)
key_part1=const1 and key_part2=const2 ... and key_partN=constN
InnoDB 테이블의 주요 키 (primary key)에 걸친 모든 범위 조건.
예)
SELECT * FROM innodb_table WHERE prime_key < 10 and key_col1=20;
SELECT * FROM tbl_name WHERE (key1_part1=1 and key1_part2=2) and key2=2;
인덱스 병합 교차 알고리즘은 사용된 모든 인덱스에서 동시에 스캔을 실행하고, 병합된 인덱스 스캔으로부터 전달받는 열 시퀀스에 대해 교차를 만들어 낸다.

만일 사용된 인덱스가 쿼리에서 사용된 모든 컬럼을 커버한다면, 전체 테이블 열은 추출되지 않는다.
이 경우 EXPLAIN 결과는 Extra 필드 (field)에 있는 Using index를 가진다.
예)
SELECT COUNT(*) FROM t1 WHERE key1=1 and key2=1;
만일 사용된 인덱스가 쿼리에서 사용된 모든 컬럼을 커버하지 못한다면, 사용된 모든 키에 대한 범위 조건이 만족스러울 때에만 전체 열이 추출된다.

만일 병합된 조건 중의 하나가 InnoDB 테이블의 주요 키 (primary key)에 걸쳐지는 조건이라면, 이 조건은 열 추출용으로 사용되지는 않지만, 다른 조건을 사용해서 추출된 열을 걸러 낼 때 사용된다.

Java - 성능 향상 (프로그래밍)

* 자바에 적합한 프로그래밍 방법을 사용하여 성능 향상 효과를 얻을 수 있음.

* final 사용
final 클래스는 컴파일러에 의해 하위 클래스에 의해서 오버라이딩이 불가능한 클래스로 인식되어 컴파일시 동적 메소드 호출 기능을 제거하여 메소드 호출을 최적화. 따라서 일반 메소드 호출보다 훨씬 빠름.
클래스 전체를 final로 사용하는 것은 문제가 발생할 가능성이 많으므로 꼭 필요한 경우가 아니라면 피하는 것이 좋음.
메소드 단위로 final을 사용하는 것이 효율적.

* String 대신 StringBuffer 사용
String은 자바가상머신에 의해 StringBuffer 로 변환되어 처리됨.
String 결합(concat) 연산은 내부적으로 StringBuffer로 변환되어 결합 후 다시 String으로 변환되기에 많은 자원이 소모됨.
따라서 String보다는 StringBuffer 혹은 char 배열을 사용하는 것이 빠름.

* 임시 객체 생성 자제
반복문이나 자주 사용하는 메소드 내에서 생성하는 임시 객체들은 가비지 컬렉터에게 부하를 줌.
따라서 반복문이나 자주 사용하는 메소드 내에서 임시 객체 생성을 피하는 것이 좋음.

Java - 성능 저하 원인

* 멀티스레드, 가비지컬렉션, 런타임 바인딩 등은 자바에서 제공하는 편리한 기능이나 프로그램 실행 속도를 느리게하는 원인이 된다. 이러한 기능을 지원하기 위해 보다 많은 자원과 계산이 필요하기 때문.

* 동적 바인딩 / 동적 클래스 로딩
자바는 런타임시 필요한 클래스들을 바인딩. C는 컴파일시 처리. 상대적으로 자바가 함수 호출이 느림.
동적 클래스 로딩은 실행중에 자바 가상 머신에 의해 안전한지 검사하고 초기화하기 때문에 성능 저하를 유발.

* 가비지 컬렉션
사용되지 않는 객체의 메모리를 자동으로 가용 자원으로 돌려주는 유용한 기능이나, 백그라운드에서 스레드로 수행되어야 하기 때문에 성능 저하를 유발.

* 멀티스레드
멀티스레드 사용에 있어 중요한 부분이 스레드간 충돌을 방지하고, 공유 자원에 대한 일관성을 유지하는 것으로 이를 동기화라고 한다.
동기화를 위해 synchronized 키워드를 사용하는데, 스레드 모니터에서는 모든 스레드를 관리하며 synchronized 설정된 스레드가 한 순간에 한 번만 사용되도록 해야한다.
JDK에서 제공되는 많은 메소드들이 synchronized 선언되어 있으며, 백그라운드에서 스레드모니터가 항상 스레드 관리 작업을 수행하는데 많은 자원이 소모되어 성능 저하를 유발

JavaScript - 성능 향상 (반복문)

* for-in
반복문 중 가장 느리므로 사용하지 말 것.
for-in외의 반복문은 주어진 배열 객체를 배열의 특성에 맞게 순차적으로 모든 요소를 탐색.
for-in구문은 배열을 배열이 아닌 일반 객체로 취급, 반복 시점마다 객체의 모든 속성을 무작위로 탐색.

* Array.length
반복문 안에서 직접 사용하지 말 것. 변수 선언 후 사용하는 것이 더 빠름.
반복문 안에서 length를 구하게되면 반복횟수만큼 length를 구하는 작업을 반복.
사용예)
var arr = [1, 2, 3];
for (var i=0; i<arr.length; i++) {
    // ...
}
==>
var len = arr.length;
for (var i=0; i<len; i++) {
    // ...
}

JavaScript - 성능 향상 (스코프 체인 탐색 줄이기)

* 스코프 체인
탐색 성능을 높이는 것이 본질.
자바스크립트 실행성능 저하는 변수, 객체, 함수의 메모리상 위치 탐색 작업.

* 스코프 체인 구성
활성화 객체(Activate Object) + 전역 객체(Global Object)

* 활성화 객체
함수 내부 접근시 생성. (지역변수, this, arguments 객체)
함수 빠져 나오면 활성화 객체 제거됨 .

* 실행 문맥 (Execution Context) > 스코프 체인 (1, 2) > 활성화 객체 (1) > 전역 객체 (2) 순으로 실행.

* 함수가 전역 속성 참조 순서
실행문맥 > 스코프 체인 > 활성화 객체 (함수) > 스코프 체인 > 전역 객체 순으로 속성 참조

* 활성화 객체에서 전역 변수 사용시
함수 내부에 var LocalVariable = GlobalVariable; 식으로 지역변수화하여 전역속성 탐색을 제거.

JavaScript - 성능 향상 (성능우위 문법)

* 배열 생성
var arr = new Array(); 대신 var arr = []; 사용

* 배열 접근
arr.push(i) 대신 arr[i] = value 사용

* 객체 생성
var obj = new Object(); 대신 var obj = {}; 사용

* 객체 접근
obj["a"] = 1 대신 obj.a = 1; 사용

* 문자열 생성
var str = new String("aaa"); 대신 var str = "aaa"; 사용

* 문자열 연산
loop문에서 문자열 조작시 str += "test"; 대신 arr=[]; loop{ arr[i]="test"; } arr.join(""); 사용
String과 StringBuffer개념과 유사

* 정규표현식
탐색 대상을 축소.
loop 문 안에 정규표현식을 넣지 말고 밖에 놓아 한번만 컴파일되도록 처리.
(loop문에 있으면 계속 컴파일됨)

MySql - 성능 최적화 (글로벌 변수)

* innodb_buffer_pool_size, innodb_log_file_size, innodb_log_files_in_group,
innodb_flush_log_at_trx_commit, innodb_doublewrite, sync_binlog
정도가 성능에 직접적인 영향을 미침.

* innodb_buffer_pool_size
InnoDB에게 할당하는 버퍼 사이즈로 50~60%가 적당.
지나치게 많이 할당하면 Swap이 발생할 수 있음.

* innodb_log_file_size
트랜잭션 로그를 기록하는 파일 사이즈이며, 128MB ~ 256MB가 적당.

* innodb_log_files_in_group
트랜잭션 로그 파일 개수로 3개로 설정.

* innodb_flush_log_at_trx_commit
일반적으로 2로 설정.
0 : 초당 1회씩 트랜잭션 로그 파일(innodb_log_file)에 기록
1 : 트랜잭션 커밋 시 로그 파일과 데이터 파일에 기록
2 : 트랜잭션 커밋 시 로그 파일에만 기록, 매초 데이터 파일에 기록

* innodb_doublewrite
이중으로 쓰기 버퍼를 사용하는지 여부를 설정하는 변수.
활성화 시 innodb_doublewrite 공간에 기록 후 데이터 저장.
활성 권장.

* sync_binlog
트랜잭션 commit시 바이너리 로그에 기록할 것인지에 관한 설정.
비활성 권장

Oracle - 데이터베이스 링크(Database Link)란

* 데이터베이스 링크는 클라이언트 또는 현재의 데이터베이스에서 네트워크상의 다른 데이터베이스에 접속하기 위한 접속 설정을 정의하는 오라클 객체이다.

* 오라클 INSTANCE가 두 개 이상이고, 각각의 HOST NAME과 ORACLE_SID는 다르고 NLS_CHARACTER_SET은 동일하게 되어 있어야 한다.

* 문법
Create [public] database link link_nm connect to username identified by password using service_nm

link_nm : 데이터베이스 링크의 이름
service_nm : 네트워크 접속에 사용할 오라클 데이터베이스 네트워크 서비스명을 지정
username, password : 오라클 사용자명과 비밀번호를 지정

Oracle - 커넥션수 및 세션정보 조회하기

* 커넥션 수 조회하기
세션에 대한 정보는 V$SESSION을 참고.
SELECT
    COUNT(*)
FROM V$SESSION s
WHERE s.username IS NOT NULL
    AND NVL (s.osuser, 'x') 'SYSTEM'
    AND s.TYPE 'BACKGROUND';

* 세션 정보 조회
SELECT /*+ rule */
    s.status "Status", s.serial# "Serial#", s.TYPE "Type",
    s.username "DB User", s.osuser "Client User", s.server "Server",
    s.machine "Machine", s.module "Module", s.terminal "Terminal",
    s.program "Program", p.program "O.S. Program",
    s.logon_time "Connect Time", lockwait "Lock Wait",
    si.physical_reads "Physical Reads", si.block_gets "Block Gets",
    si.consistent_gets "Consistent Gets",
    si.block_changes "Block Changes",
    si.consistent_changes "Consistent Changes", s.process "Process",
    p.spid, p.pid, s.serial#, si.sid, s.sql_address "Address",
    s.sql_hash_value "Sql Hash", s.action
FROM V$SESSION s, V$PROCESS p, SYS.V_$SESS_IO si
WHERE s.paddr = p.addr(+)
    AND si.sid(+) = s.sid
    AND s.username IS NOT NULL
    AND NVL (s.osuser, 'x') 'SYSTEM'
    AND s.TYPE 'BACKGROUND'
ORDER BY 3;

Oracle - 유저 계정의 잠금 및 잠금 해제, 그리고 암호를 만료 하는 법

* 사용자 계정 잠금
명시적으로 사용자의 계정을 잠글 경우 사용.
SYSDBA 권한으로 접속 한다 C:\> SQLPLUS / AS SYSDBA
scott유저의 계정을 잠금 SQL> ALTER USER scott ACCOUNT LOCK;

* 사용자 계정 잠금 해제
SYSDBA 권한으로 접속 한다 C:\> SQLPLUS / AS SYSDBA
scott유저의 계정 잠금 해제 SQL> ALTER USER scott ACCOUNT UNLOCK;

* 비밀 번호 만료
SYSDBA 권한으로 접속 한다 C:\> SQLPLUS / AS SYSDBA
scott유저의 암호를 만료 시킨다. SQL> ALTER USER scott PASSWORD EXPIRE;

Oracle - COPY명령으로 테이블 복사하기

* SQL*Plus에서 COPY라는 명령어를 이용해서 테이블을 복사 할 수 있는 기능을 제공.
COPY명령어는 SQL*Net이 설치되어 있어야하고, SQL*Plus에서만 사용 가능.


* 문법
COPY FROM 복사해올유저명

    CREATE 생성할 테이블명
    USING 원본 테이블 질의
 

* 사용예
SQL> COPY FROM scott/tiger@oracle
        CREATE emp2 USING SELECT * FROM emp;

Oracle - 유저의 패스워드를 쉽게 바꾸는 방법

* SQL*Plus에서 PASSWORD 명령으로 쉽게 유저의 패스워드를 변경 할 수 있다.

* 사용예
SQL> PASSWORD;
SCOTT에 대한 암호를 변경합니다
이전 암호: *****
새로운 암호: ******
새로운 암호를 다시입력합니다: ******

Oracle - LIKE연산자에서 '%'와 '_'를 포함하는 단어 검색 방법

* LIKE 연산으로 '%'나 '_'가 들어간 문자를 검색하기 위해서는 ESCAPE를 사용.
'_'나 '%'앞에 ESCAPE로 특수 문자를 지정하면 검색할 수 있다.


* '_' 가 있는 문자 검색
SELECT

    loc
FROM dept
WHERE loc like '%#_%' ESCAPE '#';
=>
NEW_YORK


SELECT

    loc
FROM dept
WHERE loc like '%N%@_%' ESCAPE '@'
=>
NEW_YORK


SELECT

    loc
FROM dept
WHERE loc like '%_%';
=>
NEW_YORK
DALLAS
CHICAGO
BOSTON

Oracle - 랜덤 사용하기

* DBMS_RANDOM 패키지를 사용하면 숫자와 문자의 랜덤 데이터를 생성할 수 있으며, 테이블 데이터를 램덤한 순서로 정렬하여 조회할 수 있다.

* DBMS_RANDOM.VALUE
랜덤한 숫자를 생성한다.
Syntax : DBMS_RANDOM.VALUE(low IN NUMBER, high IN NUMBER)
파라미터 low는: 최소 범위, high는: 최대 범위 값이다.

SELECT DBMS_RANDOM.VALUE(1000, 10000) rand FROM DUAL;
=> 5942.39469
 

* DBMS_RANDOM.STRING
랜덤한 문자열을 생성한다.
Syntax : DBMS_RANDOM.STRING opt IN CHAR, len IN NUMBER)
- opt (옵션)은 아래와 같다.
'u', 'U' : 대문자
'l', 'L' : 소문자
'a', 'A' : 대소문자 구분없는 영문자
'x', 'X' : 영문자와 숫자 혼합
'p', 'P' : 문자 혼합
SELECT DBMS_RANDOM.STRING('U', 10) rand FROM DUAL -- 대문자
=> NSBJGKKQCL


* DBMS_RANDOM.RANDOM
DBMS_RANDOM.RANDOM은 랜덤 한 숫자를 생성.
DBMS_RANDOM.RANDOM 함수를 이용하여 데이터를 랜덤한 순서로 정렬.

Oracle - DATE Format 변경하기

* INIT[dbname].ora 파일 수정하기
NLS_DATE_FORMAT = 'RR-MM-DD' 이와 같이 변수와 값을 추가.


* Shell 프로그램 이용
C Shell: OS 상태에서 setenv NLS_DATE_FORMAT 'RR/MM/DD'추가.
B Shell: NLS_DATE_FORMAT='RR/MM/DD' export NLS_DATE_FORMAT 추가.
K Shell: B Shell 방법과 추가로 export NLS_DATE_FORMAT='RR/MM/DD' 로 표현 가능


* SYS.PROPS$ VIEW를 이용하여 UPDATE하는 방법
 

* Session 에서 set 하는 방법
SQLPLUS 상태에서 ALTER SESSION SET NLS_DATE_FORMAT='RR/MM/DD' 실행
단 SESSION 내에서만 활용가능

Oracle - 사용자 세션 강제 종료하기

* ALTER SYSTEM문을 KILL SESSION 연산자와 함께 사용.
사용자의 SESSION KILL은 ALTER SYSTEM 권한 필요.


* ALTER SYSTEM KILL SESSION 명령어가 수행하는 작업
사용자의 현재 트랜잭션을 롤백 한다.
현재 사용중인 모든 테이블 또는 행의 LOCK을 해제 한다.
사용자에의해 예약 되었던 시스템 자원을 해제 한다.
 

* 문법
Alter System kill session '세션아이디.시리얼번호‘;
세션ID와 시리얼번호를 확인하기 위해서는 V$SESSION 뷰를 조회

Oracle - 데이터 파일 이동하기

* ALTER DATABASE를 이용한다.
1) 데이터베이스를 종료 한다.
2) 운영체제 명령을 사용하여 데이터 파일을 이동 한다.
3) 데이터베이스를 마운트 모드로 시작한다.
4) ALTER DATABASCE RENAME FILE명령을 수행하여 이름을 변경한다.
5) 인스턴스를 시작한다

Oracle - 데이터 파일 관리

* 데이터 파일의 크기 조절하기
기존 데이터 파일들은 ALTER DATABASE와 ALTER TABLESPACE 명령어로 크기를 재조정.

ALTER DATABASE
    DATAFILE 'C:\ORACLE\ORADATA\ORACLE\SYSTEM01.DBF'
    RESIZE 400m;



* 데이터 파일 자동 확장 하기
CREATE DATABASE, CREATE TABLESPACE, ALTER TABLESPACE 명령을 사용

CREATE TABLESPACE KJS
    DATAFILE 'C:\ORACLE\ORADATA\ORACLE\KJS.DBF'
    SIZE 300M
    AUTOEXTEND ON
    NEXT 10M
    MAXSIZE 500M;



* 새로운 데이터 파일을 기존 테이블 스페이스에 추가하기
KJS테이블 스페이스에 AUTOEXTEND, MAXSIZE를 명시하고 100메가의 KJS_01.DBF파일을 추가 하는 예.

ALTER TABLESPACE KJS
    ADD DATAFILE 'C:\ORACLE\ORADATA\ORACLE\KJS_01.DBF' SIZE 100M
    AUTOEXTEND ON
    MAXSIZE 300M;



* 기존 파일의 속성 변경하기
ALTER DATABASE명령을 이용하면 된다.

ALTER DATABASE
    DATAFILE 'C:\ORACLE\ORADATA\ORACLE\KJS_01.DBF'
    AUTOEXTEND ON
    MAXSIZE 500M;

Oracle - 중복된 ROW 데이터 삭제 방법

* ROWID를 사용하여 중복된 ROW를 제거 할 수 있다.

* 중복된 데이터중에서 ROWID가 큰 값(나중에 등록된 데이터) 제거
DELETE FROM emp a
WHERE ROWID > (SELECT MIN(ROWID)
                         FROM emp b
                         WHERE b.empno = a.empno);
 

* 나중에 들어온 데이터를 살릴경우
DELETE FROM emp a
WHERE ROWID < (SELECT MAX(ROWID)
                         FROM emp b
                         WHERE a.empno = b.empno);

Oracle - 테이블, 컬럼 제약 조건의 확인하기

* 테이블에 걸려있는 제약 조건의 확인하기
USER_CONS_COLUMNS : 컬럼에 할당된 제약 조건을 볼 수 있다.
USER_CONSTRAINTS : 유저가 소유한 모든 제약 조건을 불 수 있다.


SELECT 

    SUBSTR(A.COLUMN_NAME,1,15) COLUMN_NAME,
    DECODE(B.CONSTRAINT_TYPE,
        'P','PRIMARY KEY',
        'U','UNIQUE KEY',
        'C','CHECK OR NOT NULL',
        'R','FOREIGN KEY') CONSTRAINT_TYPE,
    A.CONSTRAINT_NAME CONSTRAINT_NAME
FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B
WHERE A.TABLE_NAME = UPPER('&table_name')
    AND A.TABLE_NAME = B.TABLE_NAME
    AND A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
ORDER BY 1;




* 테이블의 특정 컬럼에 걸려있는 제약 조건의 확인하기
USER_CONS_COLUMNS : 컬럼에 할당된 제약 조건을 볼 수 있다.


SELECT 

    SUBSTR(TABLE_NAME,1,15) TABLE_NAMES,
    SUBSTR(COLUMN_NAME,1,15) COLUMN_NAME,
    SUBSTR(CONSTRAINT_NAME,1,25) CONSTRAINT_NAME
FROM USER_CONS_COLUMNS
WHERE TABLE_NAME = UPPER('&table_name')
    AND COLUMN_NAME = UPPER('&column_name');

Oracle - DB에 등록된 USER 정보와, USER별 Object 정보 조회하기

* DB에 등록된 USER 정보 조회하기
SYS 사용자로 접속하여 DBA_USERS 데이터 사전을 조회.
SELECT username, default_tablespace, temporary_tablespace, created FROM DBA_USERS;




* USER의 Object 정보 조회하기
USER_OBJECTS 데이터 사전을 조회.
SELECT object_name, object_type FROM USER_OBJECTS WHERE object_type = 'INDEX';

JavaScript - 전역 범위 보호하기

* 자바스크립트의 결함 중 하나는 페이지의 모든 스크립트가 공유되는 전역 컨텍스트에서 실행된다는 점으로, 악용될 경우 웹 사이트는 교차 사이트 스크립팅 공격에 취약하게 된다.


* 공유 전역 컨텍스트는 다른 문제도 일으킨다. 예를 들어 많은 스크립트가 한 페이지에서 실행되는데, 모든 스크립트를 개발자가 결정하는 것은 아니다(광고 스크립트 등이 대표적이다). 이 스크립트들은 전역 공간에서 실행되며 모두 같은 전역 변수에 접근할 수 있다. 이러한 스크립트 두 개가 같은 전역 변수를 사용하게 되면 서로 간섭하기 시작하고, 그러면 코드는 망가지게 된다.






* 전역 범위의 사용을 최소화하는 것은 간섭을 막고 긴 디버깅 시간을 줄이는 데 도움이 되는 방어적 기법으로 변수를 전역적으로 저장하는 것을 완전히 없앨 수는 없지만, 네임스페이싱과 같은 기법을 사용하여 최소화할 수 있다.




* 사용예
// **Namespacing**
// The global footprint is a single object containing
// all other references needed.


var MyApp = {};


MyApp.id = 42;
MyApp.utils = {
    validate: function(){
        //do work
    }
};

Oracle - Switch문 기능 구현하기

* Decode 함수를 사용하여 Switch 기능을 구현할 수 있다.
DECODE (컬럼명 | 표현식
                     , 조건1, 결과1
                     , 조건2, 결과2
                     .......
                     , 조건n, 결과n
                     , 결과
)


[컬럼명 |표현식] : 이 값을 조건1부터 조건n까지 순차적으로 비교하여 같으면 해당 결과 return.
[결과] : 조건1 ~ 조건n에 모두 해당되지 않는 경우 return되는 기본값
 


* 사용예
SELECT
    DECODE ('A'
        , 'A', 'Aaa'
        , 'B', 'Bbb'
        , 'Ccc'
    )
FROM DUAL;
==> Aaa


SELECT
    DECODE ('B'
        , 'A', 'Aaa'
        , 'B', 'Bbb'
        , 'Ccc'
    )
FROM DUAL;
==> Bbb

JavaScript - 익명의 즉시 실행 함수로 스크립트 시작하기

* 익명의 즉시 실행 함수는 다음의 코드와 같이 정의
(function() {
    // ... 코드 생략 ...
}());


* 익명 함수는 자바스크립트가 런타임에 구문을 해석하여 실행.

  이는 외부의 접근을 제한함을 의미.
  따라서 외부 코드에서 익명 함수의 내부 코드를 수정할 수 없음.
 

* 즉시 실행 함수는 선언과 동시에 실행.
  익명 함수가 런타임에 사용될 준비가 되면 즉시 함수의 초기화 코드를 실행할 수 있기 때문.

JavaScript - this란

* call/apply 또는 bind를 사용하지 않을 경우 this 값은 항상 전역 객체를 참조.
단, 다음 경우 제외.
1. new 연산자를 사용하여 호출된 경우, 현재 만들어지고 있는 새로운 객체를 가리킴
2. 객체의 멤버인 경우, 이 객체를 가리킴

Maven - 명령어

* compile
complier:complie의 실행으로 src/java 및의 모든 자바소스를 컴파일해서 target/classes로


* package
target디렉터리 하위에 jar,war,ear등의 압축파일 생성.

이름은 build엘리먼트의 finalName엘리먼트의 값을 사용.
지정되지 않을 경우 "아티팩트아이디-버전”의 이름으로 압축됨
(각 압축종류별로 플러그인이 필요, 빌드 시 알아서 다운로드함)

* install
로컬 저장소로 배포


* deploy
원격 저장소로 배포


* clean
빌드를 통해 생성된 target디렉터리 삭제


* mvn clean test, mvn clean install
이전 빌드로 인해 남아있는 산출물의 문제로 빌드 오류가 발생하는 경우, 이런식으로 할 수 있음

Ehcache 란

* EhCache는 경량의 빠른 캐시 엔진으로 확장/분산 기능을 지원하며 높은 품질을 제공.

* xml 설정
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <cache name="simpleBeanCache"
              maxElementsInMemory="10000"
              eternal="false"
              timeToIdleSeconds="120"
              timeToLiveSeconds="120"
              overflowToDisk="true"
              maxElementsOnDisk="10000000"
              diskPersistent="false"
              diskExpiryThreadIntervalSeconds="120"
              memoryStoreEvictionPolicy="LRU"

    />
</ehcache>


* Cache 조회하기
CacheManager cacheManager = CacheManager.create();
Cache cache = cacheManager.getCache("simpleCacheBean");


* Cache 생성/수정하기
CacheManager cacheManager = CacheManager.create();
Cache cache = cacheManager.getCache("simpleCacheBean");
cache.put(newElement);


* Cache 삭제하기
CacheManager cacheManager = CacheManager.create();
cache.remove("SimpleCacheBean");

Java - 문자열로된 숫자 자리수 채우기

* String.format 을 사용하여 빈 자리를 0으로 채울 수 있다.
 


* 사용예
System.out.pringln( String.format("%03d", 3) ); => 003
System.out.pringln( String.format("%02d", 2) ); => 02
System.out.pringln( String.format("%02d", 10) ); => 10

Oracle - 테이블 락 확인하기

* 현재 테이블에 락이 걸려있는지 조회할 수 있다.


* 락 테이블 조회하기
SELECT
      B.OBJECT_NAME, B.OWNER, B.OBJECT_TYPE

      , A.XIDUSN, A.SESSION_ID, A.LOCKED_MODE
FROM V$LOCKED_OBJECT A, DBA_OBJECTS B
WHERE A.OBJECT_ID = B.OBJECT_ID
;
 

* 특정 테이블 락 여부 확인하기
SELECT
     A.SID, A.SERIAL#

     , B.TYPE, C.OBJECT_NAME
FROM V$SESSION A, V$LOCK B, DBA_OBJECTS C
WHERE A.SID=B.SID

  AND B.ID1=C.OBJECT_ID
  AND B.TYPE='TM'
  AND C.OBJECT_NAME = '테이블명'
;

Oracle - 한 쿼리로 INSERT 혹은 UPDATE 하기

* 테이블에 데이터 추가시 조건에 해당하는 값이 존재하면 해당 행을 UPDATE하고,
없으면 INSERT 하는 경우 사용


* 사용법
MERGE INTO [ schema. ] { table | view } [ t_alias ]
   USING { [ schema. ] { table | view } | subquery } [ t_alias ]
   ON ( condition )
WHEN MATCHED THEN
UPDATE SET column = { expr | DEFAULT }
              [, column = { expr | DEFAULT } ]...
[ DELETE where_clause ]
WHEN NOT MATCHED THEN
INSERT [ (column [, column ]...) ]
VALUES ({ expr [, expr ]... | DEFAULT })



- INTO : DATA가 UPDATE되거나 INSERT 될 테이블
- USING : 비교할 SOURCE 테이블 혹은 서브쿼리.

              INTO절의 테이블과 동일하거나 다를 수 있음.
- ON : UPDATE나 INSERT를 하게 될 조건.

         해당 조건을 만족하는 DATA가 있으면 WHEN MATCHED 절 실행
              , 없으면 WHEN NOT MATCHED 절 실행.
- WHEN MATCHED : ON 조건절이 TRUE인 ROW에 수행 할 내용.

                            (UPDATE, DELETE 포함 될 수 있음)
- WHEN NOT MATCHED : ON 조건절에 맞는 ROW가 없을 때 수행할 내용.

                                   (INSERT)

Java - JSch를 사용하여 SFTP 파일 업로드 하기

* JSch 라이브러리를 사용하여 SFTP 접속 및 파일 업로드
  (http://www.jcraft.com/jsch/)


import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;


JSch jsch = new JSch();
Session session = null;
ChannelSftp channelSftp = null;
   
/**
 * SFTP 접속
 * @param ip 아이피
 * @param port 포트
 * @param id 로그인아이디
 * @param pw 로그인비밀번호
 */
public void connect(String ip, int port, String id, String pw)
{
    // 연결 시도
    session = jsch.getSession(id, ip, port);
    session.setPassword(pw);
    java.util.Properties config = new java.util.Properties();
    config.put("StrictHostKeyChecking", "no");
    session.setConfig(config);
    session.connect(); 
   
    // 방식 설정
    Channel channel = session.openChannel("sftp");
    channel.connect();
    channelSftp = (ChannelSftp)channel;
}

/**
 * SFTP 접속 종료
 */
public void disconnect()
{
    if (channelSftp != null)
        channelSftp.disconnect();

    if (session != null)
        session.disconnect();
}
   
/**
 * 폴더 확인 및 생성
 * @param dir 폴더명(경로포함)
 */
public void checkDir(String dir)
{
    SftpATTRS attrs = null;

    // 폴더 체크
    try
    {
        attrs = channelSftp.stat(dir);
    }
    catch(Exception e)
    {
        attrs = null;
    }
   
    // attrs가 널이면 폴더 존재 X
    if (attrs == null)
    {
        channelSftp.mkdir(dir); // 폴더 생성
    }
}
   
   
/**
 * 폴더 이동
 * @param dir 폴더명(경로포함)
 */
public void moveDir(String dir)
{
    // 폴더 이동..
    channelSftp.cd(dir);
}   
   
/**
 * 파일 업로드.
 * @param fileName 파일명(경로포함)
 * @param fileData 파일내용
 * @return
 */
public boolean fileUpload(String fileName, byte[] fileData)
{
    OutputStream os = channelSftp.put(fileName);
    os.write(fileData);
    os.flush();
    os.close();
}

Java - 문자열로된 날짜 유효성 체크하기

* java.text.DateFormat.setLenient(boolean lenient)를 활용하여 체크.
  lenient를 false로 설정하면 유효한 날짜가 아닐 경우 ParseException이 발생.




import java.text.SimpleDateFormat;

/**
 * 문자열로 된 날짜 형식이 유효한지 체크
 * @param dateStr
 * @return 유효하면 true, 아니면 false
 */
public static boolean checkDateYYYYMMDD(String dateStr)
{
    try {
        SimpleDateFormat sdfYYYYMMDD = new SimpleDateFormat("yyyyMMdd");
        sdfYYYYMMDD .setLenient(false);
        sdfYYYYMMDD .parse(dateStr); //ex) dateStr="20201232"이면 ParseException 발생
        return true;
    } catch(ParseException e) {
        return false;
    } catch(Exception e) {
        return false;
    }
}

스프링 프레임워크에서 HttpServletRequest, HttpSession 객체 직접 가져오기


import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;

ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();


// HttpServletReqeust 객체
HttpServletReqeust httpServletReqeust = sra.getRequest();

// HttpSession 객체
HttpSession httpSession = sra.getRequest().getSession();