이번에 스프링을 공부하게 되면서 DTO 라는 객체를 만들어서 사용해 보게 되었다.
DTO 말고도 DAO, VO 라는 객체도 존재하는데 이들의 역할이 무엇인지 정확히 알아보고 싶었다.
레이어 간 데이터를 주고 받을 때 사용하며, getter, setter 메서드를 포함한다. (가변 객체와 불변 객체로 나뉠 수 있다.)
// 기본 생성자로 생서 후 필드를 변경 가능하다.
@Getter
@Setter
public class DtoEx {
private String name;
private Integer age;
}
// setter 가 없고 오로지 필드 값을 얻을 수만 있는 경우
// 오버라이딩 된 생성자를 사용한다.
@Getter
public class DtoEx {
private final String name;
private final int age;
public DtoEx(String name, int age) {
this.name = name;
this.age = age;
}
}
=> 사실 지금까지 많이 써왔기 때문에 이해하는데 어려움은 없었다. 하지만 생소한건 다음말할 것 부터이다.
사용하는 이유? :
1. 효율적인 커넥션 관리, 보안성
2. DAO 는 비즈니스 로직을 분리하고 도메인 로직으로 부터 DB와 관련한 메커니즘을 은닉하기 위하여 사용한다.
import java.util.List;
public interface UserDAO {
void addUser(User user);
User getUser(int id);
List<User> getAllUsers();
}
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class UserDAOImpl implements UserDAO {
private Connection connection;
public UserDAOImpl(Connection connection) {
this.connection = connection;
}
@Override
public void addUser(User user) {
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO users (name) VALUES (?)")) {
statement.setString(1, user.getName());
statement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public User getUser(int id) {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE id = ?")) {
statement.setInt(1, id);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return new User(resultSet.getInt("id"), resultSet.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public List<User> getAllUsers() {
List<User> users = new ArrayList<>();
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM users")) {
while (resultSet.next()) {
users.add(new User(resultSet.getInt("id"), resultSet.getString("name")));
}
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
}
jdbc 예시 ) 위와 같은 식으로 데이터베이스에 접근할 객체를 정의하고
정해진 객체를 통해 db에 접근함으로서 db의 매커니즘을 은닉가능
특징
불변성 (Immutable): VO 는 값이 한 번 설정되면 변경되지 않는다. 값이 변경되는 경우 새로운 VO 객체를 생성하는 방식으로 처리된다.동등성 (Equality): VO 객체는 메모리 주소가 아닌 값을 기준으로 동일성을 판단한다.
(ex : String str1 = new String("abc");
String str2 = "abc" ; // 이떼 str1 == str2)데이터 전달: 주로 시스템 내에서 데이터를 전달하거나 값을 표현하는 용도로 사용된다.
=> 보통 VO는 데이터페이스에서 가져온 데이터를 읽기 전용으로 사용하거나, 특정 연산에서 상태 변경이 불필요한 값을 전달하는 데 사용됨
public class UserVO {
private final String name;
private final String email;
// 생성자를 통해 값 설정
public UserVO(String name, String email) {
this.name = name;
this.email = email;
}
// getter 메서드만 제공하여 값이 변경되지 않도록 함
public String getName() {
return name;
}
public String getEmail() {
return email;
}
// equals()와 hashCode()를 오버라이딩하여 값을 기준으로 객체 비교
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserVO userVO = (UserVO) o;
if (!name.equals(userVO.name)) return false;
return email.equals(userVO.email);
}
@Override
public int hashCode() {
int result = name.hashCode();
result = 31 * result + email.hashCode();
return result;
}
}
public class Main {
public static void main(String[] args) {
UserVO user1 = new UserVO("John", "john@example.com");
UserVO user2 = new UserVO("John", "john@example.com");
// 두 객체가 같은 값이면 동등하다고 간주됨
if (user1.equals(user2)) {
System.out.println("두 사용자는 동일한 사용자입니다.");
}
}
}
계층 간 데이터 전송을 위한 객체로, 주로 값의 변경이 가능하고 읽기/쓰기 기능을 제공.가변, 불변의 차이일 뿐 혼용해서 사용되기도 한다. DTO는 계층간 이동이 추가된 것!