머지?
2020-10-01 ~ 2021-05-25
Spring BootAndroidTensorFlow Lite
[개요]
- 2021년도 컴퓨터공학부 졸업작품발표회
- 식품 인식 및 영양 정보 제공을 위한 통합 플랫폼으로, Android 모바일 애플리케이션과 Spring Boot 기반 백엔드 서버, TensorFlow Lite를 활용한 온디바이스 머신러닝으로 구성된 풀스택 애플리케이션입니다. 사용자는 카메라를 통해 식품을 촬영하면 실시간으로 제품을 인식하고, 상세한 영양 정보와 리뷰를 확인할 수 있습니다.
[사용 기술 스택]
- Infra
- 개발 환경 : Android Studio, IntelliJ IDEA
- 빌드 도구 : Gradle
- 버전 관리 : Git
- BE
- 개발 환경 : IntelliJ IDEA
- 빌드 도구 : Gradle
- 프레임워크 : Spring Boot (2.4.4)
- DB : MySQL, H2 (개발용)
- 데이터 접근 : JPA (Hibernate)
- 보안 : Spring Security, JWT (jjwt 0.9.0)
- 검증 : Spring Boot Validation
- 모니터링 : Spring Boot Actuator
- FE (Android)
- 개발 환경 : Android Studio
- 빌드 도구 : Gradle (4.1.3)
- 언어 : Kotlin (1.5.0-RC), Java
- 최소 SDK : 26 (Android 8.0)
- 타겟 SDK : 30 (Android 11)
- UI 프레임워크
- Android SDK
- Material Design Components
- Data Binding
- 네트워킹
- Retrofit (2.9.0): RESTful API 통신
- PersistentCookieJar: 세션 쿠키 관리
- 이미지 처리 : Glide (4.11.0): 이미지 로딩 및 캐싱
- 번역
- Google Cloud Translate API: 실시간 번역 기능
- Apache Commons Text: HTML 이스케이프/언이스케이프 처리
- 지역화 : Akexorcist Localization Library: 다국어 지원
- 라이프사이클 : Lifecycle ViewModel, LiveData
- ML
- 프레임워크 : TensorFlow Lite (2.4.0)
- 모델
- ramen.tflite (라면 분류)
- snack.tflite (과자 분류)
- drink.tflite (음료 분류)
- dairy.tflite (유제품 분류)
- icecream.tflite (아이스크림 분류)
- 추론 환경 : Android 온디바이스 추론
- 입력 크기 : 640x640 픽셀
- 출력 : Object Detection (위치, 클래스, 점수)
[주요 담당 기능]
- BE
- 사용자 인증
- JWT 기반 인증 시스템 구현
- Spring Security를 활용한 보안 설정
- 쿠키 기반 토큰 전달로 클라이언트-서버 통신 보안 강화
- 토큰 유효기간 관리 (1시간)
- 제품 관리
- 제품 정보 CRUD 기능
- 제품 중복 검증 로직
- 제품 검색 기능 (ID, 이름 기반)
- 영양 정보 관리 (칼로리, 탄수화물, 단백질, 지방 등)
- 리뷰 관리
- 리뷰 작성, 수정, 조회 기능
- 제품별 리뷰 조회
- 회원-리뷰 연관관계 관리
- 예외 처리
- 전역 예외 처리 핸들러 구현
- 도메인별 커스텀 예외 클래스 (MemberException, ProductException, ReviewException)
- 일관된 에러 응답 형식 제공
- API 설계
- RESTful API 원칙 준수
- DTO를 통한 요청/응답 데이터 구조화
- HTTP 상태 코드 적절한 활용
- FE (Android)
- 사용자 인증
- 로그인/회원가입 기능
- 자동 로그인 기능 (AutoLogin)
- JWT 기반 세션 관리
- 제품 관리
- 제품 목록 조회
- 제품 상세 정보 표시 (영양 정보 포함)
- 제품 검색 기능
- Fragment를 활용한 제품 정보/리뷰 탭 구성
- 리뷰 기능
- 리뷰 작성 및 수정
- 제품별 리뷰 목록 조회
- RecyclerView를 활용한 리뷰 리스트 표시
- 다국어 지원
- 11개 언어 지원 (한국어, 영어, 일본어, 중국어, 스페인어, 힌디어, 태국어, 베트남어, 필리핀어, 우즈베크어)
- Google Cloud Translate API를 통한 실시간 번역
- 지역화된 문자열 리소스 관리
- 네트워크 통신
- Retrofit을 활용한 RESTful API 통신
- ViewModel과 LiveData를 활용한 비동기 데이터 처리
- 에러 핸들링 및 사용자 피드백 제공
[트러블슈팅 & 문제 해결]
- BE
- JWT 검증 실패 문제
- 클라이언트에서 전송된 토큰이 서버에서 검증되지 않는 문제 발생
- 쿠키 인코딩/디코딩 과정에서 발생하는 문제
- URL 인코딩을 통한 쿠키 값 처리 및 토큰 파싱 로직 개선
- 제품 중복 저장 문제
- 동일한 제품이 여러 번 저장되는 문제 발생
- 제품명 기반 중복 검증 로직 추가 및 예외 처리
- 시간대 불일치 문제
- 데이터베이스와 애플리케이션 간 시간대 불일치
- JPA 설정 및 데이터베이스 TimeZone 설정 통일
- FE
- 다국어 지원 구현
- 앱 내 언어 변경 시 일부 리소스가 갱신되지 않는 문제
- Localization 라이브러리 도입 및 Activity 재시작 로직 구현
[성과]
- 실시간 제품 인식 : 카메라를 통한 즉각적인 제품 인식으로 사용자 편의성 향상
- 온디바이스 ML 추론 : 서버 의존 없이 오프라인에서도 제품 인식 가능
- 다국어 지원 : 11개 언어 지원으로 글로벌 사용자 확대 가능
- MVVM 아키텍처 : 코드 구조화 및 유지보수성 향상
- 실시간 번역 : Google Cloud Translate API를 활용한 동적 콘텐츠 번역
[주요 화면]
- 로그인/회원가입
- 카메라 제품 인식
- 카테고리 선택 후 카메라 촬영
- 실시간 ML 추론 결과 표시
- 제품 목록
- 제품 상세 정보
- 리뷰 작성/수정
[아키텍처 구조]
+-------------------+ +-------------------+ +-------------------+
| | | | | |
| Android 클라이언트 |<----->| 백엔드 서버 |<----->| 데이터베이스 |
| (android-merge) | | (server-merge) | | (MySQL/H2) |
| | | | | |
+---------+---------+ +-------------------+ +-------------------+
|
| (온디바이스 ML 추론)
|
+---------v---------+
| |
| TensorFlow Lite |
| 모델 |
| (dairy, drink, |
| icecream, ramen, |
| snack.tflite) |
+-------------------+
Android 아키텍처 (MVVM)
Activity/Fragment (View)
↓
ViewModel
↓
Repository/Network Service
↓
Retrofit API
↓
Backend Server
Backend 아키텍처
Controller Layer
↓
Service Layer
↓
Repository Layer (JPA)
↓
Database
[ERD]
Member
├── id (PK)
├── name
└── password
Product
├── id (PK)
├── name
├── code
├── image_name
├── manufacturer
├── kind
├── serving_per_container
├── energe (칼로리)
├── carbohydrate
├── dietary_fiber
├── sugar
├── protein
├── total_fat
├── saturated_fat
├── trans_fat
├── cholesterol
├── sodium
├── calcium
└── iron
Review
├── id (PK)
├── date
├── productId (FK → Product)
├── memberId (FK → Member)
└── reviewBody
[회고]
- Best Practice
- MVVM 아키텍처 적용 : View와 비즈니스 로직 분리로 코드 가독성 및 테스트 용이성 향상
- RESTful API 설계 : 일관된 API 구조로 프론트엔드-백엔드 협업 효율성 증대
- JWT 기반 인증 : Stateless 인증으로 서버 확장성 확보
- 다국어 지원 : 지역화된 리소스와 실시간 번역을 통한 글로벌 사용자 지원
- 예외 처리 체계화 : 도메인별 예외 클래스 및 전역 예외 핸들러로 에러 처리 일관성 유지
- DTO 패턴 활용 : 요청/응답 데이터 구조화로 API 계약 명확화
- Lesson Learned
- 프로젝트 초기 설계의 중요성 : 아키텍처와 패키지 구조를 미리 설계하지 않아 프로젝트가 커지면서 파일 탐색이 어려워짐. 다음 프로젝트에서는 도메인 중심 패키지 구조를 적용하고자 함
- 테스트 코드 작성 : 단위 테스트 및 통합 테스트 부재로 리팩토링 시 안정성 확보가 어려웠음. TDD 접근법 도입 검토 필요
- 버전 관리 : 브랜치 전략 및 커밋 메시지 컨벤션 미준수로 히스토리 관리가 어려웠음. Git Flow 등 브랜치 전략 도입 필요
[참고 자료]