Post
신규 웹 프로젝트 - 1 (구조 및 기초개발)
현재 구조를 잡고 공통단을 개발한 후에 팀원들 배포해야 해서 기록용
*JPA 사용 시, 현재 구축된 데이터베이스와 맞지 않음. 쿼리가 계속 복잡해지는 특성 상, JPA 사용 시
개발효율이 너무 떨어져서 제외
*config에서 MyBatis와 기본적인 Security 세팅 진행
*model에 쿼리 컬럼 저장 , 데이터베이스와 완벽하게 일치하진 않고, Transfer하는 용도임 (DTO)
- Controller: 클라이언트(프론트엔드)와의 인터페이스 역할. HTTP 요청을 받고 응답을 반환.
- Service: 비즈니스 로직의 명세를 정의. 어떤 기능을 제공할지 선언.(인터페이스)
- ServiceImpl: Service 인터페이스의 구체적인 구현. 트랜잭션 관리나 추가 로직 포함.
- Mapper: 데이터베이스와의 상호작용. SQL 실행과 결과를 객체로 변환.(인터페이스)
- Model: 데이터 구조 정의. DB 테이블과 매핑되거나 계층 간 데이터를 전달.
구조 변경 이유 ? 이전 Controller => Service구조에서는
1.Controller가 거의 모든 로직을 담당하기 때문에 코드 복잡성이 증가합니다.
2.Service 계층을 두고 비즈니스 로직을 한곳에서 관리해서 여러 Controller에서 호출가능하게 해서 재사용성을 늘리기 위함
3.Controller는 사실 요청/응답에 의존적이어서 단위 테스트가 좀 힘들어서 Service 분리해서 독립 테스트 가능하도록 변경
EX) 현재 CompanyService에서 페이징,트랜잭션 같은 로직 처리하는데 Controller는 단순히 요청 받고 응답을 주는 용도로 사용 중 - 아래는 구조
SSMS_NEW/
├── SSMS/ # 백엔드 (Spring Boot)
│ ├── build.gradle
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/org/kms/ssms/
│ │ │ │ ├── config/
│ │ │ │ ├── controller/
│ │ │ │ ├── mapper/
│ │ │ │ ├── model/
│ │ │ │ ├── security/
│ │ │ │ ├── service/
│ │ │ │ │ ├── impl/
│ │ │ │ ├── util/
│ │ │ │ └── SsmsApplication.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── mapper/ (MyBatis XML, 사용 시)
│ └── application.yml
└── frontend/ # 프론트엔드 (Vue.js + Vuetify)
├── package.json
├── src/
│ ├── components/
│ │ ├── 화면.vue
│ │ ├── common/ (공통.vue)
│ │ └── icons/
│ ├── plugins/
│ │ └── vuetify.js
│ ├── router/
│ │ └── index.js
│ ├── stores/
│ ├── styles/
│ ├── App.vue
│ └── main.js
└── vite.config.js
간략 설명
Controller
- 기능: HTTP 요청을 받아 Service 호출 후 결과를 클라이언트에 반환.
- /api/company/list에서 회사 목록을 조회하고, 페이징된 결과를 CustomPage로 반환.
- REST API의 엔드포인트를 깔끔하게 관리하고, 요청 파라미터(companyNm, page, size)를 처리.
- 예외 처리를 통해 클라이언트에 적절한 HTTP 상태 코드(200, 500 등)를 반환.
- 프론트엔드(Vue.js)와의 통신을
Service (인터페이스)
- 기능: 비즈니스 로직의 명세를 정의. 어떤 기능을 제공할지 선언.
- CompanyService 인터페이스에서 getCompanies, insertCompanies 등을 정의.
- 추상화: 인터페이스를 두면 구현체(ServiceImpl)를 쉽게 교체할 수 있습니다. 예를 들어, 나중에 MyBatis 대신 JPA로 바꾸고 싶다면 CompanyServiceImpl만 수정하면 됩니다.
- 의존성 주입: Spring의 DI(Dependency Injection)를 활용해 Controller가 구체적인 구현체가 아닌 인터페이스에 의존하게 함. 코드 유연성 증가.
- 테스트 용이성: 인터페이스를 Mocking해서 테스트할 수 있음.
ServiceImpl
- 기능: Service 인터페이스의 구체적인 구현. 비즈니스 로직과 트랜잭션 관리.
- CompanyServiceImpl에서 페이징 계산, 회사 이름 필터링, 트랜잭션 처리.
- 비즈니스 로직 분리: getCompanies에서 페이징 파라미터를 계산하고, 회사 이름이 있으면 필터링 쿼리를 호출. 이런 로직을 Controller에 넣으면 복잡해짐.
- 트랜잭션 관리: @Transactional로 여러 DB 작업(예: 다중 삽입)을 하나의 트랜잭션으로 묶음. 실패 시 롤백 보장.
- 재사용성: 다른 모듈이나 API에서 CompanyServiceImpl을 호출해 동일 로직 사용 가능.
Mapper
- 기능: DB와의 상호작용. SQL 실행과 결과를 model 객체로 매핑.
- CompanyMapper에서 findByCompanyNamePaged, insertCompany 등을 정의하고, XML에서 SQL 작성.
- SQL 분리: XML에 SQL을 작성하면 Java 코드와 분리되어 가독성과 수정이 쉬움. 예: findByCompanyNamePaged의 동적 페이징 쿼리.
- MyBatis의 장점: 동적 SQL(조건에 따라 WHERE 절 추가)과 결과 매핑(resultMap)이 편리함.
- DB 독립성: 나중에 DB가 바뀌어도(예: Oracle -> MySQL) SQL만 수정하면 됨.
Model
- 기능: 데이터 구조 정의. DB 테이블과 매핑되거나 계층 간 데이터 전달.
- Company 클래스에 enterCd, companyNm 등 필드 정의.
- 데이터 일관성: DB의 TMST001_NEW 테이블과 매핑되는 객체로, Mapper가 쿼리 결과를 Company로 변환.
- DTO 역할: 프론트엔드와 백엔드 간 데이터 전달 시 사용. 예: insertCompany에서 List<Company>를 받아 처리.
- Lombok 사용: @Data로 getter/setter 자동 생성해 코드 간소화.
XML (Mapper 쿼리)
- 기능: SQL 쿼리와 매핑 규칙 정의.
- companyResultMap으로 컬럼과 Company 필드 매핑, 페이징 쿼리 작성.
- 가독성: 복잡한 쿼리(예: ROWNUM을 이용한 페이징)를 Java 코드에 넣으면 지저분해짐. XML로 분리해 깔끔하게 관리.
- 유연성: 동적 조건(예: companyNm이 있을 때만 WHERE 추가) 처리가 쉬움.
SSMS_NEW에서 이전과 비교한 구조의 이점
- 유지보수성
- 문제가 생기면 어디를 봐야 할지 명확: HTTP 오류 → Controller, 로직 오류 → ServiceImpl, SQL 오류 → Mapper/XML.
- 예: 페이징이 잘못되면 CompanyServiceImpl의 PagingUtils.getPagingParams나 XML의 BETWEEN 조건을 확인.
- 확장성
- 새로운 기능(예: 회사 통계 API) 추가 시, CompanyService에 메서드 추가하고 CompanyMapper에 쿼리만 작성하면 됨.
- 팀 협업
- README에 Git 브랜치 전략이 있듯, 팀원이 각자 맡은 계층(프론트/백엔드, Controller/Service 등)을 독립적으로 작업 가능.
- 레거시 호환
- Oracle 11g XE의 기존 SSMS의 구조를 계승. MyBatis와 XML은 레거시 SQL을 재활용하기 좋아서 선택.
2025년 3월 기준:
- 백엔드:
- JWT를 사용한 사용자 인증 (액세스 및 리프레시 토큰).
- Oracle 11g XE 데이터베이스
- Spring Boot 3.4.3, Spring Security 6.4.3, MyBatis 사용.
- build.gradle에 dependencies 확인
- 프론트엔드:
- Vue.js 3와 Vuetify 3를 사용한 UI, JavaScript 기반.
- 로그인 페이지, 네비게이션 바가 있는 대시보드, Vue Router로 라우팅.
- 로그인 상태 확인을 통한 안전한 라우팅
- 공통 DataTable.vue 사용, 공통 Style사용, 공통 Errorsnackbar사용
- 보안:
- 모든 API 엔드포인트(/api/**)를 JWT 인증으로 보호.
- 프론트엔드 경로는 인증되지 않은 사용자에게 로그인 페이지로 리디렉션.
- Git 관리:
- SSMS_NEW 저장소로 GitHub에 호스팅, 정기적인 커밋으로 진행 상황 추적.
사용된 기술
- 백엔드:
- Spring Boot 3.4.3
- Spring Security 6.4.3
- MyBatis
- Oracle 11g XE
- Java 21
- JWT
- Gradle Build
- 프론트엔드:
- Vue.js 3
- Vuetify 3
- Vite
- Axios (API 호출용)
- Pinia (Store 관리)
- 도구:
- Git (버전 관리)
- GitHub (원격 저장소)
커밋 방법
- master Branch : 주기적으로 Schedule잡고 반영
- dev Branch : 작업자가 push하는 Branch (작업 내용 계속 반영)
- 각 개인의 Branch에서 작업 후 dev에 병합하기
*추후 수정 예정 사항 및 도입 사항?
1.현재 DataTable.vue를 이전에 사용하던 IBSheet와 비슷하게 기능을 만들어서 구현해야 하는데
이걸 혼자 하려니까 너어무 오래 걸림 Vue가 익숙하지 않은 상황에 갖가지 버그가 너무 많음
=> 새로운 서드파티 도입? 혹은 깃 상에서 공통으로 제작된 MIT License를 가져와서 해당 소스에 맞게 진행? , Vuetify3의 잘 만들어진 공통 부분을 가져와서 쓰기?
2.도커 도입?
댓글