public LottoResponseDto getLotto(User user) throws NoSuchAlgorithmException {
Long lottoPrice = 200L;
Lotto lotto = lottoRepository.findByUser(user);
if(user.getTotalPoint()>=lottoPrice) {
user.setTotalPoint(user.getTotalPoint()-lottoPrice);
userRepository.save(user);
Point point = new Point("로또 참여", -lottoPrice, user.getTotalPoint(), user);
pointRepository.save(point);
Random random = SecureRandom.getInstanceStrong();
int num;
if(lotto.getCount()>=5) {num = random.nextInt(3630);}
else {num = random.nextInt(10000);}
String content = "";
if (1 <= num && num < 30) {//0.3프로
content = "경 * 축 1등 당첨!!😄😄😄 세상에 이런일이.... 운이 엄청 좋으시군요...!! ";
lottoPoint1(user);
lotto.setCount(0L);
lottoRepository.save(lotto);
}else if(30<= num && num < 130){ //1프로
content = "경 * 축 2등 당첨!!😁😁😁 2등도 잘한거야!!!!";
lottoPoint2(user);
lotto.setCount(0L);
lottoRepository.save(lotto);
} else if (130 <= num && num < 630) { // 5프로
content = "경 * 축 3등 당첨!!😃😃😃 3등도 엄청난거지 ^^ 메달도 3등까지라구~";
lottoPoint3(user);
lotto.setCount(0L);
lottoRepository.save(lotto);
} else if (630 <= num && num < 1630) { //10프로
content = "축! 4등 당첨!!😎😎😎";
lottoPoint4(user);
lotto.setCount(0L);
lottoRepository.save(lotto);
} else if (1630 <= num && num < 3630) { //20프로
content = "5등 당첨!!😙😙😙";
lottoPoint5(user);
lotto.setCount(0L);
lottoRepository.save(lotto);
} else { //63.7프로
content = "아쉽게도 꽝입니다 😥😥😥😥 한번만 더 뽑으면 1등 당첨될수도...?";
lottoPoint6(user);
lotto.setCount(lotto.getCount()+1);
lottoRepository.save(lotto);
}
return new LottoResponseDto(content, lotto.getCount());
}else throw new LackPointException("보유한 포인트가 부족합니다");
}
우선 유저가 로또에 참가할수있는 포인트가 있는지 먼저 검사한다. 그 후 천장시스템을 사용하기 위해
로또라는 테이블을 만들어 count라는 컬럼을 만들고 유저와 OneToOne연관관계를 맺었다.
랜덤수를 생성할때 SecureRandom을 사용하는 것이 보안상 안전하다고 한다
Math.Random같은 경우 컴퓨터의 시간을 시드로 사용하여 난수가 생성되어서 동시간에 유저가 지속적으로 같은 작업을 반복하면 유저의 난수가 동일하게 나올 수 있다.
반면 SecureRandom은 그보다 더 복잡한 로직을 사용하여 작업을 하는 모든 유저의 난수가 랜덤하게 나오게 된다.
가챠시스템에서 시간대에 따라 확률이 바뀌면 안되므로 이 프로젝트에선 SecureRandom을 사용하였다.
SecureRandom으로 나오는 난수를 10000까지로 설정해주었는데 만약 꽝이 연속으로 5번 이상 나올 경우
랜덤값의 범위를 3630까지로 지정하여 확정으로 최소 5등이상에 당첨되게 설정해주었다.
확률의 경우 난수가 1~10000까지인데 여기서 나오는 숫자가 특정 범위안에 들어갈경우 (1~100은 만개중 백개이므로 1퍼센트가 된다) 해당 등수에 해당하는 작업이 이루어지도록 사용하였다.
public void lottoPoint1(User user) {
Long point1 = 1000000L;
user.setTotalPoint(user.getTotalPoint()+point1);
userRepository.save(user);
Point point = new Point("1등 당첨", point1, user.getTotalPoint(), user);
pointRepository.save(point);
}
public void lottoPoint2(User user) {
Long point1 = 100000L;
user.setTotalPoint(user.getTotalPoint()+point1);
userRepository.save(user);
Point point = new Point("2등 당첨", point1, user.getTotalPoint(), user);
pointRepository.save(point);
}
public void lottoPoint3(User user) {
Long point1 = 10000L;
user.setTotalPoint(user.getTotalPoint()+point1);
userRepository.save(user);
Point point = new Point("3등 당첨", point1, user.getTotalPoint(), user);
pointRepository.save(point);
}
public void lottoPoint4(User user) {
Long point1 = 1000L;
user.setTotalPoint(user.getTotalPoint()+point1);
userRepository.save(user);
Point point = new Point("4등 당첨", point1, user.getTotalPoint(), user);
pointRepository.save(point);
}
public void lottoPoint5(User user) {
Long point1 = 500L;
user.setTotalPoint(user.getTotalPoint()+point1);
userRepository.save(user);
Point point = new Point("5등 당첨", point1, user.getTotalPoint(), user);
pointRepository.save(point);
}
각 등수에 당첨될 경유 유저의 포인트에 그 등수에 해당하는 포인트를 적립해주고 포인트 내역을 만들어준다.

1번유저가 포인트 테이블의 23번부터 27번까지 연속으로 5번 꽝이 되자 다음 로또에는 확률보정이 들어가 5등당첨이 나오게 된다.
'공부기록 > 자바 스프링' 카테고리의 다른 글
스프링 아이템기능 리팩터링 (0) | 2022.03.19 |
---|---|
스프링 아이템기능 구현, 단어 뒤집기, 파파고 API (0) | 2022.03.12 |
스프링 배팅시스템 만들기 (트위치 배팅시스템 참고) (0) | 2022.03.08 |
스프링부트 JPA 중복검색 해결 <트러블 슈팅> (0) | 2022.03.07 |
스프링 DI(의존성주입), IOC컨테이너 (0) | 2022.01.29 |