스포츠 배팅 웹사이트 만들기(4)(Team Project)

병호·2023년 10월 4일

Project

목록 보기
4/5
post-thumbnail

admin/service/memberservice/MemberManagementService

@Service
@RequiredArgsConstructor
public class MemberManagementService {

    private final MemberRepository memberRepository;

    // 회원 전체 조회
    public List<Member> findAllMembers() {
        return memberRepository.findAll();
    }

    // 회원 단일 조회 (id)
    public Member findMember(String mId) {
        Member member = memberRepository.findBymId(mId);
        if (member != null) {
            return member;
        } else {
            throw new IllegalArgumentException("존재하지 않는 회원입니다.");
        }
    }

    // 회원 권한 변경
    @Transactional
    public void changeMemberRole(String mId, Role newRole) {
        Member member = memberRepository.findBymId(mId);
        if (member != null) { // ADMIN 계정 추가 이후에 수정 예정
            member.setRole(newRole);  //
            memberRepository.save(member);  // 변경된 정보 저장
        } else {
            throw new IllegalArgumentException("존재하지 않는 회원입니다.");
        }
    }

    // 회원 삭제
    @Transactional
    public void deleteMember(String mId) {
        Member member = memberRepository.findBymId(mId);
        if (member != null) {
            memberRepository.delete(member);
        } else {
            throw new IllegalArgumentException("존재하지 않는 회원입니다.");
        }
    }

    // 회원 전체 조회(페이징 처리)
    public Page<Member> getsAdminMemberWithPages(AdminSearchInfo adminSearchInfo) {

        int page = adminSearchInfo.getPage();
        int pageSize = adminSearchInfo.getPageSize();
        page = Math.max(page, 1);
        pageSize = pageSize < 1 ? 15 : pageSize;

        // 권한 오름차순, 생성일자 내림차순으로 정렬
        Pageable pageable = PageRequest.of(page - 1, pageSize,
                Sort.by(Sort.Order.asc("role"), Sort.Order.desc("createdAt")));

        Page<Member> adminMemberList = memberRepository.findAll(pageable);

        return adminMemberList;

    }

    // 검색(필터링) 페이징 처리
    public Page<Member> searchMembers(AdminSearchInfo adminSearchInfo) {
        int page = adminSearchInfo.getPage();
        int pageSize = adminSearchInfo.getPageSize();

        page = Math.max(page, 1);
        pageSize = pageSize < 1 ? 15 : pageSize;

        String sOpt = adminSearchInfo.getSOpt();
        String sKey = adminSearchInfo.getSKey();

        // 권한(Admin / Member) 오름차순, 생성일 내림차순
        Pageable pageable = PageRequest.of(page - 1, pageSize,
                Sort.by(Sort.Order.asc("role"), Sort.Order.desc("createdAt")));

        if (sOpt != null && sKey != null) {
            switch (sOpt) {
                case "mNo":
                    Long mNo = Long.parseLong(sKey);
                    return memberRepository.findBymNo(mNo,pageable);
                case "mId":
                    return memberRepository.findBymId(sKey, pageable);
                case "mName":
                    return memberRepository.findBymName(sKey, pageable);
                case "mNickName":
                    return memberRepository.findBymNickName(sKey, pageable);
                case "grade":
                    Grade grade = Grade.valueOf(sKey);
                    return memberRepository.findByGrade(grade, pageable);
                case "mLevel":
                    Integer mLevel = Integer.parseInt(sKey);
                    return memberRepository.findBymLevel(mLevel, pageable);
                case "role":
                    Role role = Role.valueOf(sKey);
                    return memberRepository.findByRole(role, pageable);
            }
        }

        return memberRepository.findAll(pageable);
    }
}

MemberManagementService에서는 회원에 관한 정보를 변경, 삭제 , 조회 등과 같은 기능들을 구현해 놓은 클래스이다. 회원 권한 변경하는 코드에서는 Role이라는 타입으로 매개변수를 받는데

public enum Role {
    MEMBER,
    ADMIN
}

위와 같이 enum타입으로 MEMBER와 ADMIN을 만들어 놓았다.

            <!-- 권한 변경 -->
            <form th:action="@{'/admin/member/' + ${member.mId} + '/role'}" method="post">
                <input type="hidden" name="_method" value="put" />
                <!-- ADMIN / MEMBER 둘 중 하나만 선택 하도록 구현 -->
                <select name="newRole">
                    <option value="MEMBER">MEMBER</option>
                    <option value="ADMIN">ADMIN</option>
                </select>
                <button type="submit">Change Role</button>
            </form>
        </td>
    </tr>

memberManagement.html에 thymeleaf로 권한 변경하는 코드를 작성해놓았다. 위 폼은 사용자가 버튼을 클릭하면 newRole에 정보를 담아서

 @PutMapping("/{mId}/role")
    public RedirectView changeMemberRole(@PathVariable String mId, @RequestParam("newRole") Role newRole) {
        try {
            memberManagementService.changeMemberRole(mId, newRole);
            return new RedirectView("/admin/member/memberList");
        } catch (IllegalArgumentException e) {
            // 예외가 발생시 해당 예외 메시지와 함께 HTTP 상태 코드 400(Bad Request)를 반환
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e);
        }
    }

위 컨트롤러에서 받아서 서비스에서 처리한 내용을 바탕으로 다시 /admin/member/memberList로 넘겨준다.

회원 전체 조회나 검색은 페이징 처리를 해서 코드를 작성했다.

@Data
public class AdminSearchInfo {

    private int page = 1;
    private int pageSize = 10;

    private String sOpt; // 검색 조건
    private String sKey; // 검색 키워드(유저 입력)

    //    private String category; // 검색 조건
//    private String query;    // 검색 키워드 (유저 입력)

}

AdminSearchInfo 클래스에 페이징 처리에 관련된 정보를 넣어놓고 Spring Data JPA에서 제공하는 페이지네이션 기능을 활용하였다.

bet/service/BetService

package com.springboot.shootformoney.bet.service;

import com.springboot.shootformoney.bet.entity.Bet;
import com.springboot.shootformoney.bet.entity.EuroPool;
import com.springboot.shootformoney.bet.repository.BetRepository;
import com.springboot.shootformoney.bet.repository.EuroPoolRepository;
import com.springboot.shootformoney.game.dto.data.Result;
import com.springboot.shootformoney.game.entity.Game;
import com.springboot.shootformoney.game.repository.GameRepository;
import com.springboot.shootformoney.member.entity.Euro;
import com.springboot.shootformoney.member.entity.Member;
import com.springboot.shootformoney.member.repository.EuroRepository;
import com.springboot.shootformoney.member.utils.MemberUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/*
* 배팅 관련 서비스(배팅 실행, 배팅 취소, 정산 후 지급금 지급) 구현 클래스
* Author: Hyedokal(https://www.github.com/Hyedokal)
*/
@Service
public class BetService {

    @Autowired
    private BetRepository betRepository;

    @Autowired
    private EuroPoolRepository euroPoolRepository;

    @Autowired
    private GameRepository gameRepository;

    @Autowired
    private MemberUtil memberUtil;

    @Autowired
    private EuroRepository euroRepository;


    //고객이 배팅하면, Bet 테이블에 기록을 저장하는 메서드
    @Transactional
    public Bet bet(Long gNo, String expect, Integer betAmount) {
        Game game = gameRepository.findById(gNo)
                .orElseThrow(() -> new RuntimeException("해당 경기 정보가 없습니다.")); //gNo로 경기 데이터를 찾아 온다.
        Bet bet = new Bet();
        bet.setGame(game);
        bet.setExpect(Result.valueOf(expect));
        bet.setBtMoney(betAmount);
        bet.setBtTime(LocalDateTime.now());
        bet.setMember(memberUtil.getEntity());
        //배팅 정보 저장 후 가져옴.
        return betRepository.save(bet);
    }

    //취소할 배팅을 불러오는 메서드
    @Transactional
    public Bet findToCancel(Long btNo){
        Optional<Bet> bet = betRepository.findByBtNo(btNo);
        if(bet.isPresent()){
           return bet.get();
        }
        return null;
    }
    //배팅 취소 메서드
    @Transactional
    public Bet betCancel(Long btNo){
        Bet bet = betRepository.findByBtNo(btNo) //btId로 배팅 데이터를 찾아 온다.
                                .orElseThrow(() -> new RuntimeException("배팅 정보가 잘못되었습니다."));
        betRepository.delete(bet);  // 찾아온 배팅 데이터 삭제
        return bet;

    }

    //경기결과가 나오면 배당률을 계산해서 모든 배팅률이 업데이트되지 않은 배팅내역에 배당률을 집어넣는다.
    @Transactional
    public void calcBtRatio(){
        try{
            List<Game> finishedMatches = gameRepository.findAllFinishedMatches();
            for(Game game : finishedMatches) {
                EuroPool targetEuroPool = euroPoolRepository.findByGame_gNo(game.getGNo());
                //걸린 유로의 총합.
                double euroSum = (double) targetEuroPool.getWinEuro() + targetEuroPool.getDrawEuro()
                        + targetEuroPool.getLoseEuro();
                //각 결과별 배당률.
                double winBtRatio = Math.round((euroSum / targetEuroPool.getWinEuro()) * 100.0) / 100.0;
                double drawBtRatio = Math.round((euroSum / targetEuroPool.getDrawEuro()) * 100.0) / 100.0;
                double loseBtRatio = Math.round((euroSum / targetEuroPool.getLoseEuro()) * 100.0) / 100.0;

                List<Bet> bets = betRepository.findAllByGame_gNo(game.getGNo());
                for (Bet bet : bets) {
                    if (bet.getExpect() == Result.WIN) {
                        bet.setBtRatio(winBtRatio);
                    } else if (bet.getExpect() == Result.DRAW) {
                        bet.setBtRatio(drawBtRatio);
                    } else if(bet.getExpect() == Result.LOSE) {
                        bet.setBtRatio(loseBtRatio);
                    }
                }
            }
        } catch (RuntimeException e){
            System.err.println("calcBtRatio()에서 오류 발생");
        }
    }

    //경기결과가 나오면 지급금을 지급하는 메서드.
    @Transactional
    public void dividend(){
        try {
            //끝난 경기들 가져오기.
            List<Game> finishedGames = gameRepository.findAllFinishedMatches();

            for (Game game : finishedGames) {
                List<Bet> bets = betRepository.findByGameAndEndPaid(game);
                for (Bet bet : bets) {
                    //배팅 적중 시 지급금을 지금하는 if문.
                    if(bet.getExpect().equals(game.getResult())){
                        Member member = bet.getMember();
                        double fee = member.getGrade().getFee();

                        //배당금 = 배팅금 * (배당률 - 1) (만 단위, 배팅금 보전)
                        double prizeValue = bet.getBtMoney() * (bet.getBtRatio() - 1);
                        //지급금 = 배당금 * (1 - 수수료) + 배팅금
                        Integer addValue = (int) ((prizeValue * (1 - fee) + bet.getBtMoney()) * 10000);

                        //현재 사용자의 유로 보유량 조회.
                        Integer originalValue = euroRepository.findBymNo(member.getMNo()).getValue();
                        //Euro 보유량 업데이트.
                        Euro euroAccount = euroRepository.findBymNo(member.getMNo());
                        euroAccount.setValue(originalValue + addValue);
                        bet.setCorrect((byte) 1);
                    }
                    //Bet엔터티의 중복검사부분 업데이트
                    bet.setEndPaid((byte) 1);
                }
            }
        } catch (Exception e){
            System.out.println("오류가 발생했습니다.");
        }
    }
}

위 코드에서 expect는 회원의 예상 결과이고 result형으로 형변환 해준 것을 볼 수 있다.

package com.springboot.shootformoney.game.dto.data;

public enum Result {
    WIN,
    DRAW,
    LOSE,
    //경기 종료 전 디폴트값.
    NN;


}

result는 위와 같이 승, 무, 패로 이루어져 있다.

profile
안녕하세요

0개의 댓글