• 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下载链接

  • 相关阅读:
    401. Binary Watch
    46. Permutations
    61. Rotate List
    142. Linked List Cycle II
    86. Partition List
    234. Palindrome Linked List
    19. Remove Nth Node From End of List
    141. Linked List Cycle
    524. Longest Word in Dictionary through Deleting
    android ListView详解
  • 原文地址:https://www.cnblogs.com/mzq123/p/12006845.html
Copyright © 2020-2023  润新知