신세계아이앤씨 JAVA 기반 백엔드 개발자 과정 2차 프로젝트
🖥️프로젝트 소개 : Effitopia
Effitopia는 B2B 창고 관리 시스템(WMS) 개발 프로젝트 입니다. WMS(Warehouse Management System)란 창고 내 재고를 효율적으로 관리하고, 입고부터 배송까지 신뢰성 있는 물류 운영을 지원하는 시스템으로 이 시스템의 이상향을 실현하는 것을 목표로 하였습니다.
깃허브
https://github.com/HongYong-Woo/WMS_Miniproject2
📅프로젝트 일정

👩🔧개발 팀🧑🔧
TOP(This is Our Page)
|
@kinggora
|
@HongYong-Woo
|
@PARK-TH
|
@qeeeeeqeqq
|
@bottomsUp-99
|
|
팀장
|
팀원
|
팀원
|
팀원
|
팀원
|
🔧개발 환경
Java 17
- IDE: IntelliJ IDEA Ultimate
- Framework: Spring Boot (3.0.1), Spring Security 6
- Database: MySQL(8.0), MyBatis
- Library: Thymeleaf, Bootstrap5
- Tools: GitHub, Notion, Slack
📂프로젝트 구조
📦effitopia
┣ 📂config
┣ 📂controller
┃ ┣ 📂formatter
┣ 📂domain
┣ 📂dto
┣ 📂enumeration
┣ 📂exception
┣ 📂mapper
┣ 📂security
┗ 📂service
⚙️주요 기능
- 로그인/회원 관리
- 창고 관리
- 입고 관리
- 출고 관리
- 재고 관리
- 재무 관리
- 고객 센터
- 대시 보드
🔎커밋 메세지 컨벤션
Commit Type Gitmoji
- 🐛 bug: 버그 수정
- ✨ sparkles: 새로운 기능 도입
- 🔥 fire: 코드나 파일 삭제
- 📝 memo: 문서 추가 또는 업데이트
- 🎨 art: 코드의 구조/형식 개선
- 🚧 construction: 작업 진행 중
- 🎉 tada: 프로젝트 시작
- ✅ white_check_mark: 테스트 추가, 업데이트 또는 통과
- 🔧 wrench: 설정 파일 추가 또는 업데이트
- 📦️ package: 컴파일된 파일이나 패키지 추가 또는 업데이트
- ♻️ recycle: 코드 리팩토링
🔍네이밍 컨벤션
| PascalCase | 자바 클래스 | ex) UserInfo |
|---|
| camelCase | 변수, 메서드 | ex) userInfo |
| snake_case | 데이터베이스 테이블, 컬럼 | ex) user_info |
| kebab-case | 디렉터리, HTML 파일명, URL 경로 | ex) user-info |
💡개발 가이드
- 컨트롤러: 요청 파라미터 유효성 검증, 서비스 호출, 예외 처리
- DTO Bean Validation Annotation + @Valid 사용
- 커스텀 필요시 Validator 구현하여 사용
- 서비스: 비지니스 로직 관련 유효성 검증, 비지니스 로직 수행, 비지니스 예외 throw
- 한 개의 메서드는 하나의 기능만 가지도록 설계
- 변수명, 메서드명은 기능을 표현하도록 네이밍 (무의미한 이름 X)
- 특히 메서드는 캡슐화하여 따로 모듈로 사용할때 알 수 있도록 메서드명을 네이밍
- 예외 처리에서 ErrorCode는 프런트에 보낼 메세지, 로그는 서버에 남기는 메세지 (System.out.println XX)
- 접근 제어자: 모든 변수 private, 상수는 기능에 따라 설정, 메서드는 외부에서 사용하는 경우 public, 내부에서만 사용하는 경우 private
- 사용자 화면(브라우저)에 IDE에 뜨는 생소한 예외 메세지가 출력되지 않도록 예외 처리
- 커스텀 에러 페이지, alert(사용자 에러 메세지), redirect…
- 주석은 꼭!! 필요한 내용만 기입
- 각 class들은 독립성을 추구 할 수 있도록 외부 연관관계를 최소화
- 서비스는 확정성을 위해 interface를 사용
내가 맡은 파트
📦재고 관리
- 재고관리란 기업이나 조직이 보유하고 있는 제품, 원자재, 부품, 완제품 등의 재고를 효율적으로 관리하는 것을 말한다. 이는 물품의 입고(구매), 출고(판매 또는 사용), 보관 등의 과정을 체계적으로 관리하여 재고의 적정 수준을 유지하고, 이를 통해 비용 절감과 서비스 품질을 극대화하는 것이 목적이다.
1. 기획
- 설명
- 재고 관리에서 CUD는 직접적으로 하는 것은 없다고 생각한다.
- 대부분 입고 및 출고 할 때 트리거로 받아서 CUD를 진행하고 R이 주 기능이 될 것 같다.
- Update는 입고 및 출고 할 때 트리거로 수량 변동을 갱신
- Read는 재고 관리에서 주 기능으로 키워드로 조회
- 임시 재고 테이블에서 입고, 출고 변동값을 계속 insert 받다가 일정 시간이 될 때(마감)마다 재고테이블로 업데이트를한다.
-
기능
a. 조회
- 전체 조회 : 현재 모든 품목을 조회
- 창고 별 조회 : 특정 창고의 재고만 조회
- 회원 별 조회 : 특정 회원의 재고만 조회
- 품목 조회 : 상품명으로 조회
- 유통기한 조회
b. 재고 실사
- 재고 실사는 현재 재고 현황과 실제로 창고가 보유한 물품을 확인하고 비교하여 재고의 정확성을 검증하는 절차로 현재 프로젝트에선 실제 창고나 품목 등이 없으므로 직접 실사 값을 입력하여 반영 하는 것을 목표로 한다.
- 재고 실사 등록 : 창고 명, 상품 명, 재고 수량 등 직접 입력하여 실사 값을 작성
- 재고 실사 반영 : 작성된 재고 실사 값을 현재 재고 현황에 반영하여 물량을 수정한다.
- 재고 실사 삭제 : 등록된 재고 실사 값을 삭제한다.
- 재고 실사 조회: 등록된 실사들을 조회
c. 재고 로그
- 입고와 출고시 재고에 수량 변동이 있을 때 변동 사항을 파일로 입출고 기록을 남긴다.
-
확장
a. 엑셀 파일로 파싱
2. 설계
- 유스케이스 다이어그램
https://drive.google.com/file/d/1-ofv6H1qPQV8Qg7KmFWKb1yPibUYceu-/view?usp=sharing
- 플로우 차트 (총관리자)
https://drive.google.com/file/d/15P835LPgrS4aemxtXSoBsK4vBZCrNFds/view?usp=sharing
-
ERD

-
Figma



3. 구현
- 시연영상
- 설명
- 조회는 mybatis의
<where>과 <if>를 사용하여 검색어 필터링을 하여 select 할 수 있게 하였다.
- 각테이블에 연관된 Foreign key를 domain, DTO에서 int id로 하는 것이 아닌 해당 테이블의 domain, DTO 즉 객체로 선언하여 한번 select 할 때 그 테이블의 필요한 정보들을 다 가져 올수 있도록 하여 확장성을 노렸다.
- select 할때 해당 테이블을 가져오기 위해
<resultMap>을 이용하여 매핑을 하였다.
매핑을 하면 쿼리문에서 join을 하면 매핑을 한 정보를 가져와 자동으로 담아준다.
- 기존에는 스케쥴러를 이용하여 임시재고 테이블에서 일정시간마다 자동으로 재고 테이블로
update를 하려고 했으나 시연영상에 담기에는 시간이 부족하기 때문에 임시재고현황을 볼 수 있는 페이지를 따로 만들고 마감버튼을 만들어 마감을 누를때마다 임시재고 테이블이 재고 테이블로 반영 될수 있도록 하였다.
- 임시재고 테이블에서 재고 테이블로 반영이 될 때는 프로시저(Procedure)
update_tempstock_to_stock()를 만들어 사용하였다.
update_tempstock_to_stock()은 커서를 이용하여 루프를 돌면서 임시재고 테이블에는 있으나 재고 테이블에는 없는 경우 Insert를, 반대로 있는 경우에는 Update를 이용하여 수량이 변동되게 하였다.
- mapper, service에서 단위 테스트를 진행하여 나중에 Merge 했을때 오류 발생률을 낮췄다.
📞고객 센터
1. 기획
- 설명
- 고객센터는 회원이나 각 관리자들이 궁금할 사항을 문의하거나 총관리자가 공지사항을 올림으로서 주의할 점이나 변경점 등을 알리는 기능을 가진다.
- 기능
- 공지사항 : 총 관리자만이 CUD 할 수 있는 기능으로 총관리자를 제외한 나머지 유저들은 R만 가능하다. 이 프로그램을 사용하는 모든 사람에게 알리는 글을 작성 하여 띄운다. (공지사항은 문의와 유사한것이 많아서 이번에는 제외)
- 문의 : 회원이 CRUD를 할 수 있는 기능으로 모든 회원이 모든 문의글을 CRUD를 할 수 있는 것은 아니고 자신이 작성한 글 한정으로 CRUD가 가능하다. 다만 총관리자는 모든 문의글을 수정 및 삭제가 가능하다.
- 문의 글 하나에 답변 하나만 가능하게 함으로써 1:1문의 성격을 가지고 이 경우 답변 할 시 ‘답변 완료’ 같은 상태 값을 줘서 답변 상태를 알릴 수 있다.
- 상태값 변경은 트리거(trigger)를 이용하여 자동으로 변경되게 한다.
2. 설계
-
유스케이스 다이어그램
https://drive.google.com/file/d/16mHpb7VJgwsMoUZIXy9cnzYYWSHK2zeL/view?usp=sharing
-
플로우 차트(총관리자)
https://drive.google.com/file/d/1Dn0Wb3AD1McrEZiLr_WtzCcb9vyuqXJk/view?usp=sharing
-
ERD

-
Figma


💾마무리
느낀점
- 2차 프로젝트는 web 페이지 제작까지 진행되었는데 SSR은 처음 접하는 것이다 보니 web과 controller 간에 데이터가 어떤 형태(객체, 배열, int 등...)로 전송하는지 파악하는 것이 힘들었다.
- error의 경우 프론트에서 주로 발생하였는데
Thymeleaf에 익숙하지 못하다보니 에러를 찾는 것에 많은 시간이 걸렸다. 어떤 error는 몇시간을 찾았는데 결론은 단어가 틀려서 생긴 것으로 매우 허무하였다.
mybatis는 처음 접함에도 불구 하고 Thymeleaf와는 다르게 사이트 및 예시를 참고하여 수월하게 사용 할 수 있었다. error 또한 서버에 관한, 문제였다보니 수월하게 해결 할 수 있었다.
mybatis는 기존처럼 String query로 쿼리문을 작성하여 preparedStatement를 생성하여 사용하지 않고 mapper.xml과 연결된 interface의 메소드를 호출하여 사용면 되니 매우 편하였다.
- 1차때와 차이점 중 하나는 DAO가 사라졌다는 것이다. 대신 Mapper가 생겨 Sevice에서 바로 Mapper(interface)의 메서드를 호출하면 Mapper(interface)와 연결된 xml파일의
mybatis로 작성해 놓은 Query문이 실행되어 바로 값을 받아온다는 것이다. 전처럼 DAO에서
connection 연결하고 preparedStatement를 생성해서 쿼리문 넘겨주고 resultmap으로 받고 이런 과정이 없어졌다.
- 이번에는
Spring 이 아닌 좀더 개선된 버전인 Spring Boot를 사용했는데 확실히 Spring보다 편해진 점이 보였다 예로 Spring에서는 WAS인 Tomcat을 일일히 연결해 줘야 했지만 Spring boot는 WAS가 내장 되어 있어 따로 설정 할 필요가 없다는 것이다.
또한 Connection Pool인 HikariCP도 따로 객체로 만들어서 관리 할 필요 없이
application.properties에 연결 값만 설정해 주면 된다.
spring boot를 사용하면서 MVC 구조 패턴을 적용하여 프로젝트를 진행하게 되었는데 역할을 나누어 지다보니 단위테스트하기 좋았고 직관성이 좋아져 효율성이 올라가는 것 같았다. 지난 1차 때도 mvc패턴으로 구조화해서 해보려고 했으나 당시에는 View가 따로 없기도 했고 mvc에 대한 이해도 부족으로 역할이 섞이거나 애매한 경우가 있었으나(대표적으로 Service와 DAO) 이번엔 좀 더 제대로 mvc패턴에 맞게 구현한 것 같다.
Spring Boot의 장점 중 하는 의존성 주입(Dependency Injection)인데 처음 프로젝트를 생성 할 때 한번 주입 해놓으면 후에는 편하게 사용 할 수 있다는 것이다. 이번에 주입후 편하게 사용했던 것들은 log를 찍을 수 있게하는 log4j2와 builder, getter, setter등을 @을 이용한 한단어로 사용하게 해주는 Lombok이 있었다.
개선할 점(Refactoring)
Thymeleaf 또는 ajax를 이용한 비동기 실행
- 재고 실사 구현
- 고객 센터 구현
추후 고려해야 하는 사항
- 동시성 제어
- 동시성 제어란 여러 사용자가 한데이터에 동시에 접근할때 데이터의 일관성과 충돌을 방지하기 위해 사용하는 기법이다.
- 필요한 이유 : 재고관리는 현재 보관하고 있는 재고의 정확성이 중요한데 재고의 특성상 입고와 출고로 인해 한 상품에 대한 수량이 계속 변동된다. 따라서 동시성제어를 통해 수량 변동을 제어 하지않는다면 기존 출고로 인해서 수량이 없는 데도 불구 하고 또 출고가 되어 버리는 모순된 읽기가 발생하여 신뢰도를 떨어뜨릴수 있다.