diff --git a/src/main/java/org/springframework/samples/petclinic/config/MvcCoreConfig.java b/src/main/java/org/springframework/samples/petclinic/config/MvcCoreConfig.java index 69ddf94e7..e96af0043 100644 --- a/src/main/java/org/springframework/samples/petclinic/config/MvcCoreConfig.java +++ b/src/main/java/org/springframework/samples/petclinic/config/MvcCoreConfig.java @@ -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; + +/** + *

+ * 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. + * + *

+ * View name resolved using bean of type InternalResourceViewResolver + * (declared in {@link MvcViewConfig}). + */ + @Override + public void configureHandlerExceptionResolvers( + List 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); + } } diff --git a/src/main/java/org/springframework/samples/petclinic/config/MvcViewConfig.java b/src/main/java/org/springframework/samples/petclinic/config/MvcViewConfig.java new file mode 100644 index 000000000..3b16448c5 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/config/MvcViewConfig.java @@ -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 viewResolvers = new ArrayList(); + 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; + } + +} diff --git a/src/main/resources/spring/mvc-core-config.xml b/src/main/resources/spring/mvc-core-config.xml deleted file mode 100644 index 170fbdba1..000000000 --- a/src/main/resources/spring/mvc-core-config.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/resources/spring/mvc-view-config.xml b/src/main/resources/spring/mvc-view-config.xml deleted file mode 100644 index 4413f0195..000000000 --- a/src/main/resources/spring/mvc-view-config.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/java/org/springframework/samples/petclinic/web/VisitsViewTests.java b/src/test/java/org/springframework/samples/petclinic/web/VisitsViewTests.java index 2f1e17fa3..8372f60af 100644 --- a/src/test/java/org/springframework/samples/petclinic/web/VisitsViewTests.java +++ b/src/test/java/org/springframework/samples/petclinic/web/VisitsViewTests.java @@ -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 {