01c Lambda·Stream 📚 전체 맵 02b Session·Service·Repository
Series 02 · Spring 기초 · 1/3

CONTROLLER
MAPPING
DTO

@Controller vs @RestController · URL 매핑 · 요청 데이터 처리 · DTO 설계
Spring MVC 구조의 핵심 — 1차·2차·3차 모두 여기서 시작

02a Controller·Mapping·DTO 02b Session·Service·Repository 02c Entity·JPA·연관관계
01 Java 기초 02 Spring 기초 03 웹/통신 04 프로젝트 코드 05 심화 06 Security 07 JVM 08 DI
이 파일의 학습 목적
02a — @Controller vs @RestController · URL 매핑 · DTO

1차 프로젝트는 @Controller에 Thymeleaf, 2·3차는 @RestController에 JSON을 반환한다. 이 차이를 모르면 프로젝트가 왜 1차에서 2차로 바뀌었는지 이해가 안 된다. 02a는 Spring MVC 핵심 — 요청이 들어오면 어떻게 처리되는지, DTO가 왜 필요한지를 정리한다.

이 파일에서 배울 5가지
  • @Controller vs @RestController — 뷰 vs JSON 반환
  • URL 매핑 — @GetMapping·@PostMapping·@RequestMapping
  • @ModelAttribute vs @RequestBody — 1차 vs 2·3차 차이
  • DTO — Entity를 그대로 반환하지 않는 이유
  • Model · RedirectAttributes — 1차 Thymeleaf에서만 사용
프로젝트 단계별 변화
  • · 1차 — @Controller + @ModelAttribute + Model
  • · 2·3차 — @RestController + @RequestBody + ResponseEntity
  • · DTO — 1차는 Entity 직접 / 2·3차는 BoardDto 변환
시리즈 순서: 01a·01b·01c Java 기초 → 02a ← 지금 여기 → 02b Session·Service → 02c Entity·JPA
01 — @Controller vs @RestController
1차는 HTML 반환 / 2차·3차는 JSON 반환 — 우리 프로젝트의 가장 큰 전환점
🔀 핵심 차이 MVC
🍱 비유 — 배달 방식
@Controller = 완성된 도시락 배달 → 서버가 HTML까지 완성해서 브라우저에 전달
@RestController = 밀키트 배달 → 서버는 재료(JSON)만 전달, React가 화면을 만듦
1차 — @Controller (HTML 반환)
@Controller
public class BoardController {
@GetMapping("/board/list")
public String list(Model model) {
model.addAttribute("boards",
boardService.getList());
return "board/list";
// templates/board/list.html
}
}
2차·3차 — @RestController (JSON 반환)
@RestController
public class BoardController {
@GetMapping("/api/board/list")
public ResponseEntity<?> list() {
return ResponseEntity.ok(
boardService.getList());
// JSON 반환
// [{id:1,title:"..."},...]
}
}
💡 @RestController = @Controller + @ResponseBody
@ResponseBody = "반환값을 JSON으로 변환해서 HTTP 응답에 바로 담아라"
2차부터 Thymeleaf 완전 제거, @RestController만 사용
구분@Controller@RestController
반환값뷰 이름 (String)데이터 (JSON)
화면 생성Thymeleaf (서버)React (브라우저)
URL 패턴/board/list/api/board/list
사용 시점1차 프로젝트2차·3차 프로젝트
02 — URL 매핑 어노테이션
어떤 URL 요청을 어떤 메서드가 처리할지 연결 — HTTP 메서드별 의미
🗺️ @RequestMapping + HTTP 메서드 매핑 Routing
Java — 프로젝트 BoardController URL 구조
@RestController
@RequestMapping("/api/board") // 공통 URL 접두사
public class BoardController {

@GetMapping("/list") // GET /api/board/list → 목록 조회
public ResponseEntity<?> list() { ... }

@PostMapping("/write") // POST /api/board/write → 새 글 등록
public ResponseEntity<?> write() { ... }

@PutMapping("/edit/{id}") // PUT /api/board/edit/1 → 글 수정
public ResponseEntity<?> edit(@PathVariable Long id) { ... }

@DeleteMapping("/delete/{id}") // DELETE /api/board/delete/1 → 글 삭제
public ResponseEntity<?> delete(@PathVariable Long id) { ... }
}
어노테이션HTTP 메서드의미프로젝트 예시
@GetMappingGET조회 — 데이터 가져오기/api/board/list
@PostMappingPOST생성 — 새 데이터 만들기/api/board/write
@PutMappingPUT수정 — 전체 교체/api/board/edit/{id}
@DeleteMappingDELETE삭제/api/board/delete/{id}
@RequestMapping모두클래스 레벨 공통 URL/api/board (접두사)
03 — @ModelAttribute vs @RequestBody
요청 데이터를 Java 객체로 받는 방법 — 1차(form)와 2차·3차(JSON)의 차이
📥 요청 데이터 처리 방식 Request
📮 비유 — 우체국 vs 택배
@ModelAttribute = 우체국 창구 (form 제출) — username=hong&password=1234 형식
@RequestBody = 택배 상자 (JSON) — {"username":"hong","password":"1234"} 형식
1차 — @ModelAttribute (form 데이터)
// 브라우저가 보내는 형식:
// username=hong&password=1234

@PostMapping("/user/register")
public String register(
@ModelAttribute UserDto userDto) {
// form 데이터 → UserDto 자동 매핑
userService.register(userDto);
return "redirect:/login";
}
2차·3차 — @RequestBody (JSON)
// React axios가 보내는 형식:
// {"username":"hong","password":"1234"}

@PostMapping("/api/user/register")
public ResponseEntity<?> register(
@RequestBody UserDto userDto) {
// JSON → UserDto 자동 변환
userService.register(userDto);
return ResponseEntity.ok("success");
}
구분@ModelAttribute@RequestBody
데이터 형식form 데이터 (key=value)JSON ({key:value})
사용 상황1차 HTML form 제출2차·3차 React axios 요청
Content-Typeapplication/x-www-form-urlencodedapplication/json
반환값뷰 이름 (String)ResponseEntity
04 — DTO가 왜 필요한가
Entity를 직접 쓰면 안 되는 이유 — 보안 + 필요한 데이터만 전달
📋 DTO (Data Transfer Object) Design
🏥 비유 — 진료 기록 vs 처방전
Entity = 전체 진료 기록 — 개인정보·병력·주민번호 다 있음
DTO = 처방전 — 필요한 정보만 골라서 약국에 전달 (주민번호 X)
→ Entity를 직접 API 응답에 쓰면 비밀번호가 노출될 수 있음
❌ Entity 직접 반환 (위험)
// User Entity에는 password 있음
@GetMapping("/api/boards")
public List<Board> list() {
return boardRepository.findAll();
// Board 안에 User가 있고
// User 안에 password가 있어서
// 비밀번호가 JSON에 노출됨!
}
✅ DTO 변환 후 반환 (안전)
@GetMapping("/api/boards")
public List<BoardDto> list() {
return boardService.getList();
// BoardDto에는
// id·title·nickname·날짜만
// password 없음 ✅
}
Java — 프로젝트 Entity vs DTO 실제 구조
// User Entity: DB와 매핑, 모든 필드 포함
@Entity
public class User {
private Long id;
private String username;
private String password; // ← 민감 정보!
private String nickname;
private String role;
}

// BoardDto: 게시글 목록에 필요한 정보만
@Getter @Setter
public class BoardDto {
private Long id;
private String title;
private String nickname; // 작성자 닉네임만
private int viewCount;
private String createdAt;
// password 없음! userId도 없음!
}

// Service에서 Entity → DTO 변환
private BoardDto toDto(Board board) {
BoardDto dto = new BoardDto();
dto.setTitle(board.getTitle());
dto.setNickname(board.getUser().getNickname());
// password는 안 담음
return dto;
}
💡 DTO의 3가지 역할
1. 보안 — 민감 정보(password) 제외하고 전달
2. 데이터 최적화 — 필요한 필드만 담아서 전송 크기 줄임
3. Entity 보호 — 외부 요청이 Entity를 직접 건드리지 못하게 차단
05 — Model · RedirectAttributes
1차 Thymeleaf에서 데이터를 HTML로 전달하는 방법
📤 1차 전용 — Controller → HTML 데이터 전달 1차만 사용
Java — Model / RedirectAttributes 실제 사용
// Model: Controller → HTML 템플릿으로 데이터 전달
@GetMapping("/board/list")
public String list(Model model) {
model.addAttribute("boardList", boardService.getList());
// HTML에서 ${boardList}로 접근 가능
return "board/list";
}

// RedirectAttributes: redirect 시 메시지 전달 (한 번만 사용되는 임시 데이터)
@PostMapping("/user/register")
public String register(RedirectAttributes ra) {
try {
return "redirect:/user/login"; // 성공
} catch (Exception e) {
ra.addFlashAttribute("error", e.getMessage());
return "redirect:/user/register"; // 실패 → 에러 메시지 전달
// 회원가입 페이지에서 ${error}로 접근
}
}
⚠️ 2차·3차에서는 안 씀
Model·RedirectAttributes는 Thymeleaf(서버 렌더링) 전용.
2차부터 React로 전환 → ResponseEntity로 JSON 반환이 그 역할을 대체함.
01c Lambda·Stream 📚 전체 맵 02b Session·Service·Repository