<mvc:annotation-driven>
<mvc:path-matching
path-helper="pathHelper"
path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-config
Web on Servlet Stack
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonl
docs.spring.io
틀린 해석이나 내용이 있다면 알려주세요 🤓
MVC 를 구성하는 API에 대해 한번 살펴보자
1.12.1. Enable MVC Configuration
@EnableWebMvc 애노테이션을 사용하여 활성화한다
- 자바방식
@Configuration
@EnableWebMvc
public class WebConfig {
}
- xml 방식 <mvc:annotation-driven>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
</beans>
Spring MVC infrastructure beans 을 등록하고 경로에서 사용 가능한 종속성을 적용한다
1.12.2. MVC Config API
WebMvcConfigurer 인터페이스를 을 상속하여 구현할 수있다
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods...
}
1.12.3. Type Conversion
기본적으로 다양한 숫자, 날짜 타입의 formatter 가 설치된다
@NumberFormat, @DateTimeFormat
사용자가 정의하고 싶은 formatter 가 있으면 이곳에 등록한다
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
XML방식
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.MyConverter"/>
</set>
</property>
<property name="formatters">
<set>
<bean class="org.example.MyFormatter"/>
<bean class="org.example.MyAnnotationFormatterFactory"/>
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.example.MyFormatterRegistrar"/>
</set>
</property>
</bean>
</beans>
기본적으로 날짜 값을 가져올 때 요청 Locale 에 맞춰서 가져온다
이 형식을 바꾸려면 addFormatter에 사용자정의 하면 된다
FormatterRegister 구현 방법
Core Technologies
In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do
docs.spring.io
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
1.12.4. Validation
앞서 공부했던 validation
기본적인 valid를 (Hibernate Validator 등)에 등록을 하면
LocalValidatorFactoryBean 은 @Valid 애노테이션과 함께 전역 Validator로 등록 된다
Controller method arguments 에서 Validated 된다
그치만 WebConfig 코드에서 전역으로 등록할 수 있다
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator() {
// ...
}
}
XML 방식
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="globalValidator"/>
</beans>
전역이 아닌 로컬 구현을 위해서는 이렇게 사용할 컨트롤러에서 initBinder 한다
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
LocalValidatorFctoryBean을 어딘가에 주입해야할 경우에는
MVC선언과 충돌을 피할 수 있도록 bean을 만들고 @Primary 애노테이션을 붙여준다
1.12.5. Interceptors
요청에 적용할 interceptor 도 이 WebConfig 에서 한다
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
}
}
XML
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
Mapped interceptors are not ideally suited as a security layer due to the potential for a mismatch with annotated controller path matching, which can also match trailing slashes and path extensions transparently, along with other path matching options. Many of these options have been deprecated but the potential for a mismatch remains. Generally, we recommend using Spring Security which includes a dedicated MvcRequestMatcher to align with Spring MVC path matching and also has a security firewall that blocks many unwanted characters in URL paths.
Spring MVC Integration :: Spring Security
Spring Security provides AuthenticationPrincipalArgumentResolver, which can automatically resolve the current Authentication.getPrincipal() for Spring MVC arguments. By using @EnableWebSecurity, you automatically have this added to your Spring MVC configur
docs.spring.io
1.12.6. Content Types
Spring MVC Request 에서 요청된 미디어 유형(Accept header, URL path extension, query parameter, and others) 을 결정하는 방법을 구성한다
기본적으로 Header Accept 를 체크한다
If you must use URL-based content type resolution, consider using the query parameter strategy over path extensions. See Suffix Match and Suffix Match and RFD for more details.
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
configurer.mediaType("xml", MediaType.APPLICATION_XML);
}
}
xml방식
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
1.12.7. Message Converters
Java configuration 에서 HttpMessageConverter를 정의할 수 있다
1. configureMessageConverters()(Spring MVC에서 생성된 기본 변환기 대체)
2. extendMessageConverters()(기본 변환기를 사용자 지정하거나 추가 변환기를 기본 변환기에 추가)
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
Jackson2ObjectMapperBuilder 는 MappingJackson2HttpMessageConverter 및 MappingJackson2XmlHttpMessageConverter 공통 구성을 생성할 때 사용 하고
들여쓰기, 사용자 정의 날짜 형식등에 대한 형식을 추가했다
This builder customizes Jackson’s default properties as follows:
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES is disabled.
- MapperFeature.DEFAULT_VIEW_INCLUSION is disabled.
It also automatically registers the following well-known modules if they are detected on the classpath:
- jackson-datatype-joda: Support for Joda-Time types.
- jackson-datatype-jsr310: Support for Java 8 Date and Time API types.
- jackson-datatype-jdk8: Support for other Java 8 types, such as Optional.
- jackson-module-kotlin: Support for Kotlin classes and data classes.
https://search.maven.org/search?q=g:org.codehaus.woodstox%20AND%20a:woodstox-core-asl
- jackson-datatype-money: Support for javax.money types (unofficial module).
- jackson-datatype-hibernate: Support for Hibernate-specific types and properties (including lazy-loading aspects).
XML방식
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="xmlMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true"
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>
1.12.8. View Controllers
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
예제를 보면 ParameteriableViewController 호출 시에
그냥 바로 원하는 컨트롤러로 전달 할 수 있도록 선언한다.
/ ->를 바로 home 이 붙은 컨트롤러로 전달해준다
XML방식
<mvc:view-controller path="/" view-name="home"/>
If an @RequestMapping method is mapped to a URL for any HTTP method then a view controller cannot be used to handle the same URL.
This is because a match by URL to an annotated controller is considered a strong enough indication of endpoint ownership so that a 405 (METHOD_NOT_ALLOWED), a 415 (UNSUPPORTED_MEDIA_TYPE), or similar response can be sent to the client to help with debugging.
For this reason it is recommended to avoid splitting URL handling across an annotated controller and a view controller.
1.12.9. View Resolvers
The MVC configuration simplifies the registration of view resolvers.
JSON rendering 을 위한 기본 뷰를 JSP 및 Jackson으로 구성하는 예제
자바
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
xml
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:jsp/>
</mvc:view-resolvers>
java2 (freemarker 사용)
자바코틀린
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker().cache(false);
}
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/freemarker");
return configurer;
}
}
xml2 (freemarker 사용)
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>
1.12.10. Static Resources
리소스 기반 위치 list 에서 Static Resources를 편리하게 제공할 수 있다
/resources로 시작하는 요청이 있을 때 상대 경로를 사용하여 웹 애플리케이션 루트 아래 또는 /static 아래의 클래스 경로에서 /public에 상대적인 정적 리소스를 찾겠다는 코드.
리소스는 브라우저 캐시의 최대 사용과 브라우저의 HTTP 요청 감소를 보장하기 위해 향후 1년 만료로 제공한다.
Last-Modified 정보는 HTTP 조건부 요청이 "Last-Modified" 헤더로 지원되도록 Resource#lastModified에서 deduce한다
(정적자원에 대한 HTTP Caching)
Web on Servlet Stack
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonl
docs.spring.io
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
}
}
<mvc:resources mapping="/resources/**"
location="/public, classpath:/static/"
cache-period="31556926" />
ResourceResolver 및 ResourceTransformer 체인도 지원하여 최적화된 리소스 작업이 가능하다
You can use the VersionResourceResolver for versioned resource URLs based on an MD5 hash computed from the content, a fixed application version, or other. A ContentVersionStrategy (MD5 hash) is a good choice — with some notable exceptions, such as JavaScript resources used with a module loader.
VersionResourceResolver 를 사용한 예제
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
<mvc:resources mapping="/resources/**" location="/public/">
<mvc:resource-chain resource-cache="true">
<mvc:resolvers>
<mvc:version-resolver>
<mvc:content-version-strategy patterns="/**"/>
</mvc:version-resolver>
</mvc:resolvers>
</mvc:resource-chain>
</mvc:resources>
ResourceUrlProvider 를 사용하여 URL을 다시 작성하고 전체 체인을 적용할 수 있다
ResourceUrlProvider 빈을 제공하기 때문에 다른 빈에 주입할 수 있고
HttpServletResponse encodeURL에 의존하는 타임리프, JSP, FreeMarker 등에 대한 ResourceUrlEncodingFilter를 사용하여 재작성할 수 있다
EncodedResourceResolver(gzip 또는 brotli로 인코딩된 리소스 제공)와 VersionResourceResolver를 모두 사용하는 경우에는
순서대로 등록해야 한다. 콘텐츠 기반 버전이 인코딩되지 않은 파일을 기반으로 항상 안정적으로 처리해야하기 때문이다
https://www.webjars.org/documentation#springmvc
WebJars - Documentation
Instructions for Play 2.6 (Sample Source) WebJars can be added as dependencies to an app by simply adding them to the build.sbt file like: libraryDependencies += "org.webjars" % "bootstrap" % "3.1.1-2" Play automatically extracts the WebJar contents and ma
www.webjars.org
The Java configuration based on ResourceHandlerRegistry provides further options for fine-grained control, e.g. last-modified behavior and optimized resource resolution.
1.12.11. Default Servlet
Spring MVC는 static resource 요청이 컨테이너의 기본 서블리에 의해 처리 될 수 있도록 허용하면서
DispatcherServlet을 "/"에 매핑할 수 있다
URL 매핑을 /** 로 두고 우선 순위가 가장 낮은 DefaultServletHttpRequestHandler 를 구성한다
이 핸들러는 모든 요청을 기본 servlet 으로 전달하기 때문에
다른 모든 URL HandlerMappinig의 마지막 순서에 있어야한다
사용자 정의 된 HandlerMapping instance를 사용할 때도
order 속성을 DefaultServletHttpRequestHandler 의 Integer.MAX_VALUE보다 낮게 설정해주어야한다
DefaultServletHandlerConfigurer 활성화
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
<mvc:default-servlet-handler/>
/ Servlet 매핑에 재정의를 하려면 RequestDispatcher 를 검색할 때 경로가 아닌 이름으로 해야한다
DefaultServletHttpRequestHandler 대부분의 주요 서블리 컨테이너 (Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic 및 WebSphere 포함) 에 대해 알려진 이름 목록을 사용하여 시작 시 컨테이너의 기본 서블릿을 자동 감지하려고 시도한다.
기본 Servlet이 다른 이름으로 사용자 정의 구성되었거나 기본 Servlet 이름을 알 수 없는 다른 Servlet 컨테이너가 사용되는 경우 기본 Servlet의 이름을 명시적으로 제공해야 한다.
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
1.12.12. Path Matching
You can customize options related to path matching and treatment of the URL. For details on the individual options, see the PathMatchConfigurer javadoc.
PathMatchConfigurer (Spring Framework 6.0.4 API)
Whether to use suffix pattern match (".*") when matching patterns to requests. If enabled a method mapped to "/users" also matches to "/users.*". Note: This property is mutually exclusive with setPatternParser(PathPatternParser). If set, it enables use of
docs.spring.io
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
private PathPatternParser patternParser() {
// ...
}
}
<mvc:annotation-driven>
<mvc:path-matching
path-helper="pathHelper"
path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
1.12.13. Advanced Java Config
@EnableWebMvc imports DelegatingWebMvcConfiguration, which:
- Provides default Spring configuration for Spring MVC applications
- Detects and delegates to WebMvcConfigurer implementations to customize that configuration.
DelegatingWebMvcConfiguration 을 가져와서 구성한다
@EnableWebMvc 를 제거하고 WebMvcConfigurer 대신 DelegatingWebMvcConfiguration 에서 직접 확장도 가능하다
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
// ...
}
WebConfig 에서 기존 메서드를 유지했지만
기본 클래스에서 빈 선언을 재정의하고, 클래스 경로가 다른 WebMvcConfigurer 구현을 할 수 있게 된다
1.12.14. Advanced XML Config
The MVC namespace does not have an advanced mode. If you need to customize a property on a bean that you cannot change otherwise, you can use the BeanPostProcessor lifecycle hook of the Spring ApplicationContext
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
// ...
}
}
Note that you need to declare MyPostProcessor as a bean, either explicitly in XML or by letting it be detected through a <component-scan/> declaration.
'Web > spring' 카테고리의 다른 글
[Spring framework Web MVC docs] 1.4. Functional Endpoints (0) | 2023.02.12 |
---|---|
[Spring framework Web MVC docs] 1.2. Filters (0) | 2023.02.11 |
[Spring framework Web MVC docs] 1.1.6.Path Matching ~ 1.1.7. Interception (0) | 2023.02.10 |
[Spring framework testing] 5. Spring TestContext Framework (2) (0) | 2023.02.09 |
[Spring framework testing] 5. Spring TestContext Framework (1) (0) | 2023.02.09 |