
책을 기반을 내용을 정리하고 추가했습니다. Thymeleaf 내용은 스킵하고 기본적인 개념만 정리했습니다.
MVC는 사용자 인터페이스를 가진 애플리케이션을 개발할 때 적용하는 일반적인 설계 개념으로 MVC패턴으로 불림.
역할
- Model : 업무 로직(Service), 데이터 보유(Entity), 데이터 접근(Repository)
- View : 화면을 표현하기 위한 HTML 생성
- Controll : Request -> Response에 대한 전체 흐름도
단계 동작 흐름 설명 1 브라우저 → Controller 사용자가 브라우저를 통해 요청을 보냄 2 Controller → Model Controller가 요청을 처리하고 Model 호출 3 Model ↔ 데이터베이스 Model이 데이터베이스와 통신하여 데이터 처리 4 Model → Controller 처리된 데이터를 Controller에 반환 5 Controller → View Controller가 데이터를 View에 전달 6 View → 브라우저 View가 데이터를 렌더링하여 사용자에게 응답
스프링 MVC는 MVC 패턴의 사고방식에 따라 효율적으로 web application을 만들 수 있게 하는 것이 스프링의 기능.
Controller는 Bean으로 관리되므로 Service 등의 의존 객체를 인젝션하여 사용할 수 있음.
@Controller는 스테레오 어노테이션 중 하나로, 컴포넌트로 스캔되어 Bean으로 관리.
또한 스프링MVC에 Controller 클래스로 인식되어 스프링 MVC가 제공하는 어노테이션을 사용할 수 있게 됨.
//예시 코드
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
@GetMapping("/hello")
public String sayHello(Model model) {
// Model에 데이터를 추가
model.addAttribute("message", "안녕하세요, MVC 패턴!");
// "hello"라는 이름의 뷰를 반환
return "hello";
}
}
설명
@Controller: 이 클래스가 컨트롤러 역할을 한다고 선언합니다.@GetMapping("/hello"): /hello 경로로 GET 요청이 오면 sayHello 메서드를 실행합니다.- Model: 뷰(View)에 데이터를 전달하기 위해 사용됩니다.
- return "hello": 뷰의 이름으로 hello.html (혹은 hello.jsp)를 반환합니다.
Spring MVC의 내부 동작을 보여주는 이 그림은 요청이 클라이언트(브라우저)에서 시작되어 DispatcherServlet을 거쳐 최종적으로 View로 응답되는 과정
단계 구성 요소 설명 1 브라우저 클라이언트가 HTTP 요청을 보냅니다. 예를 들어, 특정 URL 요청을 전송합니다. 2 DispatcherServlet 모든 요청을 받아 적절한 처리 흐름을 결정합니다. 3 Handler Mapping 요청 URL과 관련된 컨트롤러를 찾아 DispatcherServlet에 전달합니다. 4 Handler Adapter 컨트롤러를 호출하기 위해 필요한 추가 작업(데이터 바인딩 등)을 수행합니다. 5 Controller 요청을 처리하고 비즈니스 로직을 실행하거나 Service와 상호작용합니다. 6 Model 컨트롤러에서 데이터를 저장하여 View에 전달합니다. 7 View Resolver 컨트롤러가 반환한 뷰 이름을 기반으로 실제 뷰 템플릿을 찾습니다. 8 View 데이터를 렌더링하여 HTML 등의 형식으로 클라이언트에 반환합니다. 9 클라이언트(브라우저) 최종적으로 클라이언트가 렌더링된 HTML 응답을 받습니다.
Contrller 객체는 Service 객체의 메서드를 호출해야 하기 때문에 Service 객체가 필요함.
- 생성자 주입을 통한 서비스 객체 주입
생성자 주입은 의존성을 주입하는 가장 권장되는 방식으로, 불변성을 보장하고 테스트 용이성을 높여줍니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SampleController {
private final SampleService sampleService;
public SampleController(SampleService sampleService) {
this.sampleService = sampleService;
}
@GetMapping("/sample")
public String getSample(Model model) {
String data = sampleService.getData();
model.addAttribute("data", data);
return "sampleView";
}
}
@RequestMapping은 Spring MVC에서 HTTP 요청과 컨트롤러의 메서드를 매핑하는 데 사용됩니다. 이를 통해 특정 URL 경로와 메서드를 연결하여 요청을 처리할 수 있습니다.
핸들러 메서드 동작 과정
1. 클라이언트 요청 → DispatcherServlet이 요청을 받음.
2. @RequestMapping URL과 매핑된 핸들러 메서드를 호출.
3. 메서드가 데이터를 준비하여 반환 (뷰 이름 또는 JSON 응답).
4. DispatcherServlet이 반환 데이터를 뷰로 렌더링하거나 직접 응답으로 반환.
핵심 개념
- @RequestMapping:
- 클래스나 메서드 수준에서 사용 가능.
- URL 경로, HTTP 메서드(GET, POST 등), 요청 매체 유형 등을 설정.
- 기본적으로 모든 HTTP 메서드(GET, POST 등)를 처리하지만, 명시적으로 제한 가능.
- 핸들러 메서드:
- 요청을 처리하고 응답을 반환하는 메서드.
- 요청 URL에 따라 실행되며, 비즈니스 로직을 처리하거나 서비스를 호출.
- 뷰 이름을 반환하거나 JSON, XML 같은 데이터를 직접 반환 가능.
@RequestMapping 사용
@Controller
@RequestMapping("/example") // 클래스 레벨 매핑
public class ExampleController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello(Model model) {
model.addAttribute("message", "안녕하세요, Spring MVC!");
return "helloView"; // 뷰 이름 반환 (예: helloView.html)
}
}
축약 어노테이션 사용 (@GetMapping, @PostMapping 등)
장점: 코드가 간결해지고, HTTP 메서드가 더 명확하게 드러납니다.
Spring 4.3 이상에서는@RequestMapping의 축약형 어노테이션을 사용할 수 있습니다:
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/get")
public String handleGet() {
return "GET 요청 처리";
}
@PostMapping("/post")
public String handlePost() {
return "POST 요청 처리";
}
}
핸들러 메서드 요청 방식
매핑 방식 어노테이션 설명 예시 Path Variable @PathVariableURL 경로에서 변수로 값을 전달받음 /users/{id}→@PathVariable("id") Long idQuery Parameter @RequestParamURL 쿼리 문자열에서 값을 추출 /search?query=book→@RequestParam("query") String queryRequest Body @RequestBodyHTTP 요청 본문에서 JSON, XML 데이터를 객체로 매핑 { "name": "John", "age": 25 }→@RequestBody User userHTTP Header @RequestHeaderHTTP 요청 헤더에서 값을 추출 Authorization: Bearer <token>→@RequestHeader("Authorization") String tokenCookie @CookieValueHTTP 요청 쿠키에서 값을 추출 Cookie: sessionId=abc123→@CookieValue("sessionId") String sessionIdMatrix Variable @MatrixVariableURL 경로에서 세미콜론(;)으로 구분된 데이터를 추출 /users;name=John;age=30→@MatrixVariable("name") String nameFile Upload @RequestParamHTTP 요청 본문에서 파일 데이터를 처리 <input type="file" name="file">→@RequestParam("file") MultipartFile file
- 입력 검사 기술로는 자바 표준 기술인 Bean Validation을 이용하는 것이 편리.
- Spring MVC는 Bean Validation과 원활하게 연동 가능
Bean Validation 주요 어노테이션
어노테이션 설명 사용 예시 @NotNull 값이 null이 아니어야 함@NotNull private String name;@NotEmpty 문자열, 컬렉션 등이 null이거나 비어 있지 않아야 함@NotEmpty private String name;@NotBlank 문자열이 null, 공백(스페이스) 또는 빈 문자열이 아니어야 함@NotBlank private String name;@Size 문자열, 컬렉션, 배열 등의 크기가 지정된 범위 내에 있어야 함 @Size(min=2, max=30) private String name;@Min 숫자가 지정된 최소값 이상이어야 함 @Min(18) private int age;@Max 숫자가 지정된 최대값 이하여야 함 @Max(65) private int age;유효한 이메일 형식이어야 함 @Email private String email;@Pattern 특정 정규 표현식에 맞는 문자열이어야 함 @Pattern(regexp="^[a-zA-Z0-9]*$") private String username;@AssertTrue 값이 true여야 함@AssertTrue private boolean isActive;@AssertFalse 값이 false여야 함@AssertFalse private boolean isInactive;@Null 값이 null이어야 함@Null private String deprecatedField;
입력 오류 시 화면에 표시되는 문구는 기본으로 제공되지만 임의의 문구로 지정 가능. 오류 문구는 프로파티 파일로 지정해야함.
message.propertiesresource 아래에 설정하면 됨.
# Bean Validation 메시지
NotNull.user.name = 이름은 반드시 입력해야 합니다.
Size.user.name = 이름은 {min}자 이상 {max}자 이하로 입력해야 합니다.
Email.user.email = 유효한 이메일 주소를 입력하세요.
NotBlank.user.password = 비밀번호는 공백일 수 없습니다.
Size.user.password = 비밀번호는 {min}자 이상 {max}자 이하로 입력해야 합니다.
Positive.user.age = 나이는 양수로 입력해야 합니다.
Past.user.birthDate = 생년월일은 과거 날짜여야 합니다.
FutureOrPresent.user.eventDate = 이벤트 날짜는 오늘 이후여야 합니다.
# Global 메시지
typeMismatch.java.lang.Integer = 숫자 형식으로 입력하세요.
typeMismatch.java.util.Date = 올바른 날짜 형식으로 입력하세요.
이미지 출처
스프링 내부구조 이미지 출처 - 그림으로 배우는 스프링6