2023.09.08.금.TIL

heeh·2023년 9월 11일

TIL

목록 보기
82/82
post-thumbnail

2023.09.08.금.TIL

  • 할 것
    • 알람(레디스, 소켓), 채팅(소켓) 기능 더 알아보기 및 착수
    • 오후 시간에 기능 합치기 & 회의
    • 밀린 기술 문제, CS 확인하기

회원 탈퇴 기능 풀리퀘스트

https://github.com/lazygyu97/seoulmate/pull/53

변경 사항

회원 탈퇴 신청 시 바로 회원 탈퇴(해당 user의 정보 삭제)가 되는 것이 아닌 회원 탈퇴 신청을 한 user를 withdrawalRepository에 담아주고 withdrawals table에서 확인할 수 있게 만들었습니다.

회원 탈퇴의 유예 기간은 7일이며 public void cleanupExpiredWithdrawals()의 LocalDateTime standardTime = LocalDateTime.now().minusDays(7); 에서 설정해주었습니다.

withdrawals table의 expire_time에서 삭제가 완료될 날짜와 시간을 보여주는데 이 부분은 UserService의 public ResponseEntity withdrawUser(User user)에서 LocalDateTime expireTime = LocalDateTime.now().plusDays(7); 부분입니다.

LocalDateTime standardTime = LocalDateTime.now().minusDays(7); 와 LocalDateTime expireTime = LocalDateTime.now().plusDays(7);의 날짜, 시간을 갖게 해주어야 withdrawals table의 expire_time에서 알맞은 회원 탈퇴 시간 확인이 가능합니다.

회원이 탈퇴 신청을 하고 갖는 유예 기간은 7일로 설정했습니다.

그 7일 안에 회원이 DENY 역할을 갖고 어떤 행동을 할 수 있는지에 대한 설정과 회원 탈퇴 신청을 취소하는 기능은 JwtAuthenticationFilter와 관련 있어서 팀장님이 확인해주신다고 하셨습니다.

public class WithdrawalScheduler에서 @scheduled(cron = "0 30 7,15,23 * * *")를 이용하여 스케줄러가 매일 7시 30분/15시 30분/23시 30분에 작동하게 설정하고 회원 탈퇴 유예 기간이 만료된 정보들을 검사하고 탈퇴 처리를 합니다.

ex) 10일 13시에 탈퇴한 회원 A -> 17일 15시 30분에 작동하는 스케줄러가 회원 탈퇴 처리

ex) 11일 15시 32분에 탈퇴한 회원 B -> 18일 23시 30분에 작동하는 스케줄러가 회원 탈퇴 처리

ex) 11일 23시 57분에 탈퇴한 회원 C -> 19일 7시 30분에 작동하는 스케줄러가 회원 탈퇴 처리

완성된 기능 확인

탈퇴 유예 기간은 7일이며, 2023-09-07 19:33에 탈퇴 신청을 한 user_id 17번의 user의 정보가 withdrawals table에서 확인됩니다.

!https://user-images.githubusercontent.com/132984807/266297158-e2447bef-76cb-44ae-a146-10daccec5cb4.png

expire_time에 보이는 것과 같이 2023-09-14 19:33에 탈퇴 완료 예정이며 23시 30분에 작동하는 스케줄러로 인해 회원 탈퇴(회원 정보 삭제)가 이루어집니다. 예정된 탈퇴 시간과 차이가 있으며 약 5~6시간이 더 걸릴 것으로 예상됩니다.

만료 기간이 다 된 정보를 스케줄러가 감지하여 withdrawals table에서 해당 데이터를 삭제하고 삭제된 데이터의 같은 user_id를 갖고 있는 회원 정보(컬럼)를 users table에서 삭제해서 회원 탈퇴가 이루어지게 됩니다.

Todo List

Check List

  • 포스트맨으로 체크해 보았나요?
  • 테스트 코드를 작성하셨나요?

트러블 슈팅

  • 처음에 Redis를 사용하여 다양하고 많은 오류가 있고 헤맸습니다...
    • Redis를 사용할 때의 오류
      1. 오류…

        java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.sparta.seoulmate.entity.redishash.Withdrawal]
      • com.sparta.seoulmate.entity.redishash.Withdrawal 클래스가 직렬화 가능한(Serializable) 형태로 구현되어 있지 않아서 발생
      • Redis는 데이터를 저장할 때 기본적으로 직렬화된 형태로 저장
      • Withdrawal 클래스는 이러한 직렬화를 지원하지 않고 있다!
      • 해결하기…
        • 클래스 내부에서 사용하는 모든 멤버 변수 또한 직렬화 가능해야 하기 때문에 해당 변수도 Serializable 인터페이스를 구현
          import java.io.Serializable;
          public class Withdrawal implements Serializable
      1. 타임투리브(만료시간만!) 이벤트 발생을 위해 → 퍼블리시, 섭스크립 매커니즘 사용해야함..
      • 오류
        Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
        2023-09-05T20:15:56.183+09:00 ERROR 18676 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :
        
        ***************************
        APPLICATION FAILED TO START
        ***************************
        
        Description:
        
        Parameter 11 of constructor in com.sparta.seoulmate.service.UserService required a bean of type 'org.springframework.data.redis.core.RedisTemplate' that could not be found.
        
        Action:
        
        Consider defining a bean of type 'org.springframework.data.redis.core.RedisTemplate' in your configuration.
        
        Process finished with exit code 1
      • 해결
        • UserService
          private final RedisTemplate<String, String> redisTemplate;
        • RedisMessagePublisher
          private final RedisTemplate<String, String> redisTemplate;
        • RedisMessageSubscriber
            ```java
            private final UserService userService;
            ```
          
        • RedisPubSubApplication
            ```java
            private final RedisMessagePublisher redisMessagePublisher;
            ```
          
  • Redis 사용으로 기능을 완성시켜 보려고 했으나 Reids에 담아야 하는 정보는 일회성이 강한 정보만 담는 것이 맞고 탈퇴한 회원의 정보같이 중요한 데이터는 담기에 부적절하다는 피드백을 받아서 public class WithdrawalScheduler을 생성하고 스케줄러를 사용하였습니다.
  • withdrawals table의 저장되는 컬럼의 user_id에 null값이 찍힘
    Withdrawal withdrawal = Withdrawal.builder()
                    .id(targetUser.getId())
                    .requestTime(now)
                    .scheduledDeletionTime(scheduledDeletionTime)
                    .status(WithdrawalStatusEnum.PENDING) // 탈퇴 상태를 대기 중으로 설정
                    .build();
    • .id(targetUser.getId())를 .user(targetUser) // 사용자 엔티티를 설정으로 수정
      LocalDateTime now = LocalDateTime.now();
              LocalDateTime scheduledDeletionTime = now.plusMinutes(1);
              Withdrawal withdrawal = Withdrawal.builder()
                      .user(targetUser) // 사용자 엔티티를 설정
                      .requestTime(now)
                      .scheduledDeletionTime(scheduledDeletionTime)
                      .status(WithdrawalStatusEnum.PENDING)
                      .build();

Issue Tracker

이슈 번호 Reseolves: #39

채팅

  • 참고

  • gradle에 websocket 임포트

  • import lombok.Data; 즉, @Data 어노테이션을 쓰면 @Getter 역할이 채워진다?!

  • ec2가 뭥미? → 아마존웹서비스(WAS)에서 제공해주는 서비스(서버)

  • 크롬 확장 프로그램인 talend api tster와 socket test client 를 사용해서 채팅 방만들기

    • Chrome 웹 스토어
      • Talend API Tester - Free Edition
      • Web Socket Client → 내가 쓴 라이브러리 기능은 Web Socket이니까 이것으로 테스트!
      • Socket.IO Test Client → Socket.IO 라이브러리 기능을 사용했으면 이것으로 테스트!
    • Talend API Tester 확장프로그램으로 API 입력창에 https://localhost:8080/chat?name=채팅방명 를 삽입
    • 채팅방을 만드는 것 자체는 Talend API Tester가 아닌 Postman으로 하고!
    • uuid
      • 참고
      • UUID란? UUID(Universally Unique IDentifier)는 네트워크상에서 고유성을 보장하는 ID를 만들기 위한 표준 규약
    • ChatServiceImpl(Class)과 ChatService(interface) 를 합치는 과정에서 @Override 삭제하기 @Override 어노테이션은 자바에서 메소드를 오버라이드(재정의)할 때 사용하는 어노테이션입니다. @Override 어노테이션을 사용하여 해당 메소드가 슈퍼클래스나 인터페이스에서 상속된 메소드를 오버라이드하고 있음을 명시적으로 나타냅니다. 그러나 위의 코드에서는 클래스 정의에 @Override 어노테이션을 사용하고 있지 않습니다. 따라서 @Override 어노테이션을 삭제해도 상관 없습니다. 이 어노테이션은 필수적으로 사용할 필요는 없으며, 클래스가 인터페이스의 메소드를 구현하거나 슈퍼클래스의 메소드를 오버라이드할 때만 사용됩니다. 현재 코드에서는 인터페이스를 구현하는 것이 아니며, @Override 어노테이션을 사용하지 않아도 됩니다. 따라서 @Override 어노테이션을 삭제해도 코드에는 영향을 주지 않습니다. 코드의 가독성을 높이기 위해 어노테이션을 사용하는 것이 좋을 수 있지만, 삭제하더라도 기능적인 측면에서는 문제가 없습니다.
  • 파라미터 안에서 Ctrl+P 하면 파라미터 안에 뭐가 들어가는지 종류를 볼 수 있다

  • @RequestParam에는 대문자가 들어갈 수 없다

    • uuid는 랜덤으로 생기는 String이기 때문에 상관없다

    • 대문자를 권장하지 않는 이유?
      - 약속…

      public ChatRoomDto createRoom(@RequestParam(name = "room-name") String roomName, @AuthenticationPrincipal UserDetailsImpl userDetails) {
              return chatService.createRoom(roomName, userDetails.getUser());
          }
    • (@RequestParam(name = "room-name")을 해주면 api에서 room-name로 표시될 수 있다

    • String roomName은 해당 값을 넣어주는 것이고

    • api 입력은 (@RequestParam(name = "room-name")의 room-name로 적어주어 사용한다

  • RoomId를 가지고 WebSocketTesting(WebSocketClient)으로 test…!

  • 튜터님 추천

  • WebSocketTesting 참고

  • 지금까지 참고 했던 블로그에서 썼던 WebSocketTest 확장 프로그램은 Web Socket Client이 아닌 Simple WebSocket Client였다!!!!!!!!

    • Web Socket Client
    • Simple WebSocket Client
    • 설명 WebSocket 테스트를 위해서 크롬 확장 프로그램 중 하나인 "Simple WebSocket Client"를 사용할 수 있습니다. 이 확장 프로그램은 WebSocket 연결을 간편하게 테스트하고 디버깅할 수 있는 도구로 사용자 친화적인 인터페이스를 제공합니다. 다른 대안으로는 웹 브라우저의 개발자 도구를 활용하여 WebSocket 연결을 테스트할 수도 있습니다. 대부분의 최신 브라우저에서 WebSocket 연결을 지원하며, 브라우저 개발자 도구를 통해 WebSocket 프로토콜을 모니터링하고 메시지를 보내고 받을 수 있습니다. 크롬 확장 프로그램인 "Simple WebSocket Client"를 사용하면 더 편리하게 WebSocket 연결을 관리하고 테스트할 수 있습니다. 이 확장 프로그램을 사용하면 WebSocket 서버와의 통신을 시뮬레이션하고 다양한 메시지를 보내고 받을 수 있습니다.
  • 연결이 안되는 문제

    • WebSecurityConfig 퍼밋 올
      • .requestMatchers("/ws/**").permitAll() // ws에서 접속하는 websocket 권한 허용
  • ChatService의 no usages 정리

    public List<ChatRoomDto> findRooms() {
            return new ArrayList<>(chatRooms.values());
        }
    public ChatRoomDto selectRoomById(String roomId) {
            ChatRoom room = chatRoomRepository.findByUuid(roomId)
                    .orElseThrow(() -> new IllegalArgumentException("해당 채팅방이 존재하지 않습니다."));
            return ChatRoomDto.builder()
                    .roomId(room.getUuid())
                    .roomName(room.getRoomName())
                    .build();
        }
  • ChatController 변경

    • 생성
      • // 채팅방 생성
            @PostMapping("/chats")
            public ChatRoomDto createChatRoom(@RequestParam(name = "room-name") String roomName, @AuthenticationPrincipal UserDetailsImpl userDetails) {
                return chatService.createChatRoom(roomName, userDetails.getUser());
            }
      • // 채팅방 생성
            @PostMapping("/chats")
            public ResponseEntity<ChatRoomDto> createChatRoom(@RequestParam(name = "room-name") String roomName, @AuthenticationPrincipal UserDetailsImpl userDetails) {
                ChatRoomDto chatRoomDto = chatService.createChatRoom(roomName, userDetails.getUser());
                return ResponseEntity.ok().body(chatRoomDto);
            }

소켓 채팅 테스트 정리

→ 코드 리팩토링 문제인지 내가 모르거나 빠뜨린 무엇이 있는 건지 OPENED까지는 되지만 Message Log에서 수행되지 않음

profile
공부하자개발하자으쌰으쌰

0개의 댓글