부트캠프에서 처음으로 java수업을 받고 있기에 기록하는게 좋다고 생각했고, 수업이 있는 날이면 매일 글을 쓰려고 합니다. 쵀대한 몰랐거나 필요하다고 생각되는 내용 위주로 기록할 예정입니다. (제가 게을러서 이러한 시도를 성공한 적이 없기에 이번 부트캠프 목표 중 1가지입니다. 할 수 있도록 화이팅!!)
🟢 DAO(Data Access Object)는 데이터베이스에 직접 접근하여 CRUD(Create, Read, Update, Delete) 작업을 수행하는 객체로 SQL 쿼리 또는 ORM을 사용하여 데이터 조회 및 조작에 사용된다.
🟢 DTO (Data Transfer Object)는 계층 간(예: Controller ↔ Service ↔ Repository) 데이터를 전달하기 위한 객체로 불필요한 데이터를 제외하고 필요한 데이터만 전달하여 성능을 최적화하는 역할을 한다.
// ------- DAO 인터페이스 정의
public interface UserDao {
User getUserById(int id);
List<User> getAllUsers();
void saveUser(User user);
void updateUser(User user);
void deleteUser(int id);
}
// -------- JDBC를 이용한 DAO 구현
public class UserDaoImpl implements UserDao {
private Connection connection;
public UserDaoImpl(Connection connection) {
this.connection = connection;
}
@Override
public User getUserById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setInt(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
return new User(rs.getInt("id"), rs.getString("name"), rs.getString("email"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
@Override
public void saveUser(User user) {
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, user.getName());
stmt.setString(2, user.getEmail());
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
// updateUser, deleteUser도 같은 방식으로 구현 가능
}
// -------- DTO 정의
public class UserDTO {
private int id;
private String name;
private String email;
public UserDTO(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getter만 제공하여 불변 객체로 유지
public int getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
}
// ------ Entity 클래스와 변환 (DTO ↔ Entity)
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String email;
private String password; // DTO에는 포함되지 않음
public User() {} // JPA 기본 생성자 필요
public User(String name, String email, String password) {
this.name = name;
this.email = email;
this.password = password;
}
// 엔티티를 DTO로 변환하는 메서드
public UserDTO toDTO() {
return new UserDTO(this.id, this.name, this.email);
}
}
Repository는 DAO보다 더 추상적인 계층을 제공하여 도메인 로직과 데이터 액세스를 연결하는 역할을 한다.
비교 항목 DAO (Data Access Object) Repository 역할 SQL을 직접 다루며 데이터 액세스를 처리 도메인 로직과 데이터 저장소를 연결 구현 방식 SQL 또는 ORM을 사용하여 직접 구현 Spring Data JPA 등으로 인터페이스 기반 자동 구현 SQL 관리 직접 작성해야 함 자동 생성 가능 (필요시 @Query
로 작성)유지보수성 SQL 변경이 필요하면 직접 수정해야 함 추상화된 인터페이스라 유지보수 용이
@Bean은 Spring에서 객체(Bean)를 수동으로 생성하고 관리할 때 사용하는 애노테이션으로 보통 @Configuration 클래스 내부에서 정의되며, 해당 메서드가 반환하는 객체를 Spring 컨테이너가 관리하는 Bean으로 등록해서 사용한다.
@Configuration
public class ContextConfiguration {
/* @Bean 어노테이션은 해당 메소드의 반환 값을 스프링 컨테이너에 빈으로 등록한다는 의미이다.
* 이름을 별도로 지정하지 않으면 메소드 이름을 bean의 id로 자동 인식한다.
* */
@Bean(name="member")
public MemberDTO getMember() {
return new MemberDTO(1, "user01", "pass01", "홍길동");
}
}
// ------
public static void main(String[] args) {
/* AnnotationConfigApplicationContext클래스를 사용하여 ApplicationContext를 생성한다.
* 생성자에 @Configuration 어노테이션이 달린 설정 클래스의 메타 정보를 전달한다. */
ApplicationContext context
= new AnnotationConfigApplicationContext(ContextConfiguration.class);
MemberDTO member = context.getBean("member", MemberDTO.class);
System.out.println(member);
}
AOP는 핵심 비즈니스 로직과 부가적인 기능(공통 관심사, Cross-Cutting Concern)을 분리하여 관리하는 프로그래밍 기법이다. 즉, 로깅, 트랜잭션 관리, 보안 검사 같은 공통 기능을 한 곳에서 관리하고, 여러 클래스에 적용할 수 있도록 도와주는 개념이다.
✅ @Before("execution(* 패키지명.클래스명.메서드(..))") → 특정 메서드 실행 전에 로깅 수행!
@Aspect // AOP 클래스 선언
@Component // 스프링 빈 등록
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))") // 특정 패키지의 모든 메서드 실행 전 적용
public void beforeMethod() {
System.out.println("[LOG] 메서드 실행 전 수행됩니다.");
}
}
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.ohgiraffers.section01.aop.*Service.*(..))")
public void logPointcut() {}
@Before("LoggingAspect.logPointcut()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before joinPoint.getTarget() : " + joinPoint.getTarget());
System.out.println("Before joinPoint.getSignature() : " + joinPoint.getSignature());
if(joinPoint.getArgs().length > 0) {
System.out.println("Before joinPoint.getArg()[0] : " + joinPoint.getArgs()[0]);
}
}
@After("logPointcut()")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After joinPoint.getSignature() : " + joinPoint.getSignature());
}
@AfterReturning(pointcut = "logPointcut()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("After Returning result : " + result);
}
@AfterThrowing(pointcut = "logPointcut()", throwing = "exception")
public void logAfterThrowing(Throwable exception) {
System.out.println("After Throwing exception : " + exception);
}
@Around("logPointcut()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Around Before : " + joinPoint.getSignature().getName());
/* 원본 조인포인트를 실행한다. */
Object result = joinPoint.proceed();
System.out.println("Around After : " + joinPoint.getSignature().getName());
return result;
}
}