Spring Boot

Spring Boot是由 Pivotal 团队提供的全新框架,用来简化 Spring 应用的初始搭建以及开发过程。

Spring Boot官方文档:Spring Boot

Spring中文文档:Spring 中文文档

微服务

微服务是一种架构风格:一个应用围绕业务功能拆分为一组小型服务,每个服务运行在自己的进程内,也就是可独立部署和升级。服务之间使用轻量级HTTP交互,去中心化,服务自治。各服务可以使用不同的语言、不同的存储技术。

发展对比

流行

Bean

轻重

J2EE时代

企业级JavaBean (Enterprise JavaBeanEJB

重量级

Spring时代

简单Java 对象(Plain Old Java ObjectPOJO

代码轻量级,配置重量级

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

  1. File > New > Project,在弹出的对话框中,左侧选中Spring Initializr,然后右侧选择Project SDK和Initializr Service URL:

Project SDK下拉框中如果没有要的JDK,点右边New...->JDK选择JDK位置。

Initializr Service URL一般默认即可(也可使用阿里云的Initializr(有更多的依赖选择),地址见上面),除非使用自己的Initializr。点下一步。

  1. 设置好项目元数据后,点下一步。

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的命令行补全

如果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";

}

}

启动项目

启动项目有三种方法:

  1. 使用Maven命令启动:在pom.xml所在目录中运行:mvn spring-boot:run
  2. 将maven项目导入IDE后直接运行引导类的main方法
  3. 打成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/

主题 Spring Boot 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用于定义一个配置类

@EnableAutoConfigurationSpring 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,如存在多种格式的配置文件,相同配置以优先级高的为准。

配置源顺序

参见:Core Features

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

书写配置代码补全提示失效解决方案:

  1. 如果没有引入配置所属相关依赖,IDE是无法提示的,先添加相关依赖再书写配置
  2. 如果idea中配置文件无绿叶标识,说明idea未将该文件识别为配置文件。解决方法:File-》Project Structure...-》左栏点Facets-》中栏点模块-》右栏点绿叶按钮-》添加未被识别的配置文件

配置文件中的数据引用:

baseDir=/usr/local/fire
dataDir=${baseDir}/data
tmpDir=${baseDir}/tmp
logDir=${baseDir}/log

转义字符处理

在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:}")//默认值是""
    private String schoolName;

    @Test

    void testValue(){
        System.out.println(schoolName);

    }

方式:使用@Autowired注解自动装配配置数据到Environment接口中,使用该接口的getProperty("配置项key")方法读取配置项值:

    @Autowired
    private Environment env;
    @Test
    void testEnvironment(){
        System.out.println(env.getProperty("school.name"));//获取不到则返回null,不会报错

    }

方式使用@ConfigurationProperties("配置项key相同的前缀")注解将有相同前缀的配置项映射为对象再将对象注册为Bean使用:

  1. 声明一个属性配置类Bean:

2)将该类bean注入其他组件类中使用:

@Data
@Configuration
//参数完整写法:prefix = "school"
@ConfigurationProperties("school")
public class SchoolConfigProperties {
    String name;

}

@Autowired
    SchoolConfigProperties schoolConfigProperties;

    public void testSchoolConfigProperties(){

        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
subjects: 语文, 数学, 英语

# 定义map
#    使用@Value获取map时,整个map最好引号
#    key为字符串时可以不引号,value为字符串时必须引号
subjectMap: "{
               '语': '语文',
               '数': '数学',
               '英': '英语'
              }"
subjectListMap: "{
                   '语文': '阅读理解,大作文',
                   '数学': '代数,几何',
                   '英语': '完形填空,小作文'
                  }"

# 定义复杂对象
person:
  name: goodboy
  age: 18
  vip: false #任意大小写均可
  birthday: '1970-01-01 00:00:00'
  birthDate: '1970-01-01'
  birthTime: '1970-01-01 00:00:00'

  hobbies: #eat, play, sleep
    - eat
    - play
    - sleep
  total-scores: #{arts: 130, sciences: 170}
    arts: 130
    sciences: 170
  detail-scores: #{arts: {historical: 60, geography: 70}, sciences: {physical: 80, chemistry: 90}}
    arts:
      historical: 60
      geography: 70
    sciences:
      physical: 80
      chemistry: 90
  current-area: #{province: 广东省, city: 深圳市}
    province: 广东省
    city: 深圳市
  used-areas: #[{province: 福建省, city: 福州市}, {province: 福建省, city: 厦门市}]
    - province: 福建省
      city: 福州市
    - province: 福建省
      city: 厦门市
  wish-areas: #{work-area: {province: 海外省, city: 美国市}, live-area: {province: 台湾省, city: 台北市}}
    work-area:
      province: 海外省
      city: 美国市
    live-area:
      province: 台湾省
      city: 台北市

# 定义string或array或list
subjects=语文, 数学, 英语

#定义map
#    整个map不要加引号
#    keyvalue为字符串时必须引号
subjectMap={\
             '语': '语文',\
             '数': '数学',\
             '英': '英语'\
           }
subjectListMap={\
                 '语文': '阅读理解,大作文',\
                 '数学': '代数,几何',\
                 '英语': '完形填空,小作文'\
               }

# 定义复杂对象
person.name=goodboy
person.age=18
person.vip=false
person.birthday=1970-01-01 00:00:00
person.birthDate=1970-01-01
person.birthTime=1970-01-01 00:00:00
person.hobbies[0]=eat
person.hobbies[1]=play
person.hobbies[2]=sleep
person.total-scores.arts=130
person.total-scores.sciences=170
person.detail-scores.arts.historical=60
person.detail-scores.arts.geography=70
person.detail-scores.sciences.physical=80
person.detail-scores.sciences.chemistry=90
person.current-area.province=广东省
person.current-area.city=深圳市
person.used-areas[0].province=福建省
person.used-areas[0].city=福州市
person.used-areas[1].province=福建省
person.used-areas[1].city=厦门市
person.wish-areas.work-area.province=海外省
person.wish-areas.work-area.city=美国市
person.wish-areas.live-area.province=台湾省
person.wish-areas.live-area.city=台北市

复杂对象映射的Bean

读取各种类型

package com.tongwx.demo.bean;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import java.util.List;
import java.util.Map;

@Data
@Configuration
@ConfigurationProperties(prefix = "person")//参数完整写法:prefix = "person"
public class PersonConfigProperties {
    private String name;
    private Integer age;
    private Boolean vip;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date birthday;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate birthDate;
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime birthTime;

    private List<String> hobbies;
    private Map<String, Integer> totalScores;
    private Map<String, Map<String, Integer>> detailScores;
    private Area currentArea;
    private List<Area> usedAreas;
    private Map<String, Area> wishAreas;

    @Data
    private static class Area {
        private String province;
        private String city;
    }
}

package com.tongwx.demo;

import com.tongwx.demo.bean.PersonConfigProperties;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@SpringBootTest
class DemoApplicationTests {
    //读取string
    @Value("${subjects:}")//默认值是""
    private String subjectString1;
    @Value("${subjects:null}")//默认值是"null"
    private String subjectString2;

    //读取array
    @Value("${subjects:}")//默认值是{}
    private String[] subjectArray;

    /**
     * 读取list
     *      #{}内是SpEL表达式,使用split函数指定了分隔符,会丢失trim元素功能;
     *     不指定分隔符则会默认以,作为分隔符,并自动trim元素。
     */
    @Value("${subjects:}")                            //默认值是{}
    private ArrayList<String> subjectList1;
    @Value("#{'${subjects:}'.split(',')}")            //默认值是{""}
    private ArrayList<String> subjectList2;
    @Value("${subjects:,}")                           //默认值是{"",""}
    private ArrayList<String> subjectList3;
    @Value("#{'${subjects:,}'.split(',')}")           //默认值是{}
    private ArrayList<String> subjectList4;
    @Value("${subjects:l1,l2,l3}")                    //默认值是{"l1","l2","l3"}
    private ArrayList<String> subjectList5;
    @Value("#{'${subjects:l1,l2,l3}'.split(',')}")    //默认值是"l1","l2","l3"}
    private ArrayList<String> subjectList6;

    //读取map
    @Value("#{${subjectMap:{}}}")//默认值是null
    private Map<String,String> subjectMap1;
    @Value("#{${subjectMap:{k1:'v1',k2:'v2'}}}")//默认值是{"k1":"v1","k2":"v2"}
    private Map<String, String> subjectMap3;
    @Value("#{${subjectListMap:{}}}")//默认值是null
    private Map<String,List<String>> subjectListMap;

    //读取复杂对象中的某个路径的属性
    @Value("${person.used-areas[1].city:}")//默认值是""
    private String pathProperty;

    //使用Environment读取配置
    @Autowired
    private Environment env;

    //读取复杂对象
    @Autowired
    private PersonConfigProperties personConfigProperties;

    @Test
    void testReadConfigProperties(){
        System.out.println("========String==========");
        System.out.println(subjectString1);
        System.out.println(subjectString2);
        System.out.println("=========Array===========");
        Arrays.asList(subjectArray).forEach(System.out::println);
        System.out.println("=========List===========");
        System.out.println(subjectList1);
        System.out.println(subjectList2);
        System.out.println(subjectList3);
        System.out.println(subjectList4);
        System.out.println(subjectList5);
        System.out.println(subjectList6);
        System.out.println("=========Map===========");
        System.out.println(subjectMap1);
        System.out.println(subjectMap3);
        System.out.println(subjectListMap);
        System.out.println("=====pathProperty=======");
        System.out.println(pathProperty);
        System.out.println("=====Environment=======");
        System.out.println(env.getProperty("subjects"));
        System.out.println(env.getProperty("subjects", List.class));
        System.out.println(env.getProperty("subjectMap"));//无法返回map,只能返回String
        System.out.println(env.getProperty("subjectListMap"));无法返回map,只能返回String
        System.out.println(env.getProperty("person.used-areas[1].city"));
        System.out.println("=====ConfigurationProperties=======");
        System.out.println(personConfigProperties);
    }

}

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("classpath:jdbc.properties")

public class JdbcConfig {

    @Value("${jdbc.url}")

    String url;

    @Value("${jdbc.driverClassName}")

    String driverClassName;

    @Value("${jdbc.username}")

    String username;

    @Value("${jdbc.password}")

    String password;

    @Bean

    public DataSource dataSource() {

        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setUrl(url);

        dataSource.setDriverClassName(driverClassName);

        dataSource.setUsername(username);

        dataSource.setPassword(password);

        return dataSource;

}

}}

@Configuration:声明该类为配置类

@PropertySource:指定属性文件路径,如果是从核心配置文件中取值,可省略该注解。

@Value:为属性注入值

@Bean:将该方法声明为一个注册Bean的方法,Spring会自动调用该方法,将方法的返回值加入Spring容器中。

配置好Bean后就可以在其他组件中注入DataSource这个Bean了。

左例还可这样写:

@ConfigurationProperties(prefix = "jdbc")

public class JdbcProperties {

    private String url;

    private String driverClassName;

    private String username;

    private String password;

    getters 和 setters ...

}

@Configuration

@EnableConfigurationProperties(JdbcProperties.class)

public class JdbcConfig {

    @Bean

    public DataSource dataSource(JdbcProperties jdbc) {

        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setUrl(jdbc.getUrl());

        dataSource.setDriverClassName(jdbc.getDriverClassName());

        dataSource.setUsername(jdbc.getUsername());

        dataSource.setPassword(jdbc.getPassword());

        return dataSource;

    }

}

@ConfigurationProperties:声明该类为属性读取类。

prefix="jdbc":读取属性文件中,前缀为jdbc的值。在类上定义的各个属性,名称必须与属性文件中键的jdbc.后面部分一致

需要注意的是,这里我们并没有指定属性文件的地址,所以我们需要把jdbc.properties的内容写到核心配置文件中。

@EnableConfigurationProperties(JdbcProperties.class):声明要使用JdbcProperties这个类的对象。

又)更优雅的创建

@Configuration

public class JdbcConfig {

    

    @Bean

    // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过dataSourceset方法注入到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,可删除exclusionjunit-vintage-engine

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

测试类示例

package com.example.demo.controller;

import com.example.demo.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class UserControllerTest {
    @Autowired
    UserController userController;
    @Test
    public void testFindAll(){
        List<User> users = userController.findAll();
        System.out.println(users);
    }
}

package com.example.demo.controller;

import com.example.demo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
public class UserControllerTest {
    @Autowired
    UserController userController;
    @Test
    public void testFindAll(){
        List<User> users = userController.findAll();
        System.out.println(users);
    }
}

如果项目有多个启动类,用@SpringBootTest的属性classes指定要运行哪个启动类,如:@SpringBootTest(classes = DemoApplication.class)

如果测试类启动类所在包或子包下,就需要指定启动如:@SpringBootTest(classes = DemoApplication.class)或@ContextConfiguration(classes = DemoApplication.class)

    1. 远程调用

发送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 -->
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>2.3.0</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

配置

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

# mybatis 别名扫描
mybatis.type-aliases-package=com.tongwx.demo.entity
# mapper.xml文件位置
mybatis.mapper-locations=classpath*:mappers/*Mapper.xml

entity和dao

注:如果不想给每一个Mapper接口添加@Mapper注解,可在启动类添加Mapper接口扫描注解配置:

@MapperScan(basePackages = {"com.tongwx.demo.dao"} )

package com.tongwx.demo.entity;

import lombok.Data;

@Data
public class User {
    Long id;
    private String name;
    private String age;
    private Date createDate;
}

package com.tongwx.demo.dao;

import com.tongwx.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserDao {
    @Select("select id, name, age, create_date as createDate from user where id = #{id}")
    User findById(Long id);
}

测试

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-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</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

# 设置表前缀
# mybatis-plus.global-config.db-config.table-prefix=
# 设置主键生成策略(默认为ASSIGN_ID雪花算法):
mybatis-plus.global-config.db-config.id-type=auto
# 设置日志输出格式(开发环境可设为StdOutImpl打印到控制台)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

分页拦截器

package com.tongwx.demo.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MPConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

entity和dao

注:如果不想给每一个Mapper接口添加@Mapper注解,可在启动类添加Mapper接口扫描注解配置:

@MapperScan(basePackages = {"com.tongwx.demo.dao"} )

package com.tongwx.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    Long id;
    private String name;
    private String age;
    private Date createDate;
}

package com.tongwx.demo.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tongwx.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao extends BaseMapper<User> {

}

测试

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;

import com.baomidou.mybatisplus.extension.service.IService;
import com.tongwx.demo.entity.User;

import java.util.List;

public interface IUserService extends IService<User> {
    //自定义API
    List<User> getLikeName(String name);
}

package com.tongwx.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tongwx.demo.dao.UserDao;
import com.tongwx.demo.entity.User;
import com.tongwx.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;

@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements IUserService {

    @Autowired
    UserDao userDao;

    //自定义API
    @Override
    public List<User> getLikeName(String name){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.hasLength(name), User::getName, name);
        return userDao.selectList(lambdaQueryWrapper);
    }
}

package com.tongwx.demo;

import com.tongwx.demo.entity.User;
import com.tongwx.demo.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class UserServiceTests {

    @Autowired
    IUserService userService;

    /**
     * 测试业务层简化开发
     */
    @Test
    void testSimpleCrud() {
        //调用IService<T>接口中定义的原始通用API
        User byId = userService.getById(3);
        //调用自定义API
        List<User> likeNameList = userService.getLikeName("张");
    }

}

    • 通用Mapper

<!-- 通用mapper -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.0.2</version>
</dependency>

@Mapper

public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User>{

}

    • Spring Data Jpa

打包运行几点说明:

  1. 点击Maven Projects窗口上的闪电图标,可在package时跳过test(test中可能会执行一些测试用例导致数据库变动)。
  2. 命令行运行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程序的启动类。
  3. 运行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)

浏览器访问http://localhost:8080/readingList

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值