프로그래밍-Back/Java

[JAVA] ibatis 기본 사용법 (MVC 기반)

programmer-coldbrew 2024. 12. 29. 22:25

0. Model (DTO)

package com.example.model;

public class User {
    private String userId;
    private String userName;
    private String userEmail;

    // 기본 생성자
    public User() {
    }

    // 모든 필드를 초기화하는 생성자
    public User(String userId, String userName, String userEmail) {
        this.userId = userId;
        this.userName = userName;
        this.userEmail = userEmail;
    }

    // Getter 및 Setter
    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    @Override
    public String toString() {
        return "User{id='" + userId + "', name='" + userName + "', email='" + userEmail + "'}";
    }
}
  • 사용하고자 하는 변수명을 기반으로 getter, setter, 생성자, toString 을 선언해줍니다. 

1. Controller

package com.example.controller;

import com.example.model.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    // 동적 사용자 조회 API
    @GetMapping("/active")
    public List<User> getActiveUsers(
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String userName,
            @RequestParam(required = false) String email) {
        
        return userService.fetchActiveUsers(startDate, userName, email);
    }
}

 

  • 프론트에서 전달받은 정보 (주로 API를 통해 받음) 를 바탕으로 Service에 값을 전달해줍니다.
  • 경로는 해당 Controller의 경우 /users/active 를 통해 연결합니다.

2. Service, ServiceImpl

package com.example.service;

import com.example.model.User;
import java.util.List;

public interface UserService {
    List<User> fetchActiveUsers(String startDate, String userName, String email);
}
package com.example.service.impl;

import com.example.dao.UserDAO;
import com.example.model.User;
import com.example.service.UserService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserServiceImpl implements UserService {

    private final UserDAO userDAO;

    public UserServiceImpl(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @Override
    public List<User> fetchActiveUsers(String startDate, String userName, String email) {
        // 동적 조건을 위한 Map 생성
        Map<String, Object> params = new HashMap<>();
        params.put("startDate", startDate);
        params.put("userName", userName);
        params.put("email", email);

        // DAO 호출
        return userDAO.getActiveUsersWithDynamic(params);
    }
}
  • Map 을 선언해 각 이름에 맞는 값을 넣어줍니다.
  • params 값을 Dao에 보내주며 SQL에 필요한 정보를 보내줘 DB에서 데이터를 가지고 올 수 있도록 합니다.

3. Dao, DaoImpl

package com.example.dao;

import com.example.model.User;
import java.util.List;
import java.util.Map;

public interface UserDAO {
    List<User> getActiveUsersWithDynamic(Map<String, Object> params);
}

 

package com.example.dao.impl;

import com.example.dao.UserDAO;
import com.example.model.User;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
import java.util.Map;

public class UserDAOImpl implements UserDAO {

    private final SqlSession sqlSession;

    // 생성자 주입 방식으로 SqlSession을 전달받음
    public UserDAOImpl(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

	// 방법 1
    @Override
    public List<User> getActiveUsersWithDynamic(Map<String, Object> params) {
        return sqlSession.selectList("selectActiveUsersWithDynamic", params);
    }
    
    // 방법 2
    @Override
    public List<User> getActiveUsersWithDynamic(Map<String, Object> params) {
        return getSqlMapClientTemplate().queryForList("com.example.getActiveUsersWithDynamic", params);
    }
    
}
  • Service에서 받은 params를 sql에서 사용할 수 있도록 전달해 줍니다.
  • 전달하는 방식은 여러가지가 있습니다. 두번째 방식의 경우 getActiveUsersWithDynamic 앞부분은 해당 Controller와 Service, Dao, Model이 있는 곳의 경로와 동일하게 지정합니다.

4. XML 파일 

<resultMap id="userResultMap" class="com.example.User">
    <result property="userId" column="user_id" />
    <result property="userName" column="user_name" />
    <result property="userEmail" column="user_email" />
</resultMap>

<select id="selectActiveUsersWithDynamic" resultMap="userResultMap" parameterType="map">
    SELECT user_id, user_name, user_email
    FROM users
    WHERE
        user_status = 'ACTIVE'
        <dynamic prepend="WHERE">
            <isNotEmpty property="startDate" prepend="AND">
                created_date >= TO_DATE(#startDate, 'YYYY-MM-DD')
            </isNotEmpty>
            <isNotEmpty property="userName" prepend="AND">
                user_name LIKE '%' || #userName || '%'
            </isNotEmpty>
            <isNotEmpty property="email" prepend="AND">
                user_email = #email
            </isNotEmpty>
        </dynamic>
</select>
  • <resultMap> 태그
    • selectActiveUsersWithDynamic의 결과로 return 되는 값의 형태를 의미합니다.
    • 컬럼에서 user_id 값은 Java 등의 서버에서 userId 로 사용할 수 있게 저장합니다. 

          ++

resultMap을 사용하는 대신 resultClass를 사용해 DTO의 경로로 사용하는 방법도 있습니다. 

이 방법의 경우 resultMap 선언이 필요없지만, DTO에 생성자로 형성되어있어야 합니다.

ex) <select id="selectActiveUsersWithDynamic" resultClass = "com.example.model.User" parameterType="map"> 

  • <dynamic> 태그:
    • 여러 조건을 포함할 수 있는 컨테이너로, 내부 조건이 하나라도 만족할 경우 실행됩니다.
    • prepend="AND"를 사용하면 첫 번째 조건 앞에 AND를 자동으로 추가하지 않고 이후 조건에만 추가합니다.
  • <isNotEmpty> 태그:
    • 동적 조건이 추가되는지 확인하며, 각 조건은 필요할 때만 SQL에 포함됩니다.
    • 만약 selectActiveUsersWithDynamic을 실행시키는 DaoImpl에서 parameter값을 startDate만 준다면 usename과 email 이 포함된 부분은 실행되지 않으며, quary 로그에도 찍히지 않습니다.
  • <where> 태그:
    • WHERE 절을 자동으로 추가하며, 불필요한 AND를 제거합니다.