JavaScript와 XML을 이용한 비동기적 정보 교환 기법
브라우저의 XMLHttpRequest를 이용해 전체 페이지를 새로 가져오지 않고도 페이지 일부만을 변경할 수 있도록 javascript를 실행해 서버에 데이터만을 별도로 요청하는 기법
1. AJAX의 핵심 개념
✅ 비동기 통신 (Asynchronous)
- AJAX는 요청을 보내고 응답을 기다리지 않고, 다른 작업을 계속 수행할 수 있도록 합니다.
- 동기 방식(Synchronous)에서는 요청을 보낸 후 응답이 올 때까지 기다려야 하지만, AJAX는 기다릴 필요 없이 응답이 오면 특정 이벤트를 통해 처리합니다.
✅ XML 대신 JSON 사용
- 초기에는 XML을 데이터 형식으로 많이 사용했지만, 현재는 더 가볍고 효율적인 JSON을 주로 사용합니다.
✅ 새로고침 없이 데이터 갱신
- 페이지 전체를 다시 로드하지 않고 필요한 부분만 업데이트할 수 있어 사용자 경험(UX)이 개선됩니다.


Session 인증의 단점
- 인증방식
→ 1. 사용자(클라이언트)가 서버에 로그인 요청
→ 2. 서버는 인증절차를 수행하고, 인증이 유효하면 세션 객체를 생성하고 서버에 저장
→ 3. 서버는 요청에 대한 응답으로 응답 헤더의 set -cookie를 통해 세션 ID를 클라이어트에게 전달
→ 4. 이후부터는 클라이언트가 서버에 요청할 때마다 전달받은 쿠기를 요청헤더아 추가하여 요청 (쿠키를 요청헤더에 추가해주는 것은 브라우저가 처리)
- Session 방식의 한계
- 세션 정보를 서버에서 관리해야 해서, 사용자가 많아지면 서버 메모리 사용량 증가
- 특히, 대규모 서비스에서는 세션 저장을 위한 추가적인 관리(ex. Redis, DB 저장)가 필요요
- 서버가 여러 대일 경우, 세션 정보 공유 필요
- 세션을 중앙 저장소에 저장하지 않으면, 사용자가 처음 접속한 서버에서만 인증이 유지되는 문제가 생길 수 있음
- 세션 하이재킹(Session Hijacking): 세션 ID가 탈취되면 공격자가 사용자로 위장할 수 있음
- 세션 고정 공격(Session Fixation): 공격자가 미리 정해놓은 세션 ID를 사용하도록 유도할 수 있음
- CSRF(Cross-Site Request Forgery) 공격에 취약할 수도 있다
- 세션이 만료되지 않으면, 사용자가 직접 로그아웃하지 않는 한 계속 유지될 수 있다
- 공유 컴퓨터에서는 보안 위험이 클 수 있다
- 일반적으로 세션 ID는 쿠키를 통해 관리되는데, 브라우저에서 쿠키를 차단하면 인증이 제대로 작동하지 않을 수 있다
- XSS(크로스 사이트 스크립팅) 공격을 통해 세션 쿠키가 탈취될 가능성도 있다
→ 1. 서버 부하 증가
→ 2. 확장성 문제
→ 3. 보안 문제
→ 4. 수동 로그아웃 필요
→ 5. 쿠키 의존성
전자서명 인증
- 전자서명 인증의 개념
→ 전자서명 인증은 공개 키 암호화(PKI, Public Key Infrastructure) 를 기반으로 사용자의 신원을 검증하는 인증 방식
→ 전자서명은 문서나 데이터의 무결성을 보장하고, 송신자의 신원을 확인할 수 있다.
- 전자서명의 작동 원리
- 전자서명 인증은 개인 키(Private Key)와 공개 키(Public Key) 를 활용하여 다음과 같은 방식으로 작동한다
- 사용자가 개인 키(Private Key)로 문서 또는 데이터를 암호화하여 서명을 생성함
- 서명된 문서와 함께 전자서명(Signature)을 상대방에게 보냄
- 수신자는 송신자의 공개 키(Public Key)를 사용하여 서명의 유효성을 검증
- 복호화된 데이터가 원본과 일치하면 무결성(Integrity) 및 신원(Authenticity)이 확인됨
→ 1. 서명생성 (Signing)
→ 2. 서명 전송
→ 3. 서명 검증 (Verification)

ex06/test05.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>fetch get, post, put, delete</h1>
<hr />
<button onclick="get1()">get</button>
<button onclick="post1()">post</button>
<button onclick="put1()">put</button>
<button onclick="delete1()">delete</button>
<form>
<input type="text" id="title" placeholder="title" /><br />
<input type="text" id="content" placeholder="content" /><br />
<input type="text" id="author" placeholder="author" /><br />
<button type="button" onclick="write1()">게시글쓰기</button>
</form>
<script>
async function write1() {
let requestBody = {
title: document.querySelector("#title").value,
content: document.querySelector("#content").value,
author: document.querySelector("#author").value,
};
let response = await fetch("http://localhost:8080/api/boards", {
method: "post",
body: JSON.stringify(requestBody),
headers: { "Content-Type": "application/json" },
});
let responseBody = await response.json();
console.log(responseBody);
}
async function get1() {
let response = await fetch("http://localhost:8080/api/boards/1", {
method: "get",
});
let responseBody = await response.json();
console.log(responseBody);
}
async function post1() {
let requestBody = {
title: "제목9",
content: "내용9",
author: "ssar",
};
let response = await fetch("http://localhost:8080/api/boards", {
method: "post",
body: JSON.stringify(requestBody),
headers: { "Content-Type": "application/json" },
});
let responseBody = await response.json();
console.log(responseBody);
}
async function put1() {
let requestBody = {
title: "제목11",
content: "내용11",
author: "ssar",
};
let response = await fetch("http://localhost:8080/api/boards/1", {
method: "put",
body: JSON.stringify(requestBody),
headers: { "Content-Type": "application/json" },
});
let responseBody = await response.json();
console.log(responseBody);
}
async function delete1() {
let response = await fetch("http://localhost:8080/api/boards/1", {
method: "delete",
});
let responseBody = await response.json();
console.log(responseBody);
}
</script>
</body>
</html>
Blog
localhost:8080/
index
{{> layout/header}}
<div class="container p-5">
<table class="table table-striped">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th></th>
</tr>
</thead>
<tbody id="board-box">
</tbody>
</table>
</div>
<script>
// 책임: 컴퍼넌트 생성
function makeBoard(board) {
let tr = document.createElement("tr");
tr.innerHTML = `<td>${board.id}</td>
<td>${board.title}</td>
<td>${board.content}</td>
<td>${board.author}</td>
<td>
<div class="d-flex">
<form action="#">
<button class="btn btn-danger" onclick="deleteBoard(${board.id})">삭제</button>
</form>
<form action="/board/${board.id}/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>`;
return tr;
}
// 책임: 통신
async function init() {
let response = await fetch("/api/boards");
let responseBody = await response.json();
let boardList = responseBody.body;
//console.log(boardList);
let tBody = document.querySelector("#board-box");
boardList.forEach((board) => {
tBody.append(makeBoard(board));
});
}
init();
</script>
{{> layout/footer}}
BoardApiContoller
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin
@RequiredArgsConstructor
@RestController
public class BoardApiController {
private final BoardRepository boardRepository;
@PutMapping("/api/boards/{id}")
public ApiUtil<?> update(@PathVariable("id") int id, @RequestBody BoardRequest.UpdateDTO requestDTO) {
boardRepository.updateById(requestDTO, id);
return new ApiUtil<>(null);
}
@PostMapping("/api/boards")
public ApiUtil<?> write(@RequestBody BoardRequest.WriteDTO requestDTO) {
boardRepository.insert(requestDTO);
return new ApiUtil<>(null);
}
@DeleteMapping("/api/boards/{id}")
public ApiUtil<?> deleteById(@PathVariable Integer id) {
Board board = boardRepository.selectOne(id);
boardRepository.deleteById(id);
return new ApiUtil<>(null);
}
@GetMapping("/api/boards/{id}")
public ApiUtil<?> findById(@PathVariable("id") int id) {
Board board = boardRepository.selectOne(id);
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return new ApiUtil<>(board); // MessageConverter
}
@GetMapping("/api/boards")
public ApiUtil<?> findAll() {
List<Board> boardList = boardRepository.selectAll();
return new ApiUtil<>(boardList); // MessageConverter
}
}
BoardController
package shop.mtcoding.blog.board;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@RequiredArgsConstructor
@Controller
public class BoardController {
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
@GetMapping("/board/{id}/updateForm")
public String updateForm(@PathVariable("id") int id, HttpServletRequest request, HttpServletResponse response) {
Cookie cookie = new Cookie("boardId", id + "");
cookie.setHttpOnly(true);
response.addCookie(cookie);
request.setAttribute("boardId", id);
return "board/updateForm";
}
}
BoardRepository
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 List<Board> selectAll(){
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
List<Board> boardList = query.getResultList(); // 못찾으면 빈 컬렉션을 준다 (크기=0)
return boardList;
}
public Board selectOne(int id){
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
try {
Board board = (Board) query.getSingleResult();
return board;
} catch (Exception e) {
return null;
}
}
@Transactional
public void insert(BoardRequest.WriteDTO requestDTO){
Query query = em.createNativeQuery("insert into board_tb(title, content, author) values(?, ?, ?)");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.executeUpdate();
}
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
@Transactional
public void updateById(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title=?, content=?, author=? where id=?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.setParameter(4, id);
query.executeUpdate();
}
}

localhost:8080/board/saveForm
saveForm
{{> layout/header}}
<div class="container p-5">
<div class="card">
<div class="card-header"><b>익명 글쓰기 화면입니다</b></div>
<div class="card-body">
<form action="#">
<div class="mb-3">
<input type="text" class="form-control" placeholder="Enter author" id="author">
</div>
<div class="mb-3">
<input type="text" class="form-control" placeholder="Enter title" id="title">
</div>
<div class="mb-3">
<textarea class="form-control" rows="5" id="content"></textarea>
</div>
<button type="button" class="btn btn-primary form-control" onclick="writeBoard()">글쓰기완료</button>
</form>
</div>
</div>
</div>
<script>
// 아래 함수 작성하기 전에,
// 1. button -> type button으로!!
// 2. input name을 id로 변경하기
async function writeBoard() {
// 1. id 값 찾아서 requestBody 오브젝트에 넣기
let requestBody = {
author: document.querySelector("#author").value,
title: document.querySelector("#title").value,
content: document.querySelector("#content").value
}
// 2. fetch post 요청하기
let response = await fetch("/api/boards", {
method: "post",
body: JSON.stringify(requestBody),
headers: {"Content-Type": "application/json"},
});
let responseBody = await response.json();
console.log(responseBody);
// 3. 마지막에 아래 코드로 페이지 이동하기 (console볼땐 주석처리)
location.href = "/";
}
</script>
{{> layout/footer}}
BoardApiController
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin
@RequiredArgsConstructor
@RestController
public class BoardApiController {
private final BoardRepository boardRepository;
@PutMapping("/api/boards/{id}")
public ApiUtil<?> update(@PathVariable("id") int id, @RequestBody BoardRequest.UpdateDTO requestDTO) {
boardRepository.updateById(requestDTO, id);
return new ApiUtil<>(null);
}
@PostMapping("/api/boards")
public ApiUtil<?> write(@RequestBody BoardRequest.WriteDTO requestDTO) {
boardRepository.insert(requestDTO);
return new ApiUtil<>(null);
}
@DeleteMapping("/api/boards/{id}")
public ApiUtil<?> deleteById(@PathVariable Integer id) {
Board board = boardRepository.selectOne(id);
boardRepository.deleteById(id);
return new ApiUtil<>(null);
}
@GetMapping("/api/boards/{id}")
public ApiUtil<?> findById(@PathVariable("id") int id) {
Board board = boardRepository.selectOne(id);
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return new ApiUtil<>(board); // MessageConverter
}
@GetMapping("/api/boards")
public ApiUtil<?> findAll() {
List<Board> boardList = boardRepository.selectAll();
return new ApiUtil<>(boardList); // MessageConverter
}
}
BoardController
package shop.mtcoding.blog.board;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@RequiredArgsConstructor
@Controller
public class BoardController {
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
@GetMapping("/board/{id}/updateForm")
public String updateForm(@PathVariable("id") int id, HttpServletRequest request, HttpServletResponse response) {
Cookie cookie = new Cookie("boardId", id + "");
cookie.setHttpOnly(true);
response.addCookie(cookie);
request.setAttribute("boardId", id);
return "board/updateForm";
}
}
BoardRepository
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 List<Board> selectAll(){
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
List<Board> boardList = query.getResultList(); // 못찾으면 빈 컬렉션을 준다 (크기=0)
return boardList;
}
public Board selectOne(int id){
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
try {
Board board = (Board) query.getSingleResult();
return board;
} catch (Exception e) {
return null;
}
}
@Transactional
public void insert(BoardRequest.WriteDTO requestDTO){
Query query = em.createNativeQuery("insert into board_tb(title, content, author) values(?, ?, ?)");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.executeUpdate();
}
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
@Transactional
public void updateById(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title=?, content=?, author=? where id=?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.setParameter(4, id);
query.executeUpdate();
}
}



localhost:8080/board/{id}/updateForm
updateForm
{{> layout/header}}
<div class="container p-5">
<div class="card">
<div class="card-header"><b>익명 글수정 화면입니다</b></div>
<div class="card-body">
<form action="#">
<input type="hidden" id="boardId" value="{{boardId}}">
<div class="mb-3">
<input type="text" class="form-control" placeholder="Enter author" id="author">
</div>
<div class="mb-3">
<input type="text" class="form-control" placeholder="Enter title" id="title">
</div>
<div class="mb-3">
<textarea class="form-control" rows="5" id="content"></textarea>
</div>
<button type="button" class="btn btn-primary form-control" onclick="updateBoard()">글수정완료</button>
</form>
</div>
</div>
</div>
<script>
async function updateBoard() {
// 1. id 값 찾아서 requestBody 오브젝트에 넣기
let requestBody = {
author: document.querySelector("#author").value,
title: document.querySelector("#title").value,
content: document.querySelector("#content").value
}
// 2. fetch put 요청하기
let response = await fetch(`/api/boards/${boardId}`, {
method: "put",
body: JSON.stringify(requestBody),
headers: {"Content-Type": "application/json"}
})
let responseBody = await response.json();
console.log(responseBody);
// 3. 마지막에 아래 코드로 페이지 이동하기 (console볼땐 주석처리)
location.href = "/";
}
let boardId = document.querySelector("#boardId").value;
//let boardId2 = getCookie("boardId");
// 책임: 통신
async function init() {
let response = await fetch("/api/boards/" + boardId);
let responseBody = await response.json();
document.querySelector("#author").value = responseBody.body.author;
document.querySelector("#title").value = responseBody.body.title;
document.querySelector("#content").value = responseBody.body.content;
}
init();
function getCookie(key) {
const cookies = document.cookie.split('; ');
for (let cookie of cookies) {
const [k, v] = cookie.split('=');
if (k === key) {
return v;
}
}
return null; // 해당 키가 없으면 null 반환
}
</script>
{{> layout/footer}}
BoardApiController
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin
@RequiredArgsConstructor
@RestController
public class BoardApiController {
private final BoardRepository boardRepository;
@PutMapping("/api/boards/{id}")
public ApiUtil<?> update(@PathVariable("id") int id, @RequestBody BoardRequest.UpdateDTO requestDTO) {
boardRepository.updateById(requestDTO, id);
return new ApiUtil<>(null);
}
@PostMapping("/api/boards")
public ApiUtil<?> write(@RequestBody BoardRequest.WriteDTO requestDTO) {
boardRepository.insert(requestDTO);
return new ApiUtil<>(null);
}
@DeleteMapping("/api/boards/{id}")
public ApiUtil<?> deleteById(@PathVariable Integer id) {
Board board = boardRepository.selectOne(id);
boardRepository.deleteById(id);
return new ApiUtil<>(null);
}
@GetMapping("/api/boards/{id}")
public ApiUtil<?> findById(@PathVariable("id") int id) {
Board board = boardRepository.selectOne(id);
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return new ApiUtil<>(board); // MessageConverter
}
@GetMapping("/api/boards")
public ApiUtil<?> findAll() {
List<Board> boardList = boardRepository.selectAll();
return new ApiUtil<>(boardList); // MessageConverter
}
}
BoardController
package shop.mtcoding.blog.board;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@RequiredArgsConstructor
@Controller
public class BoardController {
@GetMapping("/")
public String index() {
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
@GetMapping("/board/{id}/updateForm")
public String updateForm(@PathVariable("id") int id, HttpServletRequest request, HttpServletResponse response) {
Cookie cookie = new Cookie("boardId", id + "");
cookie.setHttpOnly(true);
response.addCookie(cookie);
request.setAttribute("boardId", id);
return "board/updateForm";
}
}
BoardRepository
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 List<Board> selectAll(){
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
List<Board> boardList = query.getResultList(); // 못찾으면 빈 컬렉션을 준다 (크기=0)
return boardList;
}
public Board selectOne(int id){
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
try {
Board board = (Board) query.getSingleResult();
return board;
} catch (Exception e) {
return null;
}
}
@Transactional
public void insert(BoardRequest.WriteDTO requestDTO){
Query query = em.createNativeQuery("insert into board_tb(title, content, author) values(?, ?, ?)");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.executeUpdate();
}
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
@Transactional
public void updateById(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title=?, content=?, author=? where id=?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.setParameter(4, id);
query.executeUpdate();
}
}


localhost:8080/api/boards/{id}/delete
index
{{> layout/header}}
<div class="container p-5">
<table class="table table-striped">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th></th>
</tr>
</thead>
<tbody id="board-box">
</tbody>
</table>
</div>
<script>
async function deleteBoard(boardId) {
let response = await fetch("/api/boards/" + boardId, {method: "delete"});
let responseBody = await response.json();
document.querySelector(`#item-${boardId}`).remove();
}
// 책임: 컴퍼넌트 생성
function makeBoard(board) {
let tr = document.createElement("tr");
tr.setAttribute("id", `item-${board.id}`);
tr.innerHTML = `
<td>${board.id}</td>
<td>${board.title}</td>
<td>${board.content}</td>
<td>${board.author}</td>
<td>
<div class="d-flex">
<form>
<button type="button" class="btn btn-danger" onclick="deleteBoard(${board.id})">삭제</button>
</form>
<form action="/board/${board.id}/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>`;
return tr;
}
// 책임: 통신
async function init() {
let response = await fetch("/api/boards");
let responseBody = await response.json();
let boardList = responseBody.body;
//console.log(boardList);
let tBody = document.querySelector("#board-box");
boardList.forEach((board) => {
tBody.append(makeBoard(board));
});
}
init();
</script>
{{> layout/footer}}
BoardApiController
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin
@RequiredArgsConstructor
@RestController
public class BoardApiController {
private final BoardRepository boardRepository;
@PutMapping("/api/boards/{id}")
public ApiUtil<?> update(@PathVariable("id") int id, @RequestBody BoardRequest.UpdateDTO requestDTO) {
boardRepository.updateById(requestDTO, id);
return new ApiUtil<>(null);
}
@PostMapping("/api/boards")
public ApiUtil<?> write(@RequestBody BoardRequest.WriteDTO requestDTO) {
boardRepository.insert(requestDTO);
return new ApiUtil<>(null);
}
@DeleteMapping("/api/boards/{id}")
public ApiUtil<?> deleteById(@PathVariable("id") Integer id) {
Board board = boardRepository.selectOne(id);
boardRepository.deleteById(id);
return new ApiUtil<>(null);
}
@GetMapping("/api/boards/{id}")
public ApiUtil<?> findById(@PathVariable("id") int id) {
Board board = boardRepository.selectOne(id);
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
return new ApiUtil<>(board); // MessageConverter
}
@GetMapping("/api/boards")
public ApiUtil<?> findAll() {
List<Board> boardList = boardRepository.selectAll();
return new ApiUtil<>(boardList); // MessageConverter
}
}
BoardRepository
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 List<Board> selectAll(){
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
List<Board> boardList = query.getResultList(); // 못찾으면 빈 컬렉션을 준다 (크기=0)
return boardList;
}
public Board selectOne(int id){
Query query = em.createNativeQuery("select * from board_tb where id = ?", Board.class);
query.setParameter(1, id);
try {
Board board = (Board) query.getSingleResult();
return board;
} catch (Exception e) {
return null;
}
}
@Transactional
public void insert(BoardRequest.WriteDTO requestDTO){
Query query = em.createNativeQuery("insert into board_tb(title, content, author) values(?, ?, ?)");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.executeUpdate();
}
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate();
}
@Transactional
public void updateById(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title=?, content=?, author=? where id=?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, requestDTO.getAuthor());
query.setParameter(4, id);
query.executeUpdate();
}
}


Share article