Spring/MSA

[스프링 MSA] MSA_S5 : Catalogs and Orders Microservice

ajeong7038 2023. 11. 15. 17:31

`Spring Cloud로 개발하는 마이크로서비스 애플리케이션 (MSA)` 강의를 듣고 정리한 자료입니다

 

✨ Gateway 연동

포트 번호 연동

- return 값에 String.format("~ $s", env.getProperty("local.server.port"));

- 랜덤 포트로 할당되어진 값을 가져올 수 있다

application.yml

- routes: uri: lb://[유레카에 등록되어 있는 이름 값]

- lb : 로드밸런싱 작업을 위해 설정함

predicates: #조건식
  - Path=/user-service/**

 

- `user-service` 정보가 들어오면 전부 uri (여기서는 `lb://USER-SERVICE)으로 포워딩 시켜달라고 요청

오류

- 8000번 포트인 apigateway-service에서 user-service로 포워딩시키려 했더니 에러가 났다

1. 열려있는 `http://localhost:11166/health_check` 정상 작동

2. 그러나 `http://localhost:8000/user-service/health_check` => 404 에러

    -> gateway를 통해 user-service 포워딩, health_check로 넘어가려 함

=> User Service의 URI와 API Gateway의 URI가 다르기 때문에 이러한 현상이 생긴다!

    -> User Service 에서는 @GetMapping 으로 `/health_check`를 받고, API Gateway에서는 `user-service/health_check` 값을 넘겨준다

    -> @GetMapping 값을 "/user-service/health_check"로 변경해주면 해결 완료


✨ Microservice - 사용자 조회

`@JsonInclude(JsonInclude.Include.NON_NULL)`

- null은 버리고 데이터 값이 있는 것만 전달하는 애노테이션

`@PathVariable("userId")`

- getUser로 userId 값을 받아 사용자를 조회한다고 했을 경우 그냥 String 값을 받아오게 되면 이름이 일치하지 않았을 경우 오류가 날 위험이 있다

- 이름이 다르다 할지라도 매개변수로 들어왔던 UserId 값을 원하는 변수명으로 지정이 가능하다

- 매개변수 앞에 달아줄 것

@PathVariable("userId") String userId)

 

- 참고 : 503 에러는 정상적으로 갱신이 안 될 경우 발생하는 에러이기 때문에 새로고침을 한 번 해주면 된다


✨ 데이터 직렬화

- Serializable 인터페이스 구현

// ex)
public class CatalogEntity implements Serializable { }

 

- 직렬화 (자바 기준 설명) : 자바 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트 형태로 데이터를 변환하는 매커니즘

- 내부에서 DTO 등을 사용하는 경우에는 필요하지 않을 수도 있겠지만 외부에서 사용할 수도 있기 때문에 강의에서는 DTO 클래스에 직렬화 작업을 해주었다


✨ DTO

- Data Transfer Object

- 계층 간 데이터 교환을 위해 사용하는 객체 (자바 빈)

- MVC 패턴에서 Controller는 View와 도메인 Model의 데이터를 주고 받을 때 별도의 DTO를 주로 사용한다


✨ data.sql

- 초기 기동과 동시에 data.sql 파일 안 데이터 자동 생성


✨ annotation

createAt

- h2 db에서 현재 날짜를 현재 시간에 갖고 오기 위한 함수 호출 방법

- createAt 함수에 현재 데이터가 들어온다

@Column(nullable = false, updatable = false, insertable = false) // 초기 인서트 X, 자동 생성
@ColumnDefault(value = "CURRENT_TIMESTAMP") // h2 DB에서 현재 날짜를 현재 시간에 갖고 오기 위한 함수를 호출하기 위한 방법
private Date createdAt;

@ Id

- @Id

- @GeneratedValue 달기

    -> (strategy = GenerationType.IDENTITY) // id 중복 값 허용 X

@ Column

- nullable = false

- length = 120

- unique = true


✨ Optional

- Optional을 쓰면 null 값을 효율적으로 처리할 수 있다

    -> null 값 허용

// ex
Optional<UserEntity> findByUserId(String userId);

 


✨ MVC 패턴

- Model + View + Controller : 프로젝트 구성 요소를 세 가지 역할로 나눴다

- 컴포넌트(=모듈) : 재사용이 가능한 각각의 독립된 모듈

1. Model

- 애플리케이션의 정보, 데이터들의 가공과 관련된 컴포넌트이다

- Model에서 UI에 직접 접근할 수 없다

    -> Model과 User 분리

2. View

- 사용자 인터페이스 요소

- 데이터의 입·출력을 담당한다

    ->데이터를 받으면 화면에 표시하는 등의 역할 수행

3. Controller

- 데이터, 사용자 인터페이스 간 `다리` 역할

    -> 데이터 관련 이벤트 처리를 담당한다


✨ `@Controller` vs `@RestController`

@Controller

- 주로 View를 반환하기 위해 사용

    -> Client의 요청으로부터 View 반환

- 데이터를 반환하는 경우 `@ResponseBody` 애노테이션을 활용하면 Controller에서 Json 형태로 데이터 반환이 가능하다

- 컨트롤러를 통해 객체를 반환할 때 일반적으로 `ResponseEntity`로 감싸서 반환한다

@Controller
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

    @GetMapping(value = "/users")
    public @ResponseBody ResponseEntity<User> findUser(@RequestParam("userName") String userName){
        return ResponseEntity.ok(userService.findUser(user));
    }
}

 

@RestController

@Controller
@RequiredArgsConstructor
public class UserController {

    private final UserService userService;

	@GetMapping(value = "/users")
    public User findUser(@RequestParam("userName") String userName){
        return userService.findUser(user);
    }

    @GetMapping(value = "/users")
    public ResponseEntity<User> findUserWithResponseEntity(@RequestParam("userName") String userName){
        return ResponseEntity.ok(userService.findUser(user));
    }
}

 

- User 객체 그대로 반환 -> 클라이언트가 예상하는 HttpStatus를 설정해줄 수 없다

- 객체를 상황에 맞는 ResponseEntity로 감싸서 반환해주는 것 (User 객체 반환 -> User을 ResponseEntity로 감싸기)

`@RequestParam`

- 파라미터 이름으로 바인딩

    -> HTTP 요청 파라미터를 @RequestParam으로 받는다

@PostMapping("/save")
public String save(@RequestParam("username") String username, @RequestParam("age") int age, Model model) {
    ...
}

 

@RequestMapping("/주소")

- 컨트롤러에서 기본적으로 받아야 할 이름 처리


✨ 질문

1. UserDto

- 왜 userDto가 반환값인가요?

// user-service -> userServiceImpl.java
public UserDto getUserByUserId(String userId) {
	...
	UserDto userDto = new ModelMapper().map(userEntity, UserDto.class);
}

 

- (헷갈려서 다시 적어보는) DTO : 계층 간 데이터 교환을 위해 사용하는 객체

1 - 답

DTO 사용 이유

1. 엔티티 내부 구현을 캡슐화 (UI 계층에 노출 X)

2. 화면에 필요한 데이터 선별 가능 (필요한 속성만 보여준다)

3. 순환참조 예방

    -> 엔티티 참조 객체의 지연 로딩, 로딩된 객체가 또 참조 객체를 호출하며 무한 루프에 빠지는 경우가 발생할 수 있다

2. setOrders 함수

userDto.setOrders(orders);

 

- userDto에 존재하지 않던데... (기본 제공 함수?)

- 내부적으로 setOrder() 처리?

https://www.inflearn.com/questions/381193/createorderitem-%EB%A9%94%EC%86%8C%EB%93%9C%EC%97%90%EC%84%9C-setorder%EB%A5%BC-%ED%95%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EC%9D%B4%EC%9C%A0%EA%B0%80-%EC%9E%88%EC%9D%84%EA%B9%8C%EC%9A%94

3. CrudRepository 찾아볼 것

 

 


✨ 참고 자료

 

 

https://ittrue.tistory.com/243

https://mangkyu.tistory.com/49

https://m.blog.naver.com/jhc9639/220967034588

https://wildeveloperetrain.tistory.com/49

https://velog.io/@modsiw/Spring-DTO%EB%9E%80