1. BoardController
// 인증 필요 없음
@GetMapping("/api/boards/{id}/detail")
public ResponseEntity<?> detail(@PathVariable Integer id, HttpServletRequest request){
String jwt = request.getHeader("Authorization");
try {
if(jwt != null){
jwt = jwt.replace("Bearer ", "");
SessionUser sessionUser = JwtUtil.verify(jwt);
// 임시 세션 (jsessionId는 필요 없음)
HttpSession session = request.getSession();
session.setAttribute("sessionUser", sessionUser);
}
}catch (Exception e){
throw new Exception401("토큰 검증 실패");
}
SessionUser sessionUser = (SessionUser) session.getAttribute("sessionUser");
BoardResponse.DetailDTO respDTO = boardService.글상세보기(id, sessionUser);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
2. BoardService
public BoardResponse.DetailDTO 글상세보기(int boardId, SessionUser sessionUser) {
Board board = boardJPARepository.findByIdJoinUser(boardId)
.orElseThrow(() -> new Exception404("게시글을 찾을 수 없습니다"));
return new BoardResponse.DetailDTO(board, sessionUser);
}
3. BoardResponse
@Data
public static class DetailDTO {
private int id;
private String title;
private String content;
private int userId;
private String username; // 게시글 작성자 이름
private boolean isOwner;
private List<ReplyDTO> replies = new ArrayList<>();
public DetailDTO(Board board, SessionUser sessionUser) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
this.userId = board.getUser().getId();
this.username = board.getUser().getUsername(); // join 해서 가져왔음
this.isOwner = false;
if(sessionUser != null){
System.out.println("로그인한 userId : "+sessionUser.getId());
if(sessionUser.getId() == userId) isOwner = true;
}
this.replies = board.getReplies().stream().map(reply -> new ReplyDTO(reply, sessionUser)).toList();
}
@Data
public class ReplyDTO {
private int id;
private String comment;
private int userId; // 댓글 작성자 아이디
private String username; // 댓글 작성자 이름
private boolean isOwner;
public ReplyDTO(Reply reply, SessionUser sessionUser) {
this.id = reply.getId(); // lazy loading 발동
this.comment = reply.getComment();
this.userId = reply.getUser().getId();
this.username = reply.getUser().getUsername(); // lazy loading 발동 (in query)
this.isOwner = false;
if(sessionUser != null){
if(sessionUser.getId() == userId) isOwner = true;
}
}
}
}
4. 인터셉터 수정 (session 날리기)
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HttpSession session = request.getSession();
session.invalidate();
}
5. React Detail 페이지 수정
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import { useSelector } from "react-redux";
import { Link, useParams } from "react-router-dom";
const Detail = (props) => {
const { id } = useParams();
const jwt = useSelector((state) => state.jwt);
const [board, setBoard] = useState({
id: undefined,
title: "",
content: "",
userId: undefined,
username: "",
owner: false,
replies: [],
});
useEffect(() => {
fetchDetail(id);
}, []);
async function fetchDetail(boardId) {
let response = await axios({
url: `http://localhost:8080/api/boards/${boardId}/detail`,
headers: {
Authorization: jwt,
},
});
let responseBody = response.data;
setBoard(responseBody.body);
}
function fetchDelete(boardId) {}
return (
<div>
<h1>{board.owner.toString()}</h1>
{board.owner ? (
<>
<Link to={`/updateForm/${board.id}`} className="btn btn-warning">
수정
</Link>
<Button
className="btn btn-danger"
onClick={() => fetchDelete(board.id)}
>
삭제
</Button>
</>
) : (
""
)}
<br />
<br />
<h1>{board.title}</h1>
<hr />
<div>{board.content}</div>
</div>
);
};
export default Detail;
Share article