Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

우리마의 웹 개발

[Spring]게시판 글 상세보기에서 '좋아요' 처리 로직 정리 본문

WEB/Spring

[Spring]게시판 글 상세보기에서 '좋아요' 처리 로직 정리

우리마 2020. 9. 14. 16:37

Spring환경에서 게시판으로 개발 연습을 하면서 게시글에 대해서 해당 글의 '좋아요' 처리에 대한 개인적인 로직을 정리하고자 한다. 지극히 주관적인 로직과 코딩이라서 상당히 하드 할 수 있다.

지적사항, 더좋은 방법 등 댓글 환영

 

개발 환경
Spring Framework 5.2.3
Tomcat 8.0
DB MySql8 , MyBatis3.5
Browser Chrome
IDE STS 3.9.11

 

DB '좋아요' 테이블 구조

bbsidx와 useridx는 각각 게시글 테이블과 사용자 테이블의 일련번호를 외래 키로 사용하고 있다.

게시글을 본 사용자에 대해서 '좋아요'를 처리하기 위함이다.

게시글 상세보기 페이지 최초 접속시 처리 프로세스

 

'좋아요'버튼 (하트) 눌렀을때 처리 프로세스

 

 

게시글 상세보기 페이지 접속 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 
/* Controller */
//게시글 상세보기 detail
@RequestMapping("/communityDetail")
public String communityDetail(@RequestParam int idx, Model model,HttpServletRequest request,HttpServletResponse response, HttpSession session){
    logger.info("request: /communityDetail");
    Map<String,Object> resultMap = null;
    Map<String,Object> idxMap = new HashMap<>();
    int bbsidx = idx;
    int useridx = 0;
            /* 생략 */
 
    try {
        Map<String,Object> userInfo = (Map<String, Object>) session.getAttribute("userInfo");
        useridx = Integer.parseInt(userInfo.get("idx").toString());
        
            /* 생략 */
        resultMap = service.communityDetail(bbsidx); // 게시판 상세정보 가져옴
        idxMap.put("bbsidx", bbsidx);
        idxMap.put("useridx", useridx);
 
        Map<String,Object> likecheckMap = service.likecheck(idxMap);
        //like 테이블 에서 사용자가 해당 게시글에 대해서 좋아요를 눌렀는지 확인
        if(likecheckMap == null) {
//사용자가 좋아요를 한번도 누른적이 없으면
//like테이블에 데이터가 없으므로 null반환
            model.addAttribute("likecheck",0);
        }
        else {
            model.addAttribute("likecheck",likecheckMap.get("likecheck"));
        }
 
        model.addAttribute("likecnt",resultMap.get("likecnt"));
model.addAttribute("bbsidx",bbsidx);
model.addAttribute("useridx",useridx);
                /* 생략 */
    } catch (Exception e) {
        logger.debug(e.getMessage());
    }
    return "communityDetail";
}
 
/* SQL.xml */
<select id="communityDetail" resultType="map">
    SELECT 
        //생략
       , bbs.likecnt as likecnt
        //생략
    from 
        training_bbs bbs
    where 1=1 
    and bbs.idx = #{idx}
</select>
 
<!-- 좋아요 눌렀는지 여부 확인 -->
<select id="likecheck" resultType="map">
    select likecheck 
    from training_like 
    where bbsidx=#{bbsidx} 
      and useridx=#{useridx}
</select>
 
/* communityDetail.jsp */
<c:choose>
    <c:when test="${likecheck eq '0' or empty likecheck}"> <!-- likecheck가0이면 빈하트-->
        <img src="/home/img/ico_like_before.png" 
             id="btn_like" align="left" style="cursor:pointer; width: 20px;">
    </c:when>
    <c:otherwise> <!-- likecheck가1이면 빨간 하트-->
        <img src="/home/img/ico_like_after.png" 
              id="btn_like" align="left" style="cursor:pointer; width: 20px;">
    </c:otherwise>
</c:choose>
<dd id="likecnt" style="margin-left:5px;">${likecnt}</dd>
cs
 
 
 

communityDetail이 호출되었을 때 먼저 Controller에서 접속 중인 사용자에 대한 정보를 session에 등록된 정보 즉, userInfo에 있는 정보에서 사용자의 일련번호 (useridx)를 가져오고 communityDetail에 호출될때 파라미터로 해당 게시글의 일련번호(bbsidx)를 받는다. 이 두가지 값을 이용해서 해당 게시글에 사용자가 '좋아요'를 누른적있는지 없는지 확인한다.( 21번줄)  한번도 누른 적이 없으면 like테이블 조회 결과가 없으므로 null값이 들어갈 것이기 때문에 model로 jsp에 넘길 때 0을 담고(jsp에서 빈 하트 출력) 한 번이라도 누른 적이 있으면 like테이블의 likecheck 칼럼 값을 model에 담아 jsp로 넘긴다.

게시글의 좋아요 개수(likecnt) 값은 게시글 테이블에 값이 있다.

 

'좋아요'버튼(하트) 눌렀을때 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/* JSP SCRIPT */
var
 bbsidx = ${bbsidx};
var useridx = ${useridx};
 
var btn_like = document.getElementById("btn_like");
 btn_like.onclick = function(){ changeHeart(); }
 
/* 좋아요 버튼 눌렀을떄 */
 function changeHeart(){ 
     $.ajax({
            type : "POST",  
            url : "/clickLike",       
            dataType : "json",   
            data : "bbsidx="+bbsidx+"&useridx="+useridx,
            error : function(){
                Rnd.alert("통신 에러","error","확인",function(){});
            },
            success : function(jdata) {
                if(jdata.resultCode == -1){
                    Rnd.alert("좋아요 오류","error","확인",function(){});
                }
                else{
                    if(jdata.likecheck == 1){
                        $("#btn_like").attr("src","/home/img/ico_like_after.png");
                        $("#likecnt").empty();
                        $("#likecnt").append(jdata.likecnt);
                    }
                    else if (jdata.likecheck == 0){
                        $("#btn_like").attr("src","/home/img/ico_like_before.png");
                        $("#likecnt").empty();
                        $("#likecnt").append(jdata.likecnt);
                        
                    }
                }
            }
        });
 }
 
/* Controller */
    //좋아요 눌렀을때
    @RequestMapping("/clickLike")
    @ResponseBody
    public Map<String,Object> clickLike(@RequestParam Map<String,Object> commandMap){
        logger.info("request: /clickLike");
        int resultCode = 1;
        int likecheck = 1;
        Map<String,Object> map = new HashMap<>();
        Map<String,Object> likecntMap = new HashMap<>();
        Map<String,Object> resultMap = new HashMap<>();
        try {
            map = service.likecheck(commandMap);
            if(map == null) {
                //처음 좋아요 누른것 likecheck=1, 좋아요 빨간색이 되야됨
                service.insertLikeBtn(commandMap); //좋아요 테이블 인서트
                service.updateLikeCntPlus(commandMap); //bbs 테이블 업데이트 +1
                resultCode = 1;
            }
            else if(Integer.parseInt(map.get("likecheck").toString()) == 0) {
                //좋아요 처음은 아니고 취소했다가 다시 눌렀을때 likecheck=1, 좋아요 빨간색 되야됨
                commandMap.put("likecheck",likecheck);
                service.updateLikeCheck(commandMap); //좋아요 테이블 업데이트
                service.updateLikeCntPlus(commandMap); // bbs테이블 +1
                resultCode = 1;
            }
            else {
                //좋아요 취소한거 likecheck=0, 빈하트 되야됨
                likecheck = 0;
                commandMap.put("likecheck", likecheck);
                service.updateLikeCheck(commandMap);
                service.updateLikeCntMinus(commandMap);
                resultCode = 0;
            }
            resultMap = service.getLikeCnt(commandMap); 
            // 해당 게시글 테이블의 likecnt칼럼  update가 끝난후 likecnt값 가져옴
            resultMap.put("likecheck", likecheck);
        } catch (Exception e) {
            logger.debug(e.getMessage());
            resultCode = -1;
        }
        
        resultMap.put("resultCode", resultCode);
        //resultCode가 1이면 빨간하트 0이면 빈하트
        return resultMap;
    }
cs

communityDetail.jsp 에서 script로 하트 버튼 이벤트를 등록하고 ajax를 통해 Controller로 bbsidx와 useridx를 파라미터로 넘겨준다. 이에 따라서 resultCode 값을 통해 '좋아요'를 눌렀는지 '좋아요 취소'를 했는지 확인할 수 있고, 빈 하트 또는 빨간 하트를 출력한다.

Controller에서 각각의 경우에 따라서 Service를 태우고 resultCode 값을 정한다 위에 있는 FlowChart와 주석 설명을 참조 바란다.

 

화면

최초 접속 또는 '좋아요' 취소한 모습
'좋아요 ' 누른 모습

처음에 로직을 생각할때 사용자가 해당 글에 대해서 '좋아요'를 누른 적 있는지 없는지, '좋아요'를 누른 적은 있는데 취소를 한 것인지 '좋아요'누른 상태 인지 등등 이런 경우들을 어떻게 구별하는지 고민을 많이 했는데  필자가 좀 어렵게 생각한 면도 있는 거 같고 지금 와서 봐도 상당히 하드코딩 느낌이 난다...  

댓글로 더좋은 방법, 지적 환영합니다..

 

즐겁지 않은 즐거운 코딩 하세요.

Comments