블로그
전체 32025. 03. 23.
0
[인프런 워밍업 클럽 3기] 3주차 발자국
3주차에는 Admin 개발 실습을 진행했다.Presentation vs. AdminPresentation사용자(방문자)가 보게될 화면에 대한 기능 개발(ex) 홈페이지 메인 페이지, 회원가입/로그인, 계정 정보, 검색 기능 등등 Admin내부 운영진이 보게될 화면에 대한 기능 개발(ex) 사용자 관리, 사용 통계 대시보드, 시큐리티 관리 등등 Q. 굳이 사용 영역을 나눠주는 이유는 무엇일까?A1. 보안 강화: 외부에 노출되면 안되는 데이터(사용자 정보, 매출 등)를 별도로 다루기 위해A2. 개발 및 배포 분리: 각 영역을 독립적으로 관리하기 위해 -> Admin은 내부적으로, Presentation은 외부적으로A3. 권한 분리: 데이터 접근 권한을 달리 하기 위해 -> 운영자 한정으로 고급 권한을 부여 즉, 쉽게 말해 홈페이지와 구별되는 '운영자 전용 작업 페이지'를 만드는 작업이다.Admin 작동 구조크게 보았을 때, 이전에 실습했던 Achievement, Skill 등등 포트폴리오에 들어갈 사항들을 DB 테이블에 맞춰 각자 service 기능을 서술하고 이를 응답했을 때의 예외 처리 기능인 exception이 메인이었다. 작동 방식Presentation과 같다! 아래는 이해를 돕기 위해 이미지. 느낀 점controller, service, exception 등등 이때까지 해오면서 본 과정과 비슷했다.물론 이해하기 어려운 부분이 있었지만 Kotlin을 써보지 못한 낯섬에서 오는 문제라고 생각했다.이번 주에 아쉬운 점이 있다면 강의에서 사용된 뷰 템플릿의 유료화로 강의 진행에 차질이 있었다는 점.물론 강사님의 잘못은 아니지만 기간 내 완강을 하지 못하는 것에 아쉬움이 남는 것은 어쩔수가 없겠다.
워밍업
・
3주차
2025. 03. 16.
0
[인프런 워밍업 3기] 2주차 발자국
[2주차]강의수강이론으로 알고 있었지만 실습에 들어가니 스프링은 굉장히 개념들이 잘 세분화 되어있다는 것을 느낄 수 있었습니다.실습해보면서 배운 각 개념들에 대해 회고하며 복습해보도록 하겠습니다.Repository: 데이터베이스와 직접적으로 상호작용하는 계층. DB 쿼리에 대한 청사진을 그린다고 이해했습니다. -> 그 역할을 해주는 인터페이스가 JPA.그 인터페이스를 받아서 @Repository가 붙인 Presentation 컴포넌트 클래스에서 직접 사용.interface AchievementRepository : JpaRepository { // 문법에 맞게 JPA를 작성하면 DB에서 다음과 같은 쿼리가 작용한다. // select * from achievement where is_active = :isActive fun findAllByIsActive(isActive: Boolean): List }// 개별적인 JPA Repository의 기능을 모아서 제공하는 서비스 성격의 Repository 클래스. @Repository class PresentationRepository( // 여러 개의 Repository 인터페이스를 필드로 주입받는다. private val achievementRepository: AchievementRepository, private val experienceRepository: ExperienceRepository, private val introductionRepository: IntroductionRepository, private val linkRepository: LinkRepository, private val projectRepository: ProjectRepository private val skillRepository: SkillRepository, ) { fun getActiveAchievements(): List { return achievementRepository.findAllByIsActive(true) } ... } DTO(Data Transfer Object, 데이터 전송 객체). 쉽게 말해, 여러 개의 데이터를 하나의 상자로 포장해 옮긴다.레이어드 계층 간에 데이터 전송을 위한 객체.순수 데이터 이동이 목적. 거기에 불필요한 데이터 전송을 방지해 보안성을 높인다고 함.사용 사례// Introduction Entity에는 content와 isActive 필드가 있다. // 그중에서 content 필드만 선택적으로 골라서 전송하는 것이다. data class IntroductionDTO( val content: String ) { constructor(introduction: Introduction) : this( content = introduction.content ) }@Service class PresentationService( private val presentationRepository: PresentationRepository ) { // 트랜잭션을 간편하게 열고 닫을 수 있게 해줍니다. @Transactional(readOnly = true) fun getIntroductions(): List { val introductions = presentationRepository.getActiveIntroductions() // 엔터티 리스트 가져오기 return introductions.map { introduction -> IntroductionDTO(introduction) } // DTO 변환 후 반환 } }Service: 비즈니스 로직을 담당하는 계층여러 개의 Repository에서 데이터를 가져와 비즈니스에 맞게 조합하는 계층.단순 조합을 넘어 요구사항에 맞는 규칙을 적용하는 것도 가능.Controller와 Repository 중간에서 데이터를 제어. Controller: 사용자의 요청을 처리하는 계층. 사용자가 원하는 데이터를 조회하거나, 자신이 알고있는 데이터를 서버에 전송한다. Request.Controller에서 검증사용자의 요청에 응답한다. 알고 있는 데이터를 보여준다던지 받아서 저장한다든지. Response.우리 실습에선 ApiController와 ViewController가 있었다. 각각 REST Api와 웹 페이지 담당이라고 하는데 ApiController가 잘 이해가 안돼서 다시 봐야될 것 같다... @Controller class PresentationViewController( private val presentationService: PresentationService ) { @GetMapping("/") fun index(model: Model): String { // 변수 model에 Introduction 정보를 추가한다. val introductions = presentationService.getIntroductions() model.addAttribute("introductions", introductions) // 변수 model에 Link 정보를 추가한다. val links = presentationService.getLinks() model.addAttribute("links", links) return "presentation/index" } }테스트 코드: 코드의 안정성을 보장하는 장치. 개발 시 가장 많은 시간이 소비되는 작업."코드가 잘 작동하는걸 증명할게!"라는 느낌으로 작성.각 계층마다 예상되는 오류를 최대한 많이 상정해서 테스트 코드를 많이 만드는게 좋음.given, when, then으로 나눠서 테스트 코드를 작성한다고 함.@SpringBootTest @AutoConfigureMockMvc @DisplayName("[API 컨트롤러 테스트]") class PresentationApiControllerTest( @Autowired private val mockMvc: MockMvc ) { @Test @DisplayName("Introductions 조회") fun testGetIntroductions() { // given val uri = "/api/v1/introductions" // when val mvcResult = performGet(uri) val contentAsString = mvcResult.response.getContentAsString(StandardCharsets.UTF_8) val jsonArray = JSONArray(contentAsString) // then assertThat(jsonArray.length()).isPositive() } } Thymeleaf 중복 처리에 대하여Thymeleaf: Spring Boot에서 사용하는 서버사이드 템플릿 엔진. 즉, 백엔드에서 동적으로 HTML을 생성할 수 있도록 도와주는 도구받아온 템플릿을 고치는 과정에서 중복 처리 과정을 거쳤다.페이지마다 중복되는 navigation, header, footer를 각 html로 옮긴뒤 불러오기 기능을 사용하는 것.새 페이지를 만들 때 사용하면 코드의 가독성도 오르고, 작업 효율도 오를 것이다.힘들었던 점실행을 해보니 resume와 projects 웹페이지의 응답이 이뤄지지 않아 적잖이 당황했었다.로그 메세지를 따라가면서 모든 계층을 확인해봐도 해결이 안되던 것이었는데 결국 문제는 Repository 이름 오타 때문에 클래스를 찾지 못해 Controller 작동이 안되던 것이었다.되게 단순한 문제였지만 동시에 찾기 어려웠다. 기본을 잘 지키며 개발해야겠다고 생각했다...
워밍업
・
2주차
2025. 03. 09.
0
[인프런 워밍업 클럽 3기] 1주차 발자국
[1주차]강의수강웹 서비스를 구성하는 요소 - 클라이언트에 요청에 의해 동작하는 과정 학습 클라이언트: 요청하는 주체서버: 응답하는 객체(CRUD 작업)데이터베이스: 데이터의 집합 (ex) DBMS: Oracle, MySQL 등MVC 패턴 - 요청을 받은 서버의 동작을 개발자가 기능 역할에 따라 분류한 소프트웨어 아키텍처 디자인 패턴 Model: 데이터를 담는다. Controller는 데이터를 넣고, View는 데이터를 꺼내온다.View: User에게 보여지는 화면을 담당한다. Model에서 데이터를 꺼내온다.Controller: 요청을 받으면 그에 합당한 기능을 수행한다. 작업의 결과물을 Model에 넣는다.레이어드 아키텍처: 세 개의 계층으로 된 소프트웨어 아키텍처. 스프링에서 자주 사용함Presentation(Controller): Service의 함수 호출Service: MVC에서 Controller의 기능을 담당한다. Repository에서 데이터를 불러와 CRUD 작업을 수행.Repository: DB에 접근하여 작업을 요청한다.스프링 Bean과 컨테이너에 대한 개념 - 흔히, 자바에서 가장 중요한 "객체"와 "상속"의 개념으로 이해했다.REST API: HTTP 통신으로 동작하는 어플리케이션 기능을 정의하는 일종의 규칙, 컨벤션 Query Parameter, HTTP Request Body, Path VariableUsing @RequestParam, @RequestBody, @PathVariable데이터베이스: 이론적으로는 데이터의 집합. Excel, Access 같은 것도 DB에 속하지만 웹 개발에서는 DBMS를 뜻함.관계형 데이터베이스: 데이터를 행과 열로 이루어진 표의 형태로 저장 (Oracle, MySQL, PostgreSQL)한 행은 한 개의 데이터, 한 열은 하나의 데이터 특성'키(key)'라는 개념에 따라 1:1 또는 1:N 또는 N:M의 관계를 가질 수 있게 함비관계형 데이터베이스: 관계형 데이터베이스를 제외한 모든 종류 (MongoDB, Redis)학습 회고- 학교 수업과 동아리에서 배웠던 내용들이라 친숙했다. 아마 웹 개발에 필요한 핵심 개념들은 모두 들어있다고 생각한다. 특히나 Spring을 다뤄본적 없는 내 입장에서는 'Bean'이라는 개념이 가장 신선하게 다가왔던 것 같다.미션아직 스터디 초기 단계! 레포지토리 만들고 commit 하는 미션에 어려움은 없었다.프로젝트의 목적: 우리 동네 도서관의 사물함 예약 서비스를 이용하는데 불편함을 느껴 한번 만들어보고자 함
워밍업
・
1주차