MSA 7일차 : 스프링 클라우드 - 비지니스 로직, remote 실습

parang·2025년 6월 5일

LG CNS AM Inspire Camp 2기

목록 보기
39/50
post-thumbnail
이제 글쓰기 작성을 위한 post 프로젝트를 생성할 것이다. 
현재 스프링 클라우드에 대한 내용을 실습하고 있지만
서비스 로직 작성하는 부분이 대부분이기에
조금 더 흐름을 익히고 정리하기 위한 포스트가 될 것 같다. 

프로젝트 환경 설정

프로젝트 생성

https://start.spring.io/

언어들을 학습하고 실습하면서 가장 기본이 되는 것은 프로젝트 생성이다. 언제 어디서든 뚝딱! 프로젝트를 만드는게 가장 쉽지만 어려운 부분이라 생각한다.

의존성 추가

  1. spring Web
  2. Cloud LoadBalancer
  3. Eureka Discovery Client
  4. OpenFeign
  5. Spring Data JPA
  6. MySQL Driver
  7. Lombok
  8. Validation

환경 세팅

  1. sdk 확인
  2. yml 파일 분리
  3. active profiles 지정

local yml 파일에는 그 전과 같이 서버, 데이터소스, jpa, 유레카 내용이 포함된다.

필수 애노테이션 추가

@EnableDiscoveryClient 
@EnableFeignClients

유레카 서버와 openFeign과 관련된 애노테이션을 꼭 추가해주어야 한다.

서비스 로직

post 프로젝트의 주 기능은 글쓰기 기능, 댓글 기능이다.

작성할 로직은 크게 다음과 같다.
헤더유틸, 엔티티, 레파지토리, dto, 서비스, 컨트롤러.

게이트웨이 요청 헤더 유틸(GatewayRequestHeaderUtils)

제일 먼저 작성할 코드는 제목과 같다. 이 클래스에서 게이트웨이에서 넘어온 헤더 정보를 꺼내는 역할을 하게된다. 보통, 사용자 정보를 읽어온다.

X-Auth-UserId
X-Auth-Client-Device
X-Auth-Client-Address

값을 뽑아 오는 함수들과 예외로 구성되어 있다. 순서대로

getUserId()
getClientDevice()
getClientAddress() 메서드가 있고, 각 ThrowException()로 감싸져 있다.

따라서 다른 클래스에서 이 클래스를 사용할 때, GatewayRequestHeaderUtils.getUserIdOrThrowException() 이렇게 사용하게 된다.

Entity

연관 관계

포스팅, 댓글 엔티티를 작성할 것이고 포스팅 하나에 댓글이 여러개 달릴 수 있으므로 1 : N의 관계이다. 그러므로 댓글 엔티티 쪽에 ManyToOne 애노테이션이 들어가고 포스팅 쪽에도 댓글을 사용하므로 OneToMany 애노테이션을 달아 둔다.

  public void addComment(PostComment comment) {
        comment.setPost(this);
        this.comments.add(comment);
  }

setPost와 댓글 엔티티 쪽에 @Setter
private Post post; 연결 된다.

Dto

포스팅, 댓글 생성 dto.
주의할 사항은 파라미터 userId 같은 정보를 직접적으로 가져오면 보안적으로 치명적인 문제 가 된다.
엔티티를 만드는 것이 목표! -> post, comment 리턴.

대표로 post dto만 자세히 살펴보자.

@Getter
@Setter
public class PostCreateDto {
    @NotBlank(message = "타이틀을 입력하세요.")
    private String title;

    @NotBlank(message = "본문을 입력하세요.")
    private String content;

    public Post toEntity() {
        Post post = new Post();
        post.setUserId(GatewayRequestHeaderUtils.getUserIdOrThrowException());
        post.setPost(this.title, this.content);

        return post;
    }
}

✅ entity에서 title, content가 
nullable = false 옵션이 있기 때문에 @NotBlank를 사용했다.

✅ toEntity()

Dto로 요청을 받고 entity로 변환하는 역할을 하는 메서드이다.
이 메서드를 사용함으로써 DTO와 Entity의 책임 분리, 코드의 일관성, 유지보수, 보안 등의 장점을 얻을 수 있다.

Service(⭐⭐)

서비스에서 구현할 가능은 포스팅 생성, 댓글 추가이다. 트랜잭션 안에서 save 하도록 한다.

postCommentRepository.save(postComment); -> 새로운 댓글이 생성된 상태

post.addComment(postComment); -> addComment를 해서 setPost를 통해 댓글과 포스트 사이에 연관 관계가 맺어지고 (화살표 같이) comment.add를 함으로써 post 안에 댓글이 최종 추가된다.

@Transactional
public void createPost(PostCreateDte create Dto) {
	Post post = createDto.toEntity();
    
    postRepository.save(post)
    
    -> db에 저장

gateway 라우팅 추가

          - id: backend-post
            uri: lb://backend-post
            predicates: # 라우팅 조건
              - Path=/api/post/**
            filters:
              - AddAuthenticationHeader

포스팅, 댓글 api 확인 결과

먼저 회원 등록, 로그인을 한 후 발행되는 토큰을 Bearer Token에 넣고, 바디를 넣은 후 post요청을 보내면 아래 사진 처럼 db에 잘 등록이 됨을 알 수 있다.

알림 메시지 전송

이제, 포스트 댓글이 달리면 알림 메시지 로그 전송하는 것을 구현할 것이다. 이번엔 아날로그로 구현하고 다음 포스트에는 kafka를 이용할 것 같다.

유저의 핸드폰 번호로 전송한다는 컨셉이므로, post 프로젝트에 userInfoDto를 먼저 작성한다.


@Getter
@Setter
public class SiteUserInfoDto {
    private String userId;
    private String phoneNumber;
}

유저 프로젝트 컨트롤러


@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "backend/user/v1", produces = MediaType.APPLICATION_JSON_VALUE)
public class BackendUserController {

    private final SiteUserService siteUserService;

    @GetMapping(value = "/user/{userId}")
    public ApiResponseDto<SiteUserInfoDto> userInfo(@PathVariable String userId) {
        SiteUserInfoDto userInfoDto = siteUserService.userInfo(userId);

        return ApiResponseDto.createOk(userInfoDto);
    }

}

post 프로젝트 유저 서비스

@FeignClient(name = "backend-user", path = "backend/user/v1")
public interface RemoteUserService {
    @GetMapping(value = "/user/{userId}")
    public ApiResponseDto<SiteUserInfoDto> userInfo(@PathVariable String userId);
}

-> openFeign을 이용하여 RestTemplate 없이 유저 서비스의 api를 호출할 수 있게 해준다.

이 후에는 알림을 받을 dto, 알림 서비스(전송 api)를 작성한다.
마찬가지로 openFeign을 이용해 알림 서비스의 api를 사용한다.

결론

[댓글 작성 요청] →
[PostService] →
① PostRepository에서 게시글 조회 →
② PostCommentRepository에 댓글 저장 →
③ RemoteUserService 통해 작성자 정보 조회 →
④ RemoteAlimService 통해 SMS 전송

최종적으로 알림서비스 로그에 sms 알림 문구가 찍히게 된다.

profile
파랑입니다.

0개의 댓글