Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: # 어떤 이벤트와 브랜치에서 트리거 될건지
# push:
# branches: [ "main" ]
pull_request:
branches: [ "main", "dev" ]
branches: [ "deploy", "main", "dev" ]

jobs:
build:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.dangsim.chat.controller;

import java.security.Principal;

import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.stereotype.Controller;
Expand All @@ -21,10 +19,10 @@ public class ChatMessageStompController {
@MessageMapping("/chat-rooms/{chatRoomId}")
public void createChatMessage(
@DestinationVariable Long chatRoomId,
Principal principal,
@Valid CreateChatMessageRequest request
) {
Long userId = Long.valueOf(principal.getName());

Long userId = request.senderId();
chatMessageService.createChatMessage(request, userId, chatRoomId);
}

Expand Down
9 changes: 5 additions & 4 deletions src/main/java/com/dangsim/chat/dto/ChatRoomMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ public static TaskInfoResponse toTaskInfoResponse(Task task) {
}

public static ChatRoomInfoResponse toChatRoomInfoResponse(Long chatRoomId, User chatPartner,
TaskInfoResponse taskInfoResponse) {
TaskInfoResponse taskInfoResponse, Long userId) {
return new ChatRoomInfoResponse(
chatRoomId,
taskInfoResponse,
chatPartner.getId(),
chatPartner.getNickname()
chatPartner.getNickname(),
userId
);
}

Expand All @@ -56,9 +57,9 @@ public static String getThumbNail(List<TaskImage> imageUrls) {

public static boolean isCompletedTask(Task task) {
if (Objects.equals(task.getStatus(), TASK_COMPLETE)) {
return false;
return true;
}
return true;
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public record CreateChatMessageRequest(
MessageType type,
@Size(max = 300, message = "최대 300자까지 입력이 가능합니다.")
@NotBlank
String content
String content,
@NotNull
Long senderId
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public record ChatRoomInfoResponse(
Long chatRoomId,
TaskInfoResponse taskInfo,
Long chatPartnerId,
String partnerNickname
String partnerNickname,
Long myId
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.dangsim.chat.dto.response;

import java.util.Objects;

import com.dangsim.chat.entity.ChatMessage;
import com.dangsim.chat.entity.ChatRoom;
import com.dangsim.common.util.DateTimeFormatUtils;
Expand All @@ -12,7 +14,8 @@ public record ChatRoomSimpleResponse(
String nickname,
String content,
String timestamp,
Boolean isRead
Boolean isRead,
Long chatMessageId

) {
@QueryProjection
Expand All @@ -21,9 +24,35 @@ public ChatRoomSimpleResponse(ChatRoom chatRoom, ChatMessage lastChatMessage, Us
chatRoom.getId(),
partner.getId(),
partner.getNickname(),
lastChatMessage.getMessage(),
DateTimeFormatUtils.formatDateTime(lastChatMessage.getCreatedAt()),
lastChatMessage.isRead()
initChatMessage(lastChatMessage),
initTimeStamp(lastChatMessage),
initIsRead(lastChatMessage),
lastChatMessage.getId()
);
}

private static final String DEFAULT = "채팅을 시작해보세요";

public static String initChatMessage(ChatMessage lastChatMessage) {
if (Objects.isNull(lastChatMessage)) {
return DEFAULT;
}
return lastChatMessage.getMessage();
}

public static String initTimeStamp(ChatMessage lastChatMessage) {
if (Objects.isNull(lastChatMessage)) {
return "";
}
return DateTimeFormatUtils.formatDateTime(lastChatMessage.getCreatedAt());
}

public static Boolean initIsRead(ChatMessage lastChatMessage) {
if (Objects.isNull(lastChatMessage)) {
return false;
}
return lastChatMessage.isRead();
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,26 @@ public class ChatRoomQueryRepositoryImpl implements ChatRoomQueryRepository {
private final JPAQueryFactory queryFactory;

@Override
public CursorPageResponse<ChatRoomSimpleResponse> findChatRoomsByCursor(String cursor, int size, Long userId) {
public CursorPageResponse<ChatRoomSimpleResponse> findChatRoomsByCursor(
String cursor, int size, Long userId) {

QChatMessage lastMessage = new QChatMessage("lastMessage");
QUser partner = new QUser("partner");

BooleanExpression isRequester = chatRoom.requester.id.eq(userId)
.and(partner.id.eq(chatRoom.performer.id));
BooleanExpression isPerformer = chatRoom.performer.id.eq(userId)
.and(partner.id.eq(chatRoom.requester.id));
BooleanExpression partnerJoinCondition = isRequester.or(isPerformer);

BooleanExpression cursorFilter = null;
if (cursor != null && !cursor.isBlank()) {
cursorFilter = lastMessage.id.lt(Long.parseLong(cursor));
}

List<ChatRoomSimpleResponse> chatRooms = queryFactory
.select(new QChatRoomSimpleResponse(chatRoom, lastMessage, partner))
.from(chatRoom)
//최근 메시지 조인
.leftJoin(lastMessage)
.on(lastMessage.chatRoomId.eq(chatRoom.id),
lastMessage.id.eq(
Expand All @@ -50,17 +61,14 @@ public CursorPageResponse<ChatRoomSimpleResponse> findChatRoomsByCursor(String c
.from(chatMessage)
.where(chatMessage.chatRoomId.eq(chatRoom.id))
))
//상대방 유저 조인
.leftJoin(partner)
.on(
chatRoom.requester.id.eq(userId).and(partner.id.eq(chatRoom.performer.id))
.or(chatRoom.performer.id.eq(userId).and(partner.id.eq(chatRoom.requester.id)))
)
.on(partnerJoinCondition)
.where(
chatRoom.requester.id.eq(userId).or(chatRoom.performer.id.eq(userId)),
isBeforeCursor(lastMessage.createdAt, cursor)
chatRoom.requester.id.eq(userId)
.or(chatRoom.performer.id.eq(userId)),
cursorFilter
)
.orderBy(lastMessage.createdAt.desc())
.orderBy(lastMessage.id.desc())
.limit(size + 1)
.fetch();

Expand All @@ -74,27 +82,43 @@ public CursorPageResponse<ChatRoomSimpleResponse> findChatRoomsByCursor(String c
@Override
public CursorPageResponse<ChatRoomDetailResponse> findChatMessagesByCursor(Long chatRoomId, String cursor, int size,
Long userId) {

List<ChatMessageDetailResponse> allMessages = queryFactory
.select(new QChatMessageDetailResponse(chatMessage))
.from(chatMessage)
.where(
chatMessage.chatRoomId.eq(chatRoomId),
isBeforeCursor(chatMessage.createdAt, cursor)
chatMessageCursorFilter(cursor)
)
.orderBy(chatMessage.createdAt.desc())
.orderBy(chatMessage.id.desc())
.limit(size + 1)
.fetch();

boolean hasNext = allMessages.size() > size;
List<ChatMessageDetailResponse> pageMessages = subLastPage(allMessages, hasNext);
String nextCursor = getNextCursorByMessage(pageMessages, hasNext);
System.out.println("nextCursor = " + nextCursor);

ChatRoomDetailResponse detailResponse = new ChatRoomDetailResponse(chatRoomId, pageMessages);

return new CursorPageResponse<>(Collections.singletonList(detailResponse), nextCursor, hasNext);
}

private BooleanExpression chatRoomCursorFilter(String cursor) {
if (Objects.isNull(cursor) || cursor.isBlank()) {
return null;
}

return chatRoom.id.lt(Long.parseLong(cursor));
}

private BooleanExpression chatMessageCursorFilter(String cursor) {
if (Objects.isNull(cursor) || cursor.isBlank()) {
return null;
}

return chatMessage.id.lt(Long.parseLong(cursor));
}

private BooleanExpression isBeforeCursor(DateTimePath<LocalDateTime> dateTimePath, String cursor) {
if (cursor == null) {
return null;
Expand All @@ -106,14 +130,14 @@ private String getNextCursor(List<ChatRoomSimpleResponse> chatrooms, boolean has
if (Objects.isNull(chatrooms) || chatrooms.isEmpty() || !hasNext) {
return null;
}
return chatrooms.get(chatrooms.size() - 1).timestamp();
return String.valueOf(chatrooms.get(chatrooms.size() - 1).chatMessageId());
}

private String getNextCursorByMessage(List<ChatMessageDetailResponse> messages, boolean hasNext) {
if (Objects.isNull(messages) || messages.isEmpty() || !hasNext) {
return null;
}
return messages.get(messages.size() - 1).timeStamp();
return String.valueOf(messages.get(messages.size() - 1).messageId());
}

private <T> List<T> subLastPage(List<T> list, boolean hasNext) {
Expand Down
13 changes: 2 additions & 11 deletions src/main/java/com/dangsim/chat/service/ChatRoomService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.dangsim.chat.service;

import java.time.LocalDateTime;
import java.util.Objects;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -17,7 +14,6 @@
import com.dangsim.chat.repository.ChatRoomRepository;
import com.dangsim.common.CursorPageResponse;
import com.dangsim.common.exception.runtime.BaseException;
import com.dangsim.common.util.DateTimeFormatUtils;
import com.dangsim.task.dto.response.TaskInfoResponse;
import com.dangsim.task.entity.Task;
import com.dangsim.task.exception.TaskErrorCode;
Expand Down Expand Up @@ -51,18 +47,13 @@ public ChatRoomResponse createChatRoom(@Valid CreateChatRoomRequest request, Use

@Transactional(readOnly = true)
public CursorPageResponse<ChatRoomSimpleResponse> getChatRoomsByCursor(String cursor, int size, Long userId) {
if (Objects.isNull(cursor) || cursor.isBlank()) {
cursor = DateTimeFormatUtils.formatDateTime(LocalDateTime.now());
}

return chatRoomRepository.findChatRoomsByCursor(cursor, size, userId);
}

public CursorPageResponse<ChatRoomDetailResponse> getChatMessagesByCursor(Long chatRoomId, String cursor, int size,
Long userId) {
if (Objects.isNull(cursor) || cursor.isBlank()) {
cursor = DateTimeFormatUtils.formatDateTime(LocalDateTime.now());
}

return chatRoomRepository.findChatMessagesByCursor(chatRoomId, cursor, size, userId);
}

Expand All @@ -84,7 +75,7 @@ public ChatRoomInfoResponse getChatRoomInfo(Long chatRoomId, Long userId) {
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));

return ChatRoomMapper.toChatRoomInfoResponse(chatRoomId, chatPartner,
taskInfoResponse);
taskInfoResponse, userId);

}
}
2 changes: 1 addition & 1 deletion src/main/java/com/dangsim/common/config/CorsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
// }
// };
// }
// }
// }
13 changes: 12 additions & 1 deletion src/main/java/com/dangsim/common/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
Expand All @@ -21,6 +22,14 @@
@EnableWebSecurity
public class SecurityConfig {

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring()
.requestMatchers(
"/error", "/favicon.ico", "/ws/**"
);
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, JwtProvider jwtProvider,
UserRepository userRepository) throws Exception {
Expand All @@ -32,6 +41,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, JwtProvider jwtProvide
// .anyRequest().permitAll()
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers(HttpMethod.GET, "/api/tasks").permitAll()
.requestMatchers("/ws-chat/**").permitAll()
.requestMatchers(
"/swagger-ui/**",
"/v3/api-docs/**",
Expand All @@ -53,7 +63,8 @@ public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(
"http://localhost:3000",
"https://dangsim-fe.pages.dev"
"https://dangsim-fe.pages.dev",
"/ws/**"
));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
configuration.setAllowedHeaders(List.of("*"));
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/dangsim/common/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-chat") //웹소켓 연결 주소
.setAllowedOriginPatterns("*") //cors 허용
.withSockJS();
.setAllowedOrigins("http://localhost:3000"); //cors 허용
// .withSockJS();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public Message<?> preSend(Message<?> message, MessageChannel channel) {
Long userId = jwtProvider.getUserIdFromToken(token);
Principal principal = () -> String.valueOf(userId);
accessor.setUser(principal);
accessor.setLeaveMutable(true);
}
return message;
}
Expand Down
Loading