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를 제거합니다.