
1. BoardApiController에서 @DeleteMapping("api/boards/{id}") 만들기
- 아이디 중복체크는 무조건 ajax로 해야 함!
- 아니면 적은 글이 다 날아감
- 로직이 실행이 안됨
- res에 html을 담아준다는 것은 말이 안됨 → index를 리턴하면 망함
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 삭제하기
@DeleteMapping("api/boards/{id}") // 보드 중에 몇번을 삭제할게
public ApiUtil<?> deleteById(@PathVariable Integer id) {
boardRepository.deleteById(id);
return new ApiUtil<>(null); // 삭제는 데이터를 줄 것이 없음
}
// 주소 만들기
@GetMapping("api/boards") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public ApiUtil<List<Board>> findAll(HttpServletResponse response) {
//response.setStatus(401);
List<Board> boardList = boardRepository.selectAll(); // 상태코드랑 메세지랑 같이 줘야함
return new ApiUtil<>(boardList); // MessageConverter라는 클래스가 오브젝트를 응답할때 자동 발동함
}
}
2. BoardRepository에 deleteById() 만들기
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(String title, String content, String author) {
Query query = em.createNativeQuery("insert into board_tb(title, content, author) values(?, ?, ?)");
query.setParameter(1, title);
query.setParameter(2, content);
query.setParameter(3, author);
query.executeUpdate();
}
@Transactional
public void deleteById(Integer id) {
Query query = em.createNativeQuery("delete from board_tb where id = ?");
query.setParameter(1, id);
query.executeUpdate(); // insert, update, delete는 커밋이 발동
}
}

3. BoardApiController에 api/boards/{id}에 null일 때 셋팅하기
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 삭제하기
@DeleteMapping("api/boards/{id}") // 보드 중에 몇번을 삭제할게
public ApiUtil<?> deleteById(@PathVariable Integer id, HttpServletResponse response) {
Board board = boardRepository.selectOne(id);
if (board == null) {
response.setStatus(404);
return new ApiUtil<>(404, "해당 데이터를 찾을 수 없습니다");
}
boardRepository.deleteById(id);
return new ApiUtil<>(null); // 삭제는 데이터를 줄 것이 없음
}
// 주소 만들기
@GetMapping("api/boards") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public ApiUtil<List<Board>> findAll(HttpServletResponse response) {
//response.setStatus(401);
List<Board> boardList = boardRepository.selectAll(); // 상태코드랑 메세지랑 같이 줘야함
return new ApiUtil<>(boardList); // MessageConverter라는 클래스가 오브젝트를 응답할때 자동 발동함
}
}
4. index.mustache에 del함수 추가하기
{{> 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>
s
</thead>
<tbody id="board-box">
</tbody>
</table>
</div>
<script> // 나중에 js 파일을 따로 빼서 링크를 걸게 됨
function del(boardId) {
$.ajax({
url: `api/boards/${boardId}`,
type: "delete"
}).done((res) => {
$(`#board-${boardId}`).remove();
}).fail((res) => {
alert(res.responseJSON.msg);
});
}
// 페이지 로드될때 무조건 시작되야 도니까 밖에 있음
$.ajax({
url: "/api/boards", //서버가 같으면 8080뒤에 있는 주소는 뒤에 것만 적어도 됨
type: "get" // poset면 컨텐트타입, 데이터가 추가로 들어감
}).done((res) => { // 정상(200)이면 done->바디 데이터
console.log("통신 성공");
console.log(res);
// for(board of boardList){}도 가능하나 stream api를 쓰는 것이 좋음
let boardList = res.body;
boardList.forEach((board) => {
$("#board-box").append(render(board));
});
}).fail((res) => {
//console.log(res);
alert(res.responseJSON.msg);
// location.herf="/loginForm";
}); // 실패면 다 fail
function render(board) {
return `<tr id="board-${board.id}">
<td>${board.id}</td>
<td>${board.title}</td>
<td>${board.content}</td>
<td>${board.author}</td>
<td>
<div class="d-flex">
<button onclick="del(${board.id})" class="btn btn-danger">삭제</button>
<form action="/board/${board.id}/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>`;
}
</script>
{{> layout/footer}}

5. 삭제 실패시 강제로 F5하기
- F5 하면서 확인하는게 폴링 기법
{{> 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> // 나중에 js 파일을 따로 빼서 링크를 걸게 됨
function del(boardId) {
$.ajax({
url: `api/boards/${boardId}`,
type: "delete"
}).done((res) => {
$(`#board-${boardId}`).remove();
}).fail((res) => {
alert(res.responseJSON.msg);
location.reload(); // F5 강제로 해주기
});
}
// 페이지 로드될때 무조건 시작되야 도니까 밖에 있음
$.ajax({
url: "/api/boards", //서버가 같으면 8080뒤에 있는 주소는 뒤에 것만 적어도 됨
type: "get" // poset면 컨텐트타입, 데이터가 추가로 들어감
}).done((res) => { // 정상(200)이면 done->바디 데이터
console.log("통신 성공");
console.log(res);
// for(board of boardList){}도 가능하나 stream api를 쓰는 것이 좋음
let boardList = res.body;
boardList.forEach((board) => {
$("#board-box").append(render(board));
});
}).fail((res) => {
//console.log(res);
alert(res.responseJSON.msg);
// location.herf="/loginForm";
}); // 실패면 다 fail
function render(board) {
return `<tr id="board-${board.id}">
<td>${board.id}</td>
<td>${board.title}</td>
<td>${board.content}</td>
<td>${board.author}</td>
<td>
<div class="d-flex">
<button onclick="del(${board.id})" class="btn btn-danger">삭제</button>
<form action="/board/${board.id}/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>`;
}
</script>
{{> layout/footer}}




6. 푸시 서버(push server)
- 일반적으로 클라이언트 애플리케이션으로 메시지를 보내는 서버
- 푸시 알림, 채팅 메시지, 업데이트 알림 등 다양한 형태
- 주로 모바일 애플리케이션에서 사용
- 클라이언트 애플리케이션이 서버에 대한 요청 없이도 서버에서 메시지를 받을 수 있게 해줌
Share article