Post

신규 웹 프로젝트 - 1 (구조 및 기초개발)

#naver-import

원문: https://blog.naver.com/qoxmfaktmxj/223789566184

현재 구조를 잡고 공통단을 개발한 후에 팀원들 배포해야 해서 기록용

*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에서 이전과 비교한 구조의 이점

  1. 유지보수성
    • 문제가 생기면 어디를 봐야 할지 명확: HTTP 오류 → Controller, 로직 오류 → ServiceImpl, SQL 오류 → Mapper/XML.
    • 예: 페이징이 잘못되면 CompanyServiceImpl의 PagingUtils.getPagingParams나 XML의 BETWEEN 조건을 확인.
  2. 확장성
    • 새로운 기능(예: 회사 통계 API) 추가 시, CompanyService에 메서드 추가하고 CompanyMapper에 쿼리만 작성하면 됨.
  3. 팀 협업
    • README에 Git 브랜치 전략이 있듯, 팀원이 각자 맡은 계층(프론트/백엔드, Controller/Service 등)을 독립적으로 작업 가능.
  4. 레거시 호환
    • 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 (원격 저장소)

커밋 방법

  1. master Branch : 주기적으로 Schedule잡고 반영
  2. dev Branch : 작업자가 push하는 Branch (작업 내용 계속 반영)
  3. 각 개인의 Branch에서 작업 후 dev에 병합하기

*추후 수정 예정 사항 및 도입 사항?

1.현재 DataTable.vue를 이전에 사용하던 IBSheet와 비슷하게 기능을 만들어서 구현해야 하는데

이걸 혼자 하려니까 너어무 오래 걸림 Vue가 익숙하지 않은 상황에 갖가지 버그가 너무 많음

=> 새로운 서드파티 도입? 혹은 깃 상에서 공통으로 제작된 MIT License를 가져와서 해당 소스에 맞게 진행? , Vuetify3의 잘 만들어진 공통 부분을 가져와서 쓰기?

2.도커 도입?

댓글