Spring注解@EnableWebMvc使用坑点解析

通过注解的方式来进行Spring4 MVC开发时,我们都会在配置文件中加入<mvc:annotation-driven/>标签,这个配置会自动注册了一个 RequestMappingHandlerMapping、一个RequestMappingHandlerAdapter、以及一个ExceptionHandlerExceptionResolver 以支持使用注解Controller的注解方法(如@RequestMapping、@ExceptionHandler)来处理request,并开启一系列默认功能设置。

<!-- 开启SpringMVC注解模式 -->
<!-- 提供一系列功能:数据绑定,数字和日期format @NumberFormat,
@DataTimeFormat,xml/json默认读写支持-->
<mvc:annotation-driven/>
1
2
3
4
如果没有配置<mvc:annotation-driven/>,org.springframework.web.servlet.DispatcherServlet无法找到控制器并把请求分发到控制器。添加上<mvc:annotation-driven/>后,请求会被相应的Controller处理。然而这时访问静态资源可能就不好使了,怎么办?一般可以使用 <mvc:default-servlet-handler />这个标签

<!-- 静态资源默认servlet配置
1.加入对静态资源的处理:js/gif
2.允许使用"/"做整体映射
-->
<mvc:default-servlet-handler />
1
2
3
4
5
所以这两个标签一般放在一起使用。

在Spring Boot中使用@EnableWebMvc也可能遇到类似的问题,@EnableWebMvc是使用注解方式快捷配置Spring Webmvc的一个注解。在使用时你可能会遇到以下问题:

Spring Boot在application文件中的配置失效
在Spring Boot的自定义配置类加上@EnableWebMvc后,发现自动配置的静态资源路径(classpath:/META/resources/,classpath:/resources/,classpath:/static/,classpath:/public/)资源无法访问。
通过查看@EnableWebMvc的源码,可以发现该注解就是为了引入一个DelegatingWebMvcConfiguration 配置类,而DelegatingWebMvcConfiguration又继承于WebMvcConfigurationSupport。也就是说,如果我们使用@EnableWebMvc就相当于导入了WebMvcConfigurationSupport类,这个时候,Spring Boot的自动装配就不会发生了,我们能用的,只有WebMvcConfigurationSupport提供的若干个配置。其实不使用@EnableWebMvc注解也是可以实现配置Webmvc,只需要将配置类继承于WebMvcConfigurationSupport类即可。

当使用@EnableWebMvc时,加载的是WebMvcConfigurationSupport中的配置项。

当不使用@EnableWebMvc时,使用的是WebMvcAutoConfiguration引入的配置项。

查看一下WebMvcAutoConfiguration 的源码:

@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
...
}
1
2
3
4
5
6
7
8
9
10
可以看到自动配置类 WebMvcAutoConfiguration 上有条件注解

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
1
这个注解的意思是在项目类路径中缺少 WebMvcConfigurationSupport类型的bean时改自动配置类才会生效。

有时候我们需要自己定制一些项目的设置,可以有以下几种使用方式:

@EnableWebMvc+extends WebMvcConfigurationAdapter,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置

extends WebMvcConfigurationSupport,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot的@EnableAutoConfiguration中的设置

extends WebMvcConfigurationAdapter/WebMvcConfigurer,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot的@EnableAutoConfiguration中的设置

WebMvcConfigurer 没有暴露高级设置,如果需要高级设置 需要第二种方式继承WebMvcConfigurationSupport或者DelegatingWebMvcConfiguration,例如:

@Configuration
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurationSupport {

@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addConverter(new MyConverter());
}

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// Create or delegate to "super" to create and
// customize properties of RequestMappingHandlerAdapter
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
所以无论是使用@EnableWebMvc还是WebMvcConfigurationSupport,都会禁止Spring Boot的自动装配@EnableAutoConfiguration中的设置( 虽然禁止了Spring boot的自动装配,但是WebMvcConfigurationSupport本身,还是会注册一系列的MVC相关的bean的)。

@EnableAutoConfiguration是SpringBoot项目的启动类注解@SpringBootApplication的子元素,@EnableAutoConfiguration实际是导入EnableAutoConfigurationImportSelector和Registar两个类,主要功能是通过SpringFactoriesLoader.loadFactoryNames()导入jar下面配置文件META-INF/spring.factories。我们翻spring.factories,其中就包含WebMvc自动装配类:

...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
...
1
2
3
4
5
并且@EnableAutoConfiguration 注解,会自动读取 application.properties 或 application.yml 文件中的配置。因此想想前面提到的第一个问题就很明白了。

如果想要使用自动配置生效,同时又要使用部分spring mvc默认配置的话,比如增加 viewController ,则可以将自己的配置类可以继承 WebMvcConfigurerAdapter 这个类。不过在Spring5.0版本WebMvcConfigurerAdapter 后这个类被标记为@Deprecated了 。

* @author Rossen Stoyanchev
* @since 3.1
* @deprecated as of 5.0 {@link WebMvcConfigurer} has default methods (made
* possible by a Java 8 baseline) and can be implemented directly without the
* need for this adapter
*/
@Deprecated
public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
...
}
1
2
3
4
5
6
7
8
9
10
Spring 5.0后要使用Java8,而在Java8中接口是可以有default方法的,所以这个类就没必要了。所以我们只需要在自定义配置类中直接实现 WebMvcConfigurer 接口就好了

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MyWebConfig implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("helloworld");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
When we access URL /hello then helloworld.jsp will run.

对于第二个问题,如果使用@EnableWebMvc了,那么就会自动覆盖了官方给出的/static, /public, META-INF/resources, /resources等存放静态资源的目录。而将静态资源定位于src/main/webapp。当需要重新定义好资源所在目录时,则需要主动添加上述的那个配置类,来重写 addResourceHandlers方法。

@Configuration
@EnableWebMvc
public class MyWebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/public/");
}
}
1
2
3
4
5
6
7
8
9
从上述可知在SpringBoot中大多数时我们并不需要使用@EnableWebMvc注解,来看下官方的一段说明:

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration

说明:

Spring Boot 默认提供Spring MVC 自动配置,不需要使用@EnableWebMvc注解
如果需要配置MVC(拦截器、格式化、视图等) 请使用添加@Configuration并实现WebMvcConfigurer接口.不要添加@EnableWebMvc注解。
@EnableWebMvc 只能添加到一个@Configuration配置类上,用于导入Spring Web MVC configuration
最后,如果Spring Boot在classpath里看到有 spring webmvc 也会自动添加@EnableWebMvc。
————————————————
版权声明:本文为CSDN博主「zxc123e」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zxc123e/article/details/84636521

原文地址:https://www.cnblogs.com/shujiying/p/12442775.html

时间: 2024-08-30 13:57:09

Spring注解@EnableWebMvc使用坑点解析的相关文章

Spring注解Component原理源码解析

在实际开发中,我们经常使用Spring的@Component.@Service.@Repository以及 @Controller等注解来实现bean托管给Spring容器管理.Spring是怎么样实现的呢?我们一起跟着源码看看整个过程吧! 照旧,先看调用时序图: public AnnotationConfigApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); } Spring启动

spring注解式开发之视图解析器

http://localhost:8089/springmvc-04-viewResovler/springmvc/hello 原文地址:https://www.cnblogs.com/wq-9/p/10166504.html

Spring注解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析

URL:http://www.ulewo.com/user/10001/blog/273 我们在使用spring的时候经常会用到这些注解,那么这些注解到底有什么区别呢.我们先来看代码 同样分三层来看: Action 层: package com.ulewo.ioc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Co

spring注解详解

1. 使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的 类的实现: Java代码 public class UserManagerImpl implements UserManager { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } ... } public class UserManagerImpl implements Use

Spring注解@Component、@Repository、@Service、@Controller区别

Spring注解@Component.@Repository.@Service.@Controller区别 Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository.@Service 和 @Controller.在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,但是从注释类的命名上,很容易看出这 3 个注释分别和持久层.业务层和控制层(Web 层)相对应.虽然目前这 3 个注释和 @Comp

Struts2+Spring3+MyBatis3整合以及Spring注解开发

 分类: Web(2)  版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在做一个SpringMVC+spring+MyBatis的项目,突然想起以前自己要搭建一个Struts2+Spring+IBatis的框架,但是没成功,正好看见培训时候老师给的千里之行的开源项目.于是将这个项目提供的SQL加入到了自己的数据库中(所以数据和项目名用的是qlzx),打算以后做练习的时候用这个数据库.那么接下来问题来了(不要说某翔或者不约,不是那个问题):我有了数据库和数据,想要搭建一个网站,该怎么做

spring注解说明之Spring2.5 注解介绍(3.0通用)

spring注解说明之Spring2.5 注解介绍(3.0通用) 注册注解处理器 方式一:bean <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> 方式二:命名空间 <context:annotation-config /><context:annotationconfig /> 将隐式地向Spring容

Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable(转)

最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一) 构建简单Web应用 Spring 注解学习手札(二) 控制层梳理 Spring 注解学习手札(三) 表单页面处理 Spring 注解学习手札(四) 持久层浅析 Spring 注解学习手札(五) 业务层事务处理 Spring 注解学习手札(六) 测试 Spring 注解学习手札(七) 补遗--@R

Spring 注解

转自 Spring注解详解  http://blog.csdn.net/xyh820/article/details/7303330/            这篇文章不错   但没说清楚一些问题 概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名.类型等信息,如果关系表字段和 PO 属性名.类型都一致,您甚至无需编写任务属性映射信息--因