
1. index.mustache에서 검색 폼 만들기
- 쿼리 스트링이 body값으로 감
- keyword값 들고 page는 안넣었으니까 0, ‘/’로 감
- form태그 안에 들어있고 메서드가 get이면 ‘/’가 들어가짐
{{> layout/header}}
<div class="container p-5">
<div class="row justify-content-end">
<div class="col-md-4">
<form action="/" method="get" class="form-inline">
<div class="input-group rounded">
<input class="form-control me-2 rounded-end" type="text" placeholder="Search..." name="keyword" />
<button class="btn btn-primary rounded-start" type="submit">검색</button>
</div>
</form>
</div>
</div>
</div>
{{#boardList}}
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/boardList}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item {{#first}}disabled{{/first}}"><a class="page-link" href="?page={{prev}}&keyword={{keyword}}">Previous</a></li>
<li class="page-item {{#last}}disabled{{/last}}"><a class="page-link" href="?page={{next}}&keyword={{keyword}}">Next</a></li>
</ul>
</div>
{{> layout/footer}}
- null을 허용하던지 defaultValue를 넣어줘야 함
- isEmpty : 공백, null
- isBrank : 공백, null, space
package shop.mtcoding.blog.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@RequiredArgsConstructor
@Repository
public class BoardRepository {
private final EntityManager em;
public Long count() {
Query query = em.createNativeQuery("select count(8) from board_tb");
return (Long) query.getSingleResult();
}
public Long count(String keyword) {
Query query = em.createNativeQuery("select count(*) from board_tb where title like ?");
query.setParameter(1, "%"+keyword+"%");
return (Long) query.getSingleResult();
}
public List<Board> findAll(Integer page, String keyword) {
Query query = em.createNativeQuery("select * from board_tb where title like ? order by id desc limit ?, 3", Board.class);
query.setParameter(1, "%"+keyword+"%");
query.setParameter(2, page * 3);
return query.getResultList();
}
public List<Board> findAll(Integer page) {
Query query = em.createNativeQuery("select * from board_tb order by id desc limit ?,3", Board.class);
query.setParameter(1, page*3);
return query.getResultList();
}
public Board findById(int id) {
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
Board board = (Board) query.getSingleResult();
return board;
}
public BoardResponse.DetailDTO findByIdWithUser(int idx) {
Query query = em.createNativeQuery("select b.id, b.title, b.content, b.user_id, u.username from board_tb b inner join user_tb u on b.user_id = u.id where b.id = ?");
query.setParameter(1, idx);
Object[] row = (Object[]) query.getSingleResult();
Integer id = (Integer) row[0];
String title = (String) row[1];
String content = (String) row[2];
int userId = (Integer) row[3];
String username = (String) row[4];
System.out.println("id : " + id);
System.out.println("title : " + title);
System.out.println("content : " + content);
System.out.println("userId : " + userId);
System.out.println("username : " + username);
BoardResponse.DetailDTO responseDTO = new BoardResponse.DetailDTO();
responseDTO.setId(id);
responseDTO.setTitle(title);
responseDTO.setContent(content);
responseDTO.setUserId(userId);
responseDTO.setUsername(username);
return responseDTO;
}
@Transactional
public void save(BoardRequest.SaveDTO requestDTO, int userId) {
Query query = em.createNativeQuery("insert into board_tb(title, content, user_id, created_at) values(?,?,?, now())");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, userId);
query.executeUpdate();
}
@Transactional
public void deleteById(int id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
@Transactional
public void update(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title=?, content=? where id = ?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, id);
query.executeUpdate();
}
}
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.blog.reply.ReplyRepository;
import shop.mtcoding.blog.user.User;
import java.util.List;
@RequiredArgsConstructor
@Controller
public class BoardController {
private final HttpSession session; // DI
private final BoardRepository boardRepository; // DI
private final ReplyRepository replyRepository;
// ?title=제목1&content=내용1
// title=제목1&content=내용1
// 쿼리 스트링과 -x-www-form-urlencoded와 파싱 방법이 동일함
@PostMapping("/board/{id}/update")
public String update(@PathVariable int id, BoardRequest.UpdateDTO requestDTO) { // 파싱 전략이 json으로 바뀜
// System.out.println(requestDTO); 정보 받기 확인
// 인증 체크하기
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 권한 체크하기
Board board = boardRepository.findById(id);
if (board.getUserId() != sessionUser.getId()) {
return "error/403";
}
// update board_tb set title =?, content =?, where id =?
boardRepository.update(requestDTO, id);
return "redirect:/board/" + id; // 수정한 게시글로 돌아가기
}
@GetMapping("/board/{id}/updateForm") // 보드에 해당 페이지
public String updateFormn(@PathVariable int id, HttpServletRequest request) {
// 인증 체크하기
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 권한 체크하기
Board board = boardRepository.findById(id);
if (board.getUserId() != sessionUser.getId()) {
request.setAttribute("status", 403);
request.setAttribute("msg", "게시글을 수정할 권한이 없습니다");
return "error/40x"; // 리다이렉트 하면 데이터 사라지니까 하면 안됨
}
// 가방에 담기
request.setAttribute("board", board);
return "board/updateForm";
}
@PostMapping("/board/{id}/delete") // body데이터가 없어서 유효성 검사 안해도 됨
public String delete(@PathVariable int id) {
// 1. 인증 검사하기
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 권한 검사하기
Board board = boardRepository.findById(id);
if (board.getUserId() != sessionUser.getId()) {
return "error/403";
}
boardRepository.deleteById(id);
return "redirect:/";
}
@PostMapping("/board/save")
public String save(BoardRequest.SaveDTO requestDTO, HttpServletRequest request) {
// 1. 인증 체크
User sessionUser = (User) session.getAttribute("sessionUser");
System.out.println("sessionUser:" + sessionUser);
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 바디 데이터 확인 및 유효성 검사
System.out.println(requestDTO);
if (requestDTO.getTitle().length() > 30) {
request.setAttribute("status", 400);
request.setAttribute("msg", "title의 길이가 30자를 초과해서는 안되요");
return "error/40x"; // BadRequest
}
// 3. 모델 위임
// insert into board_tb(title, content, user_id, created_at) values(?,?,?, now());
boardRepository.save(requestDTO, sessionUser.getId());
return "redirect:/";
}
// http://localhost:8080?page=0 쿼리스트링
// 스프링에서 쿼리 스트링 받는 방법은 매개 변수에 받기
@GetMapping({"/"})
public String index(HttpServletRequest request,
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "") String keyword) {
// isEmpty : 공백, null
// isBlank : 공백, null, 화이트 space(눈에 안보이는 공백)
if (keyword.isBlank()) {
List<Board> boardList = boardRepository.findAll(page);
// 전체 페이지 개수
int count = boardRepository.count().intValue();
int namerge = count % 3 == 0 ? 0 : 1;
int allPageCount = count / 3 + namerge;
request.setAttribute("boardList", boardList);
request.setAttribute("first", page == 0);
request.setAttribute("last", allPageCount == page + 1);
request.setAttribute("prev", page - 1);
request.setAttribute("next", page + 1);
request.setAttribute("keyword", "");
} else {
List<Board> boardList = boardRepository.findAll(page, keyword);
// 전체 페이지 개수
int count = boardRepository.count(keyword).intValue();
int namerge = count % 3 == 0 ? 0 : 1;
int allPageCount = count / 3 + namerge;
request.setAttribute("boardList", boardList);
request.setAttribute("first", page == 0);
request.setAttribute("last", allPageCount == page + 1);
request.setAttribute("prev", page - 1);
request.setAttribute("next", page + 1);
request.setAttribute("keyword", keyword);
}
return "index";
}
@GetMapping("/board/saveForm") // /board/saveForm Get요청이 옴
public String saveForm() { // session 영역에 접근하기 위한
// 1. session 영역에 sessionUser 키 값에 user 객체가 있는지 체크하기
User sessionUser = (User) session.getAttribute("sessionUser");
// 2. 값이 null이면 로그인 페이지로 리다이렉션
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 3. null이 아니면 /board/saveForm으로 이동
return "board/saveForm";
}
// 상세보기시 호출
@GetMapping("/board/{id}") // 1이 프라이머리키 -> 뭐든 넣어도 실행시키려면 변수화시켜서 {}
public String detail(@PathVariable int id, HttpServletRequest request) {
User sessionUser = (User) session.getAttribute("sessionUser"); // 페이지 권한
BoardResponse.DetailDTO boardDTO = boardRepository.findByIdWithUser(id); //메서드 이름 변경
boardDTO.isBoardOwner(sessionUser); // null이면 터짐
List<BoardResponse.ReplyDTO> replyDTOList = replyRepository.findByBoardId(id, sessionUser);
request.setAttribute("board", boardDTO);
request.setAttribute("replyList", replyDTOList);
return "board/detail";
}
}




더미 데이터 추가후 테스트 하기
insert into user_tb(username, password, email, created_at) values('ssar', '1234', 'ssar@nate.com', now());
insert into user_tb(username, password, email, created_at) values('cos', '1234', 'cos@nate.com', now());
insert into board_tb(title, content, user_id, created_at) values('제목1', '내용1', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목2', '내용2', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목3', '내용3', 1, now());
insert into board_tb(title, content, user_id, created_at) values('제목4', '내용4', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title5', '내용5', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title6', '내용6', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title7', '내용7', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title8', '내용8', 2, now());
insert into board_tb(title, content, user_id, created_at) values('title9', '내용9', 2, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글1', 1, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글2', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글3', 4, 1, now());
insert into reply_tb(comment, board_id, user_id, created_at) values('댓글4', 4, 2, now());



Share article