1. 程式人生 > >springboot學習筆記之SpringMVC自動配置原理

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” 加/表示當前專案下