Migrate to the Spring MVC Java Configuration

This commit is contained in:
Antoine Rey 2014-07-05 10:20:34 +02:00
parent 8ffd295196
commit b0a2dc69b1
5 changed files with 247 additions and 135 deletions

View file

@ -1,10 +1,148 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.samples.petclinic.web.PetTypeFormatter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
/**
* <p>
* The ContentNegotiatingViewResolver delegates to the
* InternalResourceViewResolver and BeanNameViewResolver, and uses the requested
* media type (determined by the path extension) to pick a matching view. When
* the media type is 'text/html', it will delegate to the
* InternalResourceViewResolver's JstlView, otherwise to the
* BeanNameViewResolver.
*
*/
@Configuration
@ImportResource("classpath:spring/mvc-core-config.xml")
public class MvcCoreConfig {
@EnableWebMvc
@Import(MvcViewConfig.class)
// POJOs labeled with the @Controller and @Service annotations are
// auto-detected.
@ComponentScan(basePackages = { "org.springframework.samples.petclinic.web" })
public class MvcCoreConfig extends WebMvcConfigurerAdapter {
@Autowired
private ClinicService clinicService;
@Override
public void configureContentNegotiation(
ContentNegotiationConfigurer configurer) {
configurer.ignoreAcceptHeader(true);
configurer.defaultContentType(MediaType.TEXT_HTML);
configurer.mediaType("html", MediaType.TEXT_HTML);
configurer.mediaType("xml", MediaType.APPLICATION_XML);
configurer.mediaType("atom", MediaType.APPLICATION_ATOM_XML);
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
// Serve static resources (*.html, ...) from src/main/webapp/
configurer.enable();
}
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addFormatter(petTypeFormatter());
}
@Bean
public PetTypeFormatter petTypeFormatter() {
return new PetTypeFormatter(clinicService);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// all resources inside folder src/main/webapp/resources are mapped so
// they can be refered to inside JSP files (see header.jsp for more
// details)
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
// uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...)
registry.addResourceHandler("/webjars/**").addResourceLocations(
"classpath:/META-INF/resources/webjars/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("welcome");
}
@Bean(name = "messageSource")
@Description("Message source for this context, loaded from localized 'messages_xx' files.")
public ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource() {
// Files are stored inside src/main/resources
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages/messages");
return messageSource;
}
/**
* Resolves specific types of exceptions to corresponding logical view names
* for error views.
*
* <p>
* View name resolved using bean of type InternalResourceViewResolver
* (declared in {@link MvcViewConfig}).
*/
@Override
public void configureHandlerExceptionResolvers(
List<HandlerExceptionResolver> exceptionResolvers) {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
// results into 'WEB-INF/jsp/exception.jsp'
exceptionResolver.setDefaultErrorView("exception");
// needed otherwise exceptions won't be logged anywhere
exceptionResolver.setWarnLogCategory("warn");
exceptionResolvers.add(exceptionResolver);
}
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.samples.petclinic.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.samples.petclinic.model.Vets;
import org.springframework.samples.petclinic.web.VetsAtomView;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.BeanNameViewResolver;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.xml.MarshallingView;
@Configuration
public class MvcViewConfig {
@Bean
public ContentNegotiatingViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
ContentNegotiatingViewResolver contentNegotiatingViewResolver = new ContentNegotiatingViewResolver();
List<ViewResolver> viewResolvers = new ArrayList<ViewResolver>();
viewResolvers.add(internalResourceViewResolver());
viewResolvers.add(beanNameViewResolver());
contentNegotiatingViewResolver.setViewResolvers(viewResolvers );
contentNegotiatingViewResolver.setContentNegotiationManager(manager);
return contentNegotiatingViewResolver;
}
@Bean
@Description("Default viewClass: JSTL view (JSP with html output)")
public ViewResolver internalResourceViewResolver() {
// Example: a logical view name of 'vets' is mapped to
// '/WEB-INF/jsp/vets.jsp'
InternalResourceViewResolver bean = new InternalResourceViewResolver();
bean.setViewClass(JstlView.class);
bean.setPrefix("/WEB-INF/jsp/");
bean.setSuffix(".jsp");
return bean;
}
@Bean
@Description("Used for 'xml' and 'atom' views")
public ViewResolver beanNameViewResolver() {
return new BeanNameViewResolver();
}
@Bean(name = "vets/vetList.atom")
@Description("Renders an Atom feed of the visits. Used by the BeanNameViewResolver")
public VetsAtomView vetsAtomView() {
return new VetsAtomView();
}
@Bean(name = "vets/vetList.xml")
@Description("Renders an XML view. Used by the BeanNameViewResolver")
public MarshallingView marshallingView() {
return new MarshallingView(marshaller());
}
@Bean
@Description("Object-XML mapping declared using annotations inside 'Vets'")
public Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(Vets.class);
return marshaller;
}
}

View file

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="mvc-view-config.xml"/>
<!--
- POJOs labeled with the @Controller and @Service annotations are auto-detected.
-->
<context:component-scan
base-package="org.springframework.samples.petclinic.web"/>
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- all resources inside folder src/main/webapp/resources are mapped so they can be refered to inside JSP files
(see header.jsp for more details) -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...) -->
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<mvc:view-controller path="/" view-name="welcome" />
<!-- serve static resources (*.html, ...) from src/main/webapp/ -->
<mvc:default-servlet-handler/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="org.springframework.samples.petclinic.web.PetTypeFormatter"/>
</set>
</property>
</bean>
<!--
- Message source for this context, loaded from localized "messages_xx" files.
- Files are stored inside src/main/resources
-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="messages/messages"/>
<!--
- This bean resolves specific types of exceptions to corresponding logical
- view names for error views.
-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- view name resolved using bean of type InternalResourceViewResolver (declared in mvc-view-config.xml) -->
<property name="defaultErrorView" value="exception"/>
<!-- results into 'WEB-INF/jsp/exception.jsp' -->
<property name="warnLogCategory" value="warn"/>
<!-- needed otherwise exceptions won't be logged anywhere -->
</bean>
</beans>

View file

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- DispatcherServlet application context for PetClinic's web tier.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
- The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,
- and uses the requested media type (determined by the path extension) to pick a matching view.
- When the media type is 'text/html', it will delegate to the InternalResourceViewResolver's JstlView,
- otherwise to the BeanNameViewResolver.
-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="cnManager"/>
<property name="viewResolvers">
<list>
<!-- Default viewClass: JSTL view (JSP with html output) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- Example: a logical view name of 'vets' is mapped to '/WEB-INF/jsp/vets.jsp' -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- Used here for 'xml' and 'atom' views -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
</list>
</property>
</bean>
<!-- Simple strategy: only path extension is taken into account -->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="true"/>
<property name="defaultContentType" value="text/html"/>
<property name="mediaTypes">
<map>
<entry key="html" value="text/html" />
<entry key="xml" value="application/xml" />
<entry key="atom" value="application/atom+xml" />
</map>
</property>
</bean>
<!-- Renders an Atom feed of the visits. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.atom" class="org.springframework.samples.petclinic.web.VetsAtomView"/>
<!-- Renders an XML view. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.xml" class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="marshaller"/>
</bean>
<oxm:jaxb2-marshaller id="marshaller">
<!-- Object-XML mapping declared using annotations inside 'Vets' -->
<oxm:class-to-be-bound name="org.springframework.samples.petclinic.model.Vets"/>
</oxm:jaxb2-marshaller>
</beans>

View file

@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.samples.petclinic.config.BusinessConfig;
import org.springframework.samples.petclinic.config.MvcCoreConfig;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.ContextHierarchy;
@ -48,7 +49,7 @@ import org.springframework.web.context.WebApplicationContext;
@WebAppConfiguration
@ContextHierarchy({
@ContextConfiguration(classes = BusinessConfig.class),
@ContextConfiguration(locations = "classpath:spring/mvc-core-config.xml")})
@ContextConfiguration(classes = MvcCoreConfig.class)})
@ActiveProfiles("jdbc")
public class VisitsViewTests {