Spring Boot是由 Pivotal 团队提供的全新框架,用来简化 Spring 应用的初始搭建以及开发过程。
Spring Boot官方文档:Spring Boot
Spring中文文档:Spring 中文文档
微服务
微服务是一种架构风格:一个应用围绕业务功能拆分为一组小型服务,每个服务运行在自己的进程内,也就是可独立部署和升级。服务之间使用轻量级HTTP交互,去中心化,服务自治。各服务可以使用不同的语言、不同的存储技术。
发展对比
流行 | Bean | 轻重 |
J2EE时代 | 企业级JavaBean (Enterprise JavaBean,EJB) | 重量级 |
Spring时代 | 简单Java 对象(Plain Old Java Object,POJO) | 代码轻量级,配置重量级 Spring 2.5 引入了基于注解的组件扫描 Spring 3.0 引入了基于 Java 的配置 Spring 4.x 可以完全脱离xml |
Spring Boot时代 | 轻量级 无需 XML 配置,同时可以修改默认值。 |
Spring Boot特性
核心思想:约定优于配置(Convention Over Configuration,COC)
特性 | 含义 | 阐释 |
Auto-configuration 自动配置 | 如自动扫描包、自动配置Bean | 涉及Java持久化API(Java Persistence API,JPA)、Thymeleaf模板、安全和Spring MVC |
Starters 起步依赖 | 简化依赖配置,按功能聚合常用依赖做成一系列组合依赖(starters),引入一个starter坐标就引入了相关依赖。 | |
命令行界面 | 可选特性。借此在命令行里就能简单快速地用Groovy进行开发,无需传统的项目构建。 | CLI能检测到你使用了哪些类,它知道要向Classpath中添加哪些起步依赖才能让它运转起来。一旦那些依赖出现在Classpath中,一系列自动配置就会接踵而来,确保启用DispatcherServlet和Spring MVC,这样控制器就能响应HTTP请求了。 |
Actuator 内部监控 | 让你能够检视运行中的Spring Boot应用程序的内部情况。 Actuator通过Web端点和shell界面向外界提供信息。如果要借助shell界面,你可以打开SSH(Secure Shell),登入运行中的应用程序,发送指令查看它的情况。 | 可以查看如: 上下文里配置的Bean; 自动配置做的决策; 环境变量、系统属性、配置属性和命令行参数; 线程的当前状态; 最近处理过的HTTP请求的追踪情况; 各种和内存用量、垃圾回收、Web请求以及数据源用量相关的指标 |
内嵌WEB服务器 | 内嵌Tomcat服务器,原理是将Tomcat服务器作为Bean交给Spring容器管理运行。 |
-
- Spring Initializr创建Spring Boot项目
通过Web界面初始化Spring Boot项目并导入eclipse
1)浏览器打开https://start.spring.io,在页面中输入所创建的项目的相关参数,根据需要勾选所需的依赖,点击按钮即可下载项目。
打包方式为war,其他参数默认时下载的zip包中主要的目录及文件: | 用途说明: |
│ pom.xml ├─src/main/java │ └─com.example.demo │ │ DemoApplication.java │ │ ServletInitializer.java ├─src/main/resources │ │ application.properties │ ├─static │ └─templates └─src/test/java └─com.example.demo │ DemoApplicationTests.java | pom.xml/build.gradle:Maven/Gradle构建说明文件。q XxxApplication.java:名称由由输入的artifact参数决定,是Spring Boot的配置兼启动引导类。带有 main()方法用于启动整个项目。 ApplicationTests.java:一个空的JUnit测试类,它加载了一个使用Spring Boot自动配置功能的Spring应用程序上下文。 application.properties:Spring Boot的配置文件,非必需。 DemoApplicationTests.java:一个基本的集成测试类。 static目录:放置的是Web应用程序的静态内容。 templates目录:放置的是用于呈现模型数据的模板。 com.example.demo根包:名称由输入的group和artifact参数决定,后续创建的各个组件类(如控制器)都必须放在该包或其子包下,因为SpringBoot默认配置的组件扫描就是扫这个包! |
2)如果上一步指定的构建类型是maven,就将下载的项目解压到eclipse的workspace中,并通过Eclipse的Import > Existing Maven Projects方式导入项目。
3)导入后,项目开始自动更新,如果没有开始自动更新,就对项目点右键,选择Maven > Update Project,在弹出的对话框中勾选Force Update!
注意1:如果使用的是Mars(4.5)版本的Eclipse,在pom.xml文件中可能会提示Maven相关的错误,可以无视该错误提示,并不影响程序运行!如果需要解决错误,更换使用Oxygen(4.7)或以上版本的Eclipse即可!
注意2:Spring Boot项目内置Tomcat,启动项目时,就会启动内置的Tomcat,并将整个项目部署到该Tomcat中!如果Tomcat所需的端口被占用,会导致启动失败!
除了Spring官方的Initializr,还可以使用阿里云的Initializr(有更多的依赖选择):https://start.aliyun.com/
通过Spring Tool Suite初始化Spring Boot项目
Spring Tool Suite是Eclipse IDE的一个发行版,增加了诸多能辅助Spring开发的特性,从3.4.0版本开始集成了Spring Initializr。
Spring Tool Suite可以从Spring | Tools下载。
也可以用Eclipse安装Spring Tool Suite插件来开发Spring Boot项目,插件安装方法:Help > Eclipse Macketplace > Popular > 找到Spring Tool Suite插件进行安装。
1)File > New > Spring Starter Project,在弹出的对话框中输入所创建的项目的相关参数,点下一步。
2)根据需要选择所需的版本和依赖,点下一步。
3)Site Info:将要用来访问Initializr的URL,通常默认即可(也可使用阿里云的Initializr(有更多的依赖选择),地址见上面)。如果要部署自己的Initializr服务器(从https://github.com/spring-io/initializr复制代码即可),则在Site Info中设置自己的Initializr基础URL。
4)点Finish开始生成和导入项目,该过程必须联网,因为该向导其实是把项目生成的工作委托给http://start.spring.io上的Spring Initializr来做的。
通过IntelliJ IDEA初始化Spring Boot项目
IntelliJ IDEA 14.1已经支持Spring Boot了(自带Spring Tool Suite插件)。
IntelliJ IDEA商业IDE下载地址:Download IntelliJ IDEA – The Leading Java and Kotlin IDE
- File > New > Project,在弹出的对话框中,左侧选中Spring Initializr,然后右侧选择Project SDK和Initializr Service URL:
Project SDK下拉框中如果没有要的JDK,点右边New...->JDK选择JDK位置。
Initializr Service URL一般默认即可(也可使用阿里云的Initializr(有更多的依赖选择),地址见上面),除非使用自己的Initializr。点下一步。
- 设置好项目元数据后,点下一步。
2)根据需要选择所需的依赖,点下一步。
3)输入项目名称、项目位置等信息,然后点Finish开始创建项目,该过程同样需要联网。
-
- Spring Boot CLI创建Spring Boot项目
安装Spring Boot CLI
【Windows环境】手工安装:下载、解压并将bin目录添加到系统路径:
1)打开下载地址:JFrog
2)选一个版本文件夹进入,然后找到bin.zip结尾的文件,下载之。
3)解压下载好后的压缩文件到合适的目录,将子目录bin的路径添加到系统路径(环境变量Path)里。(要用到其中的Spring.bat脚本)
4)查看版本号以验证安装:CMD运行命令spring --version
【Unix环境】手工安装:下载、解压并将bin目录添加到系统路径:
1)下载、解压:
# wget https://repo.spring.io/release/org/springframework/boot/spring-boot-cli/2.1.6.RELEASE/spring-boot-cli-2.1.6.RELEASE-bin.tar.gz
# tar -zxvf spring-boot-cli-2.1.6.RELEASE-bin.tar.gz -C /usr/local
# rm spring-boot-cli-2.1.6.RELEASE-bin.tar.gz
2)将Spring Boot Cli的bin目录路径添加到系统路径(环境变量Path)里(要用到其中的spring脚本):
# vi /etc/profile
末尾加入一行:export PATH=$PATH:/usr/local/spring-2.1.6.RELEASE/bin
使环境变量生效:
# source /etc/profile
注:可以建立一个指向解压目录的符号链接,然后把这个符号链接添加到系统路径,而不是实际的目录。这样后续升级Spring Boot新版本,或是转换版本,都会很方便,只要重建一下符号链接,指向新版本就好了。
3)查看版本号以验证安装:
# spring --version
【Unix环境】使用Software Development Kit Manager进行安装
使用SDKMAN来管理Spring Boot CLI有一个好处,你可以便捷地在Spring Boot的不同版本之间切换。这样你可以在正式发布前试用快照版本(snapshot)、里程碑版本(milestone)和尚未正式发布的候选版本(release candidate),试用后再切回稳定版本进行其他工作。
步骤:
1)从http://sdkman.io获取并安装软件开发工具管理包(Software Development Kit Manager,SDKMAN,曾用简称GVM):
# curl -s get.sdkman.io | bash
2)复制提示的命令并执行使SDKMAN生效:
# source "/root/.sdkman/bin/sdkman-init.sh"
3)使用SDKMAN安装Spring Boot CLI最新版本:
# sdk install springboot
安装好的Spring Boot CLI文件目录在/root/.sdkman/candidates/springboot/之下
4)查看版本号以验证安装:
# spring –version
其他命令:
查看可用版本(包括已安装和正在使用的):
# sdk list springboot
安装指定版本(安装完毕将自动设为默认版本):
# sdk install springboot 2.1.8.RELEASE
切换到另一个版本(若未安装将提示是否安装,安装后将自动设为当前shell的默认版本):
# sdk use springboot 2.1.6.RELEASE
指定某版本为默认版本:
# sdk default springboot 2.1.8.RELEASE
【OS X环境】手工安装:参考Unix环境的安装步骤。
【OS X环境】使用Software Development Kit Manager进行安装:参考Unix环境的安装步骤。
【OS X环境】使用Homebrew进行安装:见《Spring Boot实战》第一版1.2.1.3
【OS X环境】使用MacPorts进行安装:见《Spring Boot实战》第一版1.2.1.4
如果Spring Boot CLI是通过Homebrew安装的,那么命令行补全已经安装完毕。
如果Spring Boot CLI是通过MacPorts安装的,那么不必考虑命令行补全。
如果Spring Boot CLI是通过手工或SDKMAN安装的,那么就需要通过执行脚本或者手工来安装命令行补全。
通过执行脚本安装
以SDKMAN安装的Spring Boot CLI和shell为BASH为例,当前shell有效:
# . ~/.sdkman/candidates/springboot/current/shell-completion/bash/spring
(装完不能用,不知道为什么)
开启了命令行补全之后,在命令行里键入 spring 命令,然后按Tab键就能看到下一步该输什么的提示。选中一个命令后,键入 -- (两个连字符)后再按Tab,就会显示出该命令的选项列表。
通过手工安装:
# spring shell
键入上述命令后,Spring Boot CLI shell会新开一个特别针对Spring Boot的shell,在里面可以执行各种CLI命令,Tab键也能有命令补全。
使用Spring Boot CLI初始化Spring Boot项目
Spring Boot CLI的init命令用来创建Spring Boot项目,最简单的用法是创建最基本的Spring Boot项目:
$ spring init
在和Initializr的Web应用程序通信后, init 命令会下载一个demo.zip文件。里面包含一个Maven的pom.xml构建描述文件。Maven的构建说明只包含最基本的内容,即只有Spring Boot基线和测试起步依赖。
如果要指定起步依赖,使用--dependencies 或 -d参数(注意:-d和依赖之间不能有空格,否则参数含义就变成了指定下载的文件名):
$ spring init -dweb,jpa,security
如果要指定构建类型为Gradle,使用 --build 参数:
$ spring init -dweb,jpa,security --build gradle
如果要指定打包类型为WAR,使用 --packaging 或者 -p 参数:
$ spring init -dweb,jpa,security --build gradle -p war
如果要解压下载的ZIP文件,可以指定一个用于解压的目录如myapp:
$ spring init -dweb,jpa,security --build gradle -p war myapp
如果要把生成的项目解压到当前目录,使用 --extract 或者 -x 参数:
$ spring init -dweb,jpa,security --build gradle -p jar -x
要查看init有哪些参数,使用help 命令:
$ spring help init
要查看那些参数都有哪些可选项,使用 init 命令的 --list 或 -l 参数:
$ spring init -l
init 命令还有不少其他参数,如基于Groovy构建项目的参数、指定用Java版本编译的参数,选择构建依赖的Spring Boot版本的参数。
init命令不能完全支持初始化Spring Boot项目的所有参数,如不能指定根包的名字,它默认为demo。
Spring Boot项目构建过程解析
使用Gradle构建Spring Boot项目时,Initializr创建的build.gradle文件中使用了Spring Boot的Gradle插件:
plugins { id 'org.springframework.boot' version '2.1.8.RELEASE' id 'io.spring.dependency-management' version '1.0.8.RELEASE' id 'java' } |
使用Maven构建Spring Boot项目时,Initializr创建的pom.xml文件中中使用了Spring Boot的Maven插件:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> |
构建插件的主要功能是把项目打包成一个可执行的超级JAR(uber-JAR),包括把应用程序的所有依赖打入JAR文件内,并为JAR添加一个描述文件,其中的内容能让你用 java -jar 来运行应用程序。
-
- Maven创建Spring Boot项目
创建Maven工程
工程名如springboot_demo,打包方式选jar
添加起步依赖,变更JDK版本
在pom.xml中添加父工程依赖和web启动器依赖,以及变更JDK版本:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tongwx.demo</groupId> <artifactId>springboot-demo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project> |
创建启动类
package cn.tongwx.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } |
Spring MVC实现Hello World输出
写Controller类实现json数据的输出:
package cn.tongwx.demo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @RequestMapping("/info") public String info(){ return "HelloWorld"; } } |
启动项目
启动项目有三种方法:
- 使用Maven命令启动:在pom.xml所在目录中运行:mvn spring-boot:run
- 将maven项目导入IDE后直接运行引导类的main方法
- 打成jar包启动
打jar包前需先在pom.xml中添加如下插件:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> |
手动打jar包:在pom.xml所在目录中运行:mvn package
eclipse中打jar包:右击项目,选择Run As - Maven clean,再右击项目,选择Run As - Maven install
成功后会在项目的target目录下生成jar包,在该目录下运行:java -jar jar包文件名(注意:cmd窗口属性中去掉“快速编辑模式”)
启动项目后,在浏览器地址栏输入 http://localhost:8080/info 即可看到运行结果
-
- Gradle创建Spring Boot项目
时间 2015-01-06 00:00:00 JavaChen's Blog
原文 http://blog.javachen.com/2015/01/06/build-app-with-spring-boot-and-gradle/
开发环境
- 操作系统: mac
- JDK:1.7.0_60
- Gradle:2.2.1
创建项目
参考使用Gradle构建项目 创建一个 helloworld 项目,执行的命令如下:
$ mkdir helloworld && cd helloworld
$ gradle init
helloworld 目录结构如下:
➜ helloworld tree
.
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
2 directories, 6 files
然后修改build.gradle文件:
buildscript {
repositories {
maven { url "https://repo.spring.io/libs-release" }
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.10.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'helloworld'
version = '0.1.0'
}
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spring.io/libs-release" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("junit:junit")
}
task wrapper(type: Wrapper) {
gradleVersion = '2.2.1'
}
创建一个实体类
新建一个符合Maven规范的目录结构, src/main/java/hello:
$ mkdir -p src/main/java/hello
创建一个实体类 src/main/java/hello/Greeting.java:
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
创建控制类
创建一个标准的控制类 src/main/java/hello/GreetingController.java:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public @ResponseBody Greeting greeting(
@RequestParam(value="name", required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
Greeting 对象会被转换成 JSON 字符串,这得益于 Spring 的 HTTP 消息转换支持,你不必人工处理。由于 Jackson2 在 classpath 里,Spring的 MappingJackson2HttpMessageConverter 会自动完成这一工作。
上面的代码还可以这样写:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", required=false, defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
这段代码使用 Spring4 新的注解: @RestController ,表明该类的每个方法返回对象而不是视图。它实际就是 @Controller 和 @ResponseBody 混合使用的简写方法。
创建一个可执行的类
尽管你可以将这个服务打包成传统的 WAR 文件部署到应用服务器,但下面将会创建一个独立的应用,使用 main 方法可以将所有东西打包到一个可执行的jar文件。并且,你将使用 Sping 对内嵌 Tomcat servlet 容器的支持,作为 HTPP 运行时环境,没必要部署成一个 tomcat 外部实例。
创建一个包含 main 方法的类 src/main/java/hello/Application.java:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
main 方法使用了 SpringApplication 工具类。这将告诉Spring去读取 Application 的元信息,并在Spring的应用上下文作为一个组件被管理。
@Configuration 注解告诉 spring 该类定义了 application context 的 bean 的一些配置。
@ComponentScan 注解告诉 Spring 遍历带有 @Component 注解的类。这将保证 Spring 能找到并注册 GreetingController,因为它被 @RestController 标记,这也是 @Component 的一种。
@EnableAutoConfiguration 注解会基于你的类加载路径的内容切换合理的默认行为。比如,因为应用要依赖内嵌版本的 tomcat,所以一个tomcat服务器会被启动并代替你进行合理的配置。再比如,因为应用要依赖 Spring 的 MVC 框架,一个 Spring MVC 的 DispatcherServlet 将被配置并注册,并且不再需要 web.xml 文件。
你还可以添加 @EnableWebMvc 注解配置 Spring Mvc。
运行项目
可以在项目根路径直接运行下面命令:
./gradlew bootRun
也可以先 build 生成一个 jar 文件,然后执行该 jar 文件:
打包:./gradlew build
运行jar包: java -jar helloworld-0.1.0.jar
修改端口号:java -jar demo.jar --server.port=9000
启动过程中你回看到如下内容:
Let's inspect the beans provided by Spring Boot:
application
beanNameHandlerMapping
defaultServletHandlerMapping
dispatcherServlet
embeddedServletContainerCustomizerBeanPostProcessor
handlerExceptionResolver
helloController
httpRequestHandlerAdapter
messageSource
mvcContentNegotiationManager
mvcConversionService
mvcValidator
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$DispatcherServletConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration
org.springframework.boot.context.embedded.properties.ServerProperties
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
propertySourcesBinder
propertySourcesPlaceholderConfigurer
requestMappingHandlerAdapter
requestMappingHandlerMapping
resourceHandlerMapping
simpleControllerHandlerAdapter
tomcatEmbeddedServletContainerFactory
viewControllerHandlerMapping
测试
打开浏览器访问 http://localhost:8080/greeting ,可以看到页面输出下面内容:
{"id":1,"content":"Hello, World!"}
添加一个参数,访问 http://localhost:8080/greeting?name=User ,这时候页面输出下面内容:
{"id":2,"content":"Hello, User!"}
创建静态页面
创建 public/hello.js:
$(document).ready(function() {
$.ajax({
url: "http://localhost:8080/greeting"
}).then(function(data, status, jqxhr) {
$('.greeting-id').append(data.id);
$('.greeting-content').append(data.content);
console.log(jqxhr);
});
});
创建一个页面 public/index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello jQuery</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="hello.js"></script>
</head>
<body>
<div>
<p class="greeting-id">The ID is </p>
<p class="greeting-content">The content is </p>
</div>
<h4>Response headers:</h4>
<div class="response-headers">
</div>
</body>
</html>
现在可以使用 Spring Boot CLI 启动一个嵌入式的 tomcat 服务来访问静态页面,你需要创建 app.groovy 告诉 Spring Boot 你需要运行 tomcat:
@Controller class JsApp { }
Spring Boot CLI 在 mac 系统上通过 brew 安装的方法如下:
brew tap pivotal/tap
brew install springboot
接下来可以指定端口运行一个 tomcat:
spring run app.groovy -- --server.port=9000
starter:聚合依赖简化依赖配置
起步依赖starter是特殊的依赖,利用传递依赖解析,把常用库聚合在一起,组成了几个为特定功能而定制的组合依赖。
如果想要了解传递依赖的版本,运行下面对应的命令:
Gradle插件提供的命令:$ gradle dependencies
Maven插件提供的命令:$ mvn dependency:tree
Spring官方提供的起步依赖列表:Developing with Spring Boot
Spring官方提供的起步依赖以spring-boot-starter开头,第三方提供的起步依赖以spring-boot-starter结尾。
当新建Spring Boot项目时,项目会默认引入spring-boot-starter-test起步依赖并生成XxxApplicationTests测试类。
当新建Spring Boot项目未手动引入任何starter时,项目会默认引入spring-boot-starter起步依赖。
parent:版本管理减少依赖冲突
spring-boot-starter-parent是所有SpringBoot项目的父工程,该父工程又继承自spring-boot-dependencies工程
spring-boot-dependencies工程中定义了许多传递依赖的版本(<properties>),对这些传递依赖进行管理(<dependencyManagement>)
因此SpringBoot的版本(即父工程spring-boot-starter-parent的版本)决定起步依赖的版本,起步依赖的版本决定它们引入的传递依赖的版本。
我们在SpringBoot项目中只需指定SpringBoot版本即可,除非祖父工程中未将依赖纳入版本管理,我们才需要手动添加版本号(要小心版本冲突)。
如果我们需要自定义依赖的版本号:
1、查看祖父工程spring-boot-dependencies里面定义的当前依赖的版本用的key。
2、在当前项目里面重写配置,例如:
<properties> <mysql.version>5.1.43</mysql.version> </properties> |
如果我们需要排除某依赖:
例如可以把Web起步依赖中内嵌的Tomcat换成Jetty:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--Web起步依赖中排除Tomcat起步依赖-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加Jetty起步依赖,版本由SpringBoot版本决定-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
-
- (引导类)
package cn.itcast.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } |
引导类是spring boot应用程序的入口点,包含@SpringBootApplication注解和main方法。
@SpringBootApplication注解
@SpringBootApplication是以下三个注解的总和:
@Configuration:用于定义一个配置类
@EnableAutoConfiguration:Spring Boot会自动根据你jar包的依赖来自动配置项目。
@ComponentScan:组件扫描。默认扫描当前类所在包及其子包,因此controller、service、dao等包一般放在启动类所在包下。可使用@SpringBootApplication的scanBasePackage属性来自定义要扫描的基本包。
SpringApplication
SpringApplication.run(Application.class, args)方法返回的ConfigurableApplicationContext容器实例可用来获取bena。
我们直接执行这个引导类的main方法,会发现控制台出现的Spring的logo。
核心配置文件
核心配置文件优先级
核心配置文件位于src\main\resources\目录下,有application.properties或application.yml/application.yaml两种格式。
优先级:properties > yml > yaml,如存在多种格式的配置文件,相同配置以优先级高的为准。
配置源顺序
Spring Boot可将配置外部化,以便在不同的环境中使用不同的配置。
Spring Boot 指定了配置源顺序(PropertySource Order),后面的配置源可以覆盖前面定义的值:
默认属性(通过 SpringApplication.setDefaultProperties 指定)。
@Configuration 类上的 @PropertySource 注解。注意:这样的属性源直到application context被刷新时才会被添加到环境中。这对于配置某些属性来说已经太晚了,比如 logging.* 和 spring.main.* ,它们在刷新开始前就已经被读取了。
配置数据(如 application.properties 文件)。
RandomValuePropertySource,它只有 random.* 属性。
操作系统环境变量
Java System properties (System.getProperties()).
java:comp/env 中的 JNDI 属性。
ServletContext init parameters.
ServletConfig init parameters.
来自 SPRING_APPLICATION_JSON 的属性(嵌入环境变量或系统属性中的内联JSON)。
命令行参数。(参数将传给main方法,进而传给SpringApplication.run方法;idea可将命令行参数写在Run/Debug Configurations中对应应用的Program arguments中)
你在测试中的 properties 属性。在 @SpringBootTest 和测试注解中可用,用于测试你的应用程序的一个特定片断。
你测试中的@TestPropertySource注解.
当devtools处于活动状态时,$HOME/.config/spring-boot 目录下的Devtools全局设置属性。
配置数据文件按以下顺序考虑。
在你的jar中打包的Application properties(application.properties 和 YAML)。
在你的jar中打包的 特定的 Profile application properties(application-{profile}.properties 和 YAML)。
在你打包的jar之外的Application properties(application.properties和YAML)。
在你打包的jar之外的特定的 Profile application properties( application-{profile}.properties 和YAML)。
常用配置
可配置的属性列表见 Common Application Properties
#设置应用端口号
server.port=80
#设置应用上下文根
server.servlet.context-path=/demo
#设置日志级别
logging.level.root=debug
logging.level.包的完全限定名=debug
书写配置代码补全提示失效解决方案:
- 如果没有引入配置所属相关依赖,IDE是无法提示的,先添加相关依赖再书写配置
- 如果idea中配置文件无绿叶标识,说明idea未将该文件识别为配置文件。解决方法:File-》Project Structure...-》左栏点Facets-》中栏点模块-》右栏点绿叶按钮-》添加未被识别的配置文件
配置文件中的数据引用:
baseDir=/usr/local/fire |
转义字符处理
在YAML中:
msg: 'hello \t springboot' #加单引号或不加引号将忽略转义字符
读取结果:
hello \t springboot
msg: "hello \n springboot" # 加双引号将识别转义字符
读取结果:
hello springboot
在properties中无法处理,都会识别转义字符
多环境
可以为不同环境(开发、测试、准生产、生产)准备不同的核心配置文件,如(黄色标部分名称自定义):
application-dev.properties、application-test.properties、application-ready.properties、application-product.properties
然后在主核心配置文件中设置使某个分核心配置文件生效:spring.profiles.active=dev
读取配置值
三种方式比较:
三种方式 | 可读取类型 |
@Value注解 | 基本类型、string、array、list、map |
Environment接口 | 基本类型、string、array、list、对象的某个基本类型或String值 |
@ConfigurationProperties注解 | 对象 |
假设在核心配置文件中有如下配置:school.name=mySchool
方式一:使用@Value("${配置项key}")注解将配置项值注入到组件类的字段中:
@Value("${school.name:}")//默认值是"" @Test void testValue(){ } |
方式二:使用@Autowired注解自动装配配置数据到Environment接口中,使用该接口的getProperty("配置项key")方法读取配置项值:
@Autowired } |
方式三:使用@ConfigurationProperties("配置项key相同的前缀")注解将有相同前缀的配置项映射为对象,再将对象注册为Bean使用:
| 2)将该类bean注入其他组件类中使用: |
@Data } | @Autowired System.out.println(schoolConfigProperties.getName(); |
激活@ConfigurationProperties的几种方式:
增加注解 @ConfigurationPropertiesScan
增加注解 @EnableConfigurationProperties(value = {目标类.class})
在目标类上添加@Component注解进行实例化
在 @Configuration 注解的类内手动创建@Bean
获取中文配置值乱码解决方案(不建议使用中文):
idea中:Settings...-》Editor-》File Encodings-》Properties Files-》Transparent native-to-ascii conversion打钩
各种类型的写法和读取
yml写法 | properties写法 |
# 定义string或array或list hobbies: #eat, play, sleep | # 定义string或array或list |
复杂对象映射的Bean | 读取各种类型 |
package com.tongwx.demo.bean; private List<String> hobbies; | package com.tongwx.demo; |
在pom.xml中添加如下配置。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> |
Spring Boot应用程序的启动流程:
创建上下文:创建一个Spring应用程序上下文,同时扫描当前应用程序所在的包及其子包以找到所有被@Component注解的类
实例化bean:根据@Component注解找到的所有类会被实例化,并将它们注册到Spring应用程序上下文中
自动装配IoC:根据依赖关系将bean连接起来
配置加载:包括从application.properties或application.yml文件中的配置和@ConfigurationProperties注解的配置
自动配置starter:扫描并加载所有的自动配置类,这些类会根据应用程序中已有的类和配置信息来自动配置应用程序
启动Web服务器:启动内嵌或外部的Web服务器,比如Tomcat或Jetty等,用于处理HTTP请求。
配置Bean
示例:配置连接池的Bean
1)引入Druid连接池依赖 | 2)创建jdbc.properties文件,编写jdbc属性 | |||
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> | jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/leyou jdbc.username=root jdbc.password=123 | |||
3)创建配置类来配置Bean(通过简单类型给Bean注入属性值) | 又)创建配置类来配置Bean(通过复杂类型给Bean注入属性值) | |||
@Configuration:声明该类为配置类 @PropertySource:指定属性文件路径,如果是从核心配置文件中取值,可省略该注解。 @Value:为属性注入值 @Bean:将该方法声明为一个注册Bean的方法,Spring会自动调用该方法,将方法的返回值加入Spring容器中。 配置好Bean后就可以在其他组件中注入DataSource这个Bean了。 左例还可这样写: |
@ConfigurationProperties:声明该类为属性读取类。 prefix="jdbc":读取属性文件中,前缀为jdbc的值。在类上定义的各个属性,名称必须与属性文件中键的jdbc.后面部分一致 需要注意的是,这里我们并没有指定属性文件的地址,所以我们需要把jdbc.properties的内容写到核心配置文件中。 @EnableConfigurationProperties(JdbcProperties.class):声明要使用JdbcProperties这个类的对象。 | |||
又)更优雅的创建 | ||||
@Configuration public class JdbcConfig {
@Bean // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过dataSource的set方法注入到dataSource中 @ConfigurationProperties(prefix = "jdbc") public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); return dataSource; } } |
-
- Junit
当新建Spring Boot项目时,项目会默认引入spring-boot-starter-test起步依赖并生成XxxApplicationTests测试类。
整合Junit4的Spring Boot单元测试示例 | 整合Junit5的Spring Boot单元测试示例 | |
Maven依赖 | 在Spring Initializr生成的Spring Boot 2.x项目中默认排除了运行Junit4的老式引擎junit-vintage-engine(使用运行Junit5的新式引擎junit-jupiter-engine),如果要使用Junit4,可删除exclusion项junit-vintage-engine | |
<dependency> | <dependency> | |
测试类示例 | package com.example.demo.controller; | package com.example.demo.controller; |
如果项目有多个启动类,用@SpringBootTest的属性classes指定要运行哪个启动类,如:@SpringBootTest(classes = DemoApplication.class) 如果测试类不在启动类所在包或子包下,就需要指定启动类,如:@SpringBootTest(classes = DemoApplication.class)或@ContextConfiguration(classes = DemoApplication.class) |
-
- 远程调用
发送HTTP请求的工具有URLConnection、HttpClient、OkHttp
// 传统的方式,直接显示写死IP是不好的! //private static final String REST_URL_PREFIX = "http://localhost:8001"; // 服务实例名 private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT"; /** * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap, * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。 */ @Autowired private RestTemplate restTemplate; @RequestMapping(value = "/consumer/dept/add") public boolean add(Dept dept) { return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class); } |
通过实现WebMvcConfigurer并添加@Configuration注解来实现
首先我们定义一个拦截器:
package com.leyou.interceptor; public class LoginInterceptor implements HandlerInterceptor { private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { logger.info("preHandle method is now running!"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { logger.info("postHandle method is now running!"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { logger.info("afterCompletion method is now running!"); } } |
然后,我们定义配置类,注册拦截器:
package com.leyou.config; @Configuration public class MvcConfig implements WebMvcConfigurer{ /** * 通过@Bean注解,将我们定义的拦截器注册到Spring容器 */ @Bean public LoginInterceptor loginInterceptor(){ return new LoginInterceptor(); } /** * 重写接口中的addInterceptors方法,添加自定义拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径 registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**"); } } |
-
- JDBC
添加JDBC启动器和数据库驱动如mysql:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> |
JDBC启动器自动引入了HikariCP连接池。如果就用这个连接池,只需指定连接池参数即可:
# 连接四大参数 spring.datasource.url=jdbc:mysql://localhost:3306/heima spring.datasource.username=root spring.datasource.password=123 # 可省略,SpringBoot自动推断 spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.hikari.idle-timeout=60000 spring.datasource.hikari.maximum-pool-size=30 spring.datasource.hikari.minimum-idle=10 |
如果要用Druid连接池,添加Druid官方提供的启动器:
<!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> |
Druid连接池参数:
#初始化连接数 spring.datasource.druid.initial-size=1 #最小空闲连接 spring.datasource.druid.min-idle=1 #最大活动连接 spring.datasource.druid.max-active=20 #获取连接时测试是否可用 spring.datasource.druid.test-on-borrow=true #监控页面启动 spring.datasource.druid.stat-view-servlet.allow=true |
-
- Druid
导入Druid对应的starter
<!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> |
修改数据源配置:
方式一:
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8
spring.datasource.druid.username=root
spring.datasource.druid.password=root
方式二:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
注:Spring Boot2.x默认集成了hikari连接池(spring.datasource.type=com.zaxxer.hikari.HikariDataSource)。
-
- mybatis
选择MyBatis Framework(Mybatis提供的启动器)和MySQL Driver,坐标如下:
<!--mybatis --> |
配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # mybatis 别名扫描 |
entity和dao
注:如果不想给每一个Mapper接口添加@Mapper注解,可在启动类添加Mapper接口扫描注解配置:
@MapperScan(basePackages = {"com.tongwx.demo.dao"} )
package com.tongwx.demo.entity; | package com.tongwx.demo.dao; |
测试
package com.tongwx.demo;
import com.tongwx.demo.dao.UserDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Autowired
UserDao userDao;
@Test
void testUserDao() {
System.out.println(userDao.findById(1L));
}
}
-
- MyBatis-Plus
依赖
Spring Boot官方未提供MyBatis-Plus的starter,需要手工去仓库查找添加如下(不需要MyBatis的依赖):
<!--mybatis-plus--> |
配置
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver |
分页拦截器
package com.tongwx.demo.config; |
entity和dao
注:如果不想给每一个Mapper接口添加@Mapper注解,可在启动类添加Mapper接口扫描注解配置:
@MapperScan(basePackages = {"com.tongwx.demo.dao"} )
package com.tongwx.demo.entity; | package com.tongwx.demo.dao; |
测试
package com.tongwx.demo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tongwx.demo.dao.UserDao;
import com.tongwx.demo.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
@SpringBootTest
class UserDaoTests {
@Autowired
UserDao userDao;
/**
* 测试简单增删改查
*/
@Test
void testSimpleCrud() {
int insertedRows = userDao.insert(new User(null, "张三", "21", new Date()));
User user = userDao.selectById(35L);
user.setAge("22");
int updatedRows = userDao.updateById(user);
List<User> users = userDao.selectList(null);
userDao.deleteById(1);
}
/**
* 测试条件查询
*/
@Test
void testWrapper(){
/*
* 推荐
*/
String name = "张";
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//第一个参数判断需不需要增加本条件
lambdaQueryWrapper.like(StringUtils.hasLength(name), User::getName, name);
List<User> users1 = userDao.selectList(lambdaQueryWrapper);
/*
* 不推荐
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name","李");
List<User> users2 = userDao.selectList(queryWrapper);
}
/**
* 测试分页(&条件)查询
*/
@Test
void testPage() {
//第几页、每页几条
IPage<User> page = new Page<>(2,5);
//第二参可传入查询条件(Wrapper<T>)
userDao.selectPage(page, null);
System.out.println(page.getPages());
System.out.println(page.getCurrent());
System.out.println(page.getRecords());
System.out.println(page.getSize());
System.out.println(page.getTotal());
}
}
业务层简化开发(不推荐?)
定义一接口继承 IService<T> 接口
定义一实现类继承 ServiceImpl<M, T> 类,并实现上一步定义的接口
可在通用接口基础上做功能追加,注意尽量不要覆盖 IService<T> 接口中定义的原始API,避免原始通用功能丢失
package com.tongwx.demo.service; |
package com.tongwx.demo.service.impl; |
package com.tongwx.demo; |
-
- 通用Mapper
<!-- 通用mapper --> |
@Mapper public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User>{ } |
-
- Spring Data Jpa
打包运行几点说明:
- 点击Maven Projects窗口上的闪电图标,可在package时跳过test(test中可能会执行一些测试用例导致数据库变动)。
- 命令行运行jar需依赖Maven插件spring-boot-maven-plugin,spring-boot-maven-plugin打的包包含三个部分:用户程序、依赖包、JarLauncher。用户程序和依赖包位于jar包内的BOOT-INF目录下,JarLauncher位于jar包内的org目录下。在jar包内META-INF目录下的MANIFEST.INF文件中指定了Main-Class: org.springframwork.boot.loader.JarLauncher作为jar包的运行器,指定了Start-Class即Spring Boot程序的启动类。
- 运行jar时可指定临时参数替换配置文件中的参数(多个用空格分割),如java -jar xxx.jar --server.port=8080
项目名称:阅读书目的增删改查
初始化项目
技术选型
用Spring MVC处理Web请求
用Thymeleaf定义Web视图
用Spring Data JPA实现数据持久化
用嵌入式的H2作为数据库
用Java来开发项目
用Gradle作为构建工具
项目元数据:
Project:Gradle Language:Java Spring Boot:2.1.8
Group:com.manning Artifact:readinglist Name:readinglist
Description:Reading List Demo Package Name:com.manning.readinglist
Packaging:Jar Java Version:8
Dependencies:Spring Web、Thymeleaf、Spring Data JPA、H2 Database
注:如果用Spring Boot CLI来初始化应用程序,可以在命令行里键入以下内容:
$ spring init -dweb,data-jpa,h2,thymeleaf --build gradle readinglist
请记住,CLI的 init 命令是不能指定项目根包名和项目名的。包名默认是demo,项目名默认是Demo 。在项目创建完毕之后,你可以打开项目,把包名demo 改为readinglist, 把DemoApplication.java改名为ReadingListApplication.java(里面的类名也要改)。
配置兼启动引导类介绍:
package com.manning.readinglist; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ReadinglistApplication { public static void main(String[] args) { SpringApplication.run(ReadinglistApplication.class, args); } } |
@SpringBootApplication 开启了Spring的Java配置、组件扫描和Spring Boot的自动配置功能。
实际上,@SpringBootApplication 将三个注解组合在了一起:
q Spring的 @Configuration :标明该类使用Spring基于Java的配置。
q Spring的 @ComponentScan :启用组件扫描。
q Spring Boot 的 @EnableAutoConfiguration:又称@Abracadabra,启用自动配置。
在Spring Boot的早期版本中,你需要在 ReadingListApplication 类上同时标上这三个注解,但从Spring Boot 1.2.0开始,有 @SpringBootApplication 就行了。
如果应用程序需要其他Spring配置,最好把它写到根包下一个单独的 @Configuration 标注的类里(组件扫描会发现并使用这些类)。极度简单的情况下,可以把自定义配置加入ReadingListApplication.java。
测试类介绍
package com.manning.readinglist; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class ReadinglistApplicationTests { @Test public void contextLoads() { } } |
一个典型的Spring集成测试会用 @ContextConfiguration 注解标识如何加载Spring的应用程序上下文。但是,为了充分发挥Spring Boot的魔力,这里应该用 @SpringApplicationConfiguration 注解。正如你在代码清单2-2里看到的那样, ReadingListApplicationTests使用 @SpringApplicationConfiguration 注解从 ReadingListApplication 配置类里加载Spring应用程序上下文。
ReadingListApplicationTests 里还有一个简单的测试方法,即 contextLoads() 。实际上它就是个空方法。但这个空方法足以证明应用程序上下文的加载没有问题。如果ReadingListApplication 里定义的配置是好的,就能通过测试。如果有问题,测试就会失败。
当然,现在这只是一个新的应用程序,你还会添加自己的测试。但 contextLoads() 方法是个良好的开端,此刻可以验证应用程序提供的各种功能。第4章会更详细地讨论如何测试SpringBoot应用程序。
优化起步依赖
排除起步依赖中不需要的传递依赖,为项目瘦身
例如,Spring Boot的Web起步依赖传递依赖了Jackson JSON库。如果你正在构建一个生产或消费JSON资源表述的REST服务,那它会很有用。但是,要构建传统的面向人类用户的Web应用程序,你可能用不上Jackson。虽然把它加进来也不会有什么坏处,但排除掉它的传递依赖,
可以为你的项目瘦身。
Gradle排除传递依赖的方法:(貌似此段代码不适用Gradle(Buildship 3.x))
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'com.fasterxml.jackson.core' } |
Maven里排除传递依赖的方法:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.core</groupId> </exclusion> </exclusions> </dependency> |
覆盖起步依赖中传递依赖的版本(慎重)
假设Web起步依赖引用了Jackson 2.3.4,但你需要使用2.4.3。
Maven中直接在pom.xml中写入需要的依赖,直接写入的依赖会覆盖起步依赖中的传递依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.4.3</version> </dependency> |
Gradle会优先使用新版本依赖,因此:(貌似下列两段代码不适用Gradle(Buildship 3.x))
如果需要使用较新版本的依赖,直接写入该依赖:
compile("com.fasterxml.jackson.core:jackson-databind:2.4.3") |
如果需要使用老版本的依赖,则需在加入老版本依赖时排除起步依赖中对应的传递依赖:
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'com.fasterxml.jackson.core' } compile("com.fasterxml.jackson.core:jackson-databind:2.3.1") |
不管什么情况,在覆盖Spring Boot起步依赖引入的传递依赖时都要多加小心。虽然不同的版本放在一起也许没什么问题,但你要知道,起步依赖中各个依赖版本之间的兼容性都经过了精心的测试。应该只在特殊的情况下覆盖这些传递依赖(比如新版本修复了一个bug)。
定义领域模型
package com.manning.readinglist.entity; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Book { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String reader; private String isbn; private String title; private String author; private String description; setter和getter方法... } |
@Entity 注解表明它是一个JPA实体,id 字段加了 @Id 和 @GeneratedValue 注解,表明该字段是实体的唯一标识,且字段值为自动生成。
定义仓库接口
package com.manning.readinglist.dao; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.manning.readinglist.entity.Book; public interface ReadingListRepository extends JpaRepository<Book, Long> { List<Book> findByReader(String reader); } |
通过扩展 JpaRepository , ReadingListRepository 直接继承了18个执行常用持久化操作的方法。 JpaRepository 是个泛型接口,有两个参数:仓库操作的领域对象类型,及其ID属性的类型。
此外,我们还增加了一个 findByReader() 方法,可以根据读者的用户名来查找阅读列表。
在应用程序启动后,Spring Data使用动态代理生成ReadingListRepository实现类进行数据库操作。
创建Web控制器
package com.manning.readinglist.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.manning.readinglist.dao.ReadingListRepository; import com.manning.readinglist.entity.Book; @Controller @RequestMapping("/") public class ReadingListController { private ReadingListRepository readingListRepository; @Autowired public ReadingListController(ReadingListRepository readingListRepository) { this.readingListRepository = readingListRepository; } @RequestMapping(value = "/{reader}", method = RequestMethod.GET) public String readersBooks(@PathVariable("reader") String reader, Model model) { List<Book> readingList = readingListRepository.findByReader(reader); if (readingList != null) { model.addAttribute("books", readingList); } return "readingList"; } @RequestMapping(value = "/{reader}", method = RequestMethod.POST) public String addToReadingList(@PathVariable("reader") String reader, Book book) { book.setReader(reader); readingListRepository.save(book); return "redirect:/{reader}"; } } |
创建Web试图(Thymeleaf模板)
/readinglist/src/main/resources/templates/readingList.html
/readinglist/src/main/resources/static/style.css
模板定义了一个HTML页面,该页面概念上分为两个部分:页面上方是读者的阅读列表中的图书清单;下方是是一个表单,读者可以从这里添加新书。为了美观,Thymeleaf模板引用了一个名为style.css的样式文件。
运行项目
通过Maven和Gradle来运行应用程序
如我所说, ReadingListApplication 还是一个启动引导类。要运行Spring Boot应用程序有几种方式,其中包含传统的WAR文件部署。但这里的 main() 方法让你可以在命令行里把该应用程序当作一个可执行JAR文件来运行。这里向 SpringApplication.run() 传递了一个ReadingListApplication 类的引用,还有命令行参数,通过这些东西启动应用程序。
实际上,就算一行代码也没写,此时你仍然可以构建应用程序尝尝鲜。要构建并运行应用程序,最简单的方法就是用Gradle的 bootRun 任务:
$ gradle bootRun
bootRun 任务来自Spring Boot的Gradle插件,我们会在2.1.2节里详细讨论。此外,你也可以用Gradle构建项目,然后在命令行里用 java 来运行它:
$ gradle build
...
$ java -jar build/libs/readinglist-0.0.1-SNAPSHOT.jar
Spring Boot的Maven插件与之类似,提供了一个 spring-boot:run 目标,如果你使用Maven,它能实现相同的功能。
应用程序应该能正常运行,启动一个监听8080端口的Tomcat服务器。要是愿意,你可以用浏览器访问http://localhost:8080,但由于还没写控制器类,你只会收到一个HTTP 404(NOT FOUND)错误,看到错误页面。在本章结束前,这个URL将会提供一个阅读列表应用程序。
构建并运行可执行JAR
构建WAR文件并部署到Java Web应用服务器如Tomcat里
使用Spring Tool Suite运行项目
项目或启动引导类中右键RunAs > Spring Boot App(或者Java Application)