SpringBoot入门

SpringBoot基于Spring4.0设计,不仅继承了Spring框架原有的优秀特性,而且还通过简化配置来进一步简化了Spring应用的整个搭建和开发过程,另外SpringBoot通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得以解决。Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。

SpringBoot

  • Create stand-alone Spring applications
  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
  • Provide opinionated ‘starter’ dependencies to simplify your build configuration
  • Automatically configure Spring and 3rd party libraries whenever possible
  • Provide production-ready features such as metrics, health checks, and externalized configuration
  • Absolutely no code generation and no requirement for XML configuration


微服务

1.微服务(Microservices)是一种软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic)的API集相互通信。

2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现。

1.微服务是一种开发软件的架构和组织方法,其中软件由通过明确定义的 API 进行通信的小型独立服务组成。这些服务由各个小型独立团队负责。

2.整体式架构与微服务架构

通过整体式架构,所有进程紧密耦合,并可作为单项服务运行。这意味着,如果应用程序的一个进程遇到需求峰值,则必须扩展整个架构。随着代码库的增长,添加或改进整体式应用程序的功能变得更加复杂。这种复杂性限制了试验的可行性,并使实施新概念变得困难。整体式架构增加了应用程序可用性的风险,因为许多依赖且紧密耦合的进程会扩大单个进程故障的影响。

使用微服务架构,将应用程序构建为独立的组件,并将每个应用程序进程作为一项服务运行。这些服务使用轻量级 API 通过明确定义的接口进行通信。这些服务是围绕业务功能构建的,每项服务执行一项功能。由于它们是独立运行的,因此可以针对各项服务进行更新、部署和扩展,以满足对应用程序特定功能的需求。

3.微服务的优势

  • 敏捷性

  • 灵活扩展

  • 轻松部署

  • 技术自由

  • 可重复使用的代码

  • 弹性



初识SpringBoot

GitHub Spring Boot

Spring initializr

Spring Boot 2.6.4 API

SpringBoot Docs

Spring Boot Reference Documentation

  • 官网 Maven Project 2.6.4 8
  • IDEA集成

Dependencies

  • Website

    • Spring Web:Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.
  • IDEA

    • Spring initializr->Dependencies->Web
  • Maven

    1
    2
    3
    4
    5
    <!--pom.xml-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

1.官网包如果没有导入依赖和对应文件结构可以在Settings中选择对应Maven位置Plugin

2.org.springframework.boot:spring-boot-maven-plugin: not found(添加版本号)

1
2
3
4
5
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4.RELEASE</version>
</plugin>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
│  .gitignore
│ HELP.md
│ mvnw
│ mvnw.cmd
│ pom.xml

├─.idea
│ .gitignore
│ compiler.xml
│ encodings.xml
│ jarRepositories.xml
│ misc.xml
│ runConfigurations.xml
│ uiDesigner.xml
│ workspace.xml

├─.mvn
│ └─wrapper
│ maven-wrapper.jar
│ maven-wrapper.properties

├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─example
│ │ │ └─demo
│ │ │ │ SpringbootDemoApplication.java(程序主入口)
│ │ │ │
│ │ │ ├─controller
│ │ │ │ HelloController.java
│ │ │ │
│ │ │ ├─dao
│ │ │ ├─pojo
│ │ │ └─service
│ │ └─resources
│ │ │ application.properties
│ │ │
│ │ ├─static
│ │ └─templates
│ └─test
│ └─java
│ └─com
│ └─example
│ └─demo
│ SpringbootDemoApplicationTests.java

└─target
├─classes
│ │ application.properties(SpringBoot核心配置文件)
│ │
│ └─com
│ └─example
│ └─demo
│ │ SpringbootDemoApplication.class
│ │
│ └─controller
│ HelloController.class

├─generated-sources
│ └─annotations
├─generated-test-sources
│ └─test-annotations
└─test-classes
└─com
└─example
└─demo
SpringbootDemoApplicationTests.class(单元测试)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!--pom.xml-->
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringbootDemo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web 依赖:tomcat dispatcherServlet xml...-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!--jar打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

@RequestMapping("hello")
public String hello(){
return "Hello SpringBoot";
}
}

打包(Jar): Maven(右侧)->Lifecycle->package(可在target目录下生成对应jar包)

执行:java -jar demo-0.0.1-SNAPSHOT.jar


1
2
3
4
5
<!--spring-boot-devtools支持Spring Boot应用支持热部署,提高开发效率,无需手动重启Spring Boot应用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>

1.自定义Banner

spring boot项目启动时会打印spring boot的ANSI字符画

1.在Spring Boot工程的/src/main/resources目录下创建含有自定义字符画的banner.txt文件

Spring Boot框架在启动时会按照以下顺序,查找banner信息:

  • 在 Classpath 下查找文件 banner.gif 或 banner.jpg 或 banner.png

  • 以上都没有就在 Classpath 下找 banner.txt

  • 都没找到使用默认 SpringBootBanner

2.重写Banner类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.zero.demo.Banner;

import org.springframework.boot.Banner;
import org.springframework.core.env.Environment;

import java.io.PrintStream;

public class MyBanner implements Banner {
private static final String BANNER = "\n :) \n";
@Override
public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
out.println(BANNER);

}
}
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {

SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.setBanner(new MyBanner());
springApplication.run(args);
}
}

2.隐藏Banner

1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {

SpringApplication springApplication = new SpringApplication(DemoApplication.class);
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);

}

}
1
spring.main.banner-mode=off

Run/Debug Configurations->Spring Boot->Hide Banner



SpringBoot自动装配原理

Dependencies

引入大多数SpringBoot应用时不需要版本号,因为Spring-boot-dependenceies含有对应版本参数


Starter

using-boot-starter

starter无需用户导入依赖库以及各种配置信息,只需要在maven中引入对应的starter依赖即可,SpringBoot会自动通过classpath路径下的类发现需要的Bean并注册到IOC容器。Spring Boot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。这些依赖模块都遵循着约定成俗的默认配置,并允许调整配置。

Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors.

The starters contain a lot of the dependencies that you need to get a project up and running quickly and with a consistent, supported set of managed transitive dependencies.

1.在Spring Boot Framework中,Spring Boot官方的启动器都是以spring-boot-starter-* 命名的,其中*表示特定类型的应用程序。

2.使用Spring和JPA进行数据库访问,则需要在项目的pom.xml文件中包含spring-boot-starter-data-jpa依赖项。而第三方的启动器不能以spring-boot开头命名(Spring Boot官方artifacts),第三方启动器通常以项目名称开头,如mybatis的mybatis-spring-boot-starter。


自定义Starter

1.编写Starter

  • 新建SpringBoot项目,导入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.0.0.RELEASE</version>
<optional>true</optional>
</dependency>
<!--打包插件-->
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
</dependency>
<!--JackSon导入@JsonFormat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<!--无main类带依赖jar打包-->
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
  • 编写对应类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@ConfigurationProperties(
prefix = "spring.zero"
)
public class ZeroProperties {
private String projectName;
private String projectAuthor;
private Date projectTime;

public ZeroProperties() {
}

public String getProjectName() {
return this.projectName;
}

public void setProjectName(String projectName) {
this.projectName = projectName;
}

public String getProjectAuthor() {
return this.projectAuthor;
}

public void setProjectAuthor(String projectAuthor) {
this.projectAuthor = projectAuthor;
}

public Date getProjectTime() {
return this.projectTime;
}

public void setProjectTime(Date projectTime) {
this.projectTime = projectTime;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@ConfigurationProperties(prefix = "spring.zero")
public class ZeroProperties {
/*实体类,用于映射配置属性*/
private String projectName;
private String projectAuthor;

private Date projectTime;

public String getProjectName() {
return projectName;
}

public void setProjectName(String projectName) {
this.projectName = projectName;
}

public String getProjectAuthor() {
return projectAuthor;
}

public void setProjectAuthor(String projectAuthor) {
this.projectAuthor = projectAuthor;
}

public Date getProjectTime() {
return projectTime;
}

/*除了直接注入projectTime外,结合Spring通过setter注入对应值,可选择传入字符串转换为Date注入*/
public void setProjectTime(String time) throws ParseException {
this.projectTime = new SimpleDateFormat("yyyy-MM-dd").parse(time);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ZeroService {
/*编写相关操作逻辑,供外部调用*/
private ZeroProperties properties;
public ZeroService(){
}
public ZeroService(ZeroProperties zeroProperties){
this.properties = zeroProperties;
}
public String getProjectInfo() {
return
"This project is " + properties.getProjectName() +
" , author is " + properties.getProjectAuthor() +
" , creation time is " + properties.getProjectTime().toString();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@EnableConfigurationProperties(ZeroProperties.class) /*启用ZeroProperties并添加到容器中*/
@ConditionalOnClass(ZeroService.class)
@ConditionalOnProperty(prefix = "spring.zero",value = "enabled",matchIfMissing = true)
public class ZeroServiceAutoConfiguration {
/*自动配置类,完成Bean创建,给Spring容器添加组件等*/
@Autowired
private ZeroProperties properties;

@Bean
@ConditionalOnMissingBean(ZeroService.class) /*容器中没有ZeroService该方法生效*/
public ZeroService zeroService(){
return new ZeroService(properties);
}
}
  • resources下创建目录META-INF,在 META-INF 目录下创建 spring.factories,在SpringBoot启动时会根据该类文件来加载项目的自动化配置类
1
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zero.ZeroServiceAutoConfiguration
  • 打包(Maven->package)

2.使用自定义Starter

  • 新建SpringBoot项目,在Project Structure检查是否maven版本正确
  • 将jar包加入Maven(Terminal)
1
mvn install:install-file  -DgroupId="com.zero"  -DartifactId=spring-boot-zero-starter -Dversion="0.0.1-SNAPSHOT"  -Dpackaging=jar -Dfile="C:\Users\29921\Desktop\spring-boot-zero-starter-0.0.1-SNAPSHOT.jar"
  • 自定义starter添加pom依赖
1
2
3
4
5
<dependency>
<groupId>com.zero</groupId>
<artifactId>spring-boot-zero-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
  • 配置application.yml
1
2
3
4
5
spring:
zero:
project-name: MyStarter
project-author: Zero
project-time: 2022-01-23 # 直接注入 project-time: 2008/12/22
  • 编写controller类测试
1
2
3
4
5
6
7
8
9
10
@RestController
@RequestMapping("/my")
public class TestController {
@Resource
private ZeroService zeroService;
@GetMapping("/starter")
public Object starter() {
return zeroService.getProjectInfo();
}
}

SpringBootApplication

1
2
3
4
5
6
7
@SpringBootApplication 
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class);
}
}


yaml

概述

1.YAML是一个可读性高,用来表达资料序列化的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822)中获得灵感。Clark Evans在2001年首次发表了这种语言。

2.YAML是YAML Ain't a Markup Language(YAML不是一种标记语言)的递归缩写。开发该语言时YAML其实是Yet Another Markup Language(仍是一种标记语言),但为了强调这种语言以数据为中心,而不是以标记语言为重点,而用反向缩略语重命名。

3.YAML的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等资料形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。尽管它比较适合用来表达层次结构式(hierarchical model)的数据结构,不过也有精致的语法可以表示关系性(relational model)的资料。巧妙避开各种封闭符号使得yaml易于上手,如:引号、各种括号等,这些符号在嵌套结构时会变得复杂而难以辨认。

4.YAML 的配置文件后缀为 .yml

基本语法

  • 小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • # 表示注释,从这个字符一直到行尾,都会被解析器忽略

数据类型

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

YAML 对象

对象键值对

  • 冒号结构 key: value,冒号后面要加一个空格

  • 将所有键值对写成一个行内对象,key: {key1: value1, key2: value2, ...}

  • 使用缩进表示层级关系;

1
2
3
key: 
child-key: value
child-key2: value2

对应 JavaScript

1
{ key: { key1: value1, key2: value2 } }

可以使用问号加一个空格代表一个复杂的 key,配合一个冒号加一个空格代表一个 value:

1
2
3
4
5
6
7
# 对象的属性是一个数组 [complexkey1,complexkey2],对应的值也是一个数组 [complexvalue1,complexvalue2]
?
- complexkey1
- complexkey2
:
- complexvalue1
- complexvalue2

YAML 数组

一组-开头的行表示构成一个数组:

1
2
3
- A
- B
- C

转换为 JavaScript

1
[A,B,C]

YAML 可使用行内表示:

1
key: [value1, value2, ...]

对应 JavaScript

1
{ key: [ value1, value2 ] }

数据结构的子成员是一个数组,可在该项下面缩进一个空格。

1
2
3
4
-
- A
- B
- C
1
2
3
4
5
6
7
8
9
10
# companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price: 500W

数组可使用流式(flow)的方式表示:

1
companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]

复合结构

数组和对象可以构成复合结构,例:

1
2
3
4
5
6
7
8
9
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
Perl: use.perl.org

转换为 json 为:

1
2
3
4
5
6
7
8
9
{ 
languages: [ 'Ruby', 'Perl', 'Python'],
websites: {
YAML: 'yaml.org',
Ruby: 'ruby-lang.org',
Python: 'python.org',
Perl: 'use.perl.org'
}
}

纯量

纯量是最基本的,不可再分的值,包括:

1.字符串

  • 字符串默认不使用引号表示
  • 字符串包含空格或特殊字符,需要放在引号之中
  • 单引号和双引号都可使用,双引号不会对特殊字符转义
  • 单引号之中如还有单引号,须连续使用两个单引号转义
  • 字符串可写成多行,从第二行开始,必须有一个单空格缩进。换行符会被转为空格
  • 多行字符串可以使用|保留换行符,也可以使用>折叠换行
  • +表示保留文字块末尾的换行,-表示删除字符串末尾的换行
  • 字符串可插入 HTML 标记
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
str: 你好世界
str1: 'Hello world'
str2: 'labor''s day'
s1: '内容\n字符串'
s2: "内容\n字符串"
str3: This
is
String
this: |
Foo
Bar
that: >
Foo
Bar
s1: |
Foo

s2: |+
Foo


s3: |-
Foo
message: |

<p style="color: red">
段落
</p>

部分转换为JavaScript

1
2
3
4
5
{ s1: '内容\\n字符串', s2: '内容\n字符串' }
{ str: 'This ' }
{ this: 'Foo\nBar\n', that: 'Foo Bar\n' }
{ s1: 'Foo\n', s2: 'Foo\n\n\n', s3: 'Foo' }
{ message: '\n<p style="color: red">\n 段落\n</p>\n' }

2.布尔值

true(True)false(False)

1
2
isSet: true
isNumber: True

3.整数

1
2
num: 123
count: 0b1010_0111_0100_1010_1110 #二进制表示

4.浮点数

1
2
num: 3.14
point: 6.8523015e+5 #科学计数法

5.Null

使用~表示null

1
parent: ~  

6.时间

时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区

1
datetime: 2018-02-17T15:02:31+08:00

7.日期

日期使用复合ISO 8601格式,即yyyy-MM-dd

1
datetime: 1976-07-31

YAML允许使用两个感叹号强制转换数据类型

1
2
e: !!str 12
f: !!str true

对应JavaScript

1
{ e: '12', f: 'true' }

引用

& 锚点和 * 别名,可以用来引用:

1
2
3
4
5
6
7
8
9
10
11
defaults: &defaults
adapter: postgres
host: localhost

development:
database: myapp_development
<<: *defaults

test:
database: myapp_test
<<: *defaults

相当于

1
2
3
4
5
6
7
8
9
10
11
12
13
defaults:
adapter: postgres
host: localhost

development:
database: myapp_development
adapter: postgres
host: localhost

test:
database: myapp_test
adapter: postgres
host: localhost

& 用来建立锚点(defaults),<< 表示合并到当前数据,* 用来引用锚点。

1
2
3
4
5
- &showell Steve 
- Clark
- Brian
- Oren
- *showell

转为 JavaScript 代码:

1
[ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]


1
2
3
4
5
6
<!--Spring Boot Configuration Annotation Processor not configured-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
1
2
3
4
5
6
7
8
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
private String name;
private Integer age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Boolean isEmployee;
private Date birth;
private Map<String,Object> hobbies;
private Pet pet;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
server:
port: 8081

person:
name: Spring
age: 34
isEmployee: true
birth: 2020/08/06
hobbies:
- read
- code
pet:
name: Coco
age: 6
1
2
3
4
5
6
7
8
9
10
@SpringBootTest
class DemoApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
1
2
3
4
5
6
@Data
@Component
public class Pet {
private String name;
private Double weight;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
person:
user-name: Admin
boss: true
birth: 2019/12/1 20:01:23
age: 34
pet:
name: jackson
weight: 23.5
interests: [阅读,运动]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]

yaml文件加载中文数组时java.lang.IllegalStateException: Failed to load ApplicationContext: 将IDEA右下角格式ISO-8859-1改为UTF-8


指定配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
/*指定配置文件*/
@PropertySource(value = "classpath:application.properties")
public class Pet {
/*SPEL表达式取出配置文件的值*/
@Value("${name}")
private String name;
@Value("${age}")
private Integer age;
}
1
2
3
4
5
6
7
8
9
@SpringBootTest
class DemoApplicationTests {
@Autowired
private Pet pet;
@Test
void contextLoads() {
System.out.println(pet);
}
}
1
2
name=zero
age=6

1
2
3
4
5
6
7
8
9
10
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "pet")
public class Pet {
private String name;
private Integer age;
private String id;
}
1
2
3
4
pet:
name: ${person.name:boot}_dog
age: ${random.int}
id: ${random.uuid}
@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 单个指定
松散绑定 支持 不支持
SpEl 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持


数据校验

JSR-303是 Java EE 6 中的一项子规范(Bean Validation),官方参考实现是hibernate Validator。 JSR 303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。
1.导入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2.测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties(prefix = "pet")
@Validated /*数据校验*/
public class Pet {
@NotEmpty(message = "姓名不能为空")
private String firstName;

private Integer age;
@Email(message = "邮箱格式错误")
private String email;
}
  • Bean Validation 中内置的 constraint
Constraint 详细信息
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(value) 被注释的元素必须符合指定的正则表达式
  • Hibernate Validator 附加的 constraint
Constraint 详细信息
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内


Property Files

By default, the configured locations are . The resulting search order is the following:classpath:/,classpath:/config/,file:./,file:./config/

1.file:./config/

2.file:./

3.classpath:/config/

4.classpath:/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
│  application.yml
│ pom.xml

├─.idea
├─.mvn
├─config
│ application.yml

├─src
│ ├─main
│ │ ├─java
│ │ │ └─com
│ │ │ └─zero
│ │ │ └─demo
│ │ │ │ DemoApplication.java
│ │ └─resources
│ │ │ application.yml
│ │ │
│ │ └─config
│ │ application.yml
│ │
│ └─test
│ └─java
│ └─com
│ └─zero
│ └─demo
│ DemoApplicationTests.java

└─target

1.file:项目次级目录(src包同级) classpath:resources路径

同一路径下优先级:properties > yml > yaml

1
2
3
4
# application.properties
server.port=8080
# Springboot多环境配置
spring.profiles.active=dev
1
2
# application-dev.properties
server.port=8081
1
2
# application-test.properties
server.port=8082

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server:
port: 8081
spring:
profiles:
active: test
debug: true
# 开启调试,查看自动配置类是否生效
#Positive matches:(自动配置类启用:正匹配)
#Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
#Unconditional classes: (没有条件的类)
---
server:
port: 8082
spring:
config:
activate:
on-profile: dev
---
server:
port: 8083
spring:
config:
activate:
on-profile: test


Web开发

静态资源导入

1.WebJars:WebJars are client-side web libraries (e.g. jQuery & Bootstrap) packaged into JAR (Java Archive) files.

  • Explicitly and easily manage the client-side dependencies in JVM-based web applications
  • Use JVM-based build tools (e.g. Maven, Gradle, sbt, …) to download your client-side dependencies
  • Know which client-side dependencies you are using
  • Transitive dependencies are automatically resolved and optionally loaded via RequireJS
  • Deployed on Maven Central
  • Public CDN

1.导入资源

1
2
3
4
5
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>

2.访问资源(注意浏览器缓存)

1
2
3
/*WebProperties*/
/*@ConfigurationProperties("spring.web")*/
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
1
2
3
4
5
6
resources
│ application.yml
├─public
├─resources
├─static
└─templates

http://localhost:8080/webjars/jquery/3.6.0/jquery.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private Resource getIndexHtml(String location) {
return this.getIndexHtml(this.resourceLoader.getResource(location));
}

private Resource getIndexHtml(Resource location) {
try {
Resource resource = location.createRelative("index.html");
if (resource.exists() && resource.getURL() != null) {
return resource;
}
} catch (Exception var3) {
}

return null;
}

SpringMVC

The Spring Web MVC framework (Spring MVC) is a rich “model view controller” web framework. Spring MVC lets you create special @Controller or @RestController beans to handle incoming HTTP requests. Methods in your controller are mapped to HTTP by using @RequestMapping annotations.

Spring Boot provides auto-configuration for Spring MVC that works well with most applications:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
  • Support for serving static resources, including support for WebJars.
  • Automatic registration of Converter, GenericConverter, and Formatter beans.
  • Support for HttpMessageConverters.
  • Automatic registration of MessageCodesResolver.
  • Static index.html support.
  • Custom Favicon support.
  • Automatic use of a ConfigurableWebBindingInitializer bean.

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.


1
2
3
4
5
6
7
8
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/*视图跳转 /hello->index.html*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello").setViewName("index");
}
}

员工管理系统

1.数据库模拟

1
2
3
4
5
6
7
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
private Integer id;
private String departmentName;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Data
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;
private Department department;
private Date birth;

public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.department = department;
this.birth = new Date();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Repository
public class DepartmentDao {
private static Map<Integer, Department> departments = null;
static {
departments = new HashMap<Integer,Department>();
departments.put(101,new Department(101,"教学部"));
departments.put(102,new Department(102,"市场部"));
departments.put(103,new Department(103,"教学部"));
departments.put(104,new Department(104,"运营部"));
departments.put(105,new Department(105,"后勤部"));
}
public Collection<Department> getDepartments(){
return departments.values();
}
public Department getDepartmentById(Integer id){
return departments.get(id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Repository
public class EmployeeDao {
private static Map<Integer, Employee> employees = null;
@Autowired
private DepartmentDao departmentDao;

static {
employees = new HashMap<Integer,Employee>();
employees.put(1001,new Employee(1001,"Alice","2329@qq.com",1,new Department(101,"教学部")));
employees.put(1002,new Employee(1002,"Bob","232309@qq.com",1,new Department(102,"市场部")));
employees.put(1003,new Employee(1003,"Coke","32309@qq.com",1,new Department(103,"教学部")));
employees.put(1004,new Employee(1004,"Dice","22309@qq.com",1,new Department(104,"运营部")));
employees.put(1005,new Employee(1005,"Eric","23239@qq.com",1,new Department(105,"后勤部")));
}
/*主键自增*/
public static Integer initId = 1006;
/*用户新增*/
public void addEmployee(Employee employee){
if(employee.getId()==null){
employee.setId(initId++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(),employee);

}
/*获取所有员工信息*/
public Collection<Employee> getAll(){
return employees.values();
}
/*id查询员工*/
public Employee getEmployeeById(Integer id){
return employees.get(id);
}
/*id删除用户*/
public void deleteEmployeeById(Integer id){
employees.remove(id);
}
}

2.首页访问

1
2
3
4
5
6
7
8
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>
<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label class="sr-only">Username</label>
<input type="text" class="form-control" placeholder="Username" required="" autofocus="">
<label class="sr-only">Password</label>
<input type="password" class="form-control" placeholder="Password" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>
</body>
</html>

3.国际化

  • IDEA->Setting->File Encoding(UTF-8)
  • 安装ResourceBundle Editor插件(用于编辑本地化的属性文件(localized properties files),同时管理所有相关联属性文件中的key/value信息 IDEA右下角Resource Bundle)
  • 在Resource文件夹下新建i18n文件夹,加入配置文件
1
2
3
4
5
6
# login.properties
login.tip=登录
login.password=密码
login.remember=记住
login.username=用户名
login.btn=登录
1
2
3
4
5
6
# login_en_US.properties
login.tip=Sign in
login.password=password
login.remember=Remember
login.username=username
login.btn=Sign in
1
2
3
4
5
6
# login_zh_CN.properties
login.tip=Sign in
login.password=password
login.remember=Remember
login.username=username
login.btn=Sign in
1
2
3
4
5
6
7
8
# application.properties
# 关闭thymeleaf模板引擎缓存
spring:
thymeleaf:
cache: false
# Spring Boot looks for the presence of a messages resource bundle at the root of the classpath.
messages:
basename: i18n.login
  • 更改页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<!-- Custom styles for this template -->
<link th:href="@{/css/signin.css}" rel="stylesheet">
</head>

<body class="text-center">
<form class="form-signin" action="dashboard.html">
<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" class="form-control" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" th:text="#{login.remember}">
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm" th:href="@{/index(lang='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index(lang='en_US')}">English</a>
</form>
</body>
</html>
  • 自定义LocalResovler组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest request) {
String language = request.getParameter("lang");
Locale locale = Locale.getDefault(); /*无参数默认*/
/*请求是否含有国际化参数*/
if(!StringUtils.isEmpty(language)){
String[] split = language.split("_");
locale = new Locale(split[0],split[1]);
}
return locale;
}

@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
  • 组件注册Spring容器
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}

4.登录

  • 修改页面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<form class="form-signin" th:action="@{/user/login}">
<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
<label class="sr-only" th:text="#{login.username}">Username</label>
<input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<label class="sr-only" th:text="#{login.password}">Password</label>
<input type="password" name="password" class="form-control" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" th:text="#{login.remember}">
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm" th:href="@{/index(lang='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index(lang='en_US')}">English</a>
</form>
  • 编写Controller类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model
){
if(!StringUtils.isEmpty(username)&&password.equals("root")){
return "redirect:/main.html";
}else{
model.addAttribute("msg","用户名或者密码错误");
return "index";
}

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}

5.登录拦截

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model, HttpSession session){
if(!StringUtils.isEmpty(username)&&password.equals("root")){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}else{
model.addAttribute("msg","用户名或者密码错误");
return "index";
}

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LoginHandlerIntercept implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*登录成功 用户session*/
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser==null){
request.setAttribute("msg","请先登录");
request.getRequestDispatcher("/index").forward(request,response);
return false;
}else{
return true;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerIntercept())
.addPathPatterns("/**")
.excludePathPatterns("/index","/","/user/login","/static/**");
/*.excludePathPatterns("/index","/","/user/login","/css/*","/js/*","/img/*");*/
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
<!--dashboard.html-->
<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Dashboard Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="/css/dashboard.css" rel="stylesheet">
<style type="text/css">
/* Chart.js */
@-webkit-keyframes chartjs-render-animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
@keyframes chartjs-render-animation {
from {
opacity: 0.99
}
to {
opacity: 1
}
}
.chartjs-render-monitor {
-webkit-animation: chartjs-render-animation 0.001s;
animation: chartjs-render-animation 0.001s;
}
</style>
</head>
<body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
<div class="container-fluid">
<div class="row">
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
Customers
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Year-end sale
</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<div class="chartjs-size-monitor" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: hidden; pointer-events: none; visibility: hidden; z-index: -1;">
<div class="chartjs-size-monitor-expand" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
<div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div>
</div>
<div class="chartjs-size-monitor-shrink" style="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;">
<div style="position:absolute;width:200%;height:200%;left:0; top:0"></div>
</div>
</div>
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group mr-2">
<button class="btn btn-sm btn-outline-secondary">Share</button>
<button class="btn btn-sm btn-outline-secondary">Export</button>
</div>
<button class="btn btn-sm btn-outline-secondary dropdown-toggle">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
This week
</button>
</div>
</div>
<canvas class="my-4 chartjs-render-monitor" id="myChart" width="1076" height="454" style="display: block; width: 1076px; height: 454px;"></canvas>
</main>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="/js/jquery-3.2.1.slim.min.js" ></script>
<script type="text/javascript" src="/js/popper.min.js" ></script>
<script type="text/javascript" src="/js/bootstrap.min.js" ></script>
<!-- Icons -->
<script type="text/javascript" src="/js/feather.min.js" ></script>
<script>
feather.replace()
</script>
<!-- Graphs -->
<script type="text/javascript" src="/js/Chart.min.js" ></script>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
datasets: [{
data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
lineTension: 0,
backgroundColor: 'transparent',
borderColor: '#007bff',
borderWidth: 4,
pointBackgroundColor: '#007bff'
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
}
}]
},
legend: {
display: false,
}
}
});
</script>
</body>
</html>

注解

  • @Autowired:byType方式实现依赖注入

  • @component:可将pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>,可代表各种组件,当类不属于各种归类(如@Controller、@Services等),可以使用@Component来标注这个类。

  • @ConfigurationProperties:用于外部化配置,如果要绑定和验证某些外部属性(如 .properties),可将其添加到类定义或类中的方法。绑定通过调用带注释的类上的 setter 实现。如果使用@ConstructorBinding,则通过绑定到构造函数参数来执行。可将配置文件中配置属性的值,映射到该组件中,即该类中的属性和配置文件中相关配置进行绑定。The prefix of the properties that are valid to bind to this object.

  • @Resource:byName方式实现依赖注入