자바스크립트로 블록체인 구현 강좌4 - 나만의 비트코인 발행하기


지난 포스팅에 이어서 이번시간에는 저번 포스팅에서 작성한 마지막 블락 가져오기 함수와 새로운 트랜젝션 생성하기 함수를 test.js 에서 한번 찍어 보겠다. 그리고 트랜잭션과 새로운 블락이 생겼을 때 , 그리고 새로운 블록이 생긴 이후 트랜잭션 데이터는 어떻게 변하는지 이 관계를 살펴보도록 하자.


test.js로 이동해서 새로운 블락을 생성하는 함수와 새로운 트랜젝션을 생성하는 함수를 하나씩 작성한다.


//blockchain.js 모듈을 이곳에서 가져다 쓰겠다.

const Blockchain = require('./blockchain')

//위에서 가져온 모듈의 객체를 만든다.
const bitcoin = new Blockchain();

//새로운 블락 만들기
bitcoin.createNewBlock(1111,"aaaaaaa","1a1a1a1a1a1a");

//새로은 트랜잭션 생성 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(100,'PACKadffaaf','HONGllalflks')

//찍어보기
console.log(bitcoin)


//결과
/*
Blockchain {
chain:
[ { index: 1,
timestamp: 1527228481937,
transactions: [],
nonce: 1111,
hash: '1a1a1a1a1a1a',
previousBlockHash: 'aaaaaaa' } ],
pendingTransaction:
[ { amount: 100, sender: 'PACKadffaaf', recipient: 'HONGllalflks' } ] }
*/

위의 코드에서 주석처리된 결과 부분을 보자

새로운 블락인 index 1 은 chain 배열에 객체 형태로 들어갔다. 

그뒤 발생한 새로운 트랜젝션 은 pendingTransaction 배열에 객체 형태로 들어갔다.

그래서? 이게 뭐? 라고 생각할 수도 있다. 일단은 지금까지 이론으로만 알았던 '블록 하나에  거래내역을 저장한다' 라는 말이 조금 이해가 될것이다. 

그래서 블록체인을 공용장부라고 한다. 일단은 지금 index 1 블록의 transaction[]은 비어있다. 그렇다면 지금 pendingTransaction에 있는 거래 데이터를 어떻게 index : 1 인 블록의 transaction에 기록할까? 채굴을 해야 한다. 이말은 새로운 블락이 하나더 생성이 되면 그 새로운 블락의 transaction에 지금의 미완료된 트랜젝션이 기록된다는 뜻이다.

//새로은 트랜잭션 생성 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(100,'PACKadffaaf','HONGllalflks') 이 코드 아래에 추가


//새로운 블락 생성 - 채굴후 얻은 블락
bitcoin.createNewBlock(2222,"bbbbbbb","2b2b2b2b2b2b");


새로운 블록이 추가 되었다. 한번 찍어보자. 뚜둥. 결과 값은 아래와 같다. 위에서 발생한 pendingTransaction 거래 기록은 새로 생성된 index 2 인 블록의 transaction[] 배열에 들어 갔다. 지금은 [Array] 이렇게 표시가 되어 있는데 저 부분만 한번 찍어보자.

//결과
/*
Blockchain {
chain:
[ { index: 1,
timestamp: 1527229062594,
transactions: [],
nonce: 1111,
hash: '1a1a1a1a1a1a',
previousBlockHash: 'aaaaaaa' },
{ index: 2,
timestamp: 1527229062594,
transactions: [Array],
nonce: 2222,
hash: '2b2b2b2b2b2b',
previousBlockHash: 'bbbbbbb' } ],
pendingTransaction: [] }

*/


index : 2 블록 부분만 찍어보았다. 아래에. transactions 배열 부분을 보자. 위에서 봤던 pendingTransaction의 객체 형태의 데이터가 들어가 있다.

//찍어보기
console.log(bitcoin.chain[1])


//결과
/*
{ index: 2,
timestamp: 1527229359157,
transactions:
[ { amount: 100, sender: 'PACKadffaaf', recipient: 'HONGllalflks' } ],
nonce: 2222,
hash: '2b2b2b2b2b2b',
previousBlockHash: 'bbbbbbb' }

*/


이제 대충 감이 올것이다. 추가로 트랜젝션을 더 발생시켜보자. 위에서 작성한 새로운 블락 만드는 소스 아래에 소스 코드를 추가해준다.

//새로은 트랜잭션 생성2 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(777,'PACKadffaaf','HONGllalflks')
//새로은 트랜잭션 생성3 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(888,'PACKadffaaf','HONGllalflks')
//새로은 트랜잭션 생성4. - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(999,'PACKadffaaf','HONGllalflks')



그리고 다시 node 명령어로 실행을하고 결과를 보자. 위에서 발생한 트랜젝션 3건 데이터가 어디에 있는가? 이것만 빨리 캐치하면 된다. pendingTransaction 배열에 있다. 아직 미완결된 거래이기 때문에 일단 저기 들어가 있다. 그러면 저 데이터가 블락안에 들어가서 신뢰할 수 있는 데이터가 되려면 어떻게 해야 하나? 컴퓨팅 파워로 암호를 풀어서 생성해주면 된다. 일단 지금은 컴퓨팅 파워를 엄청 써서 새로운 블락을 또 생성했다고 가정하자. 또 새로운 블락이 생성이 되었기 때문에 해당 코드를 한번 더 작성해보자.


//찍어보기
console.log(bitcoin)


//결과
/*
Blockchain {
chain:
[ { index: 1,
timestamp: 1527229704057,
transactions: [],
nonce: 1111,
hash: '1a1a1a1a1a1a',
previousBlockHash: 'aaaaaaa' },
{ index: 2,
timestamp: 1527229704057,
transactions: [Array],
nonce: 2222,
hash: '2b2b2b2b2b2b',
previousBlockHash: 'bbbbbbb' } ],
pendingTransaction:
[ { amount: 777, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 888, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 999, sender: 'PACKadffaaf', recipient: 'HONGllalflks' } ] }

*/


마이닝으로 새로운 블락이 생성되었다.

//새로운 블락 만들기
bitcoin.createNewBlock(3333,"ccccccc","3c3c3c3c3c3c");


이전 거래들이 어떻게 이동이 되는지 자세히 보라. pendingTransaction[] 에 일단 값들이 보이지 않는다. 그리고 index:3 블록 transactions[] 에 Array 배열 값이 생겼다. 이제 거의 감을 잡았으리라 생각한다. 찍어보자.

console.log(bitcoin)


//결과
/*
Blockchain {
chain:
[ { index: 1,
timestamp: 1527229993383,
transactions: [],
nonce: 1111,
hash: '1a1a1a1a1a1a',
previousBlockHash: 'aaaaaaa' },
{ index: 2,
timestamp: 1527229993384,
transactions: [Array],
nonce: 2222,
hash: '2b2b2b2b2b2b',
previousBlockHash: 'bbbbbbb' },
{ index: 3,
timestamp: 1527229993384,
transactions: [Array],
nonce: 3333,
hash: '3c3c3c3c3c3c',
previousBlockHash: 'ccccccc' } ],
pendingTransaction: [] }
*/


index : 3 블록만 찍어보았다. 이전 거래내역들이 새로 생성된 블락으로 이동한것을 볼 수 있다.

//찍어보기
console.log(bitcoin.chain[2])


//결과
/*
{ index: 3,
timestamp: 1527230266389,
transactions:
[ { amount: 777, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 888, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 999, sender: 'PACKadffaaf', recipient: 'HONGllalflks' } ],
nonce: 3333,
hash: '3c3c3c3c3c3c',
previousBlockHash: 'ccccccc' }
*/


혹시나해서 test.js의 전체 코드를 올려놓는다.

//blockchain.js 모듈을 이곳에서 가져다 쓰겠다.
const Blockchain = require('./blockchain')

//위에서 가져온 모듈의 객체를 만든다.
const bitcoin = new Blockchain();

//새로운 블락 만들기
bitcoin.createNewBlock(1111,"aaaaaaa","1a1a1a1a1a1a");

//새로은 트랜잭션 생성 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(100,'PACKadffaaf','HONGllalflks')


//새로운 블락 생성 - 채굴후 얻은 블락(마이닝)
bitcoin.createNewBlock(2222,"bbbbbbb","2b2b2b2b2b2b");

//새로은 트랜잭션 생성2 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(777,'PACKadffaaf','HONGllalflks')
//새로은 트랜잭션 생성3 - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(888,'PACKadffaaf','HONGllalflks')
//새로은 트랜잭션 생성4. - (총금액, 보내는이, 받는이)
bitcoin.createNewTransaction(999,'PACKadffaaf','HONGllalflks')


//새로운 블락 만들기
bitcoin.createNewBlock(3333,"ccccccc","3c3c3c3c3c3c");




//찍어보기
console.log(bitcoin.chain[2])


//결과
/*
{ index: 3,
timestamp: 1527230266389,
transactions:
[ { amount: 777, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 888, sender: 'PACKadffaaf', recipient: 'HONGllalflks' },
{ amount: 999, sender: 'PACKadffaaf', recipient: 'HONGllalflks' } ],
nonce: 3333,
hash: '3c3c3c3c3c3c',
previousBlockHash: 'ccccccc' }
*/









!!만약에 이 포스팅을 보면서 따라 해봤는데도 이해가 안간다면 이것만 기억하자. 

1.거래가 발생하면 트랜잭션 데이터가 생긴다.

2.이 데이터는 아직 신뢰할 수 없다.

3.어떻게 해야하나? -> 채굴자들이 마이닝을 해서 새로운 블락을 생성해야 한다.

4.새로운 블락이 생성되었다.

5.이전 트랜잭션 데이터는 새로운 블락에 쓰여지면서 신뢰할 수 있게된다.




  1. JHY 2019.08.01 18:21

    오 중간정리까지 꼼꼼하게 잘 올려주셔서 그나마 이해가 잘 되요 다른 댓글들이 말씀하신 것처럼.....ㅎㅎㅎ

자바스크립트로 블록체인 구현 강좌3 - 나만의 비트코인 발행하기



이번포스팅에서는 마지막 블록을 얻는 함수, 새로운거래가 발생할때 거래 트랜잭션 데이터를 생성하는 함수를 만들어 보도록 하겠다.

먼저 blockchain.js 로가서 이어서 코드를 작성해보자.


Blockchain.prototype.createNewBlock  ... 생략. 이 코드 아래에 마지막 블록을 가져오는 함수를 작성한다.


//마지막 블록 얻기 - chain 배열에는 블록데이터가 들어간다. 맨마지막 블록을 가져와라.
Blockchain.prototype.getLastBlock = function(){
return this.chain[this.chain.length - 1];
}


그 밑에 새로운 트랜잭션이 발생했을 때 작동되는 함수를 작성한다.

참고로 거래가 발생할때 마다 생성되는 데이터를 트랜잭션이라고 하는데, 중요한건 트랜잭션은 거래로 인해 발생한 어떤 것이지 블록이 아니다. 블록이 되려면 채굴자들이 마이닝, 즉 컴퓨팅 파워로 채굴을 해야 한다. 그래서 아직 완결이 안된 데이터라고도 할 수 있다. 우리는 맨위에 function Blockchain(){} 데이터 구조에서 this.newTransaction = [] 배열을 생성했다. 이 이름을 좀 더 직관적으로 pendingTransaction으로 바꿔주도록 하자. 아직 대기상태의, 미완결된 값이기 때문에 이렇게 작명을 해주겠다. 전부다 바꿔주도록 하자.

//새로운 트랜젝션(거래)가 발생했을 때 작동되는 함수
//인자값으로, 총액수, 보내는사람, 받는사람이 들어간다.
Blockchain.prototype.createNewTransaction = function(amount,sender,recipient){
const newTransaction = {
amount: amount,
sender: sender,
recipient: recipient
}

//맨위 트랜잭션 배열에 값을 넣어준다.
this.pendingTransaction.push(newTransaction);

//마지막 블록의 index 에서 + 1
return this.getLastBlock()['index'] + 1
}


blockchain.js의 전체 코드는 아래와 같다. 다음 포스팅에서는 test.js에서 이번 포스팅에서 만든 함수들이 어떻게 출력이되는지 찍어보도록 하겠다. 

//블록체인 데이터 구조
function Blockchain(){
this.chain = [];
this.pendingTransaction = [];
}


//블록체인 프로토 타입 함수 정의
Blockchain.prototype.createNewBlock = function(nonce,previousBlockHash,hash){
//새 블록 객체
const newBlock = {
index: this.chain.length + 1,
timestamp: Date.now(),
transactions: this.pendingTransaction,
nonce:nonce,
hash:hash,
previousBlockHash:previousBlockHash
};

//다음 거래를 위한 거래내역 배열 비워주고 새로운 블록을 chin 배열에 추가
this.pendingTransaction = [];
this.chain.push(newBlock);

return newBlock;

}

//마지막 블록 얻기 - chain 배열에는 블록데이터가 들어간다. 맨마지막 블록을 가져와라.
Blockchain.prototype.getLastBlock = function(){
return this.chain[this.chain.length - 1];
}

//새로운 트랜젝션(거래)가 발생했을 때 작동되는 함수
//인자값으로, 총액수, 보내는사람, 받는사람이 들어간다.
Blockchain.prototype.createNewTransaction = function(amount,sender,recipient){
const newTransaction = {
amount: amount,
sender: sender,
recipient: recipient
}

//맨위 트랜잭션 배열에 값을 넣어준다.
this.pendingTransaction.push(newTransaction);

//마지막 블록의 index 에서 + 1
return this.getLastBlock()['index'] + 1
}

//Blockchain 모듈화
module.exports = Blockchain;



자바스크립트로 블록체인 구현 강좌2 - 나만의 비트코인 발행하기


지난 포스팅에서는 자바스크립트로 블록체인 구현을 위한 셋팅과 자바스크립트의 데이터구조와 프로토타입에 대한 기본 지식을 알아보았다. 이번에는 지난번 포스팅에서 구현한 내용을 직접 console.log로 찍어보면서 대충 아~ 이런거구나 하고 감을 잡아보자

blockchain.js  모듈화 하기

//블록체인 데이터 구조
function Blockchain(){
this.chain = [];
this.newTransactions = [];
}


//블록체인 프로토 타입 함수 정의
Blockchain.prototype.createNewBlock = function(nonce,previousBlockHash,hash){
//새 블록 객체
const newBlock = {
index: this.chain.length + 1,
timestamp: Date.now(),
transactions: this.newTransactions,
nonce:nonce,
hash:hash,
previousBlockHash:previousBlockHash
};

//다음 거래를 위한 거래내역 배열 비워주고 새로운 블록을 chin 배열에 추가
this.newTransactions = [];
this.chain.push(newBlock);

return newBlock;

}

//Blockchain 모듈화
module.exports = Blockchain;

module.exports = Blockchain으로 다른 페이지에서도 이 모듈을 사용할 수 있게 해준다.


test.js 로 이동. 

아래와 같이 코드를 작성해준다. 위에서 작성한 블록체인 코드를 여기서 테스트 해보겠다는 뜻이다. 그리고 실행해보자.

//blockchain.js 모듈을 이곳에서 가져다 쓰겠다.
const Blockchain = require('./blockchain')

//위에서 가져온 모듈의 객체를 만든다.
const bitcoin = new Blockchain();

//찍어보기
console.log(bitcoin)


 node 명령어로 실행해보기 

 node 명령어로 실행한거 확인해보기 -  짜쟌


저게 먼지는 아직 잘 몰라도 일단 콘솔에 우리가 적은 코드랑 비스무리한게 떴다.

자 그럼 이제 직접 새로운 블락을 생성해보자

주석으로 새로운 블락 만들기를 보자. createNewBlock은 앞 포스팅에서 만들어놓은 프로토 타입 함수다. 인자값으로 일단 아무 값이나 넣어주었다.

//blockchain.js 모듈을 이곳에서 가져다 쓰겠다.
const Blockchain = require('./blockchain')

//위에서 가져온 모듈의 객체를 만든다.
const bitcoin = new Blockchain();

//새로운 블락 만들기
bitcoin.createNewBlock(1111,"aaaaaaa","1a1a1a1a1a1a");

//찍어보기
console.log(bitcoin)

//결과
//Blockchain { chain: [], newTransactions: [] }


다시 실행해보자


와우. 일단 그럴듯한 객체 데이터가 생성이 된것을 볼 수 있다. 몇개를 더 만들어 볼까?

//새로운 블락 만들기
bitcoin.createNewBlock(1111,"aaaaaaa","1a1a1a1a1a1a");
bitcoin.createNewBlock(2222,"bbbbbbb","2b2b2b2b2b2b");
bitcoin.createNewBlock(3333,"ccccccc","3c3c3c3c3c3c");


결과

Blockchain {

  chain: 

   [ { index: 1,

       timestamp: 1527223987875,

       transactions: [],

       nonce: 1111,

       hash: '1a1a1a1a1a1a',

       previousBlockHash: 'aaaaaaa' },

     { index: 2,

       timestamp: 1527223987875,

       transactions: [],

       nonce: 2222,

       hash: '2b2b2b2b2b2b',

       previousBlockHash: 'bbbbbbb' },

     { index: 3,

       timestamp: 1527223987875,

       transactions: [],

       nonce: 3333,

       hash: '3c3c3c3c3c3c',

       previousBlockHash: 'ccccccc' } ],

  newTransactions: [] }


이번 포스팅에서는 새로운 블락을 생성하고 콘솔로 한번 찍어 보았다. 아직은 이게 먼지 100% 감이 안올거다. 일단 하나씩 따라와 보자. 

  1. 김도원 2018.07.07 12:38

    오타 있네요 ㅎㅎ..

    첫번 째 코드블록 주석 보시면
    //다음 거래를 위한 거래내역 배열 비워주고 새로운 블록을 chin 배열에 추가

    의 주석 중 chin 배열에 추가 인데 chain 배열에 추가 로 변경해야합니다 ~

    • 길위의 개발자 2018.07.09 17:27 신고

      감사합니다. 급하게 정리하느라 검토를 못했습니다. ㅠㅠ 요즘 일이 바빠서 블로그 정리도 못하고 있네요. 더운날씨 건강조심하시기 바랍니다.

2년전부터 블록체인 기술에 관심이 생겨서 이것저것 찾아보면서 지식을 쌓았다. 이론만 공부하면 뜬구름 잡는 이야기처럼 들릴 수 있기 때문에 개발자라면 직접 구현을 한번 해보는것이 중요하다. 블록체인을 구현할 수 있는 언어들이 많지만 그중에서 가장 접근성이 쉬운 자바스크립트를 이용해서 개발을 해보겠다. 일단 자바스크립트와 node .js에 대한 기초 지식은 있어야 한다.


자바스크립트로 블록체인 구현 강좌1 - 나만의 비트코인 발행하기

1.셋팅

바탕화면에 개발 폴더를 만든다. 예를 들면 blockchain폴더를 만들었다고 하자. 그 폴더 위치에서 npm init을 해준다. 그러면 node js 서버를 구축 할 수 있는 기본 셋팅이 완료 된다. blockchain 폴더 안에 dev 폴더를 만들고 그안에 test.js blockchain.js 폴더를 만들자. 아래 그림과 같다.


2. 기초지식 - 자바스크립트 데이터 구조

본격적으로 들어가기전에 자바 스크립트로 데이터를 주고 받을 데이터 구조에 대한 개념을 살펴보자. 일단 데이터 구조는 function 키워드로 만든다. 


function User(name,age){

this.name = name;

this.age = age;

}


이렇게 구조를 만들었으면 이 구조를 이용해서 객체를 생성할 수 있다.


var user1 = new User('길위의 개발자', '30');

....

var user50000 = new User('스티브잡스', '31');


이런식이다. 이렇게 user의 수천 수만건의 name, age 데이터를 컨트롤 할 수 있다.


3.기초지식  - 자바스크립트 프로토타입 객체

프로토타입은 아주 쉽게 말해서 함수에 속성이나 기능을 공통적으로 추가하는 객체를 이야기 한다. 엄청간단하게 말하면 그렇다. 예를 들면

위에서 만든 User 함수에 

User.prototype.emailDomain = "@google.co.kr";

이라고 설정해주면 User 로 만든 모든 객체들이 예를들면 user1....user5000까지 emailDomain 속성을 가지게 되고 그 값으로 @google.co.kr 을 가진다.

user50000.emailDomain; 이라고 쳐보자 위에서 대입한 이메일 값이 나올것이다. 이렇게 속성 값을 공통으로 지정해 줄 수 있을 뿐 아니라 기능도 추가해 줄 수 있다.


User.prototype.getEmailAddress = function(){

return this.name + this.age this.emailDomain;

}

이런식으로!


그리고 

user50000.getEmailAddress(); 라고 쳐보자 어떤 값이 나오는지! 유저 객체의 이름과 나이, 이메일 값을 리턴하는 것을 볼 수 있을 것이다.


3.블록체인 데이터 구조 만들기

위의 내용을 기초로 블록체인 데이터 구조를 만들어 보자. blockchain.js 파일을 열고 아래와같은 코드를 넣어준다.

//블록체인 데이터 구조
function Blockchain(){
this.chain = [];
this.newTransactions = [];
}


클래스를 이용해서 아래처럼 만들 수 있지만 위에 데이터 구조를 이용하겠다.

//클래스를 이용한 블록체인 데이터 구조 위와 동일하다...
class Blockchain{
constructor(){
this.chain = [];
this.newTransactions = [];
}
}


3.블록체인 프로토타입 함수 정의하기

위에서 블록체인 데이터 구조를 정의 했으면 이번에는 프로토 타입 함수를 이용해서 블록체인 객체에 새로운 블록생성 기능을 담당하는 함수를 정의한다. 새로운 블록이 생성될때 발생하는 시간데이터, 순번 데이터, hash 데이터들을 담을 newBlock 객체를 만들어 주었다.

nonce, hash 는 블록체인 이론에 대해서 설명을 해야 되기 때문에 이번 포스팅에서는 넘어가도록 하자. 아직까지 이해가 안갈 수 있는데 나중에 이 함수가 어떻게 출력이 되는지 직접 데이터를 찍어보겠다.

//블록체인 프로토 타입 함수 정의
Blockchain.prototype.createNewBlock = function(nonce,previousBlockHash,hash){
//새 블록 객체
const newBlock = {
index: this.chain.length + 1,
timestamp: Date.now(),
transactions: this.newTransactions,
nonce:nonce,
hash:hash,
previousBlockHash:previousBlockHash
};

//다음 거래를 위한 거래내역 배열 비워주고 새로운 블록을 chin 배열에 추가
this.newTransactions = [];
this.chain.push(newBlock);

return newBlock;

}



여기까지 정리하면 아래 그림과 같다



firebase 안드로이드 2 단계 - tablayout framgment CustomAdapter 감사리스트 불러오기

소스코드

https://firebasestorage.googleapis.com/v0/b/testmemo-8978f.appspot.com/o/android_thanks_project%2FThanks2.zip?alt=media&token=41421387-7dbf-43a8-9e71-7dbdbe41750f



일지:

tablayout 을 구성하고, fragment를 만들어주었다. 

그리고 customAdaptView를 만들어서 listview에 넣어주었 (AdaptView를 통해서)

파이어베이스에서 데이터를 가져와서 리스트뷰에 뿌려주었다.


다음에 할 것:

1.감사리스트 써서 저장.

2.리스트뷰 갱신.

3.감사리스트 글 하나 클릭하면 다른 유저 프로필 페이지로 넘어가기.

4.(레이아웃만들어주고, 파이어 베이스에서 데이터 받아와서 뿌려주기, 뒤로가기 버튼 추가)

5.가입할 때 파이어베이스 user table에 user name 넣어주기.



소스코드








탭바 레이아웃


탭바 java

package me.happygate.thanks;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.widget.TextView;
import android.support.v4.app.Fragment;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;

public class MainActivity extends AppCompatActivity {
//이메일 비밀번호 로그인 모듈 변수
private FirebaseAuth mAuth;
//현재 로그인 된 유저 정보를 담을 변수
private FirebaseUser currentUser;

private TextView mTextMessage;

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

switch (item.getItemId()) {
case R.id.navigation_home:
replaceFragment(Fragement_A_Activity.newInstnace());
return true;
case R.id.navigation_dashboard:
replaceFragment(Fragement_B_Activity.newInstnace());
return true;
case R.id.navigation_notifications:
replaceFragment(Fragement_C_Activity.newInstnace());
return true;
}
return false;
}

};

// Fragment 변환을 해주기 위한 부분, Fragment의 Instance를 받아서 변경
private void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content, fragment).commit();
}


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAuth = FirebaseAuth.getInstance();
mTextMessage = (TextView) findViewById(R.id.message);

BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.content, Fragement_A_Activity.newInstnace()).commit();

}


//로그인 되어있으면 currentUser 변수에 유저정보 할당. 아닌경우 login 페이지로 이동!
@Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
currentUser = mAuth.getCurrentUser();
if(currentUser == null){
startActivity(new Intent(MainActivity.this, LoginActivity.class));
finish();
}
}


}




리스트뷰



리스트뷰 소스코드

package me.happygate.thanks;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.FirebaseDatabase;

import java.util.ArrayList;

public class Fragement_A_Activity extends Fragment {

public static Fragement_A_Activity newInstnace(){
return new Fragement_A_Activity();
}

//이메일 비밀번호 로그인 모듈 변수
private FirebaseAuth mAuth;
//현재 로그인 된 유저 정보를 담을 변수
private FirebaseUser currentUser;
//데이터 베이스 저장
private static FirebaseDatabase database;

//감사리스트 데이터 담을 리스트
ArrayList<String> names = new ArrayList<String>();
ArrayList<String> contents = new ArrayList<String>();
ArrayList<String> dates = new ArrayList<String>();
ArrayList<String> thankPK = new ArrayList<String>();
ArrayList<String> userKey = new ArrayList<String>();

CustomAdapter ca; //커스텀 어뎁터

//제일 먼저 호출
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAuth = FirebaseAuth.getInstance();
database = FirebaseDatabase.getInstance();
Log.d("myTag1", "onCreate-0");
displayThanks();
}
//두번째 호출됨
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

Activity root = getActivity(); //이 클래스가 프레그먼트이기 때문에 액티비티 정보를 얻는다.
Log.d("myTag1", "onCreateView-1");
Log.d("myTag2", "onCreateView-2");
View view = inflater.inflate(R.layout.activity_fragement__a_,container,false);

ListView listView = (ListView)view.findViewById(R.id.listView);
final EditText editText = (EditText)view.findViewById(R.id.thanksTxtField);
final Button writeBtn = (Button)view.findViewById(R.id.thankWriteButton);
writeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
writeBtn.setText(editText.getText().toString());
}
});

ca = new CustomAdapter();
listView.setAdapter(ca);

return view;

}
//커스텀 뷰
class CustomAdapter extends BaseAdapter{
@Override
public int getCount() {
return names.size();
}
@Override
public long getItemId(int position) {
return 0;
}

@Override
public Object getItem(int position) {
return null;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {

Activity root = getActivity(); //이 클래스가 프레그먼트이기 때문에 액티비티 정보를 얻는다.
Toast.makeText(root,"getView" , Toast.LENGTH_SHORT).show();

//커스텀뷰에 있는 객체들 가져오기
convertView = getLayoutInflater().inflate(R.layout.custom_listview_layout,null);
TextView tName = (TextView)convertView.findViewById(R.id.textView_name);
TextView tDate = (TextView)convertView.findViewById(R.id.textView_date);
TextView tContent = (TextView)convertView.findViewById(R.id.textView_content);

tName.setText(names.get(position));
tDate.setText(dates.get(position));
tContent.setText(contents.get(position));
return convertView;
}
}

//감사 리스트 호출 함수
public void displayThanks(){
database.getReference("thanks/")
.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//개수 만큼 돈다

//Activity root = getActivity(); //이 클래스가 프레그먼트이기 때문에 액티비티 정보를 얻는다.
//Toast.makeText(root,"onChildAdded-2" , Toast.LENGTH_SHORT).show();
Log.d("myTag3", "onChildAdded-2");


ThankDTo thankDTo = dataSnapshot.getValue(ThankDTo.class);
//키값이랑 같이 넣어주기
thankDTo.setThankPK(dataSnapshot.getKey());

//Activity root = getActivity(); //이 클래스가 프레그먼트이기 때문에 액티비티 정보를 얻는다.
//Toast.makeText(root, thankDTo.getName()+"/"+ thankDTo.getComment(), Toast.LENGTH_SHORT).show();

names.add(thankDTo.getName());
dates.add(thankDTo.getCreatetime());
contents.add(thankDTo.getComment());
thankPK.add(thankDTo.getThankPK());
userKey.add(thankDTo.getUserkey());

int a = names.size();
String aa = String.valueOf(a);
Log.d("myTagrsult", aa);
//이거를 해줘야지 adapter getView가 호출이 된다!!!!중요!!!
ca.notifyDataSetChanged();
//Toast.makeText(root, aa , Toast.LENGTH_SHORT).show();
}

@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {

}

@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {

}

@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {

}

@Override
public void onCancelled(DatabaseError databaseError) {

}
});
}

}



커스텀 레이아웃







  1. dk0011 2018.10.11 14:59

    names.add(thankDTo.getName());
    dates.add(thankDTo.getCreatetime());
    contents.add(thankDTo.getComment());
    thankPK.add(thankDTo.getThankPK());
    userKey.add(thankDTo.getUserkey());

    int a = names.size();
    String aa = String.valueOf(a);
    Log.d("myTagrsult", aa);
    //이거를 해줘야지 adapter getView가 호출이 된다!!!!중요!!!

    여기서 정확히 어떤 코드가 adapter의 getView가 호출이 된다는건지 알려주실 수 있나요?

    • 나그네 2019.09.09 17:24

      1년 뒤 지나가던 나그네가 답합니다만...
      다른 공부하시는 분들 도움이 되고자ca.notifyDataSetChanged();
      이 코드가 adapter의 getView를 호출해줍니다.

firebase 안드로이드 1 단계 - 설정 로그인 가입 기능




소스코드 다운로드


https://firebasestorage.googleapis.com/v0/b/testmemo-8978f.appspot.com/o/android_thanks_project%2FAndroid_Thanks1.zip?alt=media&token=f9cda798-6348-4bbd-8d89-d5e4c0af0f61



* 초기 설정


0. 안드로이드 플랫폼 설정해주기


1.Google-play.service.json app 수준에 넣어준다.


2.프로젝트 빌드 그래들 열어서 Sdk 추가하기


3.앱모듈안에도 sdk 넣어준다.


4.싱크 나우 눌러주기


5.안되면 구글 리파지토리, sdk 업데이트


 6.Apply plugin 아랫줄에 복사해서 넣어준다.


프로젝트 생성





구성파일 다운로드






프로젝트 수준 build.gradle




메니페스트





앱 수준 build.gradle




서명 인증서






서명인증서











--------------------------------------------------------------------------------------------------------------------------------------------------














join.activity


package me.happygate.thanks;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
import com.google.firebase.auth.FirebaseAuthWeakPasswordException;
import com.google.firebase.auth.FirebaseUser;

public class JoinActivity extends AppCompatActivity {

//이메일 비밀번호 로그인 모듈 변수
private FirebaseAuth mAuth;
//현재 로그인 된 유저 정보를 담을 변수
private FirebaseUser currentUser;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join);

mAuth = FirebaseAuth.getInstance();

//이메일
final EditText emailTxt = (EditText)findViewById(R.id.emailTxt);
//이름
final EditText nameTxt = (EditText)findViewById(R.id.nameTxt);
//비밀번호
final EditText pwTxt = (EditText)findViewById(R.id.pwTxt);
//버튼
Button joinBtn = (Button)findViewById(R.id.joinBtn);


//버튼이 눌렀을 때
joinBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

String email = emailTxt.getText().toString();
String name = nameTxt.getText().toString();
String pw = pwTxt.getText().toString();


Toast.makeText(JoinActivity.this,email +"/=가입 버튼 눌리고" + name +"/" + pw,Toast.LENGTH_SHORT).show();


//가입 성공했을 때 -> 감사리스트 메인 페이지로 이동하기

//Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
//startActivityForResult(signInIntent, 100);Toast.makeText(AuthActivity.this,"btn",Toast.LENGTH_SHORT).show();
//Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
// startActivityForResult(signInIntent, 100);

joinStart(email,name,pw);
}
});

}
//가입 함수
public void joinStart(String email, final String name, String password){

mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {

if(!task.isSuccessful()) {
try {
throw task.getException();
} catch(FirebaseAuthWeakPasswordException e) {
Toast.makeText(JoinActivity.this,"비밀번호가 간단해요.." ,Toast.LENGTH_SHORT).show();
} catch(FirebaseAuthInvalidCredentialsException e) {
Toast.makeText(JoinActivity.this,"email 형식에 맞지 않습니다." ,Toast.LENGTH_SHORT).show();
} catch(FirebaseAuthUserCollisionException e) {
Toast.makeText(JoinActivity.this,"이미존재하는 email 입니다." ,Toast.LENGTH_SHORT).show();
} catch(Exception e) {
Toast.makeText(JoinActivity.this,"다시 확인해주세요.." ,Toast.LENGTH_SHORT).show();
}
}else{

currentUser = mAuth.getCurrentUser();

Toast.makeText(JoinActivity.this, "가입 성공 " + name + currentUser.getEmail() + "/" + currentUser.getUid() ,Toast.LENGTH_SHORT).show();

startActivity(new Intent(JoinActivity.this, MainActivity.class));
finish();
}
}
});

}
}




login.activity

package me.happygate.thanks;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseNetworkException;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
import com.google.firebase.auth.FirebaseAuthInvalidUserException;
import com.google.firebase.auth.FirebaseUser;

public class LoginActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener{

//이메일 비밀번호 로그인 모듈 변수
private FirebaseAuth mAuth;
//현재 로그인 된 유저 정보를 담을 변수
private FirebaseUser currentUser;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mAuth = FirebaseAuth.getInstance(); //이메일 비밀번호 로그인 모듈 변수

//이메일
final EditText emailTxt = (EditText)findViewById(R.id.emailTxt);
//비밀번호
final EditText pwTxt = (EditText)findViewById(R.id.pwTxt);
//버튼
Button joinBtn = (Button)findViewById(R.id.joinBtn);


//이메일
final TextView goJoinTxt = (TextView)findViewById(R.id.goJoinTxt);

//로그인 버튼이 눌렀을 때
joinBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

String email = emailTxt.getText().toString();
String password = pwTxt.getText().toString();

//로그인 성공했을 때 -> 감사리스트 메인 페이지로 이동하기
loginStart(email, password);
}
});

//가입하러 가기 버튼 눌렀을 때
goJoinTxt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(LoginActivity.this,"가입하러 가기 버튼 눌렀을 때",Toast.LENGTH_SHORT).show();
startActivity(new Intent(LoginActivity.this, JoinActivity.class));
finish();
}
});

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Toast.makeText(LoginActivity.this,"연결이 해제되었습니다",Toast.LENGTH_SHORT).show();
}

//public Boolean check;
public void loginStart(String email, String password){
Toast.makeText(LoginActivity.this,"loginStart 함수 안으로" ,Toast.LENGTH_SHORT).show();
mAuth.signInWithEmailAndPassword(email,password).addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {

Toast.makeText(LoginActivity.this,"mAuth. onComplete 함수" ,Toast.LENGTH_SHORT).show();
if (!task.isSuccessful()) {
try {
throw task.getException();
} catch (FirebaseAuthInvalidUserException e) {
Toast.makeText(LoginActivity.this,"존재하지 않는 id 입니다." ,Toast.LENGTH_SHORT).show();
} catch (FirebaseAuthInvalidCredentialsException e) {
Toast.makeText(LoginActivity.this,"이메일 형식이 맞지 않습니다." ,Toast.LENGTH_SHORT).show();
} catch (FirebaseNetworkException e) {
Toast.makeText(LoginActivity.this,"Firebase NetworkException" ,Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Toast.makeText(LoginActivity.this,"Exception" ,Toast.LENGTH_SHORT).show();
}

}else{


currentUser = mAuth.getCurrentUser();

Toast.makeText(LoginActivity.this, "로그인 성공" + "/" + currentUser.getEmail() + "/" + currentUser.getUid() ,Toast.LENGTH_SHORT).show();

startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}

}
});
}

//로그아웃 안했으면, 즉 로그인 되어있으면 자동으로 메인페이지로 이동시키기
@Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
currentUser = mAuth.getCurrentUser();
if(currentUser != null){
startActivity(new Intent(LoginActivity.this, MainActivity.class));
finish();
}
}



}







Main.activity


package me.happygate.thanks;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.widget.TextView;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;

public class MainActivity extends AppCompatActivity {
//이메일 비밀번호 로그인 모듈 변수
private FirebaseAuth mAuth;
//현재 로그인 된 유저 정보를 담을 변수
private FirebaseUser currentUser;

private TextView mTextMessage;

private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {

@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {

switch (item.getItemId()) {
case R.id.navigation_home:
mTextMessage.setText(currentUser.getEmail());
return true;
case R.id.navigation_dashboard:
mTextMessage.setText(currentUser.getUid());
return true;
case R.id.navigation_notifications:
mTextMessage.setText(currentUser.getEmail());
return true;
}
return false;
}

};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAuth = FirebaseAuth.getInstance();
mTextMessage = (TextView) findViewById(R.id.message);

BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}


//로그인 되어있으면 currentUser 변수에 유저정보 할당. 아닌경우 login 페이지로 이동!
@Override
public void onStart() {
super.onStart();
// Check if user is signed in (non-null) and update UI accordingly.
currentUser = mAuth.getCurrentUser();
if(currentUser == null){
startActivity(new Intent(MainActivity.this, LoginActivity.class));
finish();
}
}


}










=============================================================================================================================









다음작업


1.가입할때 user name 파이어베이스 db에 push 시켜주기


2.로그아웃 기능



3.땡스피드 페이지 꾸미기 - tap layout , intent, viewpager  체크


*글쓰기 기능 - 저장 , null 체크

*조회 - 감사리스트 불러오기

*글 누르면 다른 user 프로필 페이지로 이동하기





firebase 호스팅 테스트 4단계 글 수정 삭제 기능& 다른사람이 쓴 글 클릭하면 글 조회


소스파일

testMemo.zip



개발일지

마이페이지를 들어오면 현재 로그인한 유저의 key 와 글테이블에 넣어놓은 userkey를 비교해서 자신이 쓴글을 전부 가져오기를 성공했다.

그리고 dom으로 수정, 삭제 버튼을 붙여 주었고, 수정과 삭제는 토글 기능을 구현해 주었다. 저장을 누르면 저장이 된다.

그리고 감사 리스트에서 다른사람이 쓴글을 누르면 프로필 페이지로 이동하고 다른 사람 프로필과 쓴글을 볼 수 있다. 

하지만 수정 삭제 버튼은 없다. 이것도 key를 이용해서 처리해 주었다. 그리고 js 인디케이터 기능을 구현해주었다. 

firebase storege에서 파일을 가져올때 시간이 조금 지연되는것을 발견했다... 이건 조금더 파봐야 될것 같다.

그래서 페이지 새로 고침하면 뱅글뱅글 돌아가는 인디케이터를 1초정도 줘서 유저가 지루해(?)하지 않게 해주었다.

그리고 네비게이션바를 모바일버젼에 맞게 수정해주었다. pc버젼에서는메뉴가 길게 늘어나고, 모바일 버젼에서는 오른쪽에 석삼? 햄버거? 모양처럼 나오게 만들었다.

음...가입할때 id 채크 비번체크 등등등 디테일하게 해줄게 정말 많지만... 

이번은 firebase 테스트 버젼이기 때문에.. 적당히(?) 얼른얼른 넘어가쟈 >.<


***********************************************************************************************************************************


!유지보수해야될 부분

그리고..문제가 하나 있당..

감사리스트에서 다른사람이 쓴 글 클릭하면 다른사람 프로필페이지로 넘어가는데.. 

window.locatoin = '/주소' + 다른사람key

이렇게 처리 했따..

큰문제는 없지만..보안상 문제가 쬐끔 될수 있겠다..

시간나면 다른방법을 생각해보자!


문제 하나 더!

프로필 페이지 수정부분에서 글만 수정하려고 하면 수정이 안된다.

이미지를 업로드하고 글을 같이 수정 또는 삽입 해야 변경이된다.

이 부분도 해결하자.



사진캡쳐


#.페이지 인디케이터 만들어주기


#.수정버튼을 누르면



#.input text 활성화가 되고 수정글 넣기~



#.수정완료



#.삭제하면 confirm 창뜨고 확인 누르면 삭제


#.삭제 되었음


#.다른 사람 페이지에 가면 수정, 삭제 버튼이 없다.


#다음 작업


1.감사리스트 날짜순으로 정렬, 

2. 감사리스트 페이징 해보기,

3. 감사리스트 날짜 스트링함수로 정리해서 이쁘게 보여주기 

4.검색기능 달아보기 

5. 감사리스트에 마우스 올리면 회색 표시해주기 ~~

6. 사진 대체 해주기 7. 엔터 이벤트 기능












firebase 호스팅 테스트 3단계 프로필 페이지 만들기



오늘은 프로필 페이지를 만들었다. html웹에서 firebase로 사진 업로드 하는 기능을 넣었다. 첫 프로필 화면에서 수정버튼을 누르면 사진 선택하기 버튼, 한줄 상태 메시지 수정하기 필드가 활성화된다. 저장하기를 누르면 사진이 firebase 스토리지에 저장이되고 그 URL 주소가  firebase 실시간 DB에 저장이 된다.


수정전



수정중




수정완료




* 남은 이슈

1.쓴 글목록 날짜 최신순으로 정렬시키기

2.마이페이지 읽어 올때 너무 사진이 너무 느리게 로드 된다. 그래서 사진 로드 되기전에 수정하기 버튼누르면 오류가 발생한다. 웹에는 로딩중이라는 인디케이터 같은게 없을까낭..음.. 그리고 마이페이지 부분 소스코드 정리를 좀 해야겠다..

3.닉네임도 수정할 수 있게 해야 하나? 음..........고민

4.thanks 테이블에서 createtime은 그냥 time 으로 바꿔주자.. 그냥 수정 일자만 중복으로 저장되게.........

5.사진 파일 선택후 이미지를 열기 하면 화면상에 바로 나타지않는다. 저장하기 눌러야 스토리지에 저장이 된다음 나타난다. 이 문제도 생각을 해보자


* 다음작업

1.마이페이지의 한줄 상태 메시지 밑에 자기가 쓴 감사 리스트 가져와서 뿌려주고

2.수정 삭제 버튼 따로 만들어서 붙여주기 

3.로그인된 userkey와 글 리스트의 userkey를 비교해서 같으면 수정삭제 버튼이 뜨게 해야지 

4.메인 페이지 글리스트에서 해당 글을 누르면 다른 유저의 마이페이지로 가는데 수정버튼 삭제하고, 글만 볼 수 있게 5. 마찬가지로 userkey로비교




firebase 호스팅 테스트 2단계 글목록 불러오기


 소스코드

testMemo.zip




오늘 구현할 작업은

1.감사일기 삽입하기 (로그인 안되어있으면 글쓰기 불가능, 리스트도 나오지 않음)


2.로그인 되어 있으면 체크해서 감사일기를 쓰기 폼 밑 부분에 리스트로 뿌리기

(로그인 안되어 있으면 리스트 안나옴)



3.클릭하면 해당 마이 페이지로(메모 리스트 태그에 userkey 삽입해놓기)


-유저 정보와 유저가 글목록 보이게 하기



4.내가 글이면 수정 삭제 가능(버튼이 보이게하기)













파이어 베이스 부분








일지


파이어베이스에 감사일기를 담는 thanks라는 최상위 테이블(객체)를 생성하는데 애를좀 먹었다. 익숙하지가 않아서...

감사리스트는 로그인 되어 있으면 js 단에서 동적으로 가져와서 실시간으로 만들어 준다.

글을쓴 후 쓰기 버튼을 누르면 파이어베이스에 저장이 되고 바로 새로 고침 없이 리스트로 뿌려준다.

메모 하나 하나당 글쓴 유저의 key 값을 넣어놓았다. 누르면 해당 유저 페이지로 이동한다. 

하지만 오늘은 시간이 없어서 다음에 구현해야지...




다음에 구현할 작업


3.클릭하면 해당 마이 페이지로(메모 리스트 태그에 userkey 삽입해놓기)


-유저 정보와 유저가  글목록 보이게 하기 (페이지 만들고 마무리 짓기)



4.내가  글이면 수정 삭제 가능하게 구현(버튼이 보이게하기)





firebase 호스팅 테스트 1 단계


firebase 테스트 한 결과 개인적으로 정리하는 페이지 입니다.(가입,로그인,로그아웃) ..정리 보다는 기록을 위한 페이지 입니다..


소스파일 

testMemo.zip





파이어 베이스 부분





작업순서

0.파이어베이스 프로젝트 생성

1.node.js 설치

2.firebase 설치

3. 바탕화면에 폴더 만들고

4. firebase init

5. public 폴더 만들어서 index.html 생성

5-1. firebase serve 로 서버 가동



6.메인 페이지 만들기

7.로그인 되어 있는지 안되어 있는지 확인하기



8.가입페이지 만들기

-가입성공하면 바로 메인화면으로 리다이렉트

9.로그인 페이지 만들기

-로그인 했으면 메뉴이름을 '로그아웃'으로 바꿔주기

- 로그인 했으면 메뉴 이름을 닉네임으로 바꿔주기


10.로그아웃 페이지 만들기

-로그아웃 하면 메뉴 이름을 다시 원래대로 해주기



일지: 메인페이지를 만들었고, 가입, 로그인, 로그아웃 페이지를 만들었고 해당 기능을 만들었다. 상용보다는 firebase를 익히기 위한 목적이니 firebase의 데이터 구조와 파이어 베이스의 insert, update delete 함수를 익히는데 집중해야겠다.

다음 작업은 

1.메인화면에 '오늘의 감사' 쓰기. 

2.그리고 그 밑 부분에 회원들이 쓴 오늘의 감사 리스트 출력해서 보여주기.(날짜순으로)

3. 마이페이지 들어가면 나의 정보 조회하기, 수정, 사진 업데이트하기, 내가 쓴 글 리스트 출력하기 (조회), 삭제하기, 수정하기. 



+ Recent posts