

BoardResponse
package shop.mtcoding.blog.board;
import lombok.Data;
import org.springframework.data.domain.Page;
import shop.mtcoding.blog.reply.Reply;
import shop.mtcoding.blog.user.User;
import java.util.ArrayList;
import java.util.List;
public class BoardResponse {
@Data
public static class DTO {
private int id;
private String title;
private String content;
public DTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getContent();
}
}
// 게시글 상세보기 화면
@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, User 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){
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, User 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;
}
}
}
}
// 게시글 목록보기 화면
@Data
public static class MainDTO {
private int id;
private String title;
public MainDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
}
}
// 게시글 목록보기 화면
@Data
public static class MainV2DTO {
private Integer totalPage;
private Integer number; // 현재 페이지
private Boolean isFirst;
private Boolean isLast;
private List<BoardDTO> boards;
public MainV2DTO(Page<Board> boardPG) {
this.totalPage = boardPG.getTotalPages();
this.number = boardPG.getNumber();
this.isFirst = boardPG.isFirst();
this.isLast = boardPG.isLast();
this.boards = boardPG.getContent().stream().map(BoardDTO::new).toList();
}
@Data
public class BoardDTO {
private int id;
private String title;
public BoardDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
}
}
}
}
BoardService에 추가
public BoardResponse.MainV2DTO 글목록조회V2(Pageable pageable) {
Page<Board> boardPG = boardJPARepository.findAll(pageable);
return new BoardResponse.MainV2DTO(boardPG);
}

BoardController 이 부분으로 덮어씌워
@GetMapping("/")
public ResponseEntity<?> mainV2(@PageableDefault(size=3, sort="id", direction = Sort.Direction.DESC) Pageable pageable){
BoardResponse.MainV2DTO respDTO = boardService.글목록조회V2(pageable);
return ResponseEntity.ok(new ApiUtil(respDTO));
}
// 인증 필요 없음
@GetMapping("/v1")
public ResponseEntity<?> main(){
List<BoardResponse.MainDTO> respDTO = boardService.글목록조회();
return ResponseEntity.ok(new ApiUtil(respDTO));
}
바디데이터랑 똑같이 하면 됨.

Home.js
커서 ai post ⇒ board로 고치기



고치셈

detail에서도post⇒ board로 고치기
Detail.js
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import { Link, useParams } from "react-router-dom";
const Detail = (props) => {
const { id } = useParams();
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`,
});
let responseBody = response.data;
setBoard(responseBody.body);
}
function fetchDelete(boardId) {}
return (
<div>
<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;
Home.js
import axios from "axios";
import React, { useEffect, useState } from "react";
import { Pagination } from "react-bootstrap";
import PostItem from "../../components/BoardItem";
const Home = () => {
const [page, setPage] = useState(0);
const [model, setModel] = useState({
totalPage: undefined,
number: undefined,
isFirst: true,
isLast: false,
boards: [],
});
// http://localhost:8080 -> http://localhost:8080?page=0
// 실행시점 : 최초 렌더링
// 변경 : page가 바뀌면 useEffect 실행되게 할 예정
useEffect(() => {
console.log("useEffect 실행");
apiHome();
}, [page]);
async function apiHome() {
let response = await axios({
url: "http://localhost:8080?page=" + page,
method: "get",
});
console.log("page", response.data.body);
setModel(response.data.body);
}
function prev() {
setPage(page - 1);
}
function next() {
console.log("next click");
setPage(page + 1);
}
return (
<div>
{model.boards.map((board) => (
<PostItem key={board.id} id={board.id} title={board.title} />
))}
<br />
<div className="d-flex justify-content-center">
<Pagination>
<Pagination.Item onClick={prev} disabled={model.isFirst}>
Prev
</Pagination.Item>
<Pagination.Item onClick={next} disabled={model.isLast}>
Next
</Pagination.Item>
</Pagination>
</div>
</div>
);
};
export default Home;
Share article