
게시글의 우측 상단의 좋아요 버튼을 누르는 보편적인 좋아요 기능이다.
프로세스의 논리 구조는 다음과 같다.
그리고 최종적으로는 좋아요가 눌린 총합을 게시글의 우측 상단에 조회해준다.
먼저 member 테이블과 healing_message 게시판의 DB 구조는 다음과 같다.

여기서 healing_message 게시판의 좋아요 정보를 저장하는 테이블은
heaglin_message_like 테이블이다.
다른 데이터 테이블과의 연관관계를 따져보고 명령어를 설계해보자.
구현간 어려움은 없었다.
한번에 성공했다.
다만, 코드의 수가 많아서 시간이 조금 걸릴 수 밖에 없었다.
Controller -> Service -> ServiceImple -> Mapper -> XML 순서대로 프로세스가 진행이 되는데,
하나의 컨트롤러에서 시작했지만,
말단의 Mapper와 Xml에는 각각 4개의 로직이 들어가야 해서 코드를 입력하는 시간이 조금 많았을 뿐이지,
실제 논리적인 난이도는 상당히 낮았다.
/**
* 힐링 메시지 좋아요 누르기
* @param request 사용자 요청
* @param messageId 게시글 고유 번호
* @return 좋아요 누른 수
*/
@Operation(summary = " 힐링 메시지에 좋아요 누르기 API ", description = "")
@PostMapping("/like/{messageId}")
public ResponseEntity<Long> clickLike(HttpServletRequest request,
@PathVariable("messageId") Long messageId){
return ResponseEntity.ok(healingMessageService.clickLike(request,messageId));
}
/**
* 힐링 메시지 좋아요 누르기
* @param request 사용자 요청
* @param messageId 게시글 아이디
* @return 좋아요 누른 수
*/
Long clickLike(HttpServletRequest request, Long messageId);
[서비스 단에서 인터페이스와 구현체의 분리 설계]
느슨한 결합 & 코드의 유연성
구현체에 직접 의존하지 않으므로, 코드의 종속성이 줄어들고 유지보수가 쉬워집니다.
역할 분리
인터페이스 = 무엇을 구현할 것인가?
구현체 = 어떻게 구현할 것인가?
기획 변경에 대비
비즈니스 로직이 변동되더라도 interface를 통해 서비스 계층의 기본 계약(Contract)은 유지된다.
이를 통해 기존 코드를 최소한으로 수정하면서 새로운 요구사항을 반영할 수 있습니다.
/**
* 힐링 메시지 좋아요 누르기
* @param request 사용자 요청
* @param messageId 게시글 아이디
* @return 좋아요 누른 수
*/
@Override
public Long clickLike(HttpServletRequest request, Long messageId) {
/* 사용자 고유 번호 조회 */
Long userNumber = jwtService.extractUserNumberFromRequest(request);
/* 좋아요 클릭 여부 판단 */
boolean clickStatus = healingMessageMapper.checkAlreadyCliked(messageId,userNumber);
log.info("clickStatus {} ", clickStatus);
/*
* 1. 이미 좋아요를 눌렀으면 , 좋아요 취소
* 2. 좋아요가 기록이 없으면 , 좋아요 승인
* */
if(clickStatus){
healingMessageMapper.deleteLike(messageId,userNumber);
log.info("좋아요 삭제");
}else{
healingMessageMapper.permitLike(messageId,userNumber);
log.info("좋아요 추가");
}
/* 좋아요 총량 합산 */
Long likeCount = healingMessageMapper.getLikeCount(messageId);
log.info("like Count {}",likeCount);
return likeCount;
}
사용자의 고유번호 + 게시글의 고유번호를 주된 매개변수로 사용을 한다.
먼저 좋아요가 기존에 클릭되었는지를 조회하고,
참 & 거짓값에 따라서 if 문으로 다음 로직은 실행한다.
이미 좋아요를 눌렀으면 , 좋아요 취소
좋아요가 기록이 없으면 , 좋아요 승인
모든 연산이 끝나면 최종적으로 좋아요의 총합을 반환한다.
/**
* 동일한 messageId,userNumber 데이터가 있는지 확인
* @param messageId 메시지 아이디
* @param userNumber 사용자 고유 번호
* @return
*/
Boolean checkAlreadyCliked(@Param("messageId") Long messageId,
@Param("userNumber") Long userNumber);
/**
* 좋아요 취소
* @param messageId 메시지 아이디
* @param userNumber 사용자 고유 번호
*/
void deleteLike(@Param("messageId") Long messageId,
@Param("userNumber") Long userNumber);
/**
* 좋아요 승인
* @param messageId 메시지 아이디
* @param userNumber 사용자 고유 번호
*/
void permitLike(@Param("messageId") Long messageId,
@Param("userNumber") Long userNumber);
/**
* DB에서 좋아요 총량 조회
* @param messageId 메시지 아이디
* @return 총량 반환
*/
Long getLikeCount(Long messageId);
각 메서드는 최대한 본연이 역할을 잘 반영하도록 네이밍을 실시하였다.
<!-- 동일한 messageId와 userNumber 데이터 확인 -->
<select id="checkAlreadyCliked" resultType="boolean">
SELECT
IF(COUNT(*) > 0, TRUE, FALSE)
FROM
healing_message_like
WHERE
messageId = #{messageId} AND userNumber = #{userNumber}
</select>
<!-- 좋아요 취소 -->
<delete id="deleteLike">
DELETE
FROM
healing_message_like
WHERE
messageId = #{messageId} AND userNumber = #{userNumber}
</delete>
<!-- 좋아요 승인 -->
<insert id="permitLike">
INSERT INTO healing_message_like (messageId,userNumber)
VALUES (#{messageId}, #{userNumber})
</insert>
<!-- DB에서 좋아요 총량 조회 -->
<select id="getLikeCount" resultType="java.lang.Long">
SELECT
COUNT(*)
FROM
healing_message_like
WHERE
messageId = #{messageId}
</select>
200ok 성공 메시지와
좋아요를 누른 합산 = 1이 출력되었다.

아래 사진은 로그 기록이다.
한줄한줄 차례대로 설명하면,
1. 이전에 클릭 여부 = false (이번에 처음 누름)
2. 좋아요 추가 메서드 실행
3. 좋아요 총 합산 값 = 1
