Sprgin Boot指南——入门

入门材料

  1. 官网: spring.io

  2. 入门索引

    Spring Boot中文索引

  3. 推荐:大致了解Spring Boot视频教程:

    2小时学会Spring Boot

    Spring Boot进阶之Web进阶 代码

  4. 关于Spring Boot整合其他技术的视频教程:

    SpringBoot开发常用技术整合

    代码

  5. 一步一步详细开发的博客系列:

    Spring Boot教程与Spring Cloud开源教程-SpringBoot-Learning

    Spring Boot 揭秘与实战 系列

快速开始

开发环境:IntelliJ IDEA、Spring Boot 1.5.11、JDK 1.8

  1. New Project

    new_project

  2. 工程配置

  3. 选择Spring Boot组件,此处选择最简单的Web。

  4. 编写Controller

  5. 运行

    运行应用,此处Debug运行:

运行结果如下:

Web开发

数据访问

JdbcTemplate访问数据库

注意:Spring Boot 版本未1.5.11

  1. 添加依赖

    首先,为了连接数据库需要引入jdbc支持,在pom.xml中引入如下配置:

(注:要获取最新的mysql connector版本,请参考这里)

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--以MySQL数据库为例,先引入MySQL连接的依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
  1. 数据库配置

    application.properties中配置数据源信息:

1
2
3
4
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=ipad
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  1. 访问数据库

    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
    public interface UserService {
    void create(String name, Integer age);
    void deleteByName(String name);
    Integer getAllUsers();
    void deleteAllUsers();
    }

    @Service
    public class UserServiceImpl implements UserService{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void create(String name, Integer age) {
    jdbcTemplate.update("insert into USER(NAME, AGE) values(?, ?)", name, age);
    }

    @Override
    public void deleteByName(String name) {
    jdbcTemplate.update("delete from USER where NAME = ?", name);
    }

    @Override
    public Integer getAllUsers() {
    return jdbcTemplate.queryForObject("select count(1) from USER", Integer.class);
    }

    @Override
    public void deleteAllUsers() {
    jdbcTemplate.update("delete from USER");
    }
    }
  2. 测试

    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
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @WebAppConfiguration
    public class UserServiceTest {

    @Autowired
    private UserService userSerivce;

    @Before
    public void setUp() {
    // 准备,清空user表
    userSerivce.deleteAllUsers();
    }

    @Test
    public void test() throws Exception {
    // 插入5个用户
    userSerivce.create("a", 1);
    userSerivce.create("b", 2);
    userSerivce.create("c", 3);
    userSerivce.create("d", 4);
    userSerivce.create("e", 5);

    // 查数据库,应该有5个用户
    Assert.assertEquals(5, userSerivce.getAllUsers().intValue());

    // 删除两个用户
    userSerivce.deleteByName("a");
    userSerivce.deleteByName("e");

    // 查数据库,应该有5个用户
    Assert.assertEquals(3, userSerivce.getAllUsers().intValue());

    }
    }
  3. 相关错误处理

    • 假如遇到No Beans of 'UserService' type found之类的错误提示:

在Application main函数中添加要扫描的包,其路径为beans的目录即可,如下:

1
2
3
4
5
6
@SpringBootApplication(scanBasePackages = "com.example")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

整合MyBatis

分页插件:MyBatis-Spring-Boot]( https://github.com/abel533/MyBatis-Spring-Boot)

假如无法匹配mapper,添加扫描配置@MapperScan如下:

1
2
3
4
5
6
7
8
@SpringBootApplication(scanBasePackages = "com.example.*")
@MapperScan(basePackages = { "com.example.mapper" }, sqlSessionFactoryRef = "sqlSessionFactory")
public class DemoApplication {

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

显示Sql日志

方案一:在yml中配置如下:

com.luci.beefun.mybatis.mapper是mapper路径。

1
2
3
logging:
level:
com.luci.beefun.mybatis.mapper : debug

方案二:直接针对mybatis日志配置。

1
2
3
4
5
6
mybatis:
type-aliases-package: com.luci.beefun.model
mapper-locations: classpath:mapper/*.xml
#日志显示SQL的执行情况
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

Mybatis generator

mybatis generator插件

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
<!--mybatis自动生成代码插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<!-- 是否覆盖 -->
<overwrite>true</overwrite>
<!--允许移动生成的文件 -->
<verbose>true</verbose>
<!-- 自动生成的配置,${basedir}表示项目根目录 ,configurationFile默认在resource目录下-->
<configurationFile>src/main/resources/mybatis/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!--集成通用mapper依赖-->
<!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<!-- 通用 Mapper -->
<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.5.3</version>
</dependency>
</dependencies>
</plugin>

上面指定了配置文件generatorConfig.xml如下:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
<!--配置参考地址:http://www.mybatis.org/generator/configreference/xmlconfig.html-->
<!--配置参考地址http://blog.csdn.net/pk490525/article/details/16819307-->
<!--配置参考:http://blog.csdn.net/lirui874125/article/details/49589563-->
<!--配置参考:http://www.jianshu.com/p/e09d2370b796-->


<!-- 引入配置文件 -->
<properties resource="mybatis/generator.properties"/>
<!-- 指定数据连接驱动jar地址 -->
<!-- <classPathEntry location="/Program Files/IBM/SQLLIB/java/db2java.zip" />-->

<!--
context:生成一组对象的环境
id:必选,上下文id,用于在生成错误时提示
defaultModelType:指定生成对象的样式
1,conditional:类似hierarchical;
2,flat:所有内容(主键,blob)等全部生成在一个对象中;
3,hierarchical:主键生成一个XXKey对象(key class),Blob等单独生成一个对象,其他简单属性在一个对象中(record class)
targetRuntime:
1,MyBatis3:默认的值,生成基于MyBatis3.x以上版本的内容,包括XXXBySample;
2,MyBatis3Simple:类似MyBatis3,只是不生成XXXBySample;
introspectedColumnImpl:类全限定名,用于扩展MBG
-->

<context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
<!--https://mapperhelper.github.io/docs/3.usembg/,自动生成代码的通用mapper插件-->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
<!-- caseSensitive默认false,当数据库表名区分大小写时,可以将该属性设置为true -->
<!-- <property name="caseSensitive" value="true"/>-->
</plugin>
<!-- 注释 -->
<commentGenerator >
<!-- 是否取消自动生成的注释 -->
<!--<property name="suppressAllComments" value="false"/>-->
<!-- 是否生成注释代时间戳-->
<!-- <property name="suppressDate" value="true" />-->
</commentGenerator>

<jdbcConnection driverClass="${jdbc_driver}"
connectionURL = "${jdbc_url}"
userId="${jdbc_user}"
password="${jdbc_password}">
<!-- 针对mysql数据库 -->
<property name="useInformationSchema" value="true"/>
</jdbcConnection>

<!-- 类型转换 -->
<javaTypeResolver >
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>

<!-- 生成实体类地址 -->
<javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<!--<property name="enableSubPackages" value="true" />-->
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<!--<property name="trimStrings" value="true" />-->
</javaModelGenerator>

<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="${targetXMLPackage}" targetProject="${targetResourcesProject}">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<!-- <property name="enableSubPackages" value="true" />-->
</sqlMapGenerator>

<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator type="XMLMAPPER" targetPackage="${targetMapperPackage}" targetProject="${targetJavaProject}">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<!--<property name="enableSubPackages" value="true" />-->
</javaClientGenerator>

<!-- 配置表信息 -->
<!-- schema即为数据库名 tableName为对应的数据库表 domainObjectName是要生成的实体类 enable*ByExample
是否生成 example类 -->
<!--<table schema="jack" tableName="ALLTYPES" domainObjectName="Customer" >-->
<!-- <property name="useActualColumnNames" value="true"/>
<generatedKey column="ID" sqlStatement="DB2" identity="true" />
<columnOverride column="DATE_FIELD" property="startDate" />-->
<!-- 忽略列,不生成bean 字段 -->
<!--<ignoreColumn column="FRED" />-->
<!-- 指定列的java数据类型 -->
<!-- <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" />-->
<!-- </table>-->
<table tableName="repos" domainObjectName="Repository" />

</context>
</generatorConfiguration>

其中涉及到的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#Mybatis Generator configuration

targetJavaProject =src/main/java
targetResourcesProject=src/main/resources

jdbc_driver =com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/beefun
jdbc_user=root
jdbc_password=****


targetModelPackage=com.luci.beefun.model
targetMapperPackage=com.luci.beefun.mapper
#对应的Mappper XML地址,需要在yml中配置
targetXMLPackage=mapper

完成以上配置后,在终端输入:

1
$ mvn mybatis-generator:generate -e

就应该能在**.model和**.mapper路径下获取到对应的文件。

如果报错,说找不到对应的mapper,在Application中添加:

1
2
3
4
5
@SpringBootApplication(scanBasePackages = "com.luci.beefun.*")
@MapperScan(basePackages = "com.luci.beefun.mapper")
public class Application implements CommandLineRunner {
// ******
}

另外,假如说无法访问:

[ERROR] Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.5:generate (default-cli) on project beefun: Access denied for user ‘root’@’localhost’ (using password: YES) -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.5:generate (default-cli) on project beefun: Access denied for user ‘root’@’localhost’ (using password: YES)

则注意generatorConfig.xml 中数据库密码的配置。

Mybatis 分页插件

https://pagehelper.github.io/docs/howtouse/

注意:假如分页到最后一页一直返回有数据,则将下面字段reasonable置为false:

1
2
3
4
5
6
#配置参考: https://pagehelper.github.io/docs/howtouse/
pagehelper:
helperDialect: mysql
reasonable: false
supportMethodsArguments: true
params: count=countSql

数据缓存

整合Redis

日志管理

消息队列

发布部署

Jar包

确认pop.xml有maven插件,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

然后在项目目录下执行:

1
$ maven package

就会在当前项目目录下生成jar包。

运行jar包:

1
$ java -jar xxx.jar

通过命令行设置属性值

相信使用过一段时间Spring Boot的用户,一定知道这条命令:java -jar xxx.jar --server.port=8888,通过使用–server.port属性来设置xxx.jar应用的端口为8888。

在命令行运行时,连续的两个减号--就是对application.properties中的属性值进行赋值的标识。所以,java -jar xxx.jar --server.port=8888命令,等价于我们在application.properties中添加属性server.port=8888,该设置在样例工程中可见,读者可通过删除该值或使用命令行来设置该值来验证。

Spring Boot也贴心的提供了屏蔽命令行访问属性的设置,只需要这句设置就能屏蔽:SpringApplication.setAddCommandLineProperties(false)

另外一种场景,假如需要执行不同环境配置可以如下:

1
$ java -jar xxx.jar --spring.profiles.active=dev

单元测试

错误集合

  1. Error starting ApplicationContext. To display the auto-configuration report re-run your application with ‘debug’ enabled.

    在一些情况下Spring Boot的自动化配置也会给我们惹来不少的麻烦,比如这些场景:

    • 项目依赖复杂的情况下,由于依赖方的依赖组织不够严格,可能引入了一些实际我们不需要的依赖,从而导致我们的项目满足一些特定的自动化配置。
    • 传统Spring项目转换为Spring Boot项目的过程中,由于不同的组织方式问题,引发自动化配置加载的错误,比如:通过xml手工组织的多数据源配置等。

    上面这些原因都会导致不必要的自动化配置加载而导致应用无法启动或触发/health的健康检查不通过等问题。比如,我们在改造传统Spring项目到Spring Boot项目中碰到的一些错误:

    1
    2
    3
    4
    5
    6
    7
    Description:

    Cannot determine embedded database driver class for database type NONE

    Action:

    If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).

    从报错信息中,我们就可以分析出错误原因是触发了数据源的自动化配置,然而当前项目其实并不需要数据源。查其根源是依赖方提供的API依赖中引用了一些多余的依赖触发了该自动化配置的加载。

2.Spring Boot Autowired null

​ SpringBoot在自定义类中调用service层等Spring其他层,使用Autowired时,通过以下方式调用,一直返回null。

1
2
3
4
5
6
7
8
9
@Component
public class ExploreTopicNetwork {
@Autowired
private DBTopicService dbTopicService;
}

//调用
ExploreTopicNetwork topicNetwork = new ExploreTopicNetwork();
topicNetwork.startParseTopicList();

​ 失败原因:如果采用new ExploreTopicNetwork();这种方式调用,Spring 自动装配会失效。参考Spring Boot Autowired null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class ExploreTopicNetwork {
@Autowired
private DBTopicService dbTopicService;

private static ExploreTopicNetwork exploreTopicNetwork;

@PostConstruct //通过@PostConstruct实现初始化bean之前进行的操作
public void init() {
exploreTopicNetwork = this;
exploreTopicNetwork.dbTopicService = this.dbTopicService;
// 初使化时将已静态化的dbTopicService实例化
}

//测试调用
public void test(){
exploreTopicNetwork.dbTopicService.<你的service层方法>;
}

​ 将需要调用Spring的Service层的类通过@Component注解为组件加载; 

​ 同样通过@Autowired获取Service层的Bean对象,为类声明一个静态变量,方便下一步存储bean对象;

​ 划重点:通过注解@PostConstruct ,在初始化的时候初始化静态对象和它的静态成员变量dbTopicService,原理是拿到service层bean对象,静态存储下来,防止被释放。

​ 以上参考引用:SpringBoot在自定义类中调用service层等Spring其他层

https://stackoverflow.com/questions/26461697/spring-boot-autowired-null