1. 프로젝트의 구현 목표와 준비
- 프로젝트의 전체 구조
- 검색과 필터링을 적용할 수 있는 화면 구성, MyBatis 동적 쿼리를 이용해서 상황에 맞는 Todo 검색
- 새로운 Todo 등록 시, 문자열, boolean, LocalDate 자동 처리
- 목록에서 조회 화면으로 이동할 때 모든 검색, 필터링, 페이징 조건 유지하도록 구성
- 조회 화면에서 모든 조건을 유지한 채 수정 / 삭제 화면으로 이동
- 삭제 시 다시 목록 화면으로
- 수정시 다시 조회 화면으로, 검색, 필터링, 페이징 조건은 초기화
- 프로젝트의 3티어 구성

1) 프로젝트 준비
- Spring 관련 라이브러리
// spring 관련 라이브러리
implementation group: 'org.springframework', name: 'spring-core', version: '5.3.20'
implementation group: 'org.springframework', name: 'spring-context', version: '5.3.20'
implementation group: 'org.springframework', name: 'spring-test', version: '5.3.20'
implementation group: 'org.springframework', name: 'spring-webmvc', version: '5.3.20'
implementation group: 'org.springframework', name: 'spring-jdbc', version: '5.3.19'
implementation group: 'org.springframework', name: 'spring-tx', version: '5.3.19'
- MyBatis / MariaDB / HikariCP 관련 라이브러리
// MyBatis 라이브러리
implementation group: 'org.mybatis', name: 'mybatis', version: '3.5.6'
implementation group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.6'
// mariadb 라이브러리
implementation 'org.mariadb.jdbc:mariadb-java-client:3.0.4'
// HikariCP 관련 라이브러리
implementation group: 'com.zaxxer', name: 'HikariCP', version: '5.0.1'
- JSTL 관련 라이브러리
// JSTL 라이브러리
implementation group: 'jstl', name: 'jstl', version: '1.2'
- DTO와 VO 변환을 위한 ModelMapper
// ModelMapper
implementation group: 'org.modelmapper', name: 'modelmapper', version: '3.0.0'
- DTO 검증을 위한 validation 관련 라이브러리
// DTO 검증을 위한 validation 관련 라이브러리
implementation group: 'org.hibernate', name: 'hibernate-validator', version: '6.2.1.Final'
2) 프로젝트의 폴더 / 패키지 구조
- 예제 실습을 위해 작성했던 Sample 관련 파일 정리

- 서버가 제대로 작동하는지 확인

- 테이블 수정
drop table tbl_todo;
create table tbl_todo(
tno int auto_increment primary key,
title varchar(100) not null,
dueDate date not null,
writer varchar(50) not null,
finished tinyint default 0
)

- 서비스 패키지 설정: 프로젝트 내에 서비스 영역을 담당하는 service 패키지 생성

3) ModelMapper 설정과 @Configuration
- DTO → VO 또는 VO → DTO의 변환이 빈번하므로 ModelMapper를 스프링의 Bean으로 등록해서 처리
- config 패키지 추가 > ModelMapperConfig 클래스 추가
// ModelMapperConfiguration
package org.zerock.springex.config;
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// @Configuration은 해당 클래스가 스프링 Bean에 대한 설정을 하는 클래스림을 명시
@Configuration
public class ModelMapperConfig {
// getMapper() 메서드가 ModelMapper를 반환
// @Bean 어노테이션은 해당 메서드의 실행 결과로 반환된 객체를 스프링의 Bean으로 등록시키는 역할
@Bean
public ModelMapper getMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(org.modelmapper.config.Configuration.AccessLevel.PRIVATE)
.setMatchingStrategy(MatchingStrategies.STRICT);
return modelMapper;
}
}
- ModelMapperConfiguration을 스프링의 Bean으로 인식할 수 있도록 root-context.xml에 config 패키지를 추가
<!-- root-context.xml -->
<!-- ModelMapperConfiguration을 스프링의 Bean으로 인식시키기 위한 추가 -->
<context:component-scan base-package = 'org.zerock.springex.config'/>
2. 화면 디자인 - 부트스트랩 적용
- 부트스트랩 메인 페이지의 소스를 활용하여 테스트 페이지 작성
- https://getbootstrap.com/docs/5.3/getting-started/introduction/
Get started with Bootstrap
Bootstrap is a powerful, feature-packed frontend toolkit. Build anything—from prototype to production—in minutes.
getbootstrap.com
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello, world</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD"
crossorigin="anonymous">
</head>
<body>
<h1>Hello, world!</h1>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN"
crossorigin="anonymous">
</script>
</body>
</html>

1) 부트스트랩의 container, row 적용
<!doctype html>
...
<body>
<div class = "container-fluid">
<div class = "row">
<h1>Header</h1>
</div>
<div class = "row content">
<h1>Content</h1>
</div>
<div class = "row footer">
<h1>Footer</h1>
</div>
</div>
...
</body>
</html>

2) Card 컴포넌트 적용하기
- 부트스트랩 사이트의 Component > Card > Header and Footer 부분의 코드 사용

<!doctype html>
...
<body>
...
<!-- body안에 "row content" 클래스 안에 "col" 클래스 생성 후 부트스트랩 코드 복사 -->
<div class = "row content">
<div class = "col">
<div class="card">
<div class="card-header">
Featured
</div>
<div class="card-body">
<h5 class="card-title">Special title treatment</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</div>
</div>
...
</body>
</html>

3) Navbar 컴포넌트 적용
- 부트스트랩 사이트의 Component > Navbar > Nav 부분의 코드 사용

<!doctype html>
...
<body>
<div class = "container-fluid">
<!-- body안에 "row" 클래스 안에 "col" 클래스 생성 후 부트스트랩 코드 복사 -->
<div class = "row">
<div class = "col">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link disabled">Disabled</a>
</li>
</ul>
</div>
</div>
</nav>
</div>
</div>
...
</body>
</html>

4) Footer 처리
- 가장 아래에 "row footer" 클래스에는 간단한 footer 적용
<!doctype html>
...
</head>
<body>
...
<div class = "row footer">
<div class = "row fixed-bottom" style = "z-index: -100">
<footer class = "py-1 my-1">
<p class = "text-center text-muted">Footer</p>
</footer>
</div>
</div>
</div>
...
</body>
</html>

3. MyBatis와 스프링을 이용한 영속 처리
- MyBatis와 스프링을 연동하여 기존 JDBC보다 적은 양의 코드로 개발 가능
- MyBatis를 이용한 개발 단계
- VO 선언
- Mapper 인터페이스의 개발
- XML의 개발
- 테스트 코드의 개발
- 프로젝트에 domain 패키지 선언 > TodoVO 클래스 추가
// TodoVO
package org.zerock.springex.domain;
import lombok.*;
import java.time.LocalDate;
@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TodoVO {
private Long tno;
private String title;
private LocalDate dueDate;
private String writer;
private boolean finished;
}
1) TodoMapper 인터페이스와 XML
- TodoVO는 Mapper 인터페이스의 파라미터나 리턴타입이 될 수 있기 때문에 먼저 정의하고 이를 이용해 TodoMapper 인터페이스 정의
// TodoMapper
package org.zerock.springex.mapper;
public interface TodoMapper {
String getTime();
}
- resources > mappers 폴더에 TodoMapper.xml을 선언하고 getTime()에 해당하는 내용 작성
- XML 작성 시 (namespace 값 = 인터페이스의 이름), (메서드 이름 = <select> 태그의 id)로 설정
<!-- TodoMapper.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTO Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace는 TodoMapper의 경로를 정확히 일치시켜야 함 -->
<mapper namespace = "org.zerock.springex.mapper.TodoMapper">
<!-- id도 TodoMapper 내의 메서드 getTime()과 일치해야 함 -->
<select id = "getTime" resultType = "string">
select now()
</select>
</mapper>
- 테스트 코드로 동작 여부 확인
- Test > java > org.zerock.springex.mapper > TodoMapperTests 클래스 생성
// TodoMapperTests
package org.zerock.springex.mapper;
import lombok.extern.log4j.Log4j2;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
public class TodoMapperTests {
@Autowired(required = false)
private TodoMapper todoMapper;
@Test
public void testGetTime() {
log.info(todoMapper.getTime());
}
}

- SQL 실행로그를 더 자세히 보기 위해 org.zerock.springex.mapper 패키지 로그는 TRACE 레벨로 기록하도록 log4j2.xml에 코드 추가
<!-- log4j2.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status = "INFO">
<Appenders>
...
</Appenders>
<Loggers>
...
<logger name = "org.zerock.springex.mapper" level = "TRACE" additivity = "false">
<appender-ref ref = "console" />
</logger>
...
</Loggers>
</Configuration>

'back-end > Java' 카테고리의 다른 글
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(3) (0) | 2023.02.15 |
---|---|
[자바 웹 개발 워크북] 4.4 - 스프링 Web MVC 구현하기(2) (0) | 2023.02.14 |
[자바 웹 개발 워크북] 4.3 - 스프링 Web MVC 기초 (0) | 2023.01.17 |
[자바 웹 개발 워크북] 4.2 - MyBatis와 스프링 연동 (0) | 2023.01.13 |
[자바 웹 개발 워크북] 4.1 - 의존성 주입과 스프링 (0) | 2023.01.12 |