[플레이데이터 풀스택 백엔드 9기] 5월 5주차 회고 (11주차)

FerryLa·2025년 6월 3일

서론

5월 5주차 (11주차) - (05/26 ~ 06/01)

스프링 프레임워크의 다형성과 캡슐화로 인해 편의성이 대폭 상승함을 느꼈습니다.
다만, 실질적으로 함축적이기에 어려운 내용이라고 느꼈습니다. 가능한 구조적인 부분과 형식적인 부분에 대해 학습하려 했고, 이해하는 시간이 더 필요하다는 생각이 들었습니다.

1. 내용정리

MVC (복습)

  1. Controller 계층은 클라이언트의 요청을 처리하고 비즈니스 로직을 실행한 뒤 Model 객체를 반환
  2. Service 계층은 비즈니스 로직을 수행하는 역할, Controller에서 전달받은 Model 객체를 가공하고, DAO에서 전달받은 데이터를 조합하여 비즈니스 로직을 실행
  3. DAO 계층은 데이터베이스와의 상호작용을 담당 데이터베이스에 접근하여 데이터를 조회하거나 수정하는 등의 작업을 수행
  4. 이렇게 수행된 결과는 Service 계층으로 전달되어 가공된 후, Controller 계층으로 반환

[SpringWeb]

핸들러 메서드 (Handler Method)

  • 요청 처리
    • @GetMapping: GET 요청을 처리하는 어노테이션
    • @PostMapping: POST 요청을 처리하는 어노테이션
    • @RequestMapping: GET, POST, PUT, DELETE 등 모든 HTTP 메서드에 대해 매핑할 수 있는 가장 기본적인 어노테이션. (@RequestMapping은 value={"/modify", "/delete"}처럼 여러 개의 URL을 지정할 수 있으며, params, headers 등의 조건을 추가해 더욱 세밀하게 매핑 가능
    • WebRequest 파라미터 : HTTP 요청 정보를 받아올 수 있는 객체로, HttpServletRequest보다 더 유연하게 사용할 수 있음
    • @RequestParam: 특정 요청 파라미터를 매핑하는 어노테이션으로, 값을 받아올 때 required, defaultValue 등의 속성을 지정 가능
    • 그 외 @ModelAttribue, @SessionAttribute, @RequestBody 등
  • 세션 처리
    • @SessionAttributes → Model을 통해 자동으로 세션에 값 저장
    • SessionStatus.setComplete() → 세션 만료 처리
    • @RequestBody → 요청 바디 데이터 가져오기
    • @RequestHeader → HTTP 헤더 값 가져오기
    • @CookieValue → 특정 쿠키 값 가져오기

예외 처리 (Exception Handler)

  • 컨트롤러 레벨의 예외 처리
    • @ExceptionHandler가 붙은 메서드로 특정 뷰를 반환하거나 처리
    • 특정 컨트롤러에서 발생하는 예외만 처리 (컨트롤러 단)
  • 전역 에외 처리
    • @ControllerAdvice를 클래스에 사용해 모든 컨트롤러에서 발생하는 에외를 통합 관리
    • 여러 개의 컨트롤러에서 발생하는 예외를 한 곳에서 일괄적으로 처리

인터셉터 (Interceptor Handler)

애플리케이션 전역에서 공통 코드의 재사용성과 유지보수를 크게 개선하고 인증, 권한 체크와 같이 반복적으로 필요하지만 분리된 로직을 중앙집중적으로 관리할 때 유용한 도구

  • 특징
    • 클라이언트 요청을 가로채서 공통 로직을 처리하거나, 인증 및 권한 검사를 수행하는 기능을 제공
    • 필터와 유사하지만 스프링 컨텍스트 내부에서 동작하여 빈으로 관리되며 의존성 주입이 가능
  • 핵심매서드 사용
    • preHandle() : 컨트롤러 실행 전, 요청을 가로챔
    • postHandle() : 컨트롤러 실행 후, 뷰 렌더링 전 호출됨
    • afterCompletion() : 뷰 렌더링 후 호출됨
  • 등록 및 적용
    인터셉터는 WebMvcConfigurer를 통해 스프링 컨텍스트에 등록되며, 특정 URL 패턴에 대해 적용

타임리프 (Thymleaf)

서버 사이드 템플릿 엔진 / 컨트롤러에서 전달받은 모델 데이터를 HTML 템플릿 내의 표현식을 사용해 동적으로 렌더링

  • 방식
    1. Spring 프로젝트에 Thymeleaf 의존성을 추가하고, 컨트롤러에서 데이터를 준비
    2. HTML 파일에 Thymeleaf 네임스페이스를 선언하고, 컨트롤러에서 전달된 데이터를 바인딩
    3. HTML 파일에 표현식 사용
    4. th:if, th:unless로 조건부 처리하고, th:each를 통해 목록 데이터를 반복적으로 출력
    5. 애플리케이션을 실행한 후 브라우저에서 동작하는지 확인
  • 표현식
    • 변수 표현식 (${...}) th:text="\${member.name}"
    • 선택 표현식 (*{...}) th:value="*{username}"
    • 메시지 표현식 (#{...}) th:text="#{welcome.message}
    • 링크 URL 표현식 (@{...}) th:href="@{/lecture/expression}
    • 프래그먼트 표현식 (~{...}) th:replace="~{fragments/header :: header}

[MyBatis]

Myatis CRUD 구성( java방식)

  • DTO (Data Transfer Object)
    • 데이터의 이동을 담당하며, 주로 데이터베이스의 테이블과 대응 되는 형태
  • DTO (Data Access Object)
    • XML 매퍼에 정의된 SQL 문을 실행하는 역할을 수행
    • SQL 실행 결과를 받아 Service 계층에 반환
  • Service
    • 비지니스 로직을 구현하며, 여러 DAO를 조합하여 복합적인 작업을 수행
  • Controller
    • 클라이언트의 요청을 받아 Service를 호출하고, 결과를 클라이언트에 전달
  • MapperXML
    • menu-mapper.xml 파일과 같이 CRUD 작업에 해당하는 SQL문이 정의되어 있으며, 데이터베이스와의 실제 상호작용을 담당
  • MyBatis 설정 파일
    • mybatis-config.xml 파일에서 MyBatis 전체 설정 (예: 환결 설정, 메퍼 경로 등)이 정의
  • Mapper 인터페이스
    • MyBatis에서 SQL 실행 메서드의 계약을 정의
    • 인터페이스에 선언된 메서드와 XML 메퍼 또는 어노테이션 기반 SQL이 자동으로 연결되어, MyBatis가 런타임에 동적 프록시 객체를 생성해 실제 SQL 실행을 담당
    • 스프링 환경에서는 @Mapper 어노테이션이나 @MapperScan을 이용해 빈으로 등록되고 의존성 주입(DI)을 받을 수 있어, 타입 안정성과 코드 유지보수가 용이
public interface MenuMapper {
    @Results(id="menuResultMap", value = {
            @Result(id= true, property = "menuCode", column = "menu_code"),
            @Result(property = "menuName", column = "menu_name"),
            @Result(property = "menuPrice", column = "menu_price"),
            @Result(property = "categoryCode", column = "category_code"),
            @Result(property = "orderableStatus", column = "orderable_status")
    })
    @Select("        SELECT\n" +
            "               menu_code\n" +
            "             , menu_name\n" +
            "             , menu_price\n" +
            "             , category_code\n" +
            "             , orderable_status\n" +
            "          FROM tbl_menu\n" +
            "         WHERE orderable_status = 'Y'\n" +
            "         ORDER BY menu_code")
    List<MenuDTO> selctAllMenu();

    @ResultMap("menuResultMap")
    @Select("SELECT\n" +
            "              menu_code\n" +
            "            , menu_name\n" +
            "            , menu_price\n" +
            "            , category_code\n" +
            "            , orderable_status\n" +
            "        FROM tbl_menu\n" +
            "        WHERE menu_code = #{ menuCode }")
    MenuDTO selectMenuByMenuCode(int menuCode);

    @Insert("  INSERT\n" +
            "          INTO tbl_menu(menu_name, menu_price, category_code, orderable_status)\n" +
            "        VALUES\n" +
            "            (#{ menuName }, #{ menuPrice }, #{ categoryCode }, 'Y')")
    int insertMenu(MenuDTO menu);

    @Update(" UPDATE tbl_menu\n" +
            "           SET menu_name = #{ menuName }\n" +
            "             , menu_price = #{ menuPrice }\n" +
            "             , category_code = #{ categoryCode }\n" +
            "         WHERE menu_code = #{ menuCode }")
    int updateMenu(MenuDTO menu);

    @Delete("        DELETE\n" +
            "          FROM tbl_menu\n" +
            "         WHERE menu_code = #{ menuCode }")
    int deleteMenu(int menuCode);
}

XML방식 주요 설정

  • MyBatis 환경 설정
[mybatis-config.xml]

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!-- 개발 환경 설정, 기본값을 'development'로 지정 -->
    <environments default="development">	
        <environment id="development">
        <!-- 트랜잭션 관리 설정: JDBC를 사용하여 직접 관리 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED"> <!-- 데이터베이스 연결 풀 사용 -->
                <!-- MySQL JDBC 드라이버 설정 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!-- 데이터베이스 연결 URL 설정 (로컬 MySQL, menudb 사용) -->
                <property name="url" value="jdbc:mysql://localhost:3306/menudb"/>
                 <!-- 데이터베이스 접속 계정 정보 -->
                <property name="username" value="ohgiraffers"/>
                <property name="password" value="ohgiraffers"/>
            </dataSource>
        </environment>
    </environments>
    
     
    <!-- 매퍼(XML 파일) 등록: SQL 문을 포함하는 매퍼 지정 -->
    <mappers>
        <mapper resource="menu-mapper.xml"/>
    </mappers>
</configuration>
  • SQL 매핑 정의 (Java와 DB 연결)
[mapper.xml]

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ohgiraffers.transaction.mapper.OrderMapper">
<!--    select -->
    <select id="selectDate" resultType="java.util.Date">
        select NOW()
    </select>

<!--    insert -->
    <insert id="insertOrder" useGeneratedKeys="true" keyProperty="orderCode">
        INSERT INTO tbl_order (order_date, order_time, total_order_price)
        VALUES (#{ orderDate }, #{ orderTime }, #{ totalOrderPrice })
    </insert>
    <insert id="insertOrderMenu">
        INSERT INTO tbl_order_menu (order_code, menu_code, order_amount)
        VALUES (#{ orderCode }, #{ menuCode }, #{ orderAmount })
    </insert>

</mapper>
  • 스프링부트 환경설정 (yml파일)
[application.yml] 
# mybatis config
mybatis:
  configuration:
    map-underscore-to-camel-case: true
  type-aliases-package: com.ohgiraffers.transaction
  mapper-locations: mappers/**/*.xml

2. 마무리

> 좋았던 점과 아쉬웠던 점

SQLD 자격증 시험은 생각보다 쉽지 않았고, 결과는 좋지 못할 것 같아 아쉬움이 남습니다.
첫 자격증 시험이라는 것에 의미가 있었고, 쿼리문을 복습했다는 점에 의의를 두었습니다.

> 개선할 점

회고를 작성하면서 느낀 점은 학습 내용을 요약하여 정리하지 못했다고 느꼈습니다.
효과적인 복습을 위해 핵심 내용을 보다 체계적으로 정리하는 방법이 필요해 보입니다.

> 다음주 계획

MyBatis CRUD JavaConfig방식, MyBatis와 Spring 연동에 관해 재복습하고 테스트

커리큘럼 : 스프링 프레임워크 (JPA)
08/09 : ADsP 자격증 시험

profile
김지환

0개의 댓글