저번 글에서는 정적으로 만들어진 자료를 보여주었지만, 이번에는 글을 작성하고 동적으로 DB에서 글을 불러오기 위해서 DB 연동 및 Mybatis 설정을 합니다.
DB는 MySQL을 사용합니다.
create user "유저이름" identified by "비밀번호";
create database 데이터베이스 이름;
use 데이터베이스 이름;
grant create,drop,insert,select,update,delete,alter on 데이터베이스이름.* to "유저이름"@'%';
글을 저장할 post 테이블을 생성합니다. post테이블에는 제목, 내용, 생성 날짜, 작성자 이름을 저장합니다.
create table post(
id int primary key not null auto_increment,
title varchar(50),
content TEXT,
created_date TIMESTAMP,
name varchar(10));
Java를 위한 ORM으로 SQL을 프로그램 코드와 구분하여서 관리할 수 있습니다. 복잡하거나 다이나믹한 쿼리에 강하고, 프로그램 코드와 SQL의 분리로 코드의 간결성 및 유지보수성 향상을 할 수 있습니다.
연동에 필요한 아래의 라이브러리들을 적용해줍니다. 사이에 넣으면 됩니다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
@Configuration
@MapperScan("ac.kr.smu.mapper")
@EnableTransactionManagement //트랜잭션 관리를 위한 Annotation
public class RootConfig {
@Autowired
private ApplicationContext applicationContext;
/*
커넥션 풀을 이용해 DB에 연결하는 클래스
*/
@Bean
public ComboPooledDataSource comboPooledDataSource(){
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try{
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/데이터베이스이름");
dataSource.setUser("유저이름");
dataSource.setPassword("비밀번호");
dataSource.setCheckoutTimeout(1000);
}catch (Exception e){e.printStackTrace();}
return dataSource;
}
/*
MyBatis 설정을 위한 클래스
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSources){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
try {
sqlSessionFactoryBean.setDataSource(dataSources);
sqlSessionFactoryBean.setConfigLocations(applicationContext.getResource("classpath:mybatis-config.xml"));
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mappers/*.xml"));
}catch (IOException e){ e.printStackTrace();}
return sqlSessionFactoryBean;
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactoryBean){
return new SqlSessionTemplate(sqlSessionFactoryBean);
}
/*
트랜잭션을 위한 클래스
*/
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}
@Autowired은 Spring이 관리하는 Bean들 중에 올바른 타입의 클래스를 의존성 주입을 해주는 Annotation입니다.
@MapperScan은 경로로 지정된 패키지의 Mapper클래스들을 Bean으로 등록해주는 Annotation입니다.
메소드들의 매개변수들은 자동으로 Spring이 의존성 주입을 하여서 실행해줍니다. 만약 의존성 주입을 할 클래스가 없다면 오류가 나옵니다.
mybatis-config.xml에는 VO(Value Object)의 alias(별명)를 설정합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="ac.kr.smu.vo.PostVO" alias="PostVO"/>
</typeAliases>
</configuration>
Mapper.xml들은 SQL을 작성하는 xml입니다. mapper패키지에 선언한 인터페이스를 구현하는 구현체라 생각하면 됩니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ac.kr.smu.mapper.PostMapper">
</mapper>
DB와 MyBatis 설정이 잘 되었는지 확인해봅니다.
VO는 Value Object의 약자입니다.
@Data
public class PostVO {
private int id;
private String title;
private String content;
private Timestamp created_date;
private String name;
}
@Data는 lombok의 Annotation으로 @ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor의 역할을 해줍니다. 각각의 기능은 찾아보시는 걸 추천드립니다.
Lombok은 코드에서 반복적으로 들어가는 것들을(EX) Setter, Getter, ToString..) Annotation으로 생략하게 해주어서 코드를 간결하게 만들어줍니다.
테스트를 위해서 간단히 Annotation을 사용해서 더미 데이터를 받아오는 방법으로 작성하겠습니다.
public interface PostMapper {
@Select("select * from post")
public List<PostVO> test();
}
로그에 List에 담겨있는 객체들을 하나씩 출력하도록 수정합니다.
@Controller
@RequestMapping("/")
@Slf4j
public class TestContoller {
@Autowired
private PostMapper testMapper;
@GetMapping
public String getTest(){
testMapper.test().stream().forEach(t -> log.info(t.toString()));
return "test";
}
}
@Slf4j는 lombok의 Annotation으로 slf4j의 로그를 만들어 주는 Annotation입니다. 이를 이용하여서 로그를 남길 수 있습니다.
private Logger log = LoggerFactory.getLogger(TestContoller.class);
위의 코드가 생략되있다고 생각하면 됩니다.
insert into post(title,content,name) values("test","test","test");
위의 SQL을 실행하여서 더미 데이터를 하나 입력합니다. 그 후 실행을 하게 되면 아래 사진과 같이 결과가 나옵니다.
여러번 로그가 찍히는 것은 브라우저가 서버에 여러 번 요청을 나누어서 보내기 때문에 여러번 찍히게 됩니다.
만약 실행할 때 serverTimezone 관련해서 오류가 뜬다면 jdbcUrl 끝에 &serverTimeZone=UTC 혹은 아래 SQL을 실행합니다.
set global time_zone = "+09:00";