
1. 초기 셋팅하기
- 연결 끊고 내 GitHub에 Repository 추가해서 연결하기

2. AJAX 문법
- $.ajax( url {, settings } ) : setting안에 url을 집어넣을 수 있음
- $.ajax( {settings} )
- url : string
- setting: js object
$.ajax({
accepts: {
mycustomtype: 'application/x-some-custom-type'
},
// Instructions for how to deserialize a `mycustomtype`
converters: {
'text mycustomtype': function(result) {
// Do Stuff
return newresult;
}
},
// Expect a `mycustomtype` back from server
dataType: 'mycustomtype'
});
- async : 디폴트가 true 건드릴 일 없음
- accepts : 건드릴 일이 없음, 적지도 않을 것임, 대부분 json임
- contentType : default: application/x-www-form-urlencoded; charset=UTF-8
- context :
- data : javascript object 형태, x-www-form-urlencoded
a=bc&d=e%2Cf
a=bc: "a"라는 이름의 값이 "bc"
d=e%2Cf`: "d"라는 이름의 값이 "e,f"로 URL 인코딩된 값
쉼표(,)는 URL에서 특수 문자이므로 %2C로 인코딩
a%5B%5D=1&a%5B%5D=2
"a"라는 이름의 값이 배열로 표현, 값은 각각 1과 2
%5B%5D는 "[]"를 URL 인코딩한 것
"a[]"라는 이름의 배열로 해석
- RFC : HTTP프로토콜들이 ?된 문서
- url을 safe하게 작성해야 함
주소에 board?, board=, board&는 안됨
퍼센트-인코딩을 한 후의 예약어 문자
! | # | $ | & | ' | ( | ) | * | + | , | / | : | ; | = | ? | @ | [ | ] |
%21 | %23 | %24 | %26 | %27 | %28 | %29 | %2A | %2B | %2C | %2F | %3A | %3B | %3D | %3F | %40 | %5B | %5D |
3. 더미 데이터를 가져와서 뿌릴 것
- 가방에 담는 것이 아니라 디자인만 줄 것
- 순수하게 INDEX 페이지로 이동
4. index.mustache에서 게시글 하나 빼고 다 삭제하기
{{> 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>
<tr>
<td>5</td>
<td>제목5</td>
<td>내용5</td>
<td>홍길동</td>
<td>
<div class="d-flex">
<form action="#">
<button class="btn btn-danger">삭제</button>
</form>
<form action="/board/1/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>
</tbody>
</table>
</div>
{{> layout/footer}}

- 바뀔 데이터들은 json으로 다운 받아 사용할 것
- render함수 만들기
{{> 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>
</tbody>
</table>
</div>
<script>
function render(){
return `<tr>
<td>5</td>
<td>제목5</td>
<td>내용5</td>
<td>홍길동</td>
<td>
<div class="d-flex">
<form action="#">
<button class="btn btn-danger">삭제</button>
</form>
<form action="/board/1/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>`;
}
</script>
{{> layout/footer}}
- 처음에 이 틀만 주고 브라우저가 ajax 통신해서 다운받아 쓰게 됨
- 템플릿 엔진이 없어도 됨
- 순수한 html문서에 js로 바인딩하면 됨

5. ajax로 삭제하기 위해 id 추가하기
{{> 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>
</tbody>
</table>
</div>
<script>
function render(){
return `<tr id="board-5">
<td>5</td>
<td>제목5</td>
<td>내용5</td>
<td>홍길동</td>
<td>
<div class="d-flex">
<form action="#">
<button class="btn btn-danger">삭제</button>
</form>
<form action="/board/1/updateForm" method="get">
<button class="btn btn-warning">수정</button>
</form>
</div>
</td>
</tr>`;
}
</script>
{{> layout/footer}}
5. 통신 코드 넣기
- 이 페이지가 로드되고 나서 바로 다운받아야 함
- 버튼 안눌러도 데이터가 나와야 함
- function안에 넣을 필요없음
- 넣어서 호출해도됨
- 다운 받으려면 json을 받을 수 있는 api가 서버에 없어서 만들어야 함
- 다 리턴되는게 템플릿 엔진, 파일들 = 컨트롤러
- 데이터를 리턴하는 것을 api컨트롤러라고 함 → 만들기
6. BoardApiController만들기
- board : 보드 줘라는 주소
- boards : 복수는 보드들 줘
- boards/1 : 보드들 중에 1번 줘 해서 보통 복수형을 씀
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 주소 만들기
@GetMapping("api/board") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public void findAll(){
}
}
7. BoardApiController에서 api/boards 주소 만들기
- 데이터만 주는 것, 얘만 응답하면 안됨
- 항상 상태 코드랑 메세지를 같이 줘야 함
바로 boardList를 주면 받는 쪽에서 if해서 분기 처리할 때 복잡해짐
그래서 상태 코드만 보면 됨
- 성공했을 때의 상태 코드, 메세지는 중요하지 않음
실패했을 때의 상태 코드와 메세지가 중요함
- 결과가 null이라고 무조건 오류라고 할 수 없음
- sucess : 상태 코드 → body말고 header에도 들어옴
그래도 body에 담아줘야 하는 이유 : 헤더에만 주면 메세지를 못 봄
→ body에 담아서 줘야 무슨 에러인지 알 수 있음
ex) 휴대폰 애도 동일하게 레이어가 있음
휴대폰도 레파지토리가 있음
레파지토리는 api서버에 연결됨
휴대폰 자체 내장된 데이터테이스가 있을 수 있음
내부에 sql write가 있음(메모장, 달력 등)
응답을 받을 때 http 프로토콜 요청이니까 header와 body를 받음
레파지토리의 책임 : 데이터를 잘 받아서 자기 오브젝트로 파싱하는 것
→ header에 상태코드 400이 들어오면? 실패 → body를 파싱할 필요가 없음
→ 통신 요청하고 나서 400확인하고 폰에 에러났다고 돌려줄 때 400만 주면 메세지를 못 봄
그래서 body에 담아서 줘야 무슨 에러인지 알 수 있음
→ 그냥 400만 주면 글자를 뿌릴 수 없음, 정확한 분기 처리를 위한 정확한 데이터가 필요함

실패해도 무조건 파싱해야함
파싱하고 body만 돌려주면 됨
컨트롤러 입장에서는 body에 상태코드가 없으면 400인지 알 수가 없음
body에 상태코드, 메세지, 응답되는 데이터(null일 수 있음)가 담겨있음
→ 성공하면 데이터를 입히고 실패하면 데이터를 파싱해서 alert창 띄우기
→ 성공 여부를 알 수 있는 상태 코드, 응답 데이터, 메세지(실패했을 때 중요)가 필요함

package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 주소 만들기
@GetMapping("api/boards") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public void findAll(){
List<Board> boardList = boardRepository.selectAll(); // 상태코드랑 메세지랑 같이 줘야함
}
}
8. 응답의 공통 DTO - ApiUtil만들기
- 상태 코드 : 200, 400, 404, 405
- 메세지 : 성공, 실패시 -> 정확한 메세지
- 데이터 타입을 알 수 없으니 제네릭 사용
- new를 못하면 제네릭을 못 씀 이때 오브젝트를 사용
- new 할 수 있으면 제네릭을 사용
package shop.mtcoding.blog.board;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class ApiUtil<T> {
private Integer status; // 상태 코드 : 200, 400, 404, 405
private String msg; // 메세지 : 성공, 실패시 -> 정확한 메세지
private T body; // 데이터 타입을 알 수 없으니 제네릭 사용
}
- 생성자 만들기
package shop.mtcoding.blog.board;
import lombok.Data;
@Data
public class ApiUtil<T> {
private Integer status; // 상태 코드 : 200, 400, 404, 405
private String msg; // 메세지 : 성공, 실패시 -> 정확한 메세지
private T body; // 데이터 타입을 알 수 없으니 제네릭 사용
public ApiUtil(T body) {
this.status = 200;
this.msg = "성공";
this.body = body;
}
public ApiUtil(Integer status, String msg) {
this.status = status;
this.msg = msg;
this.body = body;
}
}
9. json으로 상태코드, 메세지, 바디 전송하기
- 오브젝트 걸고 리턴하면 스프링이 자동으로 json으로 변환해줌
@RestController @responseBody가 붙었을때
- 굳이 내가 오브젝트 맵퍼로 해서 변환해줄 필요가 없음
- 내가 response를 제어하면 스프링이 강제로 바꿔버림
- 무조건 apiUtil로 리턴하면 됨
- 오브젝트일때 MessageConverter라는 클래스가 오브젝트를 응답할 때 자동 발동함
- MessageConverter(추상 클래스) : 뭐가 올지 모르니까 추상화 되어 있음
- 첫번째 방법
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 주소 만들기
@GetMapping("api/boards") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public ApiUtil<?> findAll() {
// ApiUtil<List<Board>>도 가능
List<Board> boardList = boardRepository.selectAll(); // 상태코드랑 메세지랑 같이 줘야함
return new ApiUtil<>(200, "성공", boardList);
}
}
- 두번째 방법
package shop.mtcoding.blog.board;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RequiredArgsConstructor
@RestController // 데이러틀 리턴
public class BoardApiController {
private final BoardRepository boardRepository; // DI
// 주소 만들기
@GetMapping("api/boards") // 보드 줘라는 주소, 복수는 보드들 줘, 보드들 중에 1번 줘해서 복수형을 씀
public ApiUtil<List<Board>> findAll() {
List<Board> boardList = boardRepository.selectAll(); // 상태코드랑 메세지랑 같이 줘야함
return new ApiUtil<>(boardList);
}
}


Share article