SpringBoot系列之集成jsp模板引擎


SpringBoot系列之集成jsp模板引擎

1、模板引擎簡介

引用百度百科的模板引擎解釋:

模板引擎(這里特指用於Web開發的模板引擎)是為了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用於網站的模板引擎就會生成一個標准的HTML文檔。

在JavaEE領域有幾中比較常用的模板引擎,分別是Jsp、Velocity、Freemarker、Thymeleaf,不過對於前端頁面渲染效率來說,jsp其實還是最快的,Velocity次之。Thymeleaf雖然渲染效率不是很快,但是語法方面是比較輕巧的,Thymeleaf語法比Velocity輕巧,但是渲染效率不如Velocity

2、環境准備

ok,Springboot是一款javaee框架,使用非常簡捷,創建工程也是默認打成jar包的,啟動jar包就可以直接運行嵌入式的Servlet容器,比如Tomcat等等,不過Springboot要集成模板引擎的話,是默認不支持jsp的,但是並不表示不能使用,首先Springboot項目默認是jar方式運行的,而我們之前的jsp項目大部分都是war包方式,jar方式打包的項目默認就沒有webapp等等這些文件,所以我們要創建jsp項目,就可以創建工程時候改成war包形式

ok,進行jsp實驗,環境准備:

  • 版本:
    • Maven3.9+
    • SpringBoot2.2.1
  • IDE:
    • IntelliJ IDEA

創建Springboot Initializer項目,打包方式選擇war方式
在這里插入圖片描述

創建好的項目,默認是沒有webapp文件的,所以我們可以手動加上,或者在idea這樣做:

在這里插入圖片描述
新增web.xml,記得改下默認路徑
在這里插入圖片描述
創建好之后,我們可以看看自動生成的項目有什么特征:

  • 首先是多了一個ServletInitializer類,這個類是干什么的?后面再詳講
    在這里插入圖片描述
  • Pom文件,翻了一下,發現spring-boot-starter-tomcat的作用范圍被改成provided的,這個是什么意思?需要補充一下maven的基礎知識,maven中三種classpath 編譯,測試,運行
    • 1.compile:默認范圍,編譯測試運行都有效
    • 2.provided:在編譯和測試時有效
    • 3.runtime:在測試和運行時有效
    • 4.test:只在測試時有效
    • 5.system:在編譯和測試時有效,與本機系統關聯,可移植性差
      修改scope為provided,也就是在運行時不起效,也就是打成war包時候,就不引入對應的Tomcat jar包,不使用嵌入式的Tomcat容器,使用外部的Tomcat容器
      在這里插入圖片描述

3、外部Servlet容器

Springboot項目創建之后,其實就可以直接創建jsp應用了,然后從其自動生成的配置可以看出我們在創建war包時,是可以使用外部的Tomcat容器的,所以,我們引入一下外部Tomcat
在這里插入圖片描述

在這里插入圖片描述
部署時候,直接使用暴露的war即可,Application context可以寫上也可以不管
在這里插入圖片描述
直接創建一個jsp頁面
在這里插入圖片描述
進行頁面跳轉,寫個Controller類:

@Controller
public class HelloController {

    @RequestMapping(value = {"/success"})
    public String toSuccess(){
        return "success";
    }
}

注意:還要向以前那樣定義一下mvc的一下配置:

spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp

ok,我之前博客SpringBoot源碼學習系列之嵌入式Servlet容器
已經比較詳細地介紹了Springboot嵌入式Servlet容器的知識,所以本博客有必要對比一下嵌入式的Servlet容器和本博客介紹的外部Servlet容器的區別

  • 外部Servlet容器:maven打包是war形式,先啟動Servlet容器,在創建ioc容器
  • 嵌入式Servlet容器:maven打包是jar形式,啟動時候先創建ioc容器,再啟動嵌入式的Servlet容器,比如Tomcat、undertow等等

4、源碼原理簡介

尚硅谷視頻介紹過Servlet的規范,翻下文檔,找到如圖章節,這個章節介紹了創建war包項目時候會自動創建ServletInitializer類,主要介紹共享庫和運行時插件,里面介紹了ServletContainerInitializer,也就是Servlet容器的一個初始化類的使用,啟動時候會通過配置在META-INF/services的文件找對應類,通過@HandlesTypes注解在啟動時候將需要的類引進來

。
全局搜索,在Spring-web項目找到對應配置
在這里插入圖片描述

@HandlesTypes(WebApplicationInitializer.class)//SpringServletContainerInitializer 容器類啟動時候會一起創建WebApplicationInitializer類
public class SpringServletContainerInitializer implements ServletContainerInitializer {

	@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<>();

		if (webAppInitializerClasses != null) {
			for (Class<?> waiClass : webAppInitializerClasses) {
				// Be defensive: Some servlet containers provide us with invalid classes,
				// no matter what @HandlesTypes says...
				//檢驗WebApplicationInitializer不是一個接口、抽象類就進行實例
				if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
						WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
					try {
						initializers.add((WebApplicationInitializer)
								ReflectionUtils.accessibleConstructor(waiClass).newInstance());
					}
					catch (Throwable ex) {
						throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
					}
				}
			}
		}

		if (initializers.isEmpty()) {
			servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
			return;
		}

		servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
		AnnotationAwareOrderComparator.sort(initializers);
		//遍歷獲取到的WebApplicationInitializer 類,調用其對應的onStartup方法
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

}

WebApplicationInitializer 其實就是一個接口類,所以打開其實現類,可以看到SpringBootServletInitializer類
在這里插入圖片描述
SpringBootServletInitializer類implements WebApplicationInitializer接口,所以在Servlet容器啟動時候也會被創建,同時執行onStartup方法,如圖,找關鍵點:

在這里插入圖片描述
createRootApplicationContext方法是創建根據的容器,看看源碼:

protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
		//創建SpringApplication的構建器
		SpringApplicationBuilder builder = createSpringApplicationBuilder();
		builder.main(getClass());//設置main方法
		ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
		if (parent != null) {
			this.logger.info("Root context already created (using as parent).");
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
			//構建器初始化
			builder.initializers(new ParentContextApplicationContextInitializer(parent));
		}
		builder.initializers(new ServletContextApplicationContextInitializer(servletContext));
		builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
		//關鍵點,調用configure方法
		builder = configure(builder);
		builder.listeners(new WebEnvironmentPropertySourceInitializer(servletContext));
		SpringApplication application = builder.build();
		if (application.getAllSources().isEmpty()
				&& MergedAnnotations.from(getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
			application.addPrimarySources(Collections.singleton(getClass()));
		}
		Assert.state(!application.getAllSources().isEmpty(),
				"No SpringApplication sources have been defined. Either override the "
						+ "configure method or add an @Configuration annotation");
		// Ensure error pages are registered
		if (this.registerErrorPageFilter) {
			application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
		}
		//啟動Application類
		return run(application);
	}

從這個源碼找到關鍵點configure方法,繼續跟一下這個方法,基類的方法很簡單,只是返回構造器
在這里插入圖片描述
所以,在idea里ctrl+alt+B打開其實現方法,如圖看到關鍵點,這個不就是自動創建的ServletInitializer類?而且重寫了configure方法,而且將Springboot的Application類傳給構造器類,所以跟到這里就明白了,為什么Servlet容器啟動時候就會觸發Springboot的ioc容器創建
在這里插入圖片描述

代碼例子下載:github下載鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM