Devlog
article thumbnail
Published 2022. 5. 3. 17:35
[Spring] Spring MVC Structure 강의/KOSTA

위 글은 해당 카테고리의 수업 강의 자료를 정리한 것입니다.

 

 

 

MVC 구조의 이해

MVC(Model-View-Controller)

  • 대부분의 서블릿 기반 프레임워크들이 사용하는 방식
  • 데이터와 처리, 화면을 분리하는 방식
  • 웹에서는 Model2 방식으로 표현

 

 

스프링과 스프링 MVC

  • 스프링 프레임워크 Core + 여러 Sub 프로젝트들
  • 별도로 결합해서 사용하기 때문에 설정 역시 별도로 처리 가능
 

Spring | Projects

Spring Framework Provides core support for dependency injection, transaction management, web apps, data access, messaging, and more.

spring.io

 

 

 

일반적인 스프링 + 스프링 MVC

XML이나 Java 설정 이용시에 설정 분리

 

 

 

웹 프로젝트의 구조

  • 스프링을 실행하는 존재
    • ApplicationContext ➡️ WebApplicationContext
    • 같이 연동되는 방식으로 동작하기 때문에 설정을 분리해도 통합해서 사용 가능

 

 

 

스프링 MVC의 기본 사상

  • 서블릿 기반이긴 하지만 한 단계 더 추상화된 수준의 개발 지향
  • 서블릿 API 없이도 개발이 가능한 수준

 

 

 

 

모델2 방식과 스프링 MVC

 

 

 

스프링 MVC의 기본 흐름

 

 

 

스프링 기반 웹서비스 시작과 처리 과정

  1. WAS가 구동되면서 web.xml이 로딩
  2. web.xml에 등록되어 있는 ContextLoaderListener(Java Class)가 생성됨, ContextLoaderListener 클래스는 ServletContextListener 인터페이스를 구현하고 있으며 ApplicationContext를 생성하는 역할을 수행함
  3. 생성된 ContextLoaderListener는 root-context.xml을 loading 함
  4. root-context.xml에 등록되어 있는 Spring Container가 구동됨, 이때 개발자가 작성한 비즈니스 로직에 대한 부분과 DAO, VO 객체들이 생성됨
  5. 클라이언트로부터 웹 애플리케이션의 요청이 옴
  6. DispatcherServlet(Servlet)이 생성됨
  7. DispatcherServlet은 servlet-context.xml을 loading 함, DispatcherServlet은 HandleMapping을 통해 Controller로 위임처리 함
  8. 두 번째 Spring Container가 구동되며 응답에 맞는 PageController들이 동작함, 이때 첫 번째 Spring Container가 구동되면서 생성된 DAO, VO, ServiceImpl 클래스들과 협업하여 알맞은 작업 처리
  9. 처리 후 controller는 view이름을 리턴하고 viewResoler를 통해 사용자에게 보여줌

 

 

 

DispatcherServlet이란

  • 과거의 servlet 방식의 웹 어플리케이션은 web.xml에 <url-pattern>을 설정하여 클라이언트의 모든 요청을 처리하였음
  • DispatcherServlet을 web.xml에 등록해도 계속 서블릿을 web.xml에 매핑해서 쓸 수 있음
  • 옛 방식을 버리고 DispatcherServlet을 이용해 웹 개발을 한다면 서블릿 파일을 만들 필요도 없어짐과 동시에 획기적이고 놀라운(??) MVC의 혜택을 얻을 수 있음
  • MVC 설계 원칙에 따른 웹 어플리케이션의 개발

 

  • Model, Controller, View를 조합하여 브라우저에게 응답하는 일 수행

 

 

 

정적인 요소는 DispatcherServlet과 분리

  • 모든 웹 리소스들은 DispatcherServlet이 가로채지 못하도록 해야함
  • <resources mapping="/resources/-*" location="/resources/" />
  • 이 전략은 디스패처 서블릿을 통해 들어온 요청을 처리하는데 만약 해당 요청에 대한 컨트롤러를 찾을 수 없다면 2차적으로 위의 설정된 경로를 검색하여 해당 자원을 찾아내게 되는 구조

기존의 resources 폴더의 Deployment Assembly를 변경하여 아래와 같이 설정하는 예

 

 

 

Controller

  • HttpServletRequest, HttpServletResponse를 거의 사용할 필요 없이 필요한 기능 구현
  • 다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용 가능
  • GET, POST 방식 등 전송 방식에 대한 처리를 어노테이션 (@)으로 처리 가능
  • 상속, 인터페이스 방식 대신에 어노테이션만으로도 필요한 설정 가능

 

 

@Controller, @RequestMapping

  • @Controller
    • 해당 클래스의 인스턴스를 스프링의 빈으로 등록하고 컨트롤러로 사용
    • <component-scan>과 같이 활용
  • @RequestMapping
    • 특정한 URL에 대한 처리를 해당 컨트롤러나 메소드에서 처리
package org.zerock.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
@RequestMapping("/sample/*")
public class SampleController {
 
}

 

@Controller에 의해 스프링의 객체로 등록되어짐

 

 

 

@RequestMapping의 변화

  • 스프링 4.3 전까지는 @RequestMapping(method='get') 방식으로 사용
  • 스프링 4.3 이후에는 @GetMapping, @PostMapping 등으로 간단히 표현 가능
  @RequestMapping(value = "/basic", method = {RequestMethod.GET, RequestMethod.POST})
  public void basicGet() {
 
    log.info("basic get...................");
 
  }
 
  @GetMapping("/basicOnlyGet")
  public void basicGet2() {
 
    log.info("basic get only get...................");
 
  }

 

 

 

컨트롤러의 파라미터 수집

  • 스프링 MVC의 컨트롤러는 메서드의 파라미터를 자동으로 수집, 변환하는 편리한 기능을 제공
  • Java Beans 규칙에 맞게 작성되어야 함
    • 생성자가 없거나 빈 생성자
    • 올바른 규칙으로 만들어진 Getter/Setter
@Data
public class SampleDTO {
 
  private String name;
  private int age;
}
@GetMapping("/ex01")
  public String ex01(SampleDTO dto) {
 
    log.info("" + dto);
 
    return "ex01";
  }

 

리스트 또는 배열로 파라미터 넘기기

@GetMapping("/ex02List")
  public String ex02List(@RequestParam("ids")ArrayList<String> ids) {
 
    
    log.info("ids: " + ids);
    
    return "ex02List";
}

 

 

 

@InitBinder

  • Spring Validator를 사용 시 @Valid 어노테이션으로 검증이 필요한 객체를 가져오기 전에 수행할 method를 지정해주는 어노테이션
public class TodoDTO {
 
  private String title;
  private Date dueDate; //날짜 타입의 변환 필요 
}
@InitBinder
  public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
  }
 
…생략…
 
  @GetMapping("/ex03")
  public String ex03(TodoDTO todo) {
    log.info("todo: " + todo);
    return "ex02";
  }

 

 

@DataTimeFormat

  • @InitBinder 외에도 날짜에 대한 처리가 쉽게 추가된 어노테이션
package org.zerock.domain;
 
import java.util.Date;
 
import org.springframework.format.annotation.DateTimeFormat;
 
import lombok.Data;
 
@Data
public class TodoDTO {
 
  private String title;
  
  @DateTimeFormat(pattern = "yyyy/MM/dd")
  private Date dueDate;
}

 

 

 

Model이라는 데이터 전달자

  • Model 객체는 JSP에 컨트롤러에서 생성된 데이터를 담아서 전달하는 역할을 하는 존재
  • 모델2 방식에서 사용하는 request.setAttribute()와 유사한 역할
public String home(Model model) {
        
    model.addAttribute("serverTime", new java.util.Date());
    
    return "home";
  }

 

 

 

@ModelAttribute

  • 컨트롤러에서 메소드의 파라미터는 기본 자료형을 제외한 객체형 타입은 다시 화면으로 전달
  • @ModelAttribute는 명시적으로 화면에 전달되도록 지정
 @GetMapping("/ex04")
  public String ex04(SampleDTO dto, @ModelAttribute(“page”) int page) {
 
    log.info("dto: " + dto);
    log.info("page: " + page);
 
    return "/sample/ex04";
}
<h2>SAMPLEDTO   ${sampleDTO }</h2>
<h2>PAGE ${page }</h2>

 

 

 

 

RedirectAttribute

  • 화면에 한번만 전달되는 파라미터를 처리하는 용도
  • 내부적으로 HttpSession 객체에 담아서 한번만 사용되고 폐기
 rttr.addFlashAttribute("name", "AAA");
    rttr.addFlashAttribute("age", 10);
    
    return "redirect:/";
response.sendRedirect("/home?name=aaa&age=10");

 

 

 

Controller의 리턴 타입

  • String
    • jsp를 이용하는 경우에는 jsp 파일의 경로와 파일 이름을 나타내기 위해서 사용
    • 상황에 따라 다른 화면을 보여줄 필요가 있을 경우에 유용
    • String 타입에는 다음과 같은 특별한 키워드를 붙여서 사용할 수 있음
      • redirect: 리다이렉트 방식으로 처리
      • forward: 포워드 방식으로 처리
  • void
    • 호출하는 URL과 동일한 이름의 jsp를 의미
 @GetMapping("/ex05")
  public void ex05() {
    log.info("/ex05..........");
  }

  • VO, DTO (객체)타입
    • 주로 JSON 타입의 데이터를 만들어서 반환하는 용도로 사용 (추가적인 라이브러리 필요)
    • XML이나 JSON으로 처리
    • @RepsoneBody 어노테이션과 같이 사용
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
</dependency>
@GetMapping("/ex06")
  public @ResponseBody SampleDTO ex06() {
    log.info("/ex06..........");
 
    SampleDTO dto = new SampleDTO();
    dto.setAge(10);
    dto.setName("홍길동");
 
    return dto;
  }

  • ResponsEntity 타입
    • response할 때 Http 헤더 정보와 내용을 가공하는 용도로 사용 (추가적인 라이브러리 필요)
    • HTTP 헤더 정보와 추가적인 데이터를 전달할 때 사용
@GetMapping("/ex07")
  public ResponseEntity<String> ex07() {
    log.info("/ex07..........");
 
    // {"name": "홍길동"}
    String msg = "{\"name\": \"홍길동\"}";
 
    HttpHeaders header = new HttpHeaders();
    header.add("Content-Type", "application/json;charset=UTF-8");
 
    return new ResponseEntity<>(msg, header, HttpStatus.OK);
  }

  • Model, ModelAndView: Model로 데이터를 변환하거나 화면까지 같이 지정하는 경우에 사용 (최근에는 많이 사용하지 않음)
  • HttpHeaders: 응답에 내용 없이 Http 헤더 메시지만 전달하는 용도로 사용

 

 

 

컨트롤러의 예외(Exception) 처리

  • @ExceptionHandler와 @ControllerAdvice를 이용한 처리
  • @ResponseEntity를 이용한 예외 메시지 구성

 

  • @ControllerAdvice
    • 예외처리와 원래의 컨트롤러가 혼합된 형태의 클래스가 작성되는 방식
    • @ExceptionHandler는 해당 메소드가 () 들어가는 예외 타입을 처리한다는 것을 의미
@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
 
  @ExceptionHandler(Exception.class)
  public String except(Exception ex, Model model) {
 
    log.error("Exception ......." + ex.getMessage());
    model.addAttribute("exception", ex);
    log.error(model);
    return "error_page";
  }
}

 

 

 

 

profile

Devlog

@덩이

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그