SpringBoot系列之集成jsp模板引擎

目录

  • 1、模板引擎简介
  • 2、环境准备
  • 3、外部Servlet容器
  • 4、源码原理简介

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方式
SpringBoot系列之集成jsp模板引擎_第1张图片

创建好的项目,默认是没有webapp文件的,所以我们可以手动加上,或者在idea这样做:

SpringBoot系列之集成jsp模板引擎_第2张图片
新增web.xml,记得改下默认路径
SpringBoot系列之集成jsp模板引擎_第3张图片
创建好之后,我们可以看看自动生成的项目有什么特征:

  • 首先是多了一个ServletInitializer类,这个类是干什么的?后面再详讲
    SpringBoot系列之集成jsp模板引擎_第4张图片
  • 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容器
      SpringBoot系列之集成jsp模板引擎_第5张图片

3、外部Servlet容器

Springboot项目创建之后,其实就可以直接创建jsp应用了,然后从其自动生成的配置可以看出我们在创建war包时,是可以使用外部的Tomcat容器的,所以,我们引入一下外部Tomcat
SpringBoot系列之集成jsp模板引擎_第6张图片

SpringBoot系列之集成jsp模板引擎_第7张图片
部署时候,直接使用暴露的war即可,Application context可以写上也可以不管
SpringBoot系列之集成jsp模板引擎_第8张图片
直接创建一个jsp页面
SpringBoot系列之集成jsp模板引擎_第9张图片
进行页面跳转,写个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注解在启动时候将需要的类引进来

SpringBoot系列之集成jsp模板引擎_第10张图片
全局搜索,在Spring-web项目找到对应配置
SpringBoot系列之集成jsp模板引擎_第11张图片

@HandlesTypes(WebApplicationInitializer.class)//SpringServletContainerInitializer 容器类启动时候会一起创建WebApplicationInitializer类
public class SpringServletContainerInitializer implements ServletContainerInitializer {

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

        List 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类
SpringBoot系列之集成jsp模板引擎_第12张图片
SpringBootServletInitializer类implements WebApplicationInitializer接口,所以在Servlet容器启动时候也会被创建,同时执行onStartup方法,如图,找关键点:

SpringBoot系列之集成jsp模板引擎_第13张图片
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方法,继续跟一下这个方法,基类的方法很简单,只是返回构造器
SpringBoot系列之集成jsp模板引擎_第14张图片
所以,在idea里ctrl+alt+B打开其实现方法,如图看到关键点,这个不就是自动创建的ServletInitializer类?而且重写了configure方法,而且将Springboot的Application类传给构造器类,所以跟到这里就明白了,为什么Servlet容器启动时候就会触发Springboot的ioc容器创建
SpringBoot系列之集成jsp模板引擎_第15张图片

代码例子下载:github下载链接

你可能感兴趣的:(SpringBoot系列之集成jsp模板引擎)