- 一、SpringBoot简介
- 二、Java EE应用与Spring
- 三、SpringBoot优势
- 四、SpringBoot应用打包类型
- 五、pom.xml文件
- 六、编写控制器
- 七、定义视图页面
- 八、运行应用
- 九、创建可执行的JAR包
- 十、执行JAR包启动SpringBoot应用
- 十一、Maven生命周期
- 十二、开发业务组件
- 十三、开发DAO组件
- 十三、编写单元测试
- 1.测试RESTful接口
创建第一个SpringBoot应用:
- IDEA 创建第一个Springboot程序
Springboot是Java企业开发里最流行的框架,它为各种第三方框架的快速整合提供了自动配置,一旦用上了SpringBoot,开发者只需专注于应用中业务逻辑功能的实现。
二、Java EE应用与SpringSpring是Java领域中应用最广的框架,从本质上说:
- Spring只是一个组件容器,负责创建并管理容器中的组件(称为Bean),并管理组件之间的依赖关系。
- 由于Spring将容器功能做到了极致,Java EE应用所涉及的以下各种组件,都处于Spring容器的管理之下:
- 前端控制器组件
- 安全组件
- 业务逻辑组件
- 消息组件
- DAO组件(Spring也称其为Repository)
- 连接数据库的基础组件(如DataSource、ConnectionFactory、SessionFactory等)
对于其他各种功能型的框架,它们都需要一个容器来承载其运行,而Spring正是这个不可替代的容器。
关于Java领域中的功能型框架,各方面的功能都存在不少框架可供选择:
- 前端:Spring WebFlux、Spring MVC、Struts2
- 安全领域:Spring Security、Shiro等
- 消息组件:ActiveMQ、RabbitMQ、Kafka等
- 缓存:JCache、EhCache、Hazelcast、Redis等
- 持久层框架:JPA、MyBatis、jOOQ、R2DBC
- 分布式:ZooKeeper、Dubbo等
- NoSQL存储:Redis、MongoDB、Neo4j、Cassandra、Geodo等
- 搜索引擎:Lucene、Solr、Elasticsearch等
- 数据库存储:MySQL、PostgreSQL、Oracle等
- Web服务器:Tomcat、Jetty、Undertow等
作为容器的Spring,是无可替代的,上面列出的这些框架,它们都需要与Spring进行整合,这就是Spring的魅力
传统Spring使用XML配置或注解来管理这些组件,因此搭建一个Java EE应用往往需要进行大量的配置和注解。这些配置工作都属于项目的基础搭建,与业务功能无关,这些工作对于初、中级开发者往往难度不小,很容易出错,在这种背景下,Spring推出了SpringBoot。
三、SpringBoot优势Spring框架唯一的缺点是配置过多,搭建项目时需要进行大量的配置,而SpringBoot的出现,就是为了解决这个问题。
SpringBoot为绝大部分第三方框架的快速整合提供了自动配置,SpringBoot使用约定优先于配置的理念,针对企业应用开发各种场景提供了对应的Starter,开发者只要将该Starter添加到项目的类加载路径中,该Starter即可完成第三方框架的整合。
总体来说:SpringBoot具有以下特性:
- 内嵌Tomcat、Jetty或Undertow服务器,因此SpringBoot应用无需被部署到其他服务器中。
- SpringBoot应用可被做成独立的Java应用程序。
- 尽可能地自动配置Spring及第三方框架。
- 完全没有代码生成,也不需要XML配置
- 提供产品级监控功能,如运行状况检查和外部化配置等
SpringBoot主要功能就是:
- 为Spring及第三方框架的快速启动提供自动配置
- 当Spring及第三方框架整合起来之后,SpringBoot的责任也就完成了
- 在实际开发中发挥功能的依然是前面列出的那些框架和技术
由于SpringBoot内嵌了Tomcat、Jetty或Undertow服务器,因此SpringBoot应用通常不需要被部署到Web服务器中,选择打包成JAR即可。
只有在极个别的情况下,不想使用SpringBoot内嵌服务器,才会考虑将它打包成WAR包(Web应用包),部署到独立的Web服务器中
五、pom.xml文件六、编写控制器4.0.0 com.bigdata.boot boot-helloworld 1.0-SNAPSHOT 8 8 org.springframework.boot spring-boot-starter-parent 2.4.2 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin 2.4.3 org.springframework.boot spring-boot-configuration-processor
SpringBoot的功能只是为整合提供自动配置,因此SpringBoot应用的控制器依然是Spring MVC、Spring WebFlux或Struts 2的控制器,具体定义哪种控制器取决于项目技术栈的前端框架,本例采用Spring MVC作为前端框架,因此这里定义一个Spring MVC的前端控制器类。
@Controller
public class BookController
{
@GetMapping("/")
public String index(Model model)
{
model.addAttribute("tip","欢迎访问第一个SpringBoot应用");
return "hello";
}
@GetMapping("/rest")
@ResponseBody
public ResponseEntity restIndex()
{
return new ResponseEntity<>("欢迎访问第一个springboot应用",null,HttpStatus.OK);
}
}
上面的BookController就是一个再普通不过的Spring MVC的控制器,@Controller、@GetMapping、@ResponseBody注解都是最基本的SpringMVC注解。
- @Controller:用于修饰类,指定该类的实例作为控制器组件
- @GetMapping:用于修饰方法,指定该方法所能处理的Get请求的地址
- @ResponseBody:用于修饰方法,指定该方法生成Restful响应
上面的控制器类中定义了两个处理方法,其中第一个index()方法返回的"hello"字符串只是一个逻辑视图名,因此它还需要物理视图资源。
SpringBoot推荐使用Thymeleaf作为视图模版技术,同时可以使用BootStrap UI库美化界面。
使用前后端分离架构的应用,SpringBoot应用根本不需要生成视图响应,自然也就不需要任何视图模版技术了,在前后端分离架构的应用中,SpringBoot只需要对外提供Restful响应,前端应用则通过Restful接口与后端通信,前端应用负责生成界面,与用户交互。
七、定义视图页面为BookController的第一个处理方法返回的"hello"逻辑视图名定义Thymeleaf视图页面hello.html
SpringBoot默认要求将Thymeleaf视图页面放在resourcetemplates目录下,因此需要将hello.html的视图放在该目录下。由于该页面是为hello逻辑视图名提供视图,因此该页面的文件名为"hello.html".
Thymeleaf视图页面的语法核心设计就是:以“th:”开头的属性来处理表达式的值,比如th:text属性的作用就是用目标HTML元素来显示表达式的值。
八、运行应用package com.bigdata.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MainApplication{
public static void main(String[] args) {
//创建Spring容器,运行SpringBoot应用
SpringApplication.run(MainApplication.class,args);
}
}
调用SpringApplication类的run()方法来创建Spring容器,运行SpringBoot应用。
SpringBoot是基于Spring框架的,而Spring框架最重要的核心就是Spring容器,对于Spring来说,万物都是Bean,而容器就是所有Bean所在的天地,负责管理所有Bean的生死。一个Spring容器就是天地万物,因此所有Spring框架的应用的第一步都是创建Spring容器。
SpringApplication类中run()方法的返回值就是ConfigurableApplicationContext,这就是Spring容器,可见run()方法将会创建并返回Spring容器
有了Spring容器之后,容器中的Bean来自任意用@Configuration注解修饰的Java类(Java配置类,相当于传统的XML配置文件),Spring容器会加载该配置类并创建该配置类中的所有Bean,并且会扫描该配置类相同包或其子包下的所有Bean。
run()方法的第一个参数是MainApplication类,该类应该是带@Configuration注解修饰的配置类。查看@SpringBootConfiguration源码,发现@SpringBootConfiguration就是@Configuration源码。由此可见,@SpringBootApplication注解相当于3个注解的组合版。
- @Configuration:该注解修饰的类将作为Java配置类
- @EnableAutoConfiguration:启用自动配置
- @ComponentScan:指定零配置时扫描哪些包及其子包下的Bean
可见SpringBootConfiguration注解只是一个快捷方式,同时启用了3个注解,从而完成了3个功能:
- 将被修饰的类变成Java配置类
- 启用自动配置
- 定义了Spring容器扫描Bean类的包及其子包
所谓的自动配置,只是SpringBoot提供了预配置。由于SpringBoot提供的预配置,因此开发者无须过多配置即可把项目搭建起来。被@SpringBootApplication修饰的类位于org.crazyit.firstboot包下,因此Spring容器会自动扫描并处理该包及其子包下的所有配置类(@Configuration注解修饰的类)和组件类(@Component、@Controller、@Service、@Repository等注解修饰的类)。
- @Configuration、@Controller、@Service、@Repository等注解的本质都是@Component,Spring容器会扫描@Component修饰的类,将它变成容器中的Bean。
由于前面定义的控制器类BookController位于org.crazyit.firstboot.controller包下,且使用了@Controller修饰,因此Spring容器就能将它加载成容器中的Bean.
九、创建可执行的JAR包由于SpringBoot应用内嵌了Web服务器(Tomcat、Jetty),所以无须将SpringBoot应用部署到其他Web服务器中,SpringBoot应用完全可以独立运行。
在发布SpringBoot应用时,只需要将该应用打包成一个可执行的JAR包,以后就可以使用该JAR包来运行SpringBoot应用了。
为了将SpringBoot应用打包成JAR包,需要保证在pom.xml文件中添加了Spring Boot Maven插件,也就是其中包含如下配置:
org.springframework.boot spring-boot-maven-plugin 2.4.3 org.springframework.boot spring-boot-configuration-processor
只要执行如下两条命令即可生成可执行的JAR包:
mvn clean mvn package
- mvn clean:用于清除所有在构建过程中生成的文件。
- mvn package:指定执行到Maven生命周期的package阶段,用于生成可执行的JAR包
java -jar firstboot-0.0.1-SNAPSHOT.jar十一、Maven生命周期
mvn package命令会从默认生命周期的第一阶段一直执行到package阶段,Maven的默认生命周期包含compile(编译项目)->test(单元测试)->package(项目打包)->install(安装到本地仓库)->deploy(部署到远程)这几个核心阶段
十二、开发业务组件前面控制器的处理方法直接返回了字符串作为响应,这在实际项目中肯定是不行的,实际项目中的控制器要调用业务组件来处理用户响应,因此需要开发一个业务组件来处理用户请求。
业务组件要实现添加图书、删除图书、列出全部图书这三个功能。下面是本例业务组件的接口代码。
serviceBookService.java
public interface BookService
{
List getAllBooks();
Integer addBook(Book book);
void deleteBook(Integer id);
}
该Service组件的实现类则调用DAO组件的方法来实现上述方法。下面是BookService组件的实现类代码。
serviceimplBookServiceImpl.java
@Service
@Transactional(propagation=Propagation.REQUIRED,timeout=5)
public class BookServiceImp1 implements BookService
{
//依赖注入容器中的BookDao组件
@Autowired
private BookDao bookDao;
@Override
public List getAllBooks()
{
return (List) bookDao.findAll();
}
@Override
public Integer addBook(Book book)
{
book.save(book);
return book.getId();
}
@Override
public void deleteBook(Integer id)
{
bookDao.deleteById(id);
}
}
上面第一行粗体字代码使用了@Service注解修饰该实现类,且该类位于org.crazyit.firstboot.service.impl包下,也就是位于FirstbootApplication类所在包的子包下,因此SpringBoot会自动扫描该实现类,并将它配置成容器中的Bean。
上面第二行粗体字代码使用了@Transaction注解修饰该Service组件,该注解指定事务传播规则为REQUIRED,事物超时时长为5秒,Spring将会为该Service组件生成事物代理,从而为该Service组件中的每个方法都添加事务。为目标组件生成事务代理是Spring AOP的功能,但生成事务代码所需要的事务管理器,同样由SpringBoot自动配置提供。
上面第三行粗体字代码使用了@Autowired注解修饰符BookDao实例变量,这也是Spring的基本用法,Spring将会把容器中唯一的、类型为BookDao的Bean注入该实例变量。
下面修改后的BookController类的代码
@Controller
public class BookController
{
@GetMapping("/")
public String index(Model model)
{
model.addAttribute("tip","欢迎访问第一个SpringBoot应用");
return "hello";
}
@GetMapping("/rest")
@ResponseBody
public ResponseEntity restIndex()
{
return new ResponseEntity<>("欢迎访问第一个springboot应用",null,HttpStatus.OK);
}
@Autowired
private BookService bookService;
@PostMapping("/addBook")
public String addBook(Book book,Model model)
{
bookService.addBook(book);
return "redirect:listBooks";
}
@PostMapping("/rest/books")
@ResponseBody
public ResponseEntity
上面的BookController类增加了一个BookService实例变量,且使用了@Autowired注解修饰,因此Spring会将容器中唯一的、类型为BookService的Bean注入该实例变量。
接下来该BookController定义了6个处理方法,这些处理方法使用了@GetMapping、@PostMapping、@DeleteMapping等注解修饰,映射这些处理方法能处理来自不同URL地址的请求。这些注解都属于Spring MVC的基本注解,并不属于SpringBoot。
上面这些方法定义了两个版本,带界面响应的版本和Restful版本,使用@ResponseBody修饰的方法就是用于生成Restful响应的方法。
对于RESTful响应的处理方法,Spring Boot应用无须提供视图页面,在前后端分离的架构中,前端应用会负责提供用户界面、处理用户交互。SpringBoot应用主要暴露RESTful接口即可。
对于要生成界面的处理方法,程序还需要为它们提供视图页面。首先在前面的hello.html页面中增加一个表单,该表单供用户填写图书信息,修改后的hello.html页面代码如下。
在这里插入代码片
上面页面添加了一个Bootstrap样式的表单,该表单的界面看起来会比较美观,该表单的提交地址是addBook,与前面BookController中处理方法定义的处理地址对应。
还需要一个list.html页面用于显示所有图书,该页面代码如下:
在这里插入代码片十三、开发DAO组件
前面BookService中用到了BookDao组件和Boolk类,这些都是与持久化相关的类,本例直接使用SpringBoot Data JPA来访问数据库,为此首先要为项目添加如下依赖:
- SpringBoot Data JPA依赖
- MySQL数据库驱动依赖
增加下面两个依赖:
org.springframework.boot spring-boot-starter-data-jps mysql mysql-connector-java runtime
添加了上面依赖后,重新加载项目依赖库,然后在项目的srcmainapplication目录下添加一个application.properties文件,这个文件是SpringBoot项目的配置文件,当整合不同的项目时,该配置文件支持大量不同的属性,不同的属性也由不同的类处理类负责读取。
#数据库url地址 sparing.datasource.url=jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC #连接数据库的用户名 spring.datasource.username=root #连接数据库的密码 spring.datasource.password=32147 #指定显示SQL语句 spring.jpa.show-sql=true #指定根据实体自动建表 spring.jpa.generate-ddl=true
上面配置文件指定了连接数据库的基本信息:URL地址、用户名和密码,并指定了JPA能根据实体类自动建表,还会显示所执行的SQL语句。
为项目创建一个Book实体类,该实体类代码如下:
firstbookdomainBook.java
@Entity
@Table(name="book_inf")
public class Book
{
@Id
@Column(name="book_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String title;
private String author;
private double price;
//省略getter、setter方法
}
配置文件指定了连接数据库的基本信息,SpringBoot将会自动在容器中配置一个DataSource Bean,SpringBoot将会自动在容器中配置一个EntityManagerFactory Bean。
为项目创建DAO组件:BookDao,该DAO组件接口代码如下:
public interface BookDao extends CrudRepository{ }
该BookDao接口完全是一个空接口,仅仅继承了CrudRepository,实际上已经拥有了大量方法。得益于Spring Data的优秀设计,集成了CrudRepository接口的BookDao不需要提供实现类,Spring Data会自动为它动态生成实现类,并将给实现类的实例部署在Spring容器中,Spring Data还可为BookDao动态增加很多查询方法。
该应用还提供了RESTful接口,可使用Postman来测试RESTful接口。使用Postman向"http://localhost:8080/rest/books"发送GET请求
十三、编写单元测试 1.测试RESTful接口SpringBoot提供了@SpringBootTest注解,该注解用于修饰单元测试用例类。测试用例的测试方法依然使用@Test或@ParameterizedTest注解修饰。
org.springframework.boot spring-boot-starter-test test
该依赖就是指SpringBoot单元测试的依赖库,由于该依赖又依赖JUnit 5.x,因此添加该依赖会自动添加JUnit5依赖。
controllerRandomPortTest.java
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class RandomPortTest
{
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testIndexRest()
{
//测试restIndex方法
var result = restTemplate.getForObject("/rest",String.class);
Assertions.assertEquals("欢迎访问第一个SpringBoot应用")
}
@ParameterizedTest
@CsvSource({"java,fy,180","python,py,160"})
public void testRestAddBook(String title,String author,double price)
{
var book =new Book(title,author,price);
//测试restAddBook方法
var result = restTemplate.postForObject("/rest/books",book,Map.class);
Assertions.assertEquals(result.get("tip"),"添加成功");
}
@Test
public void testRestList()
{
//测试restList方法
var result = restTemplate.getForObject("/rest/books",List.class);
result.forEach(System.out::println);
}
@ParameterizedTest
@ValueSource(ints={4,5})
public void testRestDelete(Integer id){
//测试restDelete方法
restTemplate.delete("/rest/books/{0}",id);
}
}
上面测试用例类使用了@SpringBootTest注解yt.RANDOM_PORT,这表示在运行测试时,将会为Web服务器随机分配端口。
上面测试方法有的使用了@Test修饰,有的使用了@ParameterizedTest修饰,后者是JUnit 5.x新增的测试注解,用于表示参数化测试。@ValueSource、@CsvSource等注解提供的参数来调用参数化测试方法。
上面的测试用例中依赖注入了一个TestRestTemplate对象,这个TestRestTemplate对象实际上是对Resttemplate进行了封装,可以在测试环境中更方便地使用RestTemplate的功能,因此TestRestTemplate主要用于测试RESTful接口的功能。
上面的@SpringBootTest注解指定了webEnvironment = WebEnvironment.RANDOM_PORT,不需要知道web服务器端口是多少,可以直接进行测试。如果想使用固定端口,可以将webEnvironment属性指定为WebEnvironment.DEFINED_PORT,这样SpringBoot就会读取项目配置文件中的端口来启动Web服务器,若没有配置的话,默认值为8080端口



