멀티캠퍼스

[2026.07.06] - TIL 66일차 (Spring Boot 게시판 보완과 Thymeleaf 시작)

buckwheat 2026. 7. 7. 17:35

기존 StartBoot02 게시판 프로젝트를 보완하고, StartBoot03에서 Thymeleaf 기본 문법을 학습했다.
기존 JSP 기반 흐름에서 Spring Boot 방식의 설정, 필터, 인터셉터, MyBatis Mapper 구조를 조금 더 정리했고, 이후 Thymeleaf 템플릿 사용법으로 넘어갔다.


1. StartBoot02 게시판 구조 보완

StartBoot02는 Spring Boot에서 Oracle DB와 MyBatis를 사용해 게시판 CRUD를 구현한 프로젝트다.

전체 흐름은 다음과 같다.

Controller
 -> Biz
 -> Dao
 -> Mapper
 -> DB

기존에는 DAO 안에 SQL이 직접 들어가 있었는데, SQL을 Mapper로 분리했다.

@Mapper
public interface MyBoardMapper {

    @Select(" SELECT * FROM MYBOARD ORDER BY MYNO DESC ")
    List<MyDto> selectList();

    @Select(" SELECT * FROM MYBOARD WHERE MYNO = #{myno} ")
    MyDto selectOne(@Param("myno") int myno);
}

이렇게 하면 DAO는 SQL을 직접 갖지 않고 Mapper를 호출하는 역할만 하게 된다.

@Repository
public class MyDaoImpl implements MyDao {

    @Autowired
    private MyBoardMapper mapper;

    @Override
    public List<MyDto> selectList() {
        return mapper.selectList();
    }
}

즉, SQL 관리는 Mapper에서 하고, DAO는 데이터 접근 흐름만 담당하게 되어 구조가 더 깔끔해진다.


2. Filter 설정

Spring Boot에서는 web.xml 대신 Java 설정 클래스로 필터를 등록할 수 있다.

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<Filter> checkFilter(){
        FilterRegistrationBean<Filter> regiBean = new FilterRegistrationBean<Filter>();

        regiBean.setFilter(new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                System.out.println("필터 실행!");
                chain.doFilter(request, response);
            }
        });

        regiBean.addUrlPatterns("/myboard/*");
        regiBean.setOrder(1);
        return regiBean;
    }
}

필터는 Controller에 도착하기 전에 먼저 실행된다.
공통 로그 출력, 인코딩 처리, 보안 검사 같은 작업에 사용할 수 있다.


3. Interceptor 설정

Interceptor는 Spring MVC 내부에서 Controller 실행 전후에 동작한다.

public class CheckInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("인터셉터 - 요청 uri: " + request.getRequestURI());
        return true;
    }
}

preHandle()에서 true를 반환하면 Controller가 계속 실행되고, false를 반환하면 Controller로 가지 않는다.

Interceptor는 WebMvcConfigurer를 통해 등록한다.

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CheckInterceptor())
                .addPathPatterns("/myboard/*")
                .excludePathPatterns("/myboard/test");
    }
}

Filter와 Interceptor의 차이는 다음처럼 정리할 수 있다.

Filter      : Spring MVC 바깥에서 먼저 동작
Interceptor : Controller 실행 전후에 동작

4. StartBoot03과 Thymeleaf 시작

StartBoot03에서는 Thymeleaf 템플릿 엔진을 학습했다.

Thymeleaf는 HTML 안에 th:* 속성을 사용해서 서버에서 전달받은 데이터를 출력하는 템플릿 엔진이다.

<html xmlns:th="http://www.thymeleaf.org">

Controller에서 Model에 값을 담으면:

model.addAttribute("name", "Thymeleaf!!");

HTML에서는 ${}로 값을 꺼낼 수 있다.

<h1 th:text="${name}">기본 텍스트</h1>

실제 응답에서는 기본 텍스트가 아니라 Model에 담긴 값이 출력된다.


5. Thymeleaf 유틸리티 객체

Thymeleaf에는 날짜, 숫자, 문자열 등을 처리하는 내장 유틸리티 객체가 있다.

<p th:text="${#calendars.format(#calendars.createNow(), 'yyyy-MM-dd HH:mm')}">
    #date object
</p>

숫자 포맷도 가능하다.

<p th:text="${#numbers.formatInteger(345.1234, 5)}">
    #numbers object
</p>

문자열 처리도 지원한다.

<p th:text="${#strings.toUpperCase('hello,spring boot and thymeleaf')}">
    #strings object
</p>

6. Thymeleaf 조건문과 반복문

조건문은 th:if, th:unless를 사용한다.

<p th:if="*{seq gt 30}">
    <span>seq가 30보다 크다</span>
</p>
<p th:unless="*{seq gt 30}">
    <span>seq가 30보다 작다</span>
</p>

반복문은 th:each를 사용한다.

<tr th:each="dto : ${list}">
    <td th:text="${dto.subject}">과목</td>
    <td th:text="${dto.seq}">번호</td>
</tr>

JSP의 c:forEach와 비슷한 역할이다.


정리

Spring Boot 게시판 프로젝트를 보완하면서 Filter, Interceptor, Mapper 구조를 정리했고, 이후 Thymeleaf 기본 문법을 학습했다.

핵심은 다음과 같다.

Mapper
- SQL을 따로 분리해서 관리

Filter
- Controller 이전에 실행되는 공통 처리

Interceptor
- Controller 실행 전후에 동작

Thymeleaf
- HTML 기반 템플릿 엔진
- th:text, th:each, th:if 등으로 서버 데이터를 출력