v8
★ MILESTONE · REST

REST 컨트롤러로 변환

v6 게시판을 다른 옷으로 입혀본다

학습 목표

  • v6 의 BoardController 를 @RestController 로 옮긴다
  • 두 컨트롤러의 차이를 라인별로 본다
  • JSON 응답이 어떻게 만들어지는지 안다
  • REST API 의 URL 디자인 컨벤션을 익힌다

⚠️ 지금까지의 한계

v6 게시판의 답답함
  • 매 클릭마다 페이지 전체가 깜빡임
  • 다른 시스템과 데이터 주고받을 길 없음 (서버끼리 또는 모바일 앱과)
  • JSP 가 화면 그리는 일에만 적합

REST API 로 만들면 이 모든 게 풀립니다. 같은 게시판을 「다른 옷」으로.

🛠️ @RestController

@Controller + @ResponseBody

모든 메서드 반환값을 자동으로 JSON 으로 변환해 응답 바디로 보내는 컨트롤러. View 박스가 흐름에서 빠짐.

기존 @Controller @RestController ────────────────── ────────────────── 브라우저 → Controller 브라우저 → Controller ↓ ↓ Service Service ↓ ↓ Mapper Mapper ↓ ↓ DB DB ↑ (객체 반환) ↑ (객체 반환) Controller : Model 담기 Controller : 반환 ↓ ↓ Jackson 자동 변환 return ViewName JSON 응답 ↓ ↓ ViewResolver → JSP 브라우저 받음 ↓ (JS 로 렌더링) HTML 응답

v6 BoardController — 조회


package com.smhrd.controller;

@Controller
@RequestMapping("/board")
public class BoardController {

    @Autowired
    private BoardService service;

    @GetMapping("/list")
    public String list(Model model) {
        model.addAttribute("boards", service.selectList());
        return "board/list";    // → JSP
    }

    @GetMapping("/view")
    public String view(@RequestParam int num, Model model) {
        model.addAttribute("board", service.selectOne(num));
        return "board/view";    // → JSP
    }
}

👉 결과를 Model 에 담고 ViewName 을 반환 — JSP 가 화면을 그림.

v6 BoardController — 등록


    @PostMapping("/write")
    public String write(Board b, HttpSession s) {
        Member u = (Member) s.getAttribute("loginUser");
        b.setWriter(u.getId());
        service.insert(b);
        return "redirect:/board/list";
    }
}

👉 폼 데이터를 객체로 바인딩, 저장 후 목록 페이지로 redirect.

v8 BoardApiController — 조회


package com.smhrd.controller;

@RestController                       // ⭐ 변경 1
@RequestMapping("/api/boards")        // ⭐ URL prefix 변경
public class BoardApiController {

    @Autowired
    private BoardService service;

    @GetMapping                       // GET /api/boards
    public List<Board> list() {
        return service.selectList();  // ⭐ 객체 반환 → 자동 JSON
    }

    @GetMapping("/{num}")             // GET /api/boards/3
    public Board view(@PathVariable int num) {
        return service.selectOne(num);
    }
}

👉 Model 도 ViewName 도 사라짐. 객체를 그대로 반환하면 JSON.

v8 BoardApiController — 등록


    @PostMapping                      // POST /api/boards
    public Board create(@RequestBody Board b,
                        HttpSession s) {
        Member u = (Member) s.getAttribute("loginUser");
        b.setWriter(u.getId());
        service.insert(b);
        return b;
    }
}

👉 폼 바인딩 대신 @RequestBody 로 JSON 을 받고, 저장 결과를 JSON 으로 응답.

변경점 — 5 가지

자리v6v8
클래스 어노테이션@Controller@RestController
URL prefix/board/api/boards
반환 타입String (ViewName)객체 또는 List
Model매개변수로 받음없음
파라미터폼 바인딩@RequestBody JSON

RESTful URL 디자인

동작v6 (전통)v8 (REST)
목록GET /board/listGET /api/boards
상세GET /board/view?num=3GET /api/boards/3
작성POST /board/writePOST /api/boards
수정POST /board/updatePUT /api/boards/3
삭제POST /board/deleteDELETE /api/boards/3

👉 REST 는 「리소스(boards)」를 URL 로, 「동작」을 HTTP 메서드로 표현.

JSON 자동 변환 — Jackson 의 마법

Service.selectList() 반환값: List<Board> [ Board { num=1, title="첫 글", ... }, Board { num=2, title="둘째 글", ... } ] ↓ (Jackson 이 자동으로) 응답 바디 (JSON): [ { "num": 1, "title": "첫 글", ... }, { "num": 2, "title": "둘째 글", ... } ] 필요한 설정: pom.xml 의 jackson-databind 의존성 (Spring MVC 기본 의존성에 이미 포함)

@RequestBody — 거꾸로


@PostMapping
public Board create(@RequestBody Board b, ...) {
    // b 는 클라이언트가 보낸 JSON 이 자동 변환된 객체
}
클라이언트 fetch: fetch('/api/boards', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ title: '새 글', content: '내용...' }) }); 요청 바디: { "title": "새 글", "content": "내용..." } ↓ Jackson 이 거꾸로 변환 Board b: Board { title="새 글", content="내용...", writer=null }

실행 — 브라우저로 직접 확인

  1. Tomcat 시작
  2. 브라우저: http://localhost:8080/.../api/boards
  3. 화면에 JSON 배열 출력
    [{"num":1,"title":"첫 글",...}, ...]
  4. F12 Network 탭에서 응답 헤더 확인 — Content-Type: application/json
  5. http://localhost:8080/.../api/boards/1 — 단일 객체

POST 요청은 어떻게 테스트하나

브라우저 주소창은 GET 만 가능. POST 는 다른 방법:

  • F12 Console 에서 fetch:
    fetch('/api/boards', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({title: '테스트', content: 'hello'})
    }).then(r => r.json()).then(console.log);
  • Postman — REST 테스트의 표준 도구
  • curl:
    curl -X POST -H "Content-Type: application/json" \
      -d '{"title":"테스트","content":"hello"}' \
      http://localhost:8080/.../api/boards

v6 와 v8 공존

둘 중 하나만 만들 수 있는 게 아닙니다. 같은 Service 를 공유하면서 두 가지 형태로:

  • BoardController (전통, JSP)
  • BoardApiController (REST, JSON)

실무에서도 흔합니다. 관리자 화면은 JSP, 사용자 모바일 앱과는 REST API.

🔄 v6 → v8 코드 차이 — v6 (JSP 형)


@Controller
@RequestMapping("/board")
public class BoardController {

    @GetMapping("/view")
    public String view(
        @RequestParam int num,
        Model model
    ) {
        model.addAttribute(
            "board",
            service.selectOne(num)
        );
        return "board/view";
    }
}

👉 데이터 → Model → ViewName → JSP 화면.

🔄 v6 → v8 코드 차이 — v8 (REST 형)


@RestController
@RequestMapping("/api/boards")
public class BoardApiController {

    @GetMapping("/{num}")
    public Board view(
        @PathVariable int num
    ) {
        return service.selectOne(num);
    }
}

👉 같은 일 — 다른 도구. Service 호출 부분은 똑같고, 반환 객체가 곧 JSON.

실무 응용 미리보기

  • 모바일 앱 — 우리 REST API 를 그대로 사용
  • 다른 서비스와 연동 — 카카오·네이버 로그인 등도 REST API
  • 마이크로서비스 — 작은 서비스들이 REST 로 대화
  • SPA(Single Page App) — React/Vue 가 REST 로 데이터만 받아 화면 그림

👉 v8 는 모든 현대 웹 개발의 출발점.

v8 의 의미

v8 부터 우리 사이트는 두 얼굴을 가집니다:

  • JSP 화면 (사람용)
  • REST API (다른 시스템용)

다음 차시 v9 에서는 JS 가 우리 REST API 를 호출해 새로고침 없는 화면을 만듭니다.

🔄 Before / After

Part 5 끝 (v6/v7)

JSP 기반 게시판이 동작. 매 동작마다 화면 깜빡.

v8 끝

같은 게시판이 REST API 로도 동작. 다른 시스템이 사용 가능. 화면 새로고침 제거의 토대.

이번 차시의 데이터 흐름

클라이언트
(JS / 앱 / curl)
@RestController
Service
DB
JSON 응답
View 박스가 사라지고 「JSON 응답」 박스가 자리 — Part 6 의 핵심 변화

정리

오늘 들고 가는 것

  • @RestController = @Controller + @ResponseBody
  • 객체 반환 → Jackson 이 자동 JSON 변환
  • @RequestBody = JSON → 자바 객체 자동 변환
  • RESTful URL: 리소스를 URL 로, 동작을 HTTP 메서드로
  • v8 — REST API 게시판의 시작

다음: v9 비동기 댓글 — 이 REST API 를 fetch 로 호출해 새로고침 없는 화면.