본문 바로가기
개발/KB IT's Your Life 7기

KB IT's Your Life 7기 - 서버 사이드 백엔드 개발 후기

by Lylica 2026. 7. 12.

 

이번 주를 끝으로 그동안의 교육과정이 모두 끝났다.

 

마지막 교육 내용은 Vue.js와 Spring Legacy를 이용해서 하나의 게시판 백엔드를 구현하는 과정이었다. 

 

생각해보면 이 블로그 포스팅이 동작하는 과정 자체를 구현하는 것이라고 봐도 되지 않을까?

 

간단하다면 간단하지만, 그래도 역시 기초적인 내용에 충실할 수 있는게 CRUD 게시판 구현인가 내심 느끼게 된다.

 

이것이 마지막 수업이다.

 

백엔드 계층 구조

 

참 많이도 보아왔던 계층 구조다.

 

어떤 곳에서 어떤 역할을 담당하고, 어떤 책임을 지는지, 항상 고민해오던 시간이 있었다.

 

해당 내용을 계속해서 반복하고 있다. 눈으로 익히고, 손으로 치면서 체화하고.

 

그런 과정을 반복했다.

 

 

Controller는 클라이언트가 전달한 게시글 번호를 받고 Service에 조회를 요청한다.

 

Service는 Mapper가 조회한 객체를 확인하고, 응답에 사용할 DTO로 변환한다.

 

Mapper 는 Service와 MyBatis SQL를 연결한다.

 

MyBatis와 DB에서 게시글, 그에 연결된 첨부파일을 함께 조회한다.

 

 

그런 흐름이다. 

 

 

REST API 처리 흐름

 

위의 흐름도는 결국 처음의 백엔드 계층 구조에서 크게 벗어나지 않았다.

 

컨트롤러, 서비스, Mapper, MyBatis의 DB 조회.

 

전부 동일한 흐름이다.

 

단지 REST의 스타일에 맞춰서 요청을 송수신하는 과정이 필요할 뿐이다.

 

이렇게 흐름이 정해져 있으니, 이 흐름을 기억하고 체화하는게 중요한거다.

 

내가 당장 코드를 고쳐야 할 때 어디가 무슨 역할을 하는지 구조만 보고도 이해할 수 있게 만들어주고 싶은게 아닐까 싶다.

 

 

MyBatis 객체 매핑

 

우리가 보여줄 게시글 객체 하나를 만드는 과정도 있었다.

 

하나의 게시글과 여러개의 첨부파일 목록을 엮어서 가져오는 과정이었다.

 

당연하지만, 하나의 게시글에 여러개의 첨부 파일이 있을 수 있으니, 각 게시글별로 JOIN을 수행해주는 것이 필요했다.

 

<resultMap id="attachmentMap"
           type="org.scoula.board.domain.BoardAttachmentVO">
    <id column="ano" property="no"/>
    <result column="bno" property="bno"/>
    <result column="filename" property="filename"/>
    <result column="path" property="path"/>
    <result column="content_type" property="contentType"/>
    <result column="size" property="size"/>
    <result column="a_reg_date" property="regDate"/>
</resultMap>

<resultMap id="boardMap"
           type="org.scoula.board.domain.BoardVO">
    <id column="no" property="no"/>
    <result column="title" property="title"/>
    <result column="content" property="content"/>
    <result column="writer" property="writer"/>
    <result column="reg_date" property="regDate"/>
    <result column="update_date" property="updateDate"/>

    <collection property="attaches"
                resultMap="attachmentMap"/>
</resultMap>

<select id="get" resultMap="boardMap">
    SELECT b.*,
           a.no AS ano,
           a.bno,
           a.filename,
           a.path,
           a.content_type,
           a.size,
           a.reg_date AS a_reg_date
    FROM tbl_board b
    LEFT OUTER JOIN tbl_board_attachment a
        ON b.no = a.bno
    WHERE b.no = #{no}
    ORDER BY a.filename
</select>

 

코드로 보면 대략 이렇게 나온다.

 

resultMap이 SQL 조회 결과를 자바의 객체 필드 어디에 넣을지 정해주는 역할이니까ㅡ 우리가 사용할 VO 객체에 맞게 만들어주면 되는 것이다.

 

어렵긴 한데, 또 막상 직접 들여다보면 VO 하나 또 만드는 느낌일 뿐이다. 정확하게만 적어주면 되던 일이다.

 

이중 인증 구조

 

이제 프론트도 관리하고, 백엔드도 관리해야 한다.

 

그중에서 인증은 아무래도 중요하니까, 앞단 뒷단 모두 관리하는게 중요하다.

 

그래서 프론트엔드에서는 인증 가드로 로그인 하지 않은 애들을 로그인 페이지로 넘겨버린다.

 

동시에 서버에서는 POST, PUT, DELETE 같은 데이터를 조작하게 될 요청들마다 인증을 요구하게 된다.

 

진짜 이녀석이 이 요청을 처리해도 되는 놈인지 ( 인증과 인가 ) 하는 과정을 배웠다.

 

Multipart 요청처리

 

이제 단순히 문자 데이터만 넘기는게 아니라 첨부파일도 함께 넘기기 때문에 Multipart 요청이라는 점이 있겠다.

 

그래서 컨트롤러에서는 @RequestBody 어노테이션을 붙이지 않고 사용하게 된다.

 

그리고, 컨트롤러가 멀티파트 동작을 다루기 전에 앞단에서 적절한 필터 체인을 거쳐서 전송해주도록 만들었다.

 

단순히 서블릿에 들어가기 전에 요청과 응답을 순서대로 검사하고 변환하는 연결 구조를 만들어보는 시간이었다.

 

 

트랜잭션 처리

 


트랜잭션, 정말 중요한 개념이다.

 

MySQL 에서 왜 중점적으로 다루지 않았나 생각해서 포스팅을 올리기도 했었고.

 

Java 프로그래밍 파트에서 안정성의 측면을 강조할 때도 이 트랜잭션을 예시로 들었다.

 

그 때도 @Transactional 어노테이션으로 추상화해서 구현한다고 언급했었다.

 

이제는 그걸 제대로 활용할 뿐이다.

 

게시글 한 건과 첨부파일이 여러개가 같이 등록되는 구조니까, 트랜잭션을 넣어서 일부데이터만 저장되는 참사를 막아주게 된돠.

 

 

REST API 구성

 

결국 컨트롤러는 프론트엔드와 어떻게 상호작용할지 적어주는 공간이기 때문에, 정확한 명세를 적어주는게 좋다.

 

저런 여러가지 상호작용에 대해서 REST API 방식으로 BoardController를 구성하게 된다.

 

게시판 관련 URL과 HTTP 메서드를 어노테이션으로 모아주는 역할로 만들었다.

 

 

페이지네이션 파이프라인

 

마지막으로 게시판의 페이지네이션을 구현해본다.

 

여러개의 게시글을 적절하게 긁어오되, 이제 서버와 URL 상태를 맞추는게 조금 더 중요했던 것 같다.

 

서버는 PageRequest로 offset을 계산해서 전체 건수와 현재 목록을 (Page<T>) 반환했다.

 

프론트에서는 page랑 amount를 URL에 정보를 계속 남겨둬서 (쿼리스트링) 내가 보고있던 목록 위치를 다시 찾아올 수 있게 만드는 방법을 배웠다.

 

 

회고

 

마침내 부트캠프 정규 수업과정이 끝나게 되었다.

 

이제는 새로운 사람들을 만나서 새로운 프로젝트를 진행하게 된다.

 

내가 배웠던 모든 내용들이 이 프로젝트에서 새롭게 태어나 꽃피우게 될 것이니,

 

즐거운 마음으로 나아가자.