✨개요
Spring, 또는 SpringBoot 둘 중 하나를 택해 웹 서비스를 개발하는 수업의 과제물로 제출한 프로젝트이다.
총 4명의 팀원이 함께 협업하였으며, 수업에서 배운 모든 분야의 지식을 두루 활용하기 위해
프론트/백의 구분을 두지 않고 전원이 풀스택으로 개발하였다.
여기에 팀장으로서 과제 산출물과 전반적인 개발 과정을 검토하고, 회의를 주도하였다.
1편은 기능 구현에 초점을 두어 작성하고, 2편은 테스트 작성과 리팩토링을 다룬다.
✨Git 링크
https://github.com/jinju9553/SOMusic-SpringBoot
✨수행 기간
2022.03.15 ~ 2022.06.23
✨기술 스택
- Language:
Java 1.8 - Framework :
SpringBoot,Spirng Data JPA - View:
JSP,ThymeLeaf - DB:
Oracle Database - Test:
JUnit5,Mockito
Spring을 먼저 학습한 후 SpringBoot를 뒤늦게 배웠는데, 시간이 촉박하더라도 SpringBoot로 개발하는 것을 택했다.JpaRepository 인터페이스를 사용하면 메소드 작명 규칙에 따라 쿼리가 자동으로 생성되고,Lombok 의 어노테이션을 이용하면 Getter와 Setter 까지 자동으로 생성되는 등,Spring보다 다양하고 편리한 기능들이 많이 정의되어 있었기에 한정된 기간 내에 원하는 기능을 모두 개발할 수 있을 거라 판단했다. 겸사겸사 문서를 읽고 라이브러리를 사용하는 요령도 길렀다.
✨기능

✨수행 과정
- 2주차
- 주요 활동 주제 및 개발범위를 선정하고, 개발 업무를 분담하였다.
- 3주차
- 요구사항을 분석하고 세부 기능을 정의하였다.
- 실제로 구현이 어떤 방식으로 이루어지는지 몰랐기 때문에 요구사항을 과도하게 세분화하는 불상사가 발생했다.
- 결국 최종 보고서 제출 시에 세분화 된 몇몇 기능을 통합해서 도표를 작성하기도 했다.
- 4주차
- UI를 설계하고 Request 처리 흐름도를 간략하게 작성하였다.
- 요청 흐름 작성은 Spring 기반 웹 프로그램에서 어떤 방식으로 요청이 발생하고 어떤 흐름으로 요청이 전달되는 지 정확하게 알아야만 작성할 수 있는 도표이다. 처음 MVC 구조를 학습할 때에는 쉽사리 구조가 파악되지 않아 교안을 반복해서 확인하기도 했다. 후에는 이 지식을 확실히 내것으로 만들기 위해서 빈 종이 위에 Controller, View, Service 등을 표시하고 그 사이에 오가는 요청을 도표로 그려보기도 하였다. 이 방식이 특히 프로그램의 흐름을 익히기에 적합한 것 같다.
- 5주차
- 데이터베이스 스키마(논리적, 물리적)를 설계하고 도메인 클래스를 작성하였다.
- DB 스키마는 설계 단계에서부터 신중을 기해야 한다고 생각한다. 일전의 프로젝트에서는 각 테이블 별 연관 관계 특성 상 데이터가 꼬이는 바람에, 요구사항에 맞는 API를 설계하기 위해서 DB를 지우고 다시 설계해야만 하는 불상사가 발생한 적 있다.
- 이 과정에서 특히나 도움이 되는 것은 요청 흐름과 데이터의 이동을 말로 풀어서 설명하는 것이다. DB 스키마는 현실 세계에 존재하는 문제 상황을 데이터로 모델링한 산출물이라고 생각한다. 이 산출물을 올바르게 내기 위해서는 요청 흐름과 요구사항을 정확하게 파악해야 하며, 데이터가 어디에서 어떻게 전달되어야 하는지를 사람의 언어로 잘 풀어내는 것이 요청 흐름과 프로그램 구조를 이해하는 데에 도움이 된다.
- 이 때문에 팀원들과 온라인 화상 회의에서 몇 시간동안을 말로 설명하고 이해한 것을 DB 구조로 옮겨 적었던 기억이 난다.
- 6주차
- 설계한 데이터베이스 스키마를 토대로 ER 다이어그램을 작성한다.
- 설계서 제출을 위해 개체관의 관계와 각 컬럼의 의미를 풀어서 설명하였다. 상기한 바와 같이 설계서도 결국 사람이 읽는 것이기 때문에 명료하고 이해하기 쉬운 언어로 내용을 설명하는 것이 중요하다고 생각한다. 팀 내의 어떤 사람이 읽어도 중의적으로 해석되지 않고, 한 가지 의미로만 뚜렷하게 설명되어야 하지 않을까 싶다.
- 7주차
Controller클래스,Service클래스를 정의하고 Request 처리 흐름도를 최종적으로 작성하였다.- 요청 처리 흐름은 Use Case별로 구분하여 작성하였다. 마찬가지로 흐름도를 명료하게 작성하기 위해서라면 프로그램의 실행 구조에 대한 이해가 수반되어야 한다.
Controller에서 어떤 handler 메소드를 거쳐야 하는지, 그 메소드에서는 어떤Service메소드를 호출하는지, 그Service메소드는 또 어떤DAO메소드를 호출하고,DAO메소드는 DB에 접근하여 어떻게 데이터를 처리하고 어떤 데이터(View또는Model)를 반환하는지 등등... 수업에서 제공한 예제 프로젝트와 예제의 설계도를 반복적으로 읽으며 분석하였다.
- 9주차~10주차
- 중간고사를 마치고 Handler 메소드의 이름을 정의하고,
DAO인터페이스 및Controller클래스를 다이어그램으로 정의하였다. - 슬슬 산출물이 쌓이는 단계이기도 하고, 설계를 토대로 실질적으로 기능 구현에 들어서는 시기였다. 어떤 클래스를 얼마나 정의하고, 그 안에는 무슨 메소드가 정의되어 있는지를 미리 설계했기 때문에 이를 토대로 개발을 시작하기가 비교적 수월했다.
- 중간고사를 마치고 Handler 메소드의 이름을 정의하고,
- 11주차
- 전체 기능 중 먼저 구현해야 하는 우선순위를 정하고, 커밋메시지 양식을 통일하였다.
220512 login fix와 같이 yyMMdd + 기능 설명(한글or영어) 으로 통일하였는데, 당시에는 흔히 통용되는 커밋 메시지 양식을 잘 몰라서(feat, fix, style 등등) 이와 같은 형식으로 결정했었다. 조금 더 검색해보고 결정했을걸 하는 아쉬움이 남는다.
- 12~16주차
- 본격적으로 기능을 구현해나갔다. 맞닥뜨린 오류와 해결 방법은 아래의 항목에 적는다.
✨문제 해결
- 스프링부트에서 jsp 파일을 인식할 수 없었던 오류
application.properties파일에 경로가 올바르게 설정되어 있는지 검토한다. thymeleaf로 정의된 View는 대개 classpath:templates 디렉토리 아래에 배치되지만, jsp 파일은 그렇지 않다. 본 프로젝트에서는 jsp 파일이 WEB-INF/jsp 디렉토리 아래에 위치하기 때문에 적절하게 파일 경로를 나타내는 prefix와 suffix를 수정해주었다.
- SQL:
인덱스에서 누락된 IN 또는 OUT 매개변수- 질의문과 여기에 매핑되는 Object의 컬럼수가 맞지 않을 때 발생한다. 본 프로젝트에서는
JpaRepository나springframework라이브러리에 정의된@Repository어노테이션으로 자동 생성되는 쿼리문 외에도 특정 기능 구현을 위해JdbcTemplate기반으로 직접 쿼리문을 작성할 필요가 있었다. 요청하는 데이터의 가짓수가 많을 수록 혼동할 확률이 높으니 쿼리문과 Object가 알맞에 매핑되었는지 검토할 필요가 있다.
- 질의문과 여기에 매핑되는 Object의 컬럼수가 맞지 않을 때 발생한다. 본 프로젝트에서는
ORA-00911: 문자가 부적합합니다- SQL문 중간에 세미콜론(;)이 포함되는 등, SQL문 자체에 문제가 있을 때 발생하는 오류이다. 오탈자가 없는지 점검하였다.
class [I cannot be cast to class [Ljava.lang.Object; ([I and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')ModelAttribute로int[]타입 객체를 전송할 때 발생하는 에러이다.ModelAttribute로는String[]또는Object[]타입만 전송할 수 있다.ModelAttribute로는 primitive type을 보낼 수 없음에 유의해야 한다.
ORA-02296: 사용으로 설정 불가 - 널 값이 발견되었습니다.- DB에서 null값으로 생성된 컬럼의 디폴트를 not null로 설정할 때 발생하는 오류이다. String의 경우 공백문자 등을 이용해 초기화 시키고 값을 바꿔주어야 한다.
Neither BindingResult nor plain target object for bean name“000”available as request attribute- 직역하면 Request Attribute로 사용할 "000"이라는 Bean이 BindingResult나 plain target object로 전송되지 않았음.
- 즉, View로 보내는 Request에 command 객체를 담지 않아서 발생하는 문제이다. 누락된 Attribute가 없는지 점검한다.
java.sql.SQLException: 부적합한 열 인덱스 오류- 쿼리문의 파라미터 개수와 거기에 삽입하는 값의 개수, 또는 위치가 달라서 발생하는 오류이다. 오탈자가 없는지 점검한다.
✨소감
- SpringBoot를 이용해 두 번째로 개발해보는 웹 프로젝트인데, Spring의 DI나 IoC등의 원리를 학습한 것은 처음이다.
- 아직 프레임워크의 동작에 익숙하지 않기 때문에, 데이터베이스와 연동된 기능을 구현하고, CRUD 기능이 온전히 작동하는 프로그램을 만드는 데에 초점을 두어 학습하였다.
- 그렇기 때문에 주로 프레임워크를 처음 사용한다는 점에서 비롯된 어려움이나 문법 오류 등이 발목을 잡았다.
- 또, 과제 제출에 초점을 맞추어 학습하다보니 코드의 질이나, Spring의 작동 원리에 대해서는 크게 고려하지 못했던 점이 아쉽다.
- 요청 처리 흐름을 파악하기 어렵거나, 프로그램의 구조를 이해하지 못했을 때에는 상기한 바와 같이 그림을 그려 이해하려고 했다.
- 개발 시간이 넉넉하지 않은 탓에, 구현 중 맞닥뜨린 어려움을 정공법으로 해결하지 못하고 임시방편으로 기능만 돌아가도록 만든 것이 큰 아쉬움으로 남았다.
- 그 탓에 코드가 난잡해지고 직관적으로 이해하기 어려울 뿐더러, 불필요한 코드 반복이 나타나기도 했다. 이 점은 다음 포스팅인 리팩토링 편에서 해결 방안을 다룰 것이다.
'Study > Project' 카테고리의 다른 글
| [프로젝트] 수업 과제물 : SpringBoot 웹 프로젝트 회고록 ②리팩토링 (0) | 2023.05.09 |
|---|---|
| [프로젝트] 개발 동아리 과제물 : Solar 2D 개인 프로젝트 (0) | 2021.02.10 |