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下载链接
SpringBoot系列之集成jsp模板引擎的更多相关文章
- springboot系列四、配置模板引擎、配置热部署
一.配置模板引擎 在之前所见到的信息显示发现都是以 Rest 风格进行显示,但是很明显在实际的开发之中,所有数据的显示最终都应该交由页面完成,但是这个页面并不是*.jsp 页面,而是普通的*.html ...
- springboot同时使用thymeleaf和jsp模板
语言:javaEE 框架:springboot+thymeleaf.jsp模板引擎 背景:学习springboot过程中想同时使用thymeleaf和jsp访问(官方不建议) 步骤: 1) 在pom ...
- SpringBoot系列之集成Druid配置数据源监控
SpringBoot系列之集成Druid配置数据源监控 继上一篇博客SpringBoot系列之JDBC数据访问之后,本博客再介绍数据库连接池框架Druid的使用 实验环境准备: Maven Intel ...
- SpringBoot系列之集成Mybatis教程
SpringBoot系列之集成Mybatis教程 环境准备:IDEA + maven 本博客通过例子的方式,介绍Springboot集成Mybatis的两种方法,一种是通过注解实现,一种是通过xml的 ...
- SpringBoot系列之集成logback实现日志打印(篇二)
SpringBoot系列之集成logback实现日志打印(篇二) 基于上篇博客SpringBoot系列之集成logback实现日志打印(篇一)之后,再写一篇博客进行补充 logback是一款开源的日志 ...
- SpringBoot系列之集成Dubbo的方式
SpringBoot系列之集成Dubbo的方式 本博客介绍Springboot框架集成Dubbo实现微服务的3种常用方式,对于Dubbo知识不是很熟悉的,请先学习我上一篇博客:SpringBoot系列 ...
- 九、SpringBoot集成Thymeleaf模板引擎
Thymeleaf咋读!??? 呵呵,是不是一脸懵逼...哥用我的大学四级英文知识告诉你吧:[θaimlif]. 啥玩意?不会音标?...那你就这样叫它吧:“赛母李府”,大部分中国人是听不出破绽的.. ...
- SpringBoot集成Thymeleaf模板引擎
简单介绍 目前在JavaEE领域有几中比较常用的模板引擎,分别是Jsp.Velocity.Freemarker.Thymeleaf,对Freemark语法不是特别熟悉,不过对于前端页面渲染效率来说,j ...
- SpringBoot系列之集成Thymeleaf用法手册
目录 1.模板引擎 2.Thymeleaf简介 2.1).Thymeleaf定义 2.2).适用模板 3.重要知识点 3.1).th:text和th:utext 3.2).标准表达式 3.3).Thy ...
随机推荐
- 【AtCoder - 5659 】>< (思维题)
>< 直接写中文了 Problem Statement 给定的是长度为N-1的字符串S. S中的每个字符都是<或>. 当对所有i(1≤i≤N-1)都满足以下条件时,N个非负整数 ...
- 使用Typescript重构axios(六)——实现基础功能:获取响应数据
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- day 2 下午 骑士 基环树+树形DP
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #inc ...
- Python脚本之——API自动化框架总结
学完了Python脚本接口自动化之后,一直没有对该框架做总结,今天终于试着来做一份总结了. 框架结构如下图: 来说一下每个目录的作用: Configs:该目录下存放的是.conf,.ini文件格式的配 ...
- 深入理解计算机系统 第二章 信息的表示和处理 part1
欣哥划的重点: 第二章比较难,建议至少掌握下面几个知识点: 1. 字节顺序 : 大端和小端 2. 运行 图2-24, 图2-25程序 show-bytes.c 观察结果,看看有什么问题 3. 理解布尔 ...
- 微信小程序(mpvue) wx.openSetting 无法调起设置页面
在开发过程有个需要保存图片/视频到设备相册的业务,so easy~ 巴啦啦撸下来了完整功能, wx.saveVideoToPhotosAlbum 会自动调起用户授权,美滋滋~~ btu.... ...
- Ubuntu清空回收站
ubuntu 回收站的具体位置:$HOME/.local/share/Trash/ 执行如下命令清空回收站: sudo rm -fr $HOME/.local/share/Trash/files/ 如 ...
- java编程思想第四版第三章要点习题
使用"简短的" 和正常的 打印语句来编写一个程序 package net.mindview.util; public class Print { /** * 不带有回车 * @pa ...
- opencv 3 core组件进阶(3 离散傅里叶变换;输入输出XML和YAML文件)
离散傅里叶变换 #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" ...
- c# 发送邮箱,企业邮箱测试成功
今天在项目中需要实现一个发送邮箱的功能,来实现用户邮箱激活功能!!! 之前采用的是个人的邮箱进行测试,一切都是很顺利的,后来换成了公司的企业邮箱,遇到了一点小问题,问题如下: 发送邮件失败,原因:命令 ...