[Spring] 유저 등급 자동 갱신

강민승·2023년 8월 18일
0

spring

목록 보기
8/17

간단한 등급 자동 갱신

Entity

여기서는 @Builder를 사용했고 최소set을 사용했다.

Entity를 만들 때는 외부에서 쉽게 변경할 수 없게 @Setter를 사용하지않는다. 그 이유는 @Setter를 사용하면 의도가 불명확하고 변경하면 안되는 중요한 값임에도 불구하고 변경 가능한 값으로 착각할 수 있다. (== 안정성 보장이 안된다.)

package com.ssafy.crit.auth.entity;

import com.ssafy.crit.auth.entity.enumType.AuthProvider;
import com.ssafy.crit.auth.entity.enumType.Grade;
import com.ssafy.crit.auth.entity.enumType.Role;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.ColumnDefault;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import javax.persistence.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor
@Table(name = "users")
public class User extends BaseTimeEntity {
    @Id
    @Column(name = "user_id")
    private String id;

    @Column(nullable = false)
    private String nickname;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false)
    private String email;

    @Column
    private String profileImageUrl;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private Role role;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private AuthProvider authProvider;

    @Column(length = 300)
    private String refreshToken;

    private Date tokenExpirationTime;

    private String tid;

    private int exp;

    @Enumerated(EnumType.STRING)
    private Grade grade;

    @Column
    private Boolean isChecked;

    @OneToMany(mappedBy = "follower")
    private List<Follow> followers = new ArrayList<>();

    @OneToMany(mappedBy = "following")
    private List<Follow> followings = new ArrayList<>();

    @ColumnDefault("0")
    private int cashPoint;

    @Builder
    public User(String id, String nickname, String password, String email, String profileImageUrl,
        Role role, AuthProvider authProvider, String refreshToken, Date tokenExpirationTime, String tid, int exp,
        Grade grade, Boolean isChecked, List<Follow> followers, List<Follow> followings, int cashPoint ) {
        this.id = id;
        this.nickname = nickname;
        this.password = password;
        this.email = email;
        this.profileImageUrl = profileImageUrl;
        this.role = role;
        this.authProvider = authProvider;
        this.refreshToken = refreshToken;
        this.tokenExpirationTime = tokenExpirationTime;
        this.tid = tid;
        this.exp = exp;
        this.grade = grade;
        this.isChecked = false;
        this.followers = followers;
        this.followings = followings;
        this.cashPoint = cashPoint;
    }


public void setGrade(int exp){
        this.grade = Grade.getGradeByExp(exp);
}

public void loginExp(int exp, boolean isChecked){
    this.exp = exp + 10;
    this.isChecked = true;
}

User Grade enum

여기서는 Grade를 어떻게 나누고 로직을 통해 Grade를 설정할 지 정하는 부분을 enum파일에 작성하였다.

package com.ssafy.crit.auth.entity.enumType;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum Grade {
	Beginner(0, "초보자"),
	IntermediateLow(100, "하급 챌린저"),
	IntermediateMiddle(300,"중급 챌린저"),
	IntermediateHigh(500, "상급 챌린저"),
	Challenger(1000, "그랜드 챌린저"),
	Administrator(Integer.MAX_VALUE, "관리자");

	private final int key;
	private final String title;

	public static Grade getGradeByExp(int exp) {
		Grade[] grades = Grade.values();
		Grade result = Grade.Beginner;

		for (Grade grade : grades) {
			if (exp >= grade.getKey()) {
				result = grade;
			} else {
				break;
			}
		}
		return result;
	}


}

Service

현재 로그인 로직만 가져왔다. 하루에 첫 로그인일 경우 login Exp를 올리고 증가한 Exp를 통해 승급 가능할 경우 승급된 등급을 보여주도록 한다.

public LogInResponseDto logIn(LogInRequestDto logInRequestDto) throws Exception {

		BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
		if (!userRepository.existsById(logInRequestDto.getId())) {
			throw new BadRequestException(ErrorCode.NOT_EXISTS_USER_ID);
		}
		User user = userRepository.findById(logInRequestDto.getId()).get();
		if (!bCryptPasswordEncoder.matches(logInRequestDto.getPassword(), user.getPassword())) {
			throw new BadRequestException(ErrorCode.NOT_EXISTS_USER_PASSWORD);
		}

		// exp 올리고 Grade 판단 로직
		if (!user.getIsChecked()) {
			user.loginExp(user.getExp(), false);
			user.setGrade(user.getExp());
		}

		// 토큰 발급
		TokenDto accessTokenDto = jwtProvider.createAccessToken(logInRequestDto.getId(), user.getAuthProvider());
		TokenDto refreshTokenDto = jwtProvider.createRefreshToken(logInRequestDto.getId(), user.getAuthProvider());

		user.updateRefreshToken(refreshTokenDto.getToken(), refreshTokenDto.getTokenExpirationTime());

		return LogInResponseDto.builder()
			.id(user.getId())
			.nickname(user.getNickname())
			.email(user.getEmail())
			.accessToken(accessTokenDto.getToken())
			.refreshToken(refreshTokenDto.getToken())
			.refreshTokenExpirationTime(refreshTokenDto.getTokenExpirationTime())
			.exp(user.getExp())
			.grade(user.getGrade())
			.cashPoint(user.getCashPoint())
			.imageUrl(user.getProfileImageUrl())
			.build();
	}

Grade 자동 설정에는 controller 단에서는 따로 필요가 없기 때문에 Entity, enum, service 단에서만 로직을 작성하면 된다.

이걸 생각하면서

profile
Step by Step goes a long way. 꾸준하게 성장하는 개발자 강민승입니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 18일

좋은 글 감사합니다.

답글 달기