요구 사항
- User(사용자) 는 1개의 Crew(모임) 에 참여 할 수 있다.
- Crew(모임) 의 작성자는 참여 신청한 사용자를 조회/승인/반려 할 수 있다.
- User(사용자) 는 상세페이지에 접근했을때, 참여 상태에 따른 버튼이 달라져야한다.
진행 사항
플로우 차트 및 UI 화면
엔티티 설계
- 참여 라는 엔티티를 만들어 User Crew 를 FK 로 받고 status 를 나타냄
public class Participation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "crew_id")
private Crew crew;
private Integer status;
//...
}
public class Crew{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//이하 내용 생략 참여중인사람 조회
@OneToMany(mappedBy = "crew")
private List<Participation> participations = new ArrayList<>();
}
1:N 관계에서 연관관계 주인에 관한 매핑 관련해서 아래 자료 참고하여
Reference 관계는는 양방향 매핑을 해주고(OneToMany, ManyToOne),
DB 에서는 Paticipation 에 FK 를 저장하는 방식을 선택했다.
서비스 로직
한명의 사용자가 어떠한 특정 모임에 참여했을때 신청상태를 나타내는 status 가 필요
클라이언트가 상세페이지에 접근할때 JS 로 로직을 거쳐 화면을 설정한다.
화면이 로딩될때 아래 메소드를 실행시킨다( Participation 상태를 확인하고 화면의 버튼을 수정하는 메소드 )
async function enterCheck(){
console.log("enterCheck()");
var crewId = document.getElementById('crewIdJoin').value;
let response = await fetch("/api/v1/part/"+crewId, {
method: "GET",
headers: {
"Content-Type": "application/json"
},
credentials: "include"
})
if(response.ok){
var json = await response.json();
console.log(json.result);
if(json.result.status === 0){
document.getElementById("sendtogle").style.display = "block";
document.getElementById("notallowed").style.display = "none";
document.getElementById("signed").style.display = "none";
document.getElementById("chatroom").style.display = "none";
document.getElementById("members").style.display = "none";
}
if(json.result.status === 1) {
document.getElementById("sendtogle").style.display = "none";
document.getElementById("notallowed").style.display = "block";
document.getElementById("signed").style.display = "none";
document.getElementById("chatroom").style.display = "none";
document.getElementById("members").style.display = "none";
}
if(json.result.status === 2){
document.getElementById("sendtogle").style.display = "none";
document.getElementById("signed").style.display = "block";
document.getElementById("chatroom").style.display = "block";
document.getElementById("members").style.display = "block";
}
if(json.result.status === 3){
document.getElementById("sendtogle").style.display = "none";
document.getElementById("signed").style.display = "none";
document.getElementById("chatroom").style.display = "none";
document.getElementById("members").style.display = "block";
document.getElementById("finished").style.display = "block";
document.getElementById("finishCrew").style.display = "none";
}
}
}
let response = await fetch("/api/v1/part/"+crewId, {
method: "GET",
headers: {
"Content-Type": "application/json"
},
credentials: "include"
})
api 를 호출했을때 아래와 같이 JSON 형식으로 반환되어 Response 클래스에 담겨 반환되게 된다.
public class PartResponse {
private Integer now;
private Integer limit;
private Integer status;
private String title;
private String body;
}
@GetMapping("/{crewId}")
public Response findParticipate(@PathVariable Long crewId, Authentication authentication){
log.info("#1 participateController crewId: "+ crewId);
return Response.success(participationService.findParticipate(crewId, authentication.getName()));
}
1. fetch 방식으로 스프링부트 내 api 를 호출해서 상세페이지의 id 값으로 crew 를 찾고
2. 내가 로그인한 Authentication.getName() 의 string 값으로 User 를 찾는다.
- 참여 엔티티가 존재하지 않을 경우에는 response status 에 0을
- 참여 엔티티가 존재하면 해당 값을 response status 에 반영한다.
@Transactional
public PartResponse findParticipate(Long crewId, String userName) {
User user = userRepository.findByUserName(userName).orElseThrow(() -> new AppException(ErrorCode.USERID_NOT_FOUND, ErrorCode.USERID_NOT_FOUND.getMessage()));
Crew crew = crewRepository.findById(crewId).orElseThrow(() -> new AppException(ErrorCode.CREW_NOT_FOUND, ErrorCode.CREW_NOT_FOUND.getMessage()));
if (!participationRepository.existsByCrewAndAndUser(crew, user)) {
return PartResponse.builder().status(0).build();
}
Participation participation = participationRepository.findByCrewAndUser(crew, user).orElseThrow(() -> new AppException(ErrorCode.DB_ERROR, ErrorCode.DB_ERROR.getMessage()));
return PartResponse.builder()
.now(crew.getParticipations().size())
.limit(crew.getCrewLimit())
.status(participation.getStatus())
.build();
}
Paticipation 컬럼 상태값에 따른 버튼이 변경되는 모습을 확인 할 수 있다.
승인대기 상태인 User 에 대한 조회
이제 어떤 User 가 어떤 Crew 에 참여 신청을 했을 경우
참여 승인대기 상태의 User 를 확인하는 로직이다.
- crewId 는 참여 신청한 crewId 를 의미
- userId 는 참여 신청한 userId 를 의미
- status 는 현재 상태를 나타냄 (1: 승인대기, 2: 참여중, 3: 모임종료상태)
자신이 작성한 모임에 어떤사람이 신청을 했는지에 대한 유무를 파악하고 싶으면
crewId 에 매핑된 userId 가 자신과 같은 Id 값과 일치를 한다면 해당되는 Participation 중에서 status 가 1인 내용들만 보여주면 된다.
마무리
- Js 로 사용하다보니 document.getElementById() 의 innerHTML 속성을 변경을 하면서 화면 렌더링을 진행했는데, 레이아웃을 신경쓴다고 많은 시간이 들었다. 프론트엔드를 심화적으로 이해한다면 수월했을거 같다. 이후 리액트를 공부해서 도입해볼 생각이다.
- 1상태에 따른 botton 의 속성값을 변경함에 따라 바뀌는 화면 설정 방법이 소스가 매우 아쉽게 보인다. 조금 더 가독성 있게 효율적으로 짜는 방법이 있을까?
자세한 소스 내용에 관련해서는 https://github.com/rnrudejr9/poco_a_poco 주소를 참고하세요!
GitHub - rnrudejr9/poco_a_poco: 오늘부터 운동메💪 "동네 운동 메이트를 찾아 함께 스포츠를 즐기는 서
오늘부터 운동메💪 "동네 운동 메이트를 찾아 함께 스포츠를 즐기는 서비스". Contribute to rnrudejr9/poco_a_poco development by creating an account on GitHub.
github.com
'2023년 > 멋쟁이사자처럼 팀프로젝트' 카테고리의 다른 글
[팀 프로젝트] SockJS를 활용한 STOMP 방식 채팅방에서 채팅내역 저장과 읽음처리 기능 구현하기 (0) | 2023.03.01 |
---|---|
[팀프로젝트] SockJs를 활용한 STOMP 방식 채팅방에서 실시간 사용자 체크하는 기능 구현하기 (0) | 2023.03.01 |
[팀프로젝트] datepicker / Timepicker 적용하기 (2) | 2023.02.07 |
[팀프로젝트] STOMP 활용한 프로젝트 채팅방 구현 (0) | 2023.02.02 |
[팀프로젝트] Spring Boot에서 jwt + 쿠키를 활용한 로그인 구현과 비동기 방식 처리 (0) | 2023.02.01 |