블로그

vin

[인프런 워밍업 클럽 BE 2기] 백엔드 프로젝트 - 4주차 발자국

마지막 주차인 4주차는 지금까지 개발한 어디민 페이지의 뷰를 개발하였고, 스프링 시큐리티를 이용한 로그인 개발, 로그 저장 등의 기능을 구현 하였다. 프로젝트를 마무리 짓고 최종적으로 docker와 구글 클라우드를 이용해서 배포를 하였다. 어드민 화면 개발 1부트스트랩 템플릿 적용 시 코드 분석 및 TODO 체크 기능 해제: 부트스트랩 템플릿을 사용해 UI를 구성할 때 코드 변경 사항이 많아 analyze code와 check TODO 기능이 오래 걸려, 이를 해제하여 커밋 및 푸시 시간을 줄임.사이드바 개발에서 th:classappend, th:attr data-bs-target, th:classappend show 사용: Thymeleaf의 th:classappend를 이용해 동적으로 클래스를 추가하고, th:attr을 통해 부트스트랩의 data-bs-target 속성을 설정하여 UI 요소를 제어함. show 클래스를 사용해 사이드바를 열고 닫는 동작을 구현.뷰 레이아웃 개발 및 테이블 페이지(Table) 구현: HTML 템플릿에서 레이아웃을 설계하고, 데이터가 표시될 테이블 형태의 페이지를 구성. 이를 통해 표 형태로 데이터를 보기 쉽게 표시./*<![CDATA[*/ 구문 사용과 [[${pageName}]] 바인딩: Thymeleaf에서 스크립트를 안전하게 사용하기 위해 CDATA 구문을 사용하고, ${pageName}을 통해 페이지 이름을 동적으로 바인딩하여 화면에 표시.테이블 아이디 tableName 설정: HTML에서 테이블을 식별하기 위한 아이디를 tableName으로 설정하여 JavaScript 등에서 쉽게 접근 가능하도록 함. 어드민 화면 개발 2테이블 페이지(Form) 개발: 사용자가 데이터를 입력하고 제출할 수 있는 Form 페이지를 구성. 입력된 데이터를 서버로 전송하고 처리하는 역할을 함.onsubmit : Form이 제출되기 전에 특정 JavaScript 함수를 실행하여 데이터를 검증하거나 추가 작업을 수행할 수 있게 해주는 이벤트.대시보드와 로그인 기능 개발스프링 시큐리티를 이용한 로그인 개발: 스프링 프레임워크에서 제공하는 시큐리티 모듈을 사용해 사용자 인증 및 권한 관리를 구현. 안전한 로그인 기능을 제공.패스워드 인코더 및 필터 체인 개발: 패스워드 보안을 위해 PasswordEncoder를 사용해 비밀번호를 암호화하고, 인증 과정을 제어하기 위해 필터 체인을 설정함.AntPathRequestMatcher 사용: 특정 URL 경로와 HTTP 메서드에 대해 시큐리티 필터링을 설정하는 데 사용. 로그아웃 등의 특정 경로에 대해 시큐리티를 설정할 때 유용함.구글 클라우드 플랫폼으로 프로젝트 배포Docker로 MySQL 실행 및 컨테이너 설정: Docker 이미지를 사용해 MySQL 데이터베이스를 컨테이너로 실행하고, 필요한 포트와 환경 변수를 설정하여 데이터베이스를 관리.ports, command, volumes 설정:ports: 호스트와 컨테이너 간의 포트를 매핑하여 외부에서 데이터베이스에 접근할 수 있도록 함.command: 컨테이너가 시작될 때 실행할 명령어를 정의. 예를 들어, MySQL의 문자 집합을 설정하는 명령어를 추가.volumes: 컨테이너의 데이터가 호스트에 영구적으로 저장되도록 설정하여 컨테이너 재시작 시 데이터가 손실되지 않도록 함.프로젝트 컨테이너 설정 및 depends_on 사용: Spring 애플리케이션을 실행하는 컨테이너와 데이터베이스 컨테이너를 설정하고, depends_on을 통해 MySQL이 먼저 실행된 후 애플리케이션이 실행되도록 순서를 지정.호스트 포트 (Host Port): 호스트 컴퓨터에서 사용되는 포트입니다. 예를 들어, 3306:3306에서 앞의 3306이 호스트 포트입니다. 이는 Docker를 실행하는 컴퓨터에서 접근 가능한 포트 번호를 의미합니다. 다른 컴퓨터나 서버에서 이 호스트의 IP 주소와 포트를 사용하여 Docker 컨테이너의 서비스에 접근할 수 있습니다.컨테이너 포트 (Container Port): 컨테이너 내부에서 서비스가 실행되는 포트입니다. 3306:3306에서 뒤의 3306이 컨테이너 포트입니다. 이는 컨테이너 내부에서 MySQL 서비스가 동작하는 포트를 의미합니다. 컨테이너 내의 애플리케이션은 이 포트를 통해 데이터베이스와 통신합니다.Docker로 프로젝트 빌드Google Cloud Platform에서 Compute Engine 인스턴스 생성: 애플리케이션을 배포할 가상 머신을 생성하여, Docker 컨테이너를 실행할 환경을 제공.도커 허브로 푸시 시 커맨드로 진행: Docker Desktop에서 푸시 시 발생하는 오류를 해결하기 위해 명령어를 사용하여 직접 푸시.Compute Engine에서 도커 컨테이너 실행: Google Cloud에서 생성한 인스턴스에 도커 컨테이너를 실행하여 애플리케이션을 운영.메모리 스왑 설정 및 Nginx 사용: 하드디스크의 일부를 메모리처럼 사용하는 메모리 스왑을 설정하고, Nginx를 사용해 애플리케이션의 로드 밸런싱 및 리버스 프록시 역할을 설정.도메인 연결 및 HTTPS 적용: 애플리케이션에 도메인을 연결하고 SSL 인증서를 적용하여 HTTPS를 통해 안전하게 서비스.[미션 6] MySQL에 내 데이터 넣기문제 상황: Docker로 실행한 MySQL과 DBeaver에서 연결된 데이터베이스의 내용이 달랐음.원인: 과거 MariaDB 사용 이력이 있어, MariaDB와 MySQL이 서로 다른 포트로 연결되어 데이터가 불일치.DBeaver에서는 MariaDB에 연결되고, Docker에서는 MySQL에 연결되는 상황 발생.해결 방법: MariaDB의 서비스를 중단하여 MySQL만 실행되도록 설정하여 문제를 해결.[미션 7] 내 포트폴리오 도메인 공유하기문제 상황: Google Cloud Compute Engine에서 Docker Hub의 이미지를 pull하려 했으나, Docker push가 되지 않아 pull이 실패.원인: Docker Desktop 4.3.3 버전 이후로, Docker Desktop을 통한 push에서 오류 발생.해결 방법: Docker Desktop 대신 명령어를 사용해 push하여 문제를 해결.

웹 개발워밍업클럽백엔드프로젝트웹개발백엔드

vin 26일 전
vin

[인프런 워밍업 클럽 BE 2기] 백엔드 프로젝트 - 3주차 발자국

이번 주차에서는 포트폴리오 사이트 화면과 어드민 기능을 개발하며, 사이트의 삽입, 수정, 조회 API 구현과 인터셉터 설정을 완료하였다. 타임리프와 부트스트랩을 활용한 뷰 템플릿 구성, 데이터 처리, 예외 관리 등 다양한 기능을 학습하며 웹 개발의 전체적인 흐름을 이해할 수 있었다. 포트폴리오 사이트 화면 개발하기 1RestController와 Controller의 차이점RestController: JSON 데이터를 반환하며, 주로 RESTful API를 구현할 때 사용. HTML 뷰 템플릿을 반환하지 않음.Controller: HTML 등 뷰 템플릿을 반환하기 위해 사용.부트스트랩과 타임리프 프래그먼트 사용부트스트랩 템플릿 적용: 부트스트랩 사이트에서 템플릿을 다운로드하여 프로젝트에 적용.타임리프 프래그먼트 사용: head, footer, navigation 등의 공통 영역을 분리하여 프래그먼트로 구성.th:fragment: 프래그먼트의 이름을 지정해 원하는 곳에서 재사용.th:replace: 프래그먼트를 뷰 파일에 포함할 때 사용.타임리프 문법 활용th:each: 컨트롤러에서 전달된 모델 데이터를 반복하여 출력.th:text: 서버 데이터를 HTML 요소에 텍스트로 삽입.target="_blank": 링크 클릭 시 새 탭에서 열리도록 설정.포트폴리오 사이트 화면 개발하기 2동적 콘텐츠와 레이아웃 처리th:fragment에 파라미터 전달: 프래그먼트에 파라미터를 전달해 동적 콘텐츠를 처리.th:block 사용 이유: 불필요한 태그 없이 블록을 형성해 th:each와 조건부 렌더링(th:if)을 함께 사용하기 위함.d-inline 태그: 인라인 요소로 배치하여 레이아웃 조정을 쉽게 함.레이아웃 작업: 공통 레이아웃을 th:fragment로 정의해, 수정 시 모든 페이지에 자동 반영되도록 구성.인터셉터의 역할과 설정인터셉터: 컨트롤러보다 앞단에서 동작하며, 여러 컨트롤러의 요청을 잡아 공통적인 처리를 수행.addInterceptors 오버라이딩: WebMvcConfigurer에서 인터셉터를 등록할 때 사용.모든 경로를 대상으로 하며, 정적 자원 경로(CSS, JS 등)는 제외.presentationInterceptor의 HandlerInterceptor 추가:preHandle: 컨트롤러에 도달하기 전 실행.postHandle: 컨트롤러의 응답 후 실행되나, 예외가 발생하면 동작하지 않음.afterCompletion: 예외 발생 여부와 상관없이 항상 실행.HttpInterface 사용: 클라이언트 정보를 수집해 기록.어드민 공통 기능 개발하기클래스 생성 및 관리admin 패키지: 컨트롤러, 데이터 처리, 예외 처리, 인터셉터, 보안 관련 클래스를 구성.예외 처리와 로깅Throwable: 모든 오류의 최상위 클래스.Error: 복구할 수 없는 오류.Exception: 애플리케이션이 복구 가능한 오류.Checked Exception: 컴파일 시점에 예외가 검출됨.Unchecked Exception: 런타임 시점에 발생.ControllerAdvice: 인터셉터와 유사하게 동작하며, 예외 처리를 담당.@ExceptionHandler: 특정 예외를 처리하는 메소드.Logger 사용: LoggerFactory.getLogger를 활용해 로그를 기록.DTO 개발companion object: 클래스 내부에서 정적 메소드와 변수를 정의할 때 사용.vararg: 가변 인자를 받아 여러 파라미터를 전달할 수 있도록 함.filterings: 데이터에서 제외할 필드를 관리.classInfo: 클래스의 메타데이터와 정보를 담음.인터셉터 추가postHandle 오버라이딩: 메뉴 데이터를 modelAndView에 추가해 특정 페이지에 전달.addInterceptors 설정: admin 경로에 인터셉터를 추가하며, 정적 자원(CSS, JS 등)은 제외.데이터 조회 기능 개발하기조회 기능 구현context 패키지: 화면과 관련된 설정을 서버에서 관리.orElseThrow: 데이터가 없을 경우 예외를 발생.@field: 필드 유효성 검사를 수행.@PathVariable: 경로 변수를 통해 데이터를 전달.@RequestBody: 요청 본문 데이터를 객체로 변환.@Validated: 입력 데이터의 유효성을 검사.데이터 삽입, 수정, 삭제 기능 개발하기DTO와 데이터 처리form 패키지: DTO 역할을 하는 클래스들을 생성해 데이터 전달에 활용.ifPresent 사용ifPresent: 값이 존재할 때만 특정 동작을 수행하도록 처리.[미션4] 조회 REST API 만들기이번 미션에서는 제품, 브랜드, 카테고리, 재고에 대한 조회 API를 개발하고, 각 경로(/api/products, /api/brands, /api/categories, /api/stocks)에 대해 테스트 코드를 작성하였다.이번 미션에서는 조회 API 개발 및 테스트 코드 작성을 통해 RESTful API의 기본 구조를 익히고, Null 처리와 영속성 관리를 경험하였다. 특히 **?.let {}**과 ?: 엘비스 연산자를 활용해 null-safe한 코드를 작성하는 방법을 익혔으며, 서비스 계층 분리를 통해 더 효율적인 설계를 계획하게 되었다.ProductDTO에서 발생한 Null 처리 이슈와 해결조회 API를 구현하는 과정에서 ProductDTO 내의 brand와 category가 null일 경우 NullPointerException이 발생하는 문제가 발견되었다. 이를 해결하기 위해 ?.let {} 구문을 사용해 null-safe하게 처리하였다.?.let {}의 역할?.let {}: 객체가 null이 아닐 때만 코드 블록 내부를 실행한다.예시:brand = product.brand?.let { BrandDTO(it) }product.brand가 null이 아닐 경우에만 BrandDTO를 생성하고, 그렇지 않으면 실행되지 않음.엘비스 연산자(?:) 사용조회 로직에서는 **엘비스 연산자 ?:**를 사용하여, 값이 null일 경우 대체 동작을 수행하도록 하였다.?: 연산자: 왼쪽의 값이 null이면 오른쪽 값을 반환한다. product = stock.product ?: throw IllegalArgumentException("제품정보를 찾을 수 없습니다..")만약 stock.product가 null이면 IllegalArgumentException을 던지도록 처리.영속성 설정: Cascade = PERSIST재고와 관련된 엔티티를 영속성 컨텍스트에 포함시키기 위해, cascade = PERSIST 옵션을 사용하였다. 이 설정은 엔티티가 함께 영속화될 수 있도록 보장하며, 이를 통해 테스트 코드가 문제없이 성공적으로 실행되었다.재고 수량 설정과 서비스 계층 분리 계획현재 재고 테이블의 재고 수량(stockCount) 설정은 Stock 엔티티의 메서드를 통해 처리하고 있다.하지만, 이 로직을 추후 삽입 및 수정 API에서 더 깔끔하게 관리하기 위해 서비스 계층으로 분리할 계획이다.

웹 개발백엔드워밍업클럽백엔드프로젝트웹개발

vin 1개월 전
채널톡 아이콘