담배200 프로젝트의 소켓 통신에선, 클라이언트와 서버의 원활한 통신을 위해 특정 정보(요청 사용자 id, 응답 해줄 채널)가 모든 소켓 요청마다 필요해졌습니다. 기존 HTTP방식에서 소켓 통신으로 넘어가기 위해 해당 필드가 추가된 DTO를 따로 만들면, 기존 HTTP용 DTO와 코드중복이며 비효율적이라고 생각했습니다. 무엇보다 그 DTO를 그대로 서비스 레이어으로 넘기게 되면, 서비스 코드가 컨트롤러에서 요구하는 형태에 종속되는 문제가 있다고 생각됐습니다.
그래서 소켓통신에 필수적인 필드가 존재하는 소켓통신용 DTO를 만들었고, 기존 HTTP용 요청, 응답 DTO를 소켓 통신 용 DTO로 wrapping함으로써, 서비스 코드가 컨트롤러에서 요구하는 형태에 종속되지 않는 구조를 취했습니다.
덕분에 소켓용 DTO나 서비스코드를 따로 만들지 않고서 통신방법을 HTTP에서 STOMP로 변경할 수 있었습니다. 만약 언젠가 소켓 요청 API들의 통신방식이 HTTP로 바뀐다고해도, Service 코드의 추가나 수정 없이 HTTP용 Controller만 추가하면 작동할 수 있게되었습니다.
SocketRequest
public class SocketRequest<T> {
@NonNull
Long requestUserId;
@NonNull
String responseChannel;
T content;
}
SocketMessage(Response 격)
public class SocketMessage<T> {
Long requestUserId;
T content;
}
Service로 넘길 땐 getContent()해서 Service에 필요한 정보만 넘김
@MessageMapping("/store/add_cigar")
public void addCigaretteOnListById(Principal principal, @Payload @Valid final SocketRequest<CigaretteOnListAddRequest> request) {
final String destination = "/sub/store/" + request.getContent().getStoreId() + "/add_cigar";
final CigaretteOnListGetResponse response = cigaretteOnListUpdateService.addCigaretteOnList(request.getContent());
final StandardResponse<SocketMessage<CigaretteOnListGetResponse>> message = StandardResponse.ok(new SocketMessage<>(request.getRequestUserId(), response));
template.convertAndSend(destination, message);
}