728x90
반응형

워드프레스와 같은 설치형 블로그를 만들고 나서 블로그가 어느정도 자리를 잡았다고 생각되면 다음에 해야 할 일은 무엇일까? 바로 여러 검색 사이트에 RSS 피드를 등록하는 것이다. 그래야만 해당 검색 사이트에서 키워드를 검색하였을 때, 자신의 블로그의 포스트가 노출되게 된다. 물론 자신의 블로그는 정상적인 RSS 피드를 발행하고 있어야 한다. 다행이 구글의 경우 https://www.google.com/webmasters/tools/submit-url?pli=1에서 한 번의 클릭만으로 쉽게 검색 등록을 할 수 있다. 필자는 구글 웹마스터 툴을 사용하고 있기 때문에 따로 그럴 필요는 없었다.

하지만 국내 검색엔진의 경우 굉장히 폐쇠적이어서(사실 네이버를 까라고 하면 하루종일 깔 수가 있지만, 살아남기 위해서는 강자에게 복종해야 한다 OTL) 직접 검색엔진 관계자와 접촉 후 심사를 받아야 한다(예전에 운영하던 티스토리 블로그의 경우에는 별도의 심사 없이 자연스럽게 네이버 등에 노출 되었었다).
 
 
 
naver-naver

먼저 네이버에 RSS 피드를 등록하는 방법을 알아보자. 한글로 된 포스트가 상당 수 있다면, 남한의 검색엔진 점유율이 압도적인 네이버의 선택을 받는 것은 블로거에게 불가피하다. 필자는 네이버의 선택을 받기까지 약 한 달 반의 시간을 소요했다.

먼저 아래 링크를 클릭하여 “문의하기” 를 통해 “RSS 피드 등록 요청”을 제목으로 하는 요청글을 네이버에게 보내야 한다.

https://help.naver.com/ops/step2/mail.nhn?catg=547

그렇다면 이메일로 답변이 올 것이다. 물론 한 번에 검색 결과에 반영했다는 답변이 오면 좋겠지만, 그렇지 않은 경우가 많다. 그 이유는 “심사 소요 기간이 오래 걸림”, “블로그 포스트 부족”, “복제된 글 많음”, “저작권 위반”, “광고성 블로그” 등 실로 다양하다. 필자는 한 달에 걸쳐 총 5번의 등록 요청을 하였으나 번번히 퇴짜를 맞았다.

rss-naver1

그 이유도 알지 못한 채 그저 아직 심사중이라는 앵무새같은 답변만을 받을 뿐이었다. 물론 네이버 나름대로 까다로운 심사 내부 규정이 있었을 것이지만, 이렇게 오래 걸릴 줄은 알 지 못했다. 그러던 중에 어떤 블로거의 “전화를 하니까 바로 등록해 주던데요?” 라는 식의 내용의 포스트를 보고, 필자도 바로 1588-3820 으로 전화를 걸었다. 몇 번의 숫자 버튼을 눌러 상담원과 연결되었는데, 블로그 주소와 연락처를 알려달라는 간단한 얘기만 5분 정도 한 채 1주일 이내에 연락드리겠다는 말을 남겼다. 그런데 전화 문의를 한 지 3일 정도 지나자 네이버로부터 아래와 같은 답변을 받게 된다.

rss-success

역시 전화가 좋구나! 결국 아래와 같이 이후 네이버로부터의 유입이 서서히 감지되기 시작했다.

refer-naver
 
 
 
daumlogo남한에서 검색시장 업계 2위는 다음이다. 물론 그 격차는 상당하지만, 다음에도 검색 등록을 해 주는 것이 좋다. 다음의 경우에는 네이버에 비해 쉽게 RSS 피드 등록을 해 주는 편이다. 아래 링크로 들어가서

http://cs.daum.net/mail/form/15.html

블로그, 카페 검색 문의 – 내 블로그 검색(RSS) 문의를 선택하고 문의를 하면 수 일 안에 RSS 피드가 등록 된다.


http://www.leunkim.com/others/word-press-tips/rss-feed-naver/

728x90
반응형
728x90
반응형

DecimalFormat이란... 10진수의 값을

원하는 포멧으로 변형해 주는 클래스를 말합니다.
DecimalFormat 클래스는 객체를 생성할 때 new 연산자를 사용합니다.
format 메소드를 사용해서 특정 패턴으로 값을 포맷할 수 있습니다.

 



패턴 형식은 '0'과 '#'을 사용 해서 지정합니다.
예를들면, '00.###', '0.#', '000.##'등으로 패턴을 지정할 수 있습니다.
'0' 은 표시한 자리수만큼의 값을 최소한으로 표시해야한다는 것이며,

#은 표시한 소수점자리수만큼 반올림하여 표시해야한다는 것입니다.

 



예를들어 12.3456789의 경우에 아래와 같습니다.
'00.###' = 12.346
'0.#' = 12.3 
'000.##' : 012.35

 

해당 패턴을 지정하여 DecimalFormat을 사용하는 방법은 아래와 같습니다.
DecimalFormat fmt=new DecimalFormat("00.###");
String decimal= fmt.format(12.3456789);
위와 같이 사용하면 decimal에는 12.346이 반환되죠.

 



DecimalFormat의 패턴을 변경하려 할 때는

void applyPattern(String pattern)를 사용합니다.
fmt.applyPattern("000.###")으로 변경하면

이후에는 변경된 Pattern이 포맷으로 적용됩니다.

 

다음 예제를 보면


 

 

실행결과

 


Decimal 패턴의 형식은 "0"과 "#" 외에도 여러 종류가 더 있습니다.
더 자세한 내용은 Java API DOC을 참고 하세요.

728x90
반응형
728x90
반응형


 IT Blog - https://moon9342.github.io/

728x90
반응형

'Web Programming > Angular - TypeScript' 카테고리의 다른 글

앵귤러JS (AngularJS) 란?  (0) 2018.08.29
Angular Component LifeCycle  (0) 2018.08.28
Angular Pipe  (0) 2018.08.28
Angular Directive  (0) 2018.08.28
Angular Material Table Event  (0) 2018.08.28
728x90
반응형

Component Lifecycle

이번 포스트에서는 Angular의 Lifecycle에 대해서 알아보겠습니다. 다른 Framework과 마찬가지로 Angular 역시 여러 단계의 lifecycle을 관리합니다. Component와 Directive가 이 lifecycle의 영향을 받게 되며 각 lifecycle마다 제공되는 hook method를 이용하여 특정 작업을 처리할 수 있습니다.

이런 hook method는 interface형태로 우리에게 제공됩니다. Component 혹은 Directive class가 이 interface를 구현하고 그 안의 특정 method를 overriding하는 식으로 hook method를 이용할 수 있습니다.

Component를 대상으로 객체가 생성되고 소멸되기까지 호출되는 hook method를 순서대로 나열하면 다음과 같습니다. Directive는 View를 가지고 있지 않기 때문에 ngAfter로 시작되는 hook method는 호출되지 않습니다.

  • constructor
  • ngOnChanges
  • ngOnInit
  • ngDoCheck
  • ngAfterContentInit
  • ngAfterContentChecked
  • ngAfterViewInit
  • ngAfterViewChecked
  • ngOnDestroy

간단하게 Project를 하나 생성해서 각 lifecycle단계에서 해당 hook method가 호출되는지 확인하는 식으로 진행하시면 됩니다.


 constructor

Component 혹은 Directive가 생성될 때 호출됩니다. 사실 constructor는 Angular의 lifecycle의 단계에 포함될 내용은 아닙니다.

TypeScript에서는 일반적으로 constructor에서 초기화를 진행합니다. 하지만 Angular에서 사용하는 속성의 초기화는 ngOnInit에서 하는것이 좋습니다.


 ngOnChanges

@Input을 이용해 부모 Component가 자식 Component에게 데이터를 전달할 수 있습니다. ngOnChanges는 부모 Component에서 자식 Component로 데이터가 binding 될 때 혹은 변경되었을 때 호출됩니다. 따라서 @Input을 사용하지 않으면 호출되지 않습니다.

정확하게는 부모 Component로부터 자식 Component에게 전달하는 primitive 값이 변경되거나 혹은 참조하는 객체의 reference가 변경되어야 호출됩니다. 즉, 참조하는 객체의 property가 변경되는 경우에는 ngOnChanges가 호출되지 않는다는 것 기억하셔야 합니다.

@Input을 이용한 값의 binding은 생성자가 호출된 후에 일어납니다. 즉, 생성자에서 @Input을 이용해 binding한 값을 출력하면 undefined가 출력되게 됩니다. 간단한 이벤트 처리를 통해 @Input으로 전달되는 값을 변경해보면 값이 변경될 때마다 ngOnChanges hook method가 호출되는걸 확인할 수 있습니다.

ngOnChanges hook method의 인자로 SimpleChanges 객체를 하나 받을 수 있습니다. 해당 객체를 이용하면 변경되기 이전값과 이후값등을 알 수 있습니다.

import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges {

  @Input() myInput: string;

  constructor() {
    console.log(`Constructor 호출!! => myInput : ${this.myInput}`);
  }

  ngOnChanges(simpleChanges: SimpleChanges) {
    console.log(`ngOnChanges 호출!! => myInput : ${this.myInput}`);
    console.log(simpleChanges.myInput.previousValue);
    console.log(simpleChanges.myInput.currentValue);
  }

  ngOnInit() {
  }

}

 ngOnInit

ngOnInit는 ngOnChanges가 호출된 이후에 모든 속성에 대한 초기화가 완료된 시점에 딱 한번만 호출됩니다. 즉, class가 가지고 있는 속성과 @Input을 통해 값을 내려받은 속성이 모두 초기화가 된 이후에 호출됩니다. 결국 Component의 속성 참조는 ngOnInit hook method이후에 참조하는 것이 좋습니다.

결국 생성자는 Service의 Injection같은 사항을 처리하고 속성에 대한 초기화는 ngOnInit에서 처리하시는게 좋다는 말입니다.

import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges {

  @Input() myInput: string;
  myString = 'Hello';

  constructor() {
    console.log(`Constructor 호출!! => myInput : ${this.myInput}`);
    console.log(`Constructor 호출!! => myString : ${this.myString}`);
  }

  ngOnChanges(simpleChanges: SimpleChanges) {
    console.log(`ngOnChanges 호출!! => myInput : ${this.myInput}`);
    console.log(simpleChanges.myInput.previousValue);
    console.log(simpleChanges.myInput.currentValue);
  }

  ngOnInit() {
    console.log(`ngOnInit 호출!! => myInput : ${this.myInput}`);
    console.log(`ngOnInit 호출!! => myString : ${this.myString}`);
  }

}

 ngDoCheck

ngOnInit hook method가 호출된 이후에 호출됩니다. Component에서 발생하는 모든 상태변화에 반응하여 호출되어지는 hook method로 Angular의 Changes Detection이 상태변화를 감지하면 자동으로 호출되게 됩니다. 한가지 주의하셔야 할 점은 ngOnChanges와는 다르게 primitive값의 변경, reference 객체의 변경, reference객체의 속성변경에 대한 모든 변경에 대해 해당 hook mehtod가 호출된다는 점입니다. 심지에 이전값과 같은 값이 assign되었음에도 호출됩니다. 따라서 ngDoCheck을 많이 사용하게 되면 그만큼 성능이 저하될 수 있습니다.

import {Component, DoCheck, Input, 
        OnChanges, OnInit, SimpleChanges} from '@angular/core';

interface IBook {
  btitle: string;
  bauthor: string;
}

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges, DoCheck {

  @Input() myInput: IBook;
  myString = 'Hello';

  constructor() {
    console.log(`Constructor 호출!! => myInput : ${this.myInput}`);
    console.log(`Constructor 호출!! => myString : ${this.myString}`);
  }

  ngOnChanges(simpleChanges: SimpleChanges) {
    console.log(`ngOnChanges 호출!! => myInput : ${this.myInput}`);
    console.log(simpleChanges.myInput.previousValue);
    console.log(simpleChanges.myInput.currentValue);
  }

  ngOnInit() {
    console.log(`ngOnInit 호출!! => myInput : ${this.myInput}`);
    console.log(`ngOnInit 호출!! => myString : ${this.myString}`);
  }

  ngDoCheck() {
    console.log(`ngDoCheck 호출!! => myInput : ${this.myInput}`);
    console.log(`ngDoCheck 호출!! => myString : ${this.myString}`);
  }
}

 ngAfterContentInit, ngAfterContentChecked

최초의 ngDoCheck hook method가 호출된 후에 한번만 호출되며 앞서 배운 ngContent directive를 이용해 부모 Component의 template 일부를 자식 Component에서 projection한 후 호출됩니다. 여기서 Content의 의미는 ngContent directive처럼 외부에서 Component View안으로 내용을 가져온 것을 지칭합니다. 이 hook method 이후에 Change Detection이 실행된 후 바로 따라서 ngAfterContentChecked hook method가 호출됩니다.


 ngAfterViewInit, ngAfterViewChecked

Component에 속한 모든 View와 ViewChild가 시작되고 나서 호출됩니다. 쉽게 생각하면 HTML이 모두 화면에 출력된 후 호출된다고 생각 하시면 됩니다. ngAfterViewChecked는 Component의 View에 대한 Change Detection이 실행되고 난 후 호출됩니다.


 ngOnDestroy

Component가 소멸하기 직전에 호출됩니다. 일반적으로 사용된 자원에 대한 해제 코드가 들어옵니다.

import {
  AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, 
  Component, DoCheck, Input, OnChanges, OnDestroy, OnInit,
  SimpleChanges
} from '@angular/core';

interface IBook {
  btitle: string;
  bauthor: string;
}

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, OnChanges, DoCheck, AfterContentInit,
  AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {

  @Input() myInput: IBook;
  myString = 'Hello';

  constructor() {
    console.log(`Constructor 호출!! => myInput : ${this.myInput}`);
    console.log(`Constructor 호출!! => myString : ${this.myString}`);
  }

  ngOnChanges(simpleChanges: SimpleChanges) {
    console.log(`ngOnChanges 호출!! => myInput : ${this.myInput}`);
    console.log(simpleChanges.myInput.previousValue);
    console.log(simpleChanges.myInput.currentValue);
  }

  ngOnInit() {
    console.log(`ngOnInit 호출!! => myInput : ${this.myInput}`);
    console.log(`ngOnInit 호출!! => myString : ${this.myString}`);
  }

  ngDoCheck() {
    console.log(`ngDoCheck 호출!! => myInput : ${this.myInput}`);
    console.log(`ngDoCheck 호출!! => myString : ${this.myString}`);
  }

  ngAfterContentInit() {
    console.log(`ngAfterContentInit 호출!!`);
  }

  ngAfterContentChecked() {
    console.log(`ngAfterContentChecked 호출!!`);
  }

  ngAfterViewInit() {
    console.log(`ngAfterViewInit 호출!!`);
  }

  ngAfterViewChecked() {
    console.log(`ngAfterViewChecked 호출!!`);
  }

  ngOnDestroy() {
    console.log(`ngOnDestroy 호출!!`);
  }
}

이번 포스트는 Angular가 제어하는 Component와 Directive의 lifecycle에 대해서 살펴봤습니다. 어떤 시점에 어떤 hook method가 호출되는지 이해하고 Change Detection이 어느 시점에 호출되는지를 이해하시면 조금 더 Angular를 이해하는데 도움이 될 듯 합니다.

728x90
반응형

'Web Programming > Angular - TypeScript' 카테고리의 다른 글

앵귤러JS (AngularJS) 란?  (0) 2018.08.29
Angular 강좌 및 참고사이트  (0) 2018.08.28
Angular Pipe  (0) 2018.08.28
Angular Directive  (0) 2018.08.28
Angular Material Table Event  (0) 2018.08.28
728x90
반응형

Pipe

이번 포스트에서는 Angular의 Pipe에 대해서 알아보겠습니다. Pipe는 HTML template내에서 출력하고자 하는 데이터를 원하는 형식으로 변환하여 출력하는 기능입니다. 원본 데이터에는 변형을 가하지 않은 상태로 출력 형태만 변경해 주기 때문에 원치않은 Side Effect를 없앨 수 있습니다.

가장 흔하게 사용하는 예부터 시작하여 사용자 정의 pipe를 생성하는 것 까지 살펴보겠습니다.


 Built-in Pipe

Angular는 몇가지 종류의 built-in pipe를 지원합니다. 자세한 사항은 여기를 클릭해 보시면 볼 수 있습니다. 이 중 몇가지만 예를 들어 보기로 하죠.

다음은 대문자로 출력내용을 바꾸는 pipe의 사용법입니다.


<h5 #resultStatus 
    class="mb-0 text-white lh-100">
    Search Result : {{searchTitle | uppercase }}
</h5>

searchTitle의 값이 그대로 interpolation을 이용해 출력되는 형태에서 uppercase라는 내장 pipe를 이용해 출력되는 영문문자열을 대문자로 변경해 출력하는 것입니다.

이와 유사하게 다음과 같이 날짜에 대한 pipe도 존재합니다.


<div>{{ today }}</div>
<div>{{ today | date }}</div>
<div>{{ today | date: 'y년 MM월 dd일' }}</div>

today = new Date();

원래 출력되는 형식과 pipe로 변형되서 출력되는 형식을 잘 보시면 될 듯 합니다. 또한 pipe사용은 체이닝을 지원합니다. 여러 pipe를 이어서 원하는 형식으로 변환시켜 출력 가능하다는 말이죠.

이번에는 우리예제 중 Material Table의 출력 중 가격부분을 통화단위로 바꾸어서 출력하는걸 해보도록 하죠.

다음은 list-box.component.html의 일부입니다.


<ng-container matColumnDef="bprice">
  <mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
  <mat-cell *matCellDef="let element"> {{element.bprice | currency: 'KRW'}} </mat-cell>
</ng-container>

위의 예에서 볼 수 있듯이 책의 가격을 통화단위(원화)로 변경해서 출력할 수 있습니다. 이렇게 built-in pipe를 이용해서 처리할 수 있고 built-in pipe로 처리할 수 없는 것들은 custom pipe를 이용해 처리할 수 있습니다.

사용자 정의 pipe를 이용해 비슷한 처리를 해 보겠습니다.

command 창을 열고 다음의 명령을 실행해 pipe를 생성합니다.

ng generate pipe bookPrice

book-price.pipe.ts 파일이 생성되게 됩니다. 기본적인 code가 생성되고 내용은 다음과 같이 수정합니다.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'bookPrice'
})
export class BookPricePipe implements PipeTransform {

  transform(value: any, args?: any): any {
    return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + '원';
  }

}

bookPrice란 이름의 pipe를 사용하면 transform() method가 호출되서 변환작업을 진행하게 됩니다. 적절하게 해당 method의 내용을 우리가 원하는 내용으로 변경해주면 되겠네요. 위의 코드는 입력받은 숫자를 3자리마다 ,를 찍고 맨 마지막에 ‘원’을 붙여서 문자열을 리턴하는 코드입니다.

우리가 만든 pipe를 Module에 등록하고 list-box.component.html 에서 다음과 같이 사용하시면 됩니다.


<ng-container matColumnDef="bprice">
  <mat-header-cell *matHeaderCellDef> Price </mat-header-cell>
  <mat-cell *matCellDef="let element"> {{element.bprice | bookPrice}} </mat-cell>
</ng-container>

이번 포스트에서는 Angular에서 Pipe라고 불리는 요소가 어떠한 역할을 하는지에 대해서 알아보았습니다. Pipe는 어렵지 않은 내용이기 때문에 built-in pipe를 사용하는 방법과 custom pipe를 작성하는 방법만 몇가지 알아두시면 됩니다.

728x90
반응형

'Web Programming > Angular - TypeScript' 카테고리의 다른 글

Angular 강좌 및 참고사이트  (0) 2018.08.28
Angular Component LifeCycle  (0) 2018.08.28
Angular Directive  (0) 2018.08.28
Angular Material Table Event  (0) 2018.08.28
Angular Service RxJS  (0) 2018.08.28

+ Recent posts