📌 기본 애노테이션 (클릭하여 펼치기)
| 애노테이션 | 설명 |
|---|---|
@SpringBootApplication |
스프링 부트 애플리케이션의 메인 클래스에 사용 |
@Component |
스프링 빈으로 등록할 클래스 표시 |
@Autowired |
의존성 자동 주입 (생성자/필드/메서드) |
@Controller |
MVC 컨트롤러 클래스 표시 |
@Service |
비즈니스 로직 서비스 클래스 표시 |
@Repository |
데이터 액세스 계층 클래스 표시 |
⚙️ 설정 관련 (클릭하여 펼치기)
| 애노테이션 | 설명 |
|---|---|
@Configuration |
스프링 설정 클래스 표시 |
@Bean |
메서드 반환 객체를 빈으로 등록 |
🧪 테스트 관련 (클릭하여 펼치기)
| 애노테이션 | 설명 |
|---|---|
@SpringBootTest |
통합 테스트용 전체 컨텍스트 로드 |
@Transactional |
테스트 후 자동 롤백 |
@Test |
테스트 메서드 표시 |
@BeforeEach |
각 테스트 전 실행 메서드 |
@AfterEach |
각 테스트 후 실행 메서드 |
🗄️ JPA 관련 (클릭하여 펼치기)
| 애노테이션 | 설명 |
|---|---|
@Transactional |
JPA 작업 트랜잭션 처리 |
@Entity |
JPA 엔터티 클래스 표시 |
@Id |
엔터티 기본 키 필드 표시 |
@GeneratedValue |
기본 키 생성 전략 지정 |
🔄 AOP 관련 (클릭하여 펼치기)
| 애노테이션 | 설명 |
|---|---|
@Aspect |
AOP Aspect 클래스 표시 |
@Around |
메서드 실행 전후 로직 처리 |
Spring Boot Starter 사용해서 프로젝트 생성
IntelliJ Gradle 대신 Java 직접 실행 Setting ⇒ Build Tools ⇒ Gradle ⇒ Run, Test Java사용으로 바꾸기
resources/static/경로에 위치한 파일은 요청 시 그대로 응답됨- 별도의 컨트롤러 없이 HTML, CSS, JS, 이미지 등을 정적으로 서비스
- 실제 웹 페이지처럼 보여지며, 빠르게 로딩됨
- 사용자의 요청을 Controller가 받고
- 데이터를 Model에 담아
- 템플릿 엔진(View) 으로 화면에 출력
- 대표 템플릿 엔진: Thymeleaf
- URL에 파라미터를 넣어 전달한 값을 동적으로 화면에 출력 가능
@ResponseBody를 사용하면 템플릿 없이 데이터를 직접 응답- 텍스트나 JSON 형태로 반환 가능
- 텍스트: 브라우저에 문자열 그대로 출력
- 객체: JSON으로 자동 변환되어 반환됨
- ViewResolver 대신 HttpMessageConverter가 동작함
- 문자열:
StringHttpMessageConverter - 객체:
MappingJackson2HttpMessageConverter
- 문자열:
- 주로 프론트엔드와 백엔드가 분리된 구조에서 사용됨
| 계층 | 역할 |
|---|---|
| Controller | 웹 요청을 받고 처리 |
| Service | 비즈니스 로직 담당 |
| Repository | 데이터 저장 및 조회 담당 |
| Domain | 비즈니스 객체 (예: 회원) |
- Member 클래스: 회원의 id와 name 필드 보유
- MemberRepository 인터페이스: save, findById, findByName, findAll 정의
- MemoryMemberRepository: 위 인터페이스를 구현한 메모리 저장소
- 내부에 Map으로 회원 저장
clearStore()메서드로 데이터 초기화 가능
- JUnit5를 사용한 단위 테스트 수행
- 테스트는
src/test/java폴더에 작성 - 각 테스트 후
@AfterEach로 저장소 초기화하여 독립성 확보 - 테스트 대상: 저장, 이름으로 조회, 전체 조회 기능
좋은 테스트는 순서에 의존하지 않고 독립적이어야 함
- MemberService 클래스: 회원 등록 및 전체/단건 조회 기능 제공
- 중복 회원은 이름으로 검증하여 예외 처리
- 초기에
new MemoryMemberRepository()로 직접 생성 → DI (Dependency Injection)방식으로 변경
@BeforeEach: 테스트 실행 전, 새로운 저장소와 서비스 생성@AfterEach: 테스트 후 저장소 초기화
- 컴포넌트 스캔과 자동 주입
@Controller,@Service,@Repository어노테이션으로 스프링 빈 자동 등록- 생성자에 **
@Autowired**를 사용하여 의존성 자동 주입 (스프링 4.3+부터 단일 생성자 시 생략 가능)
- 자바 코드로 직접 등록
@Configuration클래스 내@Bean메서드로 명시적 빈 등록- 구현체 변경이 필요한 경우 유용 (예: 메모리 → DB 리포지토리 전환)
- 생성자 주입 (실무 권장 방식)
- 의존관계 불변성 보장
- 테스트 코드 작성 용이
- 순환 참조 방지
- Setter 주입
- 선택적 의존관계 시 사용 (거의 사용되지 않음)
- 필드 주입
- 간결하지만 테스트와 유연성 측면에서 비권장
- 싱글톤 스코프: 기본적으로 스프링 빈은 싱글톤으로 관리됨
- 컴포넌트 스캔 범위: **
@SpringBootApplication**이 있는 패키지 및 하위 패키지 대상 - 주의사항:
- **
@Autowired**는 스프링 컨테이너가 관리하는 빈에서만 동작 - 직접 생성한 객체에는 적용 불가
- **
- 정형화된 코드: 컴포넌트 스캔 방식 (
@Controller,@Service,@Repository) - 동적 구현체 전환 필요 시: 자바 설정 파일(
@Configuration)을 통한 수동 빈 등록 - 의존성 주입 우선순위: 생성자 주입 → Setter 주입 → 필드 주입
- HomeController 생성
- **
@GetMapping("/")**으로 기본 경로 매핑 home.html템플릿 반환
- **
- 정적 파일 우선순위
- 컨트롤러가 정적 리소스(static/index.html)보다 우선 적용됨
- 등록 폼 컨트롤러
GET /members/new→createMemberForm.html반환
- 데이터 전송 객체(DTO)
MemberForm클래스로 이름(name) 필드 수신
- 등록 처리
POST /members/new요청 처리MemberService.join()으로 회원 가입 후 홈(/)으로 리다이렉트
- 조회 컨트롤러
GET /members→ **memberService.findMembers()**로 전체 회원 조회- **
Model**에 회원 목록 추가하여memberList.html반환
- Thymeleaf 템플릿
- **
th:each**로 회원 목록 렌더링 - **
${members}**로 컨트롤러에서 전달된 데이터 접근
- **
| 기능 | HTTP Method | URL | 처리 내용 |
|---|---|---|---|
| 홈 | GET | / |
홈 화면 표시 |
| 등록 폼 | GET | /members/new |
회원 가입 폼 제공 |
| 등록 | POST | /members/new |
회원 데이터 저장 후 리다이렉트 |
| 조회 | GET | /members |
전체 회원 목록 표시 |
- Thymeleaf 사용:
th:text, **th:each**로 동적 HTML 생성 - PRG 패턴: POST 후 리다이렉트(
redirect:/) 적용 - MVC 구조: 컨트롤러 → 서비스 → 리포지토리 계층 분리
-
개발용 경량 DB로 웹 콘솔 제공
-
버전 호환성:
- 스프링 부트 2.x → H2 1.4.200
- 스프링 부트 3.x → H2 2.1.214+
-
연결 설정:
spring.datasource.url=jdbc:h2:tcp://localhost/~/test spring.datasource.username=sa
- 순수 JDBC
DataSource주입 후Connection,PreparedStatement로 SQL 직접 처리- 단점: 반복 코드 다량 발생, 리소스 수동 관리 (
try-catch-finally)
- 스프링 JdbcTemplate
- 반복 코드 제거 (예: **
RowMapper**로 결과 매핑 간소화) - SQL은 직접 작성 but 리소스 관리 자동화
- 반복 코드 제거 (예: **
-
객체 중심 설계 지원 (SQL 자동 생성)
-
엔터티 매핑:
@Entity public class Member { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private String name; } -
트랜잭션 필수:
@Transactional로 메서드 단위 관리 -
장점: 생산성 ↑, 패러다임 전환 (SQL → 객체)
-
인터페이스만으로 CRUD 구현
public interface MemberRepository extends JpaRepository<Member, Long> { Optional<Member> findByName(String name); // 메서드명으로 쿼리 자동 생성 } -
기능:
- 기본 CRUD 자동 제공
- 메서드 네이밍 규칙으로 조회/페이징 처리
- 실무 필수 기술 (복잡한 쿼리는
Querydsl활용)
| 기술 | 코드량 | SQL 관리 | 생산성 | 학습 곡선 |
|---|---|---|---|---|
| 순수 JDBC | 많음 | 직접 | 낮음 | 낮음 |
| JdbcTemplate | 중간 | 직접 | 중간 | 중간 |
| JPA | 적음 | 자동 | 높음 | 높음 |
| 스프링 데이터 JPA | 최소 | 자동 | 최고 | 높음 |
- H2 접근 문제: URL에
localhost명시 필요 - 트랜잭션: JPA 사용 시
@Transactional필수 적용 - 테스트:
@SpringBootTest+@Transactional로 데이터 격리
- 공통 관심 사항(cross-cutting concern): 여러 메서드에 걸쳐 반복되는 로직 (예: 시간 측정, 로깅, 트랜잭션)
- 핵심 관심 사항(core concern): 비즈니스 로직 (예: 회원 가입, 조회)
- 문제점:
- 공통 로직이 핵심 로직과 섞여 유지보수 어려움
- 변경 시 모든 메서드를 수정해야 함
-
Aspect 정의:
- **
@Aspect**로 클래스 표시 - **
@Around**로 적용 범위 지정 (예:execution(* 패키지..*(..)))
java
Copy
@Component @Aspect public class TimeTraceAop { @Around("execution(* hello.hellospring..*(..))") public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); try { return joinPoint.proceed(); // 핵심 로직 실행 } finally { long duration = System.currentTimeMillis() - start; System.out.println(joinPoint + " 실행 시간: " + duration + "ms"); } } } - **
-
분리된 공통 로직:
- 시간 측정, 로깅 등 공통 기능을 한 곳에서 관리
- 핵심 로직은 깔끔하게 유지
- 프록시 패턴:
- 스프링은 AOP 적용 시 대상 객체의 프록시를 생성
memberService호출 시 실제 객체 대신 프록시가 먼저 실행- 프록시에서 공통 로직 처리 후 실제 메서드 호출 (
joinPoint.proceed())
- 유지보수성 향상: 공통 로직 중앙 집중화
- 변경 용이성: 공통 로직만 수정하면 전체 적용
- 코드 간결성: 핵심 로직에만 집중 가능
- AOP는 스프링 빈에만 적용 가능 (직접 생성한 객체에는 불가)
- **
@Around**의 포인트컷 표현식으로 적용 대상 제어 가능