메인페이지(글목록)에서 로그인이 확인되면 글쓰기 버튼을 보여주고, 로그아웃 상태면 글쓰기 버튼을 숨깁니다.
thymeleaf에서 sec:authorize="isAuthenticated()" 를 사용하여 인증여부를 확인합니다.
public Long createBoard(BoardDto boardDto) { //글 등록
Account writer = accountRepository.findByNickname(boardDto.getWriter());
Board board = Board.builder()
.title(boardDto.getTitle())
.content(boardDto.getContent())
.writer(writer)
.count(boardDto.getCount())
.build();
boardRepository.save(board);
return board.getId();
} //BoardService.java
작성자는 DB를 조회해서 Account 테이블에 있는 nickname과 매칭합니다.
Account findByNickname(String nickname); //nickname을 검색하는데 사용
// AccountRepository.java
account 테이블과 board 테이블을 일대다 관계로 조인합니다.
@ManyToOne
@JoinColumn(name = "account_id")
private Account writer; //작성자
@OneToMany(mappedBy = "writer", cascade = CascadeType.ALL)
private List<Board> boards = new ArrayList<>();
board 테이블에 account_id 컬럼(외래키)이 추가되고 자동으로 값이 들어갑니다.
public List<BoardDto> postList(Long id) { //글 목록
List<Board> boardEntity = boardRepository.findAll(); //게시글 엔터티를 모두 가져옵니다.
List<BoardDto> boardDtoList = new ArrayList<>(); // BoardDto 객체들을 담을 리스트를 생성합니다.
for (Board board : boardEntity) { // 가져온 게시글 엔터티 목록을 순회합니다.
BoardDto boardDto = BoardDto.builder() // Board 엔터티를 BoardDto로 변환하는 작업
.id(board.getId()) //Board 엔터티의 ID를 BoardDto에 설정
.title(board.getTitle())
.count(board.getCount())
.writer(board.getWriter().getNickname())
.content(board.getContent())
.createdDate(board.getCreatedDate())
.build();
boardDtoList.add(boardDto); //변환된 BoardDto를 리스트에 추가합니다.
}
return boardDtoList; // 변환된 BoardDto 리스트를 반환합니다.
} // BoardService.java
@GetMapping("/")
public String home(@AuthenticationPrincipal UserAccount userAccount , Model model, Long id){
//spring security에서 생성된 커스텀 userDetails 객체입니다.
//엔터티를 직접적으로 참조하지 않고, 사용자 정보를 포함하고 있습니다.
if(userAccount != null){
model.addAttribute("userAccount", userAccount);
}
List<BoardDto> boardDtoList = boardService.postList(id);
model.addAttribute("boardDtoList",boardDtoList);
return "index";
} //Controller.java
Controller에서 PostList 메서드를 호출하고 반환된 List를 boardDtoList 변수에 할당합니다.
view에서는 boardDtoList에 있는 각각의 요소를 board 라는 임시 변수에 대입하여 반복문을 실행합니다.


public BoardDto getPostDetail(Long id) { //게시글 상세보기
Optional<Board> boardEntityWrapper = boardRepository.findById(id); // 주어진 ID에 해당하는 게시글을 찾습니다.
if (boardEntityWrapper.isPresent()) { //값이 존재하는지 확인
Board boardEntity = boardEntityWrapper.get(); //Optional 객체에서 실제 Board 엔터티를 가져옵니다. .get()메서드를 사용하여 실제 값을 추출
return BoardDto.builder()
.id(boardEntity.getId())
.writer(boardEntity.getWriter().getNickname()) //조인 했기 때문에 Board 엔터티의 writer에 대한 정보를 가져오고, 작성자의 닉네임을 반환합니다.
// writer는 Board 엔터티에서 Account를 참조하고 있습니다.
.title(boardEntity.getTitle())
.content(boardEntity.getContent())
.count(boardEntity.getCount())
.createdDate(boardEntity.getCreatedDate())
.build();
} else {
throw new EntityNotFoundException("게시글을 찾을 수 없습니다." + id);
}
}//BoardService.java

thymeleaf에서 접속중인 회원의 닉네임과 작성자를 비교해서 수정, 삭제 버튼을 노출합니다.
<div sec:authorize="isAuthenticated()"
class="nav-item dropdown open"
th:if='${userAccount.account.nickname.equals(boardDto.writer)}'
style="padding-left: 15px;">
<form th:action="@{'/board/delete/' + ${boardDto.id}}"
method="post"
style="margin: 0">
<input type="hidden" name="_method" value="delete"/>
<button class="btn btn-outline-primary" style="float: right;">삭제</button>
<a id="update" th:href="@{'/board/update/' + ${boardDto.id}}"
class="btn btn-outline-primary"
style="float: right;">수정</a>
</form>
</div>
1. 사용자가 닉네임을 변경하면, 변경된 닉네임이 기존 게시글에 update 되도록 구현
2. 사용자가 닉네임을 변경해도 이미 작성된 게시물의 작성자 정보는 변경되지 않도록 구현
첫번째 방법은 게시물이 많을 경우 업데이트 작업이 많아진다는 단점이 있지만,
커뮤니티의 투명성을 위해서 첫번째 방법을 채택하였고,
추후 닉네임 변경이 3일에 한번만 이루어질 수 있도록 제한할 것 입니다.


상세페이지에서 한차례 검증을 했지만
url 경로 조작을 방지하기 위해서 자기가 쓴글이 아닌경우 메인화면으로 리다이렉트 하는 코드를 추가했습니다.
@GetMapping("/board/update/{id}") //게시글 수정 페이지
public String boardUpdateForm(@AuthenticationPrincipal UserAccount userAccount, @PathVariable Long id, Model model) {
BoardDto boardDto = boardService.getPostDetail(id);
if (userAccount != null && userAccount.getUsername().equals(boardDto.getWriter())) { // 사용자가 로그인 상태인지, 현재 사용자의 이름과 게시글의 작성자와 일치하는지 검사
model.addAttribute("userAccount", userAccount);
model.addAttribute("boardDto", boardDto);
return "board/board-update";
}
return "redirect:/"; //사용자가 로그인하지 않았거나 본인이 작성한 게시글이 아닌경우 메인화면으로 리다이렉트합니다.
}
서비스에는 게시물을 업데이트 하는 코드가 있습니다.
public void BoardUpdate(Long id, BoardDto boardDto) {
Board board = boardRepository.findById(id)
.orElseThrow(IllegalArgumentException::new); // id에 해당하는 게시물을 찾아옵니다. 찾지 못하면 예외를 발생시킵니다.
board.update(boardDto.getTitle(), boardDto.getContent());
boardRepository.save(board);
}