1 SpringMVC配置
1.1 原项目参考
一下变更大都是在此无xml
基础上整合的
先看原无xml项目地
1.2 静态资源映射
程序的静态文件(js、css
等)需要直接访问,这时我们可以在配置里重写addResourceHandler
方法,类似于在springmvc
的地方配置静态资源放行
由于优雅REST
风格的资源URL
不希望带.html
或 .do
等后缀.
由于早期的Spring MVC
不能很好地处理静态资源,所以在web.xml
中配置DispatcherServlet
的请求映射,往往使用 *.do 、 *.xhtml
等方式。这就决定了请求URL
必须是一个带后缀的URL
,而无法采用真正的REST
风格的URL
如果将DispatcherServlet
请求映射配置为/
,则Spring MVC
将捕获Web
容器所有的请求,包括静态资源的请求,Spring MVC
会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误,所以需要放行静态资源
@Configuration
@EnableWebMvc
@ComponentScan("cn.jzh")
public class MyMvcConfig implements WebMvcConfigurer {
/**
* 此处相当于web项目中 springmvc.xml文件
* @return
*/
@Bean
public InternalResourceViewResolver viewResolver (){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
/**
* 静态资源放行
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//ResourceHandler对外暴露路径 ResourceLocations:资源位置
registry.addResourceHandler("/jquery/**").addResourceLocations("classpath*:/WEB-INF/jquery/");
}
}
注意:
classpath
和classpath*
在spring
加载资源的时候是不同的:
-
classpath
:只能加载找到的第一个
资源文件 -
classpath*
:能加载多个路径下的资源文件
1.3 拦截器配置
拦截器实现一个请求处理前和处理后进行相关业务处理,类似Servlet
的Filter
可以是实现HandlerInterceptor
接口或者继承HandlerInterceptorAdapter
来实现自定义的拦截器
package cn.jzh.config;
import cn.jzh.controller.JspController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* SpringMVC拦截器配置
*/
@Component
public class MyMvcInterceptor extends HandlerInterceptorAdapter {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("请求处理器前开始执行。。。。。。");
long startTimes = System.currentTimeMillis();
request.setAttribute("startTimes",startTimes);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("请求处理器后开始执行。。。。。。");
long endTimes = System.currentTimeMillis();
long startTimes = (Long)request.getAttribute("startTimes");
request.removeAttribute("startTimes");
long handTimes = endTimes - startTimes;
log.info("本次请求处理时间:{}",handTimes);
}
}
配置到springmvc
相关配置中去
package cn.jzh.config;
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.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@Configuration
@EnableWebMvc
@ComponentScan("cn.jzh")
public class MyMvcConfig implements WebMvcConfigurer {
@Autowired
private MyMvcInterceptor interceptor;
/**
* 此处相当于web项目中 springmvc.xml文件
* @return
*/
@Bean
public InternalResourceViewResolver viewResolver (){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
/**
* 拦截器部分
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
1.4 其他配置
视图层配置ViewController
在项目开发过程中,经常会涉及页面跳转问题,而且这个页面跳转没有任何业务逻辑过程,只是单纯的路由过程 ( 点击一个按钮跳转到一个页面 )
常规写法如下:
@RequestMapping("/toview")
public String view(){
return "view";
}
如果项目中有很多类似的无业务逻辑跳转过程,那样会有很多类似的代码
那么如何可以简单编写,这种代码?
Spring MVC
中提供了一个方法,可以把类似代码统一管理,减少类似代码的书写(根据项目要求,或者代码规范,不一定非要统一管理页面跳转,有时会把相同业务逻辑的代码放在一个类中)
在实现WebMvcConfigurer的MyMvcConfig类中重载addViewControllers
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/toview").setViewName("/view");
//添加更多
}
以上代码等效于第一种写法
1.5 @EnableWebMvc
1.5.1 对spring boot项目影响
假如是pringboot
项目,pringboot
默认可以访问以下路径文件:
- classpath:/static
- classpath:/public
- classpath:/resources
- classpath:/META-INF/resources
当使用了@EnableWebMvc
时,默认的静态资源访问无效了因为默认情况下mvc
使用的配置是WebMvcAutoConfiguration
,加入该配置变成了WebMvcConfigurationSupport
1.5.2 @EnableWebMvc、WebMvcConfigurationSupport、WebMvcConfigurationAdapter
@EnableWebMvc
=WebMvcConfigurationSupport
,使用了@EnableWebMvc
注解等于扩展了WebMvcConfigurationSupport
但是没有重写任何方法
看源码如下:
同时可以看下@EnableWebMvc
源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
其中@Import(DelegatingWebMvcConfiguration.class)
为该注解的核心,
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
可以看到,该类DelegatingWebMvcConfiguration
也是WebMvcConfigurationSupport
的子类,但是相对而言,添加了自己的扩展配置,同时从setConfigurers
可以看到,所有WebMvcConfigurer
的子类也会被添加到配置中
各个组合搭配情况:
-
@EnableWebMvc
+extends WebMvcConfigurationAdapter
,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot
的WebMvcAutoConfiguration
中的设置 -
@EnableWebMvc
+extends WebMvcConfigurationSupport
只会使用@EnableWebMvc
-
extends WebMvcConfigurationSupport
,在扩展的类中重写父类的方法即可,这种方式会屏蔽springboot
的@WebMvcAutoConfiguration
中的设置 -
extends WebMvcConfigurationAdapter
,在扩展的类中重写父类的方法即可,这种方式依旧使用springboot
的WebMvcAutoConfiguration
中的设置 -
@EnableWebMvc
+implements WebMvcConfigurer
的方式可以实现springboot
的WebMvcAutoConfiguration
中的设置的配置加上自己的配置
在springboot2.x
中,WebMvcConfigurationAdapter
已经过时,通过实现接口WebMvcConfigurer
可以替代原有规则
在默认情况下,springboot
是启用WebMvcAutoConfiguration
,这点可以在spring-boot-autoconfigure.jar/META-INF/spring.factories
中看到
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration
但是打开WebMvcAutoConfiguration
可以看到
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration{
}
其中@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
说明,当没有WebMvcConfigurationSupport
对应的bean
时,才会使用该配置,所以当我们使用继承WebMvcConfigurationSupport
的方式类扩展mvc
时,原有的配置则无效。
其中WebMvcConfigurerAdapter
,也是WebMvcConfigurer
的子类,
这就是为什么我们使用@EnableWebMvc+WebMvcConfigurer
的方式可以实现EnableWebMvc
的配置加上自己的配置了