스타르타 코딩 스터디

w ho
18 min readFeb 7, 2020

--

— 가계부 웹어플리케이션

1.프로젝트 이름/설명

나의 accounting 관리하기 : 웹사이트서비스를 통해서 구매내역을 등록하여 등록된 정보를 이용하여 구매상황을 도표로 분석 및 엑셀파일로 정리

2. 기획 의도

▶1~4주차에 배운 html javascript ajax통신 python 웹크롤링 flask 등을 활용

▶사용자의 자금관리에 대한 자각을 위해 주제 선정

3.개발해야하는 기능

  1. 로그인기능 → 다른기능 완성후 추가

2. 구매내역 등록하기

3. 등록된 내역 분석 하여 화면에 보여주기

4. 데이터를 가지고 엑셀에 저장 하는 기능

4.개발계획

5주차 : 구체적인 계획 및 시작

6주차: html 폼 만들기 / 데이터 등록하기 기능 / 엑셀DB파일생성

7주차: 웹페이지에 시각화 하여 분석 / 추가: 로그인 기능

  • >시간여유가 된다면 조회기능 추가 👌

2019.20.21 개발일지

전체적인 계획 완료 : https://ovenapp.io/project/V3yBtIVRolWq3hioDiU4OrgwLBE9tvjY#zt5jK

  1. navbar 에 해당되는 페이지 ( 전체, 이번달, 거래 입력, 엑셀파일) html 생성
  2. 거래 입력 에 해당되는 페이지에서 input 값 및 화면에 띄우기
  3. 전체 가계부 -> 달력 디자인 필요 : full calendar 사용 예정

# 가져올때 달력 안에 날짜에 해당되는 DB를 고려하여 디자인 예정 #

2019.12.22 개발일지

조금이라도 진행하고자 꾸역꾸역 진행 …

달력 -> table 만들어 직접 구현 ..

원래는 모든 달력을 넣을려 했지만 그건 너무 많고, 복잡할것 같아 하나의 달력에서 진행하고자 한다. var today = new Date(); 이러한 함수를 이용하여 현재 날짜를 알아낼수 있었다. 또한
원래는 모든 달력을 넣을려 했지만 그건 너무 많고, 복잡할것 같아 하나의 달력에서 진행하고자 한다. var today = new Date(); 이러한 함수를 이용하여 현재 날짜를 알아낼수 있었다.

#전체 해당되는 값을 어떻게 화면에 보여줄지 고민이다 .

2019.12.23

팀에서 개인으로 바뀌게 되었다. .

ajax 통신으로 post get 방식 사용 money라는 db 에 저장 성공
거래 입력 화면 성공 !! ajax 통신으로 money라는 db에 저장

의문점 : pycharm 에서 열면 적용 되는데 그냥 html 파일 자체를 열면 적용안됨

2019.12.26

ajax통신 완료 -> 거래 등록시 mongodb에 저장 및 불러오기 성공!

데이터 차트로 불러오기 (라이브러리 사용 Chart.js)

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>

전체가계부 비교 화면 구현 해당 년에 월별로 가격 비교

#생각보다 금방할거 같다 …

2020.01.04 수업

AWS를처음 해봄 .. EC2접속 완료
myenv 가상환경 만들어서 FILEZILLA 이용해서 연결하기

2020. 01 .06

엑셀 파일 활용해서 프로젝트에 적용하기

function excel(){
$.ajax({
// GET 형식으로 값을 불러온다
type: "GET",
url: "/excel",
data: {},
success: function(response){ alert('파일이 생성되었습니다' ) }
})
}
@app.route('/excel',methods=['GET'])
def exeting():
result = list(db.counting.find({}, {'_id': 0}))
row = 4
work_book = load_workbook('prac01.xlsx')
work_sheet = work_book['prac']
sum=0
cafe=0
food=0
medical=0
other=0
for s in result:
print(s['somedate'])
work_sheet.cell(row=row, column=1, value=s['somedate']) #날짜 엑셀에 적용
work_sheet.cell(row=row, column=2, value=s['content']) # 내용 엑셀에 적용
work_sheet.cell(row=row, column=3, value=s['tag']) # 태그 엑셀에 적용
work_sheet.cell(row=row, column=4, value=s['money']) #돈 엑셀에 적용
sum+=int(s['money'])
if(s['tag']=='카페'):
cafe+=int(s['money'])
if (s['tag'] == '카페'):
cafe += int(s['money'])
if (s['tag'] == '음식'):
food += int(s['money'])
if (s['tag'] == '의료비 및 보험비'):
medical += int(s['money'])
if (s['tag'] == '기타'):
other += int(s['money'])
row=row+1
work_sheet.cell(row=4, column=6, value=sum) # 총 금액 엑셀에 적용 #태그별 금액
work_sheet.cell(row=7, column=6, value=cafe)
work_sheet.cell(row=7, column=7, value=food)
work_sheet.cell(row=7, column=8, value=medical)
work_sheet.cell(row=7, column=9, value=other)
work_book.save('prac01.xlsx')
return jsonify({'result': 'success', 'shops': result})

counting 데이터베이스에 있는 값들을 엑셀에 각 자리에 맞춰서 데이터를 적용 및 생성

2020 01 10

엑셀 파일생성을 거래입력에 버튼으로 바꾸고 도움말text 화면 구현
엑셀파일 생성 기능 버튼으로 변경 / 해당되는 경제활동을 5개 단위로 정리
for (var i = nextcontent; i < nextcontent+5; i++)
{
if(i>articles.length || i<0)break;
// console.log(nextcontent)
// console.log(articles[nextcontent]['content'])

make_card(articles[i]['somedate'],articles[i]['money'],articles[i]['content'],articles[i]['tag'],
count)
count++;
}
}

2020 01 20

이번달 가계부에 대한 종류별 데이터 구체화
function ready(){
$.ajax({
type: "GET",
url: "/money",
data: {},
success: function(response){
let articles = response['shops'];
console.log(response['shops'])
for (var i = 0; i < articles.length; i++)
{
console.log(articles[i]['tag'])
if(articles[i]['tag']=='음식')
{
console.log("태그 음식")
food+=parseInt(articles[i]['money'])
console.log(food)
}
if(articles[i]['tag']=='기타')
{
other+=parseInt(articles[i]['money'])
}
if(articles[i]['tag']=='카페')
{
cafe+=parseInt(articles[i]['money'])
}
if(articles[i]['tag']=='의료비 및 보험비')
{
medical+=parseInt(articles[i]['money'])
}
}
var ctx = document.getElementById("myChart").getContext('2d');
/*
- Chart를 생성하면서,
- ctx를 첫번째 argument로 넘겨주고,
- 두번째 argument로 그림을 그릴때 필요한 요소들을 모두 넘겨줍니다.
*/
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["음식", "카페", "의료", "기타"],
datasets: [{
label: '# of Votes',
data: [food, cafe, medical, other],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
],
borderWidth: 1
}]
},
options: {
maintainAspectRatio: true, // default value. false일 경우 포함된 div의 크기에 맞춰서 그려짐.
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
} })}

GET 으로 money 라는 restAPI를 했을 경우 Chart 안에 종류별로 적용

(파이선에서는 단지 값들만 호출)

@app.route('/money', methods=['GET'])
def getting():
# 모든 document 찾기 & _id 값은 출력에서 제외하기
# result =list(db.counting.find({},{'_id':0}))
result =list(db.counting.find({},{'_id':0}))
# shops라는 키 값으로 내려주기
return jsonify({'result': 'success', 'shops': result})

2020 01 12

로그인 / 회원가입 추가

jwt 라이브러리를 이용하여 로그인 구현

import jwtSECRET_KEY = 'apple'  # 토근시 필요한 보안 - 아무거나 입력 원하는거@app.route('/register')         # 회원이 아니라 면을 클릭하게 되면
def register():
return render_template('register.html')
@app.route('/api/register', methods=['POST']) #회원가입시 db.counting.insert_one(imformation)
def api_register():
id_receive = request.form['id_give']
pw_receive = request.form['pw_give']
pw_hash = hashlib.sha256(pw_receive.encode('utf-8')).hexdigest() db.temp.insert_one({'id':id_receive,'pw':pw_hash}) return jsonify({'result': 'success'})
@app.route('/api/login', methods=['POST'])
#로그인 완료시 id와 pwd 비교 성공하면 html 에서 index.html로 이동
def api_login():
id_receive = request.form['id_give']
pw_receive = request.form['pw_give']
# 회원가입 때와 같은 방법으로 pw를 암호화합니다.
pw_hash = hashlib.sha256(pw_receive.encode('utf-8')).hexdigest()
# id, 암호화된pw을 가지고 해당 유저를 찾습니다.
result = db.temp.find_one({'id':id_receive,'pw':pw_hash})
# 찾으면 JWT 토큰을 만들어 발급합니다.
if result is not None:
# JWT 토큰에는, payload와 시크릿키가 필요합니다.
# 시크릿키가 있어야 토큰을 디코딩(=풀기) 해서 payload 값을 볼 수 있습니다.
# 아래에선 id와 exp를 담았습니다. 즉, JWT 토큰을 풀면 유저ID 값을 알 수 있습니다.
# exp에는 만료시간을 넣어줍니다. 만료시간이 지나면, 시크릿키로 토큰을 풀 때 만료되었다고 에러가 납니다.
payload = {
'id': id_receive,
'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=3600)
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256').decode('utf-8')
# token을 줍니다.
return jsonify({'result': 'success','token':token})
# 찾지 못하면
else:
return jsonify({'result': 'fail', 'msg':'아이디/비밀번호가 일치하지 않습니다.'})
@app.route('/api/id', methods=['GET'])
def api_valid():
# 토큰을 주고 받을 때는, 주로 header에 저장해서 넘겨주는 경우가 많습니다.
# header로 넘겨주는 경우, 아래와 같이 받을 수 있습니다.
token_receive = request.headers['token_give']
# try / catch 문?
# try 아래를 실행했다가, 에러가 있으면 except 구분으로 가란 얘기입니다.
try:
# token을 시크릿키로 디코딩합니다.
# 보실 수 있도록 payload를 print 해두었습니다. 우리가 로그인 시 넣은 그 payload와 같은 것이 나옵니다.
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
print(payload)
# payload 안에 id가 들어있습니다. 이 id로 유저정보를 찾습니다.
# 여기에선 그 예로 닉네임을 보내주겠습니다.
userinfo = db.temp.find_one({'id':payload['id']},{'_id':0})
return jsonify({'result': 'success','id':userinfo['id']})
except jwt.ExpiredSignatureError:
# 위를 실행했는데 만료시간이 지났으면 에러가 납니다.
return jsonify({'result': 'fail', 'msg':'로그인 시간이 만료되었습니다.'})

토큰값을 받으면 id 값을 받아온다

$.ajax({
type: "GET",
url: "/api/id",
headers: { 'token_give' : $.cookie('mytoken') },
data: {},
success: function(response){
if (response['result'] == 'success'){
// 올바른 결과값을 받으면 id을 입력해줍니다.
id =response['id']
}
}
})
로그인 화면 / 쿠키값에 토큰 및 id값 저장
$.ajax({
type: "POST",
url: "/api/login",
data: { id_give:$('#userid').val(), pw_give:$('#userpw').val() },
success: function(response){
if (response['result'] == 'success'){
// 로그인이 정상적으로 되면, 토큰을 받아옵니다.
// 이 토큰을 mytoken이라는 키 값으로 쿠키에 저장합니다.
$.cookie('mytoken', response['token']);
alert('로그인 완료!')
location.href='index.html'
} else{
// 로그인이 안되면 에러메시지를 띄웁니다.
alert(response['msg'])
}
}
})

회원가입

회원가입 페이지
회원가입시 id와 pw를 mongodb에 저장 하면서 pw는 해쉬값으로 저장
로그인 후 id값을 가져와서 해당 아이디값과 가계부 입력 저장

그 후 , 해당 아이디에 해당하는 값들만 분석하여 해당 고객의 데이터를 화면에 보여줌

aaa 라는 고객이 로그인 했을 경우
bbb라는 고객이 로그인 했을경우

# 다음 해야 할 일은 고객마다 다른 엑셀파일 생성 해줘야 한다.

2020 01 13

전체적인 디자인을 변경 -> 제공하는 디자인 다운 받아 해당 프로젝트에 맞게 변경

바뀐 UI navbar 형태를 왼쪽에 두고 디자인 설정 관련 데이터 분석을 오른쪽에서 제공

2020 01 14

사용자에 따른 엑셀파일 저장 완료

def exeting():
result = list(db.counting.find({}, {'_id': 0}))
row = 4
token_receive = request.headers['token_give']
#payload를 찍어보면 id 값이 존재한다
payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
# 해당 아이디 값을 받아서 엑셀 저장 이름에 넣는다.
id = payload['id'] + '.xlsx'
....work_book.save(id)

로그인에서 받은 token 을 request 하여 payload 안에 id 값을 적용

사용자 aaa bbb가 저장시 각각 엑셀파일로 저장
EC2에 평생 적용하는 방법

2020 01 18 프로젝트 마무리

#프로젝트

밑에 부분이 짤려서 아쉽지만 아쉬운대로 완료 !!

#취지& 설명 : 금전적인 부분을 혼자서 가계부를 쓰려는 사람들에게 도움을 주는 사이트를 만들어 보자 ( 스파르타 코딩 5기 수업 안에서 배운 내용을 바탕으로 기초적인 기술과 능력을 활용 )

#기술 설명 :

전체적인 디자인 >

. 부트스트랩 이용

사용자별로 데이터 chart화 >

. chart.js 이용

데이터 등록 및 적용 >

. ajax rest api 이용 하여 mongodb에 저장 및 활용

엑셀 파일 생성 기능>

. openpyxl 라이브러리 이용

로그인 기능 / 회원가입 기능 >

  • 이범규님 코드를 참고
  • jwt 라이브러리 이용
  • id 값을 가지고 mongodb에서 각 아이디 별로 데이터 분류

모든 기능을 EC2에 연결 및 가비아 서비스를 이용하여 counting.shop이라는 도메인으로 활성화

#어려웠던부분 & 극복 방법

나중에 로그인 기능을 하게 되어 로그인 후 다시 적용 하는 부분이 어려웠다.

하지만 튜터님의 힘을 이용하여 해결

#8주간 후기

끝날때 까지 끝난게 아닌거 같은 코딩의 8주가 되었다.

--

--

No responses yet