IT/development

[jQuery] jQuery.ajax() ์‚ฌ์šฉ๋ฒ• ์˜ˆ์‹œ(feat. ๋Œ“๊ธ€ ํŽ˜์ด์ง€๋„ค์ด์…˜)

์•Œ ์ˆ˜ ์—†๋Š” ์‚ฌ์šฉ์ž 2022. 11. 21.

๋ชฉ์ฐจ

     

    jQuery .ajax() ๐Ÿ˜„

    ๋ฏธ๋ž˜์˜ ๋‚ด๊ฐ€ ๋ณด๊ธฐ ์œ„ํ•ด ๋‚จ๊ฒจ๋‘ 

    jQuery์˜ ajax ์‚ฌ์šฉ๋ฒ•๋งŒ ๊ฐ„๋‹จํžˆ ๋‚จ๊ธฐ๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ์˜ˆ์‹œ ์ฝ”๋“œ์— ์žˆ๋Š” ์ฝ”๋“œ๋“ค๋„ ๊ฐ™์ด ์ ๋Š”๊ฒŒ ์ข‹์„ ๋“ฏ ์‹ถ์–ด์„œ ๊ฐ™์ด ๋‚จ๊น€

    // ์˜ˆ์‹œ
    $.ajax({
    	// ํ˜ธ์ถœ url
        url: '/reply/insert',
        // ์ „๋‹ฌ๋ฐฉ์‹
        type: 'post',
        // dataType: "json"	// ๋ฐ์ดํ„ฐํƒ€์ž… json์œผ๋กœ ํ•  ๊ฒฝ์šฐ
        // ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ
        data: {'boardId': boardId, 'replyContent': replyContent, 'replyWriter': replyWriter},
        // ์„ฑ๊ณต ์‹œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜, ๋ฐ‘์— ์‹คํŒจ ์‹œ ์ฝœ๋ฐฑ๋„ ๋งŒ๋“ค์–ด๋„ ์ข‹๋‹ค.
        success: function (data) {
        getRelyList();
        }
    
    // ๋Œ“๊ธ€ ์กฐํšŒ ์˜ˆ์‹œ
    function getRelyList(){
        let boardId = $("#boardId").val();
        $.ajax({
        url:'/reply/list',
        type:'get',
        // ๊ฒŒ์‹œ๊ธ€์— ๋Œ€ํ•œ ๋Œ“๊ธ€ ๋ชฉ๋ก์ด๋ฏ€๋กœ boardId๋ฅผ ๋„˜๊น€ 
        // ์ด๋ ‡๊ฒŒ ์กฐํšŒํ•ด์•ผ ๋˜์„œ(SELECT * FROM reply WHERE board_id = #{boardId})
        data:{'boardId':boardId},
        success:function(data){
        // ๋Œ“๊ธ€ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ณ€์ˆ˜(์ด์ „, ๋‹ค์Œ ์กด์žฌ์—ฌ๋ถ€, ์‹œ์ž‘~๋๊ฐ’)
        let prev = data.pageMaker.prev;
        let next = data.pageMaker.next;
        let startPage = data.pageMaker.startPage;
        parseInt(startPage);
        let isPrev = startPage - 1;
        let endPage = data.pageMaker.endPage;
        parseInt(endPage);
        let isNext = endPage + 1;
    
        // console.log('prev : ' + prev + '\n' + 'next : ' + next + '\n' + 'startPage : ' + startPage + '\n' + 'endPage : ' + endPage);
        // ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์˜จ ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ $.each๋กœ ๋ฃจํ”„ ๋Œ๋ ค์„œ <div id="replyList">์—ฌ๊ธฐ์— ๋„ฃ์Œ</div>
        let replyHtml = "";
        $.each(data.replyList,function(key,value){
        replyHtml += '<div>';
        replyHtml += '<div>' + '๋Œ“๊ธ€๋ฒˆํ˜ธ:'+ value.replyId+ ' / ์ž‘์„ฑ์ž:' + value.replyWriter + ' / ์ž‘์„ฑ์ผ: ' + value.regDate;
        // click ์ด๋ฒคํŠธ์•ˆ์— parameter ๋„ฃ์„ ๋•Œ ""์•ˆ์— ''๋ฅผ ๋ถ™์—ฌ์ค˜์•ผ ํ•จ(์ด๊ฒŒ ์ฒ˜์Œ ํ•  ๋• ์€๊ทผํžˆ ์ŠคํŠธ๋ ˆ์Šค)
        replyHtml += '<button onclick="replyUpdateForm('+ value.replyId +',\'' + value.replyContent + '\');">์ˆ˜์ •</button>';
        replyHtml += '<button onclick="replyDelete(' + value.replyId + ');">์‚ญ์ œ</button></div>';
        replyHtml += '<div id="replyContentArea"><p>๋‚ด์šฉ:'+value.replyContent+'</p>';
        replyHtml += '</div>';
    });
        $("#replyList").html(replyHtml);
        // ํŽ˜์ด์ง€๋„ค์ด์…˜ ํ‘œ์‹œ
        viewPagination(boardId, prev, next, startPage, endPage, isPrev, isNext);
    }});
    }
    
    // ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ฒ˜๋ฆฌ(์–ด๋–ค ์‹์œผ๋กœ ํ•˜๋Š” ์›๋ฆฌ๋งŒ ์•Œ๊ธฐ ์œ„ํ•œ ์˜ˆ์ œ๋ผ์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•จ)
    function viewPagination(boardId, prev, next, startPage, endPage, isPrev, isNext) {
        // console.log('prev: ' + prev + '\n' + 'next: ' + next + '\n' + 'startPage: ' + startPage + '\n' + 'endPage: ' + endPage + '\n' + 'isPrev: ' + isPrev + '\n' + 'isNext: ' + isNext);
        // ํŽ˜์ด์ง€๋„ค์ด์…˜ ์˜์—ญ
        let replyPagination = "";
    	// ์ด์ „ ํŽ˜์ด์ง€
        if (prev == true) {
            replyPagination += '<li>';
            replyPagination += '<a href="/reply/list?boardId=' + boardId + '&pageNum=' + isPrev +'">' + "Prev" + '</a>';
            replyPagination += '</li>';
        }
        for (let num = startPage; num <= endPage; num++) {
            replyPagination += '<li>';
            replyPagination += '<a href="/reply/list?boardId=' + boardId + '&pageNum=' + num +'">' + num + '</a>';
            replyPagination += '</li>';
        }
        // ๋‹ค์Œ ํŽ˜์ด์ง€
        if (next == true && endPage > 0) {
            replyPagination += '<li>';
            replyPagination += '<a href="/reply/list?boardId=' + boardId + '&pageNum=' + isNext +'">' + "Next" + '</a>';
            replyPagination += '</li>';
        }
        // ํŽ˜์ด์ง€๋„ค์ด์…˜ ์˜์—ญ์„ div์— ๋ถ™์ž„
        $("#reply-pagination").html(replyPagination);
    }
    
    
    // ๋Œ“๊ธ€ ๋ฆฌ์ŠคํŠธ ์˜์—ญ
    <div class="container">
    <div id="replyList"></div>
    </div>
    
    // ๋Œ“๊ธ€ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์˜์—ญ
    <div>
    <ul id="reply-pagination" class="pagination pagination-sm no-margin pull-right"></ul>
    </div>

     

    controller

    // boardId์™€ Criteria๋ฅผ ๋ฐ›์•„์„œ ๋Œ“๊ธ€ ๋ชฉ๋ก ๋ฐ˜ํ™˜
    @GetMapping("/reply/list")
    @ResponseBody
        public Map<String, Object> replyListPaging(@RequestParam("boardId") Long boardId, Criteria cri) {
            Map<String, Object> map = new HashMap<>();
            List<ReplyVO> replyList = replyService.findReplyListPaging(boardId, cri);
            int replyCount = replyService.findCount(boardId);
            // ๋Œ“๊ธ€ ๋ชฉ๋ก
            map.put("replyList", replyList);
            // ํŽ˜์ด์ง€๋„ค์ด์…˜ ํ™”๋ฉด ์ฒ˜๋ฆฌ ๋ฐ์ดํ„ฐ
            map.put("pageMaker", new PageMaker(replyCount, cri));
            return map;
        }

     

    service

    package paging.study.service;
    
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import paging.study.domain.Criteria;
    import paging.study.domain.vo.ReplyVO;
    import paging.study.mapper.ReplyMapper;
    
    import java.util.List;
    
    @Service
    @RequiredArgsConstructor
    @Slf4j
    @Transactional(readOnly = true)
    public class ReplyService {
    
        private final ReplyMapper replyMapper;
    
    
        public List<ReplyVO> findReplyListPaging(Long boardId, Criteria cri) {
            return replyMapper.findReplyListPaging(boardId, cri);
        }
    
        public int findCount(Long replyId) {
            return replyMapper.findCount(replyId);
        }
    }

     

    mapper

    package paging.study.mapper;
    
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    import paging.study.domain.Criteria;
    import paging.study.domain.vo.ReplyVO;
    
    import java.util.List;
    
    @Mapper
    public interface ReplyMapper {
    
        List<ReplyVO> findReplyListPaging(@Param("boardId") Long boardId, @Param("cri") Criteria cri);
        int findCount(Long boardId);
    }

     

    mapper xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="paging.study.mapper.ReplyMapper">
        <resultMap id="replydMap" type="paging.study.domain.vo.ReplyVO">
            <id column="reply_id" property="replyId"/>
            <result column="board_id" property="boardId"/>
            <result column="reply_content" property="replyContent"/>
            <result column="reply_writer" property="replyWriter"/>
            <result column="reg_date" property="regDate"/>
            <result column="update_date" property="updateDate"/>
        </resultMap>
    
        <select id="findReplyListPaging" parameterType="map" resultMap="replydMap">
            SELECT * FROM t_reply
            WHERE board_id = #{boardId}
            ORDER BY reg_date DESC
            limit #{cri.limitStart}, #{cri.amount}
        </select>
    
        <select id="findCount" parameterType="Long" resultType="int">
            SELECT COUNT(*) FROM t_reply
            WHERE board_id = #{boardId}
        </select>
    </mapper>

     

    ReplyVO

    package paging.study.domain.vo;
    
    
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    
    import java.time.LocalDateTime;
    
    // ๋Œ“๊ธ€ ์šฉ๋„
    @Getter @Setter
    @ToString
    @NoArgsConstructor
    public class ReplyVO {
    
        private Long replyId;
        private Long boardId;
        private String replyContent;
        private String replyWriter;
        private LocalDateTime regDate;
        private LocalDateTime updateDate;
    
        public ReplyVO(Long boardId, String replyContent, String replyWriter) {
            this.boardId = boardId;
            this.replyContent = replyContent;
            this.replyWriter = replyWriter;
        }
    }

     

    Criteria

    package paging.study.domain;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    @Getter @Setter
    @ToString
    public class Criteria {
    
        // for paging
        private int pageNum;        // ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ(ํ˜„์žฌ ํŽ˜์ด์ง€๊ฐ€ ๋ช‡ ํŽ˜์ด์ง€์ธ์ง€)
        private int amount;         // ํ•œ ํ™”๋ฉด์— ์ถœ๋ ฅํ•œ ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜
        private int limitStart;             // ์ฟผ๋ฆฌ์—์„œ (pageNum -1) * amount ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ณ€์ˆ˜
    
        // for search
        private String title;
        private String name;
        
    	// ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์—์„œ ๊ฐ•์ œ๋กœ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์™€ ์ถœ๋ ฅ ํŽ˜์ด์ง€ ์ˆ˜ ์„ธํŒ…(ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ •์ฑ…์— ๋”ฐ๋ผ ๋ณ€๊ฒฝํ•˜๋ฉด ๋จ)
        public Criteria() {
            this(1,10);
        }
    
        public Criteria(int pageNum, int amount) {
            this.pageNum = pageNum;
            this.amount = amount;
        }
        
         // ์ฟผ๋ฆฌ์—์„œ limit 1๋ฒˆ ์งธ parameter๋กœ ์“ธ ๊ฐ’(mybatis์—์„œ ์ด getter ์ด์šฉํ•ด์„œ ๊ฐ’์„ )
        public int getLimitStart() {
            return this.limitStart = (pageNum - 1) * this.amount;
        }
    }

     

    PageMaker

    package paging.study.domain.paging;
    
    import lombok.Getter;
    import lombok.ToString;
    import paging.study.domain.Criteria;
    
    @Getter @ToString
    // ์‹ค์ œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ํ™”๋ฉด ์ฒ˜๋ฆฌ ๊ณ„์‚ฐ ๋‹ด๋‹น(๊ณตํ†ต ๋ชจ๋“ˆ)
    public class PageMaker {
        private int startPage;  //ํŽ˜์ด์ง• ํ™”๋ฉด ํ•˜๋‹จ์˜ ์‹œ์ž‘ ๋ฒˆํ˜ธ(5ํŽ˜์ด์ง€๋ผ๊ณ  ํ•˜๋ฉด [1][2][3][4][5] ์—ฌ๊ธฐ์„œ ์ œ์ผ ์ฒซ ๋ฒˆ ์งธ ์‹œ์ž‘๋ฒˆํ˜ธ์ธ [1])
        private int endPage;    //ํŽ˜์ด์ง• ํ™”๋ฉด ํ•˜๋‹จ์˜ ๋ ๋ฒˆํ˜ธ(5ํŽ˜์ด์ง€๋ผ๊ณ  ํ•˜๋ฉด [1][2][3][4][5] ์—ฌ๊ธฐ์„œ ์ œ์ผ ๋ ๋ฒˆํ˜ธ์ธ [5])
        private boolean prev, next;     // ์ด์ „, ๋‹ค์Œ ์กด์žฌ ์—ฌ๋ถ€
    
        private int totalCount;         // ์ „์ฒด ๊ฒŒ์‹œ๊ธ€ ์ˆ˜
        private Criteria cri;      // ํ”„๋ก ํŠธ์—์„œ ์ „๋‹ฌํ•˜๋Š” pageNum(ํ˜„์žฌ ํŽ˜์ด์ง€), amount(์ถœ๋ ฅ ํŽ˜์ด์ง€) ์ „๋‹ฌ ์—ญํ• 
    
        public PageMaker(int totalCount, Criteria cri) {
            this.totalCount = totalCount;
            this.cri = cri;
    		
            this.endPage = (int)(Math.ceil(cri.getPageNum() / 10.0) * 10);
            this.startPage = this.endPage - 9;
            // ์‹ค์ œ ๋ ๋ฒˆํ˜ธ
            int realEnd = (int)(Math.ceil(totalCount * 1.0) / cri.getAmount());
    
            if (realEnd < this.endPage) {
                this.endPage = realEnd;
            }
    
            this.prev = this.startPage > 1;
            this.next = this.endPage < realEnd;
        }
    }

     

    ๋Œ“๊ธ€ table

    -- ๋Œ“๊ธ€
    CREATE TABLE t_reply(
                            reply_id bigint auto_increment,
                            board_id bigint,
                            reply_content varchar (30),
                            reply_writer varchar (30),
                            reg_date timestamp,
                            update_date timestamp,
                            primary key(reply_id)
    );

    jQeury์—์„œ ajax๋ฅผ ์–ด๋–ค ์‹์œผ๋กœ ์“ฐ๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ์ž„

    to ๋ฏธ๋ž˜์˜ ๋„ˆ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค ์“ฐ์ง„ ๋ง๊ณ  ์ˆ˜์ •ํ•ด์„œ ์“ฐ๋Š”๊ฑธ ๊ถŒ์žฅํ•จ(์œ ์ง€๋ณด์ˆ˜๋‚˜ ํ™•์žฅ์„ฑ ๋“ฑ์„ ๊ณ ๋ คํ•˜๊ณ  ์ง  ์†Œ์Šค๊ฐ€ ์•„๋‹˜)

     

    ๋Œ“๊ธ€