본문 바로가기
SI 업무/나만의 프로젝트 만들기

6. DTO 대신 CustomResultMap 을 만들자.

by 새로운걸 배우는게 너무 싫은 IT 복붙러 2024. 11. 29.
728x90

 

UserMapper.xml 에 getUserById 가 수행되면 결과가 resultType 에 정의된
dto 객체에 담긴다.
그리고 service 단에서 이걸 다시 response 로 UI (아직까지는 Postman) 에 넘겨 준다.

 

만약 UserMapper.xml 에 쿼리가 1000개면

1000개의 dto가 필요한 구조다.

 

난 안그렇치만 개발자중에는 정말 단순 반복을 극혐 하는 사람들이 있다.

이런 사람들에게 매번 쿼리가 틀리니 매번 dto를 만들어야 한다면 아마

퇴사 할거다.

 

그래서 그런가!! dto를 매번 안 만들어도 되는 방법이 있다.


실제 누군가가 만든 소스를 보고 흉내 낸것이다.

1. CustomResultMap.java 구현

package com.example.myproject.biz.com;

import org.apache.commons.collections4.map.ListOrderedMap;

import java.io.Serial;
import java.io.Serializable;

public class CustomResultMap extends ListOrderedMap<String, Object> implements Serializable {
    @Serial
    private static final long serialVersionUID = -3373848823544700461L;


    // put() 메소드 오버라이드
    @Override
    public Object put(String key, Object value) {
        // 기본 put() 동작을 유지하면서 추가적인 처리를 할 수 있습니다.
        // 예: 로그, 값 검증, 변환 등
        return super.put(key, value);
    }

    // 필요에 따라 추가적인 메소드들을 추가할 수 있습니다.
    public Object get(String key) {
        return super.get(key);
    }

    public String toString() {
        return super.toString();
    }
}

 

 

2. DTO를 사용 안하고 공통API 인 CustomResultMap을 사용할 sql를 추가 한다.

    -Mapper interface 에 getAllUser 추가

    -Mapper xml 에 getAllUser 추가

    -Service 에도 추가

   == UserMapper.xml 내용==

<?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">
<mapper namespace="com.example.myproject.biz.mapper.UserMapper">

    <select id="getUserById" parameterType="int" resultType="com.example.myproject.biz.dto.User">
        SELECT id, name, email
        FROM users
        where id =#{id}
    </select>

    <select id="getAllUser" resultType="com.example.myproject.biz.com.CustomResultMap">
        SELECT id, name, email
        FROM users
    </select>

</mapper>

 

== UserMapper.java (mapper interface 추가) ==

package com.example.myproject.biz.mapper;


import com.example.myproject.biz.com.CustomResultMap;
import com.example.myproject.biz.dto.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface UserMapper {
    User getUserById(@Param("id") int id); // 매퍼 XML에 정의된 SQL과 매핑되는 메서드
    List<CustomResultMap> getAllUser();
}

 

==Service 에 추가된 내용==

package com.example.myproject.biz.service;

import com.example.myproject.biz.com.CustomResultMap;
import com.example.myproject.biz.dto.User;
import com.example.myproject.biz.mapper.UserMapper;
import com.example.myproject.biz.trace.MapperBeanChecker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
@RequestMapping("/api") // API 기본 경로
public class MyService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MapperBeanChecker beanChecker;

    // ID로 사용자 정보 조회
    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable("id") int id) {
        System.out.println("start..");

        beanChecker.check();

        return userMapper.getUserById(id); // MyBatis Mapper 직접 호출
    }

    // ID로 사용자 정보 조회
    @GetMapping("/user/all")
    public List<CustomResultMap> getAllUser() {
        System.out.println("start..");
        return userMapper.getAllUser();
    }
}

 

 

3. Postman 으로 요청을 쏘니 정상 작동 한다.

 


 

4. 여기부터 드는 궁금증.

   
    이게 어떻게 가능 한거지?

  => MyBatis는 쿼리 결과를 **ResultSet**에서 가져온 후,
       이를 매핑하여 DTO 또는 Map 객체로 변환 한다.

       만약  resultType 에 Map 객체를 쓰겠다고

       설정( resultType="com.example.myproject.biz.com.CustomResultMap">) 하면
        ResultSet에서 가져온 컬럼 이름을 Map의 key로, 컬럼 값 Map의 value로 설정한다..

        즉, MyBatis는 ResultSet의 각 행을 Map<String, Object>에 매핑하는 것이다.
       
        여기서 중요한 점은 Map 객체가 기본적으로 put() 메서드를 통해 데이터를 담기 때문에,
        위의 CustomResultMap 의 put() 메소드를 override 하면
        내가 원하는대로 key, value 를 담을수 변형해 담을수 있는 것이고 put() 메소드는 
        ResultSet 을 map 에 담는 작업을 하기 위해  mybatis api 가 put() 메소드를 호출 하는 것이다.



    resultType 에 HashMap을 넣어도 작동 하는가?

       => 가능 하다.

            <select id="selectData" resultType="java.util.HashMap">



    이렇게 쓰는게 mybatis 공식 문서에 나와 있는가?
      => 이 방식은 MyBatis 공식 문서에 나와 있으며, 유연한 쿼리 결과 처리 방식으로 많이 사용된다.


 

오늘도 읽어주셔서 감사합니다.

myproject.zip
0.14MB

 

728x90