728x90

myBatis를 사용하면서 resultType을 내가 만든 객체로 설정해서 사용하고 싶었는데 DB에서 조회한 컬럼명과 VO의 변수명이 맞지 않아서 null이 반환되었다. 이 문제의 원인은 VO의 변수명은 카멜 표기법, DB의 컬럼명은 스네이크 표기법을 적용했기 때문이다.

 가장 간단한 해결법은 resultType="hashMap"으로 사용하면 된다. 하지만 이러 경우

  1. DB의 컬럼명이 그대로 노출될 수 있다. (사실 이 부분은 별도의 조치를 하지 않는 이상 스네이크 표기법으로 노출되던게 카멜 표기법으로 노출되도록 변경되는 것 뿐이라 DB의 컬럼명이 노출되는 것은 똑같다. 하지만 DB의 컬럼명이 그대로 노출되는 것을 방지한다는 것에 의미를 두려 한다.)
  2. SQL 쿼리문 작성할 때 alies를 지정하지 않는 실수를 할 경우 restful API 반환 값의 key 값이 예상한 것과 다르게 설정될 수 있다.
  3. 맘에 들지 않는 쉬운 해결법이다. (가장 큰 이유)

와 같은 문제가 발생할 수 있다고 생각했다.

 그래서 찾아보니 mybatis configuration에 underscore to camelcase 속성이 있었고 이걸 이용해보기로 했다.


VO

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BoardVO {

    private long seq;
    private String title;
    private String content;
    private String author;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

}

Mapper (SQL)

<select id="selectAllBoard" resultType="BoardVO">
        /* QueryID = selectAllBoard */
        select seq, title, content, author, created_at
        from board
</select>

기존 api response(GET /api/board)

{
        "seq": 1,
        "title": "restfulboardtitle",
        "content": "restfulboardcontent",
        "author": "restfulboardauthor",
        "createdAt": null,  // 해당 값이 문제가 되고 있음
        "updatedAt": null
}

해결법 1.

아주 간단한 해결법으로 application.yml 에 속성값을 추가해주는 방법이다.

mybatis:
  configuration:
    map-underscore-to-camel-case: true

 

아주 간단한 해결법이지만 내 프로젝트에서는 문제가 해결되지 않았기에 해결법 2도 작성한다.

 


해결법 2.

mybatis-config.xml 파일을 생성하고 MybatisConfig.java 파일 수정하기

/resource 디렉토리 밑에 mybatis-config.xml 파일을 생성하고 내용을 작성한다. (파일명 및 파일 위치는 프로젝트에 맞추서 생성하면 된다.)

<?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>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="callSettersOnNulls" value="true"/>
        <setting name="jdbcTypeForNull" value="NULL"/>
    </settings>
</configuration>

그리고 나서 MybatisConfig.java 파일에 해당 파일과 관련된 코드를 작성해주면된다.

@Configuration
@MapperScan(value = "kim.jiwook.playground.mapper", sqlSessionFactoryRef = "SqlSessionFactory")
public class MyBatisConfig {

    @Value("${mybatis.mapper-locations}")
    String mapperPath;

    @Value("${mybatis.type-aliases-package}")
    String typeAliasesPackage;

    // 추가된 코드
    final String mybatisConfigPath = "classpath:/mybatis-config.xml";

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "SqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource,
                                               ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mapperPath));
        sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        // 추가된 코드
        sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource(mybatisConfigPath));
        
        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "SessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

변경 후 api response(GET /api/board)

    {
        "seq": 1,
        "title": "restfulboardtitle",
        "content": "restfulboardcontent",
        "author": "restfulboardauthor",
        "createdAt": "2023-11-04T00:00:00",  // sql 조회 결과와 VO의 변수명이 정상적으로 매핑되어 값이 출력됨
        "updatedAt": null
    }

 

+ Recent posts