
package org.demo.springdemo.board.controller;
@Controller
@RequestMapping("/board")
@Log4j2
@RequiredArgsConstructor
public class BoardController {
private final UploadUtil uploadUtil;
@GetMapping("/register")
public void register(){
}
@PostMapping("/register")
public String register(BoardRegisterDTO boardRegisterDTO, RedirectAttributes rttr){
log.info("register: "+ boardRegisterDTO);
List<String> uploadedFileNames = uploadUtil.upload(boardRegisterDTO.getImges());
//uuid์ ๊ธฐ์กดํ์ผ์ด ๊ฒฐํฉ๋ ํ์ผ์ด uploadedFileNames์ ๋ด๊น
boardRegisterDTO.setFileNames(uploadedFileNames);
// Service์์ DTO์ FileNames๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ํ๋ณํ์ํด
rttr.addFlashAttribute("bno", boardRegisterDTO.getBno());
// ๊ฒ์๊ธ์ด ๋ฑ๋ก๋ ์ดํ bno๊ฐ ์์ฑ๋๋๋ฐ, ํด๋น bno๋ฅผ DTO์ ์ ์ฃผ์
์์ผ ์ํ๋ฅผ ๋ณํ์ํค๊ณ , addFlashAttribute์ ์ ์ฅ๋๋ค.
return "redirect:/board/list";
}
@GetMapping("/list")
public void list(Model model){
}
}
๐ ์ฐ์ , PostMapping์ ๊ฒ์๊ธ์ ๋ฑ๋กํ ์ดํ์ ๋ฐ์์ด ๋๋๋ฐ ์ฒจ๋ถํ์ผ์ ๋ฃ์ด ๊ฒ์๊ธ์ ๋ฑ๋กํ๊ฒ ๋๋ฉด ํด๋น DTO์ ๊ฒฐํฉ๋ Imges๋ฅผ uploadUtil์ upload๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ก ๋ค์ด๊ฐ์, List<.String>๋ฐ์ดํฐํ์ ์ธ uploadedFileNames๋ณ์์ ๋ด๊ธฐ๊ฒ๋๋ค. ์ด ๊ฐ์ UUID๊ฐ ํฌํจ๋์ด ๋ง๋ค์ด์ง ์๋ก์ด FileName์ด๊ณ , ์ด FileName๋ค์ด DTO์ ์๋ setFileNames์ ๋ฃ์ด์ ธ DTO์ ์ํ๊ฐ ๋ณํ๋๋ค. ์ด ๋ณํ๋ ํ์ฌ DTO์ FileNames๊ฐ ๋ณ๊ฒฝ๋์ด ๋์ค์ Service์์ ์ฌ์ฉ์ด ๋๋ค.
๐ Serivce์์ ๋ฉ์๋๊ฐ ํธ์ถ๋์ด, ๊ฒ์๊ธ์ด ๋ฑ๋ก์ด ๋ ์ดํ์ bno๊ฐ ์์ฑ์ด ๋๊ณ ํด๋น bno๋ฅผ ์ด์ฉํ์ฌ addFlashAttribute๋ฅผ ํตํด ์ผํ์ฑ์ผ๋ก ์ ์ฅ์ด ๋์ด modal์์ ์ฌ์ฉ๋๋ค.
2-1. list.html
<form id="actionForm" action="/board/list" method="get" >
<select name="type"> <!--์๋์์ ์ ํ๋ ํ์
์ด ํด๋น select Type์ผ๋ก ์ฐ๊ฒฐ๋์ด xmlํ์ผ์ type๊ฐ๊ณผ ์ด์ด์ง๋ค -->
<option value="">---</option>
<option value="T" th:selected="${pageRequest.type == 'T'}">์ ๋ชฉ</option>
<option value="C" th:selected="${pageRequest.type == 'C'}">๋ด์ฉ</option>
<option value="W" th:selected="${pageRequest.type == 'W'}">์์ฑ์</option>
<option value="TC" th:selected="${pageRequest.type == 'TC'}">์ ๋ชฉ / ๋ด์ฉ</option>
<option value="TW" th:selected="${pageRequest.type == 'TW'}">์ ๋ชฉ / ์์ฑ์</option>
<option value="TCW" th:selected="${pageRequest.type == 'TCW'}">์ ๋ชฉ / ๋ด์ฉ / ์์ฑ์</option>
</select>
<input type="text" name="keyword" th:value="${pageRequest.keyword}">
<input type="hidden" name="page" value="1"> <!--๊ฒ์์กฐ๊ฑด์ ๋๋ฅด๋ฉด ๋ฌด์กฐ๊ฑด 1ํ์ด์ง ์ด๋ฏ๋ก-->
<button class="btn btn-secondary searchBtn">Search</button>
<button class="btn btn-primary clearBtn">Clear</button>
</form>
๐ Option์์ ์ ํ๋ value๊ฐ์ผ๋ก์ธํด name="type"์ด ๋ณ๊ฒฝ๋์ด type="T" ์ํ๋ก action์ธ /board/list์ ๊ฒฝ๋ก๋ก ์ ๋ฌ์ด ๋๋ค.
2-2. Controller
package org.zerock.b2.board.controller;
@Controller
@RequestMapping("/board")
@Log4j2
@RequiredArgsConstructor
public class BoardController {
private final UploadUtil uploadUtil;
private final BoardService boardService;
@GetMapping("/register")
public void register(){
}
@PostMapping("/register")
public String register(BoardRegisterDTO boardRegisterDTO, RedirectAttributes rttr){
log.info("Register board: " + boardRegisterDTO);
List<String> uploadedFileNames = uploadUtil.upload(boardRegisterDTO.getImages());
boardRegisterDTO.setFileNames(uploadedFileNames);
boardService.register(boardRegisterDTO);
rttr.addFlashAttribute("bno", boardRegisterDTO.getBno());
// ๋ช๋ฒ๊ฒ์๋ฌผ์ด ๋ฑ๋ก/์ญ์ ๋์๋ค๋ ๋ชจ๋ฌ์ ์ํด
return "redirect:/board/list";
}
@GetMapping("/list")
public void list(PageRequest pageRequest, Model model){
model.addAttribute("result", boardService.list(pageRequest));
}
}
๐ ํผ๋ฐ์ดํฐ๋ก ์ ๋ฌ๋ฐ์ type=T๊ฐ์ด ์ฟผ๋ฆฌ์คํธ๋ง์ ํํ๋ก action์ controller๋ก ์ ๋ฌ๋๊ณ , "/list"์์ PageRequest๋ฅผ ํตํด boardService.list์ type=T๊ฐ์ ์ ๋ฌํ๋ค.
2-3. Service
package org.zerock.b2.board.service;
@Service
@Log4j2
@Transactional
@RequiredArgsConstructor
public class BoardService {
private final BoardMapper boardMapper;
public void register(BoardRegisterDTO boardRegisterDTO) {
boardMapper.insert(boardRegisterDTO);
List<String> fileNames = boardRegisterDTO.getFileNames();
for (int i = 0; i < fileNames.size(); i++) {
boardMapper.insertAttach(boardRegisterDTO.getBno(), fileNames.get(i), i);
}
}
@Transactional(readOnly = true)
public PageResponse<BoardListDTO> list(PageRequest pageRequest) {
List<BoardListDTO> dtoList = boardMapper.listImage(pageRequest);
int total = boardMapper.count(pageRequest);
return PageResponse.<BoardListDTO>with()
.list(dtoList)
.total(total)
.pageRequest(pageRequest)
.build();
}
}
๐ service์ list์์ PageRequest๋ก ๋ฐ์ ๊ฐ์ Mapper.listImage๋ก ์ ๋ฌํ๋๋ฐ,
2-4. xml
<sql id="search">
<foreach item="type" collection="arr" open="AND (" close=")" separator="OR">
<if test='type.equals("T")'>
title like concat('%', #{keyword}, '%')
</if>
<if test='type.equals("C")'>
content like concat('%', #{keyword}, '%')
</if>
<if test='type.equals("W")'>
writer like concat('%', #{keyword}, '%')
</if>
</foreach>
</sql>
<select id="listImage" resultType="BoardListDTO">
select
board.bno, title, writer, regDate, modDate,
replyCnt, fileName
from
tbl_board board left join tbl_board_attach attach on attach.bno = board.bno
where (attach.ord = 0 or attach.ord is null)
<include refid="search"></include>
order by board.bno desc
limit #{skip}, #{size}
</select>
๐ xml์์๋ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ PageRequest์ธ
private int page = 1;
private int size = 10;
private String type;
private String keyword;
์ด๋ฌํ ์ ๋ณด๋ค์ ์ฌ์ฉํ๊ฒ๋๋ค. ๊ทธ ์ดํ list.html์
th:selected="${pageRequest.type == 'T'}" ๊ฐ์ ๋ง๋๊ฒ ๋๋๊ฒ์ด๋ค.
<div class="float-end">
<ul class="pagination flex-wrap">
<li class="page-item"><a class="page-link" href="#">PREV</a></li>
<th:block th:each="i : ${#numbers.sequence(result.startPage,result.endPage)}"> <!--th:block์ ์ฌ์ฉํ์ฌ liํ๊ทธ์ ๋ฐ๋ณต์ ๋ํด ์ฝ๊ฒ ํํ๊ฐ๋ฅ / startPage๋ถํฐ endPage๊น์ง์ ์ซ์์์ฑ -->
<li class="page-item" th:if="${i > 0}"><a class="page-link" th:href="${i}">[[${i}]]</a></li>
</th:block>
<li class="page-item"><a class="page-link" href="#">NEXT</a></li>
</ul>
</div>
๐ th:block์ ์ด์ฉํ๊ฒ ๋๋ฉด liํ๊ทธ์ ๋ฐ๋ณต์ ๋ณด๊ธฐ์ข๊ฒ ๋ง๋ค์์๋ค.
๐ ํด๋น ์ฝ๋๋ th:each๋ฅผ ์ฌ์ฉํ์ฌ, result.startPage๋ถํฐ endPage๊น์ง์ ๊ฐ์ ์ซ์๋ก ํํํ๋๊ฒ.