MySQL Workbench를 이용해서 테스트에 사용할 테이블을 생성합니다. 데이터베이스는 "도커로 MySQL 설치 및 실행"에서 생성한 것을 사용합니다.
CREATE TABLE board
(
board_idx INT (11) NOT NULL auto_increment comment '글 번호',
title VARCHAR(300) NOT NULL comment '제목',
contents TEXT NOT NULL comment '내용',
hit_cnt SMALLINT(10) NOT NULL DEFAULT '0' comment '조회수',
creator_id VARCHAR (50) NOT NULL comment '작성자',
created_dt DATETIME NOT NULL comment '작성시간',
updater_id VARCHAR (50) NULL comment '수정자',
updated_dt DATETIME NULL comment '수정시간',
deleted_yn CHAR (1) NOT NULL DEFAULT 'N' comment '삭제 여부',
PRIMARY KEY (board_idx)
);
insert into board (title, contents, creator_id, created_dt, updated_dt) values ('title #1', 'contents #1', 'user001', now(), now());
insert into board (title, contents, creator_id, created_dt, updated_dt) values ('title #2', 'contents #2', 'user001', now(), now());
insert into board (title, contents, creator_id, created_dt, updated_dt) values ('title #3', 'contents #3', 'user002', now(), now());
insert into board (title, contents, creator_id, created_dt, updated_dt) values ('title #4', 'contents #4', 'user002', now(), now());
https://start.spring.io/ 사이트에서 생성한 프로젝트 파일을 이클립스에 추가합니다.
스프링 부트 애플리케이션을 실행합니다.
정상 동작 여부 확인을 위해 Hello Spring 메시지를 출력하는 컨트롤러 클래스를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/controller/HelloController.java
package com.example.mybatisdemo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
// = @RequestMapping("/")
// = @GetMapping("/")
@RequestMapping(method = RequestMethod.GET, path = "/")
public String hello() {
return "Hello Spring";
}
}
브라우저를 통해 결과를 확인합니다.
application.properties 설정 파일에 데이터베이스 연결 정보를 추가합니다.
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:3306/msa_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Seoul
spring.datasource.hikari.username=dev
spring.datasource.hikari.password=password
spring.datasource.hikari.connection-test-query=select 1
DatabaseConfiguration 클래스를 생성하고 DataSource를 생성하는 코드를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/config/DatabaseConfiguration.java
package com.example.mybatisdemo.config;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariConfig hikariConfig() {
return new HikariConfig();
}
@Bean
public DataSource dataSource() throws Exception {
DataSource dataSource = new HikariDataSource(hikariConfig());
log.info("dataSource : {}", dataSource);
return dataSource;
}
}
콘솔창에 DataSource 정보 출력 여부를 확인합니다.
DatabaseConfiguration 클래스에 MyBatis 설정 정보를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/config/DatabaseConfiguration.java
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
:
public class DatabaseConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:/mapper/**/sql-*.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
:
}
src/main/resources 디렉터리 아래에 쿼리맵을 저장할 mapper 디렉터리를 생성합니다.
맵퍼 인터페이스와 쿼리맵을 생성합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/mapper/BoardMapper.java
package com.example.mybatisdemo.mapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BoardMapper {
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0/EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- /mybatisdemo/src/main/resources/mapper/sql-board.xml -->
<mapper namespace="mybatisdemo.BoardMapper">
</mapper>
게시판 목록 조회 RESTful API를 구현해 보도록 하겠습니다.
클라이언트가 GET 방식의 /api/boards 주소로 요청하면 Controller를 통해서 Service가 호출되고, 서비스는 쿼리와 연결된 Mapper를 호출합니다. 쿼리 실행 결과는 DTO에 담겨서 반환되며, JSON 형태로 사용자에게 전달됩니다.
먼저 데이터를 담을 DTO 클래스를 생성해 보겠습니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/dto/BoardDto.java
package com.example.mybatisdemo.dto;
import lombok.Data;
@Data
public class BoardDto {
private int boardIdx;
private String title;
private String contents;
private int hitCnt;
private String creatorId;
private String createdDt;
private String updaterId;
private String updatedDt;
}
테이블의 컬럼명(snake expression)과 DTO 객체의 필드명(camel expression)을 자동 맵핑되도록 설정 정보를 추가합니다.
:
mybatis.configuration.map-underscore-to-camel-case=true
// /mybatisdemo/src/main/java/com/example/mybatisdemo/config/DatabaseConfiguration.java
package com.example.mybatisdemo.config;
:
public class DatabaseConfiguration {
:
@Bean
@ConfigurationProperties(prefix = "mybatis.configuration")
public org.apache.ibatis.session.Configuration mybatisConfig() {
return new org.apache.ibatis.session.Configuration();
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
:
sqlSessionFactoryBean.setConfiguration(mybatisConfig());
return sqlSessionFactoryBean.getObject();
}
:
}
게시판 목록 조회 쿼리를 쿼리맵에 추가합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0/EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- /mybatisdemo/src/main/resources/mapper/sql-board.xml -->
<mapper namespace="com.example.mybatisdemo.mapper.BoardMapper">
<!-- 게시판 목록 조회 -->
<select id="selectBoardList" resultType="com.example.mybatisdemo.dto.BoardDto">
select board_idx, title, hit_cnt, creator_id, date_format(created_dt, '%Y.%m.%d %H:%i:%s') as created_dt,
updater_id, date_format(updated_dt, '%Y.%m.%d %H:%i:%s') as updated_dt, deleted_yn
from board
where deleted_yn = 'N'
order by board_idx desc
</select>
</mapper>
맵퍼 인터페이스에 게시판 목록 조회 맵퍼 메서드를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/mapper/BoardMapper.java
package com.example.mybatisdemo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.example.mybatisdemo.dto.BoardDto;
@Mapper
public interface BoardMapper {
// 게시판 목록 조회
List<BoardDto> selectBoardList() throws Exception;
}
게시판 관련 서비스 인터페이스와 클래스를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/service/BoardService.java
package com.example.mybatisdemo.service;
import java.util.List;
import com.example.mybatisdemo.dto.BoardDto;
public interface BoardService {
// 게시판 목록 조회
List<BoardDto> selectBoardList() throws Exception;
}
// /mybatisdemo/src/main/java/com/example/mybatisdemo/service/BoardServiceImpl.java
package com.example.mybatisdemo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.mybatisdemo.dto.BoardDto;
import com.example.mybatisdemo.mapper.BoardMapper;
@Service
public class BoardServiceImpl implements BoardService {
@Autowired
private BoardMapper boardMapper;
@Override
public List<BoardDto> selectBoardList() throws Exception {
return boardMapper.selectBoardList();
}
}
게시판 관련 사용자 요청과 서비스를 연결할 컨트롤러 클래스를 생성합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/controller/BoardApiController.java
package com.example.mybatisdemo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.mybatisdemo.dto.BoardDto;
import com.example.mybatisdemo.service.BoardService;
@RequestMapping(path = "/api")
@RestController
public class BoardApiController {
@Autowired
private BoardService boardService;
@GetMapping("/boards")
public List<BoardDto> selectBoardList() throws Exception {
return boardService.selectBoardList();
}
}
브라우저를 통해서 게시판 목록 조회 결과를 확인합니다.
조회 결과를 View를 통해서 클라이언트(사용자)에게 반환하는 기능을 추가해 보겠습니다.
사용자에게 보여질 View를 생성합니다. 여기서는 템플릿 엔진으로 mustache를 사용합니다.
<!-- /mybatisdemo/src/main/resources/templates/board/boardList.mustache -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 목록 조회</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h2>게시판 목록</h2>
<!-- 목록 출력 -->
<table class="table table-horizontal table-bordered">
<thead class="thead-strong">
<tr>
<th>게시글 번호</th>
<th>제목</th>
<th>조회수</th>
<th>최종수정일</th>
</tr>
</thead>
<tbody>
{{#resultList}}
<tr>
<td>{{boardIdx}}</td>
<td>{{title}}</td>
<td>{{hitCnt}}</td>
<td>{{updatedDt}}</td>
</tr>
{{/resultList}}
</tbody>
</table>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
</body>
</html>
게시판 조회 결과를 뷰를 통해서 반환하는 컨트롤러를 추가합니다.
// /mybatisdemo/src/main/java/com/example/mybatisdemo/controller/BoardController.java
package com.example.mybatisdemo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.example.mybatisdemo.dto.BoardDto;
import com.example.mybatisdemo.service.BoardService;
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@RequestMapping("/boardList.do")
public ModelAndView boardList() throws Exception {
ModelAndView mv = new ModelAndView("/board/boardList");
List<BoardDto> boardList = boardService.selectBoardList();
mv.addObject("resultList", boardList);
return mv;
}
}
브라우저를 통해서 게시판 목록 조회 결과를 확인합니다.
댓글