해당 내용은 공부하면서 간단하게 만들어본 블록체인 입니다.


1. Block 만들기

 - BlockChain을 구성하는 Block 을 생성한다,

 - Block은 BlockChain 내에서 고유한 Hash(Digital Signature)값을 가지고 있다.

 - Block 내에는 이전 Block의 Hash 값과 데이터들이 포함되어 있다.


 1) 소스코드

package kr.geun.o.bc.basic;

import java.util.Date;

/**
* Block Class
*
* @author akageun
*/
public class Block {

private String hash;
private String previousHash;

private String data;
private long timeStamp;

private Block() {

}

/**
* Block Constructor
*
* @param data
* @param previousHash
*/
public Block(String data, String previousHash) {
this.data = data;
this.previousHash = previousHash;

this.timeStamp = new Date().getTime();
}

/**
* get previousHash
*
* @return
*/
public String getPreviousHash() {
return previousHash;
}

/**
* get Hash
* - digital signature
*
* @return
*/
public String getHash() {
return hash;
}

/**
* get TimeStamp
*
* @return
*/
public long getTimeStamp() {
return timeStamp;
}

/**
* get Data
*
* @return
*/
public String getData() {
return data;
}
}

2. Hash(Digital Signature) 생성 메소드 만들기

 - Sha256을 사용.

package kr.geun.o.bc.basic;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* BlockChain Utils
*
* @author akageun
*/
public class BcUtils {

/**
* Hash 생성
*
* @param inputValues
* @return
*/
public static String generateHash(String... inputValues) {
try {
StringBuffer sb = new StringBuffer();
for (String inputValue : inputValues) {
sb.append(inputValue);
}

String input = sb.toString();

MessageDigest digest = MessageDigest.getInstance("SHA-256");

byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer();

for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
hexString.append('0');
}

hexString.append(hex);
}
return hexString.toString();

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException(e);

} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}


3. Hash 계산로직 추가.

 - 위 BcUtils 를 이용하여 Block 안 Hash값을 만드는 로직을 추가해보자.

 - Block 내 메소드 추가(소스코드)

/**
* Hash값 계산하기!
*
* @return
*/
public String calculateHash() {
return BcUtils.generateHash(previousHash, Long.toString(timeStamp), data);
}

 - 생성자 내에 해당 메소드 호출 추가


/**
* Block Constructor
*
* @param data
* @param previousHash
*/
public Block(String data, String previousHash) {
this.data = data;
this.previousHash = previousHash;

this.timeStamp = new Date().getTime();
this.hash = calculateHash(); //추가!!
}


4. Genesis Block 호출하기!

 - 첫번째 블럭 생성

Block genesisBlock = new Block("이건 Genesis Block 입니다.", "0");
System.out.println("Genesis Block Hash : " + genesisBlock.getHash());

 - 메인 메소드를 만들어 호출하면 아래와 같은 결과를 얻을 수 있다.(호출할 때마다 Hash값이 달라진다.)

Genesis Block Hash : f57e2c72feba62234118d1356799c367a802c342156a43ac2774698bb316941e


 - 몇개를 더 추가해서 출력해보면.... 아래와 같다.

Block genesisBlock = new Block("이건 Genesis Block 입니다.", "0");
System.out.println("Genesis Block Hash : " + genesisBlock.getHash());

Block secBlock = new Block("이건 두번째 블럭 입니다.", genesisBlock.getHash());
System.out.println("Second Block Hash : " + secBlock.getHash());

Block thirdBlock = new Block("이건 세번째 블럭 입니다.", secBlock.getHash());
System.out.println("Hash for block 3 : " + thirdBlock.getHash());

Genesis Block Hash : f57e2c72feba62234118d1356799c367a802c342156a43ac2774698bb316941e

Second Block Hash : 082902f4d78eab658b964d9743532178073da2b9d529b00752fa5588034fb2a2

Hash for block 3 : 97a821109da7ed12fc3263452670d42b392d71772dd70b81720a23e1d898bf15


5. 블록체인 만들기.

 - 간단하게 static List를 만들어서 블럭들을 생성해 보자.

/**
* BlockChain 메인 클래스
*
* @author akageun
*/
public class BlockChain {

public static List<Block> BLOCK_CHAIN = new LinkedList<>();

public static void main(String[] args) {

BLOCK_CHAIN.add(new Block("이건 Genesis Block 입니다.", "0"));
BLOCK_CHAIN.add(new Block("이건 두번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.add(new Block("이건 세번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));

for (Block block : BLOCK_CHAIN) {
System.out.println("=========");

System.out.println("hash : " + block.getHash());
System.out.println("previousHash : " + block.getPreviousHash());
System.out.println("timeStamp : " + block.getTimeStamp());
System.out.println("Data : " + block.getData());
}

System.out.println("=========");
}

}

 - 결과

=========

hash : 0f7e40c1f99be348a2a600f678ef6e64136d4ea6dc3d7457561e572129c628c9

previousHash : 0

timeStamp : 1532238023070

Data : 이건 Genesis Block 입니다.

=========

hash : b3a2226d4dafb77bfca41c2d792e7590df544e34450bfd5ecd69e71124f6baea

previousHash : 0f7e40c1f99be348a2a600f678ef6e64136d4ea6dc3d7457561e572129c628c9

timeStamp : 1532238023086

Data : 이건 두번째 블럭 입니다.

=========

hash : 57caa0507cbed37fbde89a4d80b2ea68450cff3698fba56856858093d8ac6982

previousHash : b3a2226d4dafb77bfca41c2d792e7590df544e34450bfd5ecd69e71124f6baea

timeStamp : 1532238023086

Data : 이건 세번째 블럭 입니다.



6. 무결성 검사

 - 계산한 Hash값이 같은지, Block 내 PreviousBlock 과 실제 이전 블럭 Hash값이 같은지를 검증하는 로직

 - 구현 소스

/**
* 블록 검증
*
*
* @return
*/
private static boolean isValidBlockChain() {
Block currentBlock;
Block previousBlock;

for (int i = 1; i < BLOCK_CHAIN.size(); i++) { //GenesisBlock 은 제외한다.
currentBlock = BLOCK_CHAIN.get(i);
previousBlock = BLOCK_CHAIN.get(i - 1);

if (currentBlock.getHash().equals(currentBlock.calculateHash()) == false) { //만들어 놓은 Hash값과 계산한 Hash값이 같은지 검증!
System.out.println("Not Equals Current Block Hash!!");
return false;
}

if (currentBlock.getPreviousHash().equals(previousBlock.getHash()) == false) {
System.out.println("Not Equals Previous Block Hash!!");
return false;
}

}

return true;
}


7. 채굴!(마이닝)

 - 작업증명'(Proof-of-Work) : BlockChain의 Block Hash는 `Difficulty`에 따라 선택된  Target 데이터 규격을 만족해야 한다.

  - Block Class 수정( nonce 값 추가)

private int nonce;

/**
* get nonce
*
* @return
*/
public int getNonce() {
return nonce;
}

  - Hash 값 연산하는 부분에 nonce 값 추가

/**
* Hash값 계산하기!
*
* @return
*/
public String calculateHash() {
return BcUtils.generateHash(previousHash, Long.toString(timeStamp), Integer.toString(nonce) , data);
}

  - 채굴 함수 추가

/**
* Mining
*/
public void mineBlock() {
char[] targetChar = new char[BlockChain.DIFFICULTY];
Arrays.fill(targetChar, '0');
String target = String.valueOf(targetChar);

while (hash.substring(0, BlockChain.DIFFICULTY).equals(target) == false) {
nonce++;
hash = calculateHash();
}

System.out.println("Block Mined!!! : " + hash);
}

  - 난이도 추가

public static int DIFFICULTY = 5;

  - 무결성 검증 코드 내 로직 추가

if (currentBlock.getHash().substring(0, DIFFICULTY).equals(hashTarget) == false) {
System.out.println("This block hasn't been mined");
return false;
}

  - 채굴해보기

BLOCK_CHAIN.add(new Block("이건 Genesis Block 입니다.", "0"));
BLOCK_CHAIN.get(0).mineBlock();

BLOCK_CHAIN.add(new Block("이건 두번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(1).mineBlock();

BLOCK_CHAIN.add(new Block("이건 세번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(2).mineBlock();

BLOCK_CHAIN.add(new Block("이건 네번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(3).mineBlock();


 - 결과

Block Mined!!! : 00000fdd8a35c69f5925051899635e1704af98bdd7da3504ed9bc36b5be30901

Block Mined!!! : 00000d8e9a9e735e8f7cbdae41458379ab8b4ac3de7826671eb10f2b7def35bd

Block Mined!!! : 000005dd4dc19710d82dda43d230ec6eabc8041af0fc0a489279802d172f8d41

Block Mined!!! : 000006ff67b1e5735d8891e3e389620f541aa3467e73471a4e2d7b11f841ed3a

=========

hash : 00000fdd8a35c69f5925051899635e1704af98bdd7da3504ed9bc36b5be30901

previousHash : 0

timeStamp : 1532240373740

Data : 이건 Genesis Block 입니다.

nonce : 465518

=========

hash : 00000d8e9a9e735e8f7cbdae41458379ab8b4ac3de7826671eb10f2b7def35bd

previousHash : 00000fdd8a35c69f5925051899635e1704af98bdd7da3504ed9bc36b5be30901

timeStamp : 1532240374917

Data : 이건 두번째 블럭 입니다.

nonce : 1603790

=========

hash : 000005dd4dc19710d82dda43d230ec6eabc8041af0fc0a489279802d172f8d41

previousHash : 00000d8e9a9e735e8f7cbdae41458379ab8b4ac3de7826671eb10f2b7def35bd

timeStamp : 1532240378568

Data : 이건 세번째 블럭 입니다.

nonce : 2130959

=========

hash : 000006ff67b1e5735d8891e3e389620f541aa3467e73471a4e2d7b11f841ed3a

previousHash : 000005dd4dc19710d82dda43d230ec6eabc8041af0fc0a489279802d172f8d41

timeStamp : 1532240383239

Data : 이건 네번째 블럭 입니다.

nonce : 504539

=========

This Blockchain is Valid : true



전체소스

1. Block 소스

package kr.geun.o.bc.basic;

import java.util.Arrays;
import java.util.Date;

/**
* Block Class
*
* @author akageun
*/
public class Block {

private String hash;
private String previousHash;

private String data;
private long timeStamp;

private int nonce;

private Block() {

}

/**
* Block Constructor
*
* @param data
* @param previousHash
*/
public Block(String data, String previousHash) {
this.data = data;
this.previousHash = previousHash;

this.timeStamp = new Date().getTime();
this.hash = calculateHash();
}

/**
* Hash값 계산하기!
*
* @return
*/
public String calculateHash() {
return BcUtils.generateHash(previousHash, Long.toString(timeStamp), Integer.toString(nonce), data);
}

/**
* Mining
*/
public void mineBlock() {
char[] targetChar = new char[BlockChain.DIFFICULTY];
Arrays.fill(targetChar, '0');
String target = String.valueOf(targetChar);

while (hash.substring(0, BlockChain.DIFFICULTY).equals(target) == false) {
nonce++;
hash = calculateHash();
}

System.out.println("Block Mined!!! : " + hash);
}

/**
* get previousHash
*
* @return
*/
public String getPreviousHash() {
return previousHash;
}

/**
* get Hash
* - digital signature
*
* @return
*/
public String getHash() {
return hash;
}

/**
* get TimeStamp
*
* @return
*/
public long getTimeStamp() {
return timeStamp;
}

/**
* get Data
*
* @return
*/
public String getData() {
return data;
}

/**
* get nonce
*
* @return
*/
public int getNonce() {
return nonce;
}
}


2. BcUtils

package kr.geun.o.bc.basic;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
* BlockChain Utils
*
* @author akageun
*/
public class BcUtils {

/**
* Hash 생성
*
* @param inputValues
* @return
*/
public static String generateHash(String... inputValues) {
try {
StringBuffer sb = new StringBuffer();
for (String inputValue : inputValues) {
sb.append(inputValue);
}

String input = sb.toString();

MessageDigest digest = MessageDigest.getInstance("SHA-256");

byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer();

for (int i = 0; i < hash.length; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
hexString.append('0');
}

hexString.append(hex);
}
return hexString.toString();

} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException(e);

} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}


3. BlockChain

package kr.geun.o.bc.basic;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
* BlockChain 메인 클래스
*
* @author akageun
*/
public class BlockChain {

public static List<Block> BLOCK_CHAIN = new LinkedList<>();

public static int DIFFICULTY = 5;

public static void main(String[] args) {

BLOCK_CHAIN.add(new Block("이건 Genesis Block 입니다.", "0"));
BLOCK_CHAIN.get(0).mineBlock();

BLOCK_CHAIN.add(new Block("이건 두번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(1).mineBlock();

BLOCK_CHAIN.add(new Block("이건 세번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(2).mineBlock();

BLOCK_CHAIN.add(new Block("이건 네번째 블럭 입니다.", BLOCK_CHAIN.get(BLOCK_CHAIN.size() - 1).getHash()));
BLOCK_CHAIN.get(3).mineBlock();

for (Block block : BLOCK_CHAIN) {
System.out.println("=========");

System.out.println("hash : " + block.getHash());
System.out.println("previousHash : " + block.getPreviousHash());
System.out.println("timeStamp : " + block.getTimeStamp());
System.out.println("Data : " + block.getData());
System.out.println("nonce : " + block.getNonce());
}

System.out.println("=========");

System.out.println("This Blockchain is Valid : " + isValidBlockChain());

}

/**
* 블록 검증
*
*
* @return
*/
private static boolean isValidBlockChain() {
Block currentBlock;
Block previousBlock;

char[] target = new char[BlockChain.DIFFICULTY];
Arrays.fill(target, '0');

String hashTarget = String.valueOf(target);

for (int i = 1; i < BLOCK_CHAIN.size(); i++) { //GenesisBlock 은 제외한다.
currentBlock = BLOCK_CHAIN.get(i);
previousBlock = BLOCK_CHAIN.get(i - 1);

if (currentBlock.getHash().equals(currentBlock.calculateHash()) == false) { //만들어 놓은 Hash값과 계산한 Hash값이 같은지 검증!
System.out.println("Not Equals Current Block Hash!!");
return false;
}

if (currentBlock.getPreviousHash().equals(previousBlock.getHash()) == false) {
System.out.println("Not Equals Previous Block Hash!!");
return false;
}

if (currentBlock.getHash().substring(0, DIFFICULTY).equals(hashTarget) == false) {
System.out.println("This block hasn't been mined");
return false;
}

}

return true;
}
}



참고 페이지

 - https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa

 - http://guruble.com/java-%EC%BD%94%EB%93%9C%EB%A1%9C-%EC%9D%B4%ED%95%B4%ED%95%98%EB%8A%94-%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8blockchain/

'BlockChain' 카테고리의 다른 글

Java로 배워보는 BlockChain  (0) 2018.05.02
블록체인 관련 기본 용어정리.  (0) 2018.02.23

1. --save

 - 응용 프로그램을 실행하는 데 필요한 패키지를 저장하는 데 사용

 - '-S'로 줄여 쓸 수 있음.

 - package.json 이 존재하면  dependencies 에 추가된다.


npm install [package_name] --save

or

npm install [package_name] -S


2. --save-dev

 - 개발 목적으로 패키지를 저장하는 데 사용

 - '-D'로 줄여 쓸 수 있다.

 - package.json 이 존재하면 devDependencies 에 추가된다.

 - mocha 등 unit test 등 추가할 때 사용...


npm install [package_name] -save-dev

or

npm install [package_name] -D


'프로그래밍 > Node.js' 카테고리의 다른 글

npm에서 --save, --save-dev 옵션  (0) 2018.05.02
Mongoose 사용하기.  (0) 2016.08.22

1. vue.js 내 v-show 를 사용해서 만들면 된다.

 - loader는 fontawesome를 사용했다.



개인적으로 개발을 하면서 좋은 코드를 작성하는 법을 고민하며, 작성한 글입니다. 


1. 읽기 좋은 소스를 만들자.

 - 혼자 개발하는 프로젝트가 아닌 이상, 다른 사람이 내 코드를 보고 빠르게 이해할 수 있어야 한다.

 - var str_1 = 'TEST_STRING_1'; var str_2 = 'TEST_STRING_2'; 정말... 최악이다.


2. 불필요한 전역변수 사용

 - 특정 메소드에서만 사용하는 변수를 전역변수로 선언해 놓을 경우 소스 상단이 굉장히 지저분해 질 수 있다. 


3. 적당한 주석

 - 주석 없이 작성된 코드를 한번에 이해할 수 있으면, 그 코드는 굉장히 잘 작성된 코드일 것이다. 

 - 허나 실제로는 그렇게 하기 힘들다. 그러니 코드를 읽는데 최대한 방해되지 않게 해야 한다고 본다. 

 - 주석보다는 명확한 변수명 또는 메소드명을 작성하여 개발 하는 걸 추천한다. 

 - 추가적으로 업무 중에는 여러 이슈들에 의해서 예외처리, 하드코딩 등이 들어갈 수 있다. 그럼 어떤 이슈 때문에 작성된 코드고, 이슈 관리를 한다면 이슈 번호를 추가하여 다른 담당자가 해당 이슈를 찾기 쉽게 작성해 놓으면 업무하는데 있어서 굉장히 편하다.


4. 코드 컨벤션

 - 여럿이 여러 컨벤션을 사용하여 하나의 프로젝트를 진행한다면 최악의 사태가 발생할 수 있다. 

 - A라는 개발자는 helloWorld 라고 변수를 만들고, B라는 개발자는 hello_world 로 만들어 사용한다면, 같은 목적을 가진 변수가 두개 존재하게 되고, 재활용을 못하게 된다.

 - 프로젝트를 진행하기전 camelCase( 각 단어의 첫 글자는 대문자를 사용(첫 단어는 소문자 사용)), underscores(각 단어를 밑줄로 구분한다) 등의 표기법을 잡고 시작하는걸 추천한다.

 - 또 formatter를 하나 만들어 공통된 코드 포멧을 사용할 수 있도록 하면 더더욱 좋다.


5. 리팩토링

 - 아 다음에 리팩토링해야지... 하는 생각은 버려라!

 - 조금씩이라도 꾸준히 리팩토링 해야한다.

 - 미사용 소스는 과감하게 삭제하고, 중복코드 또한 정리하는 걸 추천한다.

 - 추가 스팩이 발생하더라도 소스가 깔끔하게 정리되어 있다면 부담없이 추가 할 수 있을 것이다.


6. 코드리뷰

 - 혼자 작성한 코드보다는 여럿의 의견을 듣고 수정하는 코드가 더 좋을 수 밖에 없다.

 - 단, 코드리뷰시에 "비난"보다는 의견을 나누는 형태여야, 코드리뷰에 대한 스트레스가 없을 것이다.


7. 잘된 소스 보기

 - Spring 프로젝트 소스, Apache 프로젝트 소스 등을 틈틈히 읽어보다.

 - 아! 이렇게도 소스를 만들 수 있구나 싶은 부분들이 굉장히 많다.

 - 그러다보면 디자인 패턴은 기본적으로 배울 수 있게 되고, 여러 부분에서 도움이 많이 될 것이다.


 

좋은 코드 작성하는것에 대한 정답은 없는 것 같다. 단지 개발을 하면서 느낀 부분을 짧게 정리해 봤다.

'프로그래밍 > 일반' 카테고리의 다른 글

좋은 코드 작성하기.  (0) 2018.05.01
HSTS(HTTP Strict Transport Security) 개념과 설정  (0) 2018.03.08

오랜만에 쓰는듯.......


1. 풀스택개발자

 - 웹개발을 시작하면서, 내 프로젝트를 만들어보고 싶어서 Cafe24 호스팅부터 시작한 공부가 이제는 AWS, GCP 등 cloud까지 사용하고, 

 - 반복해서 html 만들고 jsp tag 쓰는게 귀찮아서 시작한 Front framework 공부!! 현재는 vue.js와 angular를 사용해보고, 개인프로젝트들을 진행.(vue는 사랑입니다.)

 - 음.... 이러다 보니

 - 평소 업무를 진행하면서 어떤 신규 프로젝트를 진행할 때, 음~ 이건 이런걸 쓰면 좋고, 저럴 때 저걸 쓰면 좋지~ 라는 생각이 든다. 그리고 좀 더 빠르게 프로젝트를 진행할 수 있는 듯 하다. (미리 개인 프로젝트로 어느정도 해봐서 ㅋㅋ)

 - 이제는 일인지 취미생활인지 잘 모르게 되었지만, 현재 이 생활이 난 재미나다.


2. 데이터분석

 - 최근 이곳 저곳 텍스트들을 모아서, 나름 의미있는 데이터를 뽑아보려고 노력중인데... 쉽지가 않다.

 - 일단 텍스트를 모으는것부터가 굉장히 힘들다.... 

 - 그래도 데이터를 가지고 노는게 참 재미나다. 

 - 이전에는 새로운 정보를 새로운 페이지로 보여주는게 재미있었다면, 이제는 무언가를 사용자가 원하는 형태로 가공해서 재미나게 보여주는걸 즐기는 듯 하다.


3. github

 - 개인용 vcs를 사용하다보니, github을 많이 방치하게 된다.

 - 어느정도 정리된 소스를 github에 push해서 삽질하시는 분들에게 아주 쬐금이라도... 도움을 드릴 수 있게~ 공유를 다시 시작해야겠다.

 - 100일 연속 커밋을 도전도... 해볼까... 싶다.


4. 블록체인

 - 책을 아주 잠깐 봤는데... 굉장히 매력적인 분야인듯.

 - 좀 더 깊게 공부해봐야겠다.

'개인 > 단상' 카테고리의 다른 글

2018-06-05 : Cloud Native Day in seoul  (0) 2018.06.05
2018-05-01  (0) 2018.05.01
Aws re:invent 2017! 후기  (0) 2017.12.02
2016-10-01  (0) 2016.10.01
2016-09-08  (0) 2016.09.08

1. javascript 버전.

<script>
function clearOnlyJavascript(eleName) {
var ele = document.getElementsByName(eleName);
for (var i = 0; i < ele.length; i++) {
ele[i].checked = false;
}
}
</script>

2. jquery 버전

 - jquery 버전에 따라 prop 의 옵션이 달라질 수 있습니다. 참고하세요.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
$("#clearBtnJquery").click(function () {
console.log($("input[name=\"radioButton\"]").prop("checked", false));
});
})
</script>


3. 풀소스


'프로그래밍 > html & css' 카테고리의 다른 글

Bootstrap 사용하기  (0) 2018.08.08
textarea 리사이즈 관련  (0) 2018.07.16
radio, checkbox clear 버튼 만들기.  (0) 2018.04.25
<html lang="ko">  (0) 2018.04.09
html tag(select box, checkbox) Readonly(?)처럼 사용하기  (0) 2018.03.08

1. 프로젝트 생성하기(vue-cli)

 1) vue-cli 설치하기.

 - Global로 설치하기

npm install  -g vue-cli


 2) project 생성하기.

mkdir {PROJECT_NAME}


cd {PROJECT_NAME}


vue init webpack-simple


 - vue 명령어

 

 설명

 비고

 init

 generate a new project from a template

 vue init {project template type} {PROJECT_NAME}

 list

 list available official templates

 vue list <-- 아래 내용 참고

 build

 prototype a new project

 

 help

 display help for [cmd] 


 - vue template

 

 설명

비고 

 browserify

 A full-featured Browserify + vueify setup with hot-reload, linting & unit testing.

 

 browserify-simple

 A simple Browserify + vueify setup for quick prototyping.

 

 pwa

 PWA template for vue-cli based on the webpack template

 

 simple

 The simplest possible Vue setup in a single HTML file

 하나의 index.html 파일만 생성해줌.

 webpack

 A full-featured Webpack + vue-loader setup with hot reload, linting, testing & css extraction.

 

 webpack-simple

 A simple Webpack + vue-loader setup for quick prototyping.

 


2. 프로젝트 분석하기

 1) 기본 구조 설명


 2) 상세설명

  (1) main.js

- 프로젝트의 기본이 되는 파일입니다. 프로젝트의 Entry Point 이기도 하다.

  (2) App.vue

- Root 컴포넌트

- Vue를 로드하고 해당 파일을 로드하면서 어플리케이션을 초기화한다.

- 참고로 *.vue 파일은 "HTML 템플릿", 단일 vue 컴포넌트를 정의하는 javascript, 특정 스타일 css 의 조합이다.


  (3) assets

- 외부 자원들에 대한 폴더이다. image, css 등이 들어간다.


 3) 그외 설명

  (1) components

- vue 파일을 저장하는 곳.

- 입맛에 따라 알아서 변경해서 쓰면 된다.


  (2) route

-backend에서 제공하는 라우팅 기능을 제공함.

- index.js 관련해서는 추후 설명할 예정


3. 프로젝트 시작하기

 1) 위에서 생성한 프로젝트 내에서

 2) 우선 npm으로 라이브러리들을 설치해야한다.

npm install


 3) 개발버전으로 프로젝트를 시작하자.

  - compile, ESLint 를 진행하고, 로컬 서버를 동작시켜준다.

  - ESLint, hot-reload 동작(변경된 상태만 변경)

npm run dev


 4) 실서비스 시

  - webpack 설정등에 따라 달라지겠지만, /dist 폴더로 hash 값이 포함된 파일명으로 파일들이 생성됨.

npm run build



참고링크

 - https://medium.com/witinweb/vue-cli-%EB%A1%9C-vue-js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-browserify-webpack-22582202cd52

 - https://blog.storyg.co/vue-js-posts/todos-tutorial

1. Vue란?

 - front-end framework

 - 배우기 쉽다.

 - view에 최적화 되어 있다.

 - MVVM(Model-View-ViewModel) 패턴을 기반으로 디자인


2. 간단하게 시작해보자.

 - index.html 파일을 만들고, 아래 링크를 포함한 페이지를 만들어보자.

https://unpkg.com/vue


or

https://cdn.jsdelivr.net/npm/vue


 1) index.html

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<p>{{ msg }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#root',
data: {
msg: 'Hello Vue.js!'
}
})
</script>
</body>
</html>

  - 결과


3. Declarative Rendering

  - 디렉티브는 vue에서 제공하는 속성, v- 로 접두어가 붙는다.


 1) v-if

  - 조건문 사용할 때 사용.

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<div v-if="type === 'LOGIN'">로그인 되었습니다.</div>
<div v-else-if="type === 'LOGOUT'">로그아웃 되었습니다.</div>
<div v-else> 로그인이 필요합니다.</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
type: "LOGOUT"
}
})
</script>
</body>
</html>


  - template 에도 사용가능

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<template v-if="type === 'LOGIN'">
<div>
로그인 되었습니다.
</div>
</template>
<template v-else-if="type === 'LOGOUT'">
<div>
로그아웃 되었습니다.
</div>
</template>
<template v-else>
<div>
로그인이 필요합니다.
</div>
</template>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
type: "LOGIN"
}
})
</script>
</body>
</html>




 2) v-show

  - 보여질지, 숨길지에 대해서 설정할 수 있는 값이다.

  - 일단 뷰 렌더링이 진행되고, css로 숨길지 나타낼지를 정한다.

  - 샘플코드

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<div v-show="visible">보이나?</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
visible: true
}
})
</script>
</body>
</html>

  - v-if는 토글 비용이 높고 v-show는 초기 렌더링 비용이 더 높다. 자주 바꾸기를 원한다면 v-show를, 런타임 시 조건이 바뀌지 않으면 v-if를 권장한다..

 - chrome 개발자 console 창에 'app.visible = false;'를 입력해보면 해당 div가 사라지는 걸 확인 할 수 있다.


 3) v-for

  - for loop

  - 목록 구현할때 많이 쓰이는 디렉티브

  - 샘플 코드

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<ul>
<li v-for="fruit in fruits" :key="fruit">{{ fruit }}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#root',
data: {
fruits: ['apple', 'banana', 'orange']
}
})
</script>
</body>
</html>

  - 결과



 4) 기타

  - v-on, v-bind, v-model 등이 있다.



* 참고

 - https://vuejs.org/v2/guide/index.html , https://kr.vuejs.org/v2/guide/index.html



1. json-schema-validator란?

 - xml의 DTD 와 유사함.

 - Json 스키마(http://json-schema.org/) 포멧이 유효한지 확인해줌.

 - 웹사이트에서 해당 내용을 테스트해볼 수 있다.(링크)


2. library

 - 기존에 jackson을 많이 사용하므로, fasterxml에서 제공하는 jsonSchema 라이브러리를 사용하려고함.

 1) pom.xml

<dependency>
<groupId>com.github.java-json-tools</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.8</version>
</dependency>


3. 간단한 Json 설명

{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "/etc/fstab", /* JSON에 대한 제목 */
"description": "JSON representation of /etc/fstab", /* JSON에 대한 설명 */
"type": "object", /* 해당 Json의 최상위 객체 타입, http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.1 참고 */
"properties": {
"swap": {
"$ref": "#/definitions/mntent" /* 하단 definitions내용을 참조 합니다. */
}
},
"patternProperties": {
"^/([^/]+(/[^/]+)*)?$": {
"$ref": "#/definitions/mntent"
}
},
"required": /* 필수 값에 대한 속성 정의 */ [
"/",
"swap"
],
"additionalProperties": false,
"definitions": {
"mntent": {
"title": "mntent",
"description": "An fstab entry",
"type": "object", /* 객체 타입 */
"properties": {
"device": {
"type": "string"
},
"fstype": {
"type": "string"
},
"options": {
"type": "array",
"minItems": 1, /* 아이템의 최소 단위 */
"items": {
"type": "string"
}
},
"dump": {
"type": "integer",
"minimum": 0,
"maximum": 0 /* 아이템의 최대 단위 */
},
"fsck": {
"type": "integer",
"minimum": 0
}
},
"required": [
"device",
"fstype"
],
"additionalItems": false
}
}
}



4. 샘플 소스

 1) Basic ( https://github.com/java-json-tools/json-schema-validator/blob/master/src/main/java/com/github/fge/jsonschema/examples/Example1.java)

 - 소스

final String urlPrefix = "https://raw.githubusercontent.com/java-json-tools/json-schema-validator/"
+ "master/src/main/resources/com/github/fge/jsonschema/examples/";

final JsonNode fstabSchema = JsonLoader.fromURL(new URL(urlPrefix + "fstab.json"));
final JsonNode good = JsonLoader.fromURL(new URL(urlPrefix + "fstab-good.json"));
final JsonNode bad = JsonLoader.fromURL(new URL(urlPrefix + "fstab-bad.json"));
final JsonNode bad2 = JsonLoader.fromURL(new URL(urlPrefix + "fstab-bad2.json"));

final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();

final JsonSchema schema = factory.getJsonSchema(fstabSchema);

ProcessingReport report;

report = schema.validate(good); //SUCCESS
print(report);

report = schema.validate(bad); //FAILURE
print(report);

report = schema.validate(bad2); //FAILURE
print(report);

 - 결과


 

 2) message custom(https://github.com/java-json-tools/json-schema-validator/blob/master/src/main/java/com/github/fge/jsonschema/examples/Example8.java)

 - 소스(valid)

final JsonNode customSchema = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt.json"));
final JsonNode good = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt-good.json"));
final JsonNode bad = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt-bad.json"));

//@formatter:off
final Library library = DraftV4Library
.get()
.thaw()
.addFormatAttribute("uuid", UUIDFormatAttribute.getInstance())
.freeze();
//@formatter:on

final String key = "invalidUUID";
final String value = "Not a valid UUID";
final MessageSource source = MapMessageSource.newBuilder().put(key, value).build();
final MessageBundle bundle = MessageBundles.getBundle(JsonSchemaValidationBundle.class).thaw().appendSource(source).freeze();

final ValidationConfiguration cfg = ValidationConfiguration.newBuilder().setDefaultLibrary("http://my.site/myschema#",
library).setValidationMessages(bundle).freeze();

final JsonSchemaFactory factory = JsonSchemaFactory.newBuilder().setValidationConfiguration(cfg).freeze();

final JsonSchema schema = factory.getJsonSchema(customSchema);

ProcessingReport report;

report = schema.validate(good);
print(report);

report = schema.validate(bad);
print(report);


  - 소스(UUIDFormatAttribute)

private static class UUIDFormatAttribute extends AbstractFormatAttribute {
private static FormatAttribute INSTANCE = new UUIDFormatAttribute();

private UUIDFormatAttribute() {
super("uuid", NodeType.STRING);
}

public static FormatAttribute getInstance() {
return INSTANCE;
}

@Override
public void validate(final ProcessingReport report, final MessageBundle bundle, final FullData data) throws ProcessingException {
final String value = data.getInstance().getNode().textValue();
try {
UUID.fromString(value);

} catch (IllegalArgumentException ignored) {
report.error(super.newMsg(data, bundle, "invalidUUID").put("input", value));
}
}
}

  - 결과


5. 전체소스



 * 참고링크

  - https://github.com/java-json-tools/json-schema-validator

  - http://json-schema.org/latest/json-schema-validation.html

  - http://json-schema-validator.herokuapp.com/

  - http://json-schema.org/example2.html

'프로그래밍 > JAVA' 카테고리의 다른 글

json schema validator 사용하기 - 02  (0) 2018.05.23
AmazonS3Client, deprecated!!!  (0) 2018.05.21
json schema validator 사용하기 - 01  (0) 2018.04.18
시스템 종료 후 File 삭제  (0) 2018.04.12
Java에서 Tuple 사용하기.  (0) 2018.04.11
try-catch-resources  (0) 2018.04.11


1. AppStore Viewer는?

 1) "대한민국" AppStore 내에 있는 "iOS"어플 들 랭킹을 보여주고. 해당 어플의 "댓글"들을 볼수 있는 어플을 만들 예정.

 2) Windows, MAC, Linux 에서 사용할 수 있도록 "Cross-Platform" 데스크톱 앱을 만들 예정.


2. Stack 소개

 1) Electron

  - Node.js 기반으로 작성된 데스크탑 어플리케이션

  - HTML, CSS, Javascript로 데스크톱 어플을 쉽게 만들 수 있게 해주는 Framework

  - Atom Editor를 개발하기 위하여 시작된 프로젝트이고 Atom Shell이라는 이름으로 시작되었다 Electron으로 변경됨.

  - 웹으로 만들어진 서비스가 있다면 손쉽게 데스크톱 어플로 기존 소스를 재활용하여 개발하기 쉬움.


 2) Angular, Typescript, Bootsrap

  - 구글 검색하면 나오는 그거~


3. 사용할 API

 1) Appstore Rss

  - https://rss.itunes.apple.com/ko-kr

  - https://itunes.apple.com/us/rss/customerreviews/id={앱아이디}/json


4. 환경 세팅하기.

 0) Intellij javascript 세팅 변경



 1) Angular-CLI 설치하기 

  - Angular의 components, pipes, services 등을 효율적으로 생성해주는 Tool 입니다.

npm install -g @angular/cli


 2) Angular2 프로젝트 생성

ng new appstore-viewer

 

 3) Electron 관련 폴더 및 파일 생성(https://electronjs.org/docs/tutorial/quick-start 참고)

cd appstore-viewer && mkdir electron 

  - 아래와 같이 파일 2개를 만든다.


  - 프로젝트는 아래와 같은 구조가 될 것이다.



   (1) electron/package.json

{
"name": "appstore-viewer",
"version" : "0.1.0",
"main" : "electron.js"
}


   (2) electron/electron.js

// appstore-viewer/electron/electron.js

const {app, BrowserWindow} = require('electron')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
backgroundColor: '#ffffff',
icon: `file://${__dirname}/dist/assets/logo.png`
})

// and load the index.html of the app.
win.loadURL(`file://${__dirname}/index.html`)

// Open the DevTools.
win.webContents.openDevTools()

// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null
})
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})

app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.


   (3) src/index.html

    - 자연스러운 실행을 위하여 base href="/"를 base href="./"로 변경한다.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>AppstoreViewer</title>
<base href="./">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>데이터를 가져오는 중 입니다.</app-root>
</body>
</html>

   (4) package.json에 electron 추가하기

    - electron-prebuilt 을 추가함

    - 컴파일된 Electron 바이너리 npm(Electron을 받아도 되지만, 그렇게되면 매번 바이너리를 다운받아야하므로, 공식문서에서는 해당 npm을 권장하고있음.)

"electron-prebuilt": "^1.4.13"


   (5) 명령어 추가

"scripts": {     "start": "ng build --watch",     "build": "ng build --prod",

    "electron": "cp electron/* dist/ && ./node_modules/.bin/electron dist/"
},

5. 실행하기 

 - 다운로드

npm install --save-dev


 - console창 두개로 명령어를 실행시켜주세요.

npm run start

npm run electron


6. 확인


7. 에러처리

 1) Cannot find module '@angular-devkit/core'

module.js:471

    throw err;

    ^


Error: Cannot find module '@angular-devkit/core'

    at Function.Module._resolveFilename (module.js:469:15)

    at Function.Module._load (module.js:417:25)

    at Module.require (module.js:497:17)

    at require (internal/module.js:20:19)

    at Object.<anonymous> (/Users/hyeonggeunkim/akageun/electron/appstore-viewer/node_modules/@angular-devkit/schematics/src/tree/virtual.js:10:16)

    at Module._compile (module.js:570:32)

    at Object.Module._extensions..js (module.js:579:10)

    at Module.load (module.js:487:32)

    at tryModuleLoad (module.js:446:12)

    at Function.Module._load (module.js:438:3)

  - "@angular/cli": "1.6.4" -> "@angular/cli": "1.6.5" 로 변경

  - https://github.com/angular/angular-cli/issues/9307


8. 참고 페이지

 - http://www.blog.bdauria.com/?p=806

 - https://github.com/RobWin/angular2-electron-demo/blob/master/package.json

 - https://angularfirebase.com/lessons/desktop-apps-with-electron-and-angular/

 - https://msp-typescript.gitbooks.io/typescript-angular2-electron/content/chapter1.html

 - https://github.com/MSP-typescript/AngularCLI-Electron-Boilerplate

 - https://www.flaticon.com/free-icon/library_100153 (무료아이콘)

'프로그래밍 > 개인프로젝트' 카테고리의 다른 글

[AppStore Viewer] 1. 세팅하기.  (0) 2018.04.17
[Github] Github 페이지 활용하기.  (0) 2017.02.06
텔레그램 봇 활용하기 -1  (0) 2016.08.23

+ Recent posts