上回我们了解了Spring Boot 项目的搭建和程序员入门Hello World 的一个体验,我们也引入了
org.springframework.boot:spring-boot-starter-web依赖,这个依赖就是我们这回要学习的重点基于Web开发。
嵌入式Web容器
说到Web开发,那么不得不说一个重重之中的东西,Web容器。我们回想下J2EE项目,额,已经改名叫Java EE项目了。它的部署是什么来着?把一个Java项目打包成war包,然后放入tomcat的webapps中,启动tomcat那么部署完成,然后就是浏览器访问了。那么,我们Spring Boot项目呢?
上回我们就聊到了fat jar的概念,就是说可执行jar文件,那么什么叫可执行jar文件呢?就是我们常说的java -jar直接启动的一个项目,我们做个简单的案例来说明fat jar。
首先我们创建一个Java世界里面的第一个文件Hello.java
package com.demo;
public class Hello{
public static void main(String[] args){
System.out.println("hello world");
}
}
然后,我们编译javac -d . Hello.java,然后我们再运行java com.demo.Hello,控制台打印出了hello,world的字样,假如说我们要把这段代码发布到生产环境的话(这是不可能的),直接发布文件吗?当然没人会这么干,那么我们怎么办呢?jdk提供了一种命令行打成jar包的形式,我们试试。
我们先创建一个MANIFEST.MF文件,这个文件是引导文件,告诉我们默认执行那个类,源码如下:
Manifest-Version: 1.0
Created-By: 1.8.0_141 (Oracle Corporation)
Main-Class: com.demo.Hello
这个文件需要注意一下三点
1. 第一行之前,行与行之间不能有空行,第一行后面不能有空格
2. 最后一行后面一定要一个空行
3. key值后面一定要一个空格,如Main-Class:后面接了一个空格
我们根据这个引导文件打成jar包指令为jar cvfm hello.jar MANIFEST.MF com ,我们稍微分析下这个指令:
1. c 创建一个jar包
2. v 生成详细的信息并输出到控制台
3. f 指定的jar包文件名
4. m 指定manifest.mf文件
打好jar包后,我们执行javar -jar hello.jar,发现控制台也打印出了hello,world的字样,这就是fat jar了。
好了,说了fat jar后,我们再回到Spring Boot,看看Spring Boot 的fat jar又是什么样子呢?我们先看下引导文件吧。
Manifest-Version: 1.0
Implementation-Title: first-gui-application
Implementation-Version: 0.0.1-SNAPSHOT
Built-By: DELL
Implementation-Vendor-Id: com.zwq
Spring-Boot-Version: 2.1.4.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.zwq.firstguiapplication.FirstGuiApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_141
Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo
ot-starter-parent/first-gui-application
无独有偶,和我们之前的hello-world版有相似之处,都有个Main-Class,这么说来,JarLauncher类就是我们的引导类了,这里先不深入探讨这个问题,我们回到标题,嵌入式容器吧,有点跑题了。
首先我们把项目导入到IDEA中(毕竟用记事本写代码效率还是比较低的),具体步骤不细说了。
说下Spring Boot 是如何嵌入式Tomcat容器的,我们使用maven查看下spring-boot-starter-web的依赖,idea里面有图形化界面可供查看,具体在maven>> dependencies 。我们也可以用命令行的形式查看,这里我们了解下命令行的形式查看依赖吧,图形化界面过于简单就不列出了。
输入命令mvn dependency:tree 我们可以知道项目的所有依赖,不过依赖太多了,我们筛选下我们感兴趣的mvn dependency:tree -Dincludes=org.springframework.* ,执行结果如下所示:
[INFO] --- maven-dependency-plugin:3.1.1:tree (default-cli) @ first-gui-application ---
[INFO] com.zwq:first-gui-application:jar:0.0.1-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.4.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.1.4.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.1.4.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.4.RELEASE:compile
[INFO] | | \- org.springframework.boot:spring-boot-starter-logging:jar:2.1.4.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:2.1.4.RELEASE:compile
[INFO] | \- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.4.RELEASE:compile
[INFO] \- org.springframework.boot:spring-boot-starter-test:jar:2.1.4.RELEASE:test
[INFO] +- org.springframework.boot:spring-boot-test:jar:2.1.4.RELEASE:test
[INFO] \- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.4.RELEASE:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
原来Spring Boot 嵌入式Tomcat容器就是加入了org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.4.RELEASE所致,那么如果我们想使用Undertow或者Jetty容器呢?是不是加入org.springframework.boot:spring-boot-starter-jetty即可?我们修改下pom.xml文件,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
得到的结果就是我们猜想的(由于spring-boot-starter-web 默认使用tomcat,如果要使用jetty那么必须移出掉tomcat依赖)。
集成Thymeleaf
集成之前我们回顾下Spring Boot的一个特点Get started in seconds using Spring Initializr,那么,集成Thymeleaf是不是也能那么快呢?答案是肯定的。
首先,我们添加上Thymeleaf的依赖org.springframework.boot:spring-boot-starter-thymeleaf,看到这个依赖是不是很熟悉,和我没的web依赖几乎一模一样,那么,使用起来,应该也是很方便的,我们在templates目录(图形化界面创建的项目会自带该目录,如果没有刻意在resource目录下自己创建一个)下创建一个thymeleaf的html文件index.html,代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<link th:href="@{bootstrap/css/bootstrap.css}" rel="stylesheet"/>
<link th:href="@{bootstrap/css/bootstrap-theme.css}" rel="stylesheet"/>
</head>
<body>
<div class="container">
<div class="panel panel-primary">
<h3 class="panel-heading">访问model</h3>
<div class="panel-body">
<span th:text="${word}"></span>
<button class="btn btn-danger">提示按钮</button>
</div>
</div>
</div>
<script th:src="@{js/jquery-1.12.4.min.js}" type="text/javascript"></script>
<script th:src="@{bootstrap/js/bootstrap.js}" type="text/javascript"></script>
</body>
</html>
这里面的一些具体语法和使用参考Thymeleaf和Bootstrap官网(相关静态代码放在static目录下),这不是这里关注的。
然后创建一个控制器,IndexController.java
@Controller
public class IndexController {
@GetMapping({"/","/index"})
public String index(Model model){
model.addAttribute("word","spring boot word");
return "index";
}
}
接下来启动项目,直接访问http://localhost:8080会看到如下
这样,我们就算集成成功了。具体为什么这么方便,我们以后再探讨。
注册Servlet、Listener、Filter
使用web项目,常用的Servlet、Listener、Filter在Spring Boot中创建也会更为的方便,接下来,我们实践一下。
- 直接使用
@WebServlet,@WebFilter,@WebListener三大注解的形式创建,需要注意的是要在启动类上加上注解@ServletComponentScan否则不会生效,篇幅有限,具体代码就不列出来了。 - Spring Boot 提供了另一种方式注册,需要借助
ServletRegistrationBean,FilterRegistrationBean,ServletListenerRegistrationBean三个类来达到注册的效果,类似于web.xml中配置。具体代码如下
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean =
new ServletRegistrationBean(new DemoServlet(),"/demoServlet");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new DemoFilter());
filterRegistrationBean.setOrder(1);
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean listenerRegistrationBean(){
ServletListenerRegistrationBean listenerRegistrationBean = new ServletListenerRegistrationBean();
listenerRegistrationBean.setListener(new DemoListener());
return listenerRegistrationBean;
}
尾声
这回,我们初步理解了嵌入式容器,继承Thymeleaf以及Spring Boot 的Servlet,Filter,Listener如何注册,千里之行,基于跬步,我们只有一步一步的学习才能真正的成长起来。