Pagination - Dynamic list

์ด๋™์–ธยท2024๋…„ 9์›” 12์ผ

new world

๋ชฉ๋ก ๋ณด๊ธฐ
44/62
post-thumbnail

9.12(๋ชฉ)

1. data-*

<tr th:each="dto: ${result.list}">
                    <td>[[${dto.bno}]]</td>
                    <td>
                    <td th:data-bno="${dto.bno}">
                        <img th:if="${dto.fileName != null}" th:src="'http://localhost:8081/attach/s_' + ${dto.fileName}">
                        [[${dto.title}]]
                    </td>
                    <td>[[${dto.writer}]]</td>
                    <td>[[${#temporals.format(dto.regDate, 'yyyy-MM-dd') }]]</td>
                    <td>[[${dto.viewCnt}]]</td>
                </tr>

๐Ÿ‘‰ th:data-bno=${dto.bno} ์ฒ˜๋Ÿผ data-bno ๋ณ€์ˆ˜์— dto.bno ๊ฐ’์„ ํ• ๋‹นํ•˜์—ฌ scriptํƒœ๊ทธ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

script

const bno = target.getAttribute("data-bno")

๐Ÿ‘‰ ์—ฌ๊ธฐ์„œ getAttribute๋Š” html์š”์†Œ์—์„œ ํŠน์ • ์†์„ฑ๊ฐ’์„ ์ฝ์–ด์˜ค๋Š” ์—ญํ• ์ธ๋ฐ, data-bno์˜ ์†์„ฑ๊ฐ’์„ ์ฝ์–ด์™€์„œ bno๋ณ€์ˆ˜์— ๋Œ€์ž…ํ•˜๋Š”๊ฒƒ.




2. ์˜ˆ์™ธ์ฒ˜๋ฆฌ - (๊ธฐ์กด์— ์—†๋Š” bno๋ฅผ ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅ์‹œ)

๐Ÿ‘‰ ๊ธฐ์กด์— ์—†๋Š” bno๊ฐ’์„ ์ž…๋ ฅํ–ˆ์„๋•Œ๋Š” NoSuchElementException ํ•ด๋‹น ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ, ์˜ค๋ฅ˜ํŽ˜์ด์ง€๊ฐ€ ๋œจ์ง€์•Š๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋งŒ๋“  404.html๋กœ ์ด๋™์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•.

2-1. BoardControllerAdvice.java

package org.demo.springdemo.board.controller;

@ControllerAdvice
@Log4j2
public class BoardControllerAdvice { // ์กด์žฌํ•˜์ง€์•Š๋Š” BNO๋ฅผ ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅํ–ˆ์„๋•Œ

    @ExceptionHandler(NoSuchElementException.class)
    public String notFound(NoSuchElementException e) {

        log.error("not found : "+e.getMessage());

        return "redirect:/404.html";
    }

}




3-1. ViewCntInterceptor

package org.demo.springdemo.board.controller.interceptor;


@Log4j2
public class ViewCntInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle-------------");


        int value = (int)(Math.random()*100);

        log.info("-----------------" + value);

        Cookie viewCookie = new Cookie("view", "123" + value);
        viewCookie.setMaxAge(60*60*24);
        viewCookie.setPath("/");
        response.addCookie(viewCookie);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle-------------");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion-------------");
    }
}

๐Ÿ‘‰ preHandle : ์š”์ฒญ์ด ์ปจํŠธ๋กค๋Ÿฌ์˜ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ํ˜ธ์ถœ, ์š”์ฒญ์ฒ˜๋ฆฌ์ „์— ์‚ฌ์ „ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ํ•ด๋‹น ๊ตฌ๊ฐ„์—์„œ cookie๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.




3-2. BoardController


    @GetMapping("/read/{bno}")
    public String read(@CookieValue("view")String viewValue, @PathVariable("bno") Long bno, Model model) {

        log.info("Reading board: "+bno);
        log.info("viewValue: "+viewValue);


        boolean existed = false;

        if(viewValue != null){
            existed = Arrays.stream(viewValue.split("%")).anyMatch(str -> str.equals(bno+""));
        }

        if(!existed) {

            log.info("View Count... update........................");

        }

        Optional<BoardReadDTO> result = boardService.get(bno);

        BoardReadDTO boardReadDTO = result.orElseThrow();

        model.addAttribute("board", boardReadDTO);

        return "/board/read";
    }


๐Ÿ‘‰ @CookieValue("view")๋ฅผ ํ†ตํ•ด view๋ผ๋Š” ํ‚ค๋ฅผ ๊ฐ€์ง„ cookie๊ธ” ๊ฐ’์„ ์ฝ์–ด๋‚ด๊ณ , viewValue๋Š” cookie๊ฐ€ % ๋กœ ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š” ํ˜•ํƒœ์ด๋‹ค.

๐Ÿ‘‰ %๋กœ ์ด์–ด์ ธ์žˆ๋Š” ์ฟ ํ‚ค๋ฅผ ๋‚˜๋ˆ„์–ด ๊ฒŒ์‹œ๊ธ€ ๋ฒˆํ˜ธ์™€ ๋น„๊ตํ•˜์—ฌ ์ด๋ฏธ ๋ณธ ๊ฒŒ์‹œ๊ธ€์ธ์ง€ ํŒ๋‹จํ•˜๊ณ , existed๊ฐ€ false์ธ๊ฒฝ์šฐ์—” ์กฐํšŒ์ˆ˜๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด์•ผํ•œ๋‹ค.

๐Ÿ‘‰ Optional์ธ result๊ฐ’์— service์˜ get๋ฉ”์†Œ๋“œ๋ฅผ ๋„ฃ์€ ๊ฐ’์„ ํ• ๋‹นํ•œ๋’ค์— ์ด result๊ฐ€ ์กด์žฌํ•˜๋Š” result์ผ๋•Œ๋งŒ ์ค„์ˆ˜์žˆ๊ธฐ ๋•Œ๋ฌธ์— orElseThorw๋ฅผ ์‚ฌ์šฉํ•œ๊ฒƒ์ด๊ณ , BoardReadDTO์— ๋„ฃ์–ด์ฃผ๋Š” ์ด์œ ๋Š” ๋‚˜์ค‘์— HTML์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Optional์˜ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ• ์ˆ˜ ์—†์œผ๋ฏ€๋กœ DTO์˜ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜์„ ์‹œ์ผœ์ฃผ๋Š”๊ฒƒ์ด๋‹ค.




4. ์ข‹์•„์š” ๋ฒ„ํŠผ - DB

insert into tbl_reply (bno,reply, replyer)
values (100,'Reply...','user00')
;

๐Ÿ‘‰ 100๋ฒˆ๊ฒŒ์‹œ๊ธ€์— Reply...๋ผ๋Š” ๋Œ“๊ธ€์„ user00์ด๋ผ๋Š” ์‚ฌ๋žŒ์ด ๋‹ฌ์•˜๋‹ค.

create table tbl_reply_favorite (
    rno int not null,
    mid varchar(50) not null,
    regDate timestamp default now()
);

๐Ÿ‘‰ tbl_reply_favorite ํ…Œ์ด๋ธ”์ƒ์„ฑ

ALTER table tbl_reply_favorite
add constraint pk_reply_favorite
primary key (rno,mid)
;

๐Ÿ‘‰ favoriteํ…Œ์ด๋ธ”์—๋Š” ๋ณตํ•ฉpk๋ฅผ ๊ฐ€์ง€๋Š”๋ฐ, rno์™€mid์ด๋‹ค.
๐Ÿ‘‰ ์—ฌ๊ธฐ์„œ rno๋Š” ๋Œ“๊ธ€์˜ ์ˆœ์„œ์ด๊ณ ,mid๋Š” ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅธ ์‚ฌ๋žŒ์ด๋‹ค.

insert into tbl_reply_favorite (rno,mid) values (1,'r1');
insert into tbl_reply_favorite (rno,mid) values (1,'r2');
insert into tbl_reply_favorite (rno,mid) values (1,'r3');
insert into tbl_reply_favorite (rno,mid) values (1,'r4');

insert into tbl_reply_favorite (rno,mid) values (2,'r1');
insert into tbl_reply_favorite (rno,mid) values (2,'r2');

๐Ÿ‘‰ ๋”๋ฏธ๋ฐ์ดํ„ฐ๋ฅผ ํ†ตํ•ด์„œ 100๋ฒˆ๊ฒŒ์‹œ๊ธ€์— ๋Œ€ํ•ด์„œ, 1๋ฒˆ๋Œ“๊ธ€์—๋Š” r1,r2,r3,r4์ธ์›์ด ์ข‹์•„์š”๋ฅผ ๋ˆŒ๋ €๊ณ  2๋ฒˆ๋Œ“๊ธ€์—๋Š” r1,r2์ธ์›์ด ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅธ์ƒํƒœ์ด๋‹ค.

select rno, min(reply), min(replyer), count(fno), sum(choice)
from(
        select reply.rno rno, reply, replyer, fa.rno fno,
               if(fa.mid = 'r1',1,0) choice
        from
            tbl_reply reply left join tbl_reply_favorite fa on reply.rno = fa.rno
        where
            reply.bno = 100
    ) r1

group by rno

๐Ÿ‘‰ ํ˜„์žฌ ์ฃผ์ฒด๋Š” r1์ด ์ฃผ์ฒด๋ผ๊ณ  ๊ฐ€์ •ํ•˜๊ณ  ๋ณธ๋‹ค.

๐Ÿ‘‰ ์ด๋•Œ ํ•ด๋‹น sql์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์šฐ์„  ๋Œ“๊ธ€์˜ ์ „์ฒด์ธ rno, ๋Œ“๊ธ€์˜ ๋‚ด์šฉ, ๋Œ“๊ธ€์ž‘์„ฑ์ž, ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅธ์‚ฌ๋žŒ์˜ ์ธ์›์ˆ˜, ๋ณธ์ธ์ด ์ข‹์•„
์š”๋ฅผ ๋ˆŒ๋ €๋Š”์ง€ ํ™•์ธ ์„ ์ฒซ์งธ์ค„ select๋กœ ์•Œ์ˆ˜์žˆ๋‹ค.

๐Ÿ‘‰ ํ—ท๊ฐˆ๋ฆด์ˆ˜์žˆ๋Š” ๋ถ€๋ถ„์ด sum(choice)์ธ๋ฐ, ์šฐ์„  ๋‚ด๋ถ€ sql๋ฌธ์„ ๋ณด๋ฉด if๋ฌธ์ด ๋ณด์ด๋Š”๋ฐ, ๋งŒ์•ฝ fa์˜ mid๊ฐ€ r1์ผ๋•Œ 1์ด๊ณ  r1์ด ์•„๋‹ˆ๋ฉด 0 ์ด๋ผ๊ณ  ํ•˜์ž, ๊ทธ๋•Œ, sum๊ฐ’์ด 1 ์ด๋ผ๊ณ  ํ•˜๋ฉด r1์ด ํ•œ๋ฒˆ์€ ํฌํ•จ๋˜์–ด์žˆ๋‹ค๋Š” ๋ง์ด๋‹ˆ๊นŒ ํ•ด๋‹น rno์—๋Š” ๋‚ด๊ฐ€ ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅธ ํšŸ์ˆ˜๊ฐ€ ์žˆ๋‹ค๋Š” ๋ง์ด ๋˜๋Š”๊ฒƒ์ด๋‹ค.

๐Ÿ‘‰ ์ด๋ ‡๊ฒŒ sum์„ ์ด์šฉํ•ด์„œ sql๋ฌธ์„ ์ง  ์ด์œ ๋Š” group by ๋ฅผ ํ†ตํ•ด ํ•˜๋‚˜์— ๋Œ“๊ธ€์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ์ข‹์•„์š”๊ฐ€ ์žˆ๋Š”๋ฐ, ๊ทธ๊ฒƒ์„ ํ•œ์ค„๋กœ ํ†ตํ•ฉ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ ์ง‘ํ•ฉ์˜ ๋А๋‚Œ์œผ๋กœ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.




5. ๋™์  list.html

๐Ÿ‘‰ ํ˜„์žฌ listํŽ˜์ด์ง€๋Š” ํฌ๊ฒŒ 4๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„๋œ๋‹ค.
๐Ÿ‘‰ ํŽ˜์ด์ง€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋Š” pagination, ๊ฒ€์ƒ‰๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋Š” searchBtn, ์ดˆ๊ธฐํ™”๋ฒ„ํŠผ์ธ claerBtn, ๊ฐ๊ฐ์˜ ๊ฒŒ์‹œ๋ฌผ๋ฒ„ํŠผ์ธ table๋กœ ๋‚˜๋‰˜์–ด์ง„๋‹ค

5-1. scriptํƒœ๊ทธ ๋‚ด๋ถ€์—์„œ ๊ณตํ†ต์ ์ธ ๊ฐ’

const {page, size, type, keyword} = [[${pageRequest}]]

    console.log(page,size,type,keyword)

    const selectTag = document.querySelector("select[name='type']")
    const keywordInput = document.querySelector("input[name='keyword']")

    if(type){
        selectTag.value=type
    }


    const bno = [[${bno}]]

    const result = [[${result}]]

    const myModal = new bootstrap.Modal(document.querySelector('#exampleModal'), null)

    if(bno){
        myModal.show()
    }

๐Ÿ‘‰ ์ฒซ๋ฒˆ์งธ๋Š” ๊ตฌ์กฐํ• ๋‹น์„ ํ†ตํ•ด pageRequest์˜ ๊ฐ’์„ page, size, type, keyword๋กœ ๊ฐ๊ฐ ๋ฐ›๊ณ ์žˆ๋‹ค.
๐Ÿ‘‰ selectTag์™€ keywordInput์€ select์†์„ฑ์ค‘์— name๊ฐ’์ด type์ธ๋ถ€๋ถ„์„ ์ฐธ์กฐํ•˜๋Š” selectTag์ด๊ณ , input์†์„ฑ์ค‘์— name๊ฐ’์ด keyword์ธ ๋ถ€๋ถ„์„ ์ฐธ์กฐํ•˜๋Š” keywordInput์ด ์žˆ๋‹ค.

๐Ÿ‘‰ ์ด๋•Œ type์ด ์žˆ์„๋•Œ type์€ select์ด๋ฏ€๋กœ ์„ ํƒํ•œ type์„ ํ• ๋‹น๋ฐ›๊ณ ์žˆ๋‹ค.

๐Ÿ‘‰ Mymodal์—์„œ๋Š” modal์„ querySelect๋ฅผ ํ†ตํ•ด ์ฐธ์กฐํ•˜๊ณ , ๋ฐ›์•„์˜จ bno๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ์— modal์ฐฝ์„ ๋„์šด๋‹ค




5-2. pagination


document.querySelector(".pagination").addEventListener("click", e=> {
        e.preventDefault()
        e.stopPropagation()

        const target = e.target

        const pageNum = target.getAttribute("href")


        if(!pageNum){
            return;
        }


        let formStr = `
              <form id="tempForm" action="/board/list">
                <input type="hidden" name="page" value='${pageNum}'>`

        if(type){
            formStr += `<input type="hidden" name="type" value='${type}'>`
        }
        if(keyword){
            formStr += `<input type="hidden" name="keyword" value='${keyword}'>`
        }

        formStr += `</form>`

        document.querySelector("#tempDiv").innerHTML = formStr
        document.querySelector("#tempForm").submit()



    },false)

๐Ÿ‘‰ ์šฐ์„  ํŽ˜์ด์ง€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„๋•Œ์— ํ•ด๋‹นํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๊ฑธ์–ด์ฃผ๊ณ , ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„๋•Œ href์˜ ์†์„ฑ์„ ๊ฐ–๊ณ ์˜ค๊ฒŒ ๋˜๋ฉด pageNum์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

๐Ÿ‘‰ pageNum์ด ์—†์œผ๋ฉด return์œผ๋กœ ๋๋‚˜๊ฒŒ ๋˜๊ณ , formํƒœ๊ทธ๋ฅผ ํ†ตํ•ด page๋ฅผ hidden์œผ๋กœ board/list์— ๋„˜๊ธฐ๊ฒŒ ๋œ๋‹ค. ์ดํ›„์—๋Š” ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ฒผ์„๋•Œ๋„ ๊ธฐ์กด์— ๊ฒ€์ƒ‰ํ•ด๋’€๋˜ type๊ณผ keyword๋ฅผ ๋ฌผ๊ณ ์žˆ๊ธฐ ์œ„ํ•ด์„œ type๊ณผ keyword๊ฐ€ ์žˆ์„๊ฒฝ์šฐ์— formStr๋กœ ๋ฌถ์–ด tempDiv์˜ innerHTML์œผ๋กœ ๋ณด๋‚ด๊ฒŒ๋œ๋‹ค.

๐Ÿ‘‰ ์—ฌ๊ธฐ์„œ tempDiv๋Š” html์˜ ๊ฐ€์žฅ ์™ธ๋ถ€์— ์กด์žฌํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ modal์— ์˜ํ–ฅ์„ ์ฃผ์ง€์•Š๊ณ  ๊ฐ’์„ ์ „๋‹ฌํ• ์ˆ˜์žˆ๋‹ค.

๐Ÿ‘‰ ์ดํ›„์— tempForm์œผ๋กœ submit์„ ํ•˜๋Š”๋ฐ ๊ฒฝ๋กœ๋Š” ์•„๊นŒ์™€ ๋˜‘๊ฐ™์€ board/list์ด๋‹ค.




5-3. searchBtn

document.querySelector(".searchBtn").addEventListener("click", e=> {
        e.preventDefault()


        let formStr = `
          <form id="tempForm" action="/board/list">
            <input type="hidden" name="page" value="1">` // ๊ฒ€์ƒ‰์‹œ ํ•ญ์ƒ 1ํŽ˜์ด์ง€๋กœ

        if(keywordInput.value && selectTag.value){
            formStr += `<input type="hidden" name="type" value='${selectTag.value}'>`
            formStr += `<input type="hidden" name="keyword" value='${keywordInput.value}'>`
        }
        formStr+= `</form>`

        document.querySelector("#tempDiv").innerHTML = formStr
        document.querySelector("#tempForm").submit()

    })

๐Ÿ‘‰ ํ•ด๋‹น ๋ถ€๋ถ„์€ select์ธ type์„ ์ •ํ•˜๊ณ  keyword๋ฅผ ์ž…๋ ฅํ•œ ์ดํ›„์— search ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฒŒ๋œ ๊ฒฝ์šฐ์ด๋‹ค.

๐Ÿ‘‰ ์šฐ์„  form์˜ ๊ฒฝ๋กœ๋Š” ์•„๊นŒ์™€ ๋˜‘๊ฐ™๊ณ , ๋‹ค๋ฅธ๋ถ€๋ถ„์€ value๊ฐ€ 1 ์ด๋ผ๋Š”๊ฒƒ์ธ๋ฐ, ์•„๊นŒ๋Š” PageNum ์ด์˜€์ง€๋งŒ, ์ง€๊ธˆ์€ ๊ฒ€์ƒ‰์„ ํ•˜๊ฒŒ๋˜๋ฉด ํ•ญ์ƒ 1๋ฒˆํŽ˜์ด์ง€๋กœ ๊ฐ€์•ผํ•˜๋ฏ€๋กœ 1์„ value๊ฐ’์œผ๋กœ ์ฃผ์—ˆ๋‹ค.

๐Ÿ‘‰ ๊ทธ๋ฆฌ๊ณ  keyword์™€ selectTag๊ฐ€ ์žˆ์„๊ฒฝ์šฐ์— hidden๊ฐ’์œผ๋กœ ๋„ฃ์–ด์ค„์ˆ˜์žˆ๋”ฐ.



5-4. clearBtn

document.querySelector(".clearBtn").addEventListener("click", e=> {
        e.preventDefault();
        self.location="/board/list"
    })

๐Ÿ‘‰ ํ•ด๋‹น๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ฒŒ๋˜๋ฉด /board/list๋กœ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๊ธฐ๋•Œ๋ฌธ์— url์— ๋‹ด๊ฒจ์žˆ๋˜ page, keyword, type๋“ฑ์ด ์—†์–ด์ง€๋ฏ€๋กœ ๋ฌผ๊ณ ์žˆ๋˜ ๊ฐ’ ์—ญ์‹œ ์—†์–ด์ง„๋‹ค.




5-5. table

document.querySelector(".table").addEventListener("click", e=>{
        e.preventDefault()
        e.stopPropagation()

        const target = e.target
        const bno = target.getAttribute("data-bno") // bno์ถ”์ถœ
        if(!bno){return}

        let formStr = `
        <form id="tempForm" action="/board/read/${bno}">
           <input type="hidden" name="page" value='${page}'>`

        if(type){
            formStr += `<input type="hidden" name="type" value='${type}'>`
        }
        if(keyword){
            formStr += `<input type="hidden" name="keyword" value='${keyword}'>`
        }

        formStr+= `</form>`

        document.querySelector("#tempDiv").innerHTML = formStr

        document.querySelector("#tempForm").submit()


    },false)

๐Ÿ‘‰ ํ•ด๋‹น ๋ถ€๋ถ„์€ table๋กœ ๊ฒŒ์‹œ๊ธ€์„ ์„ ํƒํ–ˆ์„๋•Œ ๊ฒŒ์‹œ๊ธ€์˜ read๋กœ ๋„˜์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.
์šฐ์„  getAttribute๋ฅผ ํ†ตํ•ด ์„ค์ •ํ•ด๋‘” data-bno๊ฐ’์„ ์ถ”์ถœํ•˜๊ณ  bno๊ฐ€ ์—†์œผ๋ฉด return๋œ๋‹ค.

๐Ÿ‘‰ bno๊ฐ€ ์žˆ์„๊ฒฝ์šฐ์—” /board/read/${bno}์˜ ๊ฒฝ๋กœ๋กœ ์ด๋™๋˜๊ณ , type๊ณผ keyword๊ฐ€ ์žˆ์„๊ฒฝ์šฐ์— ์—ญ์‹œ ๋ฌผ๊ณ ๊ฐ„๋‹ค.




6. Filter / Interceptor / Aop

Filter : ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๊ฐ€๋กœ์ฑ„๋Š” ์ปดํฌ๋„ŒํŠธ

Interceptor : spring MVC์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์š”์ฒญ ์ฒ˜๋ฆฌ ํŠน์ • ์‹œ์ ์— ๊ฐœ์ž…ํ• ์ˆ˜์žˆ๋Š” ๋งค์ปค๋‹ˆ์ฆ˜

AOP : ํ•ต์‹ฌ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ณ„๋„๋กœ ๊ณตํ†ต์ ์ธ ๊ด€์‹ฌ์‚ฌํ•ญ(๋กœ๊น…, ํŠธ๋žœ์žญ์…˜)

0๊ฐœ์˜ ๋Œ“๊ธ€