1 Spring MVC
- Spring Framework이 직접 제공하는 Servlet API 기반의 웹 프레임워크
- Spring MVC 는 다음 패턴의 구현체
- MVC pattern
- Front controller pattern
1.1 MVC Pattern( Model-View-Controller)
- 애플리케이션의 개발 영역을 Model, View, Controller 세 가지 역할로 구분
- 역할을 나눔으로서 코드의 복잡도를 줄일 수 있는 장점
- model: Bean
- view: JSP
- service: Servlet
1.1.1 Controller
- 사용자의 요청을 받아 어떻게 처리 할지 결정하고 요청을 분석
- 주로 비즈니스 로직을 처리하고 결과를 모델에 추가
1.1.2 Model
- 컨트롤러가 뷰에 전달할 데이터를 보관
- 데이터와 비즈니스 로직을 결합하여 뷰에 필요한 정보 제공
1.1.3 View
- 모델 데이터를 기반으로 클라이언트에게 HTML, JSON 등의 형식으로 응답을 생성
1.2 JavaBeans/JSP/Servlet (JSP Model2)
1.3 Front Controller Pattern
A controller that handles all requests for a Web site. - Martin Fowler
- 모든 요청을 Front controller 에서 받아서 요청에 따라 실제 처리할 컨트롤러에 위임
- 인증, 인가 등 공통적으로 처리해야 할 부분을 Front controller에서 처리하기 용이
1.4 DispatcherServlet
FrontController 를 DispatcherServlet 으로 부름
- Spring MVC Framework의 중심이 되는 Servlet
- Controller로 향하는 모든 웹 요청의 entry point
- Front Controller 디자인 패턴의 표현
1.5 Spring boot web MVC
- Spring boot framework 에서는 embedded WAS를 제공
- WAS 서버를 별도로 설치하지 않고 내장된 WAS를 이용해서 애플리케이션을 단독으로 실행가능
- Tomcat, Jetty, UnderTow 등이 있음
- spring-boot-starter-web 의존성을 추가하는것 만으로 자동 설정된 애플리케이션을 실행 가능
1.5.1 WebMvcAutoConfiguration
- 자동으로 스프링 웹 애플리케이션의 주요 컴포넌트 설정
- EnableWebMvcConfiguration과 WebMvcAutoConfigurationAdapter 클래스를 포함
1.5.2 EnableWebMvcConfiguration
- EnableWebMvcConfiguration 클래스는 RequestMappingHandlerMapping과 RequestMappingHandlerAdapter 컴포넌트를 생성하고 설정
1.5.3 WebMvcAutoConfigurationAdapter
- WebMvcConfigurer 인터페이스를 구현
1.5.4 WebMvcConfigurer
*개발자가 Spring MVC의 기본 설정을 커스터마이징할 수 있도록 해줌
* Spring MVC에 필요한 기본 설정을 추상 메서드를 통해서 커스터 마이징
* add~~ : 새로운 빈이나 오브젝트를 추가하는것
* configure~~ : 설정작업을 하는것
🌱 [실습] IntelliJ 에서 Spring Boot MVC 프로젝트 생성
hello world 를 출력하는 application 만들어보기
@Controller
public class HomeControlloer {
@GetMapping("/")
public String home() {
return "home";
}
}
@Controller: 스프링에게 해당 클래스가 웹 요청을 처리하는 컨트롤러임을 안내
@GetMapping(”/”) 메서드를 통해 home.html 템플릿을 찾아 렌더링
<!DOCTYPE html>
<html lang = "ko">
<head>
<meta charset="UTF-8">
<title>Hello First Web Spring</title>
</head>
<body>
<div>
<h1>Hello First Web Spring</h1>
</div>
</body>
</html>
클라이언트가 웹 브라우저에서 루트 URL("/")에 접근하면,
스프링 컨트롤러가 “home” 뷰 이름을 반환하고,
템플릿 엔진이 이 HTML 템플릿을 찾아서 렌더링한 후 사용자에게 보여준다.
view 는 thymeleaf 이므로 남는 것은 Controller
2 Controller
- MVC 패턴에서 Controller 역할
- 요청 처리 및 흐름 제어 담당
- Front Controller 패턴에서 Command interface 구현 클래스에 해당
- 실제 웹 요청을 처리하는 역할
@Controller // <-- Controller 임을 지정
public class HomeController {
@GetMapping("/") // <-- HTTP Method 지정, URL 맵핑
public String index() {
return "index"; // <-- view 이름 지정
}
}
@Controller: component scan 과정을 통해 자동으로 bean 등록
2.1 Request Mapping
요청을 Controller 메서드에 맵핑
2.1.1 @RequestMapping을 통한 URL 맵핑
@RequestMapping("/persons")
@RequestMapping(value = "/persons")
@RequestMapping 어노테이션에서 “value” 속성이 기본(default) 속성이기 때문에,
@RequestMapping("/persons")는 내부적으로 @RequestMapping(value = "/persons")와 같은 의미로 처리된다.
2.1.2 @RequestMapping을 통한 HTTP Method 맵핑
@RequestMapping(value = "/persons", method=RequestMethod.GET)
@RequestMapping(value = "/persons", method=RequestMethod.POST)
@RequestMapping(value = "/persons", method=RequestMethod.PUT)
@RequestMapping(value = "/persons", method=RequestMethod.DELETE)
@RequestMapping(value = "/persons", method=RequestMethod.PATCH)
@RequestMapping(value = "/persons", method=RequestMethod.HEAD)
@RequestMapping(value = "/persons", method=RequestMethod.OPTIONS)
@RequestMapping(value = "/persons", method=RequestMethod.TRACE)
이 코드들은 같은 URI(”/persons”)에 대해 HTTP 메서드별로 각각 별도의 요청 핸들러를 정의한다.
각 어노테이션은 해당 메서드(GET, POST, PUT 등)의 요청에만 응답하도록 만든다.
- GET: 리소스 조회
- POST: 새 리소스 생성 또는 특정 작업 실행
- PUT: 리소스 전체 업데이트
- DELETE: 리소스 삭제
- PATCH: 리소스 부분 업데이트
- HEAD: 헤더 정보만 반환
- OPTIONS: 지원하는 HTTP 메서드 목록 반환
- TRACE: 경로 추적(디버깅 용도)
2.1.3 HTTP Method 맵핑은 줄여서
@GetMapping == @RequestMapping(method=RequestMethod.GET)
@PostMapping == @RequestMapping(method=RequestMethod.POST)
@PutMapping == @RequestMapping(method=RequestMethod.PUT)
@DeleteMapping == @RequestMapping(method=RequestMethod.DELETE)
@PatchMapping == @RequestMapping(method=RequestMethod.PATCH)
2.2 Request Mapping (w/params)
2.1.1 request parameter와 연결하는 방법
- id parameter가 있는 경우에만
@RequestMapping(method = RequestMethod.GET, params = { "id" })
- id parameter가 없는 경우에만
@GetMapping(params = { "!id" })
- type parameter 값이 raw인 경우에만
@GetMapping(params = "type=raw")
- type parameter 값이 raw가 아닌 경우에만
@GetMapping(params = "type!=raw")
🌱 [실습] Controller Method 이용
@GetMapping("/")
public String index() { // return type: String, method argument: 없음
return "index";
}
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) { // return type: Person
// ... // method argument: @PathVariable
return person;
}
@PostMapping
public String doLogin(Member loginInfo, HttpSession session) { // return: `redirect:'
// ... // method argument: HttpSession
return "redirect:/login";
}
2.3 Controller Method에서 사용 가능한 method argument
- HttpServletRequest, HttpServletResponse, HttpSession, WebRequest
- Locale
- InputStream, OutputStream, Reader, Writer
- @PathVariable, @RequestParam, @RequetHeader, @CookieValue, @Value
- Map, Model, ModelMap, @ModelAttribute, @RequestBody
- Errors, BindingResult, ...
- 참조: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/arguments.html
2.4 Controller Method에서 사용 가능한 return type
- ModelAndView, View
- Map, Model, ModelMap
- String
- void
- @ResponseBody
- POJO
- 참조: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-methods/return-types.html
3 Model 이용하기
3.1 Model로 이용할 수 있는 type
- java.util.Map interface
- org.springframework.ui.Model interface
- org.springframework.ui.ModelMap class
3.1.1 실제 처리되는 내용
- Model에 설정한 속성(attribute)이 View에 request.attribute 로 전달됨
🌱 [실습] Map, Model, ModelMap 에 값을 넣어서 view에서 가져다가 출력
git checkout model
git checkout requestmapping
@Controller
@RequestMapping("/user") // user 가 prefix 처럼 동작
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/user") // 요청을 Controller 메서드에 맵핑
public String getUsers(Model model) { /* TODO 1: 적절한 모델 type 넣기 */
List<User> users = userRepository.getUsers();
//TODO 2: user 목록을 모델의 attribute 추가
model.addAttribute("users", users);
return "users";
}
}
@Controller
@RequestMapping("/messenger") // user 가 prefix 처럼 동작
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/user") // 요청을 Controller 메서드에 맵핑
public String getUsers(Map<String, Object> model) { /* TODO 1: 적절한 모델 type 넣기 */
List<User> users = userRepository.getUsers();
//TODO 2: user 목록을 모델의 attribute 추가
model.put("users", users);
return "users";
}
}

4.1 ModelAndView = Model + View
@GetMapping("/some-request")
public ModelAndView doSomething() {
ModelAndView mav = new ModelAndView("viewName");
mav.addObject("name", "value");
// ...
return mav;
}
🌱 [실습] Map, Model, ModelMap 에 값을 넣어서 view 에서 ModelAndView 로 변경
@Controller
@RequestMapping("/messenger") // user 가 prefix 처럼 동작
public class UserController {
private final UserRepository userRepository;
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
@GetMapping("/user") // 요청을 Controller 메서드에 맵핑
public ModelAndView getUsers() {
List<User> users = userRepository.getUsers();
ModelAndView modelAndView = new ModelAndView("users");
modelAndView.addObject("users", users);
return modelAndView;
}
}
4.2 요청 parameter 받아오기 (@RequestParam)
4.2.1 @RequestParam
- 요청 URL의 Query String을 처리하기 위한 어노테이션
요청 URL
GET http://localhost:8080/persons?order=-createdAt
Controller Method
@GetMapping("/persons")
public List<Person> getPersons(@RequestParam(name="order") String order) {
// ...
}
4.3 요청 URL의 가변 인자 가져오기 (@PathVariable)
4.3.1 @PathVariable
- 요청 URL의 Resource(Path)을 처리하기 위한 어노테이션
- @RequestMapping 의 path 에 변수명을 입력받기 위한 place holder 가 필요함
요청 URL
GET http://localhost:8080/persons/99499102
Controller Method
@GetMapping("/persons/{personId}")
public List<Person> getPersons(@PathVariable(name="personId", required=true) Long personId) {
// ...
}
requried=true 이면 personId를 넘겨주지 않으면 에러남
🌱 [실습] request parameter 및 가변인자를 받아서 적절한 동작을 하는 API들 완성
git checkout requestmapping
// Spring MVC 컨트롤러임을 선언
@Controller
public class UserController {
// UserRepository를 주입받아 사용자 데이터에 접근
private final UserRepository userRepository;
// 생성자 주입을 통해 UserRepository 의존성을 주입
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
// GET 요청 "/users"를 처리하여 모든 사용자 목록을 반환
@GetMapping("/users")
public String getUsers(Model model) {
// 저장소에서 사용자 목록을 조회
List<User> users = userRepository.getUsers();
// 조회한 사용자 목록을 모델에 추가하여 뷰로 전달
model.addAttribute("users", users);
// "users.html" 뷰를 반환
return "users";
}
// GET 요청 "/users/{userId}"를 처리하여 특정 사용자 정보를 반환
@GetMapping("/users/{userId}")
public String getUser(Model model,
@PathVariable("userId") String id) {
// PathVariable로 전달된 id를 이용해 사용자 정보를 조회
User user = userRepository.getUser(id);
// 조회한 사용자 정보를 모델에 추가
model.addAttribute("user", user);
// "user.html" 뷰를 반환
return "user";
}
// GET 요청 "/users"를 처리하되, 요청 파라미터 id가 있을 경우 특정 사용자 정보를 반환
@GetMapping(value = "/users", params = "{id}")
public String getUserByName(Model model,
@RequestParam("id") String id) {
// 요청 파라미터 id로 사용자 정보를 조회
User user = userRepository.getUser(id);
// 조회한 사용자 정보를 모델에 추가
model.addAttribute("user", user);
// "user.html" 뷰를 반환
return "user";
}
}
5 Cookie 값 읽어오기 (@CookieValue)
5.1 @CookieValue
- HTTP 쿠키를 처리하기 위한 어노테이션
@GetMapping("/some-request")
public List<Person> getPersons(@CookieValue(name = "SESSION") String sessionId) {
// ...
}
🌱 [실습] 로그인 만들기
git checkout login1
@Controller
public class LoginController {
private final UserRepository userRepository;
public LoginController(UserRepository userRepository) {
this.userRepository = userRepository;
}
// `SESSION` 이라는 쿠키가 있으면 로그인 완료 메세지 출력 (`loginSuccess.html`).
// `SESSION` 이라는 쿠키가 없으면 로그인 폼 화면 출력 (`loginForm.html`).
@GetMapping("/login")
public String login(@CookieValue(name = "SESSION", required = false) String session) {
if (session != null && !session.isEmpty()) { // SESSION 쿠키가 존재하면 로그인 완료 뷰 반환, 없으면 로그인 폼 반환
return "loginSuccess"; // loginSuccess.html 뷰
}
return "loginForm"; // loginForm.html 뷰
}
// `userRepository.matches(id, password)` 메서드 이용.
// 로그인 성공 시 `SESSION` 쿠키에 session id 값 저장하고
// 모델을 이용해서 `loginSuccess.html`에 세션 아이디 전달.
// 로그인 실패 시 `/login`으로 redirect.
@PostMapping("/login")
public String doLogin(@RequestParam String id, @RequestParam String password,
HttpServletResponse response, Model model) {
if (userRepository.matches(id, password)) {
String sessionId = UUID.randomUUID().toString(); // 로그인 성공 시 session id 생성
Cookie cookie = new Cookie("SESSION", sessionId); // SESSION 쿠키 생성 및 설정
cookie.setPath("/"); // 쿠키의 유효 경로를 지정
cookie.setHttpOnly(true); // 쿠키를 HttpOnly 속성으로 설정
response.addCookie(cookie); // 생성한 쿠키를 HTTP 응답에 추가하여, 클라이언트(브라우저)로 전송
model.addAttribute("sessionId", sessionId);
return "loginSuccess";
}
return "loginForm";
}
}
'Java > Java Spring' 카테고리의 다른 글
[인프런] 스프링 핵심 원리 #1 (1) | 2024.07.23 |
---|---|
[Spring] 인프런 스프링 입문 강의 정리 #2 (5) | 2024.07.11 |
[Spring] 인프런 스프링 입문 강의 정리 #1 (0) | 2024.07.07 |
댓글