SpringMVC無xml檔案之靜態資源,攔截器配置和@EnableWebMvc
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<WebMvcConfigurer> 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
的配置加上自己的配置了