Coding History

국비 지원 IT(웹앱개발) 취업반 강의 58일차 (Spring)

BlackBirdIT 2024. 8. 28. 18:37

List에서 댓글개수 확인 할 수 있게끔 코드를 짜는 것 부터 시작.

일단은 강사님이 하시는 걸 보고 만들었는데, 기존에 내가 만든 것은 댓글이 보이긴하는데 수가 맞지 않았다. 메서드를 아예 새로 만들어서 만들었는데 좀 많이 복잡한 방식이였다.

기존 코드를 적극 활용하자.

왜 계속 뭔가 새로운걸 만들어서 해결하려고 하는지 모르겠다. 강사님이 하시는거 보면 기존코드를 약간 고치거나 추가한다. 아니면 작성했던 코드를 복붙해서 메서드 이름을 바꾸거나 고친다. 이를 적극 활용하도록 노력하자.

그래서 어디를 약간 고쳤냐하면

    @Select("""
            <script>
                SELECT A.*, M.nickname AS extra__writer, //IFNULL(COUNT(R.id),0) AS extra__repliesCount
                FROM article AS A
                INNER JOIN `member` AS M
                ON A.memberId = M.id
                //LEFT JOIN `reply` AS R
                //ON A.id = R.relId
                WHERE 1
                <if test="boardId != 0">
                    AND boardId = #{boardId}
                </if>
                <if test="searchKeyword != ''">
                    <choose>
                        <when test="searchKeywordTypeCode == 'title'">
                            AND A.title LIKE CONCAT('%', #{searchKeyword}, '%')
                        </when>
                        <when test="searchKeywordTypeCode == 'body'">
                            AND A.`body` LIKE CONCAT('%', #{searchKeyword}, '%')
                        </when>
                        <when test="searchKeywordTypeCode == 'writer'">
                            AND M.nickname LIKE CONCAT('%', #{searchKeyword}, '%')
                        </when>
                        <otherwise>
                            AND A.title LIKE CONCAT('%', #{searchKeyword}, '%')
                            OR A.`body` LIKE CONCAT('%', #{searchKeyword}, '%')
                        </otherwise>
                    </choose>
                </if>
                //GROUP BY A.id
                ORDER BY A.id DESC
                <if test="limitFrom >= 0">
                    LIMIT #{limitFrom}, #{limitTake}
                </if>
                </script>
            """)
    public List<Article> getForPrintArticles(int boardId, int limitFrom, int limitTake, String searchKeywordTypeCode,
            String searchKeyword);

이렇게 각주 처리된 부분이 새로 들어온 부분이다 난 이걸 새로 만들어서 해결하려고 했다.

댓글 수정 삭제도 마찬가지로 기존의 게시물 수정 삭제 기능에서 복붙해와서 변수나 이름을 바꾸는 것으로 해결하셨다.

일단 난 이렇게 했고,

코드는 article의 수정 삭제 권한을 긁어와서 수정하고 쿼리메서드를 조금 고치는 정도였다.

    public List<Reply> getForPrintReplies(int loginedMemberId, String relTypeCode, int id) {
        List<Reply> replies = replyRepository.getForPrintReplies(loginedMemberId, relTypeCode, id);

        for (Reply reply : replies) {
            controlForPrintData(loginedMemberId, reply);
        }

        return replies;
    }
//////
    public ResultData userCanDelete(int loginedMemberId, Reply reply) {
        if (reply.getMemberId() != loginedMemberId) {
            return ResultData.from("F-2", Ut.f("%d번 댓글에 대한 삭제 권한이 없습니다", reply.getId()));
        }
        return ResultData.from("S-1", Ut.f("%d번 댓글을 삭제했습니다", reply.getId()));
    }

    public ResultData userCanModify(int loginedMemberId, Reply reply) {
        if (reply.getMemberId() != loginedMemberId) {
            return ResultData.from("F-2", Ut.f("%d번 댓글에 대한 수정 권한이 없습니다", reply.getId()));
        }
        return ResultData.from("S-1", Ut.f("%d번 댓글을 수정했습니다", reply.getId()), "수정된 댓글", reply);
    }

이렇게 처리했는데 쓴 부분은 객체로 댓글 저장할 때의 로직을 loginedMemberId로 검증하는 과정만 거친게 끝이다. 나머지는 아까 말 했듯, 복붙해와서 약간 고쳤다.


Ajax 기초

0> 재료 준비 (페이지, 메서드 등)
1> 페이지를 보게 해주는 역할.
2> 페이지 없이 기능만 실행해주는 역할
3> JS 함수를 부를 수 있게 만들어주기.
4> from 태그를 부를 수 있게 name 설정 및 변수 저장. (input 데이터의 value의 출처 파악하면서)
5> 구현하려는 기능에 따라 type을 바꿔줌. ex> submit, button

@Controller
public class UsrAjaxTestController {

    @RequestMapping("/usr/home/plus")
    public String showTestPage() {
        return "/usr/home/AjaxTest";
    }

    @RequestMapping("/usr/home/doPlus")
    @ResponseBody
    public String doPlus(int num1, int num2) {
        String msg = "더하기 성공!";

        int rs = num1 + num2;

        return rs + "/" + msg + "/S-1";
    }

    @RequestMapping("/usr/home/doPlusJson")
    @ResponseBody
    public Map<String, Object> doPlusJson(int num1, int num2) {
        Map<String, Object> rs = new HashMap<>();

        rs.put("rs", num1 + num2);
        rs.put("msg", "더하기 성공! (map)");
        rs.put("code", "S-1 (map)");

        return rs;
    }

}
</style>
<!-- 제이쿼리 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    function callByAjax() {
        let form = document.form1;
        let num1 = form.num1.value;
        let num2 = form.num2.value;
        let action = form.action;
        $.get(action, {
            num1 : num1,
            num2 : num2
        }, function(data) {
            $('.rs').text(data);
        }, 'html');
    }
    function callByAjaxV2() {
        let form = document.form1;
        let num1 = form.num1.value;
        let num2 = form.num2.value;
        let action = form.action;
        $.get(action, {
            num1 : num1,
            num2 : num2
        }, function(data) {
            data = data.split('/');
            let rs = data[0];
            let msg = data[1];
            $('.rs').text(rs);
            $('.rs-msg').text(msg);
        }, 'html');
    }
    function callByAjaxV3() {
        let form = document.form1;
        let num1 = form.num1.value;
        let num2 = form.num2.value;
        let action = form.action;
        $.get(action, {
            num1 : num1,
            num2 : num2
        }, function(data) {
            data = data.split('/');
            let rs = data[0];
            let msg = data[1];
            let code = data[2];
            $('.rs').text(rs);
            $('.rs-msg').text(msg);
            $('.rs-code').text(code);
        }, 'html');
    }
    function callByAjaxV4() {
        let form = document.form1;
        let num1 = form.num1.value;
        let num2 = form.num2.value;
        $.get('./doPlusJson', {
            num1 : num1,
            num2 : num2
        }, function(data) {
            $('.rs').text(data.rs);
            $('.rs-msg').text(data.msg);
            $('.rs-code').text(data.code);
        }, 'json');
    }
</script>
</head>
<body>
    <h1>AjaxTest</h1>

    <form name="form1" method="POST" action="./doPlus">
        <div>
            <input type="text" name="num1" placeholder="정수 1 입력" />
        </div>
        <div>
            <input type="text" name="num2" placeholder="정수 2 입력" />
        </div>
        <input type="submit" value="더하기 v1" />
        <input onclick="callByAjax();" type="button" value="더하기 v2" />
        <input onclick="callByAjaxV2();" type="button" value="더하기 v3" />
        <input onclick="callByAjaxV3();" type="button" value="더하기 v4" />
        <input onclick="callByAjaxV4();" type="button" value="더하기 v5" />
    </form>

    <h2>더한 결과</h2>
    <div class="rs"></div>
    <h2>더한 결과 메세지</h2>
    <div class="rs-msg"></div>
    <h2>더한 결과 코드</h2>
    <div class="rs-code"></div>
</body>
</html>

ajax를 계속 사용은 했지만 근본적으로 이 코드가 어떻게 돌아가는지에 대해서는 제대로 파악하지 못한채로 사용중이였다. 간단한 로직으로 이를 설명해주는 코드다.

댓글 수정 기능을 보면서 한번 더 톺아보자.

<script>
function toggleModifybtn(replyId) {

    console.log(replyId);

    $('#modify-btn-'+replyId).hide();
    $('#save-btn-'+replyId).show();
    $('#reply-'+replyId).hide();
    $('#modify-form-'+replyId).show();
}
function doModifyReply(replyId) {
     console.log(replyId); // 디버깅을 위해 replyId를 콘솔에 출력

        // form 요소를 정확하게 선택
        var form = $('#modify-form-' + replyId);
        console.log(form); // 디버깅을 위해 form을 콘솔에 출력
        // form 내의 input 요소의 값을 가져옵니다
        var text = form.find('textarea[name="reply-text-' + replyId + '"]').val();
        console.log(text); // 디버깅을 위해 text를 콘솔에 출력
        // form의 action 속성 값을 가져옵니다
        var action = form.attr('action');
        console.log(action); // 디버깅을 위해 action을 콘솔에 출력

    $.post({
        url: '/usr/reply/doModify', // 수정된 URL
        type: 'POST', // GET에서 POST로 변경
        data: { id: replyId, body: text }, // 서버에 전송할 데이터
        success: function(data) {
            $('#modify-form-'+replyId).hide();
            $('#reply-'+replyId).text(data);
            $('#reply-'+replyId).show();
            $('#save-btn-'+replyId).hide();
            $('#modify-btn-'+replyId).show();
        },
        error: function(xhr, status, error) {
            alert('댓글 수정에 실패했습니다: ' + error);
        }
    })
}
</script>

일단은 JS코드고,

<div class="comments-section">
    <c:if test="${rq.isLogined()}">
        <form action="/usr/reply/doWrite" method="post" class="comment-form">
            <input type="hidden" name="relTypeCode" value="article">
            <input type="hidden" name="relId" value="${article.id}">
            <textarea name="body" placeholder="댓글을 입력하세요" required></textarea>
            <div class="comment-form-actions">
                <button type="submit">댓글 작성</button>
            </div>
        </form>
    </c:if>

    <c:if test="${!rq.isLogined()}">
        <p>댓글 작성 <a href="/usr/member/login" class="btn">로그인</a> 필요.</p>
    </c:if>
    <h3>Comments</h3>
    <c:forEach var="reply" items="${replies}">
        <div class="comment-item">
            <span class="comment-author">Member ID: ${reply.extra__writer}</span>
            <span class="comment-date">${reply.regDate}</span>
            <p id="reply-${reply.id}" class="comment-body">${reply.body}</p>

            <!-- 수정 버튼 -->
            <c:if test="${reply.userCanModify}">
                <button id="modify-btn-${reply.id}" onclick="toggleModifybtn(${reply.id})" class="btn btn-outline btn-xs btn-success">수정</button>
            </c:if>

            <!-- 삭제 버튼 -->
            <c:if test="${reply.userCanDelete}">
                <a class="btn btn-outline btn-xs btn-error" onclick="if(confirm('정말 삭제?') == false) return false;" href="../reply/doDelete?id=${reply.id}">삭제</a>
            </c:if>

            <!-- 댓글 수정 폼 -->
            <div id="modify-form-${reply.id}" class="comment-modify-form" style="display: none;">
                <input type="hidden" name="reply-id" value="${reply.id}">
                <textarea name="reply-text-${reply.id}" rows="3">${reply.body}</textarea>
                <button type="button" onclick="doModifyReply(${reply.id})" id="save-btn-${reply.id}" class="btn btn-outline btn-xs btn-primary">저장</button>
            </div>
        </div>
    </c:forEach>
</div>

이게 화면을 구성하는 코드다.

보면 요소를 선택하기 위한 id나 가져 올 데이터, 등이 잘 결합되어있다. 디버깅을 위해서 꾸준히 콘솔에 찍고 확인하는 코드도 존재하고 수정 이후에 다시 원래 상태로 돌려놓기 위한 코드도 존재한다. 적재적소에 코드를 꾸리고 데이터를 보내고 받고를 해서 비동기 코드를 완성시키는데, 이해보다는 어떻게 사용하는지에 집중해서 다른데 계속 써먹어봐야될 것 같다.

코드를 살펴보는 와중에 var text = form.find('textarea[name="reply-text-' + replyId + '"]').val(); 해당 줄에서 .val();이게 뭔지 궁금해서 찾아봤는데,

val()은 양식(form)의 값을 가져오거나 값을 설정하는 메서드 라고 한다.
제이쿼리다.

아무튼 이해보단 사용법에 익숙해지자..

삭제도 비슷하게 꾸리면 될 것 같고, ajax를 활용해서 네이버처럼 doJoin을 비동기로 처리하는 것도 해볼 수 있다. 있는 아이디 검증 등...

이후 API 사용 방법에 대한 기초적인 것들을 배웠다.

API는 따로 빼서 포스팅하도록 하겠다.