Spring-MVC

JooH·2024년 2월 20일

NHN_BackendAcademy

목록 보기
16/23

HttpMessageConverter : 자바 객체와 Http요청 / 응답 Body를 변환하는 역할

interface

public interface HttpMessageConverter<T> {
  boolean canRead(Class<?> clazz, @Nullable MediaType mediaType);

  boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType);

  List<MediaType> getSupportedMediaTypes();

  T read(Class<? extends T> clazz, HttpInputMessage inputMessage) /*..*/;

  void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) /*..*/;
}

@EnableWebMvc - WebMvcConfigurationSupport가 default HttpMessageConverter를 제공한다

public class WebMvcConfigurationSupport /*..*/ {
    // ...

  protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(new StringHttpMessageConverter());
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new ResourceRegionHttpMessageConverter());

    // ...
  }
}

@ResponseBody

  • handler method의 return value를 HttpMessageConverter를 통해 직렬화해서 response body로 전달 // handler method : controller 에 있는 method
  • @RestController = @Controller + @ResponseBody
  • 일반 @Controller 클래스에도 method 레벨에서 @ResponseBody 가능

ResponseEntity

  • @ResponseBody + http status + response headers
@GetMapping("/something")
public ResponseEntity<String> handle() {
    String body = ... ;
    String etag = ... ;
    return ResponseEntity.ok()          // http status (200 OK)
                         .eTag(etag)    // response header (ETAG)
                         .build(body);  // response body
}

@RequestBody : request body를 읽어와서 HttpMessageConverter를 통해 deSerialize 해서 객체로 전달받기 위한 용도

@PostMapping("/api/members")
@ResponseStatus(HttpStatus.CREATED)
public void createMember(@RequestBody Member member) {
    // ...
}

Spring MVC Components
overview

Components

Handler?

  • Controller
  • HttpRequestHanler

쉽게 생각해서 Handler는 Controller다 라고 생각하면 된다

HandlerMapping
서버로 들어온 요청을 어떤 핸들러로 전달할지 결정하는 역할

HandlerAdapter
DispatcherServlet과 실제 핸들러 구현을 이어주는 Object Adapter 역할을 해준다

ViewController / RedirectViewController
@addViewController를 @Override 하면 된다

@Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addRedirectViewController("/this-is-home", "/");
    }

HandlerMapping / HandlerAdapter

ViewResolver : 문자열 기반의 View 이름을 토대로 실제 view 구현을 결정하는 역할

관련 Components
LocaleResolver / LocaleContextResolver : view rendering 시 국제화 지원(locale,timezone) 결정

  • AcceptHeaderLocaleResolver
  • CookieLocaleResolver
  • SessionLocaleResolver

ThemeResolver : view rendering 시 어떤 테마를 사용할 지 결정하는 역할

  • CookieThemeResolver
  • FixedThemeResolver
  • SessionThemeResolver

RequestToViewNameTranslator : 핸들러가 아무것도 리턴하지 않았을 때 view 이름을 결정하는 역할

HandlerExceptionResolver : 요청처리 과정에서 발생하는 예외 제어할때 사용

  • DefaultHandlerExceptionResolver

MultipartResolver : 멀티파트 요청 처리 구현하는 역할
FlashMapManager : redirect 와 같이 하나의 요청에서 다른 요청으로 속성값을 전달하는데 FlashMap을 사용하는 Mechanism 제공

HandlerInterceptor : ServletFilter와 비슷하게 DispatcherServlet이 Controller를 수행하기 전/후 요청 응답을 참조, 가공할 수 있는 필터 역할을 한다(interface)

DispatcherServlet의 HandlerExcutionChain 실행

  • HandlerExcutionChain - 요청을 처리할 하나의 handler(Controller)와 이 요청에 적용될 여러 interceptor들을 아우르는 요청 처리 객체

ServletFilter와 HandlerInterceptor의 차이?

ServletFilter는 DispatcherServlet 실행 전,후에 실행되지만 HandlerInterceptor는 DispatcherServlet이 실행되고, Controller 실행 전,후로 실행된다.

Applicationcontext 범위도 다르다.
Filter: Root ApplicationContext에 등록하고 관리된다. Filter는 Servlet ApplicationContext(MVC의 View나 @ExceptionHandler)를 이용할 수 없다 하지만HandlerInterceptor는 Servlet ApplicationContext에 등록, 관리된다.

HandlerInterceptor 설정

public class WebConfig implements WebMvcConfigurer {
    // ...

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
    }
}

FileUpload
Servlet 3.0 API 정보

@MultipartConfig(
    location = "/tmp/",
    maxFileSize = -1L,
    maxRequestSize = -1L,
    fileSizeThreshold = 1024
)
@Slf4j
public class FileUploadServlet extends HttpServlet {
    private static final String CONTENT_DISPOSITION = "Content-Disposition";
    private static final String UPLOAD_DIR = "/Users/user/Downloads";

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        for (Part part : req.getParts()) {
            String contentDisposition = part.getHeader(CONTENT_DISPOSITION);

            if (contentDisposition.contains("filename=")) {
                String fileName = extractFileName(contentDisposition);

                if (part.getSize() > 0) {
                    part.write(UPLOAD_DIR + File.separator + fileName);
                    part.delete();
                }
            } else {
                String formValue = req.getParameter(part.getName());
                log.error("{}={}", part.getName(), formValue);
            }
        }
    }

    private String extractFileName(String contentDisposition) {
        for (String token : contentDisposition.split(";")) {
            if (token.trim().startsWith("filename")) {
                String fileName = token.substring(token.indexOf("=") + 1).trim().replace("\"", "");
                int index = fileName.lastIndexOf(File.separator);
                return fileName.substring(index + 1);
            }
        }

        return null;
    }
}

Spring MVC에서 File Upload

  • MultipartResolver 이용 : 멀티파트 요청을 처리하는 구현을 결정하는 역할이다
    종류 - StandardServletMultipartResolver, CommonsMultipartResolver

View

ViewResolver

  • Spring MVC에서는 view 이름을 문자열로 관리
  • 문자열 기반의 view 이름을 토대로 실제 View 구현을 결정하는 역할

종류

Thymeleaf 문법 (변수 vs 메세지)
${variable}

  • 변수
<span th:text="${greeting}" />

#{messageKey}

  • 다국어 메세지
<span th:text="#{greeting}" />

Thymeleaf 문법은 다음과 같다 (html5) 속성 이용
th:text - 텍스트 출력(HTML escape 됨)
th:utext - 텍스트 출력(HTML 태그 그대로 적용)
th:each - 반복문
th:if, th:unless - 조건문
th:swifth, th:case
th:with - 로컬변수 선언

Expression Basic Objects

  • #locale
  • #request
  • #response
  • #session
  • #servletContext

Expression Utility Objects

  • strings : #strings - 문자열 객체를 위한 utility method
${#strings.isEmpty(name)}
${#strings.contains(name,'ez')} 
${#strings.startsWith(name,'Don')}
  • lists : #lists - list 객체를 위한 utility 메서드
${#lists.size(list)}
${#lists.isEmpty(list)}

0개의 댓글