zoukankan      html  css  js  c++  java
  • 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下载链接

  • 相关阅读:
    排序算法-总览
    MySQL插入大批量测试数据
    【剑指offer】面试的流程
    并发编程-内置锁
    并发编程-使用线程安全类
    规约先行-(二十一)设计规约
    规约先行-(二十)服务器
    [转]web.xml什么时候被加载进内存的
    DOM和BOM的理解
    代理&反向代理
  • 原文地址:https://www.cnblogs.com/mzq123/p/12006845.html
Copyright © 2011-2022 走看看