Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 72 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,72 @@
# second-hand-max
2023 마스터즈 맥스 중고거래 프로젝트
# second-hand
> 2023 마스터즈 맥스 네번째 팀 프로젝트
- 미션 기간: `2023-09-21 ~ 2023-10-6` [6 Week]
중고 거래 서비스
## 구성원

<table>
<tr>
<th colspan="2">#BE</th>
<th colspan="2">#FE</th>
</tr>
<tr>
<td width="150">
<img src="https://avatars.githubusercontent.com/u/100547825?v=4" />
</td>
<td width="150">
<img src="https://avatars.githubusercontent.com/u/98310007?v=4" />
<td width="150">
<img src="https://avatars.githubusercontent.com/u/95265031?v=4" />
</td>
<td width="150">
<img src="https://avatars.githubusercontent.com/u/109706689?v=4" />
</td>
</tr>
<tr>
<td align="center">
<code><a href="https://github.com/DOEKYONG"><strong>light</strong></a></code>
</td>
<td align="center">
<code><a href="https://github.com/CDBchan"><strong>charlie</strong></a></code>
</td>
<td align="center">
<code><a href="https://github.com/lolWK"><strong>아티</strong></a></code>
</td>
<td align="center">
<code><a href="https://github.com/qkdflrgs"><strong>litae</strong></a></code>
</td>
</tr>
</table>

## 사용하는 기술
### 프로젝트 관리
[![Notion](https://img.shields.io/badge/Notion-000000.svg?style=for-the-badge&logo=Notion&logoColor=white)](https://placid-fork-b42.notion.site/SecondHand-BE-A-a00c7636a4db4c1f982b4bbe81694b9b?pvs=4)

### BE
![](https://img.shields.io/badge/Java-007396?style=flat&logo=OpenJDK&logoColor=white)
![](https://img.shields.io/badge/SpringBoot-6DB33F?style=flat&logo=SpringBoot&logoColor=white)
![](https://img.shields.io/badge/MySQL-4479A1?style=flat&logo=MySQL&logoColor=white)
![](https://img.shields.io/badge/GitHub_Actions-2088FF?style=flat&logo=githubactions&logoColor=white)
![](https://img.shields.io/badge/-NginX-269539?style=flat&amp;logo=Nginx&amp;logoColor=white)
![](https://img.shields.io/badge/-Docker-2496ED?style=flat&amp;logo=Docker&amp;logoColor=white)
![](https://img.shields.io/badge/AWS%20EC2-FA7343?style=flat&logo=amazonec2&logoColor=white)
![](https://img.shields.io/badge/-AWS_S3-569A31?style=flat&amp;logo=Amazon-S3&amp;logoColor=white)
![](https://img.shields.io/badge/AWS_RDS-527FFF?style=flat&logo=amazonrds&logoColor=white)
![](https://img.shields.io/badge/Redis-FF4D4D?style=flat&logo=redis&logoColor=white)

- Java: `JDK 11`
- SpringBoot: `ver. 2.7.14`
- MySQL: `ver. 8.0.33`
- Redis: `7.2.0`
- Amazon AWS: `EC2`, `S3`, `RDS`

## ERD
![image](https://github.com/masters2023-project-06-second-hand/be-a/assets/100547825/675dcfcf-5809-445a-98c2-d4cbea8c346a)


## Infra
<img width="942" alt="image" src="https://github.com/masters2023-project-06-second-hand/be-a/assets/98310007/dd8a03e8-a3a7-4965-8246-7966b8a22af0">




Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ private Long getChatRoomId(StompHeaderAccessor accessor) {
private Long validateAccessToken(StompHeaderAccessor accessor) {
try {
String token = extractAccessTokenFromAccessor(accessor);
log.info("token : {}", token);
return jwtProvider.getClaims(token).get("memberId", Long.class);
} catch (RuntimeException e) {
throw new CustomRuntimeException(JwtException.from(e));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.codesquad.secondhand.domain.chat.dto.request.MessageRequest;
import com.codesquad.secondhand.domain.chat.dto.response.ChatRoomDetailsResponse;
import com.codesquad.secondhand.domain.chat.dto.response.ChatRoomListResponse;
import com.codesquad.secondhand.domain.chat.dto.response.ChatSendMessageResponse;
import com.codesquad.secondhand.domain.chat.service.ChatService;

import lombok.RequiredArgsConstructor;
Expand All @@ -36,10 +37,10 @@ public class ChatController {

@MessageMapping("/message")
public void sendMessage(MessageRequest messageRequest) {
chatService.sendMessage(messageRequest);
ChatSendMessageResponse chatSendMessageResponse = chatService.sendMessage(messageRequest);
// 채널아이디 만들기
simpMessageSendingOperations.convertAndSend("/sub/room/" + messageRequest.getChatRoomId(),
messageRequest.getMessage());
chatSendMessageResponse);
}

@PostMapping("/api/chats/room-id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
public class ChatRoomMessageResponse {
private LocalDateTime sendAt;
private String message;
private Long unreadMessageCount;

public ChatRoomMessageResponse(LocalDateTime sendAt, String message, Long unreadMessageCount) {
this.sendAt = sendAt;
this.message = message;
this.unreadMessageCount = unreadMessageCount;
}

public static ChatRoomMessageResponse of(ChatMessage chatMessage, Long count) {
return ChatRoomMessageResponse.builder()
.sendAt(chatMessage.getSendAt())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.codesquad.secondhand.domain.chat.dto.response;

import com.codesquad.secondhand.domain.chat.entity.ChatMessage;
import com.codesquad.secondhand.domain.chat.entity.ChatRoom;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
@AllArgsConstructor
public class ChatSendMessageResponse {

private Long chatRoomId;
private ChatMessageResponse messages;

public static ChatSendMessageResponse of(ChatMessage chatMessage, ChatRoom chatRoom) {
return ChatSendMessageResponse.builder()
.messages(ChatMessageResponse.of(chatMessage))
.chatRoomId(chatRoom.getId())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static com.codesquad.secondhand.domain.chat.entity.QChatMessage.*;

import java.util.Optional;

import org.springframework.stereotype.Repository;

import com.codesquad.secondhand.domain.chat.entity.ChatMessage;
Expand All @@ -15,12 +17,12 @@
public class ChatMessageQueryRepository {
private final JPAQueryFactory query;

public ChatMessage findLatestMessage(ChatRoom chatRoom) {
public Optional<ChatMessage> findLatestMessage(ChatRoom chatRoom) {
ChatMessage latestMessage = query
.selectFrom(chatMessage)
.where(chatMessage.chatRoom.eq(chatRoom))
.orderBy(chatMessage.sendAt.desc())
.fetchFirst();
return latestMessage;
return Optional.ofNullable(latestMessage);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codesquad.secondhand.domain.chat.service;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -60,7 +61,7 @@ public Long getUnReadCount(Member opponent, ChatRoom chatRoom) {
return chatMessageJpaRepository.countUnreadMessages(opponent, chatRoom);
}

public ChatMessage findLastMessage(ChatRoom chatRoom) {
public Optional<ChatMessage> findLastMessage(ChatRoom chatRoom) {
return chatMessageQueryRepository.findLatestMessage(chatRoom);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codesquad.secondhand.domain.chat.service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
Expand All @@ -15,6 +16,7 @@
import com.codesquad.secondhand.domain.chat.dto.response.ChatRoomMessageResponse;
import com.codesquad.secondhand.domain.chat.dto.response.ChatRoomOpponentResponse;
import com.codesquad.secondhand.domain.chat.dto.response.ChatRoomProductResponse;
import com.codesquad.secondhand.domain.chat.dto.response.ChatSendMessageResponse;
import com.codesquad.secondhand.domain.chat.entity.ChatMessage;
import com.codesquad.secondhand.domain.chat.entity.ChatRoom;
import com.codesquad.secondhand.domain.chat.redis.RedisChatMember;
Expand All @@ -39,7 +41,7 @@ public class ChatService {
private final NotificationService notificationService;

@Transactional
public void sendMessage(MessageRequest messageRequest) {
public ChatSendMessageResponse sendMessage(MessageRequest messageRequest) {
//1. chatRoomId 가 존재하는지 검증
ChatRoom chatRoom = chatQueryService.findChatRoomByChatRoomId(messageRequest.getChatRoomId());

Expand All @@ -55,11 +57,12 @@ public void sendMessage(MessageRequest messageRequest) {
if (redisChatMembers.size() == MAX_CHAT_MEMBERS) {
// 메세지의 읽음 상태를 true 로 변경 (채팅방에 user 가 2명이기 때문에)
chatMessage.updateReadStatusToTrue();
return;
return ChatSendMessageResponse.of(chatMessage, chatRoom);
}
//SSE 재요청 알림 보내기
Long receiverId = chatRoom.findOpponentId(sender);
notificationService.refreshChatRoomList(receiverId);
return ChatSendMessageResponse.of(chatMessage, chatRoom);
}

@Transactional
Expand Down Expand Up @@ -104,7 +107,8 @@ public List<ChatRoomListResponse> getChatRoomList(Long memberId) {
.map(chatRoom -> {
ChatRoomProductResponse productResponse = mapToChatRoomProduct(chatRoom);
ChatRoomOpponentResponse opponentResponse = mapToChatRoomOpponent(chatRoom, memberId);
ChatRoomMessageResponse chatRoomMessageResponse = mapToChatRoomMessage(chatRoom, memberId);
ChatRoomMessageResponse chatRoomMessageResponse = mapToChatRoomMessage(chatRoom, memberId)
.orElseGet(() -> new ChatRoomMessageResponse());
return ChatRoomListResponse.of(chatRoom.getId(), productResponse, opponentResponse,
chatRoomMessageResponse);
}).collect(Collectors.toList());
Expand All @@ -120,11 +124,15 @@ private ChatRoomOpponentResponse mapToChatRoomOpponent(ChatRoom chatRoom, Long m
return ChatRoomOpponentResponse.of(member.getNickname(), member.getProfileImg());
}

private ChatRoomMessageResponse mapToChatRoomMessage(ChatRoom chatRoom, Long memberId) {
ChatMessage message = chatQueryService.findLastMessage(chatRoom);
private Optional<ChatRoomMessageResponse> mapToChatRoomMessage(ChatRoom chatRoom, Long memberId) {
Optional<ChatMessage> optionalMessage = chatQueryService.findLastMessage(chatRoom);
if (!optionalMessage.isPresent()) {
return Optional.empty();
}
ChatMessage message = optionalMessage.get();
Member member = findOpponentMember(chatRoom, memberId);
Long count = chatQueryService.getUnReadCount(member, chatRoom);
return ChatRoomMessageResponse.of(message, count);
return Optional.of(ChatRoomMessageResponse.of(message, count));
}

private Member findOpponentMember(ChatRoom chatRoom, Long memberId) {
Expand Down