자동차세 지역별 연납신청 방법

자동차세는 매년 6월 12월 정기적으로 부과되나 일괄 납부하는 경우에는 연세액의 일부를 할인해 준다.



정기납부 : 6월(1기분), 12월(2기분)

정기납부 신청기간에 따라서 할인률이 상이하므로 여유가 있다면 1월에 하는 것이 유리하며 저도 한푼이라도 아낄려는 마음에 항상 연례 행사처럼 1월에 납부하고 있습니다.

  • 1월 신고납부 - 10%

  • 3월 신고납부 - 7.5%

  • 6월 신고납부 - 5%

  • 9월 신고납부 - 2.5%

지역별 납부방법.

서울특별시(다른지역은 16일부터이나 서울시는 지금가능)

서울시 ETAX - https://etax.seoul.go.kr/new_index.html


- 메뉴 > 전체메뉴 > 신고납부 > 자동차세연납

인천광역시

인천광역시 전자고지납부서비스 - https://etax.incheon.go.kr/index.etax


- 홈 > 신고납부 > 자동차세연납

대구광역시

대구광역시사이버지방세청 - http://etax.daegu.go.kr/jsp/index.do


- 자주찾는 질문 > 자동차세 연납신청
- 메뉴 > 전자신청 > 자동차세 연납신청

부산광역시

부산사이버지방세청 - https://etax.busan.go.kr/


- 자주찾는 서비스 > 자동차세연납신청
- 메뉴 > 신고하기 > 자동차세연납신청

그외 지역

위택스 http://www.wetax.go.kr

해당월 16일부터 가능함.


1. [편의기능] 또는 위택스 우측 상단 [메뉴]클릭
2. [부가서비스] > [자동이체관리] > [자동이체신청]에서 [신청지역(자치단체)]와 자동이체 수단 선택 후 원하시는 세목에 대하여 자동납부 신청가능합니다.

Posted by 다인,보리아빠
,

http://devcoding.tistory.com/24 슬라이드를 풀어서 써봤는데 가독성이 그리 좋진 않네요...

Graphql과 느낌이 비슷한 netflix falcor(http://devcoding.tistory.com/28)도 있으니 모르시는 분은 한번 알아두시면 좋을듯 합니다.



GraphQL Overview



Graph - 사전적으로 점과 선으로 이루어진 도형을 Graph라고 함

서로 관계가 있는 2개 또는 그 이상의 양의 상태값을 나타낸 도형

QL - SQL 비슷하다고 우선 생각하면 됨.

- 누가 만들었지?

Facebook

- 언제 만들었지?

2012년부터 내부적으로 사용하다 2015년 공개.

어떤 언어로 되어 있어?

단지 스펙이라서 구현을 하던지 언어별로 구현체가 있으니 가져다 쓰면 됨.http://graphql.org/code/

어디서 쓰고 있어?

Facebook - https://developers.facebook.com/docs/graph-api/using-graph-api)

Github - https://developer.github.com/

Why Github using GraphQL

블로그 : https://githubengineering.com/the-github-graphql-api/

  • 모든 Rest API를 제공하고 있지만 gw(integrators)의 요청을 유연하게 처리하기 힘들었다.

    GraphQL을 쓰면 신경 안써도 된다. 스키마만 업데이트 해주면 된다.

  • 때때로 response를 위해 2, 3번의 호출이 필요했다.

    GraphQL이 알아서 해준다.

  • 매개 변수에 대한 검증이 필요했다.

    매개변수에 대한 검증도 FE의 요청쿼리에 대한 validation 가능하다. eslint-plugin-graphql

  • 코드를 통해 문서를 생성하길 원했다.

    GraphiQL을 쓰면 schema에 대한 정보를 볼수 있고 Query도 실행/검증 가능

  • 요청 받을 Response에 대해서 요청자가 정의하길 원한다.

    이건 넣고 이건 빼고 할필요 없음. 요청자가 요청한 정보만 내려온다.(=overfetch 방지)

Rest API vs GraphQL HTTP상의 Endpoint 비교

REST API

엔티티별로 아래와 같은 스타일.

  • 리스트 조회 : GET /api/posts

  • 조회 : GET /api/posts/1

  • 생성 : POST /api/posts

  • 치환(수정) : PUT or PATCH /api/posts/1

  • 삭제 : DELETE /api/posts/1

GraphQL

모든 엔티티에 대해서 하나의 URL만 가짐.

  • POST /graphql

    ​-> 리스트, 조회, 생성, 수정, 삭제등

이정도면...간단하게 Database의 console에 붙어서 Query한다 생각하면 편하다.

다만 Query의 스펙을 미리 정의(=Schema) 해놓아야만 한다. Query 에 따라서 입력/조회/수정/삭제를 한다.

GraphQL Server가 할일은?

1. Node 정의



개별 node를 정의. 예 : 유저, 글, 댓글, 회사, 상품, 판매자

쉽게 이야기하면 Database의 테이블 단위

2. Node 간 관계설정



  • node에 관계 필드를 추가.- user node에 companyInfo 추가- company node에 users 추가

  • 관계 필드에 대해서 Store 연결.

    - companyInfo필드의 Type은 CompanyType- users 필드의 Type은 GraphQLList(UserType)과 같이 감싸준다.

노드(점)의 관계 필드(선)가 곧 Store 연결(=DB 조회)


3. Root Query 생성(선정).

Node중 최상위에서 조회가능한 녀석들을 분류해야한다.


Root Query?

  • REST API의 여러 조회용 END POINT의 모음이라 생각하면 이해하기 쉽다. 즉. Entry Point를 제공자가 정의해주는 것이다.

  • RootQuery는 의미적인 표현인 것이고 일반 node와 Type/동작 동일.= GraphQLObjectType

  • 다만 의미적으로 Root Query Node의 경우에는 다른 node를 참조만 하고,다른 노드로 부터 참조되지 않는다.

GraphQL로 서비스 구성 예시

DB든 외부연동서버든 처리할 데이타에 대해서는 Node 정의를 해주어야 합니다.


GraphQL로 서비스 예시 2

여기서도 GraphQL서버에서 Composite을 위해서 서버별 타입별로 Node정의를 해주어야 한다.

만약 A,B 서버에 동일하게 생긴 Node가 있더라도 관계설정이 달라질수 있으므로각각을 구분해주어야 한다.

GraphQL 사용시 주요 장점.

  • FE/Native의 요청 필드만 리턴하므로 Overfetch 방지.

  • MSA 구조에서 여러 서버의 데이타를 효율적으로 Data Integration 한다.

  • REST API에서 2~3회 요청에 걸쳐 데이타를 가져오는 경우를 간단하게 1 회 요청으로 끝낼 수 있다.(유연성 甲)# BE 개발자가 별도 Endpoint 추가하고 로직으로 풀던 문제를 쉽게 끝낼 수 있다.

전체 구조



이렇게도 나누는것도 가능은 할듯.

코드를 보면 이렇게도 가능할 것으로 생각된다.다만 아래와 같이 나눌 경우 동일 데이타에 대해서 변경과 조회가

함께 일어나므로 시점에 따라 값이 달라질수도 있는 문제가 발생 할 수 있다.

샘플코드

회사와 사람 Node

코드로 두 Node로 관계를 지어보자.

샘플을 실행시켜보려면 https://github.com/gidong-lee/graphQL_exam

샘플코드에 대해서.

  • axios는 back 단 rest api를 호출해주는 jQuery의 ajax같은 라이브러리다.(예 : Spring 개발시 RestTemplate)

  • JSON Server는 json파일을 읽어 쉽게 개발/목킹용 rest api 서버를 만들어 주는 녀석이다.입력,수정,삭제,페이징등을 모두 처리해준다.GitHub : https://github.com/typicode/json-server

User Type

const UserType = new GraphQLObjectType({
 name: 'User', // GraphQL Object Name(필수)
 fields: () => ({
   id: {type: GraphQLString},
   firstName: {type: GraphQLString},
   age: {type: GraphQLInt},
   companyId: {type: GraphQLString},
   company: {   /* 연결(user -> company) */
     type: CompanyType,
     resolve(parentValue, args) {
       console.log(parentValue, args);
       return axios.get(`${SERVER_DOMAIN}/companies/${parentValue.companyId}`)
        .then(req => req.data);
    }
  }
})
});

위의 fields.company 필드가 관계필드가 된다.

관계 필드는 곧 DB/Cache/rest server 연결(=DB 조회)을 뜻한다.

코드의 axios는 뒤단의 rest api를 호출하여 데이타를 가져오는 것이니 크게신경 안써도 됨.

Company Type


const CompanyType = new GraphQLObjectType({
 name: 'Company',
 fields: () => ({
   id: {type: GraphQLString},
   name: {type: GraphQLString},
   description: {type: GraphQLString},
   users: { /* 연결(company -> users) */
     type: new GraphQLList(UserType),
     args: {limit: {type: GraphQLInt}},
     resolve(parentValue, args) {
       const { limit = 20 } = args;
       return axios.get(
         `${SERVER_DOMAIN}/companies/${parentValue.id}/users?_limit=${limit}`
      ).then(req => req.data);
    }
  }
})
});

위의 fields.users 필드가 관계필드가 된다.

관계 필드는 곧 DB/Cache/rest server 연결(=DB 조회)을 뜻한다.

users필드의 타입이 GraphQLList(UserType)인 것을 잘 숙지하자.

Root Query

Query(조회) 시 시작될 수 있는 node 를 지정하여야 한다.따라서 node product 조회는 RootQuery 필드에 없으므로 company를 통해서만 접근 할 수 있다.


RootQuery 지정


const RootQuery = new GraphQLObjectType({
 name: 'RootQueryType',
 fields: () => ( {
   user: { /* RootQueryObject에 User연결 */
     type: UserType,
     args: {id: {type: GraphQLString}},
     resolve(parentValue, args) {
       return axios.get(`${SERVER_DOMAIN}/users/${args.id}`)
        .then(req => req.data);
    }
  },
   company: { /* RootQueryObject에 Company연결 */
     type: CompanyType,
     args: {id: {type: GraphQLString}},
     resolve(parentValue, args) {
       return axios.get(`${SERVER_DOMAIN}/companies/${args.id}`)
        .then(req => req.data);
    }
  }
})
});

관계 필드의 resolve 함수?

parentValue -> 나의 상위에서 주입해준 값.user의 Company에서 조회하여 리턴해준값

args -> Query 호출시에 적어주는 값. 예 : id, searchKeyword, limit, first, last, page, lastNum


const CompanyType = new GraphQLObjectType({
 name: 'Company',
 fields: () => ({
   id: {type: GraphQLString},
   name: {type: GraphQLString},
   description: {type: GraphQLString},
   users: {
     type: new GraphQLList(UserType),
     args: {limit: {type: GraphQLInt}},
     resolve(parentValue, args) {
       const { limit = 20 } = args;
       return axios.get(
         `${SERVER_DOMAIN}/companies/${parentValue.id}/users?_limit=${limit}`
      ).then(req => req.data);
    }
  }
})
});

GraphiQL - Graphql의 개발자도구.

작성한 Schema를 보고 Query를 작성하고 유효성을 검사하면서 테스트를 할 수 있는 good dev tool


설치버전도 있고, 서버(dev용으로) 띄울때 함께 띄울수 있다.




Query 해보기

User정보와 회사정보를 가져오는 샘플

요청


{
 user(id: "23") {
   id
   firstName
   company {
     name
  }
}
}
결과


{
 "data": {
   "user": {
     "id": "23",
     "firstName": "ko",
     "company": {
       "name": "tomorrow"
    }
  }
}
}

Company정보와 users를 가져오는 샘플

요청


{
 company(id: "1") {
   id
   name
   description
   users {
     id
     firstName
     age
  }
}
}
결과

{
 "data": {
   "company": {
     "id": "1",
     "name": "tomorrow",
     "description": "111st",
     "users": [
      {
         "id": "23",
         "firstName": "ko",
         "age": 20
      },
      {
         "id": "40",
         "firstName": "lee",
         "age": 40
      },
      {
         "id": "44",
         "firstName": "ra",
         "age": 45
      }
    ]
  }
}
}

Mutation

변경작업(추가, 수정, 삭제)

Response Type에 따라서 Query를 원하는대로 데이타를 받을 수도 있다.

Mutation 사용시 장점.

  • 사실 로직적으로 내부적으로 변경하는 로직을 있는것 뿐 조회 Query와 구조적으로는 같다.

  • Mutation query를 호출하더라도 해당 Mutation의 Return Type에 따라서 Response를 자유롭게 변경 할 수 있다.



Mutation - User 추가


const mutation = new GraphQLObjectType({
 name: 'Mutation',
 fields: {
   addUser: {
     type: UserType,
     args: {
       firstName: {type: new GraphQLNonNull(GraphQLString)},
       age: {type: new GraphQLNonNull(GraphQLInt)}     },
     resolve(parentValue, {firstName, age}) {
       return axios.post(`${SERVER_DOMAIN}/users`, {firstName, age})
        .then(res => res.data);
    }
  },
   deleteUser: {},
   editUser: {}
}
})

mutation을 이용한 유저 추가 및 생성 정보 받기

요청


mutation {
 addUser( firstName: "gu", age: 40 ) {
   id
   firstName
   age
}
}
결과


{
 "data": {
   "addUser": {
     "id": "SJ0Wox-i-",
     "firstName": "gu",
     "age": 40
  }
}
}


Mutation - User 삭제


const mutation = new GraphQLObjectType({
 name: 'Mutation',
 fields: {
   addUser: {},
   deleteUser: {
     type: UserType,
     args: {
       id: {type: new GraphQLNonNull(GraphQLString)}
    },
     resolve(parentValue, {id}) {
       return axios.delete(`${SERVER_DOMAIN}/users/${id}`)
        .then(res => res.data);
    }
  },
   editUser: {}
}
})

mutation을 이용한 유저 삭제

요청


mutation {
deleteUser(id : "SJ0Wox-i-") {
  id
}
}
결과


{
 "data": {
   "deleteUser": {
     "id": null
  }
}
}


Mutation - User 수정


const mutation = new GraphQLObjectType({
 name: 'Mutation',
 fields: {
   addUser: {},
   deleteUser: {},
   editUser: {
     type: UserType,
     args: {
       id: {type: new GraphQLNonNull(GraphQLString)},
       firstName: {type: GraphQLString},
       age: {type: GraphQLInt},
       companyId: {type: GraphQLString}
    },
     resolve(parentValue, args) {
       return axios.patch(`${SERVER_DOMAIN}/users/${args.id}`, args)
        .then(res => res.data);
    }
  }
}
})

mutation을 이용한 유저 수정(Patch)

요청

mutation {
 editUser( id: "44", firstName: "ra", age: 45) {
   id,
   firstName,
   age,
   company {
     id,
     name,
     description
  }
}
}
결과


{
 "data": {
   "editUser": {
     "id": "44",
     "firstName": "ra",
     "age": 45,
     "company": {
       "id": "1",
       "name": "tomorrow",
       "description": "111st"
    }
  }
}
}

상황극

GraphQL을 안쓸때 상황.

  • login.json에 userName이랑 image좀 추가해주세요.

  • NoticeList.json에서는 id, title, 작성자만 필요하니 나머지는 빼주세요.

  • 몇일있다가 수정일은 추가해주세요.

  • 이 데이타는 결과에 따라서 추가 Request가 필요하므로 서버에서 한번에 말아주세요.

  • 하위 호환 때문에 API 버전 변경이 필요해요.

GraphQL을 쓰게되면.

  • Root Query에 머하나 추가해주세요.

  • A 랑 B랑 릴레이션 맺어주심 안돼요?

  • mutation 추가해주세요.

  • 빨리 끝내고 커피 한 잔 하러 가시죠.(추정)

FrontEnd Client 3총사

URL


'Javascript/node.js Coding' 카테고리의 다른 글

ES6+(EcmaScript2015+) 정리(ing)  (0) 2017.12.27
Mobx with angular 정리.  (0) 2017.12.05
Netflix Falcor Overview  (0) 2017.12.03
Posted by 다인,보리아빠
,

Oracle의 MERGE INTO 기초

Database를 Oracle를 사용할때 유용하게 사용하는 Merge Into에 대해서 간단하게 정리.

개인적으로 실서비스에서는 크게 사용한적은 없는 것 같고 Admin이나 배치 개발시에 MyBatis와 함께 유용하게 사용하고 있다.

요구사항 : 상품이 있으면 수정하고 없으면 삽입해라.

기존 Update와 Insert 만 사용예시

mybatis를 사용한다고 했을때 가장 간단하게 처리하는 방법은 아래와 같다.

  1. 우선 Update query를 실행한 후 update 된 행의 개수를 resultType으로 return

  2. Insert into query실행.(위 update의 update rows가 0인 경우에만 실행.)

Update Query 예시.


UPDATE PRODUCT pd
SET USE_YN = #{useYn}
,PRODUCT_NAME = #{productName}
,MODIFY_DATE = SYSDATE
   WHERE pd.PRODUCT_ID = #{productId}

Insert Query 예시.

INSERT INTO PRODUCT (
    PRODUCT_ID
    , PRODUCT_NAME
    , USE_YN
    , MODIFY_DATE
  ) values (
    #{productId}
    , #{productName}
    , #{useYn}
    , SYSDATE
  )

Merge into 사용하기(Update 와 Insert 합치기.)

위 요구사항을 Merge Into를 이용하여 구현하면 아래와 같다.

기본적인 사용법은 너무 간단해서 따로 추가 내용은 필요가 없을 정도이다.

레퍼런스 사이트에 가면 좀 더 디테일 하게 내용을 확인 할 수 있다.

Merge into Query with comment

많이 사용하는 구성은 의외로 간단하다. 다만 생각해야 할 것은 Update 또는 Insert를 한번에 처리하므로 Parameter값을 잘 생각해서 주어야 한다.

MERGE INTO Product pd /* 대상이 되는 테이블 또는 뷰*/
USING DUAL /* 위의 하나의 테이블만 이용할려면 DUAL을 적으면 됨.*/
ON ( pd.PRODUCT_ID = #{productId} ) /* ON 에 해당되는 데이타가 UPDATE시 Rows가 됨. */
WHEN MATCHED THEN /* ON 조건에 해당되는 것이 있으면 아래 실행(UPDATE) */
UPDATE SET       /* Update시 테이블명이나 Where조건이 모두 위에 있다고 생각하면 됨 */
USE_YN = #{useYn}
,PRODUCT_NAME = #{productName}
,MODIFY_DATE = SYSDATE
WHEN NOT MATCHED THEN /* ON 조건에 매칭되지 않으면 아래 실행(Insert)*/
INSERT ( /* INSERT INTO PRODUCT -> INSERT로 퉁쳤다는걸 기억하다. */
    PRODUCT_ID
    , PRODUCT_NAME
    , USE_YN
    , MODIFY_DATE
  ) values (
    #{productId}
    , #{productName}
    , #{useYn}
    , SYSDATE
  )

Merge into Query without comment


MERGE INTO Product pd
USING DUAL
ON ( pd.PRODUCT_ID = #{productId} )
WHEN MATCHED THEN
UPDATE SET
USE_YN = #{useYn}
,PRODUCT_NAME = #{productName}
,MODIFY_DATE = SYSDATE
WHEN NOT MATCHED THEN
INSERT (
    PRODUCT_ID
    , PRODUCT_NAME
    , USE_YN
    , MODIFY_DATE
  ) values (
    #{productId}
    , #{productName}
    , #{useYn}
    , SYSDATE
  )

Syntax diagram

아래는 Oracle 내 레퍼런스 사이트내 Merge Into에 대한 syntax diagram이다.

https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm#SQLRF01606



merge_update_caluse 구문



merge_insert_clause 구문

'Database' 카테고리의 다른 글

java.sql.SQLSyntaxErrorException: ORA-00911: 문자가 부적합합니다  (0) 2017.12.22
Mysql 사용자 팁  (0) 2014.12.02
Posted by 다인,보리아빠
,

오랜만에 와이프와 영화를 무료로 보기 위해서 노력해 얻은 정보를 정리합니다.

준비 및 자격 사항

  • T멤버십 VIP여야 되는 것 같음.(와이프는 VIP가 아니여서 예매를 못함.)

  • SK패밀리카드가 있어야함.(T 멤버십 더블 롯데 신용카드도 가능)

특이사항

  • T멤버십 VIP의 무료영화를 다 써야지만 추가적으로 쓸수 있음.

  • 아마도 한달에 무조건 한명밖에 안되는 것 같음.

  • 내 SKT맴버십외 다른 사람의 것을 넣어서 한번에 2장 무료영화를 신청할 수 있을지 시도가 필요함.단 두명모두 VIP여야함.

결론

결론은 무조건 한달에 한번만 예매할 수 있는 것으로 확인됨.

카드를 등록하여 무료영화를 년 12회 볼수 있더라도 최대 18회까지 볼수도 있을 것 같으나

영화는 무조건 한달에 1매밖에 예매를 못하는 것 같음.

머 이런...

어쨌든 카드 등록 방법 및 사용법 안내드림.

패밀리카드 등록하여 예매방법

URL : http://tmembership.tworld.co.kr/web/html/vip_lounge/vip_3d_movie.jsp?sel=5

1. URL로 이동.


2. 영화 고르기.


3. 무료예매화면 제일 하단에 T멤버십카드 추가등록.


4. T멤버십 제휴 하나카드 등록(여러카드등록하면 무료예매혜택이 늘어남. 12장 이상되면 어찌되는진 모르겠음)


5. 카드정보 등록 및 요청. Validation check후 저장됨.


6. 이전 예매페이지로 이동하면 등록한 제휴카드가 나옴.


Posted by 다인,보리아빠
,

지난주에는 만화방에서 신과함께 만화를

이번주에는 극장에서 영화를 보고나서의 감상평.

우선 영화볼때 Tip.

  • 영화 보러 갈때는 휴지 챙겨가세요.(신파극)

  • 음료수 필수(목이메임)

  • 다시 한번 이야기하지만 엔딩크레딧 전에 쿠키영상이 다임.


영화평

개인적으로 점수는 별3.5개쯤. 우선 내용은 만화에서 내용을 끌어가던 엘리트 진기한 변호사 가 나오지 않아서

조금 이상하긴 했지만 엘리트 진기한 변호사가 나오면 신파인 영화에

어울리지 않았을지도 모르겠다.

사실 만화에서는 그리 신파가 없다.

주인공내용도 다르고

등장 인물과 연계 등등 많은 차이가 있음.

조금 무미건조 할 수 있는 만화에 스토리를 엮기 위해서 각색된 부분들이 많이 있다.

사실 만화를 보고 영화를 바로 보니 이해가 감.

그래서 안 슬플줄 알았는데....

스포일러는 없다.

다시 한번 착하게 살아야겠다는 생각을 하게됨.

와이프평

이정재 잘생긴줄 몰랐는데 잘생겼네.

후속편

2편이 함께 제작되었고 내년(2018년) 8월 1일 개봉예정이고

1, 2편을 함께 촬영하였다고 한다.

그래서 제작비도 많이 아꼈다고 한다.

아마도 만화책에서 나오고 영화에서 스포 및 쿠키영상으로 나오는 그 할아버지의 집과

그 집에 사는 가택신들이 후속편의 내용일 것으로 예상된다.

만화에 나오는 가택신

가택신이 자리를 비우면 비운자리에는 항상 문제가 생긴다고 함. 가세가 기운다고 함.....

  • 성주신(아마도 마동석) : 집을 다스리는 신.

  • 조왕 : 살림살이를 하는 부엌신으로 부녀자들의 신이라고 함.

  • 측신 : 화장실을 관장하는 신.똥신?

  • 철융신 : 장독간을 지키는 신으로 만화에서는 장맛을 책임진다.


이건 사진찍어온 것.


Posted by 다인,보리아빠
,

Typora markdown editor로 티스토리 글 붙여넣기.

개인적으로 글을 조금 정리하여 작성하고 싶을때 markdown Editor를 이용한다.

그중에서도 Typora 를 이용하여 작성을 하는데

작성한 내용을 그대로 tistory에 그대로 붙여넣고 싶은 경우가 있다.

그럴 경우 몇가지 문제점과 해결방안에 대해서 이야기 해보자.

복사 & 붙여넣기 시 문제들

1. 코드블럭 줄내림 문제.

아래와 같이 code block을 넣는 경우 줄내림이 되지 않아 곤란한 상황이 발생한다.


var msg = "안녕하세요 동해물과 백두산이 마르고 닮도록 하느님이 보우하사 우리나라 만세 무궁화 삼천리 화려강산 대한 사람 대한으로 길이 보전하세";

console.log(msg);

2. 문단 간 빈줄 없어짐.

Typora에서 한줄 공백을 넣어도 공백줄이 보이지 않는 문제가 있다.

은근 귀찮다.

3. 글자가 너무 작다.

Typora에서 볼때보다 글자가 너무 작아서 가독성이 떨어진다.

해결방안

1. 테마지정

흰색 배경의 Tistory에는 Typora github 테마가 가장 잘 어울리는 듯하다.

그래서 Typora내에서 github으로 선택.

자신의 블로그 본문 배경색을 Typora의 테마랑 맞추면 어느것을 해도 상관 없을 듯함.

2. Tistory CSS 편집.

블로그관리 > 꾸미기 > CSS편집 > CSS탭에 아래의 내용을 추가하면 Typora에서 볼때와 비슷하게 폰트사이즈와 줄내림 처리등이 가능하다.

추가적으로 발생하는 문제는 그때 그때 CSS를 수정해서 하는 수밖에는 없을 것 같다.


/* ***** markdown code block ***** */
.md-fences span {
white-space : normal;
font-size : 1.1em;
}
.md-line {
min-height : 24px;
}
.cm-tab {
width : 24px;
}
#content blockquote {
   border-left: 4px solid #dddddd;
   padding: 0 15px;
   color: #777777;
}

3. 복붙시 Tip

코드블럭이나 heading과 같은 부분에서 복사하지 말고 빈줄을 에서 전체선택을 해서 복사하여 붙여넣기를 하면됨.

Posted by 다인,보리아빠
,


ES6+(ECMAScript2015+)

var

헷갈릴수 있는 녀석이다.

앞으론 어지간해선 쓰지말자.

let

Block( {} ) 단위 스코프 변수

const

Block( {} ) 단위 스코프 상수

단 값 재할당은 안되지만 Object내의 값은 바꿀수 있음.

class 와 getter setter

class Product {
   constructor() {
       this._id = null;
  }
   get id() {
       return this._id
  }
   set id(id) {
       if (!!id && !isNaN(id) && !Number.isInteger(id))
           throw new Error('id must integer');
       this._id = id;
  }
}
class newProduct extends Product {
   constructor() {
       super();
  }
   getId() {
       return `Id is ${this.id}`;
  }
}

Default Parameter

function print(value = "hello world"){
   console.log(value);
}

Spread operator(펼침연산자)

내용을 하나씩 풀어 대입해준다.

function f(x, y, z) {  
   return x + y + z;  
}    
const args = [1, 2, 3];  
 
f.apply(this, args);  // ES5  
f(...args); // ES6

const numList1 = [1,2,3];
const numList2 = [4,5,6];
const numList3 = [...numList1, ...numList2]; //[1,2,3,4,5,6]


const user = { "name" : "gildong" };
const diffUser = { ...user, "age" : 40 }; //{ "name" : "gildong", "age" : 40 }

Destructuring assignment

Object

const user = { "name" : "gildong", "age" : 40, "path" : "pangyo" };
const { name, age, path : address, company = "무직" } = user;
//path를 address로 rename
//company에 default Value 추가.

// 때에 따라 이렇게 사용하기도 한다.
function sum({a, b}) {
return a + b;
}
const values = { a : 10, b : 20};
sum(values)

Array

const numList = [1, 2, 3, 4, 5, 6, 7, 8];
const [first, second, ,four, ...rest] = numList;
console.log(rest); //[5, 6, 7, 8]
// ...rest와 같이 사용하는 것을 rest operrator 라고 함.

Arrow function(화살표 함수)

lambda 표현식으로 함수를 정의할 수 있다. 아래 함수는 모두 동일한 일을 한다.

function sum(a, b) {
   return a + b;
}
const sum = (a, b) => { return a + b };
const sum = (a, b) => a + b; // {}를 감싸기 않으면 자동으로 return 을 한다.

// 인수가 하나인 경우 아래와 같이 () 제외할 수 있다.
const double = d => d * 2;

Arrow function의 경우 함수가 정의된 시점이 this가 됨. 즉 화살표 함수를 감싸는 스코프를 this로 계승 받음.

var userName = "둘리";
let user = {
 "userName" : "gildong",
 func : function() {
   setTimeout(function() {
     console.log("func", this, this.userName); // func, window, 둘리
  },1000);
},
 arrowFunc() {
   setTimeout(() => {
     console.log("arrowFunc", this, this.userName); // arrowFunc, user, gildong
  },1000);
}
}
user.func(); // function으로 정의된 callback의 경우 Window를 가리킴
user.arrowFunc(); // user가 정의된 이후 callback이 실행됨으로 this가 user object를 가리킴

let user2 = {
 "userName" : "gildong",
 func : function() {
   console.log("func", this, this.userName); // func, user2, gildong
},
 arrowFunc : () => {
   console.log("arrowFunc", this, this.userName); // arrowFunc, window, 둘리
}
}

user2.func(); // object method인 경우 호출자로부터 this를 전달 받음.
user2.arrowFunc(); // 정의 시점에 user2는 정의 전이므로 this는 window 가 된다

Property value shorthand

const id = 10;
const obj = { id };  // { "id" : id } 과 같다.

String

템플릿 문자열(backtick), backtick을 통한 multiline 제공

const message = "world";

console.log(`hello ${message}
javascript`)

Map

key, value 구조로 데이타 저장. 잘 알고 계시는

const names = new Map();

names.set("철수", 1);
names.set(2, "영희");
names.keys(); // MapIterator {"철수", 2}
names.values(); // MapIterator {1, "영희"}
names.size; // 2
names.has("철수"); // true
names.delete("철수"); //true

WeakMap

Map은 원시 타입, 객체 참조값 모두 키로 사용할 수 있으나 WeakMap은 객체 참조값만 사용가능하다.

포인트는 내부에 저장된 객체를 참조하는 값이 없을 경우 가비지 콜렉션의 대상이 된다.

이터러블 규약을 따르지 않아 열거할 수 없고 크기를 알수 없다.

개인적으로 어디에 쓸지 잘 모르겠다.

let wm = new WeakMap();

function func(){
   const someObj = {};
wm.set(someObj, 1);
wm.has(someObj);
console.log(wm);
}

func();
console.log(wm);

Set

유일한 데이타를 저장하기 위해서 사용한다.

특이한 점은 Object의 경우 참조값이 들어가게 된다.

따라서 아래 예제와 같이 {}을 넣으면 동일한 값이지만 참조값이 다르므로 추가된다.

const keySet = new Set();
keySet.add("10");
keySet.add("20");
keySet.add(20);
keySet.add({});
keySet.add({});
// "10", "20", 20, Object, Object
keySet.has(20); // true
keySet.delete(20); // true
keySet.size; // 4

keySet.clear();

WeakSet

Set은 원시타입과 객체참조값 모두 담을수 있지만 WeakSet은 객체 참조값만 담을 수 있다.

WeakMap처럼 이터러블 규약을 따르지 않는다.

내부에 저장된 값을 참조하는 값이 없을 때는 가비지 콜렉션 대상이 된다.

Generator

절차적 처리를 위해서 사용하며 제너레이터 함수의 yield 의 수만큼 순차적으로 값을 반환한다.

function* action(url){
   
}
function* generator_function() {
 let a = yield 12
 let b = yield a + 1
 let c = yield b + 2
 yield c + 3
}

let generator = generator_function()

console.log(generator.next().value)   // 12
console.log(generator.next(5).value)  // 6
console.log(generator.next(11).value) // 13
console.log(generator.next(78).value) // 81
console.log(generator.next().done)    // true

Promies

콜백헬 방지

작성중.....

Async await(es7)

비동기를 동기처럼 작동시킴

작성중....

'Javascript/node.js Coding' 카테고리의 다른 글

GraphQL Overview (graphql.js server code)  (0) 2018.01.05
Mobx with angular 정리.  (0) 2017.12.05
Netflix Falcor Overview  (0) 2017.12.03
Posted by 다인,보리아빠
,


아래와 같이 에러가 나는 경우

Unable to complete the scan for annotations for web application [] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [org.bouncycastle.asn1.ASN1EncodableVector->org.bouncycastle.asn1.DEREncodableVector->org.bouncycastle.asn1.ASN1EncodableVector]

원인 : 순환참조 문제.

조치 :

tomcat container path에 해당하는 conf/catalina.properties

org.apache.catalina.startup.ContextConfig.jarsToSkip=bcprov*.jar

bcprov*.jar 추가.

로그전체.

java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
12월 20, 2017 2:31:56 오후 org.apache.catalina.core.AprLifecycleListener init
심각: An incompatible version 1.1.31 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.32
12월 20, 2017 2:31:56 오후 org.apache.catalina.core.AprLifecycleListener init
심각: An incompatible version 1.1.31 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.32
12월 20, 2017 2:31:56 오후 org.apache.catalina.core.AprLifecycleListener init
심각: An incompatible version 1.1.31 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.32
12월 20, 2017 2:31:56 오후 org.apache.catalina.core.AprLifecycleListener init
심각: An incompatible version 1.1.31 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.32
12월 20, 2017 2:31:56 오후 org.apache.catalina.core.AprLifecycleListener init
심각: An incompatible version 1.1.31 of the APR based Apache Tomcat Native library is installed, while Tomcat requires version 1.1.32
12월 20, 2017 2:31:57 오후 org.apache.coyote.AbstractProtocol init
정보: Initializing ProtocolHandler ["http-bio-8080"]
12월 20, 2017 2:31:57 오후 org.apache.coyote.AbstractProtocol init
정보: Initializing ProtocolHandler ["ajp-bio-8019"]
12월 20, 2017 2:31:57 오후 org.apache.catalina.startup.Catalina load
정보: Initialization processed in 404 ms
12월 20, 2017 2:31:57 오후 org.apache.catalina.core.StandardService startInternal
정보: Starting service Catalina
12월 20, 2017 2:31:57 오후 org.apache.catalina.core.StandardEngine startInternal
정보: Starting Servlet Engine:
12월 20, 2017 2:31:58 오후 org.apache.catalina.core.ContainerBase startInternal
심각: A child container failed during start
java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
      at java.util.concurrent.FutureTask.report(FutureTask.java:122)
      at java.util.concurrent.FutureTask.get(FutureTask.java:192)
      at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1123)
      at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:816)
      at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
      at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1575)
      at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1565)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
      at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
      ... 6 more
Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations for web application [] due to a StackOverflowError. Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies. The class hierarchy being processed was [org.bouncycastle.asn1.ASN1EncodableVector->org.bouncycastle.asn1.DEREncodableVector->org.bouncycastle.asn1.ASN1EncodableVector]
      at org.apache.catalina.startup.ContextConfig.checkHandlesTypes(ContextConfig.java:2126)
      at org.apache.catalina.startup.ContextConfig.processAnnotationsStream(ContextConfig.java:2072)
      at org.apache.catalina.startup.ContextConfig.processAnnotationsJar(ContextConfig.java:1947)
      at org.apache.catalina.startup.ContextConfig.processAnnotationsUrl(ContextConfig.java:1913)
      at org.apache.catalina.startup.ContextConfig.processAnnotations(ContextConfig.java:1898)
      at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1330)
      at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:889)
      at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:386)

Posted by 다인,보리아빠
,



Mybatis시 아래와 같이 에러가 났다면 십중팔구 해당 쿼리에 세미콜론이 있는지 확인하세요.


### Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 문자가 부적합합니다

; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: ORA-00911: 문자가 부적합합니다

at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:91)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371)
at com.sun.proxy.$Proxy44.selectList(Unknown Source)
at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:198)
at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:119)
at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:63)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52)

'Database' 카테고리의 다른 글

Oracle의 MERGE INTO 기초  (1) 2018.01.02
Mysql 사용자 팁  (0) 2014.12.02
Posted by 다인,보리아빠
,


얼마전 회사 동료와 AWS의 CloudFront에 대해서 이야기하다 akamai의 CDN 서비스에서 최적경로를 찾아주는 방법에 대해서 이야기를 했었다.

서로 상반되는 부분이 있어서 정확하게 집고 넘어가는 것이 좋을 것 같아서 정리합니다.

결론부터 이야기하면 대부분 기본으로 세팅을 하는게 가장 빠르다.



기본적으로 CDN서비스를 사용하면 접속하는 User에게 가장 가까운(또는 가능빠른) 서버를 알려주게 된다.

이때 가장 가까운 서버를 알려주기 위해서는 CDN은 DNS 이용한다

대부분의 경우 사용자가 별도의 설정을 하지 않고 ISP를 통해서나 DHCP서버를 통하여 DNS 정보를 받게된다.

CDN의 DNS는 실제 요청자의 IP를 알수 없다.

다만 수없이 많은 DNS의 IP만을 알수 있다. 그중에 내가 사용하는 DNS도 있을 것이다.

CDN의 DNSDNS 매핑 테이블을 관리하여 요청하는 DNS의 IP별로 최적의 IP를 내려준다.

결국 PC에 설정되어 있는 DNS의 IP별로 최적의 서버로 할당을 해주는 구조이다.

따라서 Local DNS를 엄한 곳으로(예 : 거리상으로 먼곳에 있는 DNS) 설정을 하면 엄한곳에서 가장 가까운 IP를 알려줄테니 대역폭은 몰라도 레이턴시가 좋지 않게된다.

지속적인 다운로드가 아닌 이상 일반적인 웹페이지에서는 레이턴시는 매우 중요한 요소이다.

어느 이상의 속도가 되면 대역폭은 큰의미가 없다.

레이턴시는 빠르면 빠를수록 웹페이지가 뜨게된다.



아래 이미지를 보면 대역폭(상단), 레이턴시(하단)의 성능에 따라 페이지 로딩 시간의 차이를 보여준다.

그만큼 웹서비스에서는 레이턴시가 중요하다.

구글엔지니어에게듣는 네트워킹과 웹 성능 최적화 기법 책중

http://chimera.labs.oreilly.com/books/1230000000545


우리가 크롬 브라우저로 ebay에 접속할때 domain으로 ip를 찾는 순서를 보자.

~ www.ebay.com 을 누르면 아래방법으로 순차적으로 IP를 찾아내서 실제 접속은 IP로 하게 된다.

  1. 브라우저 : 현재 caching하고 있는 DNS인지 확인한다.

  2. /etc/hosts

    • 기본적으로 /etc/hosts등에 특수한 경우에 대해서 domain과 ip를 매핑해놓는다.

    • 예 : 127.0.0.1 localhost

    • 127.0.0.1는 루프백 IP로 현재 컴퓨터를 뜻한다.

  3. resolev.conf 에 설정된 NameServer에 질의 요청을 한다.


테스트할 DNS

SK Broadband (브로드밴드) 현재 사용중인 ISP기본 DNS 서버 주소 - 210.220.163.82

KT DNS기본 DNS 서버 주소 - 168.126.63.1

Google Public (구글 퍼블릭)기본 DNS 서버 주소 - 8.8.8.8

조회된 IP별 레이턴시 비교

SKB -> round-trip min/avg/max/stddev = 3.834/5.170/7.445/1.112 ms

KT -> round-trip min/avg/max/stddev = 4.373/7.757/22.246/5.128 ms

GOOGLE - round-trip min/avg/max/stddev = 65.981/68.006/71.258/1.896 ms

정리하면

속도는 SKB -> KT -> GOOGLE 순으로 나왔다.

아마 KT 사용자였다면 KT -> SKB -> GOOGLE순으로 나왔을 것이다.

결과적으로 아카마이가 최단거리 서버를 잘 찾아준 것을 알수 있다.

실험 1 DNS에 따른 www.ebay.com 조회 결과(저는 브로드밴드사용자)

$ nslookup
> www.ebay.com
Server: 192.168.11.1
Address: 192.168.11.1#53

Non-authoritative answer:
www.ebay.com canonical name = slot9428.ebay.com.edgekey.net.
slot9428.ebay.com.edgekey.net canonical name = e9428.b.akamaiedge.net.
Name: e9428.b.akamaiedge.net
Address: 210.205.4.6

> server 168.126.63.1
Default server: 168.126.63.1
Address: 168.126.63.1#53
> www.ebay.com
Server: 168.126.63.1
Address: 168.126.63.1#53

Non-authoritative answer:
www.ebay.com canonical name = slot9428.ebay.com.edgekey.net.
slot9428.ebay.com.edgekey.net canonical name = e9428.b.akamaiedge.net.
Name: e9428.b.akamaiedge.net
Address: 104.76.90.106

> server 8.8.8.8
Default server: 8.8.8.8
Address: 8.8.8.8#53
> www.ebay.com
Server: 8.8.8.8
Address: 8.8.8.8#53

Non-authoritative answer:
www.ebay.com canonical name = slot9428.ebay.com.edgekey.net.
slot9428.ebay.com.edgekey.net canonical name = e9428.b.akamaiedge.net.
Name: e9428.b.akamaiedge.net
Address: 104.124.245.241

실험2. 조회결과별 ping 10회 테스트

해당 테스트를 통해 round-trip(레이턴시) 이곳에서 해당 목적지까지 패킷이 다녀온 시간을 잰다.


$ ping 104.76.90.106 -c10
PING 104.76.90.106 (104.76.90.106): 56 data bytes
64 bytes from 104.76.90.106: icmp_seq=0 ttl=52 time=7.281 ms
64 bytes from 104.76.90.106: icmp_seq=1 ttl=52 time=4.755 ms
64 bytes from 104.76.90.106: icmp_seq=2 ttl=52 time=5.073 ms
64 bytes from 104.76.90.106: icmp_seq=3 ttl=52 time=7.184 ms
64 bytes from 104.76.90.106: icmp_seq=4 ttl=52 time=6.049 ms
64 bytes from 104.76.90.106: icmp_seq=5 ttl=52 time=4.373 ms
64 bytes from 104.76.90.106: icmp_seq=6 ttl=52 time=10.428 ms
64 bytes from 104.76.90.106: icmp_seq=7 ttl=52 time=22.246 ms
64 bytes from 104.76.90.106: icmp_seq=8 ttl=52 time=4.593 ms
64 bytes from 104.76.90.106: icmp_seq=9 ttl=52 time=5.587 ms

--- 104.76.90.106 ping statistics ---
10 packets transmitted, 10 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 4.373/7.757/22.246/5.128 ms


$ ping 104.124.245.241 -c10
PING 104.124.245.241 (104.124.245.241): 56 data bytes
64 bytes from 104.124.245.241: icmp_seq=0 ttl=52 time=68.003 ms
64 bytes from 104.124.245.241: icmp_seq=1 ttl=52 time=67.227 ms
64 bytes from 104.124.245.241: icmp_seq=2 ttl=52 time=66.554 ms
64 bytes from 104.124.245.241: icmp_seq=3 ttl=52 time=71.258 ms
64 bytes from 104.124.245.241: icmp_seq=4 ttl=52 time=69.599 ms
64 bytes from 104.124.245.241: icmp_seq=5 ttl=52 time=67.738 ms
64 bytes from 104.124.245.241: icmp_seq=6 ttl=52 time=65.981 ms
64 bytes from 104.124.245.241: icmp_seq=7 ttl=52 time=71.142 ms
64 bytes from 104.124.245.241: icmp_seq=8 ttl=52 time=65.984 ms
64 bytes from 104.124.245.241: icmp_seq=9 ttl=52 time=66.578 ms

--- 104.124.245.241 ping statistics ---
10 packets transmitted, 10 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 65.981/68.006/71.258/1.896 ms

Posted by 다인,보리아빠
,