본문 바로가기

Spring boot/3차 프로젝트 중 알게 된 것!

[3차 프로젝트]Ajax로 DB에 있는 게시판 목록 끌어오기

Ajax로 DB에 있는 게시판 목록 끌어오기를 해보았다. 왔다 갔다하는게 이해가 잘 안됐었는데 까먹지 않기 위해 기록!

 

이 화면에서 저 버튼을 눌렀을 때 각각 타입별 게시판이 목록에 나타나게 하는게 목표이다.

게시판은 추가 수정될 수 있으니 DB에서 값을 끌어와야 변한 내용이 그때그때 화면에 출력 될 것 이다.


 

 

header.html 전문

<header class="py-3 mb-4 border-bottom">
    <div class="container">
        <div>
            <a class="logo" href="/">
                <img alt="사이트 로고" class="logo me-5" th:src="@{/img/logo.png}">
            </a>

            <ul id="menu-box">
                <li>
                    <a class="nav-link px-2 link-dark"  onclick="boardListAjax('review')"  href="#">숙소리뷰</a>
                    <ul class="dropdown-menu text-small" id="dropdown-box-review" style="display: block;"></ul>
                </li>
                <li class="dropdown">
                    <a  href="#" id="dropdownBoard1" onclick="boardListAjax('basic')">숙소톡톡</a>
                    <ul class="dropdown-menu  text-small" id="dropdown-box-basic" style="display: block;"></ul>
                </li>
            </ul>
            <script>


                //******Type별 게시판 목록 조회*******//
                function boardListAjax(type) {
                    const getListAjax = function (type) {
                        return new Promise((resolve, reject) => {
                            $.ajax({
                                url: '/loadboardtype',
                                method: 'POST',
                                dataType: 'json',
                                data: {
                                    type: type
                                },
                                success: function (data) {
                                    resolve(data);
                                },
                                error: function (e) {
                                    reject(e);
                                }
                            });
                        });

                    };
                    async function listRequestProcess(type) {
                        try {
                            const boardList = await getListAjax(type);
                            var htmlStr = '';
                            console.log(boardList);
                            console.log(boardList.length);
                            if (boardList.length == 0) {
                                htmlStr += `<li class='dropdown-item'>게시판이 없습니다.</li>`;
                            } else {
                                for (let i = 0; i < boardList.length; i++) {
                                    htmlStr += `<li class='dropdown-item'><a href='/board/${boardList[i].boardNo}'>${boardList[i].title}</a></li>`;
                                }
                            }
                            $("#dropdown-box-"+type).html(htmlStr);
                        } catch (error) {
                            console.log("error : ", error);
                        };
                    };
                    listRequestProcess(type)
                };
                //****** Type별 게시판 목록 조회 *******//

            </script>
            <div id="login-box" th:if="${session.member} == null">
                <button class="btn btn-outline-primary me-2" onclick="location.href='/join'"
                        type="button">회원가입
                </button>
                <button class="btn btn-primary" onclick="location.href='/login'" type="button">로그인</button>
            </div>
            <div id="user-box" th:if="${session.member}">
                <ul class="notice-box">
                    <li class="dropdown">

                        <a aria-expanded="false" aria-haspopup="true"
                           class="nav-link px-2 link-dark dropdown-toggle user-alarm"
                           data-toggle="dropdown" href="#" id="dropdownAlarmList">알림<span
                                class="notion"></span></a>
                        <div aria-labelledby='dropdownAlarmList' class='dropdown-menu text-small' id="alarm-box">
                        </div>
                    </li>
                    <li>
                        <a class="nav-link px-2 link-dark user-note" th:href="@{/note/list}">쪽지<span class="notion">
                        <!-- <i
                           class="ico">3</i> --></span></a></li>
                </ul>
                <div class="dropdown private-box">
                    <a aria-expanded="false" aria-haspopup="true"
                       class="d-block link-dark text-decoration-none dropdown-toggle"
                       data-toggle="dropdown" href="#" id="dropdownUserMenu">
                        <img alt="mdo" class="rounded-circle" height="32" src="https://github.com/mdo.png"
                             width="32"><span class="user-name" th:text="${session.member.nick}"></span>
                    </a>
                    <ul aria-labelledby="dropdownUserMenu" class="dropdown-menu text-small">
                        <li><a class="dropdown-item" sec:authorize="hasRole('ROLE_ADMIN')" th:href="@{/intranet}"
                               th:if="${session.member.grade} == 5">관리자 페이지</a></li>
                        <!-- <li><a class="dropdown-item" th:href="@{/member/room?type=review}">나의 숙소 리뷰</a></li> -->
                        <li><a class="dropdown-item" th:href="@{/member/room?type=basic}">내가 쓴 게시글</a></li>
                        <li><a class="dropdown-item" th:href="@{/member/gradeup_list}">등업신청</a></li>
                        <li><a class="dropdown-item" th:href="@{/member}">정보수정</a>
                        </li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li>
                            <a class="dropdown-item" th:href="@{/logout}">로그아웃</a>
                        </li>
                    </ul>
            </div>
        </div>
    </div>
</header>

BoardController.java 전문

package com.example.board.controller;

import com.example.board.model.*;
import com.example.board.service.*;
import com.example.common.exception.Constants;
import com.example.member.model.MemberVo;
import com.example.member.service.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@Slf4j
public class BoardController {

    @Autowired
    public MemberService memberService;

    @Autowired
    private BoardService boardService;

    @Autowired
    private PostService postService;

    @Autowired
    private AttachService attachService;

    @Autowired
    private RoomService roomService;

    @Autowired
    private ReviewService reviewService;

    @Autowired
    private CommentService commentService;

    // ########## 게시글 ########## //
    // 게시글 작성 폼
    @GetMapping("/post/write")
    public String writeForm(@RequestParam(value = "boardNo", required = false) Integer boardNo, Model model, HttpServletRequest request) {
        // 작성자 본인이거나 관리자 인지 권한 확인
        // 세션 준비
        HttpSession session = request.getSession();
        MemberVo member = (MemberVo) session.getAttribute("member");

        // 회원이 아닌 경우 작성이 제한됨
        if (member == null) {

            //회원이 아닌 경우 로그인 페이지로 이동함
            return "redirect:/login?redirectUrl=" + request.getRequestURL() + "?" + request.getQueryString();

        } else {
            // 회원인 경우
            //해당 게시판 접근권한이 있는지 확인 할것

            //게시판 목록을 통해 게시글을 작성하려 할때, 유입된 게시판에 작성이 선택된다.
            int defaultListNo = 0;
            if (boardNo == null) {
                defaultListNo = 1;
            } else {
                defaultListNo = boardNo;
            }

            List<BoardVo> boards = this.boardService.retrieveBoardList();
            HashMap<Integer, String> boardList = new HashMap<Integer, String>();
            for (BoardVo board : boards) {
                boardList.put(board.getBoardNo(), board.getTitle());
            }

            List<RoomVo> roomList = this.roomService.retrieveRoomList();

            model.addAttribute("roomList", roomList);
            // request 영역에 디폴트 게시판 정보를 저장한다.
            model.addAttribute("defaultListNo", defaultListNo);
            // request 영역에 게시판 리스트 정보를 저장한다.
            model.addAttribute("boardList", boardList);

            return "page/post_write";
        }
    }

    //게시글 작성 시 이미지, 동영상, 리뷰 사용 체크
    @ResponseBody
    @GetMapping("/post/checkUse")
    public Map checkUse(@RequestParam(value = "boardNo", required = false, defaultValue = "1") int boardNo) {
        BoardVo board = this.boardService.retrieveBoard(boardNo);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("board", board);

        return map;
    }

    // 유형별 게시판 조회
    // retrieveBoardListByType
    @ResponseBody
    @PostMapping("/loadboardtype")
    public List<BoardVo> boardListByType(@RequestParam("type") String type) {
        List<BoardVo> boards = this.boardService.retrieveBoardListByType(type);
        return boards;
    }

    // 게시글 목록
    @GetMapping("/board/{boardNo}")
    public String list(@PathVariable(name = "boardNo", required = false) int boardNo, Model model) {
        //게시판 ID로 해당 게시판 내 게시글 목록을 가져온다.
        List<PostVo> posts = postService.retrieveAllPosts(boardNo);

        //게시판 ID로 해당 게시판 이름을 가져온다
        BoardVo board = boardService.retrieveBoard(boardNo);

        model.addAttribute("posts", posts);
        model.addAttribute("board", board);

        return "page/post_list";
    }

    // 내가 작성한 게시글 목록
    @GetMapping("/member/room")
    public String myList(HttpServletRequest request, Model model) {
        HttpSession session = request.getSession();

        MemberVo member = (MemberVo) session.getAttribute("member");
        int MemNo = member.getMemNo();
        List<PostVo> posts = this.postService.retrieveMyPosts(MemNo);
        model.addAttribute("posts", posts);

        return "page/member_room";
    }

    // 회원이 작성한 게시글 목록 (회원 정보 확인/회원이 작성한 글)
    @GetMapping("/member/{memNo}")
    public String memberWriteList(@PathVariable("memNo") int memNo, Model model) {

        List<PostVo> posts = this.postService.retrieveMyPosts(memNo);
        model.addAttribute("posts", posts);

        return "page/member_post_list";
    }

    // 게시글 상세보기
    @GetMapping("/post/{postNo}")
    public String read(@PathVariable("postNo") int postNo, Model model, HttpServletRequest request, HttpServletResponse response) {

        // ######### 게시글 상세정보 시작 ######### //
        PostVo post = this.postService.retrieveDetailBoard(postNo);

        if (post == null) {
            throw new RuntimeException(Constants.ExceptionMsgClass.NOTPOST.getExceptionMsgClass());
        }
        List<AttachVo> attachVoList = this.attachService.retrievePostAttach(postNo);
        ReviewVo review = this.reviewService.retrieveReview(postNo);
        BoardVo board = this.boardService.retrieveBoard(post.getBoardNo());
        RoomVo room = new RoomVo();
        if (review != null) {
            room = this.roomService.retrieveRoom(review.getRoomNo());
        }

        model.addAttribute("post", post);
        model.addAttribute("attachList", attachVoList);
        model.addAttribute("review", review);
        model.addAttribute("room", room);
        // ######### 게시글 상세정보 시작 ######### //

        // ######### 게시글 조회수 증가 시작 ######### //
        // 조회수 중복방지는 필요한 기능이지만, 완벽하게 차단해야 할만큼 중대한 사항은 아니라고 생각, 따라서 쿠키를 사용
        Cookie oldCookie = null;
        Cookie[] cookies = request.getCookies();

        //request에서 넘어온 쿠키가 있는 경우
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                //이미 게시글을 1개 이상 본 기록이 있는 경우
                if (cookie.getName().equals("postView")) {
                    //게시글 조회 쿠키 기록을 가져온다.
                    oldCookie = cookie;
                }
            }
        }

        //게시글 조회 기록이 있는 경우 (oldCookie = 이전 게시글 조회 기록)
        if (oldCookie != null) {
            log.info("oldCookie:{}", oldCookie.getValue());
            //현재 조회하려는 게시글을 본 쿠키 기록이 없는 경우
            if (!oldCookie.getValue().contains("[" + postNo + "]")) {
                //조회수를 올린다
                postService.upHitcount(postNo);
                // 현재 게시글을 조회했다고 쿠키에 추가한다.
                oldCookie.setValue(oldCookie.getValue() + "_[" + postNo + "]");
                //웹어플리케이션의 모든 URL 범위에서 전송할 수 있도록 Path를 설정해준다.
                oldCookie.setPath("/");
                //하루에 한번만 조회수가 올라가게 한다.
                oldCookie.setMaxAge(60 * 60 * 24);
                response.addCookie(oldCookie);
            }
        } else { //게시글 조회 기록이 없는 경우
            //조회수를 올린다.
            postService.upHitcount(postNo);
            //게시글 조회 기록 쿠키를 생성한다.
            Cookie newCookie = new Cookie("postView", "[" + postNo + "]");
            //웹어플리케이션의 모든 URL 범위에서 전송할 수 있도록 Path를 설정해준다.
            newCookie.setPath("/");
            //하루에 한번만 조회수가 올라가게 한다.
            newCookie.setMaxAge(60 * 60 * 24);
            response.addCookie(newCookie);
        }
        // ######### 게시글 조회수 증가 끝 ######### //


        // ######해당 게시판에서 댓글 사용 여부 판단######
        int useComment = this.boardService.retrieveBoard(post.getBoardNo()).getUseComment();
        model.addAttribute("useComment", useComment);
        System.out.println("useCommentssssss" + useComment);

        if (useComment != 0) {
            // ######### 댓글 목록 시작 ######### //
            List<CommentVo> comments = this.commentService.retrieveCommentList(postNo);
            model.addAttribute("comments", comments);
            // ######### 댓글 목록 조회 끝 ######### //
        }

        // ######해당 게시판에서 댓글 사용 여부 끝 ######### //

        return "page/post_detail";
    }

    // 게시글 수정폼
    @GetMapping("/post/modify/{postNo}")
    public String modifyFrom(@PathVariable("postNo") int postNo, Model model, HttpServletRequest request) {

        // 작성자 본인이거나 관리자 인지 권한 확인
        // 세션 준비
        HttpSession session = request.getSession();
        MemberVo member = (MemberVo) session.getAttribute("member");

        // 회원이 아닌 경우 작성이 제한됨
        if (member == null) {

            //회원이 아닌 경우 로그인 페이지로 이동함
            return "redirect:/login?redirectUrl=" + request.getRequestURL();

        } else {
            // 회원 id
            int memNo = member.getMemNo();

            // 작성된 게시글 작성자 id
            int writerNo = this.postService.retrieveDetailBoard(postNo).getWriterNo();
            System.out.println("회원" + memNo + "작성자" + writerNo);
            // 작성자 본인이 아닌 경우
            if (memNo != writerNo) {
                //권한 없음 페이지로 이동
                return "redirect:/denine";

            } else {
                // 작성자 본인인 경우
                // 게시글 정보 가져오기
                PostVo post = this.postService.retrieveDetailBoard(postNo);

                //현존하지 않은 게시글인 경우
                if (post == null) {
                    throw new RuntimeException(Constants.ExceptionMsgClass.NOTPOST.getExceptionMsgClass());
                }

                //게시판 목록 정보 가져오기
                List<String> boardNames = this.postService.retrieveBoardName();

                //HashMap 데이터 형에 게시판 목록 담기
                HashMap<Integer, String> boardList = new HashMap<Integer, String>();
                int i = 1;
                for (String string : boardNames) {
                    boardList.put(i, string);
                    i++;
                }
                //게시판 목록 model셋팅
                model.addAttribute("boardList", boardList);

                //게시글 정보 model셋팅
                model.addAttribute("post", post);

                return "page/post_modify";
            }
        }
    }

    // 게시글 수정
    @PostMapping("/post/update")
    public String update(@Valid PostVo post, HttpServletRequest request) {
        // 작성자 본인이거나 관리자 인지 권한 확인
        // 세션 준비
        HttpSession session = request.getSession();
        MemberVo member = (MemberVo) session.getAttribute("member");

        // 회원이 아닌 경우 작성이 제한됨
        if (member == null) {

            //회원이 아닌 경우 로그인 페이지로 이동함
            return "redirect:/login?redirectUrl=/post/" + post.getPostNo();

        } else {
            // 회원 id
            int memNo = member.getMemNo();

            // 작성된 게시글 작성자 id
            int writerNo = this.postService.retrieveDetailBoard(post.getPostNo()).getWriterNo();
            System.out.println("회원" + memNo + "작성자" + writerNo);

            // 작성자 본인이 아닌 경우
            if (memNo != writerNo) {
                //권한 없음 페이지로 이동
                return "redirect:/denine";

            } else {
                // 작성자 본인인 경우
                // 값 셋팅
                PostVo postVo = new PostVo();
                postVo.setPostNo(post.getPostNo());
                postVo.setBoardNo(post.getBoardNo());
                postVo.setSubject(post.getSubject());
                postVo.setContent(post.getContent());
                postVo.setTag(post.getTag());

                // 수정 쿼리 실행
                this.postService.modifyPost(postVo);

                return "redirect:/post/" + post.getPostNo();
            }
        }
    }

    // 게시글 삭제
    @GetMapping("/post/delete/{postNo}")
    public String delete(@PathVariable("postNo") int postNo, HttpServletRequest request) {
        // 작성자 본인이거나 관리자 인지 권한 확인
        // 세션 준비
        HttpSession session = request.getSession();
        MemberVo member = (MemberVo) session.getAttribute("member");

        // 회원이 아닌 경우 작성이 제한됨
        if (member == null) {

            //회원이 아닌 경우 로그인 페이지로 이동함
            return "redirect:/login?redirectUrl=/post/" + postNo;

        } else {
            // 회원 id
            int memNo = member.getMemNo();

            // 작성된 게시글 작성자 id
            PostVo post = this.postService.retrieveDetailBoard(postNo);
            int writerNo = post.getWriterNo();
            System.out.println("회원" + memNo + "작성자" + writerNo);
            // 작성자 본인이 아닌 경우
            if (memNo != writerNo) {
                //권한 없음 페이지로 이동
                return "redirect:/denine";

            } else {

                // 작성자 본인인 경우
                // 해당 게시글의 board pk값 받아옴 (삭제 후 목록이로 이동하기 위함)
                int boardNo = post.getBoardNo();

                // 삭제 쿼리 실행
                this.postService.removePost(postNo);

                //게시글 삭제시 총 개수 수정 boardNo
                //게시글 등록은 filecontroller에 있음
                boardService.reviseBoardPost(boardNo, -1);

                return "redirect:/board/" + boardNo;
            }
        }
    }
}

 

 

 

 

DB의 테이블(=해당 목록에 맞게 데이터를 입력해서 완성된 하나의 집합체)과  데이터 유형과

숙소리뷰 = review / 숙소톡톡 = basic 타입으로 db에 지정되어있다

DB의 board 테이블과 컬럼명

여튼 화면에서 사용자가 숙소 톡톡 을 클릭하면 html단의 //Type별 게시판 목록 조회///부분을 실행하라고 한다

function boardListAjax(type) // <====요 부분을 실행시켜 함수를 실행시킴

그럼 밑의 실행문으로 명령이 내려가고

listRequestProcess(type) // <====요게 실행문

이 실행문은 또 명령을 Controller단의 지정해준 주소

("/loadboardtype")

로 가져간다 (header.html에 찾아보면 주소 지정해준 부분이 있다)

가져가서

// 유형별 게시판 조회
// retrieveBoardListByType
@ResponseBody
@PostMapping("/loadboardtype")
public List<BoardVo> boardListByType(@RequestParam("type") String type) {
    List<BoardVo> boards = this.boardService.retrieveBoardListByType(type);
    return boards;
}

 

여기서 실행되면 mapper의 쿼리문을 담아서 다시 header.html로 리턴해준다

잘담아왔다면 

$.ajax({
    url: '/loadboardtype',
    method: 'POST',
    dataType: 'json',
    data: {
        type: type
    },
    success: function (data) {
        resolve(data);
    },
    error: function (e) {
        reject(e);
    }
});

요 부분에 따라서 data라는 이름으로 html 페이지에서 쓸 정보를 담아준다

실패하면 에러

 

성공했다는 가정하에 이제 

async function listRequestProcess(type) {
        try {
            const boardList = await getListAjax(type);
            var htmlStr = '';
            //console.log(boardList);
            //console.log(boardList.length);
            if (boardList.length == 0) {
                htmlStr += `<li class='dropdown-item'>게시판이 없습니다.</li>`;
            } else {
                for (let i = 0; i < boardList.length; i++) {
                    htmlStr += `<li class='dropdown-item'><a href='/board/${boardList[i].boardNo}'>${boardList[i].title}</a></li>`;
                }
            }
            $("#dropdown-box-"+type).html(htmlStr);
        } catch (error) {
            console.log("error : ", error);
        };
    };
    listRequestProcess(type)
};

이 부분을 실행해준다

위의 실행문은 받아온 type값에 따라서 게시판 목록을 뽑아준다!

 

 

자세히 보면

async function listRequestProcess(type) {
    try {
        const boardList = await getListAjax(type);
        var htmlStr = '';
        //console.log(boardList);
        //console.log(boardList.length);
        if (boardList.length == 0) {
            htmlStr += `<li class='dropdown-item'>게시판이 없습니다.</li>`;
        } else {
            for (let i = 0; i < boardList.length; i++) {
                htmlStr += `<li class='dropdown-item'><a href='/board/${boardList[i].boardNo}'>${boardList[i].title}</a></li>`;
            }
        }
        $("#dropdown-box-"+type).html(htmlStr);
    } catch (error) {
        console.log("error : ", error);
    };
};

for문으로 가져온 객체의 갯수 값만큼 목록을 뽑아 보여주고 해당 순서의 boardNo를 뽑아 링크를 걸어준다

만약 게시판이 없다면 게시판이 없다는 안내문구도 보여준다!

 

 

 

$("#dropdown-box-"+type).html(htmlStr);

이 부분은 함수부분에 받아져있는 boardVo에 지정되어있는 항목에 따라 DB에서 받아온 값들을 type에 따라서 나눠서 넣어주는 역할을 한다

 

 

id="dropdown-box-basic" //또는
id="dropdown-box-review"

 

요렇게 위에서 id를 지정해 준 부분이 있다

 

 

***********아직 프론트 부분의 보여지는 부분은 구현하지 않은 상태이다********

부트스트랩의 드롭다운을 쓰다가 바꾸는 중

 

 

 

+) async await에 대해선 여기를 참고하면 좋을것 같다 

https://joshua1988.github.io/web-development/javascript/js-async-await/

 

자바스크립트 async와 await

(중급) 자바스크립트 개발자를 위한 async, await 사용법 설명. 쉽게 알아보는 자바스크립트 async await 개념, 사용법, 예제 코드, 예외 처리 방법

joshua1988.github.io

 

 

728x90