IT/development

[mybatis] foreach parameterType hashmap 예제

알 수 없는 사용자 2022. 11. 20. 06:56
반응형

목차

    미래의 나를 위해 기록한다. 😃

    mybatis에서 foreach를 돌릴 때 list는 이제 좀 익숙해 졌는데 map은 아직 좀 서툰 느낌이 들어 기록한다.

    예제는 동적으로 insert문의 내용과 SELECT문의 내용을 채우는 예제이다.

    아직은 완성형이 아니고 아이디어만 녹인거라 코드가 매우 허술하지만 업데이트 해 나갈 것이다.

    jpa를 쓰지 않는 프로젝트에서 쿼리문 작성 시 오탈자 방지와 퍼포먼스 향상을 위해 작성하는 중

    결국 단순반복 노가다를 많이 줄이기 위함이다.

    테스트를 위한 테이블 생성

    CREATE TABLE `t_member`(
    `user_seq` bigint auto_increment,
    `user_id` varchar (250),
    `user_name` varchar(250),
    primary key(user_seq)
    );

    mapper 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="paging.study.mapper.MemberMapper">
    
        <insert id="insertMem" parameterType="hashmap">
            INSERT INTO t_member
            <foreach collection="column" item="column" open="(" separator="," close=")">
                ${column}
            </foreach>
            VALUES
            <foreach collection="column_value" item="column_value" open="(" separator="," close=")">
                #{column_value}
            </foreach>
        </insert>
    
        <select id="findMember" resultType="hashMap" parameterType="hashMap">
            SELECT
            <foreach collection="column" index="index" item="column" separator=",">
                ${column}
            </foreach>
            FROM ${tableName}
        </select>
    
    
    </mapper>

    parameter로 받은 map에 접근해 동적으로 컬럼과 테이블을 가져와 SQL문을 세팅한다.

    이 때 주의점은 아래와 같다.

    map에 저장 시 키값과 foreach의 collection명이 일치해야 한다.

    아래처럼 컬럼 키값을 변경 후 테스트 하면 아래처럼 collection이 null값이라고 에러가 발생한다.


    mapper interface

    package paging.study.mapper;
    
    import org.apache.ibatis.annotations.Mapper;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Mapper
    public interface MemberMapper {
        void insertMem(Map<String, Object> param);
        List<Map<String, Object>> findMember(Map<String, Object> param);
    }

    Map을 parameter로 받는다.


    mapper service

    package paging.study.service;
    
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import paging.study.domain.Criteria;
    import paging.study.domain.vo.BoardVO;
    import paging.study.mapper.BoardMapper;
    import paging.study.mapper.MemberMapper;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Service
    @Slf4j
    @RequiredArgsConstructor
    @Transactional(readOnly = true)
    public class MemberService {
    
        private final MemberMapper memberMapper;
    
        public void insert(List<String> column, List<String> column_value) {
            Map<String, Object> param = new HashMap<String, Object>();
            param.put("column", column);
            param.put("column_value", column_value);
            memberMapper.insertMem(param);
        }
    
        public List<Map<String, Object>> findMember(List<String> column, String tableName) {
            Map<String, Object> param = new HashMap<String, Object>();
            param.put("column", column);
            param.put("tableName", tableName);
            return memberMapper.findMember(param);
        }
    
    
    
    
    
    }

    insert()에서는 컬럼명과 컬럼에 해당되는 데이터를 list로 받아서 map에 저장해서 mapper로 보내고

    findMember()에서는 list로 컬럼명을, String으로 테이블명을 받는다.


    test code

    package paging.study.service;
    
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.annotation.Commit;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @SpringBootTest
    @Slf4j
    @Transactional
    class MemberServiceTest {
    
        @Autowired MemberService memberService;
    
        @Test
        @DisplayName("insert")
        @Commit
        public void insert() {
            List<String> column = new ArrayList<>();
            column.add("user_id");
            column.add("user_name");
        
            List<String> column_value = new ArrayList<>();
            column_value.add("아이언맨");
            column_value.add("로다주");
            memberService.insert(column, column_value);
        }
    
        @Test
        @DisplayName("find")
        public void find() {
            List<String> column = new ArrayList<>();
            column.add("user_id");
            column.add("user_name");
            List<Map<String, Object>> list = memberService.findMember(column, "t_member");
            System.out.println("list = " + list.toString());
        }
    
    }

     

    실행 결과

    insert

    select


    아래처럼 활용할 수 도 있다.

    controller

    화면에서 전달 받은 parameter를 map으로 받고 service method 호출

    @PostMapping("/board/new")
        public String create(@RequestParam Map<String, Object> map) throws Exception {
            boardService.insertBoard(map);
    }

    service

    	@Transactional
        public void insertBoard(Map<String, Object> map) {
    		
            Map<String, Object> mapperParam = new HashMap<String, Object>();
            List<Object> columns = new ArrayList<>();
            List<Object> column_values = new ArrayList<>();
    		// map에서 key, value 추출해서 list에 저장
            for (Object obj: map.keySet()) {
                columns.add(obj);
                column_values.add(map.get(obj));
            }
            mapperParam.put("column", columns);
            mapperParam.put("column_value", column_values);
    
            boardMapper.insertBoard(mapperParam);
        }

     

    mapper interface

    void insertBoard(Map<String, Object> map);

     

    mapper xml

    <!-- map을 루프 돌면서 컬럼과 데이터 세팅 -->
    <insert id="insertBoard" parameterType="hashmap">
            INSERT INTO t_board
                (
                 <foreach collection="column" item="column" separator=",">
                    ${column}
                 </foreach>
                 , reg_date
                 , update_date
                 )
            VALUES
                (
                <foreach collection="column_value" item="column_value" separator=",">
                    #{column_value}
                </foreach>
                , now()
                , now()
                )
        </insert>
    반응형