inblog logo
|
vosw1
    JQuery

    AJAX : 스프링 셋팅하기

    Feb 22, 2024
    AJAX : 스프링 셋팅하기

    1. 초기 셋팅하기

    • 연결 끊고 내 GitHub에 Repository 추가해서 연결하기
    notion image
     

    2. AJAX 문법

    jQuery.ajax()
    Data to be sent to the server. If the HTTP method is one that cannot have an entity body, such as GET, the data is appended to the URL.
    jQuery.ajax()
    https://api.jquery.com/jQuery.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&는 안됨
    URL 인코딩 및 디코딩 - 온라인
    URL 인코딩 형식으로 인코딩해보세요. 아니면 다양한 고급 옵션으로 디코딩해보세요. 저희 사이트에는 데이터 변환하기에 사용하기 쉬운 온라인 도구가 있습니다.
    URL 인코딩 및 디코딩 - 온라인
    https://www.urlencoder.org/ko/
    URL 인코딩 및 디코딩 - 온라인
    퍼센트-인코딩을 한 후의 예약어 문자
    !
    #
    $
    &
    '
    (
    )
    *
    +
    ,
    /
    :
    ;
    =
    ?
    @
    [
    ]
    %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}}
    notion image
     
    • 바뀔 데이터들은 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로 바인딩하면 됨
    notion image
     

    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만 주면 글자를 뿌릴 수 없음, 정확한 분기 처리를 위한 정확한 데이터가 필요함
    notion image
    실패해도 무조건 파싱해야함
    파싱하고 body만 돌려주면 됨
    컨트롤러 입장에서는 body에 상태코드가 없으면 400인지 알 수가 없음
    body에 상태코드, 메세지, 응답되는 데이터(null일 수 있음)가 담겨있음
    → 성공하면 데이터를 입히고 실패하면 데이터를 파싱해서 alert창 띄우기
    → 성공 여부를 알 수 있는 상태 코드, 응답 데이터, 메세지(실패했을 때 중요)가 필요함
    notion image
    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); } }
    notion image
    notion image
    Share article

    vosw1

    RSS·Powered by Inblog