
BoardWrite.jsx(React)
export function BoardWrite() {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [writer, setWriter] = useState("");
function handleSaveClick() {
axios.post("/api/board/add", {
title,
content,
writer,
});
}
return (
<Box>
<Box>๊ธ ์์ฑ ํ๋ฉด</Box>
<Box>
<Box>
<FormControl>
<FormLabel>์ ๋ชฉ</FormLabel>
<Input onChange={(e) => setTitle(e.target.value)} />
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋ณธ๋ฌธ</FormLabel>
<Textarea onChange={(e) => setContent(e.target.value)} />
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>์์ฑ์</FormLabel>
<Input onChange={(e) => setWriter(e.target.value)} />
</FormControl>
</Box>
<Box>
<Button colorScheme={"blue"} onClick={handleSaveClick}>
์ ์ฅ
</Button>
</Box>
</Box>
</Box>
);
}
Board.java
@Data
public class Board {
private Integer id;
private String title;
private String content;
private String writer;
private LocalDateTime inserted;
}
BoardController.java
@RestController
@RequestMapping("/api/board")
@RequiredArgsConstructor
public class BoardController {
private final BoardService service;
@PostMapping("add")
public void add(@RequestBody Board board) {
service.add(board);
}
}
/api/board/add ๊ฒฝ๋ก๋ก ๋ค์ด์ค๋ POST ์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.@RequestBody ์ ๋ํ
์ด์
์ ์ฌ์ฉํ์ฌ JSON ํ์์ ์์ฒญ ๋ณธ๋ฌธ์ ์๋์ผ๋ก Board ๊ฐ์ฒด๋ก ๋ณํํฉ๋๋ค.Board ๊ฐ์ฒด๋ฅผ service.add(board)๋ฅผ ํธ์ถํ์ฌ BoardService๋ก ์ ๋ฌํ๊ณ ๊ฒ์๋ฌผ์ ์ ์ฅํฉ๋๋ค.BoardService.java
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class BoardService {
private final BoardMapper mapper;
public void add(Board board) {
mapper.insert(board);
}
}
BoardMapper.java
@Mapper
public interface BoardMapper {
@Insert("""
INSERT INTO board (title, content, writer)
VALUES (#{title}, #{content}, #{writer})
""")
int insert(Board board);
}
๐ฆ ๊ฒ์๊ธ ์์ฑ์ ๋ํ ๋ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ ์ถ๊ฐ
๐ข ๋ง์ฝ ๊ฒ์๊ธ์ด ์ ์์ฑ๋์๋ค๋ฉด 200 ์ฝ๋๋ฅผ ๋ฐํํ๊ณ ๊ฒ์๊ธ์ ์ ๋ชฉ, ๋ณธ๋ฌธ, ์์ฑ์๊ฐ ๋น์ด์๋ค๋ฉด 400 ์ฝ๋๋ฅผ ๋ฐํํฉ๋๋ค.
๐ข Service์์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๊ณ ๊ทธ๊ฒ์ Controller์๊ฒ ๋๊ฒจ์ค ํด๋น ์๋ต ์ฝ๋์ ๋ง๊ฒ ํ๋ฉด์ ํ์ํฉ๋๋ค.
BoardController.java
@RestController
@RequestMapping("/api/board")
@RequiredArgsConstructor
public class BoardController {
private final BoardService service;
@PostMapping("add")
public ResponseEntity add(@RequestBody Board board) {
if (service.validate(board)) {
service.add(board);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
}
BoardController๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ฐ์ ๊ฒ์๊ธ์ BoardService๋ฅผ ํตํด ๋ฑ๋กํ๊ณ , ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํตํด ์ ์ ํ HTTP ์๋ต์ ๋ฐํํฉ๋๋ค.BoardService์ ํ ์ ํจ์ฑ ๊ฒ์ฌ๊ฐ true๋ผ๋ฉด ๊ฒ์๊ธ์ ๋ฑ๋ก์ด ์ ๋์ด 200๋ฒ ์๋ต์ ๋ฐํํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด 400๋ฒ ์๋ต์ ๋ฐํํฉ๋๋ค.BoardService.java
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class BoardService {
private final BoardMapper mapper;
~~~~~~
// ์ ๋ชฉ, ๋ด์ฉ, ์์ฑ์ ์ ํจ์ฑ ๊ฒ์ฌ(์์ฑ๋์๋์ง)
public boolean validate(Board board) {
if (board.getTitle() == null || board.getTitle().isBlank()) {
return false;
}
if (board.getContent() == null || board.getContent().isBlank()) {
return false;
}
if (board.getWriter() == null || board.getWriter().isBlank()) {
return false;
}
return true;
}
}
Board ๊ฐ์ฒด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ ๋ชฉ, ๋ณธ๋ฌธ, ์์ฑ์ ์
๋ ฅ ๊ฐ์ด null์ด๊ฑฐ๋ ๋น์ด ์๋ค๋ฉด ์ ํจํ์ง ์๊ธฐ ๋๋ฌธ์ false ๋ฅผ ๋ฐํํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด true๋ฅผ ๋ฐํํฉ๋๋ค.BoardWrite.jsx(React)
export function BoardWrite() {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const [writer, setWriter] = useState("");
const toast = useToast();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
function handleSaveClick() {
setLoading(true);
axios
.post("/api/board/add", {
title,
content,
writer,
})
.then(() => {
toast({
description: "์ ๊ธ์ด ๋ฑ๋ก๋์์ต๋๋ค.",
status: "success",
position: "top-right",
duration: 1000,
});
navigate("/");
})
.catch((error) => {
const code = error.response.status;
if (code === 400) {
toast({
status: "error",
description: "๋ฑ๋ก๋์ง ์์์ต๋๋ค. ์
๋ ฅํ ๋ด์ฉ์ ํ์ธํด์ฃผ์ธ์.",
position: "top-right",
duration: 1000,
});
}
})
.finally(() => setLoading(false));
}
// ์ ๋ชฉ, ๋ณธ๋ฌธ, ์์ฑ์ ์์ฑํ์ง ์์ผ๋ฉด ํ์ฑํ๊ฐ ๋์ง ์๋๋ค.
let disableSaveButton = false;
if (title.trim().length === 0) {
disableSaveButton = true;
}
if (content.trim().length === 0) {
disableSaveButton = true;
}
if (writer.trim().length === 0) {
disableSaveButton = true;
}
return (
<Box>
~~~~
<Button
isLoading={loading}
isDisabled={disableSaveButton}
colorScheme={"blue"}
onClick={handleSaveClick}
>
์ ์ฅ
</Button>
~~~~
</Box>
);
}
axios.post("/api/board/add") ๊ฒฝ๋ก๋ก ์์ฒญ ๋ณธ๋ฌธ์ title, content, writer ๊ฐ์ ๋ด๊ณ ์์ฒญํฉ๋๋ค..then()) : "์ ๊ธ์ด ๋ฑ๋ก๋์์ต๋๋ค." ๋ฉ์์ง๋ฅผ ํ ์คํธ๋ก ํ์ํ๊ณ ๋ฉ์ธ ํ์ด์ง๋ก ์ด๋(navigate("/"))ํฉ๋๋ค. .catch()) : 400 ์ํ ์ฝ๋์ ๋ฐ๋ผ "๋ฑ๋ก๋์ง ์์์ต๋๋ค. ์
๋ ฅํ ๋ด์ฉ์ ํ์ธํด์ฃผ์ธ์." ๋ฉ์์ง๋ฅผ ํ ์คํธ๋ก ํ์ํฉ๋๋ค.disableSaveButton() : ๋ง์ฝ์ title, content, writer ์
๋ ฅ ๊ฐ์ด ๋น์ด์๋ค๋ฉด ์ ์ฅ ๋ฒํผ์ ๋นํ์ฑ(true)ํฉ๋๋ค.loading : ๋ฒํผ ํด๋ฆญ ์ ๋ก๋ฉ์ค์ผ๋ก ๋ณํ๋๋ฉฐ post ์์ฒญ ๋ณด๋ด๊ธฐ ์ ์ true๋ก ์ค์ ํ๊ณ ๋ณด๋ธ ํ์๋ ์์ฒญ ์ฑ๊ณต, ์คํจ์ ๋ฐ๋ฅด์ง ์๊ณ ๋ฌด์กฐ๊ฑด ๋ก๋ฉ์ด ๋๋์ผ ํ๊ธฐ ๋๋ฌธ์ false๋ก ์ค์ ํฉ๋๋ค.
๐ฆ ๊ฒ์๊ธ ์ ์ฒด ๋ณด์ฌ์ฃผ๊ธฐ(Home)
BoardList.jsx(React)
export function BoardList() {
const navigate = useNavigate();
const [boardList, setBoardList] = useState([]);
// const boardList = [
// { id: 5, title: "title1", writer: "who1" },
// ];
useEffect(() => {
axios.get("/api/board/list").then((res) => setBoardList(res.data));
}, []);
return (
<Box>
<Box>๊ฒ์๋ฌผ ๋ชฉ๋ก</Box>
<Box>
<Table>
<Thead>
<Tr>
<Th>NO</Th>
<Th>์ ๋ชฉ</Th>
<Th>
<FontAwesomeIcon icon={faUserPen} />
</Th>
</Tr>
</Thead>
<Tbody>
{boardList.map((board) => (
<Tr
cursor={"pointer"}
_hover={{ bgColor: "gray.200" }}
onClick={() => navigate(`/board/${board.id}`)}
key={board.id}
>
<Td>{board.id}</Td>
<Td>{board.title}</Td>
<Td>{board.writer}</Td>
</Tr>
))}
</Tbody>
</Table>
</Box>
</Box>
);
}
axios.get(/api/board/list) ํธ์ถ์์ ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ setBoard(res.data)๋ฅผ ํตํด board ์ํ์ ์ ์ฅํฉ๋๋ค.boardList.map((board) => () : boardList๋ฅผ ์ํํ๋ฉด์ ๊ฐ board ๊ฐ์ฒด์ ๋ํ ์์ฑ(id, title, writer)๋ค์ ๊ฐ์ ๋ ๋๋งํฉ๋๋ค.useEffect() : axios๋ฅผ ์ฌ์ฉํ์ฌ GET ์์ฒญ์ผ๋ก ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ฒ๋ก๋ถํฐ ๊ฒ์๋ฌผ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๊ณ , ๊ทธ ๋ชฉ๋ก์ boardList ์ํ์ ์ ์ฅํฉ๋๋ค.BoardController.java
@GetMapping("list")
public List<Board> list() {
return service.list();
}
/api/board/list๋ก ์์ฒญ์ด ๋ค์ด์ค๋ฉด BoardService์ list() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๊ฒ์๋ฌผ ๋ชฉ๋ก์ ์ฒ๋ฆฌํฉ๋๋ค.BoardService.java
public List<Board> list() {
return mapper.selectAll();
}
BoardMapper.java
@Select("SELECT id, title, writer FROM board ORDER BY id DESC")
List<Board> selectAll();

๐ฆ ๊ฒ์๋ฌผ ํด๋ฆญ ์ ํด๋น ๊ฒ์๋ฌผ ๋ณด๊ธฐ
BoardView.jsx(React)
export function BoardView() {
const { id } = useParams();
const [board, setBoard] = useState(null);
const toast = useToast();
const navigate = useNavigate();
useEffect(() => {
axios
.get(`/api/board/${id}`)
.then((res) => setBoard(res.data))
.catch((err) => {
if (err.response.status === 404) {
toast({
status: "info",
description: "ํด๋น ๊ฒ์๋ฌผ์ด ์กด์ฌํ์ง ์์ต๋๋ค.",
position: "top-right",
});
navigate("/");
}
});
}, []);
if (board === null) {
return <Spinner />;
}
return (
<Box>
<Box>{board.id}๋ฒ ๊ฒ์๋ฌผ</Box>
<Box>
<FormControl>
<FormLabel>์ ๋ชฉ</FormLabel>
<Input value={board.title} readOnly />
</FormControl>
<Box>
<FormControl>
<FormLabel>๋ณธ๋ฌธ</FormLabel>
<Input value={board.content} readOnly />
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>์์ฑ์</FormLabel>
<Input value={board.writer} readOnly />
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>์์ฑ์ผ์</FormLabel>
<Input type={"datetime-local"} value={board.inserted} readOnly />
</FormControl>
</Box>
</Box>
</Box>
);
}
/api/board/${id} ๊ฒฝ๋ก๋ก get ์์ฒญ์ ๋ณด๋ด๊ณ ์์ฒญ์ ์ฑ๊ณตํ๋ฉด board์ ์๋ ๋ฐ์ดํฐ(title, content, writer)์ board ์ํ์ ์ ์ฅํ๊ณ ์์ฒญ์ ์คํจํ๋ฉด ์คํจ ์ฝ๋๊ฐ 404๋ผ๋ฉด ํ ์คํธ๋ก ํ๋ฉด์ ํ์ํ๊ณ home('/')์ผ๋ก ์ด๋ํฉ๋๋ค.const { id } = useParams(): URL์ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ์์ id ๊ฐ์ ์ถ์ถํฉ๋๋ค.axios.get(/api/board/${id}) ํธ์ถ์์ ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ setBoard(res.data)๋ฅผ ํตํด board ์ํ์ ์ ์ฅํฉ๋๋ค.BoardController.java
// /api/board/5
@GetMapping("{id}")
public ResponseEntity get(@PathVariable Integer id) {
Board board = service.get(id);
if (board == null) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok().body(board);
}
/api/board/id๋ก GET ์์ฒญ์ด ๋ค์ด์ค๋ฉด BoardService์ list() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๊ฒ์๋ฌผ ๋ชฉ๋ก์ ๋ฐํํฉ๋๋ค.@PathVariable : URL ๊ฒฝ๋ก์์ {id} ๋ถ๋ถ์ ์ถ์ถํ์ฌ ๋ฉ์๋ ๋งค๊ฐ๋ณ์ id์ ๋ฐ์ธ๋ฉํฉ๋๋ค.ResponseEntity๋ HTTP ์๋ต์ ๋ํ๋ด๋ ๊ฐ์ฒด๋ก, ์ํ ์ฝ๋์ ์๋ต ๋ณธ๋ฌธ์ ํฌํจํ ์ ์์ต๋๋ค.BoardService.java
public Board get(Integer id) {
return mapper.selectById(id);
}
BoardMapper.java
@Select("SELECT * FROM board WHERE id = #{id}")
Board selectById(Integer id);

BoardView.jsx(React)
export function BoardView() {
const { id } = useParams();
const [board, setBoard] = useState({});
const toast = useToast();
const navigate = useNavigate();
const { isOpen, onClose, onOpen } = useDisclosure();
~~~
function handleClickRemove() {
axios
.delete(`/api/board/${id}`)
.then(() => {
toast({
status: "success",
description: `${id}๋ฒ ๊ฒ์๋ฌผ์ด ์ญ์ ๋์์ต๋๋ค.`,
position: "top-right",
});
navigate("/");
})
.catch(() => {
toast({
status: "error",
description: `${id}๋ฒ ๊ฒ์๋ฌผ ์ญ์ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์์ต๋๋ค.`,
position: "top-right",
});
})
.finally(() => {
onClose();
});
}
return (
<Box>
~~~~~
<Box>
<Button colorScheme={"purple"}>์์ </Button>
<Button colorScheme={"red"} onClick={onOpen}>
์ญ์
</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody>์ ๋ง๋ก ์ญ์ ํ์๊ฒ ์ต๋๊น?</ModalBody>
<ModalFooter>
<Button onClick={onClose}>์ทจ์</Button>
<Button colorScheme={"red"} onClick={handleClickRemove}>
ํ์ธ
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Box>
</Box>
);
}
handleClickRemove ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค.handleClickRemove() : axios๋ก /api/board/${id} ๊ฒฝ๋ก๋ก delete ์์ฒญ์ ๋ณด๋ด๊ณ ์์ฒญ ์ฑ๊ณตํ๋ฉด ํ ์คํธ ํ์์ home(/)์ผ๋ก ๊ฒฝ๋ก ์ด๋ํฉ๋๋ค.BoardController.java
@DeleteMapping("{id}")
public void delete(@PathVariable Integer id) {
service.remove(id);
}
@PathVariable : URL ๊ฒฝ๋ก์์ {id} ๋ถ๋ถ์ ์ถ์ถํ์ฌ ๋ฉ์๋ ๋งค๊ฐ๋ณ์ id์ ๋ฐ์ธ๋ฉํฉ๋๋ค.BoardService์์ ํด๋น id ๊ฒ์๊ธ์ ์ญ์ ํฉ๋๋ค./api/board/id๋ก Delete ์์ฒญ์ด ๋ค์ด์ค๋ฉด BoardService์ remove() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ํด๋น ๊ฒ์๋ฌผ์ ์ญ์ ํฉ๋๋ค.BoardService.java
public void remove(Integer id) {
mapper.deleteById(id);
}
BoardMapper.java
@Delete("DELETE FROM board WHERE id=#{id}")
int deleteById(Integer id);


BoardView.jsx(React)
<Button
colorScheme={"purple"}
onClick={() => navigate(`/edit/${board.id}`)}
>
์์
</Button>
/edit/${board.id} ๊ฒฝ๋ก)๋ก ์ด๋ํฉ๋๋ค.BoardEdit.jsx(React)
export function BoardEdit() {
const { id } = useParams();
const [board, setBoard] = useState(null);
const toast = useToast();
const navigate = useNavigate();
const { isOpen, onClose, onOpen } = useDisclosure();
useEffect(() => {
axios.get(`/api/board/${id}`).then((res) => setBoard(res.data));
}, []);
function handleClickSave() {
axios
.put("/api/board/edit", board)
.then(() => {
toast({
status: "success",
description: `${board.id}๋ฒ ๊ฒ์๋ฌผ์ด ์์ ๋์์ต๋๋ค.`,
position: "top-right",
});
navigate(`/board/${board.id}`);
})
.catch((err) => {
if (err.response.status === 400) {
toast({
status: "error",
description: `๊ฒ์๋ฌผ์ด ์์ ๋์ง ์์์ต๋๋ค. ์์ฑํ ๋ด์ฉ์ ํ์ธํด์ฃผ์ธ์.`,
position: "top-right",
});
}
})
.finally(() => {
onClose();
});
}
if (board === null) {
return <Spinner />;
}
return (
<Box>
<Box>{board.id}๋ฒ ๊ฒ์๋ฌผ ์์ </Box>
<Box>
<Box>
<FormControl>
<FormLabel>์ ๋ชฉ</FormLabel>
<Input
defaultValue={board.title}
onChange={(e) => setBoard({ ...board, title: e.target.value })}
/>
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>๋ณธ๋ฌธ</FormLabel>
<Textarea
defaultValue={board.content}
onChange={(e) => setBoard({ ...board, content: e.target.value })}
></Textarea>
</FormControl>
</Box>
<Box>
<FormControl>
<FormLabel>์์ฑ์</FormLabel>
<Input
defaultValue={board.writer}
onChange={(e) => setBoard({ ...board, writer: e.target.value })}
/>
</FormControl>
</Box>
<Box>
<Button colorScheme={"green"} onClick={onOpen}>
์ ์ฅ
</Button>
</Box>
</Box>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader></ModalHeader>
<ModalBody>์ ์ฅํ์๊ฒ ์ต๋๊น?</ModalBody>
<ModalFooter>
<Button onClick={onClose}>์ทจ์</Button>
<Button onClick={handleClickSave} colorScheme={"blue"}>
ํ์ธ
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Box>
);
}
axios.get(/api/board/${id}) ํธ์ถ์์ ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ setBoard(res.data)๋ฅผ ํตํด board ์ํ์ ์ ์ฅํฉ๋๋ค. board์ ์ ์ฅ๋ ๊ฐ์ ์์ ํ์ด์ง์ ๋ค์ด๊ฐ์ ๋ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด์ defaultValue๋ก ์ ์ฅํด์ค๋๋ค.onChange={(e) => setBoard({ ...board, ํ๋กํผํฐ: e.target.value })} : <Input/> ํ๊ทธ์ ์
๋ ฅ ๊ฐ์ ๊ธ์ ์
๋ ฅํ๋ค๋ฉด setBoard() ํจ์๋ฅผ ํธ์ถํ์ฌ board ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ์ด์ board ์ํ๋ฅผ ๋ณต์ฌํ๊ณ , ์๋ก์ด ๊ฐ์ผ๋ก ํ๋กํผํฐ(title, content, writer)๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. e.target.value๋ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ์๋ก์ด ํ๋กํผํฐ ๊ฐ์
๋๋ค.handleClickSave ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.handleClickSave ๋ฉ์๋ : board ๊ฐ์ฒด๋ฅผ ๋ด์ ์๋ฒ์๊ฒ axios.put(/api/board/edit) ์์ฒญ์ ํฉ๋๋ค. ์์ฒญ ์ฑ๊ณต ์, toast๋ก ์ฑ๊ณต ๋ฉ์์ง๋ฅผ ํ๋ฉด์ ํ์ํ๊ณ ํด๋น ๊ฒ์๋ฌผ(/board/${board.id} ๊ฒฝ๋ก)๋ก ์ด๋ํ๊ณ ์์ฒญ ์คํจ ์, ์๋ต ์ฝ๋๊ฐ 400์ด๋ผ๋ฉด toast๋ก ์๋ฌ ๋ฉ์์ง๋ฅผ ํ๋ฉด์ ํ์ํฉ๋๋ค.BoardController.java
@PutMapping("edit")
public ResponseEntity edit(@RequestBody Board board) {
if (service.validate(board)) {
service.edit(board);
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}
}
/api/board/edit๋ก ์์ฒญ์ด ๋ค์ด์ค๋ฉด BoardService์์ ํด๋น id ๊ฒ์๊ธ์ ์์ ํฉ๋๋ค.BoardService.java
public void edit(Board board) {
mapper.update(board);
}
BoardMapper.java
@Update("""
UPDATE board SET title=#{title}, content=#{content}, writer=#{writer}
WHERE id=#{id}
""")
int update(Board board);


