[TOC]
[ 2편, 3편, 4편, 5편, 6편 / 다음편보기→ ]
결과물 git주소 : https://gitlab.ntiple.com/developers/study-202403
1. 개요
근래 몇년간 유행하는 방법론과 프레임워크로 스터디에 활용할 만큼 간단한 게시판 프로젝트를 만들어 보자 는 취지로 시작했다.
본 게시물은 2024.03.25 일 부터 대략 1주일 간격으로 3차례 진행된 스터디 내용을 바탕으로
정리하였다.
사용된 프레임워크 및 기법들 : spring-boot, spring-security, JWT, JPA, open-api, SPA, RSA, AES, next-js, react-js, redux
본 프로젝트 결과물들은 직후 실전 프로젝트에서 유용하게 써먹고 있다.
GIT 주소는 다음과 같다. (현재 정리중이라 소스작업이... 좀..... 일단 최신 소스는 react-mui 브랜치로 접근해야 한다.)
> https://gitlab.ntiple.com/developers/my-first-app
GIT 주소는 다음과 같다 (현재 블로그 내용을 토대로 새로 작성하여 운영 중이다)
스터디 협조에 응해주신 미모의 개발자 L 님에게 감사드립니다. ㅋㅋ
2. 범위
오늘 글에 포함된 범위는 일단 준비작업. 분석 및 설계단계를 정리해 볼거다.
(실제 스터디에서는 이딴거 없이 닥돌 gradle 프로젝트부터 생성했음....)
2번째 레포트에서 Java (Backend)
3번째 레포트에서 React (Frontend)
를 다룰 예정이다.
3. 분석 및 설계
3-1. 데이터 Entity
-
TB_USER: 사용자 -
TB_ARTICLE: 게시물erDiagram TB_USER { long id PK "사용자 고유번호(자동)" string(32) user_id UK "로그인 아이디" string(32) user_nm "사용자 이름" string(128) passwd "사용자 비밀번호" string(128) email "사용자 이메일" datetime ctime "생성일시" datetime utime "수정일시" } TB_ARTICLE { long id PK "게시글 고유번호(자동)" long board_id "게시판 ID" string(32) num "게시글 번호" string(128) title "게시글 제목" string(32) user_id "글쓴이 ID" string(32) user_nm "글쓴이 이름" string(9999) contents "내용" datetime ctime "생성일시" datetime utime "수정일시" } TB_USER ||--o{ TB_ARTICLE : has
3-2. 프론트엔드 / 백엔드 데이터 통신
-
프론트-백엔드 간 데이터 통신은
Restful방식 (GET,POST,PUT,DELETE)을 사용한다.구분 URI 예시 세부 내용 예시 예시설명 GET/api/atc/atc01001/1 게시물 상세조회 (id = 1) POST/api/atc/atc01001 { "searchType": "", ... } 게시물 검색 PUT/api/atc/atc01001 { "boardId": "", ... } 게시물 입력 DELETE/api/atc/atc01001/1 게시물 삭제 (id = 1)
3-3. 프로그램 모듈 설계
-
프로그램명은 대분류(영문3자리), 중분류(숫자2자리), 소분류(숫자3자리), 구분자(a/s) 세분류(숫자2자리) 로 정해진다
-
예를들어 프로그램명
cmn01002a03은 다음과 같이 설명된다.분류 구분 설명 cmn대분류 대분류 (공통, 메인... 등등 성격에 따른 영문약어) 01중분류 중분류 (대분류 내 업무, 등록순에 따른 순차번호) 002소분류 소분류 (중분류 내 작업, 등록순에 따른 순차번호) a구분자 a: 프로그램(메소드) /s: 화면(파일명)03세분류 세분류 (소분류 C/R/U/D,uri에 포함되지 않음) -
프로그램명의 중분류 까지 8자리는
Restful의 주체 (URI)가 된다. 예:cmn01002003->cmn01002 -
Restful의 주체가 되며GET,POST,PUT,DELETE등Method에 의해C/R/U/D가 정해진다구분 설명 기타 GET단일조회 PATH-VARIALBLE활용POST목록조회(검색) / 또는 데이터 전달 PUT데이터입력(및 수정) ID 유무에 따라 입력 / 수정 구분 DELETE데이터삭제 PATH-VARIALBLE활용 -
프로그램 대분류 코드는 다음과 같다
대분류 구분 설명 cmn 공통 공통서비스 mai 메인 메인화면 usr 사용자 회원가입, 마이페이지 등 사용자 관련 lgn 로그인 로그인, 로그인연장 등 로그인 관련 atc 게시물 게시물 작성, 조회, 검색 등 게시물 관련 smp 샘플 개발샘플 (운영환경 에서 비활성) -
코드 상세에 따른 프로그램 목록 은 다음과 같다
프로그램명 URI 인증 서비스 파일명 설명 기타 cmn00000a00GET /api/cmn/cmn00000CommonService.java서비스 활성화 여부 체크(PING) cmn01001a01GET /api/cmn/cmn01001CommonService.java최초 접속 환경정보 조회 mai01001a01GET /api/mai/mai01001MainService.java메인 공지사항 등 정보 usr01001a01GET /api/usr/usr01001UserService.java아이디 중복확인 usr01001a02PUT /api/usr/usr01001UserService.java회원가입 usr01002a01GET /api/usr/usr01002필요 UserService.java마이페이지 본인확인 usr01002a02PUT /api/usr/usr01002필요 UserService.java마이페이지 수정 본인확인 lgn01001a01POST /api/lgn/lgn01001LoginService.java로그인 토큰발급 lgn01002a01GET /api/lgn/lgn01002필요 LoginService.java로그인연장 토큰발급 atc01001a01PUT /api/atc/atc01001필요 ArticleService.java게시물 작성/수정 글쓴이확인 atc01001a02GET /api/atc/atc01001필요 ArticleService.java게시물 조회 atc01001a03DELETE /api/atc/atc01001필요 ArticleService.java게시물 삭제 글쓴이확인 atc01001a04POST /api/atc/atc01001필요 ArticleService.java게시물 검색 -
구현할 화면명은 다음과 같다.
화면명 URI 설명 기타 mai01001s01/mai/mai01001s01메인화면 usr01001s01/usr/usr01001s01회원가입 입력폼 usr01001s02/usr/usr01001s02회원가입 결과 usr01002s01/usr/usr01002s01마이페이지 수정폼 usr01002s02/usr/usr01002s02회원정보 수정 결과 lgn01001s01/lgn/lgn01001s01로그인 페이지 lgn01001s02/lgn/lgn01001s02로그인 결과 페이지 atc01001s01/atc/atc01001s01새글 작성 페이지 atc01001s02/atc/atc01001s02게시물 편집 페이지 atc01001s03/atc/atc01001s03게시물 조회 페이지 atc01001s04/atc/atc01001s04게시물 목록 페이지
3-4. 암호 교환 및 검증 절차
-
프론트엔드 에는 기본적으로 private-key 가 입력되어 있다.
-
프론트엔드에서 백엔드 최초 접근시
AES-key를 요청 한다 -
백엔드 에서 프론트엔드로
AES-key전송 시 public-key 로 암호화 하여 내려보낸다 -
전송받은 암호화 데이터 (
AES-key) 는 프론트엔드에서 private-key 로 복호화 한다 -
이후 상호 데이터 암호화는
AES방식으로 통신한다. -
DB 저장시 프론트엔드에서 전송받은 데이터를 백엔드에서 한번 평문화 한 후 DB 암호화 모듈을 적용한다.
-
DB 암호화는 대부분 단방향 이므로 복호화는 일반적으로 사용하지 않는다 (비밀번호 등의 데이터 검증은 암호화 된 상태에서만 비교)
sequenceDiagram Frontend->>Backend: AES-key 요청 Backend->>Frontend: public-key 암호화된 AES-key 데이터 Frontend->>Frontend: private-key 로 AES-key 복호화 Frontend->>Backend: AES 암호화 데이터 전송 Backend->>Backend: AES 데이터 복호화 Backend->>DB: DB 암호화 모듈 사용 DB->>Backend: DB 암호화 데이터 Backend->>Frontend: AES 암호화 데이터 전송 Frontend->>Frontend: AES 데이터 복호화
3-5. Auth Token 발급 및 검증 절차
- Auth Token 은
JWT형태를 사용하며TokenProvider.java를 사용하여 발급한다.
3-6. 업무분석
3-6-1. 초기화
-
순차흐름
sequenceDiagram Actor User User->>Frontend: 최초접근 Frontend->>cmn01001: 환경정보 cmn01001->>cmn01001: AES-key 암호화 (public-key) cmn01001->>Frontend: AES-key 암호데이터 Frontend->>Frontend: AES-key 복호화 (private-key) Frontend->>User: 페이지
3-6-2. 회원가입
-
전송 데이터 타입 (가입정보)
erDiagram User { long id "사용자 고유번호(자동)" string(32) userId "로그인 아이디" string(32) userNm "사용자 이름" string(128) passwd "사용자 비밀번호(DB 암호화)" string(128) email "사용자 이메일" datetime ctime "생성일시 (자동)" datetime utime "수정일시 (자동)" } -
순차흐름
sequenceDiagram Actor User User->>Frontend: 회원가입 (usr01001s01) Frontend->>usr01001: 중복확인 (usr01001a01) usr01001->>Frontend: 중복여부 Frontend->>Frontend: 비밀번호 AES 암호화 Frontend->>usr01001: 회원가입 (usr01001a02) usr01001->>usr01001: 비밀번호 AES 복호화 usr01001->>DB: 비밀번호 DB암호화 요청 DB->>usr01001: DB암호화 데이터 usr01001->>DB: save(가입정보) DB->>usr01001: 성공여부 usr01001->>Frontend: 성공여부 또는 오류정보 Frontend->>User: 완료페이지 (usr01001s02) -
기타
-
로그인 아이디 규칙설정 : 4글자 이상의 영숫자, 반드시 영문자로 시작
-
admin,user,system,root,staff,actor,common등 불용어 설정 (property)
-
3-6-3. 마이페이지
-
가입정보데이터 수정 가능 항목구분 수정가능여부 기타 id userId userNm 가능 passwd 가능 email 가능 ctime utime 가능 자동수정 -
순차흐름
sequenceDiagram Actor User User->>Frontend: 마이페이지(usr01002s01) Frontend->>usr01002: usr01002a01(userId) usr01002->>DB: findOneByUserIdEquals(userId) DB->>usr01002: 가입정보 usr01002->>Frontend: secureOut(가입정보) Frontend->>User: 마이페이지 User->>Frontend: 수정(가입정보) Frontend->>Frontend: 비밀번호 AES 암호화 Frontend->>usr01002: usr01002a02(가입정보) usr01002->>usr01002: 비밀번호 AES 복호화 usr01002->>DB: 비밀번호 DB암호화 요청 DB->>usr01002: DB암호화 데이터 usr01002->>DB: findOneByUserIdEquals(userId) DB->>usr01002: 가입정보 usr01002->>usr01002: 수정가능항목만 덮어쓰기 usr01002->>DB: save(가입정보) DB->>usr01002: 성공여부 usr01002->>Frontend: 성공여부 또는 오류정보 Frontend->>User: 완료화면(usr01002s02) -
기타
- 비밀번호는 입력시에만 업데이트 한다. (공백일 경우 기존 비밀번호 유지)
3-6-4. 로그인
-
로그인정보
erDiagram Login { string(32) userId "로그인 아이디" string(128) passwd "사용자 비밀번호 (AES 암호화)" } -
순차흐름
sequenceDiagram Actor User User->>Frontend: 로그인(lgn01001s01) Frontend->>Frontend: 비밀번호 AES 암호화 Frontend->>lgn01001: 로그인정보 lgn01001->>lgn01001: 비밀번호 AES 복호화 lgn01001->>DB: 비밀번호 DB 암호화 DB->>lgn01001: DB암호화 데이터 lgn01001->>DB: findOneByUserIdEquals(userId) lgn01001-->>Frontend: ![사용자없음] 오류정보 lgn01001->>lgn01001: 비밀번호 비교 lgn01001-->>Frontend: ![비밀번호안맞음] 오류정보 lgn01001->>TokenProvider: createToken TokenProvider->>lgn01001: authToken (accessToken, refreshToken) lgn01001->>lgn01001: authToken AES 암호화 lgn01001->>Frontend: authToken 전달 Frontend->>Frontend: authToken AES 복호화 Frontend->>Frontend: authToken 저장 (API / Bearer) Frontend->>User: 로그인 결과 화면(lgn01001s02)
3-6-5. 로그인 연장
-
순차흐름
sequenceDiagram Actor User Frontend->>User: ![2분이내 만기시] 연장여부확인 User->>Frontend: 연장요청 Frontend->>lgn01002: refreshToken lgn01002->>TokenProvider: createToken TokenProvider->>lgn01002: authToken (accessToken, refreshToken) lgn01002->>lgn01002: authToken AES 암호화 lgn01002->>Frontend: authToken 전달 Frontend->>Frontend: authToken AES 복호화 Frontend->>Frontend: authToken 저장 (API / Bearer) Frontend->>User: 연장요청결과
3-6-8. 게시물작성
-
게시물정보
erDiagram Article { long id "게시글 고유번호" long boardId "게시판 ID" string num "게시글 번호" string title "게시글 제목" string userId "글쓴이 ID" string userNm "글쓴이 이름" string contents "내용" datetime ctime "생성일시" datetime utime "수정일시" } -
순차흐름
sequenceDiagram Actor User User->>Frontend: 새글저장 Frontend->>atc01001: 게시물 작성 (atc01001a01) atc01001->>DB: save(게시물정보) DB->>atc01001: 성공여부 atc01001->>Frontend: 성공여부 또는 오류정보 Frontend->>User: 완료페이지
3-6-9. 게시물상세조회
-
순차흐름
sequenceDiagram Actor User User->>Frontend: 게시물 조회 Frontend->>atc01001: 게시물 조회 (atc01001a02) atc01001->>DB: findOneByIdEquals(id) DB->>atc01001: 게시물정보 atc01001->>Frontend: 게시물정보 Frontend->>User: 게시물 상세 페이지
3-6-10. 게시물삭제
-
순차흐름
sequenceDiagram Actor User User->>Frontend: 게시물 삭제 Frontend->>atc01001: 게시물 삭제 (atc01001a03) atc01001->>DB: delete(id) DB->>atc01001: 성공여부 atc01001->>Frontend: 성공여부 또는 오류정보 Frontend->>User: 결과페이지
3-6-11. 게시물검색
-
검색정보
erDiagram SearchEntity { string searchType "검색타입" string keyword "검색키워드" integer rowStart "검색시작" integer rowCount "검색수량" integer pagePerScreen "한화면에 표기할 페이지갯수" integer rowTotal "결과리스트총갯수" list list "결과목록" } -
순차흐름
sequenceDiagram Actor User User->>Frontend: 게시물 검색 Frontend->>atc01001: 게시물 검색(atc01001a04) atc01001->>DB: searchArticle(검색정보) DB->>atc01001: 게시물정보 목록 atc01001->>Frontend: 검색정보 Frontend->>User: 결과페이지
4. 결과물
-
본 결과물은 backend 까지 완성된 결과물로서 swagger-ui 로 표현되어있다.
-
실행 결과물은 다음과 같다.
결과물 git주소 : https://gitlab.ntiple.com/developers/study-202403