캡스톤디자인 졸업작품 프로젝트 보고서

<< 프로젝트명 : 컴백홈 >>

IT학부 인터넷정보통신과
지도교수	:	유지현 교수님
팀명	:	JOO+1
제출자	:	20172278 정재웅
	:	20172277 이주현
	:	20142461 박주형
제출일	:	2019년 12월 12일

프로젝트 보고서 제출문

프로젝트 명	컴백홈
팀원	정재웅, 이주현, 박주형	팀명	JOO+1
분야	IoT Arduino, Web, App
소속	장안대학 인터넷정보통신과	지도교수	유지현 교수님
주요산출물	프로젝트 계획 1.1 개발배경 1.2 개발목표 1.3 도메인 분석 1.4 개발일정 1.5 예산계획 1.6 개발환경 2. 요구사항 조사 2.1 Usecase Diagram 2.2 Usecase 명세서 3. 프로젝트 분석 3.1 프로젝트 구성도 3.2 Class Diagram 3.3 Sequence Diagram 4. 프로젝트 설계 4.1 메뉴 구조도 4.2 ER Diagram 4.3 화면 설계도 4.4 하드웨어 설계 5. 중심 클래스 구조 및 소스 분석 6. 사용자 메뉴얼
이 보고서를 2019학년도 IT학부 인터넷정보통신과 캡스톤디자인 졸업작품 프로젝트 완료 보고서로 제출합니다. 2019년 12월 18일 프로젝트 담당자 : 정재웅 (인) 이주현 (인) 박주형 (인) 인터넷정보통신과 학과장 귀하

JOO+1

목차

1. 프로젝트 계획

1.1 프로젝트 개요     ·····················································································································    2

1.2 프로젝트 개발목표 ·····················································································································	3

1.3 도메인 분석 ···································································································································    4

1.4 프로젝트 개발일정 ·····················································································································    8

1.5 프로젝트 예산계획 ·····················································································································	9

1.6 프로젝트 개발환경 ·····················································································································	9

2. 요구사항 조사

2.1 Usecase Diagram ·······················································································································	10

2.2 Usecase 명세서 ···························································································································	11

3. 프로젝트 분석

3.1 프로젝트 구성도 ······················································································································	19

3.2 Class Diagram ······················································································································	20

3.3 Sequence Diagram ············································································································	22

4. 프로젝트 설계

4.1 메뉴 구조도 ·····························································································································	28

4.2 ER Diagram ·····························································································································	29

4.3 화면 설계도 ·····························································································································	30

4.4 IoT 하드웨어 설계 ················································································································	33

5. 중심 클래스 구조 및 소스 분석 ············································································      34

6. 구현 화면

6.1 Web  ·················································································································································    52

6.2 App  ··················································································································································    61

7. 참고 자료 및 문헌 ···················································································································    65

·

8. 후기 ·························································································································································    66

9. 소스 CD  ···········································································································································    67

1. 프로젝트 계획

1.1 프로젝트 개요

❏ 프로젝트 필요성

지난 5년간 10만여 건의 실종 신고가 접수됐습니다. 그중 해결되지 못한 장기 실종 건수는 약 600건에 달한다. 지적장애인, 치매 노인에 대한 실종 신고 수도 매해 증가하고 있습니다.

위와 같은 상황이 발생하더라도 즉각적인 조치를 할 수 있도록 위치정보와 이동 경로를 알려주는 장치를 만들었습니다. 그리고 제 3자가 보호대상자를 찾을 수 있게 장치에서 경보음이 울리게 하고, 보호자와 연락을 할 수 있도록 NFC와 QR코드에 보호자의 연락처를 담았습니다.

저희는 보호 대상자가 집으로 무사히 돌아가길 바라는 마음으로 프로젝트 이름을 '컴백홈'이라고 짓게 됐습니다.

1.2 프로젝트 개발목표

❏ 사용자요구사항 정의서

구분	업무	주요 기능
기능적 요구사항	메인화면	회원 로그인, 관리자 로그인, 회원가입 ,고객지원을 이용 할 수 있다. 또한 공지사항을 띄워 이용자들이 확인 할 수 있게 한다.
	고객지원문의	컴백홈에 대해 궁금한 점이 있으면 웹을 통해 문의를 남기고, 그 내용을 관리자가 관리자 페이지에서 볼 수 있다.
	위치조회	컴백홈기기를 부착한 보호 대상자의 위치를 지도를 통하여 시간대별로 확인할 수 있다.
	보호자정보조회	발견자가 보호대상자를 발견해 QR코드를 태그 할 경우 보호자가 미리 작성한 정보(보호자 이름, 연락처, 이메일, 보호대상자의 이름, 메모)를 확인 할 수 있다.
	회원관리	회원의 정보(프로필, 연락처 ,기기정보, 보호자&보호대상자 정보)를 조회 ,변경 할 수 있고 기기 등록 및 위치 조회를 할 수 있다.
	경보음	보호자가 회원관리 페이지에서 버튼을 눌렀을 때 기기에서 소리가 난다.
	웹게시판	보호자와 발견자가 게시판을 통해 정보를 공유 할 수 있다.
	App	휴대폰 화면에 최적화 된 페이지를 제공하면서, 웹페이지의 모든 기능을 담고 있어야 한다.
	IoT	와이파이 연결이 가능해야 하고, GPS와 부저용으로 할당 할 핀이 3개 이상 있어야 한다.
비기능적 요구사항	시스템 성능	최소 사양 - 팬티엄 4 CPU : 3.60GHz - RAM : 8GB - SSD : 250GB
	유지보수	프로그램에 오류가 생길 경우 즉시 관리자에게 연락한다.
	인터페이스	운영체제는 window10을 원장하며 DB는 사용 가능한 SQL 10g을 권장한다.
	신뢰성	- 시스템이 다운되어서는 안 된다. - 시스템은 사용자의 요청에 정확하게 응답 할 수 있어야 한다.
	보안성	미리 등록된 사용자만이 시스템에 접근할 수 있어야 한다.
	가용성	시스템은 점검시간을 제외한 24시간 서비스를 제공해야 한다.

1.3 도메인 분석

❏ 웹 애플리케이션

프레임워크는 말 그대로 ‘뼈대나 바탕을 이루는 코드들의 묶음’이다. 프레임워크 최대 의 장점은 개발에 필요한 구조를 이미 코드로 만들어 놓았기 때문에, 실력이 부족한  개발자라 하더라도 반쯤 완성한 상태에서 필요한 부분을 조립하는 형태의 개발이  가능 하다는 점이다. 회사의 입장에서는 프레임워크를 사용하면 일정한 품질은 보장되는 결과물을 얻을 수 있고, 개발자의 입장에서는 완성된 구조에 자신이 맡은 코드를 개발해서 넣어주는 형태이므로 개발 시간을 단축할 수 있다.

POJO(Plain Old Job Object) 기반의 구성

스프링 내부에는 객체 간의 관계를 구성할 수 있는 특징을 가지고 있다. 스프링은 다른 프레임워크들과 달리 이 관계를 구성할 때 별도의 API 등을 사용하지 않는 POJO의 구성만으로 가능하도록 되어있다. 일반적인 Java 코드를 이용해서 객체를 구성하는 방식 그대로 스프링에서 사용할 수 있다. 이는 개발자가 특정한 라이브러리나 컨테이너의 기술에 종속적이지 않다는 것의 의미한다. 개발자는 가장 일반적인 형태로 코드를 작성하고 실행할 수 있기 때문에 생산성에 유리하고, 코드에 대한 테스트 작업 역시 유연하게 할 수 있다.

2. 트랜잭션 지원

데이터베이스(DB)를 처리할 때 반드시 신경 써야 하는 부분은 하나의 업무가 여러 작업으로 이루어지는 경우의 트랜잭션 처리이다. 이 트랜잭션 처리는 상황에 따라서 복잡하게 구성될 수도 있고, 아닐 수도 있는데, 그때마다 코드를 이용해서 처리하는 작업은 개발자에게는 상당히 피곤한 일이다. 스프링은 이러한 트랜잭션의 관리를 어노테이션이나 XML로 설정할 수 있기 때문에 개발자가 매번 상황에 맞는 코드를 작성할 필요가 없다.

❏ 아두이노 Node MCU

● 아두이노 Node MCU 란?

* NodeMCU는 오픈 소스 IoT 플랫폼입니다. Espressif Systems의 ESP8266 Wi-Fi SoC에서 실       행되는 펌웨어와 ESP-12 모듈 기반의 하드웨어가 포함되어 있다.

* 펌웨어는 Lua 스크립팅 언어를 사용한다.

* 시제품 및 간단한 전자제품 만들 수 있다.

* WIFI가 탑재된 Lua script 개발키트

● Hardware (하드웨어)

* 아두이노 보드에서는 사용자가 작성한 코드가 실행

* 전기신호를 제어하고, 그에 반응만 하는 것이 보드의 역할이며, 결과를 가시화하기 위해서는

부품들을 보드와 연결해야한다.

* 센서를 연결하면 보드를 통해 정보를 받아볼 수 있고, 액츄에이터(LED, 스피커, 모터 등)를

연결해 동작을 나타낼 수 있음

● Software (소프트웨어)

* 기계를 통제하려면 명령어를 통해 컨트롤해야하며, 이러한 과정을 일반적으로 코딩,

입력하는 명령어를 코드라고 부름

* 아두이노는 이러한 코드를 ‘스케치 3’ 이라고 부름

* ‘스케치 3’을 아두이노에 업로드 할 수 있도록 도와주는 프로그램이 아두이노 통합 개발환경         (IDE-Intergrated Development Environment)이다.

❏ NFC

NFC(Near Field Communication)근거리 무선 통신는 13.56MHz의 대역을 가지며, 아주 가까운 거리에서 무선 통신을 하기 위한 기술이다. 현재 지원되는 데이터 통신 속도는 초당 424 킬로비트다. 교통, 티켓, 지불 등 여러 서비스에서 사용할 수 있다.

❏ QR Code

QR(Quick Response) 코드은 흑백 격자무늬 패턴으로 정보를 나타내는 매트릭스 형식의 이차원 바코드이다. QR코드는 주로 한국, 일본, 중국, 영국, 미국 등에서 많이 사용되며 명칭은 덴소 웨이브의 등록 상표 'Quick Response'에서 유래하였다.

❏ 모듈

● GPS모듈 센서 (POS-2001/NEO-6M)

● 피에조 부저 모듈 (piezo buzzer)

● NFC태그                                               ● QR 코드

1.4 프로젝트 개발일정

단계	주차 테스크	5월 4주	6월 1주	6월 2주	6월 3주	6월 4주	7월	8월	9월	10월	11월 1주	11월 2주	11월 3주	11월 4주	12월 1주	12월 2주
계획	요구분석
	업무정의서
	디자인 시안
요구사항	유스케이스 다이어그램
	유스케이스 명세서
분석	클래스다이어그램
	시퀀스 다이어그램
설계	인터페이스 설계
	데이터베이스 설계
구현/테스트	프로그래밍/ 디자인
	테스트 계획 및 결과
완료	사용자매뉴얼
	보고서

1.5 프로젝트 예산계획

구분	소프트웨어 노임단가	투입인원	한달일수	투입기간	금 액(원)
초급 기술자	215,681 원	3 명	28 일	6 개월	108,703,224원
직접인건비 합계					108,703,224원
재경비(직접인건비의 110% ~ 120%)					119,573,546원
기술료([직접인건비 + 재경비]의 20 ~ 40%)					45,655,354원
합 계 (부가세 별도)					273,932,124원

(소프트웨어사업대가산정가이드, 2018 KOSA)

JOO+1팀 가상 예산계획안

1.6 개발환경

1) 하드웨어

구분	하드웨어	비고
CPU	Intel i7-4790 3.6GHz
RAM	16GB
SDD	500Gbyte

2) 소프트웨어

구분	소프트웨어	비고
프로그램 구현	java, jsp, html5, oracle DB, Spring framework, javascript, Bootstrap, apache tomcat 9.0, eclipse, jquery, ajax, arduino
문서작성	한글 2018
운영체제	windows 10

2. 요구사항 조사

2.1 Usecase Diagram

2.2 유스케이스 명세서

❏ ‘공지사항’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190911
유스케이스명	공지사항
개요	관리자는 사용자(보호자)가 볼 수 있게 공지사항을 등록한다. 등록한 공지사항을 보호자는 확인한다.
액터	보호자, 관리자
우선순위	상	중요도	상
		난이도	하
선행조건	컴백홈 홈페이지 or 어플에 들어갈 인터넷이 연결되있어야한다.
후행조건
시나리오
기본 시나리오	관리자는 로그인 후 관리자 페이지를 들어간다. 관리자 페이지에서 공지사항 등록을 누른다. 등록할 내용을 입력 후 등록을 한다. 사용자(보호자는)는 컴백홈 홈페이지 or 어플에 접속한다. 홈페이지 or 어플에서 공지사항을 확인한다.
대안 시나리오
비기능적요구사항	웹페이지는 Windows에 최적화 되어있다.

❏ ‘고객지원 문의’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190911
유스케이스명	고객지원 문의
개요	사용자(보호자)는 홈페이지 or 어플 메인상단에서 고객지원을 클릭 후 문의 창이 뜨면 관리자에게 문의를 보낸다.
액터	보호자, 관리자
우선순위	상	중요도	상
		난이도	하
선행조건	컴백홈 홈페이지 or 어플에 들어갈 인터넷이 연결되있어야한다.
후행조건
시나리오
기본 시나리오	사용자(보호자는)는 컴백홈 홈페이지 or 어플에 접속한다. 메인상단에 고객지원을 눌러 문의 창을 연다. 열린 문의에 문의할 내용을 입력후 확인을 누른다. 관리자는 관리자페이지에서 받은 문의를 확인한다.
대안 시나리오
비기능적요구사항	웹페이지는 Windows에 최적화 되어있다.

❏ ‘회원관리’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190911
유스케이스명	회원관리
개요	보호자는 회원가입과 기기등록을하고 로그인을 통해 가입정보를 확인한다.
액터	보호자
우선순위	상	중요도	상
		난이도	하
선행조건	보호자는 기기를 보유하고 있어야 한다.
후행조건	DB에 가입 정보가 등록 되어야 한다.
시나리오
기본 시나리오	보호자는 홈페이지에서 회원가입 버튼을 누른다. 아이디 및 연락처를 입력한 후 기기 번호를 입력한다. 가입버튼을 누른다. 4. 보호자는 웹페이지에서 로그인 하기 버튼을 누른다 5, 아이디와 패스워드를 입력한다. 6, 로그인 버튼을 누른다.
대안 시나리오	대안 시나리오 - A1기기가 없을때 보호자는 홈페이지에서 회원가입 버튼을 누른다. 2. 아이디 및 연락처를 입력한 후 기기 번호 입력 필드를 비워둔다. 3. 가입버튼을 누른다. 4. 기기가 생겼을 때 로그인 후 마이페이지에서 등록한다.
비기능적요구사항	웹페이지는 Windows에 최적화 되어있다.

❏ ‘위치추적’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190920
유스케이스명	위치추적
개요	보호자는 보호 대상자의 마지막 위치를 웹페이지와 카카오톡 플러스 친구를 통해 조회 할 수 있다.
액터	보호자
우선순위	상	중요도	상
		난이도	중
선행조건	보호자는 회원가입과 기기 등록을 해야하고, 실종자의 위치가 장비를 통해 DB에 저장되어 있어야한다.
후행조건	좌표가 웹페이지의 지도에 표시되어야 한다.
시나리오
기본 시나리오	웹페이지에서 로그인을 한다. 위치확인 버튼을 누른다. 보호대상자의 위치를 확인한다.
대안 시나리오	고객 센터를 통해서 DB관리자가 직접 조회를 한다.
비기능적요구사항

❏ ‘컴백홈 기기등록’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190920
유스케이스명	컴백홈 기기 등록
개요	보호자는 기기 등록을 한다.
액터	보호자
우선순위	상	중요도	상
		난이도	중
선행조건	컴백홈 기기가 있어야한다.
후행조건	컴백홈 기기의 고유 번호를 확인한다.
시나리오
기본 시나리오	웹페이지에서 회원가입을 누른다. 회원가입할 때 기기의 번호를 입력한다.
대안 시나리오	회원가입할 때 기기등록을 안했을경우 회원가입후 로그인을 한다. 로그인후 마이페이지에서 기기등록을 누른다. 기기 번호를 입력해 등록한다.
비기능적요구사항

❏ ‘게시판’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190927
유스케이스명	웹게시판
개요	보호자와 발견자는 웹게시판을 통해 정보를 공유한다.
액터	보호자, 발견자
우선순위	중	중요도	중
		난이도	중
선행조건	웹게시판를 들어갈 인터넷이 연결되있어야한다.
후행조건	QR이나 NFC를 조회할 수 있어야한다. 보호자 게시판은 로그인이 필요하다.
시나리오
기본 시나리오	보호자 게시판 웹페이지에서 로그인을 한다. 웹페이지에서 보호자 게시판을 클릭해 들어간다. 발견자 게시판 QR이나 NFC를 통해 웹페이지에서 보호자의 정보를 확인한다. 2. 웹페이지에서 보호자가 볼 수 있도록 게시판을 이용한다.
대안 시나리오	발견자 게시판 인터넷으로 컴백홈 홈페이지로 직접 들어와 게시판을 이용한다.
비기능적요구사항

❏ ‘보호자 정보 조회’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190927
유스케이스명	보호자 정보 조회
개요	발견자는 보호 대상자의 컴백홈기기를 확인 후 QR 또는 NFC태그를 통해 보호자의 정보를 조회한다.
액터	보호자, 발견자
우선순위	중	중요도	중
		난이도	중
선행조건	스마트폰이 있어야한다.
후행조건	스마타폰 기능중 QR NFC 기능이 있어야 한다.
시나리오
기본 시나리오	보호 대상자를 발견한다. 보호 대상자의 컴백홈기기를 확인하다. 스마트폰을 통해 QR또는 NFC를 조회한다. 조회한 보호자의 정보를 통해 보호자한테 연락을 한다.
대안 시나리오	보호자가 연락을 안 받을 경우 QR,NFC로 들어간 웹페이지에서 게시판을 들어간다. 발견자가 게시판에서 보호 대상자에 대한 정보를 게시판에 등록한다.
비기능적요구사항

❏ ‘경보음’ 유스케이스 명세서

시스템 명	컴백홈
작성자	박주형, 정재웅, 이주현	작성일	20190927
유스케이스명	경보음
개요	보호자는 웹페이지에서 경보음 버튼을 눌러 컴백홈 기기에서 경보음을 발생시킨다. 발견자는 기기에서 나오는 경보음을 통해 보호대상자에게 다가가 도움을 줄 수 있다.
액터	보호자, 발견자
우선순위	중	중요도	중
		난이도	중
선행조건	보호자는 컴백홈기기를 등록시켜야한다.
후행조건	등록한 컴백홈 기기를 보호대상자에게 지니게 한다.
시나리오
기본 시나리오	보호자는 보호대상자가 사라진 것을 확인한다. 웹페이지,어플에 접속해 로그인을 한다. 마이페이지에서 경보음 버튼을 누른다. 발견자는 경보음이 나는 컴백홈기기를 확인한다. 컴백홈기기를 가지고있는 보호대상자에게 도움을 준다.
대안 시나리오	보호대상자가 아닌 사물을 찾을 때 중요한 사물에다가 부착을한다 2. 사물이 사라졌을 때 경보음 버튼을 누른다. 3. 경보음 소리를 듣고 사물을 찾는다.
비기능적요구사항

3. 프로젝트 분석

3.1 프로젝트 구성도

❏ 컴백홈 기기

❏ 프로젝트 시나리오 구성도

3.2 Class Diagram

❏ ‘회원관리’ 클래스 다이어그램

❏ ‘위치 조회 ’ 클래스 다이어그램

❏ ‘관리자 모드’ 클래스 다이어그램

❏ ‘게시판’ 클래스 다이어그램

3.3 Sequence Diagram

❏ 회원가입(보호자)

❏ 로그인(보호자)

❏ 컴백홈 기기 등록

❏ 컴백홈 기기 위치 조회

❏ 게시판

❏ 게시판(글보기, 글쓰기, 글삭제)

4. 프로젝트 설계

4.1 메뉴구조도

❏ 메뉴 구조도 ( 메인 페이지 )

❏ 메뉴 구조도 ( 보호자 )

❏ 메뉴 구조도 ( 관리자 )

4.2 ER Diagram ( 데이터베이스 설계 )

JOO+1

4.3 화면 설계도

JOO+1

❏ 메인 화면 - Web

❏ 마이 페이지 - Web

❏ 컴백홈 기기 위치 조회 - Web

❏ 컴백홈 기기 등록 - Web

❏ 메인 화면 – App	❏ 마이 페이지 - App

❏ 컴백홈 기기 등록 - App	❏ 컴백홈 기기 위치 조회 - App

4.4 IoT 하드웨어 설계

JOO+1

❏ IoT 컴백홈 회로도

WiFi기능이 탑재된 IoT장비인 Node MCU에 GPS 모듈과 부저를 단 모습이다.

❏ GPS조회 및 DB저장

5. 중심클래스 구조 및 소스 분석

5.1 위치 전송 (IoT arduino)

❏ 클래스 개요 :

IoT 기기의 GPS값을 받아 위도, 경도위치를 웹서버로 전송 후 DB에 저장해서                보호자가 웹페이지에서 조회가 가능하다.

❏ 소스 분석

//와이파이통신을 위한 라이브러리호출

#include <ESP8266WiFi.h>

//와이파이로 HTTP 통신을 위한 라이브러리 호츌

#include <ESP8266HTTPClient.h>

//와이파이통신을 위한 라이브러리호출(보드에 내장된 TX RX핀)

#include <SoftwareSerial.h>

//GPS좌표값 계산을 위한 라이브러리 호출

#include <TinyGPS.h>

#ifndef STASSID

#define STASSID "test" //접속할 와이파이ssid

#define STAPSK  "1q2w3e4r" //접속할 와이파이 비밀번호

#endif

const char* ssid = STASSID;

const char* password = STAPSK;

String host = "http://192.168.43.57:8080"; //접속할 웹서버 주소

// 지연시간 설정

const long interval = 5000;

unsigned long previousMillis = 0;

//와이파이 서버와 클라이언트 생성 포트 80사용

WiFiServer server(80);

WiFiClient client;

HTTPClient http;

long lat,lon;

SoftwareSerial gpsSerial(4,5);

TinyGPS gps;

// Create an instance of the server

// specify the port to listen on as an argument

//부저에 할당할 핀번호

int speakerpin = 2;

//부저에서 나타낼 소리의 배열

int note[] = {2093,2349,2637,2093 ,2637,2093,2637, 2349,2637,2793,2793,2637,2349,2793 };

void setup() {

Serial.begin(115200);

gpsSerial.begin(9600);

// 와이파이 접속

Serial.println();

Serial.println();

Serial.print(F("Connecting to "));

Serial.println(ssid);

WiFi.mode(WIFI_STA);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

Serial.println("");

Serial.print("Connecting to ");

Serial.println(ssid);

Serial.print("IP address: ");

Serial.println(WiFi.localIP());

server.begin();

Serial.println("Server started");

}

void loop() {

// gps가 작동하는지 확인

while(gpsSerial.available()){

// gps값 인코딩

if(gps.encode(gpsSerial.read())){

// 위도 경도값 받기

gps.get_position(&lat,&lon);

// 위도경도 값 변수 저장

float realLat = lat;

float realLon = lon;

//위도 경도 표기법 변환

float realrealLat = (realLat /1000000,7);

float realrealLon =(realLon /1000000,7);

//위도경도를 문자형으로 변환

String strLat = String(realLat /1000000,7);

String strLon = String(realLon /1000000,7);

//Serial.print("Position: ");

//Serial.print("lat: ");

Serial.print(realLat/1000000,7);

//Serial.print(" ");// print latitude

//Serial.print("lon: ");

Serial.println(realLon/1000000,7); // print longitude

unsigned long currentMillis = millis();

if(currentMillis - previousMillis >= interval) {

previousMillis = currentMillis;

//특정 웹페이지에 위도경도 값을 전송하기위한 주소 생성

String phpHost = host+"/bbs/location/iamhere.do?dev_no=dev_01&lat="+strLat+"&lon="+strLon;

Serial.print("Connect to ");

Serial.println(phpHost);

//웹페이지에 접속(위도경도값 전송)

http.begin(client, phpHost);

http.setTimeout(1000);

int httpCode = http.GET();

Serial.println(httpCode);

if(httpCode > 0) {

Serial.printf("GET code : %d\n\n", httpCode);

}

else {

Serial.printf("GET failed, error: %s\n",	http.errorToString(httpCode).c_str());

}

http.end();}}}

// 웹서버를 생성하는 부분

WiFiClient client = server.available();

if (!client) {

return;

}

Serial.println(F("new client"));

client.setTimeout(5000); // default is 1000

String req = client.readStringUntil('\r');

Serial.println(F("request: "));

Serial.println(req);

//웹서버를 통해 받은 명령을 처리하는 부분

//부저를 울리는 부분

int val;

if (req.indexOf(F("/gpio/0")) != -1) {

val = 0;

int elementCount = sizeof(note) / sizeof(int);

for(int i=0; i<10; i++ ){

for (int i=0; i < elementCount; i++)   //note 을  play

{

tone(speakerpin,note[i],500);

delay(300);

}

delay(300);

}

} else if (req.indexOf(F("/gpio/1")) != -1) {

val = 1;

} else {

Serial.println(F("invalid request"));

val = digitalRead(LED_BUILTIN);

}

// Set LED according to the request

digitalWrite(LED_BUILTIN, val);

// read/ignore the rest of the request

//웹서버의 페이지를 구성하는 부분

// do not client.flush(): it is for output only, see below

while (client.available()) {

// byte by byte is not very efficient

client.read();

}

// Send the response to the client

// it is OK for multiple small client.print/write,

// because nagle algorithm will group them into one single packet

client.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n

<!DOCTYPE HTML>\r\n<html>"));

client.print(F("<a href='http://"));

client.print(WiFi.localIP());

client.print(F("/gpio/0'>call</a></html>"));

// The client will actually be *flushed* then disconnected

// when the function returns and 'client' object is destroyed(out-of-scope)

// flush = ensure written data are received by the other side

Serial.println(F("Disconnecting from client"));

}

5.2 위치조회 (Web, App)

❏ 클래스 개요 :

IoT기기에서 받은 GPS위치값을 조회하여 IoT기기의 위치를 조회할 수 있어

보호대상자에게 지니게해서 실시간으로 보호대상자의 위치를 알 수 있다.

❏ 소스 분석

<div class="caption">

<div class="table-box-wrap">

<div class="table-box">

<table class="table table-bordered table-hover sticky-header">

<thead>

<tr>

<th>기기번호</th>

<th>위도</th>

<th>경도</th>

<th>수신시간</th>

<th>위치조회</th>

</tr>

</thead>

<tbody>

<c:if test="${!empty location }">

<c:forEach var="loc" items="${Location}">

<tr>

<td>${loc.dev_no}</td>

<td>${loc.lat}</td>

<td>${loc.lon}</td>

<td>${loc.time}</td>

<td><a onclick="javascript:markertTest(${loc.lat},${loc.lon})">조회</a>

</td>

</tr>

</c:forEach>

</c:if>

</tbody>

</table>

</div>

</div>

<div class="container-fluid"

style="text-align: center; margin-top: 15px;">

<div style="float: right;">

<a onclick="polyline.setMap(map)">선 생성&nbsp</a> <a

onclick="polyline.setMap(null)">선 숨기기&nbsp</a> <a

onclick="hideMarkers()">모든 마커 삭제</a>

</div>

<!-- 지도를 표시할 div 입니다 -->

<div id="map" style="width: 100%; height: 670px;"></div>

<p>

<!-- <a onclick="polyline.setMap(map)"> 선 생성</a>-->

<!--<a onclick="polyline.setMap(null)"> 선 숨기기</a>

<a onclick="setMarkers(null)">모든 마커 숨기기</a>-->

</p>

<br>

<script>

<!-- 위도와 경도를 받아올 배열 생성-->

var Newlat= new Array();

var Newlon= new Array();

<!-- 위도와 경도 배열에 기입-->

<c:forEach var="loc" items="${Location}">

Newlat.push(${loc.lat});

Newlon.push(${loc.lon});

</c:forEach>

<!-- 지도생성-->

var mapContainer = document.getElementById('map'), // 지도를 표시할 div

mapOption = {

center : new kakao.maps.LatLng(Newlat[Newlat.length - 1],Newlon[Newlon.length – 1]),

// 지도의 중심좌표

level : 3

// 지도의 확대 레벨

};

var map = new kakao.maps.Map(mapContainer, mapOption); // 지도를 생성합니다

kakao.maps.event.addListener(map, 'click', function(mouseEvent) {

// 클릭한 위치에 마커를 표시합니다

addMarker(mouseEvent.LatLng(

m1, m2));

});

var markers = [];

<!-- 마커 생성-->

function markertTest(m1, m2) {

// 마커가 표시될 위치입니다

var markerPosition = new kakao.maps.LatLng(

m1, m2);

// 마커를 생성합니다

var marker = new kakao.maps.Marker({

position : markerPosition

});

// 마커가 지도 위에 표시되도록 설정합니다

marker.setMap(map);

markers.push(marker);

}

<!-- 마커를 여러개 생성하기위한 메소드-->

function setMarkers(map) {

for (var i = 0; i < markers.length; i++) {

markers[i].setMap(map);

}

}

// "마커 감추기" 버튼을 클릭하면 호출되어 배열에 추가된 마커를 지도에서 삭제하는 함수입니다

function hideMarkers() {

setMarkers(null);

}

var iwContent = '<div style="padding:5px;">최종위치</div>',

// 인포윈도우에 표출될 내용으로 HTML 문자열이나 document element가 가능합니다

iwPosition = new kakao.maps.LatLng(Newlat[Newlat.length - 1],Newlon[Newlon.length – 1]),

//인포윈도우 표시 위치입니다

iwRemoveable = true;

// removeable 속성을 ture 로 설정하면 인포윈도우를 닫을 수 있는 x버튼이 표시됩니다

// 인포윈도우를 생성하고 지도에 표시합니다

var infowindow = new kakao.maps.InfoWindow({

map: map, // 인포윈도우가 표시될 지도

position : iwPosition,

content : iwContent,

removable : iwRemoveable

});

// 선을 구성하는 좌표 배열입니다. 이 좌표들을 이어서 선을 표시합니다

var linePath = [

<c:forEach var="loc" items="${Location}">

new kakao.maps.LatLng(${loc.lat}, ${loc.lon}),

</c:forEach>

];

// 지도에 표시할 선을 생성합니다

var polyline = new kakao.maps.Polyline({

path: linePath, // 선을 구성하는 좌표배열 입니다

strokeWeight: 5, // 선의 두께 입니다

strokeColor: '#FFAE00', // 선의 색깔입니다

strokeOpacity: 0.7, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다

strokeStyle: 'solid' // 선의 스타일입니다

});

var positions = [

{

title: '카카오',

latlng: new kakao.maps.LatLng(Newlat[Newlat.length - 1],Newlon[Newlon.length - 1])

}

];

/*

// 마커 이미지의 이미지 주소입니다

var imageSrc = "http://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png";

for (var i = 0; i < positions.length; i ++) {

// 마커 이미지의 이미지 크기 입니다

var imageSize = new kakao.maps.Size(24, 35);

// 마커 이미지를 생성합니다

var markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);

// 마커를 생성합니다

var marker = new kakao.maps.Marker({

map: map, // 마커를 표시할 지도

position: positions[i].latlng, // 마커를 표시할 위치

title : positions[i].title, // 마커의 타이틀, 마커에 마우스를 올리면 타이틀이 표시됩니다

image : markerImage // 마커 이미지

});

}

*/

</script>

</div>

</div>

5.3 위치 조회

❏ 클래스 명 : LocationController.java

❏ 클래스 개요 :

등록된 컴백홈 기기의 위치를 저장, 조회하는 클래스

❏ 소스 분석

@Controller

@RequestMapping("/location")

public class LocationController {

@Autowired

private LocationService locationService;

@Autowired

private LoginService loginService;

// 위치 조회

//위치조회 페이지 매핑

@RequestMapping(value = "/location_list.do", method = RequestMethod.GET)

public String Location

(@ModelAttribute("location") Location location, Model model, HttpSession session)

throws Exception {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId); //사용할 VO 파일 정의

if (loginUser == null) { // 회원이 아닐 경우

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);

return "/member/login"; //로그인 페이지 이동

}

model.addAttribute("userVO", loginUser); //사용자의 아이디 조회

session.setAttribute("dev_no", loginUser.getDev_no()); //사용자의 등록 기기코드 조회

List<Location> loc = locationService.getLocation(location); // 조회된 GPS좌표 조회

model.addAttribute("Location", loc);

return "location/location_list"; //위치조회 페이지 이동

}

// 위치 저장

@RequestMapping(value = "/iamhere.do", method = RequestMethod.GET)// 위치저장 페이지 매핑

public String insertLoc(@ModelAttribute("location") Location location, HttpSession session,

HttpServletRequest request) throws Exception {

this.locationService.insertLoc(location); // 해당 기기의 위치 실시간 저장

return "home";

}

// 모바일 위치조회

//모바일 위치조회 페이지매핑

@RequestMapping(value = "/m.location_list.do", method = RequestMethod.GET)

public String mLocation

(@ModelAttribute("location") Location location, Model model, HttpSession session)

throws Exception {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId); //사용할 VO 파일 정의

if (loginUser == null) { // 회원이 아닐 경우

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);

return "/mobile/mlogin"; // 로그인 페이지로 이동

}

model.addAttribute("userVO", loginUser); //사용자의 아이디 조회

session.setAttribute("dev_no", loginUser.getDev_no()); //사용자의 등록 기기코드 조회

List<Location> loc = locationService.getLocation(location); // 조회된 GPS좌표 조회

model.addAttribute("Location", loc);

return "location/mlocation_list"; //모바일 위치조회 페이지 이동

}

❏ 클래스 명 : LoginController.java

❏ 클래스 개요 :

사용자의 회원관리를 하는 클래스

❏ 소스 분석

@Controller

@RequestMapping("/member/*")

public class LoginController {

@Autowired

private LoginService loginService;

// 로그인

@RequestMapping(value = "/login.do", method = RequestMethod.GET) //로그인 페이지 매핑

public String login() {

return "/member/login"; //로그인 페이지 이동

}

@RequestMapping(value = "/loginSuccess.do", method = RequestMethod.GET)

public String loginProc() {

return "/member/loginSuccess";

}

@RequestMapping(value = "/loginSuccess.do", method = RequestMethod.POST)

public String loginProc

(@Valid UserVO userVO, BindingResult result, Model model, HttpSession session) {

if (result.hasFieldErrors("userId") || result.hasFieldErrors("passwd")) {

model.addAllAttributes(result.getModel()); // 로그인 실패시 다시 로그인창으로 이동

return "/member/login";

}

UserVO loginUser = this.loginService.getUser(userVO.getUserId()); // 유저 id 조회

userVO.setPasswd(BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12)));

if (loginUser == null) {

model.addAttribute("userId", "");

model.addAttribute("errCode", "1");

return "/member/login";

} else if (BCrypt.checkpw(userVO.getPasswd(), loginUser.getPasswd())) { // 암호화된 패스워드 비교

model.addAttribute("loginUser", loginUser);

session.setAttribute("userId", loginUser.getUserId());

session.setAttribute("passwd", loginUser.getPasswd());

session.setAttribute("dev_no", loginUser.getDev_no());

session.setAttribute("userName", loginUser.getName()); // 세션에 변수등록

return "/member/loginSuccess";

} else {

model.addAttribute("passwd", "");

model.addAttribute("errCode", 4);// 패스워드 불일치

return "/member/login"; // 다시 로그인창으로 이동

}}

// 로그아웃

@RequestMapping("/logout.do")

public String logout(HttpSession session) {

session.invalidate(); // 로그아웃 세션

return "redirect:/member/login.do"; // 로그인 창으로 이동

}

// 회원가입

@RequestMapping(value = "/joinForm.do", method = RequestMethod.GET)

public String joinForm(Model model) { // 회원가입 페이지 매핑

model.addAttribute("userVO", new UserVO()); // 사용할 VO 파일 정의

return "/member/joinForm"; //회원가입 페이지 이동

}

@RequestMapping(value = "/checkid.do", method = RequestMethod.GET) // 아이디 중복체크

public String dupCheckId(@RequestParam("userId") String userId, Model model) {

String message = "";

int reDiv = 0;

System.out.println(userId);

UserVO loginuser = this.loginService.getUser(userId);

System.out.println(loginuser.getUserId());

if (loginuser.getUserId().equals(userId)) {

message = "이미 사용된 아이디 입니다";

userId = "";

reDiv = 1;

} else {

reDiv = 1;

message = "사용 가능한 아이디 입니다";

}

model.addAttribute("message", message);

model.addAttribute("reDiv", reDiv);

model.addAttribute("userId", userId);

return "/member/joinSuccess";

}

@RequestMapping(value = "/joinForm.do", method = RequestMethod.POST)

public String joinSubmit

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if (result.hasErrors()) {

model.addAllAttributes(result.getModel());

return "/member/joinForm";

} // passwd 암호화

String hashPass = BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12));

userVO.setPasswd(hashPass); // 암호화된 passwd 로 변경

System.out.println(userVO.toString());

if (this.loginService.insertUser(userVO) != 0) {

model.addAttribute("userVO", userVO);

model.addAttribute("errCode", 3);// 등록성공

return "/member/login";

} else {

model.addAttribute("errCode", 5);// 등록실패

return "/member/joinForm";

}}

// 정보 수정

@RequestMapping(value = "/edituser.do", method = RequestMethod.GET) // 정보 수정 페이지 매핑

public String toUserEditView(HttpServletRequest request, HttpSession session, Model model) {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId); //사용할 VO 파일 정의

if (loginUser == null) {

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);// 등록되지않은 아이디

return "/member/login";

}

model.addAttribute("userVO", loginUser);

System.out.println(loginUser.toString());

return "/member/editForm";  // 정보 수정 페이지 이동

}

@RequestMapping(value = "/edituser.do", method = RequestMethod.POST)

public String onEditSave

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if (result.hasErrors()) {

model.addAllAttributes(result.getModel());

return "/member/editForm";

}

System.out.println(userVO.getPasswd());

userVO.setPasswd(BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12)));  //암호화 패스워드 비교

System.out.println(userVO.getName() + userVO.getUserId());

System.out.println(userVO.getPasswd());

if (this.loginService.updateUser(userVO) != 0) {

model.addAttribute("userVO", userVO);

model.addAttribute("errCode", 3);// 등록성공

model.addAttribute("message", "다음과 같이 사용자 정보를 수정하였습니다.");

return "/member/loginSuccess";

} else {

model.addAttribute("errCode", 5);// 등록실패

model.addAttribute("errMsg", "사용자정보 수정에 실패하였습니다.");

return "/member/editForm";

}}

// 기기코드 저장

@RequestMapping(value = "/updateLoc.do", method = RequestMethod.GET) //기기코드 페이지 매핑

public String updateLoc(HttpServletRequest request, HttpSession session, Model model) {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId);  // 사용할 VO 파일 정의

if (loginUser == null) { // 기기코드 중복 체크

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);// 등록되지않은 아이디

return "/member/mypage";

}

model.addAttribute("userVO", loginUser);

System.out.println(loginUser.toString());

return "/member/updateLoc";

}

@RequestMapping(value = "/updateLoc.do", method = RequestMethod.POST) //기기코드 재등록

public String updateLocOn

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if (result.hasErrors()) {

model.addAllAttributes(result.getModel());

return "/member/updateLoc";

}

System.out.println(userVO.getPasswd());

userVO.setPasswd(BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12)));

System.out.println(userVO.getName() + userVO.getUserId());

System.out.println(userVO.getPasswd());

if (this.loginService.updateLoc(userVO) != 0) {

model.addAttribute("userVO", userVO);

model.addAttribute("errCode", 3);// 등록성공

model.addAttribute("message", "다음과 같이 사용자 정보를 수정하였습니다.");

return "/member/loginSuccess";

} else {

model.addAttribute("errCode", 5);// 등록실패

model.addAttribute("errMsg", "사용자정보 수정에 실패하였습니다.");

return "/member/updateLoc";

}}

// 보호자 조회

@RequestMapping(value = "/LocUser.do", method = RequestMethod.GET) //QR보호대상자 조회

public String LocUser(@ModelAttribute("UserVO")

UserVO userVO, Model model, HttpSession session) throws Exception {

List<UserVO> loc = loginService.getLocUser(userVO); // 사용할 VO파일 정의

model.addAttribute("UserVO", loc);

return "member/LocUser";

}

//보호자 정보 조회 수정

@RequestMapping(value = "/updateLocUser.do", method = RequestMethod.GET)

public String updateLocUser(HttpServletRequest request, HttpSession session, Model model) {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId); // 사용할 VO 파일 정의

if (loginUser == null) {

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);// 등록되지않은 아이디

return "/member/mypage";

}

model.addAttribute("userVO", loginUser);

System.out.println(loginUser.toString());

return "/member/updateLocUser";

}

@RequestMapping(value = "/updateLocUser.do", method = RequestMethod.POST)

public String updateLocUserOn

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if (result.hasErrors()) {

model.addAllAttributes(result.getModel());

return "/member/updateLocUser";

}

System.out.println(userVO.getPasswd());

userVO.setPasswd(BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12)));

System.out.println(userVO.getName() + userVO.getUserId());

System.out.println(userVO.getPasswd());

if (this.loginService.updateLocUser(userVO) != 0) {

model.addAttribute("userVO", userVO);

model.addAttribute("errCode", 3);// 등록성공

model.addAttribute("message", "다음과 같이 사용자 정보를 수정하였습니다.");

return "/member/loginSuccess";

} else {

model.addAttribute("errCode", 5);// 등록실패

model.addAttribute("errMsg", "사용자정보 수정에 실패하였습니다.");

return "/member/updateLocUser";

}}

// id 찾기

@RequestMapping(value = "/findId.do", method = RequestMethod.GET) //id찾기 페이지 매핑

public String findId(Model model) {

return "/member/findId"; // id찾기 페이지 이동

}

@RequestMapping(value = "/findId.do", method = RequestMethod.POST)

public String findId

(@Valid UserVO userVO, BindingResult result, Model model, HttpSession session) {

if (result.hasFieldErrors("name") || result.hasFieldErrors("email")) { //이름, 이메일 입력

model.addAllAttributes(result.getModel());

return "/member/findId";

}

UserVO loginUser = this.loginService.findId(userVO); // 사용할 VO 파일 정의

if (loginUser == null) { // 이름, 이메일이 다를시 다시 id찾기 페이지로 이동

model.addAttribute("errCode", 1);

return "/member/findId";

} else {  // 입력한 이름, 이메일 조회

model.addAttribute("userId", loginUser.getUserId());

model.addAttribute("userName", loginUser.getName());

model.addAttribute("errCode", 4);

return "/member/findIdSuccess";

}}

// 비번 찾기

@RequestMapping(value = "/findPass.do", method = RequestMethod.GET)// 비밀번호 찾기 페이지

public String findPass(Model model) {

return "/member/findPass";

}

@RequestMapping(value = "/editPass.do", method = RequestMethod.GET)

public String onEditpass

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if(result.hasFieldErrors("userId") || result.hasFieldErrors("name") || result.hasFieldErrors("email")) {

model.addAllAttributes(result.getModel());

return "/member/findPass";

}

UserVO loginuser = this.loginService.findPass(userVO); // 사용할 VO 파일 정의

if (loginuser == null) { // 입력한 아이디, 이름, 이메일이 틀릴시 비밀번호 찾기 페이지로 이동

model.addAttribute("errCode", 1);

model.addAttribute("userId");

return "/member/findPass";

} else { // 입력한 아이디, 이름, 이메일 조회

model.addAttribute("userId", loginuser.getUserId());

model.addAttribute("email", loginuser.getEmail());

model.addAttribute("name", loginuser.getName());

System.out.println(loginuser.toString());

return "/member/editPass"; // 입력한 정보가 조회될시  비밀번호 변경페이지로 이동

}}

@RequestMapping(value = "/editPass.do", method = RequestMethod.POST)

public String onEditpassSave

(@Valid UserVO userVO, BindingResult result, Model model) throws Exception {

if (result.hasFieldErrors("userId") || result.hasFieldErrors("email")) {

model.addAllAttributes(result.getModel());

System.out.println("result 오류!");

return "/member/editPass";

}

userVO.setPasswd(BCrypt.hashpw(userVO.getPasswd(), BCrypt.gensalt(12))); //패스워드 암호화

try {

loginService.updatePass(userVO); // 사용할 VO파일 정의

System.out.println(userVO.toString());

return "/member/editPass"; // 입력한 패스워드 재등록

} catch (DataAccessException e) {

result.reject("error.duplicate.user");

model.addAllAttributes(result.getModel());

return "/member/editPass";

}}

//마이페이지

@RequestMapping(value = "/mypage.do", method = RequestMethod.GET)

public String mypage(HttpServletRequest request, HttpSession session, Model model) {

String userId = session.getAttribute("userId").toString();

UserVO loginUser = this.loginService.getUser(userId); // 사용할 VO파일 정의

if (loginUser == null) {

model.addAttribute("userId", "");

model.addAttribute("errCode", 1);// 등록되지않은 아이디

return "/member/loginSuccess";

}

model.addAttribute("userVO", loginUser);

session.setAttribute("userName", loginUser.getName());

System.out.println(loginUser.toString());

return "/member/mypage";

}}

6. 구현 화면

6.1 Web

❏ 메인페이지

1. 상단에 공지사항을 누르면 공지사항을 볼 수 있고 게시판을 누르면 게시판으로 이동한다.

2. 오른쪽 상단에 MORE에 회원가입과 로그인을 할 수 있는 페이지로 이동한다.

3. 고객지원을 누르면 문의를 할 수 있는 창이 띄어짐

❏ 고객지원 문의

1. 해당 데이터를 입력 후 버튼을 누르면 관리자에게 문의를 보낼 수 있다.

❏ 회원가입 페이지

1. 해당 데이터를 입력 후 버튼을 누르면 회원가입 완료

❏ 로그인

1. 아이디와 비밀번호를 입력 후 로그인을 누르면 마이 페이지로 이동한다.

2. 아이디찾기, 비밀번호찾기를 누르면 찾기 페이지로 이동한다.

3. 회원가입을 누르면 회원가입 페이지로 이동한다.

❏ 마이페이지

1. 로그인 후 마이페이지 화면

2. 개인 연락처에 정보 수정을 누르면 연락처 수정 페이지로 이동

3. 보호 대상자 정보 수정을 누르면 보호대상자 수정 페이지로 이동

4. 기기등록을 누르면 등록페이지로 이동

5. 기기 위치 조회를 누르면 실시간 위치를 알 수 있는 페이지로 이동

6. 경보음 버튼을 누르면 기기에서 경보음이 발생

❏ 정보수정

1. 개인 정보를 다시 등록 할 수 있다.

❏ 보호 대상자 정보 입력

1. 보호 대상자의 정보와 메모를 등록할 수 있다.

❏ 기기 등록(보호자)

1. 기기코드를 입력 후 버튼을 눌러 등록할 수 있다.

❏ 컴백홈 기기 위치 조회

1. 기기의 실시간 좌표와 좌표시간을 알 수 있다.

2. 지도를 통해 실시간 위치 마커와 이동거리를 알 수 있다.

❏ 게시판 목록

1. 게시판을 통해 발견자가 올린 글을 확인 할 수 있다.

2. 검색을 통해 본인의 보호 대상자에 대한 글을 바로 확인 할 수 있다.

❏ 게시판 글보기

❏ 게시판 글쓰기

❏ QR 페이지 조회

1. 발견자가 컴백홈 기기에 있는 QR코드를 조회 합니다.

2. 발견자는 QR코드를 통해 보호대상자의 정보를 조회 할 수 있습니다.

❏ 로그인(관리자)

1. 관리자 아이디와 비밀번호를 입력 후 로그인을 누르면 관리자 페이지로 이동한다.

❏ 관리자 페이지

1. 관리자는 모든 회원의 정보 관리가 가능하다.

2. 관리자는 고객들이 보낸 문의를 확인할 수 있다.

❏ 회원상세정보(관리자)

1. 회원번호를 누르면 회원의 상세정보를 볼 수 있다.

❏ 회원등록 기기 위치조회

1. 회원기기번호를 누르면 회원기기의 위치를 조회 할 수 있다.

6.2 App

❏ 메인페이지	❏ 고객지원 문의

❏ 회원가입 페이지	❏ 로그인

❏ 마이페이지

❏ 컴백홈 기기 위치 조회	❏ QR페이지 확인

❏ 게시판 목록

❏ 게시판 글쓰기	❏ 게시판 글보기

❏ 관리자페이지

❏ 회원상세정보	❏ 등록된기기 위치조회

7. 참고 자료 및 문헌

참고 자료 및 문헌

제목	저자	출판사
스프링 부트로 배우는 자바 웹 개발	윤석진	제이펍
아두이노를 이용한 사물인터넷 기초부터 실무까지	김경희	동일출판사

2. 참고 사이트

https://www.youtube.com

https://okky.kr/

https://github.com/

8. 프로젝트 후기

	팀장으로서 막중한 책임을 부여받고 많은 부담감과 압박감을 느꼈지만, 팀원들이 많은 부분을 도와주고 잘 따라와 준 덕분에 저 자신도 책임감을 느끼고 열심히 했습니다. 비록 부족한 부분이 많을지도 모르지만 많은 것을 배웠고, 새로운 경험을 하게 돼서 즐거웠습니다.
정재웅
	처음 프로젝트를 진행하는 데 있어 막막하고 어려웠지만 의견을 모아 여러 가지 시도를 해보고, 그 상황을 극복해 나가는 과정이 재미있었습니다. 덕분에 새로운 지식을 배우게 됐고, 이것이 나중에 큰 도움이 되리라 생각합니다.
박주형
	프로젝트를 시작할 때 “과연 이걸 우리가 구현할 수 있을까?” 라는 걱정을 했었습니다. 모르는 부분에 대하여 팀원들과 밤낮으로 고민하며 자료를 찾아봤고, 교수님들의 조언도 받았습니다. 그 덕분에 프로젝트를 순조롭게 진행할 수 있었고, 그럴수록 실력이 많이 향상되고 있다는 것을 느꼈습니다. 어려웠고 험난한 과정들이었지만 그만큼 많은 것을 배우고 생각하게 되는 좋은 경험이었습니다.
이주현

9. 참고 자료 및 소스 CD

JOO+