이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
데이터 전달 방식은 크게 2가지
쿼리 파라미터를 통한 데이터 전송 : GET - 주로 정렬 필터(검색어)
메세지 바디를 통한 데이터 전송 : POST, PUT, PATCH - 회원 가입, 상품 주문, 리소스 등록, 리소스 변경
클라이언트에서 서버로 데이터 전송하는 4가지 상황은 다음과 같다.
이미지, 정적 텍스트 문서
조회는 GET
을 사용한다.
정적 데이터는 쿼리 파라미터 없이 리소스 경로로 단순하게 조회가 가능하다.
주로 검색, 게시판 목록에서 정렬 필터(검색어)
조회 조건을 줄여주는 피렅, 조회 결과를 정렬하는 정렬 조건에 주로 사용한다.
마찬가지로 GET
을 사용한다.
HTML Form submit 할 때 POST로 전송한다.
HTML Form 전송은 GET, POST만 지원하므로 제약이 있다.
Content-Type : multipart/form-data - 파일 업로드 같은 바이너리 데이터 전송시 사용한다.
서버 to 서버 - 백엔드 시스템 통신
앱 클라이언트 - 아이폰, 안드로이드
웹 클라이언트 - HTML에서 Form 전송 대신 자바 스크립트를 통한 통신에 사용(AJAX) ex) React, VueJs 같은 웹 클라이언트와 API 통신
GET : 조회, 쿼리 파라미터로 데이터를 전달한다.
POST, PUT, PATCH : 메세지 바디를 통해 데이터를 전송한다.
Content-Type : application/json을 주로 사용한다. (사실상 표준) - TEXT, XML, JSON 등등
회원 관리 시스템에서 HTML FORM을 사용하면 다음과 같다.
회원 목록 /members -> GET
회원 등록폼 /members -> GET
회원 등록 /members/new, /members -> POST
회원 조회 /members/{id} -> GET
회원 수정폼 /members/{id}/edit -> GET
회원 수정 /members/{id}/edit, /members/{id} -> POST
회원 삭제 /members/{id} -> POST
HTML Form은 GET, POST만 지원하므로 제약이 있기 때문에 이런 제약을 해결하기 위해 컨트롤 URI
를 사용한다.
컨트롤 URI는 동사로 된 리소스 경로를 사용하고 여기서는 POST의 /new, /edit, /delete가 컨트롤 URI에 해당한다.
HTTP 메서드로 해결하기 애매한 경우에도 사용한다. (HTTP API 포함)
회원 관리 시스템에서 API 설계를 POST 기반 등록을 했을 경우 다음과 같이 설계한다.
회원 목록 /members -> GET
회원 등록 /members -> POST
회원 조회 /members/{id} -> GET
회원 수정 /members/{id} -> PATCH, PUT, POST
회원 삭제 /members/{id} -> DELETE
회원 관리 시스템 API 설계에서 POST 기반의 등록인 경우 클라이언트는 등록될 리소스의 URI를 모르고 서버에게 넘겨주고, 서버는 새로 등록된 URI를 생성해준다. 이런 스타일의 관리를 Collection(컬렉션)
이라고 한다.
컬렉션에서는 서버가 리소스 URI를 결정하고 관리를 한다.
반면에 PUT 기반의 등록인 경우 클라이언트가 직접 리소스의 URI를 지정한다. 이런 스타일의 관리를 Store(스토어)
라고 한다.
대부분 실제 실무에서는 POST 기반의 등록(Collection 기반) 을 주로 사용한다.
문서 - 단일 개념(파일 하나, 객체 인스턴스, 데이터베이스 row)
컬렉션 - 서버가 관리하는 리소스 디렉터리. 서버가 리소스의 URI를 생성하고 관리한다.
스토어 - 클라이언트가 관리하는 자원 저장소. 클라이언트가 리소스의 URI를 알고 관리한다.
컨트롤러, 컨트롤 URI - 문서나 컬렉션, 스토어로 해결하기 어려운 부분에 대해서 도와주는 개념이다.
정리) 실무에 나가게 된다면, 문서와 컬렉션을 가지고 그 안에서 GET, POST, PUT, DELETE로 최대한 해결을 한다. 그런데 만약에 해결하기 어려운 경우에는 컨트롤 URI를 사용해서 해결한다.
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
예를 들면 요구사항에서 회원 정보 관리 API를 만드는 내용이 적혀져 있다.
이런 경우 좋은 URI 설계는 리소스를 식별하는 것이다. 여기서 리소스는 회원
을 의미한다.
회원 목록 조회 /members
회원 조회 /members/{id}
회원 등록 /members/{id}
회원 수정 /members/{id}
회원 삭제 /members/{id}
URI는 리소스만 식별하므로 리소스와 해당 리소스를 대상으로 하는 행위를 분리시킨다. 여기서 행위는 조회
, 등록
, 수정
, 삭제
을 의미한다.
행위(메서드)는 GET, POST, PUT, PATCH, DELETE 로 구분한다.
GET
: 리소스를 조회한다.
POST
: 요청 데이터 처리, 주로 등록에 사용한다.
PUT
: 리소스를 완전히 대체한다. 해당 리소스가 없으면 생성한다.
PATCH
: 리소스를 일부 변경한다. (PUT
은 모든 것을 변경한다)
DELETE
: 리소스를 삭제한다.
GET /search?q=hello&hl=ko HTTP/1.1
Host: www.google.com
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
이 글의 코드와 정보들은 강의를 들으며 정리한 내용을 토대로 작성하였습니다.
지금까지 스프링 빈을 등록할 때는 자바 코드의 @Bean을 통해서 설정 정보에 직접 등록할 스프링 빈을 나열했다면, 이번에는 자동으로 스프링 빈을 등록하는 컴포넌트 스캔
에 대해서 알아보자.
코드로 컴포넌트 스캔과 의존관계 자동 주입을 알아보자.
기존
AppConfig.java
는 과거 코드와 테스트를 유지하기 위해 남겨두고 새로운AutoAppConfig.java
를 만들었다.
package hello.core;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan (
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}
컴포넌트 스캔을 사용하기 위해서는 @ComponentScan
을 설정 정보에 입력하면 된다.
여기서 excludeFilters
는 사용한 이유는 앞서 AppConfig.java
에서 만든 설정 정보들과 등록이 겹치기 때문이다.
따라서 겹치지 않기 위해 excludeFilters
사용하여 컴포넌트 스캔 대상에서 제외하는 방법으로 설정했다.
이제 각 클래스가 컴포넌트 스캔의 대상이 되도록 @Component
애노테이션을 붙여주면 된다.
MemoryMemberRepository @Component 추가
RateDiscountPolicy @Component 추가
@Component
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
@Autowired
는 의존관계를 자동으로 주입해준다.
그리고 @Autowired
를 사용하면 생성자에서 여러 의존관계도 한번에 주입받을 수 있다.
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
@ComponentScan(
basePackages = "hello.core",
}
backPackages
: 탐색할 패키지의 시작 위치를 지정한다.
해석하자면, “hello.core” 패키지를 포함해서 하위 패키지를 모두 탐색한다는 의미이다.
basePackages = {"hello.core", "hello.service"}
처럼 여러 시작 위치를 지정할 수도 있다.@ComponentScan(
basePackageClasses = AutoAppConfig.class,
}
basePackageClasses
: 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다.
패키지의 시작 위치를 지정하지 않으면 @ComponentScan
이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다.
권장하는 방법은 패키지의 위치를 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이다. 스프링 부트도 이 방법을 기본으로 제공한다.
예를 들어 프로젝트가 다음과 같은 구조로 되어 있으면
com.hello
com.hello.service
com.hello.repository
com.hello
를 프로젝트 시작 루트로 하고, 여기에 AppConfig와 같은 메인 설정 정보를 두고, @ComponentScan 애노테이션을 붙이고, basePackages
지정은 생략한다.
그러면 com.hello
를 포함한 하위 패키지 모두 자동으로 컴포넌트 스캔의 대상이 된다.
컴포넌트 스캔은 Component
뿐만 아니라 다음과 같은 내용도 추가로 대상에 포함한다.
@Contoller
: 스프링 MVC 컨트롤러에서 사용
@Service
: 스프링 비즈니스 로직에서 사용
@Repository
: 스프링 데이터 접근 계층에서 사용
@Configuration
: 스프링 설정 정보에서 사용