caffeine-library / pro-spring-5

🌱 전문가를 위한 스프링5를 읽는 스터디
5 stars 0 forks source link

[keyword] 16장 스프링 웹 애플리케이션 키워드 정리 (1) #91

Closed JasonYoo1995 closed 2 years ago

JasonYoo1995 commented 2 years ago

주제

16장 스프링 웹 애플리케이션을 읽고 중요✨ 하다고 생각하는 키워드와 선택한 이유에 대해서 코멘트로 달아주세요.

90

JasonYoo1995 commented 2 years ago

1. MVC 소개

image

3. 스프링 MVC WebApplicationContext 구조

4. 스프링 MVC 요청 라이프사이클

5. 스프링 MVC 구성

image

binchoo commented 2 years ago

스프링 MVC 설정

서블릿 이니셜라이저 (web.xml 대체)

image

getServletMappings()

DispatcherServlet이 처리할 요청 주소 패턴을 설정한다. return new String[]{"/"} 는 모든 요청에 대한 처리를 의미함.

필터 설정

필터는 서블릿으로 들어오는 모든 요청뿐만 아니라, 나가는 응답에도 적용하는 로직이다. image

필터 CharacterEncodingFilter

요청의 문자열 인코딩을 설정한다. forceEncoding=true로 주면 응답 문자열의 인코딩도 지정한다. image

필터 HiddenHttpMethodFilter

<form>, <input> 태그 사용 시 GET, POST 제외한 다른 메서드를 지원하지 않는 브라우저가 있다. 스프링은 해당 정책을 우회하여 PUT, PATCH, DELETE 메서드도 사용할 수 있는 꼼수를 제공한다.

태그 작성 시,hidden타입 +_method` 이름을 갖도록하면 스프링이 이를 인식하여 PUT, PATCH, DELETE용 컨트롤러를 호출 해 준다.

<input type="hidden" name="_method" value="put"/>

HiddenHttpMethodFilter를 추가하는 것으로 이 기능을 활성할 수 있다.

OpenEntityManagerInView 필터 (주의할 필터)

EntityManager는 트랜잭션 단위로 유지되므로 다음과 같은 문제를 경험할 수 있다.

OSIV 패턴 EntityManager를 요청 스레드에 바인딩하여 뷰에서도 영속성 컨텍스트가 살아있는 패턴이다. 영속성 컨텍스트는 트랜잭션 범위 밖에서 조회 기능만을 제공한다. 지연 로딩 기능도 조회 기능에 포함되어 트랜잭션 범위 밖에서 동작 가능하다.

OSIV 패턴을 적용하면 뷰에서도 영속성 컨텍스트가 살아 있기 때문에 지연 로딩을 동작시킬 수 있다. image

Spring Boot는 옵션 spring.jpa.open-in-view=true로 지정하여 OSIV가 적용된 상태로 어플리케이션을 구성해 준다.

OSIV 패턴의 단점 장시간 DB 커넥션 리소스를 사용한다. 실시간 및 대량 트래픽이 중요한 애플리케이션에서는 자원이 모자랄 수 있다. 이것은 결국 장애로 이어진다.

OSIV 패턴의 대안

binchoo commented 2 years ago

DispatcherServlet 설정

image

configureDefaultServlet()

스프링 MVC는 DispatcherServlet/에 매핑되는 것을 허용한다. 원래 "/"는 컨테이너의 Default Servlet이 사용하는 주소인데 그럼 DispatcherServlet이 이것을 덮어 씌우게 된다.

이 경우 GET /styles/standard.css 같은 리소스 요청이 생기면, DispatchServelet에 대응하는 컨트롤러가 없어 응답을 할 수 없다.

그러므로 여전히 Default Servelet이 리소스 요청을 처리하도록 만들 방법이 필요하다.

그 방법은, 가장 낮은 우선순위의 /** -> Default Servlet 매핑을 설정하는 것이다. 이를 구현하는 간편한 코드가 아래와 같다.

// <=> <mvc:default-servlet-handler/>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

참고글- spring docs 참고글 - tomcat what is the default servelet?

뷰 컨트롤러 설정

컨트롤러 클래스 작성 없이 간단하게 뷰를 내려주는 뷰 컨트롤러를 등록한다.

@Override
 public void addViewControllers(ViewControllerRegistry registry) {
   //시작페이지 url을 "/"가 아닌 home으로
   registry.addRedirectViewController("/", "home");
   // "/login" 요청에 대하여 "loginPage" 뷰를 내려준다. 
   registry.addViewController("/login").setViewName("loginPage");
 }

리소스 핸들러 설정

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/")
            .setCachePeriod(31556926);
}

메시지 소스 설정

국제화 메시지가 담긴 리소스 번들(프로퍼티 파일)을 메시지 소스로 사용한다.

@Bean
ReloadableResourceBundleMessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("WEB-INF/i18n/messages", "WEB-INF/i18n/application");
    messageSource.setDefaultEncoding("UTF-8");
    messageSource.setFallbackToSystemLocale(false);
    return messageSource;
}

테마 소스 설정

리소스 번들(프로퍼티 파일)을 테마 소스로 사용한다. /src/main/resources 하위에 테마명.properties 파일을 생성하면, 해당하는 테마에 대한 리소스 번들이 된다.

@Bean TilesConfigurer tilesConfigurer() { TilesConfigurer tilesConfigurer = new TilesConfigurer(); tilesConfigurer.setDefinitions( "/WEB-INF/layouts/layouts.xml", "/WEB-INF/views/**/views.xml" ); tilesConfigurer.setCheckRefresh(true); return tilesConfigurer; }


### 국제화 지원 설정(쿠키 및 URL 패러미터)
- CookieLocaleResolver
쿠키를 사용하여 로케일 값을 브라우저에 저장하고. 나중에 로케일을 리졸브 할 때 사용할 수 있다. 기본적으로 세션 동안 쿠키 값이 유지된다.
  ```java
    @Bean
    CookieLocaleResolver localeResolver() {
        CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
        cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
        cookieLocaleResolver.setCookieMaxAge(3600);
        cookieLocaleResolver.setCookieName("locale");
        return cookieLocaleResolver;
    }

테마 지원 설정(쿠키 및 URL 패러미터)

국제화 지원과 동일한 설정 패턴이다.

    @Bean
    CookieThemeResolver themeResolver() {
        CookieThemeResolver cookieThemeResolver = new CookieThemeResolver();
        cookieThemeResolver.setDefaultThemeName("standard");
        cookieThemeResolver.setCookieMaxAge(3600);
        cookieThemeResolver.setCookieName("theme");
        return cookieThemeResolver;
    }

    @Bean
    ThemeChangeInterceptor themeChangeInterceptor() {
        return new ThemeChangeInterceptor();
    }

검증기 및 포맷터 등록

getValidator()addFormatters()를 구현하여 검증 및 포맷터 빈 등록.

@Override
public Validator getValidator() {
    return validator();
}

@Bean
public Validator validator() {
    final LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
    validator.setValidationMessageSource(messageSource());
    return validator;
}

// <=> replacement for 'typeConversionService'  bean
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
    formatterRegistry.addFormatter(dateFormatter());
}

@Bean
public DateFormatter dateFormatter() {
    return new DateFormatter();
}
binchoo commented 2 years ago

스태틱 리소스 내려주기

여태껏 사용한 구성설정에서 addResourceHandler()configureDefaultServletHandling() 부분을 주석 처리했을 때 스태틱 리소스 파일을 위한 요청이 어떻게 달라지는 지 확인해 봅니다.

얻고자 하는 파일은 프로젝트 폴더 /src/main/resources/styles/stadard.css 에 위치하던 파일입니다.

리소스 핸들러 등록 Default Servlet 핸들링 접근 주소
(/src/main/resources/styles/standard.css)
X X 접근할 수 있는 주소가 없음.
X O (ROOT 배포)
localhost:8080/styles/standard.css
(일반 배포)
localhost:8080/서블릿명/styles/standard.css
O * (ROOT 배포)
localhost:8080/resources/styles/standard.css
(일반 배포)
localhost:8080/서블릿명/resources/styles/standard.css

위 표를 보았을 때, 리소스 핸들러가 등록되어 있다면, 스태틱 리소스에 매핑되는 URL이 꼭 존재하므로 Default Servlet 핸들링 설정은 신경쓰지 않아도 됩니다.

리소스 핸들러가 없다면, https://github.com/caffeine-library/pro-spring-5/issues/91#issuecomment-986165189 에서 언급한 대로 리소스 요청에 매핑해 줄 컨트롤러가 디스패처 서블릿에 없기 때문에 Default Servelet 핸들링을 활성하여야 합니다.