자바 스프링 부트 7일차 b01Rest REST API 서버 구축부터 Axios를 활용한 프론트엔드 통신 준비

2026. 4. 14. 20:21대우개발원 수업 내용/spring boot, framework

반응형

Spring Boot를 이용한 REST API 서버 구축부터 Axios를 활용한 프론트엔드 통신 준비

1. REST 컨트롤러 기능 확장 (CRUD)

댓글 처리를 위한 ReplyController에 기본적인 조회, 삭제, 수정 기능을 구현

  • 조회 (@GetMapping): 특정 댓글 번호(rno)로 상세 정보를 가져옴
  • 삭제 (@DeleteMapping): 특정 댓글을 삭제하며, 삭제된 번호를 반환
  • 수정 (@PutMapping): JSON 데이터를 받아 기존 댓글 내용을 변경.
    이때 @RequestBody를 통해 클라이언트가 보낸 데이터를 객체로 변환.

2. 예외 처리 최적화 (@RestControllerAdvice)

애플리케이션에서 발생할 수 있는 오류를 사용자 친화적인 JSON 응답으로 변환하는 작업을 수행

  • DataIntegrityViolationException: DB 제약조건(외래키 등) 위반 시 "constraint fails" 메시지 반환.
  • NoSuchElementException: 존재하지 않는 댓글 번호를 조회하거나 삭제하려고 할 때 발생하며,
    이를 캐치하여 400(Bad Request) 에러와 함께 안내 메시지를 전달
  • 서비스 계층 보완: orElseThrow()를 사용하여 데이터가 없을 경우 명시적으로 예외를 발생시키도록 로직을 강화

3. 비동기 통신 라이브러리: Axios 도입

서버와 데이터를 주고받기 위해 Axios 라이브러리를 선택

  • 비동기 처리(Asynchronous): 서버에 데이터를 요청한 후 응답을 기다리는 동안 페이지가 멈추지 않고 다른 작업을 할 수 있게
  • 환경 설정: read.html에 Axios CDN과 직접 만든 reply.js를 연결하여 자바스크립트 실행 환경을 구축

4. 프론트엔드와 API 연결 (JavaScript)

실제 화면에서 서버의 데이터를 호출하는 기초 로직을 작성

  • async/await 활용: 비동기 통신을 마치 동기 코드처럼 가독성 있게 작성할 수 있도록 get1 함수를 구현
  • 데이터 흐름: 게시글 번호(bno)를 자바스크립트 변수로 받아 axios.get을 통해 해당 게시물의 댓글 목록 API를 호출하고
    콘솔에 출력하는 단계까지 확인

{
  "bno": 204,
  "replyText": "댓글테스트",
  "replyer": "정상연",
}

 


ReplyController에 아래 코드 추가

더보기
더보기
Long rno = replyService.register(replyDTO);
resultMap.put("rno",rno);

CustomRestAdvice에 아래 코드 추가

더보기
더보기
@ExceptionHandler(DataIntegrityViolationException.class) //DB 제약조건 오류 (FK , UNIQUE , NOT NULL 등) 발생시 실행
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public ResponseEntity<Map<String , String>> handleFkException(Exception e) {
    log.error(e);
    Map<String , String> errorMap = new HashMap<>();
    errorMap.put("time" , "" + System.currentTimeMillis());
    errorMap.put("msg" , "constraint fails");
    return ResponseEntity.badRequest().body(errorMap);
}

ReplyController에 아래 코드 추가

@Operation(description = "GET 방식으로 특정 댓글 조회")
@GetMapping("/{rno}")
public ReplyDTO getReplyDTO (@PathVariable("rno") Long rno){ //ULR 경로에 있는 값을 변수로 바인딩
    ReplyDTO replyDTO = replyService.read(rno);
    return replyDTO;
     }

실행하면

rno 부분이 추가된것을 확인

rno가 4번까지 있으니 3번을 조회

rno 3번의 정보가 뜸

 

10번을 조회하면 없는 정보이기 때문에 에러가뜸


그래서 

CustomRestAdvice코드에 아래 항목을 추가

더보기
더보기
@ExceptionHandler(NoSuchElementException.class) // 요청한 데이터가 존재하지 않을 때 발생하는 예외
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public ResponseEntity<Map<String, String>> handleNoSuchElement(Exception e) {
    log.error(e);
    Map<String, String> errorMap = new HashMap<>();
    errorMap.put("time", ""+System.currentTimeMillis());
    errorMap.put("msg", "No Such Element Exception");
    return ResponseEntity.badRequest().body(errorMap);
}

이제는 없는 항목을 조회해도 이상한 에러가 아닌 에러 안내 메세지를 보내주는 역할을 한다고 보면 된다


이제 댓글 삭제를 할 수 있는 delete기능을 만들어 볼거다

ReplyController에 아래 코드 추가

더보기
더보기
@Operation(description =  "DELETE 방식으로 특정 댓글 삭제")
@DeleteMapping("/{rno}")
public Map<String,Long> remove( @PathVariable("rno") Long rno ){
    replyService.remove(rno);
    Map<String, Long> resultMap = new HashMap<>();
    resultMap.put("rno", rno);
    return resultMap;
}

 

실행하면 delete가 정상적으로 보인다

근데 없는 번호(rno)를 remove 했는데 오류가 뜨지 않았다.

로그를 보면

조회 sql문이 뜬다.

최신 버전에서는 조회 했는데 없는 rno면 그냥 무시를 해버린다

이걸 오류로 처리 하고 싶으면 ReplyServiceImpl코드에 아래 코드를 추가

Reply reply = replyRepository.findById(rno).orElseThrow();

rno가 존재하는 rno인지 체크를 해주는 코드

advice 클래스에

@ExceptionHandler(NoSuchElementException.class) // 요청한 데이터가 존재하지 않을 때 발생하는 예외
@ResponseStatus(HttpStatus.EXPECTATION_FAILED)
public ResponseEntity<Map<String, String>> handleNoSuchElement(Exception e) {
    log.error(e);
    Map<String, String> errorMap = new HashMap<>();
    errorMap.put("time", ""+System.currentTimeMillis());
    errorMap.put("msg", "No Such Element Exception");
    return ResponseEntity.badRequest().body(errorMap);
}

이렇게 처리를 해뒀기 때문에 이제 실행하면

500 에러가 아닌 400에러가 정상적으로 뜬다.

(로그에도 확인)


특정 댓글을 수정하기 위해

ReplyController에 코드 추가

더보기
더보기
    @Operation(description = "PUT 방식으로 댓글 처리")
    @PutMapping(value = "/{rno}", consumes = MediaType.APPLICATION_JSON_VALUE)
    public Map<String,Long> remove( @PathVariable("rno") Long rno,
                                    @RequestBody ReplyDTO replyDTO ){
        replyDTO.setRno(rno); //번호를 일치시킴
        replyService.modify(replyDTO);
        Map<String, Long> resultMap = new HashMap<>();
        resultMap.put("rno", rno);
        return resultMap;
    }

DTO에 rno를 대입

서비스의 modify 매서드를 가동

rno를 담아서 return을 함


위의 코드들이 잘 실행 되는지실행

댓글 내용을 수정해봄

 

로그와 DB를 확인하면

정상적으로 수정된 것을 확인


댓글의 JavaScript처리

• Ajax를 이용해서 GET/POST/PUT/DELETE방식등을 호출
• Axios라이브러리를 이용
• JavaScript를 이용한 동적 처리

 

Axios는 자바스크립트로 서버에 데이터를 요청하고 받아올 때 쓰는, 편리하고 기능 많은 "데이터 배달부(HTTP 클라이언트)" 라이브러리(비동기화 처리 방식)

 

동기, 비동기화 처리

  • 동기 처리 방식 - 한개 끝나면 다른 한개를 순차적으로 수행하는 것
  • 비동기화 처리 방식 - 비동기 처리 방식은 1번이 수행되는 중에 2번이 절대 실행될 수 없는 동기 처리 방식과는 다르게,
    1번의 작업 완료 여부와 상관없이 2번 작업을 즉시 시작하여 시스템의 자원을 효율적으로 사용하고
    사용자 경험(멈춤 현상 방지)을 높이는 방식 (Callback이나 .then())를 수행

reply.js 파일 생성


read.html을 수정

(댓글 표시할때 read페이지에 표시하기 때문에 read페이지에 Axios를 적용)

</div><!-- end row-->

코드 아래에 작성

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"> </script>
<script src="/js/reply.js"></script>

그리고 위에 댓글(reply)을 추가 할 수 있는 버튼을 추가

더보기
더보기
<div class="row mt-3">
    <div class="col-md-12">
        <div class="my-4">
            <button class="btn btn-info addReplyBtn">ADD REPLY</button>
        </div>
        <ul class="list-group replyList">
        </ul>
    </div>
</div>
<div class="row mt-3">
    <div class="col">
        <ul class="pagination replyPaging">
        </ul>
    </div>
</div>

실행해서 read 페이지로 들어가면

ADD REPLY 버튼이 생긴것을 확인


reply.js에 아래 코드 추가

async function get1(bno) { // 함수 내부에서 await 사용 가능. 항상 Promise 반환
    const result = await axios.get(`/replies/list/${bno}`)
    // 서버 응답이 올 때까지 기다림. 비동기 호출
    console.log(result)
}

read.html

아래 

<script layout:fragment="script" th:inline="javascript">



</script>

부분을

<script layout:fragment="script" th:inline="javascript">
    const bno = [[${dto.bno}]]
    get1(bno)

</script>

이렇게 채움