Skip to content

Commit

Permalink
feat : 접속 시 연속 접속 확인 쓰레드 처리
Browse files Browse the repository at this point in the history
  • Loading branch information
imenuuu committed Oct 26, 2023
1 parent 9062457 commit 4b05385
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ public CommonResponse<String> logOut(@Parameter(hidden = true) @AuthenticationPr
}

@Operation(summary = "01-08 User👤 토큰 재발급 Made By Austin", description = "액세스 토큰 만료시 재발급 요청 하는 API X-REFRESH-TOKEN 을 헤더에 담아서 보내주세요, accessToken 은 보내지 않습니다.")
@ResponseBody
@PostMapping("/refresh")
public CommonResponse<UserResponse.ReIssueToken> reIssueToken(
@Parameter(description = "리프레쉬 토큰", required = true, in = ParameterIn.HEADER, name = "X-REFRESH-TOKEN", schema = @Schema(type = "string")) @RequestHeader("X-REFRESH-TOKEN") String refreshToken
Expand All @@ -129,7 +128,17 @@ public CommonResponse<UserResponse.ReIssueToken> reIssueToken(
UserResponse.ReIssueToken tokenRes=new UserResponse.ReIssueToken(jwtService.createToken(userId));

return CommonResponse.onSuccess(tokenRes);
}


@Operation(summary = "01-09 User👤 유저 스플레쉬 화면 단 호출 부탁합니다.", description = "유저 뱃지 발급을 위한 접속 API 입니다. 토큰만 들고오면 됩니다.")
@ApiErrorCodeExample(UserAuthErrorCode.class)
@GetMapping("/connections")
public CommonResponse<String> connectionUser(
@AuthenticationPrincipal User user
){
userService.connectionUser(user);
return CommonResponse.onSuccess("확인 되었습니다.");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ public interface UserService {
VerifyMessageStatus findVerifyMessageStatusByUser(User user);

User getCurrentLoggedInUser();

void connectionUser(User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.wineyapi.user.converter.UserConverter;
import com.example.wineyapi.user.dto.UserRequest;
import com.example.wineyapi.wineBadge.service.WineBadgeService;
import com.example.wineycommon.exception.MessageException;
import com.example.wineycommon.exception.NotFoundException;
import com.example.wineycommon.exception.UserException;
Expand All @@ -10,6 +11,7 @@
import com.example.wineycommon.properties.KakaoProperties;
import com.example.wineydomain.badge.entity.UserWineBadge;
import com.example.wineydomain.badge.repository.UserWineBadgeRepository;
import com.example.wineydomain.badge.repository.WineBadgeRepository;
import com.example.wineydomain.common.model.Status;
import com.example.wineydomain.common.model.VerifyMessageStatus;
import com.example.wineydomain.tastingNote.repository.TastingNoteRepository;
Expand Down Expand Up @@ -61,6 +63,7 @@ public class UserServiceImpl implements UserService {
private final UserWineBadgeRepository userWineBadgeRepository;
private final TastingNoteRepository tastingNoteRepository;
private final RecommendWineRepository recommendWineRepository;
private final WineBadgeService wineBadgeService;

private DefaultMessageService coolSmsService;
private final AppleOAuthUserProvider appleOAuthUserProvider;
Expand Down Expand Up @@ -275,4 +278,9 @@ public User getCurrentLoggedInUser() {

return (User) authentication.getPrincipal();
}

@Override
public void connectionUser(User user) {
wineBadgeService.checkActivityBadge(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ public interface WineBadgeService {
void calculateBadge(User user, Long userId);

void provideFirstAnalysis(User user);

void checkActivityBadge(User user);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.wineyapi.wineBadge.service;

import com.example.wineyapi.user.converter.UserConverter;
import com.example.wineyapi.wineBadge.convertor.WineBadgeConvertor;
import com.example.wineycommon.annotation.RedissonLock;
import com.example.wineydomain.badge.entity.Badge;
Expand All @@ -8,13 +9,17 @@
import com.example.wineydomain.tastingNote.entity.TastingNote;
import com.example.wineydomain.tastingNote.repository.TastingNoteRepository;
import com.example.wineydomain.user.entity.User;
import com.example.wineydomain.user.entity.UserConnection;
import com.example.wineydomain.user.repository.UserConnectionRepository;
import com.example.wineydomain.user.repository.UserRepository;
import com.example.wineydomain.wine.entity.Wine;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

Expand All @@ -28,6 +33,7 @@ public class WineBadgeServiceImpl implements WineBadgeService {
private final TastingNoteRepository tastingNoteRepository;
private final WineBadgeConvertor wineBadgeConvertor;
private final UserRepository userRepository;
private final UserConnectionRepository userConnectionRepository;

@RedissonLock(LockName = "뱃지-계산", key = "#userId")
@Async("badge")
Expand Down Expand Up @@ -63,6 +69,66 @@ public void provideFirstAnalysis(User user) {

}

@Override
@Async("connect_user")
@RedissonLock(LockName = "유저 연속 접속 확인", key = "#user.id")
public void checkActivityBadge(User user) {
UserConnection userConnection = user.getUserConnection();
if(userConnection == null){
userConnectionRepository.save(UserConnection.builder().user(user).cnt(1).build());
}else{
checkContinueConnection(user, userConnection);
}
}

private void checkContinueConnection(User user, UserConnection userConnection) {
boolean isConnectedToday = checkNowDate(userConnection.getUpdatedAt());
boolean isConnectedYesterday = checkOneDayBefore(userConnection.getUpdatedAt());

if(isConnectedToday){
return; // 오늘 이미 접속한 기록이 있으므로 함수 종료
}
if(isConnectedYesterday){
userConnection.setCnt(userConnection.getCnt() + 1);
userConnectionRepository.save(userConnection);
checkUserConnectionBadge(userConnection, user);
} else {
userConnectionRepository.deleteByUser(user);
}
}



private boolean checkNowDate(LocalDateTime updatedAt) {
LocalDate nowDate = LocalDateTime.now().toLocalDate();
LocalDate targetDate = updatedAt.toLocalDate();

System.out.println("checkNowDate : " + nowDate.isEqual(targetDate));
return nowDate.isEqual(targetDate);
}

private boolean checkOneDayBefore(LocalDateTime updatedAt) {
LocalDate nowDate = LocalDateTime.now().toLocalDate();
LocalDate targetDate = updatedAt.toLocalDate();

return targetDate.isEqual(nowDate.minusDays(1));
}

private void checkUserConnectionBadge(UserConnection userConnection, User user) {
List<Badge> badges = userWineBadgeRepository.findByUser(user).stream()
.map(UserWineBadge::getBadge)
.collect(Collectors.toList());

if(userConnection.getCnt() == 7){
if(!badges.contains(WINE_EXCITEMENT)) userWineBadgeRepository.save(wineBadgeConvertor.WineBadge(WINE_EXCITEMENT, user));
}
if(userConnection.getCnt() == 30){
if(!badges.contains(WINE_ADDICT)) userWineBadgeRepository.save(wineBadgeConvertor.WineBadge(WINE_ADDICT, user));
}
}



public List<UserWineBadge> checkSommelierBadge(List<Badge> badges, List<TastingNote> tastingNotes, User user) {
List<UserWineBadge> userWineBadges = new ArrayList<>();
int cnt = tastingNotes.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,15 @@ public Executor badgeFirstAnalysisThreadExecutor() {
executor.initialize();
return executor;
}

@Bean(name = "connect_user")
public Executor connectUserCheckThreadExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); // 기본적으로 실행 대기 중인 Thread 개수
executor.setMaxPoolSize(10); // 동시에 동작하는 최대 Thread 개수
executor.setQueueCapacity(500); // CorePool이 초과될때 Queue에 저장했다가 꺼내서 실행된다. (500개까지 저장함)
executor.setThreadNamePrefix("connect-user-badge-thread"); // Spring에서 생성하는 Thread 이름의 접두사
executor.initialize();
return executor;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ public class QUser extends EntityPathBase<User> {

public final EnumPath<com.example.wineydomain.common.model.Status> status = createEnum("status", com.example.wineydomain.common.model.Status.class);

public final BooleanPath tasteNoteAnalysis = createBoolean("tasteNoteAnalysis");

//inherited
public final DateTimePath<java.time.LocalDateTime> updatedAt = _super.updatedAt;

public final QUserConnection userConnection;

public final StringPath username = createString("username");

public QUser(String variable) {
Expand All @@ -73,6 +77,7 @@ public QUser(PathMetadata metadata, PathInits inits) {
public QUser(Class<? extends User> type, PathMetadata metadata, PathInits inits) {
super(type, metadata, inits);
this.preference = inits.isInitialized("preference") ? new com.example.wineydomain.preference.entity.QPreference(forProperty("preference"), inits.get("preference")) : null;
this.userConnection = inits.isInitialized("userConnection") ? new QUserConnection(forProperty("userConnection"), inits.get("userConnection")) : null;
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ public class User extends BaseEntity implements UserDetails {

private boolean tasteNoteAnalysis = false;

@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private UserConnection userConnection;

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.wineydomain.user.entity;

import com.example.wineydomain.common.model.BaseEntity;
import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

@Entity
@Table(name = "`UserConnection`")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@DynamicUpdate
@DynamicInsert

public class UserConnection extends BaseEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", nullable = false)
private User user;

private int cnt = 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.wineydomain.user.repository;

import com.example.wineydomain.user.entity.User;
import com.example.wineydomain.user.entity.UserConnection;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserConnectionRepository extends JpaRepository<UserConnection, Long> {
void deleteByUser(User user);
}

0 comments on commit 4b05385

Please sign in to comment.