springboot學習筆記之SpringMVC自動配置原理
Springboot中自動配置Springmvc的檔案
@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 {
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver (BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
}
檢視解析器是如何配置進去的呢?
如上圖,利用到了ContentNegotiatingViewResolver這個類
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
implements ViewResolver, Ordered, InitializingBean {
@Nullable
private List<ViewResolver> viewResolvers;
}
該類中定義了檢視解析器的集合,那麼這些檢視解析器是如何獲取到的呢
@Override
protected void initServletContext(ServletContext servletContext) {
Collection<ViewResolver> matchingBeans =
**BeanFactoryUtils.beansOfTypeIncludingAncestors(obtainApplicationContext(), ViewResolver.class).values();**
if (this.viewResolvers == null) {
this.viewResolvers = new ArrayList<>(matchingBeans.size());
for (ViewResolver viewResolver : matchingBeans) {
if (this != viewResolver) {
this.viewResolvers.add(viewResolver);
}
}
}
如上圖可以看到是在springcontext容器中獲取到的,因此我們根據這個原理可以讓ContentNegotiatingViewResolver自動裝配我們放在容器中的自定義的檢視解析器
@Bean
public ViewResolver myResolver(){
return new MyResolver();
}
private static class MyResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
然後啟動springboot,ContentNegotiatingViewResolver會為我們自動載入我們的自定義檢視解析器,要檢視效果可以看DisPatcherServlet該類的doDispastcher方法,檢視傳入引數request的屬性viewResolver中的ContentNegotiatingViewResolver,檢視他的裝載的檢視解析器列表,可以看到我們自定義的檢視解析器
擴充套件springmvc
如果我們想保留springboot對springmvc的自動配置功能,同時我們想新增簡單的springmvc的特殊功能,比如攔截器等,我們可以編寫一個配置類,且是webMvcConfigurerAdapter型別,且不能標註@enableWebMvc
/**
* 使用這個類來擴充套件springMVC的功能
*/
@Configuration
public class MyMvcConfigurer extends WebMvcConfigurerAdapter {
// 想要擴充套件什麼方法就實現什麼方法
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
}
之所以要跟上面的方式寫,為了避免每跳轉一個template的頁面就要寫一個方法,造成冗雜程式碼,我們可以在上面註冊很多個檢視,比如下面這樣
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
國際化
點選頁面中的選項,選擇中文或者英文顯示頁面中的文字
在springmvc中需要經過如下3步:
1)、編寫國際化配置檔案;
2)、使用ResourceBundleMessageSource管理國際化資原始檔
3)、在頁面使用fmt:message取出國際化內容
而在springboot中國際化非常容易,只需要編寫國際化檔案,其他springboot都幫助我們實現了
第一個配置檔案:不選擇語言資訊預設的
第二個配置檔案英文,第三個配置檔案中文
攔截器進行登陸檢查
/**
* 登陸檢查,
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
//目標方法執行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){
//未登陸,返回登陸頁面
request.setAttribute("msg","沒有許可權請先登陸");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
//已登陸,放行請求
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
註冊攔截器
//所有的WebMvcConfigurerAdapter元件都會一起起作用
@Bean //將元件註冊在容器
public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/index.html").setViewName("login");
registry.addViewController("/main.html").setViewName("dashboard");
}
//註冊攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
//靜態資源; *.css , *.js
//SpringBoot已經做好了靜態資源對映,我們不再需要單獨exclude
// /**任意目錄,任意檔案,exclude除過這些
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login");
}
};
return adapter;
}
RestfulCRUD:CRUD滿足Rest風格
URI: /資源名稱/資源標識 HTTP請求方式區分對資源CRUD操作
普通CRUD(uri來區分操作) | RestfulCRUD | |
---|---|---|
查詢 | getEmp | emp—GET |
新增 | addEmp?xxx | emp—POST |
修改 | updateEmp?id=xxx&xxx=xx | emp/{id}—PUT |
刪除 | deleteEmp?id=1 | emp/{id}—DELETE |
實驗功能 | 請求URI | 請求方式 |
---|---|---|
查詢所有員工 | emps | GET |
查詢某個員工(來到修改頁面) | emp/1 | GET |
來到新增頁面 | emp | GET |
新增員工 | emp | POST |
來到修改頁面(查出員工進行資訊回顯) | emp/1 | GET |
修改員工 | emp | PUT |
刪除員工 | emp/1 | DELETE |
小問題
th:if優先順序高於th:text
th:if="${not #strings.isEmpty(msg)}" 顯示訊息
重定向
return “redirect:/main.html” 加/表示當前專案下