목차
아이디 별로 권한을 부여하여 관리자 페이지와 사용자 페이지를 나누었다.
관리자는 회원들을 관리 할 수 있도록 구현 하였고, 헬스장 이용에 관련한 통계자료도 Spring batch를 통해 사용하려 했지만 아직은 UI만 구현한 상태이다.
사용자는 자신의 헬스장 및 PT 이용권을 확인할 수 있고, 예약도 간편하게 진행할 수 있다. 또한 가볍게 볼 수 있는 BMI 측정에 대한 알고리즘도 구현해보았다.
- 관리자 페이지
로그인 화면 및 메인 페이지
회원 정보 및 예약 정보
헬스장 예약 및 예약정보
헬스장 통계
- 사용자 페이지
로그인 및 메인 페이지
PT 예약
마이페이지 및 예약정보 수정
헬스장 이용권 조회 및 BMI 계산기
'프로젝트 > 헬스장 이용권' 카테고리의 다른 글
헬스장 이용권 #3 (Service 구성) (0) | 2023.10.15 |
---|---|
헬스장 이용권 #2 (Entity 구성) (0) | 2023.08.03 |
헬스장 이용권 #1 (Springboot+AWS+Docker) (0) | 2023.08.03 |
목차
GymMembershipService.java
- 헬스장 이용권 CRUD
@Service
public class GymMembershipService {
private final GymMembershipRepository gymMembershipRepository;
private final MemberRepository memberRepository;
private final MemberService memberService;
private final ModelMapper modelMapper;
public GymMembershipService (GymMembershipRepository gymMembershipRepository, MemberRepository memberRepository,
MemberService memberService, ModelMapper modelMapper){
this.gymMembershipRepository = gymMembershipRepository;
this.memberRepository = memberRepository;
this.memberService = memberService;
this.modelMapper = modelMapper;
}
@Transactional
public GymMembershipDTO createGymMembershipService(GymMembershipDTO requestDTO, String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail)
.orElseThrow(() -> new EntityNotFoundException("Member not found with email: " + memberEmail));
GymMembership gymMembership = modelMapper.map(requestDTO, GymMembership.class);
gymMembership.setMember(member);
GymMembership savedGymMembership = gymMembershipRepository.save(gymMembership);
GymMembershipDTO responseDTO = modelMapper.map(savedGymMembership, GymMembershipDTO.class);
responseDTO.setName(member.getName());
return responseDTO;
}
@Transactional
public List<GymMembershipDTO> getAllGymMemberships() {
List<GymMembership> gymMemberships = gymMembershipRepository.findAll();
return gymMemberships.stream()
.map(gymMembership -> {
GymMembershipDTO dto = modelMapper.map(gymMembership, GymMembershipDTO.class);
dto.setName(gymMembership.getMember().getName());
return dto;
})
.collect(Collectors.toList());
}
@Transactional
public GymMembershipDTO getGymMembershipByMe() {
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
Member member = memberRepository.findById(myInfoBySecurity.getId())
.orElseThrow(() -> new EntityNotFoundException("Member not found"));
GymMembership gymMembership = member.getGymMembership();
GymMembershipDTO dto = modelMapper.map(gymMembership, GymMembershipDTO.class);
dto.setName(gymMembership.getMember().getName());
return dto;
}
@Transactional
public GymMembershipDTO updateGymMembership(GymMembershipDTO requestDTO, String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail).orElse(null);
GymMembership gymMembership = member.getGymMembership();
if (requestDTO.getStartDate()!= null) {
System.out.println(requestDTO.getStartDate());
gymMembership.setStartDate(requestDTO.getStartDate());
}
if (requestDTO.getEndDate()!= null) {
gymMembership.setEndDate(requestDTO.getEndDate());
}
requestDTO.setName(gymMembership.getMember().getName());
GymMembership savedGymMembership = gymMembershipRepository.save(gymMembership);
return modelMapper.map(savedGymMembership, GymMembershipDTO.class);
}
@Transactional
public void deleteGymMembership(String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail).orElse(null);
GymMembership gymMembership = member.getGymMembership();
gymMembershipRepository.delete(gymMembership);
}
}
PTSubscriptionService.java
- 헬스장 PT 이용권 CRUD
@Service
@Component
@EnableScheduling
public class PTSubscriptionService {
private final PTSubscriptionRepository ptSubscriptionRepository;
private final ReservationRepository reservationRepository;
private final MemberRepository memberRepository;
private final TrainerRepository trainerRepository;
private final MemberService memberService;
private final ModelMapper modelMapper;
public PTSubscriptionService(PTSubscriptionRepository ptSubscriptionRepository, ReservationRepository reservationRepository, MemberService memberService,
MemberRepository memberRepository, ModelMapper modelMapper, TrainerRepository trainerRepository) {
this.ptSubscriptionRepository = ptSubscriptionRepository;
this.reservationRepository = reservationRepository;
this.memberService = memberService;
this.memberRepository = memberRepository;
this.trainerRepository = trainerRepository;
this.modelMapper = modelMapper;
}
@Transactional
public PTSubscriptionRequestDTO createPTSubscription(PTSubscriptionRequestDTO requestDTO,String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail)
.orElseThrow(() -> new EntityNotFoundException("Member not found with email: " + memberEmail));
System.out.println(member.getName());
PTSubscription ptSubscription = modelMapper.map(requestDTO, PTSubscription.class);
ptSubscription.setMember(member);
PTSubscription savedPtSubscription = ptSubscriptionRepository.save(ptSubscription);
System.out.println(savedPtSubscription.getMember().getName());
PTSubscriptionRequestDTO responseDTO = modelMapper.map(savedPtSubscription, PTSubscriptionRequestDTO.class);
responseDTO.setName(member.getName());
return responseDTO;
}
@Transactional
public List<PTSubscriptionRequestDTO> getAllPTSubscriptions() {
List<PTSubscription> ptSubscriptions = ptSubscriptionRepository.findAll();
return ptSubscriptions.stream()
.map(ptSubscription -> {
PTSubscriptionRequestDTO dto = modelMapper.map(ptSubscription, PTSubscriptionRequestDTO.class);
dto.setName(ptSubscription.getMember().getName());
return dto;
})
.collect(Collectors.toList());
}
@Transactional
public PTSubscriptionRequestDTO getPTSubscriptionByMe() {
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
Member member = memberRepository.findById(myInfoBySecurity.getId())
.orElseThrow(() -> new EntityNotFoundException("Member not found"));
PTSubscription ptSubscription = member.getPtSubscription();
PTSubscriptionRequestDTO dto = modelMapper.map(ptSubscription, PTSubscriptionRequestDTO.class);
dto.setName(ptSubscription.getMember().getName());
return dto;
}
@Transactional
public PTSubscriptionRequestDTO updatePTSubscription(PTSubscriptionRequestDTO requestDTO,String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail).orElse(null);
PTSubscription ptSubscription = member.getPtSubscription();
if (requestDTO.getAvailableCount() != null) {
ptSubscription.setAvailableCount(requestDTO.getAvailableCount());
}
if (requestDTO.getUsedCount() != null) {
ptSubscription.setUsedCount(requestDTO.getUsedCount());
}
PTSubscription savedPtSubscription = ptSubscriptionRepository.save(ptSubscription);
PTSubscriptionRequestDTO dto = modelMapper.map(savedPtSubscription, PTSubscriptionRequestDTO.class);
dto.setName(ptSubscription.getMember().getName());
return dto;
}
@Transactional
public void deletePTSubscription(String memberEmail) {
Member member = memberRepository.findByEmail(memberEmail).orElse(null);
PTSubscription ptSubscription = member.getPtSubscription();
ptSubscriptionRepository.delete(ptSubscription);
}
}
ReservationService.java
- PT예약 정보 CRUD
- 스케줄링을 이용해 예약정보 시간과 비교하여 이용권 차감
@Service
public class ReservationService {
private final ReservationRepository reservationRepository;
private final PTSubscriptionRepository ptSubscriptionRepository;
private final MemberService memberService;
private final ModelMapper modelMapper;
private final MemberRepository memberRepository;
private final TrainerRepository trainerRepository;
public ReservationService(ReservationRepository reservationRepository, PTSubscriptionRepository ptSubscriptionRepository, MemberService memberService
,ModelMapper modelMapper,MemberRepository memberRepository, TrainerRepository trainerRepository){
this.reservationRepository = reservationRepository;
this.ptSubscriptionRepository = ptSubscriptionRepository;
this.memberService = memberService;
this.modelMapper = modelMapper;
this.memberRepository = memberRepository;
this.trainerRepository = trainerRepository;
}
// PT 예약 생성
public ReservationRequestDTO createReservation(ReservationRequestDTO requestDTO) {
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
requestDTO.setMemberId(myInfoBySecurity.getId());
Reservation reservation = modelMapper.map(requestDTO, Reservation.class);
Member member = memberRepository.findById(myInfoBySecurity.getId())
.orElseThrow(() -> new EntityNotFoundException("Member not found"));
System.out.println(requestDTO.getReservationTrainerId());
Trainer trainer = trainerRepository.findById(requestDTO.getReservationTrainerId()).orElse(null);
reservation.setMember(member);
reservation.setTrainer(trainer);
Reservation savedReservation = reservationRepository.save(reservation);
return modelMapper.map(savedReservation, ReservationRequestDTO.class);
}
@Transactional
public List<ReservationRequestDTO> getAllReservations() {
List<Reservation> reservations = reservationRepository.findAll();
return reservations.stream()
.map(reservation -> {
ReservationRequestDTO dto = modelMapper.map(reservation, ReservationRequestDTO.class);
dto.setMemberName(reservation.getMember().getName()); // 멤버 이름 설정
dto.setTrainerName(reservation.getTrainer().getName()); // 트레이너 이름 설정
dto.setMemberEmail(reservation.getMember().getEmail());
return dto;
})
.collect(Collectors.toList());
}
@Transactional
public ReservationRequestDTO updateReservation(Long id, ReservationRequestDTO requestDTO){
Reservation reservation = reservationRepository.findById(id).orElse(null);
if (requestDTO.getReservationTrainerId() != null) {
reservation.setTrainer(trainerRepository.findById(requestDTO.getReservationTrainerId()).orElse(null));
}
if (requestDTO.getReservationTime() != null) {
reservation.setReservationTime(requestDTO.getReservationTime());
}
requestDTO.setMemberName(reservation.getMember().getName());
requestDTO.setTrainerName(reservation.getTrainer().getName());
requestDTO.setMemberEmail(reservation.getMember().getEmail());
Reservation savedReservation = reservationRepository.save(reservation);
return modelMapper.map(savedReservation,ReservationRequestDTO.class);
}
@Transactional
public ReservationRequestDTO updateMyReservation(ReservationRequestDTO requestDTO){
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
requestDTO.setMemberId(myInfoBySecurity.getId());
Reservation reservation = reservationRepository.findById(myInfoBySecurity.getId()).orElse(null);
if (requestDTO.getReservationTrainerId() != null) {
reservation.setTrainer(trainerRepository.findById(requestDTO.getReservationTrainerId()).orElse(null));
}
if (requestDTO.getReservationTime() != null) {
reservation.setReservationTime(requestDTO.getReservationTime());
}
requestDTO.setMemberName(reservation.getMember().getName());
requestDTO.setTrainerName(reservation.getTrainer().getName());
requestDTO.setMemberEmail(reservation.getMember().getEmail());
Reservation savedReservation = reservationRepository.save(reservation);
return modelMapper.map(savedReservation,ReservationRequestDTO.class);
}
// PT 예약 취소
@Transactional
public void cancelReservationMe() {
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
Member member = memberRepository.findById(myInfoBySecurity.getId())
.orElseThrow(() -> new EntityNotFoundException("Member not found"));
LocalDateTime currentDateTime = LocalDateTime.now();
// 현재 사용자의 정보를 기반으로 현재 시간 이후의 예약 정보를 가져옵니다.
List<Reservation> reservations = reservationRepository.findByMemberAndReservationTimeAfter(member, currentDateTime);
for (Reservation reservation : reservations) {
reservationRepository.delete(reservation);
}
}
@Transactional
public void cancelReservation(Long id) {
Reservation reservation = reservationRepository.findById(id).orElse(null);
reservationRepository.delete(reservation);
}
@Transactional
public List<ReservationRequestDTO> getReservationsByMe() {
MemberResponseDto myInfoBySecurity = memberService.getMyInfoBySecurity();
Member member = memberRepository.findById(myInfoBySecurity.getId())
.orElseThrow(() -> new EntityNotFoundException("Member not found"));
List<Reservation> reservations = member.getReservations();
if (reservations.isEmpty()) {
throw new EntityNotFoundException("Reservations not found for the member");
}
return reservations.stream()
.map(reservation -> {
ReservationRequestDTO reservationRequestDTO = modelMapper.map(reservation, ReservationRequestDTO.class);
reservationRequestDTO.setMemberName(member.getName());
reservationRequestDTO.setTrainerName(reservation.getTrainer().getName());
reservationRequestDTO.setMemberEmail(reservation.getMember().getEmail());
return reservationRequestDTO;
})
.collect(Collectors.toList());
}
@Scheduled(cron = "0 * * * * *") // 매 시간마다 실행
public void deductPTSubscriptionAutomatically() {
LocalDateTime currentDateTime = LocalDateTime.now();
// 예약된 PT 이용권 중 현재 시간에 해당하는 것을 차감
List<Reservation> reservations = reservationRepository.findByReservationTimeBefore(currentDateTime);
for (Reservation reservation : reservations) {
Member member = reservation.getMember();
if (member.getPtSubscription() != null && member.getPtSubscription().getAvailableCount() > 0 && !reservation.isExpired()) {
PTSubscription ptSubscription = member.getPtSubscription();
// 사용 가능한 횟수 차감
int availableCount = ptSubscription.getAvailableCount();
ptSubscription.setAvailableCount(availableCount - 1);
// 사용된 횟수 증가
int usedCount = ptSubscription.getUsedCount();
ptSubscription.setUsedCount(usedCount + 1);
reservation.setExpired(true);
reservationRepository.save(reservation);
// PTSubscription 엔티티 저장
ptSubscriptionRepository.save(ptSubscription);
}
}
}
TrainerService.java
- 트레이너 CRUD
@Service
@Component
public class TrainerService {
private final TrainerRepository trainerRepository;
private final ModelMapper modelMapper;
public TrainerService(TrainerRepository trainerRepository, ModelMapper modelMapper){
this.trainerRepository = trainerRepository;
this.modelMapper = modelMapper;
}
public TrainerDto createTrainer(TrainerDto trainerDto){
Trainer trainer = modelMapper.map(trainerDto,Trainer.class);
System.out.println(trainer.getName());
Trainer savedTrainer = trainerRepository.save(trainer);
TrainerDto savedDto = modelMapper.map(savedTrainer,TrainerDto.class);
return savedDto;
}
public List<TrainerDto> getAllTrainer(){
List<Trainer> trainers = trainerRepository.findAll();
return trainers.stream()
.map(trainer -> modelMapper.map(trainer,TrainerDto.class))
.collect(Collectors.toList());
}
}
'프로젝트 > 헬스장 이용권' 카테고리의 다른 글
헬스장 이용권 #4 (UI 구성) (0) | 2023.10.15 |
---|---|
헬스장 이용권 #2 (Entity 구성) (0) | 2023.08.03 |
헬스장 이용권 #1 (Springboot+AWS+Docker) (0) | 2023.08.03 |
목차
회원가입 로그인은 Spring Security와 JWT를 이용하였고, 이전 프로젝트에서 다루었으므로 참고하시면 됩니다.
https://jeonsg99.tistory.com/3
공유 캘린더 만들기 #2 (JWT를 이용한 회원가입 로그인)
JWT를 이용한 회원가입 로그인 본격적인 프로젝트를 구성하면서 가장 먼저 회원가입 로그인을 구현하려 한다. Spring boot를 이용해서 인증 인가 메커니즘을 구현하기 위해 Spring security 와 JWT를 이
jeonsg99.tistory.com
Entity 구성을 들어가기 전에 프로젝트 구성에 필요한 Table를 생각해보자
1. Member (유저 정보를 기록)
2. Authority (접근 권한을 이용한 관리자와 사용자 구분)
3. GymMembership (헬스장 이용권)
4. PTSubscription (PT 이용권)
5. Reservation (예약 정보)
6. Trainer (트레이너 정보)
이제부터 하나씩 구성해보자.
Member.java
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@Pattern(regexp = "^(Male|Female)$", message = "성별은 Male 또는 Female이어야 합니다.")
private String gender;
@Enumerated(EnumType.STRING)
private Authority authority;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "member")
private PTSubscription ptSubscription;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "member")
private GymMembership gymMembership;
@OneToMany(mappedBy = "member")
private List<Reservation> reservations;
public Member(Long memberId) {
this.id = memberId;
}
public void setNickname(String nickname) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
@Builder
public Member(Long id, String email, String password, String name, String gender, Authority authority) {
this.id = id;
this.email = email;
this.password = password;
this.name = name;
this.gender = gender;
this.authority = authority;
}
}
Authority.java
public enum Authority {
ROLE_USER, ROLE_ADMIN
}
GymMembership.java
- 기본적인 시작날짜와 종료날짜만 구성해주었다.
@Entity
@Getter
@Setter
@NoArgsConstructor
public class GymMembership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate startDate;
private LocalDate endDate;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
}
PTSubscription.java
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class PTSubscription {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private int availableCount=0; // 사용 가능한 횟수
private int usedCount=0; // 사용된 횟수
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
}
Reservation.java
- expired를 예약시간의 만료 유무를 판단하기 위해 bollean형식으로 두었다.
@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Reservation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDateTime reservationTime; // PT 예약 시간
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "trainer_id")
private Trainer trainer;
@Column(nullable = false)
private boolean expired = false;
}
Trainer.java
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Trainer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
@Pattern(regexp = "^(Male|Female)$", message = "성별은 Male 또는 Female이어야 합니다.")
private String gender;
@OneToMany(mappedBy = "trainer")
private List<Reservation> reservations;
}
DB Tables
'프로젝트 > 헬스장 이용권' 카테고리의 다른 글
헬스장 이용권 #4 (UI 구성) (0) | 2023.10.15 |
---|---|
헬스장 이용권 #3 (Service 구성) (0) | 2023.10.15 |
헬스장 이용권 #1 (Springboot+AWS+Docker) (0) | 2023.08.03 |
목차
1. 프로젝트 개요
- 헬스장을 운영하는 관리자와 이용하는 사용자 측면에서 편리성을 제공하고자 함
- 사용자는 남은 헬스장과 PT 이용권 기간 및 횟수를 확인할 수 있다.
- 관리자는 헬스장 이용자 등록, 현황을 확인하고, 담당 회원 PT이용 시간표를 손쉽게 볼 수 있다.
2. 사용 기술
- Spring boot
- Spring security
- JWT
- Spring Data JPA
- Docker
- AWS EC2, S3, Code Deploy, RDS(MySQL)
- Github actions
본 프로젝트에서 Back-End 부분을 담당했기 때문에 프론트 부분은 포함되어있지 않습니다.
프로젝트 초기 구성
프로젝트가 프론트 둘 백엔드 하나로 구성되어 있기 때문에 가장 먼저 서버 배포를 구현하였습니다.
서버 배포는 AWS EC2 인스턴스를 이용했고, git에 배포하는 과정도 자동 배포화를 이용하여 효율적인 프로젝트 구성을 준비하였습니다.
AWS 프리티어를 사용하고 있으므로, 메모리가 부족 할 경우를 대비하여
AWS 공식 홈페이지에 있는 스왑 파일을 이용한 메모리 확보 방법을 사용했습니다.
https://repost.aws/ko/knowledge-center/ec2-memory-swap-file
스왑 파일을 사용하여 Amazon EC2 인스턴스의 스왑 공간으로 메모리 할당
Amazon Elastic Compute Cloud(Amazon EC2) 인스턴스에서 스왑 파일로 사용할 메모리를 할당하려고 합니다. 어떻게 해야 하나요?
repost.aws
자동배포화 하는 과정은 아래 글을 참고하시면 됩니다.
https://jeonsg99.tistory.com/15
Spring boot + Docker + Github Actions + AWS 를 이용한 자동 배포화
과정 1. Github main 브랜치에 Push 2. Github Actions에서 AWS S3에 빌드 파일 및 Dockerfile, deploy.sh 등 업로드 3. Github Actions이 AWS CodeDeploy에 배포 요청 4. CodeDeploy가 배포 실행 5. 도커 빌드 및 실행 위와 같은
jeonsg99.tistory.com
'프로젝트 > 헬스장 이용권' 카테고리의 다른 글
헬스장 이용권 #4 (UI 구성) (0) | 2023.10.15 |
---|---|
헬스장 이용권 #3 (Service 구성) (0) | 2023.10.15 |
헬스장 이용권 #2 (Entity 구성) (0) | 2023.08.03 |