IT/development

[mybatis] foreach parameterType hashmap 예제

알 수 없는 사용자 2022. 11. 20.

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

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>

개인 스터디 기록을 메모하는 공간이라 틀린점이 있을 수 있습니다.

틀린 점 있을 경우 댓글 부탁드립니다.

 

[mybatis] mybatis 배열 저장(feat. foreach)

목차 위와 같이 insert를 1개 이상 하는 로직을 만들게 되었고 미래의 내가 보기 위해 기록한다. 😄 클라이언트에서 배열로 값을 받아서 DB에 저장하는 기능이 필요했다. 참고로 mysql과 Oracle은 문

yaga.tistory.com

 

[mybatis] mybatis 동적쿼리(feat. <where></where>)

목차 mybatis Dynamic SQL 😃 계속 실수 했던 동적쿼리이다. 오늘 나는 이걸 이해 했지만 미래의 넌 또 까먹을 수 있으니 여기에 메모해 둔다. 동적 WHERE 회원 테이블에서 회원이름과 이메일의 존재에

yaga.tistory.com

 

[mybatis] map을 list로 받아서 화면에 그리기

목차 미래의 내가 보기 위해 기록함 테스트 테이블 😃 CREATE TABLE `tmp_board`( `board_seq` bigint auto_increment, `title` varchar (30), `contents` varchar (30), `name` varchar (30), `reg_date` timestamp, `update_date` timestamp, primary

yaga.tistory.com

 

[mybatis] mybatis 이중 foreach insert(feat. 이중 계층 객체 저장)

목차 mybatis를 이용해서 계층 구조의 DTO 혹은 VO객체를 저장하는 방법을 기록한다. 대상 DBMS: mysql, mariaDB 아래처럼 객체가 객체를 참조하는 경우 이를 저장하는 방법이다.(시간 상 코드 위주로 최

yaga.tistory.com

 

[mybatis] selectkey값 return(Oracle)

SELECT BOARD_NO_SEQ.NEXTVAL FROM DUAL /* 게시글 작성 */ INSERT INTO BOARD ( BOARD_NO , TITLE , CONTENT , WRITER , CREATE_DATE ) VALUES ( #{boardNo} , #{title} , #{content} , #{writer} , SYSDATE ) /* 게시글 등록(mapper interface) */ void insertBoa

yaga.tistory.com

댓글