Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
SpringBoot框架中还有两个非常重要的策略:开箱即用和约定优于配置。开箱即用,Outofbox,是指在开发过程中,通过在MAVEN项目的pom文件中添加相关依赖包,然后使用对应注解来代替繁琐的XML配置文件以管理对象的生命周期。这个特点使得开发人员摆脱了复杂的配置工作以及依赖的管理工作,更加专注于业务逻辑。约定优于配置,Convention over configuration,是一种由SpringBoot本身来配置目标结构,由开发者在结构中添加信息的软件设计范式。这一特点虽降低了部分灵活性,增加了BUG定位的复杂性,但减少了开发人员需要做出决定的数量,同时减少了大量的XML配置,并且可以将代码编译、测试和打包等工作自动化。
SpringBoot应用系统开发模板的基本架构设计从前端到后台进行说明:前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它们都是用Java语言编写的,渲染模板并输出相应文本,使得界面的设计与应用的逻辑分离,同时前端开发还会使用到Bootstrap、AngularJS、JQuery等;在浏览器的数据传输格式上采用Json,非xml,同时提供RESTfulAPI;SpringMVC框架用于数据到达服务器后处理请求;到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架;数据库常用MySQL;开发工具推荐IntelliJIDEA。
优点:Spring是java企业版(J2EE)的轻量级替代品,无需开发重量级的Enterprise javaBean(EJB),Spring为企业级java开发提供了一个相对简单的方法,通过依赖注入和面向切面编程,用简单的java对象(Plain old java object,pojo)实现了EJB的功能。
缺点:Spring虽然简化了不少代码的编写,但是也增加了配置文件的编写以及注解的编写,此外,项目的依赖管理也很麻烦,在环境搭建时,需要分析导入哪些库的坐标,还要分析导入与之有依赖关系的其他库的坐标,一旦选择错了要依赖的版本,就会阻碍项目的开发。
SpringBoot对Spring的缺点进行改善和优化,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行切换,全身心地投入到逻辑业务的代码编写中,大大提高了效率。
SpringBoot要求,项目需要继承SpringBoot的起步依赖spring-boot-starter-parent,往maven项目的pom.xml添加一下代码
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.1.RELEASEversion>
parent>
SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖。springboot进行web开发只需要导入web的启动依赖,它内部已经帮我们完成了整合spring跟springmvc了。
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
新建一个包com.springboot,在这个包下新建一个类名为MySpringBootApplication,并在类上加上注解@SpringBootApplication,将其声明为一个引导类,并且通过SpringApplication.run方法来运行以下这个引导类。通过控制台我们可以发现tomcat已经启动了。
package com.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApplication.class);
}
}
新建一个包com.springboot.controller,在这个包下新建一个Controller类,里面有一个方法返回一个字符串,这个类要跟引导类放在同一个包下
package com.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
@RequestMapping("hello")
@ResponseBody
public String hello() {
return "hello spirngboot";
}
}
运行引导类之后,项目就被发布到tomcat上了,但是有的时候发布完之后我们又重新对项目的代码进行了修改,这个时候又得重新运行引导类来更新以下发布的项目。我们可以通过springboot工程热部署来解决这个问题,让springboot项目自动更新加载。实现很简单,就是在项目的pom.xml中添加一个坐标。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
添加完之后,尝试修改controller返回的字符串,修改后直接刷新一下浏览器的页面,发现自动更新了。
需要注意的是,使用IDEA进行SpirngBoot热部署的话可能不能实现,应该IDEA默认是不自动编译的,需要到设置中去修改。到Compiler勾选上build project automatically。然后Ctrl+Shift+Alt+/,选择Registry,勾选compiler automake.allow.when.app.running即可。
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.4.RELEASEversion>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
新建的项目还自动帮我们生成了引导类。跟我们手动创建的一模一样。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
然后编写一个Controller,测试一下是否可用,注意controller需要跟引导类在同一个包下,这里Controller用的是注解是@RestController,这个注解结合@Controller跟@ResponseBody,这样的这个Controller类下的方法就不用加@ResponseBody了,默认返回的都是字符串或者json格式字符串的回显:
package com.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("test")
public String test() {
return "test";
}
}
运行引导类,访问local host:8080/test,页面会显示test字符串。
每个springboot项目都需要添加一个起步依赖spring-boot-starter-parent到pom.xml中,我们到pom.xml按ctrl+左键进到里面去看看。
可以发现,里面引入了resources目录下的所有以application开头的,以yml或者yaml或者properties结尾的文件,如果resources内没有这些配置文件的话,就会引用默认的,这也就是说,当我们不想使用默认的,可以在resources目录下新建这些配置文件。
<resource>
<filtering>truefiltering>
<directory>${basedir}/src/main/resourcesdirectory>
<includes>
<include>**/application*.ymlinclude>
<include>**/application*.yamlinclude>
<include>**/application*.propertiesinclude>
includes>
resource>
再往下看都是配置了一些插件。
在spring-boot-starter-parent中,还有一段以下的代码,代表了起步依赖继承了依赖spring-boot-dependencies:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.4.RELEASEversion>
<relativePath>../../spring-boot-dependenciesrelativePath>
parent>
打开spring-boot-dependencies,会发现很多很多的版本锁定配置,也就是说,springboot给可能会用到的一些依赖包的版本都做好了设定,这就解决了在创建maven项目的时候,添加的依赖包版本不一致的问题。
此外,我们创建的springboot项目要是想实现web功能,还需要加入一个起步依赖spring-boot-starter-web,打开这个依赖,能够发现里面对tomcat、json、spring-web、springmvc等都进行了配置。
可以看到,起步依赖其实就是将我们所想要实现的功能所需要的依赖包的坐标进行打包,然后我们将这些打包的坐标一次性引入,这样就节省很多工作。
SpringBoot能够实现自动配置,很大原因是源于引导类上的注解@SpringBootApplication,我们打开这个注解看一下里面的代码。
可以看到这个注解上还加了很多的注解,其中:
SpringBoot是基于约定的,很多配置都有默认值,但如果我们想要修改这些配置,就可以通过在项目下resources目录下使用applicaiton.properties或者application.yml(yaml)进行配置。按照起步依赖内的引入顺序,如果同时配置了properties文件和yml文件,propeties会覆盖yml的配置。
前面说到的@EnableAutoConfiguration注解中涉及到的自动配置的默认配置文件有的来自于spring-boot-autoconfigure包,打开这个包下的spring-configuration-metadata.json,可以看到很多json格式的字符串,里面包含着springboot自动配置的一些默认设置。假如我们想要修改的这些默认的配置,可以在resources目录下新建一个application.properties,将要修改的配置以键值对的形式存放到里面。
比如修改默认的端口号,在spring-configuration-metadata.json下有这么一段:
{
"name": "server.port",
"type": "java.lang.Integer",
"description": "Server HTTP port.",
"sourceType": "org.springframework.boot.autoconfigure.web.ServerProperties",
"defaultValue": 8080
}
我们到application.properties里面增加一行,springboot会自动读取这个配置文件然后进行修改。这样的话,下次访问该项目所使用的端口号就不是默认的8080了。
server.port=8888
除此之外,当springboot跟项目集成的话,我们还需要利用这些配置文件提供一些配置信息,比如数据库驱动、数据库的用户名跟密码等等。
YML文件格式是YAML(YAML Aint Markup
Language)编写的文件格式,YAML是一种直观的能够被电脑识别的数据序列化格式,容易被人类阅读、容易和脚本语言交互,可以被支持YAML库的不同的编程语言导入,如C/C++,Ruby,Python,Java、Perl、C#、PHP等。以数据为核心,比传统的xml文件更简洁。YML文件的扩展名为.yml或.yaml。
在使用之前,我们要先掌握一些YML文件的语法,知道该如何使用。
第一种是配置普通数据,它是一种key: value的形式,但需要注意的是value前要有一个空格。比如:
name: zhangsan
第二种是配置对象数据,它是以下的一种形式,有一种从级关系,key1和key2前面的空格数量任意,但需要数量一致才能保持同一级关系,key1跟key2后面的冒号仍然需要加一个空格。
key:
key1: value1
key2: value2
以修改springboot默认配置端口为例,我们在application.yml种加入以下代码,就可以达到修改端口号的目的。
server:
port: 8888
配置对象数据还能使用一种方式称为行内对象配置,方式如下,注意冒号后面都需要加空格:
key: {key1: value1,key2: value2}
以修改端口号为例,就是:
server: {port: 8081}
配置数组或者List、Set集合的话就用以下这种方式,需要在值前面增加一个小横杆,横杆后要加一个空格:
key:
- value1
- value2
- value3
举个例子:
persons:
- zhangsan
- lisi
- wangwu
或者用这种方式:
key: [value1,value2,value3]
举个例子:
persons: [zhangsan,lisi,wangwu]
以上的数据或集合里面的对象都是字符串类型,如果想要存放一个对象的话,用以下形式,一个横杆代表一个对象,同样,只要出现啊了冒号的地方就要加上一个空格:
key:
- key1: value1
key2: value2
- key1: value1
key2: value2
举个例子:
persons:
- name: zhangsan
age: 17
- name: lisi
age: 18
- name: wangwu
age: 19
用行内配置的话就是这种形式:
key: [{key1: value1,key2: value2},{key1: value1,key2: value2}]
举个例子:
persons: [{name: zhangsan,age: 17},{name: lisi,age:18},{name: wangwu, age: 19}]
配置Map集合的话就用以下的形式,跟配置对象数据的形式是一样的,只不过所表达的意思不太一样,配置对象数据指的是这个对象里面的属性和对应的值,而map集合的话就是一个个键值对:
key:
key1: value1
key2: value2
在上面我们讲了如何给springboot修改或增加一些配置,当我们配置springboot中默认就带有的数据时,springboot就能自动识别出来并进行修改,但是当我们配置的springboot不带有的数据时,springboot识别不出来,就需要通过注解来映射数据达到使用的目的了。
当在application.yml文件中,配置了一个普通数据:
name: zhangsan
现在我们要在Controller类中使用这个配置好的信息,并不能够直接使用,而是要用到@Value注解。如下面,@Value注解括号内用双引号包住一个EL表达式${},表达式里面是键的名称,这样就会自动从Spring容器中拿出实例对象用来注入。
package com.springboot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${name}")
private String name;
@RequestMapping("test")
public String test() {
return name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示zhangsan。
当在application.yml中配置了对象数据时,且需要使用到对象的某一个属性时,使用@Value注解时,通过EL表达式访问数据时,要通过点来访问到对象的属性:
person:
name: lisi
age: 18
package com.springboot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${person.name}")
private String name;
@RequestMapping("test")
public String test() {
return name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示lisi。
当在application.yml中配置了数组、集合数据时,使用@Value注解时,通过EL表达式访问数据时,要通过点和下标来访问到对象的属性:
当数组集合存放的是字符串时,用下标来访问:
persons:
- zhangsan
- lisi
- wangwu
package com.springboot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${persons[2]}")
private String name;
@RequestMapping("test")
public String test() {
return name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示wangwu。
当数组、集合存放的是对象时,用下标结合点来访问:
persons:
- name: zhangsan
age: 17
- name: lisi
age: 18
- name: wangwu
age: 19
package com.springboot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@Value("${persons[2].age}")
private String name;
@RequestMapping("test")
public String test() {
return name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示19。
总的来说,使用@Value注解能够精确匹配,但是比较繁琐。
除了使用@Value注解,我们还可以使用@ConfigurationProperties来进行配置文件与类的映射,进而使用配置文件内配置的东西。
当在application.yml文件中,配置了一个普通数据:
name: zhangsan
我们只需要在需要使用这个数据的类中声明一个变量,且变量名跟键名一致,然后提供这个变量的getter、setter方法,并且在类上加上注解@ConfigurationProperties,springboot就会自动到配置文件中寻找并注入。
package com.springboot.controller;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@ConfigurationProperties
public class TestController {
private String name;
@RequestMapping("test")
public String test() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示zhangsan。
当在application.yml中配置了对象数据时,并且需要使用到对象的某一个属性时:
person:
name: lisi
age: 18
我们需要提供的跟配置普通数据几乎是一样的,但是需要给@ConfigurationProperties加上参数prefix,也就是加上一个前缀,前缀就是对象的名称。
package com.springboot.controller;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@ConfigurationProperties(prefix = "person")
public class TestController {
private String name;
@RequestMapping("test")
public String test() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示lisi。
当在application.yml中配置了数组、集合数据时,且当数组、集合存放的是对象时,用下标结合点来当前缀:
persons:
- name: zhangsan
age: 17
- name: lisi
age: 18
- name: wangwu
age: 19
package com.springboot.controller;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@ConfigurationProperties(prefix = "persons[2]")
public class TestController {
private String name;
@RequestMapping("test")
public String test() {
return name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行引导类,访问呢localhost:8080/test,页面就会显示wangwu。
我们在使用注解@ConfigurationProperties的时候,会出现一个警告,提示我们让我们安装spring-boot-configuration-processor,其实就是在pom.xml中添加一个依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
添加了这个注解执行器之后,我们可以反向配置,也就是现在类中配置所需要的属性,以及它的前缀是什么,然后再到application.yml配置文件中配置,使用Alt+/会有联想功能。
利用eclipse新建一个项目,实现web功能:
然后接下就是开始整合的步骤了:
在项目的pom.xml中添加以下依赖
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.1.1version>
dependency>
在项目的pom.xml中添加以下依赖,不需要添加版本,在springboot的起步依赖中一定设置好了版本
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
到配置文件application.properties中去添加数据库的连接信息,springboot中已经给我们设定好了格式,在先前提到的spring-configuration-metadata.json可以找到,我们直接使用即可。
在application.properties中添加如下信息:
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
随意创建一张数据库表(mysql内执行)
创建实体类User,并且提供getter、setter方法以及toString方法
package com.springboot.domain;
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
}
}
新建一个包mapper,在这个包下新建一个Mapper接口UserMapper,并且在接口上加上一个注解@Mapper,里面提供了一个查询数据库中所有用户的方法,注意mapper包要跟引导类在同一个包下。
package com.springboot.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.springboot.domain.User;
@Mapper
public interface UserMapper {
public List<User> selectAllUser();
}
在resources文件夹下新建一个mapper文件夹,在这个文件夹下新建一个mapper映射文件UserMapper.xml
<mapper namespace="com.springboot.mapper.UserMapper">
<select id="selectAllUser" resultType="user">
select * from user
select>
mapper>
还需要往application.properties添加mybatis的配置信息,让springboot与mybatis发生连接。配置的格式springboot也给我们规定好,在mybatis-spring-boot-autoconfigure包下可以查找。
# pojo别名扫描
mybatis.type-aliases-package=com.springboot.domain
# 加载mybatis映射文件
mybatis.mapper-locations=mapper/*Mapper.xml
新建一个controller包,在包下新建一个TestController类,注意controller包要跟引导类在同一个包下。
package com.springboot.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.springboot.domain.User;
import com.springboot.mapper.UserMapper;
@Controller
public class TestController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/test")
@ResponseBody
public List<User> selectAllUser(){
List<User> users = userMapper.selectAllUser();
return users;
}
}
10.运行引导类,访问页面。
访问localhost:8080/test,页面会显示
[{“id”:1,“username”:“zhangsan”,“password”:“123”},{“id”:2,“username”:“lisi”,“password”:“123”}]
这里使用的是SpringBoot整合MyBatis时所使用的项目,使用Junit将数据库的数据查询出来。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
package com.springboot;
import java.util.List;
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.SpringRunner;
import com.springboot.domain.User;
import com.springboot.mapper.UserMapper;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootMybatisApplication.class)
public class TestSpringBoot {
@Autowired
private UserMapper userMapper;
@Test
public void test() {
List<User> list = userMapper.selectAllUser();
for (User user : list) {
System.out.println(user);
}
}
}