[취준생을 위한 스프링부트 백엔드 프로그래밍] 1주차 과제

brunch.co.kr/@springboot/530

 

취준생을 위한 스프링부트 백엔드 프로그래밍 (1)

1주차 1교시 - 스프링부트란 무엇인가? | "취준생을 위한 스프링부트 백엔드 프로그래밍"이라는 주제로 약 8주간 글을 작성할 예정입니다. 제가 잘못된 길로 가지 않도록, 댓글로 의견 및 조언 

brunch.co.kr

brunch.co.kr/@springboot/531

 

취준생을 위한 스프링부트 백엔드 프로그래밍 (2)

2. 간단한 API 서버 만들어보기, 앞으로 커리큘럼 소개 | "취준생을 위한 스프링부트 백엔드 프로그래밍"이라는 주제로 약 8주간 글을 작성할 예정입니다. 제가 잘못된 길로 가지 않도록, 댓글로

brunch.co.kr

필수 과제

1. 어노테이션이 어떤 기능을 하는지 정리

스프링 : @RestController, @RequestMapping, @GetMapping, @Service, @Component,

@Configuration, @SpringBootApplication

 

Lombok : @Getter, @Setter, @Data, @Builder

 

2.스프링 프레임워크의 DI에 대해서, 면접 때 설명할 수 있는 수준으로 정리

 

3.네이버 오픈 API에 애플리케이션 등록

 

4.샘플 소스 IntelliJ에서 실행 및 잘되는지 확인

선택과제

1. 영화 검색 API 사용 시 응답 데이터를 모두 가져올 수 있도록 필드 추가

2. 테스트 코드 작성

3. 영화 API 외 블로그, 뉴스 등 검색 서비스 하나 추가로 연동해보기

4. 카카오 API 사용해보기(셀프추가)

 

※ 꼭 네이버 API 사용 안해도 됩니다.😊

 

스프링

 

@RestController

 

RestController을 알기전에 먼저 @Controller을 알아야 한다. 둘의 결정적 차이는

HTTP Response Body가 생성되는 방식의 차이다.

 

@Controller는 아래와 같은 과정을 통해 주로 View를 반환할 때 사용 한다.

https://mangkyu.tistory.com/49

1. Client가 보낸 URI 형식의 요청(localhost:8080/members)을 DispatcherServlet에서 인터셉트한다.

2. Handler Mapping에 의해 URI를 체크하여 알맞은 Controller로 보내준다.

3. Controller가 요청을 처리한후 view이름(index.html 등)을 반환한다.

4. 위 그림에는 없지만 View Resolver가 반환한 뷰이름으로부터 사용할 뷰 오브젝트를 매핑해준다.

5. DispatcherServlet을 통해 Client에게 View를 반환한다.

 

※ 위 과정을 이해하기 위해선 Spring MVC구조를 이해해야 한다. (자세한 사항드링 더 있지만 필자도 자세히는 몰라유.. 좀더공부해야합니다.. 😭)

 

사용 예시

@Controller
public class HomeController {

  @RequestMapping("/")
  public String home(){
    return "home";
  }
}

 

그럼 @RestController은 뭘까?

Spring4부터 등장한 어노테이션으로 VIEW를 반환하는게 아니라 DATA를 반환할 때 사용한다.

https://milkye.tistory.com/283

1. Client가 보낸 URI 형식의 요청(localhost:8080/members)을 DispatcherServlet에서 인터셉트한다.

2. Handler Mapping에 의해 URI를 체크하여 알맞은 Controller로 보내준다.

3. Controller가 요청을 처리한후 뷰이름이 아닌 데이터를 반환한다.

  - 스프링부트는 기본이 JSON설정이기 때문에 객체를 반환하면 JSON형식의 데이터를 Client에게 반환한다.

  - View Resolver를 쓰지 않으므로 VIEW 페이지를 보여주지 않는다.

 

※ 위 그림에는 없지만 Client에게 반환되기 전에 HttpMessageConverter 설정에 의해 적절한 데이터형식(xml 등)으로 반환되지만 너무 딮하므로 Pass...

 

※ Spring3에서 등장한 @ResponseBody를 통해 DATA를 반환해도 되지만 메소드마다 리턴타입에 추가를 해줘야 된다.

하지만 @RestConroller가 나온 이후로 컨트롤러 자체의 용도를 지정할 수 있어 DATA만 반환하는 컨트롤러를 따로 분리할 수 있고 @RestController 하나만 선언하면 @ResponseBody를 일일이 안붙여도 된다.  

@RestController = @Controller + @ResponseBody라고 이해하면 편하다.(편할까..?)

 

사용 예시

@RestController
public class HomeController {

  @RequestMapping("/testpage")
  public String hello(){
    return "HELLO_WORLD";
  }
}

@RequestMapping

Client가 요청한 URI을 알맞은 메소드에 매핑해주는 어노테이션이다. 바로 예제 소스를 확인해보자.

 

1. 단순히 경로를 지정

@Controller
public class HomeController {

  @RequestMapping("/event/list")
  public String list(){
	...
  }
}

 

2. 여러 경로를 지정(배열로 지정)

@Controller
public class HomeController {

  @RequestMapping( {"/main", "/index", "", "view/*, **/msg} )
  public String list(){
	...
  }
}

""는 URI를 지정하지 않았을 때이다. 또한, 와일드 카드도 명시할 수 있다.

 

? : 아무값이나 한글자만 요청

* : 여러 글자를 이용

Ex) /* -> /, /aaa, /bbb 맵핑 가능

** 이하 모든 요청 경로에 대해 매핑

Ex) /aaa/bbb는 /*에 맵핑이 되지 않고 /**에 맵핑 가능

 

 

3. 메서드 명시

@Controller
public class HomeController {

  @RequestMapping(value="/member/regist", method = RequestMethod.GET )
  public String regist(){
	...
  }
}

@Controller
public class HomeController {

  @RequestMapping(value="/member/regist", method = RequestMethod.POST )
  public String regist(){
	...
  }
}

 

method 속성을 지정하여 메서드에서 처리할 전송 방식을 지정할 수 있다.

URI가 동일하더라도 method속성을 통해 구분되서 알맞은 메서드로 매핑이 된다.

 

※ GET은 주로 데이터 조회시 사용한다. (회원 목록 조회 or 회원 상세 조회 등)

 

※ POST는 서버로 요청 데이터를 전달해서 신규 리소스 등록 혹은 프로세스 처리가 필요할 때 사용한다.

회원등록같은 경우는 새로운 리소스(자원)가 생성된다. 하지만 배달을 예시로 들었을 때 결제완료 -> 배달시작 -> 배달완료처럼 프로세스의 상태가 변경되는 경우에도 POST를 사용한다.(배달 시작 버튼 눌렀을 때 POST로 처리)

 

4. 클래스단에 매핑

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/search")
public class MovieController {

    private final MovieService movieService;

    @GetMapping("/movies")
    public List<ResponseMovieClientDto> getMoviesByQuery(@RequestParam(name = "q") String query){
        return movieService.search(query);
    }

}

샘플코드 예시중 하나이다. 클래스단에 매핑을 하게되면 "/api/v1/search/"로 시작하는 URI는 모두 MovieController로 매핑이 된다.

 

※ @RequiredArgsConstructor

초기화 되지 않은 final 필드나 @NonNull이 붙은 필드에 대해 생성자를 생성해준다. 주로 DI(의존성 주입)의 편의성을 위해서 사용되곤한다.

 

5. 요청 컨텐트 타입(consumes) / 응답 컨텐트 타입(produces) 제한

@Controller
public class HomeController {

  @RequestMapping(value="/member/regist", method = RequestMethod.POST, 
			consumes="application/json", produces="applicaiton/json")
  public String regist(){
	...
  }
}

consumes는 HTTP 요청시 Content-Type 요청 헤더의 값을 비교하여 일치하는 경우만 처리하고 싶을 때 사용한다.

 

produces는 응답 결과로 JSON을 요구하는 요청을 처리하고 싶을때, 즉 Accept 요청 헤더에 application/json이 포함된 경우만 처리하고 싶을 때 사용한다.

 

※ 클라이언트에서 전달한 데이터를 컨트롤러단에서 받기 위해 @RequestParam 혹은 @PathVariable을 사용한다. 여기서는 차이점을 적어볼려 한다.

 

보통 2가지 케이스가 있다.

1. http://localhost:8080?index=1&page=2

=> 파라미터의 key와 value를 함께 전달할 때 주로 사용한다.

 

예시

URI : http://localhost:8080/read?no=1

@GetMapping("/read")
public ModelAndView getFactoryRead(@RequestParam("no") int factroyId, SearchCriteria criteria) 
{
  //...    
}

위와 같이 URI 뒤에 붙는 파라미터의 값을 가져올 때 사용한다.

 

 

2. http://localhost:8080/members/100

=> Rest api에서 값을 호출할 때 주로 사용한다.

 

예시

URI : http://localhost:8080/delete/1

@PostMapping("delete/{idx}")
@ResponseBody
public JsonResultVo postDeleteFactory(@PathVariable("idx") int factoryIdx) {
	return factoryService.deleteFacotryData(factoryIdx);
}

위와 같이 URI에서 각 구분자에 들어오는 값을 처리해야 할 때 사용한다.

 

@GetMapping

Spring 4.3부터 나온 GET요청을 받는 어노테이션으로 @RequestMapping에서 메소드를 명시한 것을 축약해서 사용할 수 있다.

좀더 명시적으로 표현할 수 있으며, 메소드에만 적용할 수 있다.

 

※ @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping 도 있으니 REST API 설계시 적절하게 사용하면 된다.

 

@Service

MVC 패턴으로 프로젝트를 하면 보통 아래와 같은 구조로 진행한 경험이 있을 것이다.

http://randikatech.blogspot.com/2019/09/get-your-hands-dirty-with-micro-services.html

 

Service의 역할은 Repository를 통해 가져온 데이터를 가공하는 역할을 수행한다.

 

@Service 어노테이션은 Service의 역할을 수행하는 클래스에 붙여주는 어노테이션으로, controller와 repository 등 명시적으로 구분하기 위해 사용한다.

 

어노테이션 까보면 아래와 같다.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}

다른 건 잘 모르겠고 ㅎㅎ; 확인할 어노테이션은 @Component 이다.

 

※ @Component란?

스프링 부트를 실행하면 컴포넌트 스캔에 의해 @Component가 붙은 것들을 찾아서 스프링 빈으로 등록해준다.

 

@Controller과 @Repository도 까보면 @Component 어노테이션이 붙여 있다.

 

사실 @Component를 붙여도 스프링 빈으로 등록이 되서 사용이 가능하지만 가시성이 떨어지기 때문에 잘 사용하지 않는다.

 

 

@Component

개발자가 직접 작성한 클래스를 IoC Container에 Bean으로 등록하기 위해 사용하는 어노테이션이다.

 

예시

@Component(value="mystudent")
public class Student{
	public Student(){
    	...
    }
}

bean Id를 직접적으로 기입해줄 수 있다. 기입하지 않으면 자동으로 클래스이름을 카멜케이스로 변경한 값이 bean Id가 된다.

 

@Component를 사용한 Bean의 의존성 주입은 @Autowired어노테이션을 이용할 수 있다.

 

※ @Autowired란?

생성자나 Setter를 사용하여 의존성 주입을 할 때, 해당 빈을 찾아서 주입해주는 어노테이션이다.

 

예시

@Component
public class MadExample {

    @Autowired
    private HelloService helloService;
}

 

같은 타입의 Bean이 여러개일 경우엔?

그림과 같이 B class랑 C class가 A interface를 implements 하면 A 객체에는 B or C가 들어갈 수 있다.

 

@Service
public class example{
	@Autowired
    private A a;
}

위와 같을 때 A타입의 참조변수 a에는 어떤 값이 들어갈지 알지 못해 컴파일 에러가 발생한다.

https://galid1.tistory.com/512, 사진은 에러가 뜬다는 예시일뿐 코드는 참고만해주세요.

방법은 2가지가 있다.

1. @Primary

@Autowired 대상이 되는 클래스 들 중 주입이 되길 원하는 클래스에 붙이면 Spring이 자동으로 해당 객체를 주입해준다.

@Repository
@Primary
public class B implements C

 

2. @Qualifier

@Autowired 어노테이션으로 주입하는 곳에서 @Qualifier("bean id")를 이용해 어떤 Bean이 주입될지 명시해주면 해결된다.

@Service
public class example{
	@Autowired
    @Qualifier("b")
    private A a;
}

 

3. 모든 빈을 주입받기

리스트로 받도록 하면 IoC 컨테이너 안에 존재하는 모든 Bean이 List안에 들어가게 된다.

@Service
public class example{
	@Autowired
    List<A> a;
}

 

※ 의존성을 주입하는 방법은크기 필드 주입, 수정자 주입, 생성자 주입이 있다. 권장되는 방식은 생성자 주입 방식이다.

  • 순환 참조를 방지할 수 있다.

    • 순환 참조가 발생하는 경우 애플리케이션이 구동되지 않는다.

  • 테스트 코드 작성이 편리하다.
    • 단순 POJO를 이용한 테스트 코드를 만들 수 있다.
  • 품질 좋은 코드를 작성할 수 있다.
  • immutable(불변성)하다.
    • 실행 중에 객체가 변하는 것을 막을 수 있고 오류를 사전에 방지할 수 있다.

자세한건 요기...👇

madplay.github.io/post/why-constructor-injection-is-better-than-field-injection

 

※ 스프링부트 프로젝트 경로

스프링 부트 프로젝트를 생성하면 @SpringBootApplication이 붙은 클래스가 자동으로 생성된다.

핵심은 저 클래스가 존재하는 경로(/src/main/java/com/study/task)안에 있는 모든 파일들이 컴포넌트 스캔 대상이 된다. 하고싶은 말은 괜히 옮겼다가 스캔대상에 포함되지 않아서 에러 터뜨리지 말고 그냥 써라 :)

 

※ @Bean이란?

@Bean 어노테이션도 마찬가지로 IoC Container에 Bean을 등록하기 위해 사용하지만 @Component와 용도가 다르다.

@Bean은 개발자가 직접 제어자 불가능한 외부 라이브러리 혹은 초기에 설정 세팅 활용 등 이러한 경우에 사용된다.

 

@Configuration
public class AppConfig {
  @Bean
  public DiscountPolicy discountPolicy() {
    return new RateDiscountPolicy();
  }
}

DIscountPolicy를 라이브러리 보면 위와 같이 해당 라이브러리 객체를 반환하는 Method를 만들고 @Bean어노테이션을 붙여주면 된다.

마찬가지로 bean Id를 직접적으로 기입해줄 수 있다. 기입하지 않으면 자동으로 클래스이름을 카멜케이스로 변경한 값이 bean Id가 된다.

 

@Configuration
public class AppConfig {
  
  @Bean
  public OrderService orderService() {
    System.out.println("call AppConfig.orderService");
    return new OrderServiceImpl(
        memberRepository());
  }

  @Bean
  public MemberRepository memberRepository() {
    System.out.println("call AppConfig.memberRepository");
    return new MemoryMemberRepository();
  }
  
}

또한, 위와 같이 의존관계가필요할 때는 OrderServiceImpl의 생성자에서 MemberRepository를 주입받을 수 있도록 코드를 작성할 수 있다. Bean으로 등록된 memberRepository()를 호출함으로써 의존성을 주입할 수 있다.

 

@Configuration

스프링 IoC Container에게 해당 클래스를 Bean 구성 Class임을 알려준다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

Configuration 어노테이션에도 @Component가 있다.

위에서 설명한 @Bean을 등록하기 위해선 임의의 클래스에 만들어서 단순히 @Bean을 등록해서 되는 것이 아니다. @Bean을 사용하는 클래스에는 반드시 @Configuration 어노테이션을 붙여서 해당 클래스에서 1개 이상의 Bean을 등록하고자 함을 명시해야 한다.

 

※ @Configuration 없이 @Bean만 사용해도 스프링 빈으로 등록이 되지만 싱글톤을 보장하지 못한다. 

 

싱글톤이 머예요?

💡
어플리케이션 내에서 하나의 객체만을 생성하도록 해서, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 거란다 :)

 

@SpringBootApplication

스프링 레거시로 개발해보신 적이 있으신 분이면 환경설정하다가 멘탈이 바사삭 되는 경험을 종종 겪어보셨을 것이다.(나도...)

@SpringBootApplicaiton은 스프링 부트의 최대 장점 중 하나인 자동 환경설정을 담당하는 어노테이션이다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

눈여겨 봐야할 어노테이션은 아래와 같다.

 

  • @EnableAutoConfiguration
    • 환경설정에 필요한 자동 설정을 Bean으로 등록해준다.
    • Spring의 META-INF 아래 spring.factories 파일에 자동으로 가져올 Bean들이 정의되어 있는데 이를 미리 가져와서 등록한다.
    • 라이브러리별로 버전에 대한 의존성이 존재한다. 간혹 의존성이 맞지않아 오류가 뜰 수도 있는데 스프링 부트는 자동으로 각 라이브러리에 대한 버전을 자동으로 설정하여 제공해준다.
  •   @ComponentScan
    • 패키지 내에 컴포너트가 명시된 클래스를 찾아서 Bean으로 등록해준다.
    • 패키지란 @SpringBootApplication이 붙은 클래스가 존재하는 경로이다. 
  •   @SpringBootConfiguration 
    • 클래스가 Spring Boot 애플리케이션 @Configuration을 제공함을 나타낸다. 

 

※ 스프링 부트 장점을 요약하면 다음과 같다.

1. 간편한 설정

2. 편리한 의존성 관리 & 자동 권장 버전 관리

3. 내장 서버로 인한 간단한 배포 서버 구축

4. 스프링 Security, Spring Data JPA 등 다른 스프링 관련 프레임워크들을 간편하게 사용할 수 있다.

 

Lombok

자바에서 기계적으로 작성하는 getter, setter, 생성자 등을 어노테이션 기반으로 코드를 자동완성 해주어 코드의 다이어트를 해주는 라이브러리이다.

 

※ 참고로 인텔리제이에서 사용할려면 플러그인에서 다운받은 뒤 환경설정에서 Enable annotation processing을 추가해줘야 한다.

예전에 STS에 Lombok 적용할려다가 약간 고생한 기억이 나네요... 인텔리제이 짱!!

 

@Getter / @Setter

@Getter / @Setter는 클래스에 정의된 모든 변수들에 대해 Getter 메소드, Setter 메소드를 만들어준다.

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Person {
    private String name;
    private String hobby;
}

※ @Setter는 지양해야 한다. 

Setter사용시 의도가 분명하지 않고 객체의 상태를 언제든지 변경할 수 있어서 객체의 안전성이 보장받기 힘들다.

특히 @Entity를 명시하는 클래스에서는 조심해야 한다.

 

@AllArgsConstructor

클래스에 정의된 모든 변수를 사용하는 생성자를 자동완성 시켜주는 어노테이션이다.

@AllArgsConstructor
public class Person {
    private String name;
    private String hobby;
}

 

@NoArgsConstructor

어떠한 변수도 사용하지 않는 기본 생성자를 자동완성 시켜주는 어노테이션이다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Person {
    private String name;
    private String hobby;

    /**
     * NoArgsConstructor를 통해 아래의 상생자를 자동 생성
     * public Person() {
     *
     * }
     */

}

※ access = AccessLevel.PROTECTED를 사용하는 이유는

무분별한 객체 생성에 대해 한번 더 체크할 수 있는 수단이 된다.

예를 들어 Person이라는 Class는 name, hobby 정보를 모두 가지고있어야만 되는 상황일경우에 기본 생성자를 막아야 안전한 객체를 만들 수 있다.

 

@Getter
@Setter
@NoArgsConstructor
public class Person {
    private String name;
    private String hobby;
}


/// Main.java
public static void main(String[] args) {
    Person user = new Person();
    user.setName("testname");
    
    // hobby가 설정되지 않았으므로 Person 완전하지 않은 객체
}

Person의 생성자가 없으므로 Setter를 만들어서 값을 설정하지만
실수로 setHobby()를 누락할 경우 객체는 불완전한 상태가 되버립니다.

 

@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Person {
    private String name;
    private String hobby;
    
    public Person(String name, String hobby) {
        this.name = name;
        this.hobby = hobby;
    }
}


/// Main.java
public static void main(String[] args) {
    Person user = new Person("name", "hobby");
    
    /// 기본 생성자가 없고 객체가 지정한 생성자를 사용해야하기 때문에
    /// 무조건 완전한 상태의 객체가 생성되게 된다.
}

위와 같이 할 경우 누락할 경우 컴파일 에러가 발생하여 누락을 방지할 수 있다.

 

※ 좋은 에러 순위

컴파일 에러 >>>> 런타임 에러 >>>>>>비디치>>>>>>>베르사유 장벽>>>>>>>사용자 이벤트 시 에러

 

@EqualsAndHashCode

클래스에 대한 equals함수와 hashCode 함수를 자동으로 생성해준다. 

 

@ToString

클래스의 변수들을 기반으로 ToString 메소드를 자동으로 완성시켜 준다. 

@ToString(exclude = "변수명") //항목 에서 제외
public class Member {...}

@ToString(of = {"name", "hobby"} //명시된 것만 항목에 포함
public class Member {...}

※JPA에서 양방향 연관관계일 시 ToString을 잘못 쓰면 무한 순환 참조가 발생할 수 있다.

 

@Data

@ToString, @EqualsAndHashCode, @Getter, @Setter, @RequiredArgsConstructor를 자동완성 시켜준다.

실무에서는 너무 무겁고 객체의 안정성을 지키기 때문에 @Data의 활용을 지양한다.

 

@Builder

해당 클래스의 객체의 생성에 Builder패턴을 적용시켜준다

모든 변수들에 대해 build하기를 원한다면 클래스 위에 @Builder를 붙이면 되지만, 특정 변수만을 build하기 원한다면 생성자를 작성하고 그 위에 @Builder 어노테이션을 붙여주면 된다.

 

빌더패턴은 클래스단에 하는것 보단 생성자위에 명시하여 비즈니스 로직에 맞게 필수 값에 대해서만 생성자를 열어야 하는게 좋다.

 

Ex) JPA + Builder 사용시

JPA를 사용하면 아이덴티티 전략, BaseEntity등을 보통 작성한다. 이럴 경우 만약 클래스 단에 Builder를 명시하게 되면

위 사진과 같이 빌더패턴 사용시 id랑 updateAt에 값을 넣을 수 있기 때문에 적절하지 않다.(id랑 updateAt은 객체생성시 자동으로 찔러받는 값이기 때문이다.)

 

 

빌더패턴에 대한 내용은 요기...👇 (지금보니 설명이 미약하긴 하네요;;)

dncjf64.tistory.com/247?category=773911

 

빌더 패턴

빌더패턴이란 클라이언트 코드에서 필요한 객체를 직접 생성하는 대신, 그 전에 필수 인자들을 전달하여 빌더 객체를 만든 뒤, 빌더 객체에 정의된 설정 메서드들을 호출하여 인스턴스를 생성

dncjf64.tistory.com

※ lombok.config

참고로 사진과 같이 lombok의 config설정을 해서 @Data 사용 방지 등을 적용할 수 있다. 이러면 커뮤니케이션 비용을 줄일 수 있기 때문에 좋은 방법이라 생각한다. 

 

스프링 프레임워크의 DI

❔ 면접관 :  Spring의 DI에 대해 설명해주세요.

 

DI란 Dependency Injection의 줄임말로 한글로는 의존성 주입이라 합니다.

쉽게 말씀드리자면 외부에서 의존 객체를 생성하여 전달하는 것을 말하며

개발자가 직접 new 키워드를 이용해서 객체를 생성하지 않고 객체를 관리해주는 IoC 컨테이너에서

객체를 제공 받습니다. 

 

※ 이 부분까지 언급할지말지 고민

DI를 사용하면 객체지향 설계 원칙인 OCP(개방 폐쇄 원칙)과 DIP(의존 역전 원칙)을 자연스럽게 따르게 되

어 결합도는 낮아지고 유지보수와 확장성에 유리한 이점을 가질 수 있습니다.

  - OCP와 DIP가 뭔가요?

 

DI를 하는 방법은 총 3가지고 있습니다.

  • Setter 메서드를 이용한 주입
  • 생성자 주입
  • 필드 주입

※ 꼬리질문 예상

  - DI 주입 방법에 대한 장단점

  - IoC 컨테이너란?

 

 

스프링 MVC 아키텍처

이거는 외워야된다 외워야된다....

Ex) 클라이언트가 특정 액션(상품 구매 등)을 취해서 반환받은 결과가 주어졌을 때의 과정 등

 

네이버 오픈 API에 애플리케이션 등록

 

 

샘플 소스 IntelliJ에서 실행 및 잘되는지 확인

※ Feign Client / WebClient 이란?

스터디 초반에서는 RestTemplate을 사용해서 API 통신을 진행한다. 실무에서는 Feign Client / WebClient를 많이 사용한다고 한다. 간단히 개념정도만 적어볼려고 한다.

 

1. Feign Client

  • NetFlix에서 개발한 Http Client Binder

  • 사용시 interface를 작성하고 annotation을 선언만 해주면 간단히 사용할 수 있다. 코드축약적으로 보면 JPA -> 스프링 데이터 JPA || RestTemplate -> Feign Client 과 유사한것 같다.

  • Rest 기반의 서비스 호출을 좀더 추상화하여 개발자 들이 간편하게 클라이언트 코드를 작성할 수 있다.

2. WebClient

  • Spring5.0에서 추가된 인터페이스로 HTTP 요청을 할때 사용한다. 스프링 측에서는 WebRestTemplate은 향후 deprecated될 예정이라한다.

  • JavaDoc의 RestTemplate 부분 Note 일부분
NOTE: As of 5.0, the non-blocking, reactive org.springframework.web.reactive.client.WebClient offers a modern alternative to the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplate will be deprecated in a future version and will not have major new features added going forward. See the WebClient section of the Spring Framework reference documentation for more details and example code.

한줄 요약 : RestTemplate은 deprecated될 예정이며 더 나은 체계를 가지는 WebClient가 있으니까 그걸 써라

  • RestTemplate과는 반대로 Non-Blocking I/O 기반이다. 따라서 각 HTTP 요청이 비동기적으로 발생하게 된다.

    • 예를 들어 RestTemplate을 이용하여 HTTP 요청을 2개이상 진행했을 때 총 8초가 걸렸다면 WebClient는 각각 5초, 3초 걸리는 HTTP 요청을 동시에 처리한다.

선택과제

1. 영화 검색 API 사용 시 응답 데이터를 모두 가져올 수 있도록 필드 추가

  - 필드 추가 후 검증 테스트 작성

 

2. 테스트 코드 작성

  - 통합 테스트로 작성

  - 단위 테스트는 학습 필요...

 

3. 영화 API 외 블로그, 뉴스 등 검색 서비스 하나 추가로 연동해보기

  - 네이버 검색 카테고리 중 도서 API 사용

  - RestTemplate 대신 WebClient 사용

 

4. 카카오 API 사용해보기(셀프추가)

  - 질문1.

카카오 API 사용시 "Hello" 데이터를 가져오기 위해 아래와 같이 이중배열로 했는데 제네릭 or Inner 클래스로 가져올 수 있는 방법이 있는지..

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ResponseTransApiDto {

    private String[][] translated_text;

}

통합 질문

1. WebClient 사용관련 틀린게 있는지

  - 도서 검색 API 구현시 사용

 

2. 테스트코드 퀄리티

전체코드

github.com/jikimee64/boot-study-assignment

 

jikimee64/boot-study-assignment

스프링부트 스터디 주차별 과제. Contribute to jikimee64/boot-study-assignment development by creating an account on GitHub.

github.com

참고

engkimbs.tistory.com/808

elfinlas.github.io/2018/02/18/spring-parameter/

mrrootable.tistory.com/75

galid1.tistory.com/494

velog.io/@max9106/Spring-Autowired-b4k546knz1

mangkyu.tistory.com/75

n1tjrgns.tistory.com/231

cobbybb.tistory.com/14