캡스톤 디자인 결과보고서

캡스톤디자인 번호	2021_05팀-박현구
캡스톤디자인 분야	웹 프로그래밍
캡스톤디자인 지도교수	노기섭 교수님
캡스톤디자인 명	(국문) 농장 일기
	(영문) Farm Diary
캡스톤디자인 책임자	팀 명		웹스톤 디자인
	학 과		컴퓨터 정보 공학과
	성 명		박현구			학 번
	휴대폰					E-mail
캡스톤디자인 세부현황	번 호	세부역할			성 명		전 공		학 번
	1	디자인 / 기능 / 서버			박현구		인공지능 소프트웨어
	2	디자인 / 기능 / DB			임동근		인공지능 소프트웨어
	3	디자인 / 기능			이휘동		인공지능 소프트웨어
캡스톤디자인 수행기간	2021년 3월 02일부터 2021년 6월 10일 까지(14주)
2021년도 캡스톤디자인을 성실히 수행하고자 캡스톤디자인 계획서를 제출합니다. 2021 . 03 . 25 . 캡스톤디자인 책임자 박현구 서명 인공지능소프트웨어 전공PD 귀하

1. 요약서

※ 본 요약서는 캡스톤디자인 전체에 대한 요약서임. 캡스톤디자인 전체의 총괄적인 내용을 위주로 간략하게  1page 이내로 작성함

캡스톤디자인 번호	2021_05팀-박현구
캡스톤디자인 명	농장 일기(Farm Diary)
캡스톤디자인 책임자	박현구

○ 캡스톤디자인 목표

제4차 산업 혁명이 발달함에 따라 농촌에 대한 사람들의 인식이 점점 멀어지고 접할 수 있는 기회도 점차 시간이 지남에 따라 줄어들고 있습니다. 귀농에 대한 정보와 데이터가 많이 없어 귀농 희망자 또는 아직 하고 있는 사람들에게 정보 제공과 서로의 농장을 공유함에 따라 농업 발전에 도움을 주고 온라인 공동체를 형성 할 수 있는 웹 페이지를 제작하는 것이 목표입니다.

○ 캡스톤디자인 내용

웹 페이지에 대한 전체적인 서비스로는 농사 관련 제공 서비스, 농장 공유 서비스, 농산물 구매 및 판매 서비스, 농사 물품 추천 서비스가 있습니다. 정보 제공 서비스는 사람들에게 토지 키우기 쉬운 작물을 추천하고, 농사에 대한 정보 검색을 어려워하는 사용자에게 농사 관련 정보를 제공합니다. 농장 공유 서비스는 농장을 공유하여 농사 팁, 정보 등을 다른 사용자와 공유하는 서비스입니다. 농산물 구매 및 판매 서비스는 생산자는 생산품을 판매하고, 사용자는 원하는 물품을 구매할 수 있는 서비스입니다. 마지막으로 농사 물품 추천 서비스는 농기구, 비료 등 농사 물품 구매를 희망하는 사용자에게 적합한 물품을 추천하는 서비스입니다.

○ 캡스톤디자인 개발에 따른 기대성과

웹 페이지에서 제공하는 서비스들은 사회적, 경제적으로 영향을 줄 것으로 기대됩니다. 온라인 농촌 공동체를 형성하여 서로 도우며 일상을 공유하는 농촌 문화 진흥에 도움이 될 것 이며 단오제, 모내기 행사 등 각종 전통 행사나 체험 행사의 대중화를 이끌어 갈 것으로 예상됩니다. 그리고 농사를 지으며 경험했던 시행착오를 공유하고 함께 문제를 해결하며 농업 기술의 발전에 기여할 것으로 생각됩니다. 마지막으로 농촌에대한 정보들을 제공하고 물품들을 구매 및 판매 할 수 있으므로 농촌 발달에 대한 기대효과가 상승 할 것으로 예상됩니다.

캡스톤디자인 계획서

캡스톤디자인 명 : 농장 일기

캡스톤디자인 책임자 : 인공지능소프트웨어 / 박현구

1. 캡스톤디자인의 필요성

IT기술이 발달함에 따라 농업 기술은 점점 퇴화 되어가고 있습니다. 귀농에 대한 정보와 접할 수 있는 기회도 시간이 지남에 따라 줄어들고 있습니다. 농업에 대한 관심과 기회가 사라져 농업이 우리 역사 속으로 사라질 수 있다는 생각을 했습니다. 그래서 이번 웹 페이지 제작을 통해 농업 발달에 도움을 주고 다시 활성화 시켜 농촌 발달에 대한 기대효과가 상승 될 수 있는 웹 페이지를 제작해보려고 합니다.

2. 캡스톤디자인의 목표 및 내용

가. 캡스톤디자인 디자인 목표

제4차 산업 혁명이 발달함에 따라 농촌에 대한 사람들의 인식이 점점 멀어지고 접할 수 있는 기회도 점차 시간이 지남에 따라 줄어들고 있습니다. 귀농에 대한 정보와 데이터가 많이 없어서 귀농 희망자 또는 아직 하고 있는 사람들에게 정보 제공과 서로의 농장을 공유함에 따라 농업 발전에 도움을 주고 온라인 공동체를 형성 할 수 있는 웹 페이지를 제작하는 것이 목표입니다.

나. 캡스톤디자인 내용

	농사 정보 제공 서비스는 귀농을 처음 접하는 사람들과 농사에 대한 전반적인 지식, 그리고 농사에 대한 정보가 부족한 사람이나 농산물 관련 정보 검색을 어려워하는 사용자에게 농사 관련 정보를 제공하는 페이지입니다.
	농장 공유 서비스는 자신의 농장을 사람들과 공유하여 농사 팁, 정보들을 다른 사람들과 공유하는 페이지입니다. 또한 채팅 기능을 통해 실시간으로 접속한 사람들과 정보를 공유 할 수 있습니다.
	농산물 구매 및 판매 페이지는 자신이 원하는 물품을 구매, 판매하는 페이지입니다. 구매하고 싶은 물품은 장바구니에 추가 가능합니다. (아임포트 API 활용)
	농사 추천 페이지는 농기구, 비료 등 농사 물품 구매를 희망하는 사용자에게 적합한 물품을 추천하고 귀농에 처음 접하는 사람들에게 토지와 키우기 쉬운 작물을 추천하는 페이지입니다. (웹 크롤링 JSOUP 활용)
	궁금한 점을 올리는 게시판 페이지입니다. 댓글 기능을 이용하여 댓글을 달 수 있습니다.
	회원 정보를 수정하는 페이지입니다.

3. 캡스톤디자인의 추진전략 및 체계

Amazon Web Service를 이용해 서버를 엽니다.

2. Mysql 데이터베이스를 사용하여 회원 정보 및 공공데이터를 저장합니다.

3. 웹 페이지의 전반적인 디자인을 구상하고, 구상한 아이디어에 맞춰 디자인 먼저 코딩합니다.

4. 각 페이지 마다 기능을 만듭니다.

5. 작품이 완성되면 담당 교수님께 보여주고 피드백을 받아서 추가적인 수정 및 보완 또는 문제점들을 적절하게 조치한다.

6. 작품이 완성되면 제품을 홍보한다.

4. 캡스톤디자인의 기대효과 및 활용방안

웹 페이지에서 제공하는 서비스들은 사회적, 경제적으로 영향을 줄 것으로 기대됩니다. 온라인 농촌 공동체를 형성하여 서로 도우며 일상을 공유하는 농촌 문화 진흥에 도움이 될 것 이며 단오제, 모내기 행사 등 각종 전통 행사나 체험 행사의 대중화를 이끌어 갈 것으로 예상됩니다. 그리고 농사를 지으며 경험했던 시행착오를 공유하고 함께 문제를 해결하며 농업 기술의 발전에 기여할 것으로 생각됩니다. 마지막으로 농촌에 대한 정보들을 제공하고 물품들을 구매 및 판매 할 수 있으므로 농촌 발달에 대한 기대효과가 상승 할 것으로 예상됩니다.

6. 작업분할 구조도(WBS, Work Breakdown Structure)

6. 참여인력

가. 인력 편성표

						캡스톤디자인 책임자
						( 박현구 )
	UI / 기능 / 기타 준비						UI / 기능 / DB						UI / 기능 / 서버
이휘동						임동근						박현구
UI 제작 / 기능 구현 / 기타 준비						UI 제작 / 기능 구현 / DB 관리						UI 제작 / 기능 구현 / 서버 관리

나. 참여 인력 현황

번호	분 야	학 번	성 명	참여율(%)
1	UI 제작 / 기능 구현 / 서버 관리	16422027	박현구	35%
2	UI 제작 / 기능 구현 / DB 관리	16422041	임동근	35%
3	UI 제작 / 기능 구현 / 기타 준비	2018019237	이휘동	30%

다. 캡스톤디자인 책임자 및 참여인원의 상세 정보

1) 인적사항
	성 명		임동근
	학 번					생년월일
	주 소
	연 락 처		핸드폰				e-mail
	공학 인증		참여				미참여
2) 학적 사항
연도	학적변동 사항
2016.03	청주대학교 컴퓨터정보공학과									입학
2017.01	청주대학교 컴퓨터정보공학과									휴학
2018.02	청주대학교 인공지능소프트웨어학과									재학
3) 현장실습, 인턴쉽, 어학연수, 교육연수 현황
연도(부터～까지)		연수 명			연수기관
2020		창업경진대회			청주대학교						우수상
2020		공공데이터 경진대회			청주대학교						장려상
4) 자격증 현황
자격증 명		발행기관			취득년도
정보처리기사		한국산업인력공단			2021.06.02

1) 인적사항
	성 명		박현구
	학 번					생년월일
	주 소
	연 락 처		핸드폰				e-mail
	공학 인증		참여				미참여
2) 학적 사항
연도	학적변동 사항									비고
2016.03	청주대학교 컴퓨터정보공학과									입학
2017.01	청주대학교 컴퓨터정보공학과									휴학
2018.02	청주대학교 인공지능소프트웨어학과									재학
3) 현장실습, 인턴쉽, 어학연수, 교육연수 현황
연도(부터～까지)		연수 명			연수기관						비 고
2020		창업경진대회			청주대학교						우수상
2020		공공데이터 경진대회			청주대학교						장려상
4) 자격증 현황
자격증 명		발행기관			취득년도						비고
SQLD		한국데이터산업진흥원			2020년 6월 30일
정보처리기사		한국산업인력공단			2021.06.02

1) 인적사항
	성 명		이휘동
	학 번					생년월일
	주 소
	연 락 처		핸드폰				e-mail
	공학 인증		참여				미참여
2) 학적 사항
연도	학적변동 사항									비고
2020.03	청주대학교 인공지능소프트웨어학과									편입
3) 현장실습, 인턴쉽, 어학연수, 교육연수 현황
연도(부터～까지)		연수 명			연수기관						비 고
4) 자격증 현황
자격증 명		발행기관			취득년도						비고

7. 소요장비 및 재료

장비 및 재료 명	규격	수량	용 도	비 고
개인용 컴퓨터 (PC)		3	작업
웹 브라우저 (Chrome)		3	정보 및 자료 검색
한컴오피스 한글 2010		3	문서 작성
Microsoft Power Point		3	PPT 제작
스마트폰		3	팀원 간 연락
AWS(EC2)			서버
Javascript			웹 페이지 제작
JSP			웹 페이지 제작
JQuery			웹 페이지 제작
BootStrap			디자인

8. 캡스톤디자인 추진일정 계획

	세부 추진 내 용				추 진 일 정 (월)
					3	4	5	6
농장 일기	1	서버	AWS	생성
				관리
	2	DB	MySQL	생성
				통합
				유지보수
	3	UI/기능	UI	웹
			기능	웹
			통합

물품명 및 가격	스펙 및 부품	주소
-	-	-
-	-

9. 구매 품목

캡스톤디자인 지도교수 동의서

번호	학번	성명	연락처	비고
1	16422027	박현구	010-3215-7705
2	16422041	임동근	010-6282-0523
3	2018019237	이휘동	010-8331-2027

위의 학생(들)에 대한 캡스톤디자인 지도교수 선임에 다음과 같이 동의합니다.

- 다              음 -

전 공	직 위	지도교수 성명	날 인
인공지능 소프트웨어	교수	노기섭

2021년   03월   25일

청주대학교 인공지능소프트웨어 전공PD 귀하

캡스톤 디자인 결과보고서(結果報告書)

목  차

1. 시스템 구조 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	17
1.1. 시스템 설계 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	17
2. HTML ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.1. 메인페이지 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	18
2.2. 기상 정보 페이지 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	23
2.3. 정보 검색 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	38
2.4. 장 마당 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	42
2.4.1. 리스트 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	42
2.4.2 상세 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	49
2.4.3. 결제 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	57
2.4.4. 등록 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	66
2.5. 마이 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	72
2.6. 만남의 광장 페이지 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	82
2.7 게시판 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	92
2.8. 회원 가입∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	97
2.9. 상단 메뉴바∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	103
2.10. 하단 footer ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	105
3. flask ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	106
3.1. 로그아웃 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	106
3.2 메인 페이지∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	106
3.3. 마이 페이지 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	107
3.3.1. 마이 페이지 – 송장 번호 입력∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	108
3.4. 장 마당 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	109
3.4.1. 장 마당 – 작물 등록∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	109
3.4.2. 장 마당 – 결제∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	110
3.4.3. 장 마당 – 결제 정보∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	111
3.5. 정보 검색∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	112
3.6. 게시판∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	114
3.7. 로그인∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	115
3.8. 회원 가입∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	117
3.9. 만남의 광장∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	118
3.9.1. 만남의 광장 – 농장 등록 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	120
3.9.2. 만남의 광장 – 채팅∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	120
3.9.3. 만남의 광장 – 사진 등록, 사진관 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	121
3.9.4. 만남의 광장 – 개인 농장∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	122
3.10. 날씨 정보∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	123
4. AWS 서버, DB ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	129
4.1. AWS ec2 인스턴스 생성 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	129
4.1.2. putty ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	129
4.1.3. MySql DB ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	130
5. 마무리 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	131
5.1. 향후 추진 계획 ∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙∙	131

1. 시스템 구조

1.1. 시스템 설계

본 프로젝트는 크게 Amazon Web Service 클라우드의 ubuntu 서버를 사용하여 서버를 구축하였습니다.

ubuntu 서버 내에 mysql database를 설치하여 데이터를 운용 및 관리하였고, Amazon Web Service ec2를 사용하여 flask 웹 서버를 구동 시켜 서버를 운영하였습니다.

flask 프레임워크에 @app.route() 데코르레이더 함수를 통해서 라우팅을 실행 하였고,

라우팅 방법으로는 정적 라우팅을 사용하였습니다. 각 페이지에 사용될 HTML파일을 생성하고 해당 HTML파일을 flask 라우팅을 이용하여 기능을 구현하였습니다.

2. HTML

2.1. 메인 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<!-- 슬라이드 배너 css -->

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.min.css">

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- 무료 폰트 -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- media screen 메뉴바 CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<!-- 하단 footer CSS -->

<link rel="stylesheet" href="/static/css/footer.css">

<!-- 슬라이드 배너 CSS -->

<link rel="stylesheet" href="/static/css/banner.css">

<!-- 최신 상품  CSS -->

<link rel="stylesheet" href="/static/css/regist_view.css">

<!-- 메인 페이지 비디오 CSS -->

<link rel="stylesheet" href="/static/css/main_video.css">

<!--자바 스크립트-->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/baguetteBox.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

</head>

<body>

<!-- 네비게이션바 -->

{% include "nav_bar.html" %}

<!-- 슬라이드바 -->

<div class="owl-carousel owl-theme">

<div class="slide slide-4">

<div class="center_align_re slide-content">

<a href="/"><h1>Farm Diary</h1></a>

<p>농장 일기 사이트에 오신걸 환영합니다.</p>

</div>

</div>

<div class="slide slide-1">

<div class="center_align_re slide-content">

<a href="{{url_for('fruitinform')}}"><h1>정보 마당 </h1></a>

<p>각종 작물에 대한 정보를 확인해보세요</p>

</div>

</div>

<div class="slide slide-2">

<div class="center_align_re slide-content">

<a href="{{url_for('fruitmarket')}}"><h1>장 마당</h1></a>

<p>저렴한 작물들을 구입해 보세요</p>

</div>

</div>

<div class="slide slide-3">

<div class="center_align_re slide-content">

<a href="{{url_for('meeting')}}"><h1>만남의 광장</h1></a>

<p>다른 사람들과 농장을 공유해보세요</p>

</div>

</div>

</div>

<!-- 슬라이드 배너 작동  -->

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

<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>

<script>

$(document).ready(function () {

$(".owl-carousel").owlCarousel({

items:1,

loop:true,

nav:true,

dots:true,

autoplay:true,

autoplaySpeed:1000,

smartSpeed:1500,

autoplayHoverPause:true,

});

});

</script>

<!-- 농장 소개  -->

<div class="box-add-products">

<div class="col-lg-12">

<div class="title-all text-center">

<h1 style="font-size:40px;">Welcome Farm Diary</h1>

<p style="margin-bottom:70px;">농장일기 사이트에 오신걸 환영합니다.</p>

</div>

</div>

<div class="container">

<div class="row">

<div class="col-lg-6 col-md-6 col-sm-12">

<video autoplay controls loop>

<source src="/static/videos/nature.mp4" type="video/mp4">

</video>

</div>

<div class="col-lg-6 col-md-6 col-sm-12" style="margin-top:50px;">

<span>저희 사이트는 농업 정보와 과일,작물 정보를 제공하고, 건강한 작물을 구입할 수 있습니다.

정보를 제공함으로써 농업에 대한 지식을 습득할 수 있으며, 농장 공유를 통해 사람들과 유대감을 쌓아보시기 바랍니다. 즐거운 시간 되시기 바랍니다.

</span>

</br></br>

<p>Our site provides agricultural information, fruit and crop information, and you can purchase healthy crops.

By providing information, you can gain knowledge of agriculture, and build bonds with people through farm sharing. I hope you'll have a nice time.

</p>

</div>

</div>

</div>

</div>

<!-- 메인 페이지 리스트 제목 -->

<div class="row">

<div class="col-lg-12">

<div class="title-all text-center">

<h1 style="margin-top:50px;">Monthly Fruits & Crops</h1>

<p>이달의 농사 짓기 좋은 과일과 작물을 확인해보세요!</p>

</div>

</div>

</div>

<!-- 추천 마당 (봄, 여름 , 가을 ,겨울) -->

<div class="categories-shop">

<div class="container">

<div class="row">

<div class="col-lg-4 col-md-4 col-sm-12 col-xs-12">

<div class="shop-cat-box">

{% if (month==3) or (month==4) or (month==5) %}

<img style="height:300px;" class="img-fluid" src="/static/images/spring.jpg" alt="" />

<a class="btn hvr-hover" href="/recommend">봄의 추천 작물</a>

{% elif (month==6) or (month==7) or (month==8)%}

<img style="height:300px;" class="img-fluid" src="/static/images/summer.jpg" alt="" />

<a class="btn hvr-hover" href="/recommend">여름의 추천 작물</a>

{% elif (month==9) or (month==10) or (month==11)%}

<img style="height:300px;" class="img-fluid" src="/static/images/fall.jpg" alt="" />

<a class="btn hvr-hover" href="/recommend">가을의 추천 작물</a>

{% elif (month==12) or (month==1) or (month==2)%}

<img style="height:300px;" class="img-fluid" src="/static/images/winter.jpg" alt="" />

<a class="btn hvr-hover" href="/recommend">겨울의 추천 작물</a>

{% endif %}

</div>

</div>

<div class="col-lg-4 col-md-4 col-sm-12 col-xs-12">

<div class="shop-cat-box">

<img style="height:300px;" class="img-fluid" src="./static/images/product-3.jpg" alt="" />

<a class="btn hvr-hover" href="/meeting">만남의 광장 바로가기</a>

</div>

</div>

<div class="col-lg-4 col-md-4 col-sm-12 col-xs-12">

<div class="shop-cat-box">

<img style="height:300px;" class="img-fluid" src="./static/images/weather.jpg" alt="" />

<a class="btn hvr-hover" href="/weathertest">날씨 정보</a>

</div>

</div>

</div>

</div>

</div>

<div class="container" style="margin-bottom:60px;">

<div class="row">

<div class="col-lg-12">

<div class="title-all text-center">

<h1>Fruits & Vegetables</h1>

<p>저렴한 과일과 작물을 구입해보세요!</p>

</div>

</div>

</div>

</div>

<!-- 가장 최근에 등록한 상품들  -->

<div class="regist_wrap">

{% for product in pro %}

<div class="regist_wrap2">

<a href="/product_view{{product[0]}}"> <img src="{{ url_for('static',filename='uploads/'+product[9])}}"></a>

<div style="width:250px;margin:auto;">

<h4 style="margin-top:20px;font-size:20px;font-weight:800;">{{product[3]}}</h3>

<h4 style="font-weight:500;font-size:18px;">{{product[4]}}&nbsp;원</h4>

</div>

</div>

{% endfor %}

</div>

<!-- 하단 footer -->

{% include "footer.html" %}

<!-- 위로 올라가는 버튼 -->

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

css파일은 외부 스타일 시트 방법으로 css를 적용하였고, 메인페이지의 슬라이드 배너는

owl-carousel 플러그를 사용하여 슬라이드 배너를 제작하였습니다. 메인페이지에서는 사용자의 편의성을 생각하여 각 페이지의 기능에 대한 페이지이동 ui를 제작하였습니다.

2.2. 기상 정보 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Weather</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/weatherfont.css">

<link rel="stylesheet" href="/static/css/weatherbtn.css">

<link href="/static/css/jquery-nice-number.css" rel="stylesheet">

<link rel="stylesheet" href="/static/css/korea.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

<script type="text/javascript" src="/static/js/d3.min.js"></script>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Weather</p>

<p class="focus-in-expand-fwd2">날씨 정보를 확인하세요</p>

</div>

</div>

<!-- End All Title Box -->

<div class="dg-map dg-map-in" style="display:inline-block;margin-left:60px;border-radius:8%">

<svg x="0" y="0" width="500" height="800" viewBox="0 0 800 1200">

위도, 경도 분석 생략..

</svg>

</div>

<div style="display:inline-block;vertical-align:top;margin-top:60px;margin-left:30px;max-height:100%;border-radius:8%">

<form method="post" action="/weathertest">

<select name="local" style="width:200px;">

<option value="">지역을 선택하세요</option>

<option value="seoul">서울,경기,인천</option>

<option value="busan">부산,울산,대구,경상도</option>

<option value="gwangju">광주,전라도</option>

<option value="daejun">대전,세종,충청도</option>

<option value="gwanone">강원도</option>

<option value="jeju">제주도</option>

</select>

<button class="w_btn" >검색</button>

</form>

<table style="border:none;width:300px;margin-top:20px;">

<thead>

{% if w_list | length == 0 %}

{% else %}

<tr>

<th style="background-color: #0066CC; text-align: center; width:80px;color:white;font-weight:800px;">지역</th>

<th style="background-color: #0066CC; text-align: center; width:80px;color:white;font-weight:800px;">기온</th>

<th style="background-color: #0066CC; text-align: center; width:80px;color:white;font-weight:800px;">습도</th>

</tr>

{% endif %}

</thead>

<tbody>

{% if w_list | length == 0 %}

<tr>

<td style="border:1px solid lightgrey;width:300px;height:400px;text-align:center;font-size:18px;">원하는 지역을 선택해주세요</td>

</tr>

{% else %}

{% for weather in w_list %}

<tr>

<td style="border: 1px solid lightgrey;height:3px;">{{weather[0]}}</td>

<td style="border: 1px solid lightgrey;height:3px;">{{weather[1]}}℃</td>

<td style="border: 1px solid lightgrey;height:3px;">{{weather[2]}}%</td>

</tr>

{% endfor %}

{% endif %}

</tbody>

</table>

</div>

<div id="detail_weather" style="display:inline-block;vertical-align:top;margin-top:20px;margin-left:30px;">

<table style="margin-top:40px;width:400px;border:2px solid lightgrey;">

<thead>

<tr>

<th style="text-align:center;font-size:22px;border:3px solid white;color:white;background-color:#0066CC">상세 날씨 정보</th>

</tr>

</thead>

<tbody>

<tr>

<td style="text-align:center;">

<img src="" id="wimg" width="120px" height="120px" style="vertical-align:center;">

</td>

</tr>

<tr>

<td id="temp" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

<tr>

<td id="weather" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

<tr>

<td id="name" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

<tr>

<td id="humid" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

<tr>

<td id="wind" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

<tr>

<td id="cloud" style="background-color:#0066CC;border:3px solid white;font-size:22px;font-weight:800px;color:white;padding-left:15px;"></td>

</tr>

</tbody>

</table>

</div>

<script>

$('#detail_weather').hide();

$(".dg-map svg").mouseover(function(event) {

var _path = event.target;

var city_name = _path.id;

var new_p = document.createElement('p');

var province = $(_path).parent()[0].id;

d3.select(_path).style("fill", "#cbc3ac");

//console.log(city_name);

}).mouseout(function(event) {

var _path = event.target;

d3.select(_path).style("fill", "#fff");

});

$(function() {

$('#seoul').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Seoul&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

var URL2 = 'http://api.openweathermap.org/data/2.5/forecast?q=Seoul&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#gyeonggi').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Gyeonggi-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#gangwon').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Gangwon-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#chungbuk').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Chungcheongbuk-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#chungnam').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Chungcheongnam-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#jeju').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Jeju-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#daejeon').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Daejeon&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#daegu').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Daegu&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#busan').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Busan&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#ulsan').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Ulsan&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#gwangju').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Gwangju&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#jeonbuk').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Jeonju&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#incheon').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Incheon&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#gyeongbuk').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Gyeongsangbuk-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#gyeongnam').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Gyeongsangnam-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

$('#jeonnam').click(function() {

$('#detail_weather').fadeIn();

var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Jeollanam-do&appid=1f4ec6e728cbb33db03f67d0a9fa2642'

$.ajax({

url: URL,

dataType: "json",

type: "GET",

async: "false",

success: function(resp) {

<!-- console.log(resp); -->

var temp = Math.ceil(resp.main.temp-273.15);

var humid = resp.main.humidity;

var weather = resp.weather[0].main;

var detail_w = resp.weather[0].description;

var w_img = resp.weather[0].icon

var img_url = "http://openweathermap.org/img/w/" + w_img + ".png";

$('#wimg').attr('src', img_url);

var wind = Math.ceil(resp.wind.speed);

var local = resp.sys.country;

var name = resp.name

var cloud = resp.clouds.all

document.getElementById('temp').innerHTML = "온도 : " +temp+"℃"

document.getElementById('humid').innerHTML = "습도" + ":" +humid+"%";

document.getElementById('weather').innerHTML = "날씨 : " +weather;

document.getElementById('wimg').innerHTML = img_url;

document.getElementById('wind').innerHTML = "바람 : " +wind+"㎧";

document.getElementById('name').innerHTML = "지역 : " +name;

document.getElementById('cloud').innerHTML = "구름 : " +cloud;

}

})

});

});

/*가맹점 지도 색칠*/

$(document).ready(function(){

var mapCondition = '<?=$stx?>';

if (mapCondition == '세종특별자치시') {

$('#sejong').css("fill", "sky");

}else if (mapCondition == '충청남도') {

$('#chungnam').css("fill", "#cbc3ac");

}else if (mapCondition =='제주특별자치도') {

$('#jeju').css("fill", "#cbc3ac");

}else if (mapCondition =='경상남도') {

$('#gyeongnam').css("fill", "#cbc3ac");

}else if (mapCondition == '경상북도') {

$('#gyeongbuk').css("fill", "#cbc3ac");

}else if (mapCondition =='전라북도') {

$('#jeonbuk').css("fill", "#cbc3ac");

}else if (mapCondition =='충청북도') {

$('#chungbuk').css("fill", "#cbc3ac");

}else if (mapCondition =='경기도') {

$('#gyeonggi').css("fill", "#cbc3ac");

}else if (mapCondition == '전라남도') {

$('#jeonnam').css("fill", "#cbc3ac");

}else if (mapCondition =='울산광역시') {

$('#ulsan').css("fill", "#cbc3ac");

}else if (mapCondition =='부산광역시') {

$('#busan').css("fill", "#cbc3ac");

}else if (mapCondition == '대구광역시') {

$('#daegu').css("fill", "#cbc3ac");

}else if (mapCondition =='대전광역시') {

$('#daejeon').css("fill", "#cbc3ac");

}else if (mapCondition =='인천광역시') {

$('#incheon').css("fill", "#cbc3ac");

}else if (mapCondition =='서울특별시') {

$('#seoul').css("fill", "#cbc3ac");

}else if (mapCondition =='광주광역시') {

$('#gwangju').css("fill", "#cbc3ac");

}

})

</script>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 기상 정보를 제공하는 페이지로 세부적인 지역 날씨는 selenium, beautifulsoup4를 사용하여 크롤링 하였습니다. 옆에 지도는 위도와 경도를 분석하면 json파일 형식으로 저장됩니다.

파싱된 json파일의 위도와 경도를 svg태그 (좌표를 그리는 태그) 내부에 삽입하여 지도를 제작하였습니다. 해당 지도의 지역을 클릭하면 지역의 날씨 정보를 확인할 수 있는데 세부적인 날씨 정보는

openweathermap api를 사용하여 날씨 데이터를 수집하였습니다.

2.3. 정보 검색 페이지

<!DOCTYPE html>

<html lang="en">

<!-- Basic -->

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>fruitinform</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- media screen 메뉴바 CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<!--  footer CSS -->

<link rel="stylesheet" href="/static/css/footer.css">

<!-- search CSS -->

<link rel="stylesheet" href="/static/css/search.css">

<!-- video view CSS -->

<link rel="stylesheet" href="/static/css/video-view.css">

<!-- 중간 메뉴바 -->

<link rel="stylesheet" href="/static/css/view.css">

<!-- 중간 배너 CSS -->

<link rel="stylesheet" href="/static/css/font.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<!-- <script src="/static/js/baguetteBox.min.js"></script> -->

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<!-- <script src="/static/js/custom.js"></script> -->

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

</head>

<body>

<!-- 네비게이션 바 -->

{% include "nav_bar.html" %}

<!-- 검색 title -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Inform farm</p>

<p class="focus-in-expand-fwd2">검색을 통해 농업에 대한 정보를 얻어보세요</p>

</div>

</div>

<!-- 중간 메뉴바 -->

<div class="menu" style="text-align:center;">

<ul>

<li><a href="/fruitinform">정보 검색</a></li>

<li><a href="/searchvideo">동영상 검색</a></li>

</ul>

</div>

<!-- 검색 -->

<div class="col-lg-12" style="margin-top:50px;">

<div class="title-all text-center">

<h1>Search</h1>

<p>동영상을 통해 정보를 얻어보세요.</p>

</div>

</div>

<form method="POST" action="/video_view">

<div class="box">

<div class="container-1">

<input type="search" id="search" placeholder="Search..." name="keyword">

<button style="font-size:38px; background-color:#2b303b;color:white;border:none"><i class="fas fa-search"></i></button>

</div>

</div>

</form>

<hr style="width:90%;color:grey;margin-top:30px;margin-bottom:30px;tex-align:center"></hr>

<h2 style="text-align:center;font-weight:800;font-size:28px;margin-top:30px;margin-bottom:30px;">{{keyword}}에 대한 검색 결과입니다.</h2>

<!-- 검색 결과 -->

<div class="video_wrap">

{% for i in range(0, title_list|length) %}

<div class="video_wrap2">

{{src_list[i] | safe}}

<div style="height:30px">

<h2 style="font-size:20px;font-weight:800;margin-top:20px;">제목 : {{title_list[i]}}</h2>

</div>

<div style="font-size:18px;margin-top:20px;margin-bottom:50px;">

조회수 : {{view_list[i]}}

</div>

</div>

{% endfor %}

</div>

<!-- 하단 footer -->

{% include "footer.html" %}

<!-- 위로 이동 버튼 -->

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 정보를 검색할 수 있는 페이지로, selenium과 bealutifulsoup4를 활용하여 사용자가 검색을 하면 나무위키, 유튜브를 통해 원하는 정보를 제공하는 페이지입니다.

2.4. 장 마당 상품 리스트 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Cropmarket</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/font.css">

<link rel="stylesheet" href="/static/css/view.css">

<link rel="stylesheet" href="/static/css/regist_view.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Fruit market</p>

<p class="focus-in-expand-fwd2">직접 농사한 작물을 저렴한 가격에 구매해보세요</p>

</div>

</div>

<!-- End All Title Box -->

<div class="menu" style="text-align:center;">

<ul>

<li><a href="/fruitmarket">과일</a></li>

<li><a href="/cropmarket">작물</a></li>

<li><a href="/product_regist">과일, 작물 등록</a></li>

</ul>

</div>

<h2 style="text-align:center;margin-top:60px;margin-bottom:80px; font-size:35px;"><strong>Product</strong></h2>

<div class="regist_wrap">

{% if product_list | length == 0 %}

등록된 상품이 없습니다.

{% else %}

{% for product in product_list %}

<div class="regist_wrap2">

<a href="/product_view{{product[0]}}"> <img src="{{ url_for('static',filename='uploads/'+product[9])}}"></a>

<div style="width:250px;margin:auto;">

<h4 style="margin-top:20px;font-size:20px;font-weight:800;">{{product[3]}}</h3>

<h4 style="font-weight:500;font-size:18px;">{{product[4]}}&nbsp;원</h4>

</div>

</div>

{% endfor %}

{% endif %}

</div>

<!-- Start Shop Page  -->

<div class="shop-box-inner">

<div class="container">

<div class="row">

<div class="col-xl-9 col-lg-9 col-sm-12 col-xs-12 shop-content-right">

<div class="right-product-box">

<div class="product-categorie-box">

<div class="tab-content">

<div role="tabpanel" class="tab-pane fade show active" id="grid-view">

<div class="row">

</div>

</div>

<div role="tabpanel" class="tab-pane fade" id="list-view">

<div class="list-view-box">

<div class="row">

<div class="col-sm-6 col-md-6 col-lg-4 col-xl-4">

<div class="products-single fix">

<div class="box-img-hover">

<div class="type-lb">

<p class="new">New</p>

</div>

<img src="./static/images/img-pro-01.jpg" class="img-fluid" alt="Image">

<div class="mask-icon">

<ul>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="View"><i class="fas fa-eye"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Compare"><i class="fas fa-sync-alt"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Add to Wishlist"><i class="far fa-heart"></i></a></li>

</ul>

</div>

</div>

</div>

</div>

</div>

</div>

<div class="list-view-box">

<div class="row">

<div class="col-sm-6 col-md-6 col-lg-4 col-xl-4">

<div class="products-single fix">

<div class="box-img-hover">

<div class="type-lb">

<p class="sale">Sale</p>

</div>

<img src="./static/images/img-pro-02.jpg" class="img-fluid" alt="Image">

<div class="mask-icon">

<ul>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="View"><i class="fas fa-eye"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Compare"><i class="fas fa-sync-alt"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Add to Wishlist"><i class="far fa-heart"></i></a></li>

</ul>

</div>

</div>

</div>

</div>

]

</div>

</div>

<div class="list-view-box">

<div class="row">

<div class="col-sm-6 col-md-6 col-lg-4 col-xl-4">

<div class="products-single fix">

<div class="box-img-hover">

<div class="type-lb">

<p class="sale">Sale</p>

</div>

<img src="./static/images/img-pro-03.jpg" class="img-fluid" alt="Image">

<div class="mask-icon">

<ul>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="View"><i class="fas fa-eye"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Compare"><i class="fas fa-sync-alt"></i></a></li>

<li><a href="#" data-toggle="tooltip" data-placement="right" title="Add to Wishlist"><i class="far fa-heart"></i></a></li>

</ul>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

</div>

<!-- End Shop Page -->

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 사용자가 등록한 작물, 과일을 보여주는 페이지입니다.

2.4.1 장 마당 – 상세 페이지

<!DOCTYPE html> <html lang="en"> <!-- Basic --> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Mobile Metas --> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Site Metas --> <title>Product view</title> <meta name="keywords" content=""> <meta name="description" content=""> <meta name="author" content=""> <!-- Site Icons --> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="/static/css/bootstrap.min.css"> <!-- Site CSS --> <link rel="stylesheet" href="/static/css/style.css"> <!-- Responsive CSS --> <link rel="stylesheet" href="/static/css/responsive.css"> <link rel="stylesheet" href="/static/css/footer.css"> <link rel="stylesheet" href="/static/css/product_view.css"> <link rel="stylesheet" href="/static/css/view.css"> <link rel="stylesheet" href="/static/css/regist_view.css"> <link rel="stylesheet" href="/static/css/font.css"> <link rel="stylesheet" href="/static/css/barbar.css"> <link href="/static/css/jquery-nice-number.css" rel="stylesheet"> <!-- ALL JS FILES --> <script src="/static/js/jquery-3.6.0.min.js"></script> <script src="/static/js/jquery-nice-number.js"></script> <script src="/static/js/popper.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> <script src="/static/js/jquery.superslides.min.js"></script> <script src="/static/js/bootstrap-select.js"></script> <script src="/static/js/inewsticker.js"></script> <script src="/static/js/bootsnav.js"></script> <script src="/static/js/images-loded.min.js"></script> <script src="/static/js/isotope.min.js"></script> <script src="/static/js/owl.carousel.min.js"></script> <script src="/static/js/jquery-ui.js"></script> <script src="/static/js/jquery.nicescroll.min.js"></script> <script src="/static/js/form-validator.min.js"></script> <script src="/static/js/contact-form-script.js"></script> <script src="/static/js/Login.js"></script> <script src="/static/js/signup.js"></script> <script> $(window).on('load', function(){ $('#count[type="number"]').niceNumber(); }); </script> <script> $(function() { $('#button1').click( function() { if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) { $(this).html('<i class="fas fa-chevron-up"></i>'); $('.b').slideDown(); } else { $(this).html('<i class="fas fa-chevron-down"></i>'); $('.b').slideUp(); } }); }); </script> <script> $(function() { $('#button2').click( function() { if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) { $(this).html('<i class="fas fa-chevron-up"></i>'); $('.d').slideDown(); } else { $(this).html('<i class="fas fa-chevron-down"></i>'); $('.d').slideUp(); } }); }); </script> <style> .b { display: none; height: 500px; width:1000px;margin:auto;text-align:center; background-color: white;border:1px solid lightgrey; } .d { display: none; max-height:100%; overflow:auto;width:1000px;margin:auto;text-align:center; background-color: white;border:none; } </style> </head> <body> {% include "nav_bar.html" %} <!-- 네비케이션바 --> <!-- Start Top Search --> <div class="top-search"> <div class="container"> <div class="input-group"> <span class="input-group-addon"><i class="fa fa-search"></i></span> <input type="text" class="form-control" placeholder="Search"> <span class="input-group-addon close-search"><i class="fa fa-times"></i></span> </div> </div> </div> <!-- End Top Search --> <!-- Start All Title Box --> <div style="width:100%;height:400px;background-color:black;"> <div class="back_img"> <p class="focus-in-expand-fwd" style="padding-top:120px;">Fruit market</p> <p class="focus-in-expand-fwd2">직접 농사한 작물을 저렴한 가격에 구매해보세요</p> </div> </div> <!-- End All Title Box --> <div class="menu" style="text-align:center;"> <ul> <li><a href="/fruitmarket">과일</a></li> <li><a href="/cropmarket">작물</a></li> <li><a href="/product_regist">과일, 작물 등록</a></li> </ul> </div> <!-- <img src="/static/images/apple.jpg" style="width:300px; height:300px;" class="focus-in-expand-fwd"> --> {% for view in product %} <div class="row" style="margin-top:50px;height:700px;"> <div class="col-sm-6"> <div class="item-image" style="text-align:center;"> <img style="width:700px;height:600px;" id="item_image" src="{{ url_for('static',filename='uploads/'+view[9])}}" alt="" title=""> </div> <div class="h30 visible-xs"></div> </div> <div class="col-sm-6"> <h1>{{view[3]}}</h1> <form method="post" action="/purchase{{view[0]}}"> <table class="div-table table"> <tbody> <tr> <tr><th scope="row">종류</th><td style="padding-right:200px;">{{view[2]}}</td></tr> <tr><th scope="row">판매가격</th><td>{{view[4]}}원</td></tr> <tr><th>배송비결제</th><td>주문시 결제</td></tr> <tr> <th>수량</th> <td> <input style="float:left;"type='number' name='count' id='count' class="nice-number" value='0'/> <!-- <input style="float:left;"type='button' onclick='count("minus")' value='-'/> --> <!-- <span style="float:left; border:1px solid black;padding-left:20px;padding-right:20px"> --> <!-- <div name='result' id='result'>1</div> --> <!-- </span> --> <!-- <input type='button' onclick='count("plus")' value='+'/> --> </td> </tr> </tbody> </table> <!-- 총 구매액 --> <div style="text-align:center; padding:12px 0;"> <ul class="item-buy-btn"> <input type="submit" style="width:500px;text-align:center;margin:auto;" value="바로구매" class="btn btn-green btn-block"> </ul> </div> </form> </div> </div> <hr style="border:1p solid lightgrey;width:90%;"></hr> <div style="margin-left:100px;height:200px;"> {{view[6]}} </div> <hr style="width:90%;"></hr> {% endfor %} <h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">후기 작성하기</h2> <div style="margin-top:50px;text-align:center;"> <button id='button1' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button> <div class="b"> <form method="post" action="/proComment_write{{pro_num}}" enctype="multipart/form-data"> <div style="margin-top:50px;margin-bottom:30px;float:left;padding-left:100px;"> <img id="user_image" src="#" alt="" style="height:100px; width:100px;"> <input accept=".jpg" onchange="PreviewImage();" type="file" id="user_profile_img" name="img_name" > </div> <p><textarea style="height:200px; width:800px;border:1px solid lightgrey;"placeholder="후기쓰기.."title="content" name="content"></textarea></p> <br> <div> <button>후기 작성</button> </div> </form> </div> </div> </div> <h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">후기 확인</h2> <div style="margin-top:50px;text-align:center;margin-bottom:30px;"> <button id='button2' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button> <div class="d"> <table style="margin:auto;margin-top:50px;width:600px;margin-bottom:30px;"> {% if comment | length == 0 %} <tr> <td style="border:none">등록된 댓글이 없습니다.</td> </tr> {% else %} {%for list in comment%} <tr style="border-bottom:1px solid lightgrey;"> <td><img style="width:80px;height:80px;" src="{{ url_for('static',filename='comment/'+list[3])}}" alt="" title=""></td> <td style="width:150px;height:30px;vertical-align:top;"><strong>{{list[1]}}</strong></td> <td style="height:50px;vertical-align:top;width:500px;">{{list[2]}}</td> <td style="width:140px;vertical-align:top;">{{list[4]}}</td> </tr> {% endfor %} {% endif %} </table> </div> </div> {% include "footer.html" %} <a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a> </body> </html>
해당 페이지는 장 마당 리스트 페이지 있는 상품의 상세 정보를 확인 할 수 있는 페이지입니다. 과일, 작물에 대한 후기 및 작성된 작성된 후기를 확인할 수 있습니다.

2.4.2. 장 마당 – 결제 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Purchase</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/view.css">

<link rel="stylesheet" href="/static/css/font.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

<script src="https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>

<script type="text/javascript"

src="https://code.jquery.com/jquery-1.12.4.min.js"></script>

<script type="text/javascript"

src="https://cdn.iamport.kr/js/iamport.payment-1.1.5.js"></script>

<script>

function sample4_execDaumPostcode() {

new daum.Postcode({

oncomplete: function(data) {

// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.

// 도로명 주소의 노출 규칙에 따라 주소를 표시한다.

// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.

var roadAddr = data.roadAddress; // 도로명 주소 변수

var extraRoadAddr = ''; // 참고 항목 변수

// 법정동명이 있을 경우 추가한다. (법정리는 제외)

// 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.

if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){

extraRoadAddr += data.bname;

}

// 건물명이 있고, 공동주택일 경우 추가한다.

if(data.buildingName !== '' && data.apartment === 'Y'){

extraRoadAddr += (extraRoadAddr !== '' ? ', ' + data.buildingName : data.buildingName);

}

// 표시할 참고항목이 있을 경우, 괄호까지 추가한 최종 문자열을 만든다.

if(extraRoadAddr !== ''){

extraRoadAddr = ' (' + extraRoadAddr + ')';

}

// 우편번호와 주소 정보를 해당 필드에 넣는다.

document.getElementById('sample4_postcode').value = data.zonecode;

document.getElementById("sample4_roadAddress").value = roadAddr;

document.getElementById("sample4_jibunAddress").value = data.jibunAddress;

// 참고항목 문자열이 있을 경우 해당 필드에 넣는다.

if(roadAddr !== ''){

document.getElementById("sample4_extraAddress").value = extraRoadAddr;

} else {

document.getElementById("sample4_extraAddress").value = '';

}

var guideTextBox = document.getElementById("guide");

// 사용자가 '선택 안함'을 클릭한 경우, 예상 주소라는 표시를 해준다.

if(data.autoRoadAddress) {

var expRoadAddr = data.autoRoadAddress + extraRoadAddr;

guideTextBox.innerHTML = '(예상 도로명 주소 : ' + expRoadAddr + ')';

guideTextBox.style.display = 'block';

} else if(data.autoJibunAddress) {

var expJibunAddr = data.autoJibunAddress;

guideTextBox.innerHTML = '(예상 지번 주소 : ' + expJibunAddr + ')';

guideTextBox.style.display = 'block';

} else {

guideTextBox.innerHTML = '';

guideTextBox.style.display = 'none';

}

}

}).open();

}

</script>

<style>

.pur_btn {

border:none;

background-color:skyblue;

color:white;

font-size:20px;

font-weight:800px;

}

.pur_btn:hover {

background-color:blue;

transition:0.5s;

}

</style>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Fruitmarket</p>

<p class="focus-in-expand-fwd2">직접 농사한 작물을 저렴한 가격에 구매해보세요</p>

</div>

</div>

<div class="menu" style="text-align:center;">

<ul>

<li><a href="/fruitmarket">과일</a></li>

<li><a href="/cropmarket">작물</a></li>

<li><a href="/product_regist">과일, 작물 등록</a></li>

</ul>

</div>

<h2 style="text-align:center;margin-top:60px;font-weight:800;margin-bottom:30px;">Product Info</h2>

<table style="border:1px solid lightgrey; margin-top:50px;margin:auto;">

<thead>

<tr style="border-bottom:1px solid lightgrey;">

<th>상품 정보</th>

<th>수량</th>

<th>주문 금액</th>

<th>보유포인트</th>

</tr>

</thead>

{% for list in detail %}

<tbody>

<tr>

<td style="height:100px;">

<img style="width:80px;height:80px;" src="{{ url_for('static',filename='uploads/'+list[9])}}">

{{list[3]}}

</td>

<td>{{count}}개</td>

<td>{{count * list[4]}}원</td>

<td>{{point}}원</td>

</tr>

{% endfor %}

</tbody>

</table>

<h2 style="text-align:center;margin-top:60px;font-weight:800;margin-bottom:60px">Recipient Info</h2>

<table style="border: 1px solid lightgrey;margin:auto;">

<tr>

<td style="font-weight:800;padding-left:10px;">수령인</td>

<td style="padding-left:20px;">{{name}}</td>

</tr>

<tr style="border-top:1px solid lightgrey;">

<td style="font-weight:800;padding-left:10px;">전화 번호</td>

<td style="padding-left:20px;">{{phone}}</td>

<tr>

<tr style="border-top:1px solid lightgrey;">

<td style="font-weight:800;padding-left:10px;">배송지 정보</td>

<td style="height:200px;padding-left:20px;">

<div>

<input type="text" id="sample4_postcode" placeholder="우편번호">

<input type="button" onclick="sample4_execDaumPostcode()" value="우편번호 찾기"><br>

<input type="text" id="sample4_roadAddress" placeholder="도로명주소">

<input type="text" id="sample4_jibunAddress" placeholder="지번주소">

<span id="guide" style="color:#999;display:none"></span>

<input type="text" id="sample4_detailAddress" placeholder="상세주소">

<input type="text" id="sample4_extraAddress" placeholder="참고항목">

</div>

</td>

</tr>

</table>

<div style="text-align:center;margin-top:50px;margin-bottom:50px;">

<button id="check_module" type="submit" class="pur_btn">바로결제</button>

<script>

$("#check_module").click(function() {

if($('#sample4_postcode').val()!="" && $('#sample4_roadAddress').val()!=""  && $('#sample4_jibunAddress').val()!="" && $('#sample4_detailAddress').val()!=""){

var IMP = window.IMP; // 생략가능

IMP.init('imp94991652');

IMP.request_pay({

pg : 'kakaopay',

pay_method : 'card',

merchant_uid : 'merchant_' + new Date().getTime(),

name : '{{detail[0][3]}}',

amount : {{count * detail[0][4]}} //count*{{detail[0][4]}}

}, function(rsp) {

console.log(rsp);

if (rsp.success) {

var msg = '결제가 완료되었습니다.';

alert(msg);

$.ajax({

url:'/test2',

data:{'postcode' : $('#sample4_postcode').val(),

'roadAddress' : $('#sample4_roadAddress').val(),

'jibunAddress' : $('#sample4_jibunAddress').val(),

'detailAddress' : $('#sample4_detailAddress').val(),

'extraAddress' : $('#sample4_extraAddress').val(),

'productNum' : '{{detail[0][0]}}',

'count':{{count}} ,

'price':{{count * detail[0][4]}},

'buyer':'{{name}}',

'seller_id':'{{detail[0][1]}}'

},

method:'POST',

dataType:'json',

success:function(result){

alert("성공");

},error:function(err){console.log("err",err)}

});

document.location.href= '/mypage'

} else {

var msg = '결제에 실패하였습니다.';

msg += '에러내용 : ' + rsp.error_msg;

alert(msg);

}

});

}

else{

alert("주소를 입력해주세요.");}

});

</script>

<button  id="check_module2" type="submit" class="pur_btn">포인트결제</button>

<script>

$("#check_module2").click(function() {

if($('#sample4_postcode').val()!="" && $('#sample4_roadAddress').val()!=""  && $('#sample4_jibunAddress').val()!="" && $('#sample4_detailAddress').val()!=""){

if({{point}}>{{count * detail[0][4]}}){

alert('결제완료');

$.ajax({

url:'/test3',

data:{

'price':'{{count * detail[0][4]}}',

'point':'{{point}}'

},

method:'POST',

dataType:'json',

success:function(result){

alert("성공");

},error:function(err){console.log("err",err)}

});

}

else{

alert('포인트가 부족합니다.');}

}

else{

alert("주소를 입력해주세요.");}

});

</script>

</div>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 사용자가 구매하고자하는 상품에 대한 결제 페이지입니다. 주소 입력은 daum의 주소 api를 사용하였고, 결제 방식은 아임포트를 활용하여 카카오 페이를 사용하였습니다.

2.4.3. 장 마당 – 상품 등록

<!DOCTYPE html>

<html lang="en">

<!-- Basic -->

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Product regist</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/regist.css">

<link rel="stylesheet" href="/static/css/font.css">

<link rel="stylesheet" href="/static/css/view.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="./static/js/bootstrap.min.js"></script>

<!-- ALL PLUGINS -->

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

<script>

function PreviewImage() {

// 파일리더 생성

var preview = new FileReader();

preview.onload = function (e) {

// img id 값

document.getElementById("user_image").src = e.target.result;

};

// input id 값

preview.readAsDataURL(document.getElementById("user_profile_img").files[0]);

};

</script>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- Start Top Search -->

<div class="top-search">

<div class="container">

<div class="input-group">

<span class="input-group-addon"><i class="fa fa-search"></i></span>

<input type="text" class="form-control" placeholder="Search">

<span class="input-group-addon close-search"><i class="fa fa-times"></i></span>

</div>

</div>

</div>

<!-- End Top Search -->

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Fruit market</p>

<p class="focus-in-expand-fwd2">직접 농사한 작물을 저렴한 가격에 구매해보세요</p>

</div>

</div>

<!-- End All Title Box -->

<div class="menu" style="text-align:center;">

<ul>

<li><a href="#">과일</a></li>

<li><a href="#">작물</a></li>

<li><a href="/fruitmarket">목록</a></li>

</ul>

</div>

<h2 style="text-align:center;margin-top:60px;font-size:35px;margin-bottom:40px;"><strong>Product Regist</strong></h2>

<form method="post" action="/product_success" enctype="multipart/form-data">

<table style="margin:auto;">

<tr style="border-top:3px solid blue">

<td id="img_preview" colspan="3" rowspan="4" style="margin-top:50px;">

<img id="user_image" src="#" alt="" style="height:200px; width:180px;margin-top:30px;">

</br>

</br>

<input style="margin-left:50px;" accept=".jpg" onchange="PreviewImage();" type="file" id="user_profile_img" name="img_name" >

</td>

<td colspan="3"><strong><span style="color:red">*</span>분류</strong> &nbsp;&nbsp;&nbsp;

<input type="radio"  name="kind" value="과일" checked>

<label for="huey"><strong>과일</strong></label>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

<input type="radio"  name="kind" value="작물" checked>

<label for="huey"><strong>작물</strong></label>

</td>

</tr>

<tr>

<td colspan="3" class="product"><strong> <span style="color:red">*</span> 상품명</strong> &nbsp;&nbsp;&nbsp; <input style="width:300px;" type="text" name="name"></td>

</tr>

<tr>

<td colspan="3" class="product"><strong> <span style="color:red">*</span>가격</strong> &nbsp;&nbsp;&nbsp; <input  style="width:300px;"type="text" name="price"></td>

</tr>

<tr>

<td colspan="3" class="product"><strong><span style="color:red">*</span>수량</strong> &nbsp;&nbsp;&nbsp;  <input  style="width:300px;"type="text" name="count"></td>

</tr>

<tr>

<td colspan="6" rowspan="3"><textarea class="area" style="margin-top:10px;" name="content"></textarea></td>

</tr>

<tr>

</tr>

<tr>

</tr>

<tr>

<td colspan="6">

<input class="btn" style="margin-right:20px;margin-bottom:20px;" type="submit" value="등록하기">

<input class="btn" style="margin-bottom:20px;" type="button" value="취소">

</td>

</tr>

</table>

</form>

<!-- End Shop Page -->

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 사용자가 판매하고자 하는 상품을 등록하는 페이지입니다.

2.5. 마이페이지

<!DOCTYPE html>

<html lang="en">

<head>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css">

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.theme.default.min.css">

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/view.css">

<link rel="stylesheet" href="/static/css/font.css">

<link href="/static/css/jquery-nice-number.css" rel="stylesheet">

<!-- ALL JS FILES -->

<script src="./static/js/jquery-3.2.1.min.js"></script>

<script src="./static/js/popper.min.js"></script>

<script src="./static/js/bootstrap.min.js"></script>

<script src="./static/js/bootstrap-select.js"></script>

<script src="./static/js/inewsticker.js"></script>

<script src="./static/js/bootsnav.js"></script>

<script src="./static/js/images-loded.min.js"></script>

<script src="./static/js/isotope.min.js"></script>

<script src="./static/js/owl.carousel.min.js"></script>

<script src="./static/js/form-validator.min.js"></script>

<script src="./static/js/contact-form-script.js"></script>

<script src="./static/js/Login.js"></script>

<script src="./static/js/signup.js"></script>

<script type="text/javascript"

src="https://cdn.iamport.kr/js/iamport.payment-1.1.5.js"></script>

<script>

$(function() {

$('#button3').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.e').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.e').slideUp();

}

});

});

</script>

<script>

$(function() {

$('#button4').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.f').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.f').slideUp();

}

});

});

</script>

<style>

.f { display: none; max-height:100%; max-width:100%;margin:auto;text-align:center;}

.e { display: none; max-height:100%; max-width:100%;margin:auto;text-align:center; }

</style>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">My Page</p>

<p class="focus-in-expand-fwd2">회원 정보를 확인해보세요</p>

</div>

</div>

<div class="box-add-products">

<div class="col-lg-12">

<div class="title-all text-center">

<h1>My page</h1>

<p>{{detail[0][0]}}님 환영합니다.</p>

</div>

</div>

<div class="container">

<div class="row">

<div class="col-lg-6 col-md-6 col-sm-12">

<img style="width:200px;float:right" src="./static/images/profile.jpg" alt="" />

</div>

{% for info in user_info %}

<div class="col-lg-6 col-md-6 col-sm-12" >

<strong style="font-size:15px;">

이름 - {{info[0]}}<br>

아이디 : {{info[1]}}<br>

이메일 : {{info[3]}}<br>

전화 번호 : {{info[4]}}<br>

</strong>

<br>

포인트 : {{detail[0][5]}}

<br><input type="number" id="pay" placeholder="충전금액"></input>

<button id = "check_module3">충전</button>

{% endfor %}

<script>

$("#check_module3").click(function() {

IMP.init('imp94991652');

var point =  document.getElementById("pay").value;

IMP.request_pay({

pg : 'kakaopay',

pay_method : 'card',

merchant_uid : 'merchant_' + new Date().getTime(),

name : '충전',

amount : document.getElementById("pay").value

}, function(rsp) {

console.log(rsp);

if (rsp.success) {

var msg = '결제가 완료되었습니다.';

alert(msg);

$.ajax({

url:'/test4',

data:{'point' : point

},

method:'POST',

dataType:'json',

success:function(result){

alert("성공");

},error:function(err){console.log("err",err)}

});

} else {

var msg = '결제에 실패하였습니다.';

msg += '에러내용 : ' + rsp.error_msg;

alert(msg);

}

});

});

</script>

</div>

</div>

<h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">구매 목록</h2>

<div style="margin-top:50px;text-align:center;margin-bottom:100px;">

<button id='button3' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="e">

{% set count= 0 %}

{% for list in buy_list %}

{% set count = count +1  %}

<table style="border-top:3px solid black;margin:auto;background-color:white;">

<thead>

<tr>

<th style="width:400px;">상품 정보</th>

<th style="width:120px">판매자</th>

<th style="width:120px;">수량</th>

<th style="width:200px;">결제 금액</th>

<th style="width:200px;">배송 상태</th>

<th style="width:200px;">송장 번호</th>

<th style="width:400px;">주소</th>

<th style="width:200px;">구매 품종 번호{{count}}</th>

</tr>

</thead>

<tbody>

<tr style="border-top:1px solid lightgrey;">

<td style="width:400px"><img style="width:100px;height:100px;" id="item_image" src="{{ url_for('static',filename='uploads/'+b_list[loop.index0][0][9])}}" alt="" title=""><p><strong>{{b_list[loop.index0][0][3]}}</strong></p></td>

<td style="width:120px">{{list[2]}}</td>

<td style="width:120px">{{list[3]}}</td>

<td style="width:200px">{{list[4]}}원</td>

<td style="width:200px">{{list[5]}}</td>

<td style="width:200px">{{list[6]}}</td>

<td style="width:400px">{{list[7]}}</td>

<td style="width:200px">{{list[8]}}</td>

<br>

</tr>

<!-- {% set count = count +1  %} -->

{% endfor %}

</tbody >

</table>

</div>

</div>

<h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">판매 목록</h2>

<div style="margin-top:50px;text-align:center;margin-bottom:100px;">

<button id='button4' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="f">

{% for list in sell_list %}

<table style="border-top:3px solid black;margin:auto;background-color:white;width:1000px">

<thead>

<tr>

<th style="width:200px">구매자</th>

<th style="width:200px;">수량</th>

<th style="width:200px;">가격</th>

<th style="width:250px;">배송 상태</th>

<th style="width:200px;">송장 번호</th>

<th style="width:800px;">주소</th>

<th style="width:400px;">구매 품종 번호</th>

<th style="width:200px;">송장 번호 입력</th>

<th></th>

</tr>

</thead>

<tbody>

<tr style="border-top:1px solid lightgrey;">

<td style="width:200px">{{list[1]}}</td>

<td style="width:200px">{{list[3]}}</td>

<td style="width:200px">{{list[4]}}원</td>

<td style="width:200px">{{list[5]}}</td>

<td style="width:800px">{{list[6]}}</td>

<td style="width:200px">{{list[7]}}</td>

<td style="width:200px">{{list[8]}}</td>

<td>

<input type = "text" id = "invoNum" placeholder="송장번호입력"></input >

</td>

<td style="width:400px;">

<button id = "delivery" style="border:1px solid lightgrey;">배송하기</button>

</td>

<script>

$("#delivery").click(function() {

var number = $('#invoNum').val()

if(  $('#invoNum').val() != ""){

alert(number);

alert('{{sell_list[0][0]}}');

var msg = '배송.';

alert(msg,);

$.ajax({

url:'/test5',

data:{'invoNum' : $('#invoNum').val() ,

'pNum' : '{{sell_list[0][0]}}'

},

method:'POST',

dataType:'json',

success:function(result){

alert("성공");

},error:function(err){console.log("err",err)}

});

}

else{

alert("송장번호를 입력해주세요.");

}

});

</script>

</tr>

{% endfor %}

</tbody>

</table>

</div>

</div>

</div>

</div>

</div>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지 마이페이지로, 사용자의 정보와 구매 목록, 판매 목록을 보여주는 페이지입니다.

2.6. 만남의 광장

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Meeting</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/view.css">

<link rel="stylesheet" href="/static/css/font.css">

<link href="/static/css/jquery-nice-number.css" rel="stylesheet">

<link rel="stylesheet" href="/static/css/meeting.css">

<link rel="stylesheet" href="/static/css/user_farm.css">

<link rel="stylesheet" href="/static/css/meeting_chat.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.6.0.min.js"></script>

<script src="/static/js/jquery-nice-number.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<!-- ALL PLUGINS -->

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<!-- <script src="/static/js/baguetteBox.min.js"></script> -->

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<!-- <script src="/static/js/custom.js"></script> -->

<script src="/static/js/Login.js"></script>

<script src="/static/js/signup.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

<script>

$(function() {

$('#button1').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.b').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.b').slideUp();

}

});

});

</script>

<script>

$(function() {

$('#button2').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.d').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.d').slideUp();

}

});

});

</script>

<script>

$(function() {

$('#button3').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.e').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.e').slideUp();

}

});

});

</script>

<script>

$(function() {

$('#button4').click( function() {

if( $(this).html() == '<i class="fas fa-chevron-down"></i>' ) {

$(this).html('<i class="fas fa-chevron-up"></i>');

$('.f').slideDown();

}

else {

$(this).html('<i class="fas fa-chevron-down"></i>');

$('.f').slideUp();

}

});

});

</script>

<script type="text/javascript">

var socket = io.connect('http://' + '127.0.0.1' + ':' + 5000);

socket.on( 'connect', function() {

socket.emit( 'my event', {

data: 'User Connected'

} )

var form = $( 'form' ).on( 'submit', function( e ) {

e.preventDefault()

let user_name = '{{f_intro[0]}}';

let user_input = $( 'input.message' ).val();

socket.emit( 'my event', {

user_name : user_name,

message : user_input

} );

$( 'input.message' ).val( '' ).focus()

} )

} )

socket.on( 'my response', function( msg ) {

console.log( msg )

if( typeof msg.user_name !== 'undefined' ) {

$( 'h3' ).remove()

$( 'div.message_holder' ).append( '<div><b style="color: black;font-weight:800;font-size:17px;">'+msg.user_name+'</b>'+'<b style="background-color:yellow;border:1px solid yellow;border-radius:30%;color: black;font-weight:800;font-size:13px;margin-left:10px;">'+msg.message+'</b></div>' )

}

})

</script>

<style>

.f { display: none; height: 600px; width:1000px;margin:auto;text-align:center; background-color: white; }

.e { display: none; max-height:100%; width:1000px;margin:auto;text-align:center; background-color: white; }

.d { display: none; height: 1000px; width:1000px;margin:auto;text-align:center; background-color: white;border:1px solid lightgrey; }

.b { display: none; height: 600px; overflow:auto;width:700px;margin:auto;text-align:center; background-color: white;border:1px solid lightgrey; }

.c { display: none; height: 300px; background-color: white;border:1px solid lightgrey; }

</style>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Meeting farm</p>

<p class="focus-in-expand-fwd2">다른 사람들과 농장을 공유해보세요</p>

</div>

</div>

<div style="max-height:100%;">

<h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">농장 소개</h2>

<div style="margin-top:50px;text-align:center;">

<button id='button1' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="b">

<center>

<div class="col-md-6">

<div class="col p-4 d-flex flex-column position-static">

<h2><strong class="d-inline-block mb-2 text-success">{{f_intro[0]}}님의 농장</strong></h2>

<strong><div class="mb-1 text-muted" style="font-size:18px;width:300px;">{{f_intro[1]}}</div></strong>

<div class="col-auto d-none d-lg-block">

</div>

</div>

</div>

</div>

</center>

</div>

<h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">사진관</h2>

<div style="margin-top:50px;text-align:center;">

<button id='button2' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="d">

{% for images in u_images %}

<div class="images_wrap">

<img style="width:200px;height:200px;" src="{{ url_for('static',filename='farm/'+images[4])}}" alt="" title="">

<div style="width:250px;margin:auto;margin-top:10px;">

<h4 style="font-size:14px;font-weight:800;">제목 : <a href="/image_view{{images[0]}}">{{images[2]}}</a></h4>

<h4 style="font-size:12px;font-weight:800;">등록일자 : {{images[5]}}</h4>

</div>

</div>

{% endfor %}

<div style="margin-top:60px;margin-bottom:30px;">

<a href="/regist_farm"><button class="user_btn">사진 등록</button></a>

</div>

</div>

</div>

<h2 style="font-size:25px; font-weight:800;margin-top:40px; text-align:center;">채팅 하기</h2>

<div style="margin-top:50px;text-align:center;margin-bottom:100px;">

<button id='button3' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="e">

<div class="message_holder">

<h3 style='color: white;font-size: 30px;'>No message yet..</h3>

</div>

<form action="" method="POST">

<!-- <input type="text" class="username" placeholder="User Name"/> -->

<input type="text" class="message" placeholder="Messages"/>

<input type="submit"/>

</form>

</div>

</div>

<h2 style="font-size:18px; font-weight:800;margin-top:40px; text-align:center;">다른 유저 농장 놀러가기</h2>

<div style="margin-top:50px;text-align:center;margin-bottom:100px;">

<button id='button4' style="border-radius:50%;border:1px solid lightgrey;background-color:white;"><i class="fas fa-chevron-down"></i></button>

<div class="f">

{% for user_farm in users %}

<div>

<p><a href="{{ url_for('user_farm', visit = user_farm)}}">{{user_farm[0]}}님의 농장 바로가기</a></p>

<br>

</div>

{% endfor %}

</div>

</div>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 만남의 광장 페이지로, 자신의 농장 소개, 농장, 작물 등을 사진을 등록할 수 있는 사진관과, 사용자들끼리의 채팅 기능, 다른 유저의 농장에 갈 수 있는 페이지입니다.

2.7. 게시판 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Board</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<!--  footer CSS -->

<link rel="stylesheet" href="/static/css/footer.css">

<!-- 중단 메뉴바 CSS -->

<link rel="stylesheet" href="/static/css/view.css">

<!-- footer CSS -->

<link rel="stylesheet" href="/static/css/font.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

</head>

<body>

{% include "nav_bar.html" %} <!-- 네비케이션바 -->

<!-- 배너 -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Farm Diary</p>

<p class="focus-in-expand-fwd2">농장일기 사이트에 오신걸 환영합니다</p>

</div>

</div>

<!-- 중단 메뉴바 -->

<div class="menu" style="text-align:center;">

<ul>

<li><a href="/borad">목록</a></li>

<li><a href="/write">글 작성</a></li>

</ul>

</div>

<h2 style="height:50px;text-align:center;font-weight:800;margin-top:60px;font-size:30px;">자유 게시판</h2>

<!-- 게시판 목록 -->

<div class="container" style="height:700px;margin-top:50px;">

<div class="row">

<div class="col-lg-12">

<table class="table table-hover" style="text-align: center; border: 1px solid #dddddd">

<thead>

{% if board_list | length == 0 %}

<tr>

<th style="background-color: #eeeeee; text-align: center;">글 목록</th>

</tr>

{% else %}

<tr>

<th style="background-color: #eeeeee; text-align: center; ">번호</th>

<th style="background-color: #eeeeee; text-align: center;">제목</th>

<th style="background-color: #eeeeee; text-align: center;">작성자</th>

<th style="background-color: #eeeeee; text-align: center;">작성일</th>

<th style="background-color: #eeeeee; text-align: center;">조회수</th>

</tr>

{% endif %}

</thead>

<tbody>

{% if board_list | length == 0 %}

<tr>

<td>작성된 글이 없습니다.</td>

</tr>

{% else %}

{% for board in board_list %}

<tr>

<td><a href="/board_view{{board[0]}}">{{board[0]}}</a></td>

<td style="text-align:left;"><a href="/board_view{{board[0]}}">{{board[1]}}</a></td>

<td><a href="/board_view{{board[0]}}">{{board[2]}}</a></td>

<td><a href="/board_view{{board[0]}}">{{board[3]}}</a></td>

<td><a href="/board_view{{board[0]}}">{{board[4]}}</a></td>

</tr>

{% endfor %}

{% endif %}

</tbody>

</table>

<form method="post" action="/board_search">

<input type="text" name="keyword123">

<button style="border:1px solid lightgrey;">검색</button>

</form>

<div style="text-align:center;">

{% if block_start - 1 > 0 %}

<a href="{{url_for('borad', page=block_start - 1)}}">[이전]</a>

{% endif %}

{% for i in range(block_start, block_end + 1)%}

{% if i > last_page_num %}

{% else %}

{% if i == page %}

<b class="test">{{ i }}</b>

{% else %}

<a class="test" href="{{url_for('borad', page=i)}}">{{ i }}</a>

{% endif %}

{% endif %}

{% endfor %}

{% if block_end < last_page_num %}

<a href="{{url_for('borad', page=block_end + 1)}}">[다음]</a>

{% endif %}

</div>

</div>

</div>

</div>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지 게시판 페이지로, 사용자가 작성한 글을 확인 할 수 있고 검색할 수 있는 페이지입니다.

2.8. 회원가입 페이지

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<!-- Mobile Metas -->

<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Site Metas -->

<title>Signup</title>

<meta name="keywords" content="">

<meta name="description" content="">

<meta name="author" content="">

<!-- Site Icons -->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">

<!-- Bootstrap CSS -->

<link rel="stylesheet" href="/static/css/bootstrap.min.css">

<!-- Site CSS -->

<link rel="stylesheet" href="/static/css/style.css">

<!-- Responsive CSS -->

<link rel="stylesheet" href="/static/css/responsive.css">

<!--  footer CSS -->

<link rel="stylesheet" href="/static/css/footer.css">

<link rel="stylesheet" href="/static/css/signup2.css">

<link rel="stylesheet" href="/static/css/font.css">

<!-- ALL JS FILES -->

<script src="/static/js/jquery-3.2.1.min.js"></script>

<script src="/static/js/popper.min.js"></script>

<script src="/static/js/bootstrap.min.js"></script>

<script src="/static/js/jquery.superslides.min.js"></script>

<script src="/static/js/bootstrap-select.js"></script>

<script src="/static/js/inewsticker.js"></script>

<script src="/static/js/bootsnav.js"></script>

<script src="/static/js/images-loded.min.js"></script>

<script src="/static/js/isotope.min.js"></script>

<script src="/static/js/owl.carousel.min.js"></script>

<!-- <script src="/static/js/baguetteBox.min.js"></script> -->

<script src="/static/js/jquery-ui.js"></script>

<script src="/static/js/jquery.nicescroll.min.js"></script>

<script src="/static/js/form-validator.min.js"></script>

<script src="/static/js/contact-form-script.js"></script>

<!-- <script src="/static/js/custom.js"></script> -->

</head>

<body>

<!-- 네비케이션바 -->

{% include "nav_bar.html" %}

<!-- Start All Title Box -->

<div style="width:100%;height:400px;background-color:black;">

<div class="back_img">

<p class="focus-in-expand-fwd" style="padding-top:120px;">Farm Diary</p>

<p class="focus-in-expand-fwd2">농장일기 사이트에 오신걸 환영합니다.</p>

</div>

</div>

<!-- 회원 가입 폼 -->

<form method="POST" action="/test">

<table style="margin-top:60px;">

<tr>

<td style="text-align:center; padding-bottom:40px;font-size:45px;color:#00CC33;" class="view_title">&nbsp;&nbsp;&nbsp;Farm Diary</td>

</tr>

<tr>

<td style="border-bottom:3px solid black;" class="view_title">&nbsp;&nbsp;&nbsp;1. 귀농인, 일반인 선택하세요</td>

</tr>

<tr>

<td>

<i style="margin-left:170px; margin-top:40px;" class="fas fa-tractor fa-7x"></i>

<i style="margin-left:170px;" class="fas fa-users fa-7x"></i>

</td>

</tr>

<tr style="margin-top:30px;">

<td>

<span style="font-size:25px; font-weight:700; margin-left:180px;"><input style="margin-top:50px;" type="radio" name="job" value="farm" checked>&nbsp;&nbsp;귀농인</span>

<span style="font-size:25px; font-weight:700; margin-left:220px;"><input style="margin-top:50px;" type="radio" name="job" value="user">&nbsp;&nbsp;일반인</span>

</td>

</tr>

<tr>

<td style="border-bottom:3px solid black; padding-top:50px;" class="view_title">&nbsp;&nbsp;&nbsp;2. 기본정보 입력<span style="float:right; color:red; font-size:15px;">*이부분은 필수입니다.</span></td>

</tr>

<tr>

<td>&nbsp;&nbsp;&nbsp;</td>

</tr>

<tr>

<td>

<span style="color:red;">*</span><span>아이디</span><input type="text" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="userid">

<p style="margin-top:10px; text-align:center;">4~20자 이내 영문 소문자, 숫자만 가능합니다.</p>

<p style="margin-top:30px;"><span style="color:red;">*</span>비밀번호<input type="password" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="password"></p>

<p style="margin-top:10px; text-align:center;">반복, 연속문자, 개인정보 관련은 사용불가</p>

<p style="margin-top:30px;"><span style="color:red;">*</span>비밀번호 확인<input type="password" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="pass_check"></p>

</td>

</tr>

<tr>

<td style="border-bottom:3px solid black; padding-top:50px;" class="view_title">&nbsp;&nbsp;&nbsp;3. 개인정보사항 입력</td>

</tr>

<tr>

<td>

<p style="margin-top:30px;"><span style="color:red;">*</span>이름<input type="text" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="name"></p>

<p style="margin-top:30px;"><span style="color:red;">*</span>전화번호<input type="text" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="phoneNum"></p>

<p style="margin-top:30px;"><span style="color:red;">*</span>이메일<input type="text" style="width:400px;left: 0; right: 0; margin-left:auto; margin-right:auto; position:absolute;" name="email"></p>

</td>

</tr>

<tr>

<td style="border-bottom:3px solid black; padding-top:50px;" class="view_title"></td>

</tr>

<tr>

<td style="float:right; padding-top:20px; font-size:20px;"><button style="background-color:skyblue; color:white; border:none;" type="submit" value="회원가입">회원가입</button></td>

</tr>

</table>

</form>

{% include "footer.html" %}

<a href="#" id="back-to-top" title="Back to top" style="display: none;">&uarr;</a>

</body>

</html>

해당 페이지는 회원가입 페이지로, 사용자의 정보를 입력해서 사이트에 가입할 수 있는 페이지입니다.

2.9. 상단 메뉴바

<!-- Start Main Top -->

<header class="main-header">

<!-- Start Navigation -->

<nav class="navbar navbar-expand-lg navbar-light bg-light navbar-default bootsnav">

<div class="container">

<!-- Start Header Navigation -->

<div class="navbar-header">

<a class="navbar-brand" href="/"><strong>Farm Diary</strong></a>

</div>

<div class="collapse navbar-collapse" id="navbar-menu">

<ul class="nav navbar-nav ml-auto" data-in="fadeInDown" data-out="fadeOutUp">

<li class="nav-item active"><a class="nav-link" href="/">Home</a></li>

<li class="nav-item"><a class="nav-link" href="fruitinform">정보 마당</a></li>

<li class="dropdown">

<a href="#" class="nav-link dropdown-toggle arrow" data-toggle="dropdown">장 마당</a>

<ul class="dropdown-menu">

<li><a href="fruitmarket">과일 마당</a></li>

<li><a href="cropmarket">작물 마당</a></li>

</ul>

</li>

<li class="dropdown">

<a href="recommend" class="nav-link dropdown-toggle arrow" data-toggle="dropdown">추천 마당</a>

</li>

<li class="nav-item"><a class="nav-link" href="/meeting">만남의 광장</a></li>

<li class="dropdown">

<a href="#" class="nav-link dropdown-toggle arrow" data-toggle="dropdown">게시판</a>

<ul class="dropdown-menu">

<li><a href="borad" >목록</a></li>

<li><a href="write" >글 작성</a></li>

</ul>

</li>

{% if user_id is not none and user_id != "-1" %}

<li class="nav-item"><a class="nav-link" href="/mypage">{{name}}님</a></li>

<li class="nav-item"><a class="nav-link" href="/logout">Logout</a></li>

{% else %}

<li class="nav-item"><a class="nav-link" href="login">Login</a></li>

<li class="nav-item"><a class="nav-link" href="signup">sign up</a></li>

{% endif %}

</ul>

</div>

</div>

</nav>

</header>

해당 코드는 상단 메뉴바 코드로, 각 기능에 대한 페이지 이동 및 로그인 되었을 때 사용자의 정볼르 보여주는 코드입니다.

2.10. 하단 footer

<footer id="footer">

<div class="container">

<div class="row">

<div class="footer">

<ul>

<li><a href="#">사이트 도움말</a></li>

<li><a href="#">사이트 이용약관</a></li>

<li><a href="#">사이트 운영원칙</a></li>

<li><a href="#"><strong>개인정보취급방침</strong></a></li>

<li><a href="#">책임의 한계와 법적고지</a></li>

<li><a href="#">게시중단요청서비스</a></li>

<li><a href="#">고객센터</a></li>

</ul>

<address>

Copyright ©

<a href="http://webstoryboy.co.kr"><strong>Farm Diary</strong></a>

All Rights Reserved.

</address>

<ul>

<li class="footer_icon"><a href="#"><span><i class="fab fa-twitter-square"></i></span></a></li>

<li class="footer_icon"><a href="#"><span><i class="fab fa-facebook-square"></i></span></a></li>

<li class="footer_icon"><a href="#"><span><i class="fab fa-instagram-square"></i></span></a></li>

</ul>

</div>

</div>

</div>

</footer>

해당 코드는 모든 페이지 하단 보여주는 footer 코드입니다.

3 Flask

3.1. 로그아웃 함수

@app.route('/logout')

def logout():

session['user_id'] = None

session['name'] = None

return "<script>alert('로그아웃 되었습니다.');window.location.href='/'</script>"

세션 값을 초기화하여 로그인 정보를 삭제하는 함수입니다.

3.2. 메인페이지 함수

@app.route('/')

def index():

global month

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = f"select * from pay_board order by num desc limit 4"

curs.execute(sql)

pro = curs.fetchall()

return render_template('main.html',user_id=user_id, name=name, month=month, pro=pro)

return render_template('main.html',user_id='-1', name='-1', month=month)

해당 코드는 메인페이지 함수입니다.

3.3. 마이페이지 함수

@app.route('/mypage')

def mypage():

if "user_id" not in session:

return "<script>alert('로그인을 먼저 하세요!');window.location.href='/login'</script>"

elif "user_id" in session:

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "select * from user_info where id='%s'"%user_id

curs.execute(sql)

detail = curs.fetchall()

sql2 = "select * from pay_info where buyer='%s' order by id desc"%name

curs.execute(sql2)

buy_list = curs.fetchall()

sql3 = "select * from pay_info where seller='%s' order by id desc"%user_id

curs.execute(sql3)

sell_list = curs.fetchall()

b_list=[]

for i in range(0,len(buy_list)):

sql5="select * from pay_board where num = '%s'" %buy_list[i][8]

curs.execute(sql5)

b_list.append(list(curs.fetchall()))

s_list=[]

for i in range(0,len(sell_list)):

sql5="select * from pay_board where num = '%s'"%sell_list[i][8]

curs.execute(sql5)

s_list.append(curs.fetchall())

sql4 = "select * from user_info where name = '%s'"%name

curs.execute(sql4)

user_info = curs.fetchall()

return render_template('mypage.html',user_id=user_id, name=name,detail=detail ,buy_list=buy_list,sell_list=sell_list, user_info=user_info, b_list=b_list, s_list=s_list)

return render_template('main.html',user_id='-1', name='-1')

해당 페이지는 마이페이지 함수로 현재 로그인된 세션값으로 데이터베이스에 접속해 사용자의 정보, 구매목록, 판매목록을 가져오는 함수입니다.

3.3.1. 마이페이지 – 송장 번호 입력

@app.route('/songjang', methods=["POST"])

def songjang():

print(123)

if "user_id" in session:

user_id = session['user_id']

invoNum=request.form['invoNum']

pNum =int(request.form['pNum'])

print(type(invoNum),pNum)

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "update pay_info set invo_num = '%s',status='%s' where id = '%d'" %(invoNum,'배송중',pNum)

curs.execute(sql)

con.commit()

return render_template('main.html', user_id=user_id, name=name)

return render_template('main.html', user_id='-1', name='-1')

마이페이지의 송장 번호 입력 버튼을 클릭했을 때 발생하는 이벤트 함수입니다.

3.4 장 마당

@app.route('/fruitmarket')

def fruitmarket():

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql2 = f"select * from pay_board where kind='과일'"

curs.execute(sql2)

product_list = curs.fetchall()

print(product_list)

return render_template('fruitmarket.html',user_id=user_id, name=name, product_list=product_list)

return render_template('fruitmarket.html',user_id='-1', name='-1')

사용자가 등록한 작물, 과일 등을 가져오는 함수입니다.

3.4.1 장 마당 – 작물 등록

@app.route('/product_success', methods=["GET", "POST"])

def product_success():

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

ranNum = str(random.randint(1, 10000))

if request.method == "POST":

f = request.files['img_name']

#저장할 경로 + 파일명

f.save('static/uploads/'+secure_filename(ranNum+f.filename))

kind = request.form['kind'] #과일, 작물

name = request.form['name'] #이름

content = request.form['content'] #내용

price = request.form['price'] #가격

count = request.form['count'] #수량

img = ranNum+f.filename #이미지 이름

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "insert into pay_board (`userid`, `proname`, `price`, `content`, `count`, `kind`, `image`,`state`,`invo_num`) values ('%s', '%s','%s','%s','%s', '%s','%s','%s','%s')"%(user_id, name, price, content, count, kind, img,'준비중','준비중')

curs.execute(sql)

con.commit()

if kind == "과일":

return "<script>alert('작물 등록이 완료되었습니다');window.location.href ='/fruitmarket'</script>"

elif kind == "작물":

return "<script>alert('작물 등록이 완료되었습니다');window.location.href='/cropmarket'</script>"

해당 코드는 작물을 등록하는 코드로, 사용자가 입력한 작물의 정보를 DB에 저장하는 함수입니다.

3.4.2. 장 마당 – 결제 페이지

@app.route('/purchase<int:pro_num>', methods=["GET", "POST"])

def purchase(pro_num):

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

if request.method == "POST":

count = int(request.form["count"])

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "select * from pay_board where num=%d"%pro_num

curs.execute(sql)

detail = curs.fetchall()

sql2 = f"select phoneNum from user_info where id='%s'"%user_id

curs.execute(sql2)

phone = curs.fetchone()[0]

sql3 = f"select point from user_info where id='%s'"%user_id

curs.execute(sql3)

point = curs.fetchone()[0]

return render_template('purchase.html', user_id=user_id, name=name, detail=detail, count=count, phone=phone,point=point)

return render_template('purchase.html', user_id='-1', name='-1')

해당 코드는 작물을 결제하는 페이지로 이동하는 함수입니다.

3.4.3 장 마당 – 결제 정보

@app.route('/pay', methods=["POST"])

def pay():

if "user_id" in session:

post =  request.form['postcode']

roat =  request.form['roadAddress']

jibun =  request.form['jibunAddress']

detail =  request.form['detailAddress']

extra =  request.form['extraAddress']

productNum = int(request.form['productNum'])

seller =request.form['seller_id']

buyer=request.form['buyer']

price=int(request.form['price'])

count=int(request.form['count'])

print(post,road,jibun,detail,extra,productNum,buyer,seller,price,count)

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "insert into pay_info (`buyer`, `seller`, `count`, `price`,`status`, `invo_num`,`address`,`product_num`) values ('%s','%s','%d','%d','%s','%s','%s','%d')" %(buyer, seller, count,price,'준비중','준비중',post+road+jibun+detail+extra,productNum)

curs.execute(sql)

con.commit()

return render_template('main.html', user_id=user_id, name=name)

return render_template('main.html', user_id='-1', name='-1')

해당 페이지는 결제 후 결제 정보를 DB에 저장하는 함수입니다.

3.5. 정보 검색

@app.route('/video_view', methods=["GET", "POST"])

def video_view():

if "user_id" not in session:

return "<script>alert('로그인을 먼저 하세요!');window.location.href='/login'</script>"

elif "user_id" in session:

user_id = session['user_id']

name = session['user_name']

if request.method == "POST":

keyword = request.form['keyword']

driver_url = 'C:\\chromedriver.exe'

#driver_url = '/usr/bin/chromedriver' #우분투 환경

chrome_options = webdriver.ChromeOptions()

#chrome_options.add_argument('--headless') #우분투

chrome_options.add_argument('--no-sandbox')

chrome_options.add_argument('--privileged')

chrome_options.add_argument('--incognito')

chrome_options.add_argument('--disable-dev-shm-usage')

chrome_options.add_experimental_option("excludeSwitches", ["enable-logging"])

chrome_options = chrome_options

driver = webdriver.Chrome(driver_url, chrome_options=chrome_options)

url = f'https://www.youtube.com/results?search_query={keyword}'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

lis = soup.find_all('a', class_='yt-simple-endpoint style-scope ytd-video-renderer')

#조회수 리스트

view_list = []

#제목 리스트

title_list = []

#링크 리스트

src_list = []

for h in lis:

view_list.append(h.get('aria-label').split()[-1])

title_list.append(h["title"])

v_id = h["href"].split("v=")[1]

src_list.append( f"""<iframe width="400" height=400" src="https://www.youtube.com/embed/{v_id}" frameborder="0" allowfullscreen=""></iframe>""" )

print(f'src_list:{len(src_list)}')

src_list_html = "<br><br><br>".join(src_list)

return render_template('video_view.html', user_id=user_id, name=name, src_list=src_list, title_list=title_list, view_list=view_list, keyword=keyword)

return render_template('video_view.html',user_id='-1', name='-1')

해당 코드는 정보 검색 코드로, selenium과 beautifulsoup4를 사용하여 사용자가 원하는 정보를 검색하는 기능입니다.

3.6 게시판

@app.route('/board')

def board():

if "user_id" not in session:

return "<script>alert('로그인을 먼저 하세요!');window.location.href='/login'</script>"

elif "user_id" in session:

user_id = session['user_id']

name = session['user_name']

#페이지 값 1

page = request.args.get("page", 1, type=int)

#한 페이지 당 게시물 출력 갯수

limit = 10

# 페이지 블럭을 5개씩 표기

block_size = 5

block_num = int((page - 1) / block_size)

block_start = (block_size * block_num) + 1

block_end = block_start + (block_size - 1)

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "select count(*) from board"

curs.execute(sql)

#게시물 총 개수

count_num = curs.fetchall()[0][0]

#페이지 갯수

last_page_num = math.ceil(count_num / limit)

# 2페이지 이상

if page > 1:

item_count = count_num % ((page-1)*limit)

if item_count == 0: item_count = limit

# 1페이지

else:

item_count = count_num % (limit)

if item_count == 0: item_count = limit

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql2 = f"select num, title, writer, date, count from board order by num desc limit {limit} offset {(page-1)*limit}"

curs.execute(sql2)

board_list = curs.fetchall()

print(board_list)

return render_template('board.html',board_list=board_list, name=name, count_num=count_num,limit=limit,page=page,block_start=block_start,block_end=block_end,last_page_num=last_page_num)

return render_template('borad.html',user_id='-1', name='-1')

해당 코드는 게시판 코드로 한 페이지당 출력할 게시물을 10개로 지정하고, 페이지 블록 제한을 5개로 지정하였습니다.

3.7. 로그인

@app.route('/login', methods=["GET", "POST"])

def login():

if "uesr_id" in session:

user_id = session['user_id']

name = session['user_name']

if request.method=="GET":

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

return render_template('login.html',user_id=user_id, name=name)

return render_template('login.html',user_id='-1', name='-1')

elif request.method=="POST":

user_id = request.form["user_id"]

pw = request.form["password"]

if user_id == "":

return "<script>alert('로그인을 먼저 하세요!');window.location.href='/login'</script>"

else:

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

cur = con.cursor()

sql = f'select EXISTS (select * from user_info where id="{user_id}" and password="{pw}") as success'

cur.execute(sql)

login_check=cur.fetchone()[0]

sql2 = f'select name from user_info where id = "{user_id}"'

cur.execute(sql2)

name=cur.fetchone()

if name:

name = name[0]

#로그인성공

if login_check == 1:

session['user_id'] = user_id

session['user_name'] = name

pass

else:

return "<script>alert('존재하지 않습니다');window.location.href='/login'</script>"

print(login_check)

print(f'user_id={user_id}\tpw={pw}')

return render_template('main.html',user_id=user_id,name=name)

해당 코드는 로그인 코드로, DB에 저장되어있는 사용자의 정보와 아이디 비밀번호 값이 일치하면 사용자의 세션 값을 저장하고 로그인을 수행하는 함수입니다.

3.8 회원가입

@app.route('/signup', methods=['GET', 'POST'])

def signup(): #회원가입 함수

#입력된 값 id 값 통해 전송

if request.method == 'POST':

name = request.form['name']

userid = request.form['userid']

password = request.form['password']

passCheck = request.form['pass_check']

email = request.form['email']

phoneNum = request.form['phoneNum']

job = request.form['job']

# mysql db 연결

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql2 = f'select EXISTS (select * from user_info where id="{userid}") as success'

curs.execute(sql2)

result = curs.fetchone()[0]

if result==1:

return "<script>alert('이미 존재하는 아이디입니다.');window.location.href ='/signup'</script>"

else:

if 4 <= len(userid) < 20:

if userid not in password:

sql = "insert into user_info (`name`,`id`,`password`,`email`,`phoneNum`, `job`) values ('%s','%s','%s','%s','%s','%s')" %(name,userid,password,email,phoneNum,job)

curs.execute(sql)

con.commit()

elif userid in password:

return "<script>alert('개인정보관련은 사용불가입니다!');window.location.href='/signup'</script>"

else:

return "<script>alert('4~20자리 이내 영문 소문자, 숫자만 가능합니다.');window.location.href='/signup'</script>"

return "<script>alert('회원가입이 완료되었습니다..');window.location.href ='/login'</script>"

con.close()

curs.close()

return render_template('login.html')

해당 코드는 회원가입 코드로, 사용자가 입력한 정보를 받아 DB에 저장하는 함수입니다.

3.9. 만남의 광장

@app.route('/meeting', methods=["GET", "POST"])

def meeting():

if "user_id" not in session:

return "<script>alert('로그인 후 이용가능합니다!');window.location.href='/login'</script>"

elif "user_id" in session:

user_id = session['user_id']

name = session['user_name']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

#만남의 광장, 특정 유저 가입, 존재 여부 확인 쿼리

sql = "select exists (select * from user_intro where name = '%s') as success"%name

curs.execute(sql)

result = curs.fetchone()[0]

#데이터가 존재할때

if result == 1:

sql = f"select * from user_images where name = '%s'"%name

curs.execute(sql)

u_images = curs.fetchall()

sql2 = f"select * from user_intro where name = '%s'"%name

curs.execute(sql2)

f_intro = curs.fetchone()

#만남의 광장에 등록된 유저들

sql3 = f"select name from user_intro"

curs.execute(sql3)

users = curs.fetchall()

return render_template('meeting.html', user_id=user_id, name=name, f_intro=f_intro, u_images=u_images,users=users)

#데이터가 존재하지 않을 떄

elif result == 0:

return render_template('meeting_intro.html', user_id=user_id, name=name)

해당 페이지는 만남의 광장 페이지로 이동하는 함수입니다.

3.9.1 만남의 광장 – 농장 등록

@app.route('/meeting_intro', methods=["GET", "POST"])

def meeting_intro():

if "user_id" not in session:

return "<script>alert('로그인 후 이용가능합니다!');window.location.href='/login'</script>"

elif "user_id" in session:

user_id = session['user_id']

name = session['user_name']

if request.method == "POST":

intro = request.form['intro']

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = "insert into user_intro (`name`, `intro`) values ('%s','%s')" %(name, intro)

curs.execute(sql)

con.commit()

return redirect(url_for('meeting'))

만남의 광장에 처음 방문 시에만 실행 되는 함수입니다. 간단한 자신의 농장 소개를 DB에 저장하는 코드입니다.

3.9.2. 만남의 광장 – 채팅

def messageReceived(methods=['GET', 'POST']):

print('message was received!!!')

@socketio.on('my event')

def handle_my_custom_event(json):

print('received my event: ' + str(json))

socketio.emit('my response', json, callback=messageReceived)

만남의 광장 채팅 코드입니다. 로그인 된 유저의 세션값과 메시지를 받아 이벤트를 처리하는 함수입니다.

3.9.3 만남의 광장 – 사진 등록, 사진관

@app.route('/farm_success', methods=["GET", "POST"]) def farm_success(): global current_time global month,year,day,time if "user_id" in session: user_id = session['user_id'] name = session['user_name'] if request.method == "POST": title = request.form['title'] #사진 제목 content = request.form['content'] #사진 내용 f = request.files['file'] img = f.filename #이미지 이름 farm_load = "C:/Users/Limdonggeun/Desktop/졸작/static/farm/" #저장할 경로 + 파일명 f.save(farm_load+secure_filename(f.filename)) #사진 파일 이름 con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306) curs = con.cursor() sql = "insert into user_images (`name`, `title`, `content`, `img_name`, `date`) values ('%s','%s','%s','%s','%s')" %(name, title, content, img, current_time) curs.execute(sql) con.commit() return redirect(url_for('meeting'))	@app.route('/image_view<int:num>') def image_view(num): if "user_id" in session: user_id = session['user_id'] name = session['user_name'] con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306) curs = con.cursor() sql = f"select * from user_images where num = %d"%num curs.execute(sql) detail_farm = curs.fetchall() return render_template('image_view.html', user_id=user_id, name=name, detail_farm=detail_farm) return render_template('image_view.html', user_id='-1', name='-1')
만남의 광장 페이지의 사진 등록과, 사진을 관람할 수 있는 페이지입니다.

3.9.4. 만남의 광장 – 개인 농장 입장

@app.route('/user_farm')

def user_farm():

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

user_name = request.args.get('visit')

con = pymysql.connect(host='52.78.17.164', user='root', password='farm1234!@#$', db='farmdiary', charset='utf8', port=33306)

curs = con.cursor()

sql = f"select * from user_intro where name = '%s'"%user_name

curs.execute(sql)

visit_intro = curs.fetchone()

sql2 = f"select * from user_images where name = '%s'"%user_name

curs.execute(sql2)

visit_images = curs.fetchall()

sql3 = f"select name from user_intro"

curs.execute(sql3)

users = curs.fetchall()

if name == user_name:

return redirect(url_for('meeting'))

else:

return render_template('user_farm.html', user_id=user_id, name=name, visit_intro=visit_intro,visit_images=visit_images,users=users)

return render_template('user_farm.html', user_id='-1', name='-1')

만남의 광장에 등록된 다른 유저의 농장에 갈 수 있는 코드입니다.

3.10. 날씨 정보

@app.route('/weathertest', methods=["GET", "POST"])

def weathertest():

if "user_id" in session:

user_id = session['user_id']

name = session['user_name']

if request.method == "POST":

local = request.form['local']

driver_url = 'C:\\chromedriver.exe'

#driver_url = '/usr/bin/chromedriver' #우분투 환경

chrome_options = webdriver.ChromeOptions()

#chrome_options.add_argument('--headless') #우분투

chrome_options.add_argument('--no-sandbox')

chrome_options.add_argument('--privileged')

chrome_options.add_argument('--incognito')

chrome_options.add_argument('--disable-dev-shm-usage')

chrome_options.add_experimental_option("excludeSwitches", ["enable-logging"])

chrome_options = chrome_options

driver = webdriver.Chrome(driver_url, chrome_options=chrome_options)

contents = driver.page_source

#서울 지역 날씨

if local == "seoul":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=109&x=21&y=6&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

print(w_list)

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

#부산 지역 날씨

elif local == "busan":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=159&x=18&y=12&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

#광주 지역 날씨

elif local == "gwangju":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=156&x=24&y=14&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

#대전 지역 날씨

elif local == "daejun":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=133&x=25&y=11&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

#강원 지역 날씨

elif local == "gwanone":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=105&x=28&y=10&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

#제주도 날씨

elif local == "jeju":

url = f'https://www.weather.go.kr/weather/observation/currentweather.jsp?auto_man=m&stn=0&type=t99&reg=184&x=22&y=0&tm=2021.05.19.08%3A00'

driver.get(url)

contents = driver.page_source

soup = BeautifulSoup(contents, "html.parser")

table = soup.find('table', class_='table_develop3')

w_list = []

for tr in table.find_all('tr'):

tds = list(tr.find_all('td'))

for td in tds:

if td.find('a'):

point = td.find('a').text

temp = tds[5].text

humidity = tds[9].text

print("{0:<7} {1:<7} {2:<7}".format(point,temp,humidity))

w_list.append([point,temp,humidity])

return render_template('weathertest.html', user_id=user_id, name=name, w_list=w_list)

return render_template('weathertest.html', user_id='-1', name='-1')

날씨 정보를 크롤링 하는 코드입니다. selenum과 beautifulsoup4를 사용하여 크롤링 하였습니다.

4. AWS 서버, DB

4.1.1. AWS 인스턴스 생성

AWS ec2 ubuntu 인스턴스 생성

4.1.2. putty

putty를 사용해 AWS의 할당 받은 개인 키로 ubuntu 서버 접속

4.1.3. MySql DB

ubuntu 내의 mysql을 설치 후 데이터 관리.

5. 마무리

5.1. 향후 추친 계획  - 만남의 광장 채팅

현재 채팅 기능은 로그인 한 유저들 끼리 소통할 수 있는 단체 채팅방처럼 구현하였습니다. 향 후 개선사항은 개인 채팅방을 생성해 개개인 유저들 끼리 자유롭게 소통하는 방식을 구현하고 DB를 통해 채팅 내용을 유지 및 관리 할 수 있도록 구현하는 것입니다.

5.1.2. 향후 추친 계획  - 결제 기능

현재 결제 기능은 아임포트를 사용하여 테스트 결제 하는 방식으로 구현하였습니다. 결제 부분에서는 사용자 관점에서의 편의성 개선과, 결제 시스템에 대한 피드백이 필요하므로 멘토링을 준비하여 개선할 계획입니다.