什么是SpringBoot
Spring 和SpringBoot的关系
Spring 的诞生是为了解决web开发笨重臃肿的问题,宗旨就是为了简化开发。
但是随着Spring的发展,现今Spring项目中存在很多XML配置以及第三方整合的配置,为了解决这种问题,Spring公司发布了SpringBoot快速开发框架。
SpringBoot的特性
- 搭建项目快
- 没有冗余代码生成和XML配置的要求
- 开箱即用,提供了很多默认的配置来简化项目配置
- 内嵌了web容器
- Starter自动依赖和版本控制
- 方便监控 部署后使用 SpringBootActuator组件提供了应用的系统监控,可以查看应用的配置等相关信息
SpringBoot与微服务架构
微服务的概念:简单来说,微服务是一个架构思想,它认为我们可以把一个单一的项目拆分成多个微小的服务,并且每一个服务都运行在自己的进程中,这些服务都只处理自己服务相关的业务。服务之间通过HTTP API进行沟通,所以每个服务可以使用不同的语言进行开发,而且可以使用多种不一样的数据库。其根本目的是为了提高并发。
单体架构和微服务架构
所谓单体应用架构是指将所有业务模块都封装到一个war包中运行。
它的优点有:易于开发和测试,部署方便,当需要扩展的时候只需要复制多份war包放到多台服务器,然后再做个负载均衡就可以。
缺点:项目过于臃肿,资源无法隔离,扩展不够灵活。
微服务架构意在打破单体架构的方式,把每个服务独立出来,用这些独立出来的模块之间互相调用组合成一个拥有多种功能的项目。
它的优点有:节省了调用的资源,每一个服务都是一个可以独立运行维护与升级的模块,扩展好,高可用
缺点:发布频繁,部署复杂,架构设计复杂,运维复杂
SpringBoot快速入门
创建一个SpringBoot项目
使用idea快速创建一个SpringBoot项目,创建好后项目目录如下:
直接启动上述启动类中的main方法即可运行项目。如果需要部署项目,我们只需要将项目package成一个jar包后使用 java -jar 文件名 就可以运行了。
我们能看到其实jar包中已经准备了tomcat的jar包和一些需要的依赖jar包。
项目结构说明
打开pom.xml文件观察一下结构。
其主要分为以下几块:
- 项目元数据信息。这些是在创建项目的时候输入的project metaData部分。包括了:groupId、artifactId、version、name、description
- parent:继承了spring-boot-starter-parent的依赖管理,实现自动依赖
- dependencies:项目的具体依赖
- build:构建配置部分,默认使用了spring-boot-maven-plugin,配合spring-boot-starter-parent可以把SpringBoot项目打成har包部署运行。
SpringBoot原理分析
项目运行实际是依赖了@SpringBootApplication这个注解,下面记录一下@SpringBootApplication下都有些什么
@SpringBootApplication注解的组成
@SpringBootConfiguration
此注解的主要目的是表明当前类是一个配置类
@EnableAutoConfiguration
实际上扫描的这些配置是SpringBoot默认给我们配好的,把这些配置类导入到spring容器中。这就是所谓的约定优于配置的体现,事先已经有约定好配置
@ComponentScan
这个注解主要是用于组件扫描和自动装配
以上就是SpringBoot可以帮我们做到零配置的原理
SpringBoot的配置
SpringBoot的配置文件
SpringBoot项目的配置文件有两种
- yml文件
- properties文件
两者实现的效果是一致的,如果在项目中同时存properties和yml而且他们名字都是application,那么会优先使用properties文件中的配置。
注意:系统默认读取的文件是application.properties文件,当然我们也可以通过配置修改。
如下:如果在application.properties文件中配置了环境,那么会读取application-uat.properties文件中的配置
yml文件及yaml语法说明
yml 的全称为YAML (YAML Ain’t a Markup Language),它是一种标记语言,通常以.yml为后缀的文件,是一种直观的能够被电脑识别的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,一种专门用来写配置文件的语言。与其他标记语言不同的是:它是以数据为中心,比json、xml更适合做配置文件
基本语法:
- key:空格+value的格式,value前面的空格不能少,可以有多个,但是不能用tab来代替
- 大小写敏感
- 使用缩进表示层级关系
- 缩进长度没有限制,只要元素对齐就表示这些元素属于一个层级
- 使用#表示注释
- 字符串可以不加引号
- java中对于驼峰命名法,可用原名或使用-代替驼峰,如nickName属性,在yml中使用nickName或 nick-name都可正确映射
- 使用 — 来分割环境配置
yml支持的数据类型:
- 字面量:直接量,单个不能被拆分的值(布尔值,数字,字符串)
- 对象:键值对形式存在
- 数组:字面量/对象的集合
下面用代码演示一下yml使用场景
@Component
@ConfigurationProperties(prefix = "student")
@Validated //jsr303数据校验
public class Student {
@Email
private String email;
private String name;
private String userName;
private int age;
private boolean sex;
private Date birthday;
//{province:湖北省,city:襄阳市,area:樊城区}
private Map<String,Object> location;
private String[] hobbies;
private List<String> skillList;
private Pet pet;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Map<String, Object> getLocation() {
return location;
}
public void setLocation(Map<String, Object> location) {
this.location = location;
}
public String[] getHobbies() {
return hobbies;
}
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
public List<String> getSkillList() {
return skillList;
}
public void setSkillList(List<String> skillList) {
this.skillList = skillList;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
@Override
public String toString() {
return "Student{" +
"email='" + email + '\'' +
", name='" + name + '\'' +
", userName='" + userName + '\'' +
", age=" + age +
", sex=" + sex +
", birthday=" + birthday +
", location=" + location +
", hobbies=" + Arrays.toString(hobbies) +
", skillList=" + skillList +
", pet=" + pet +
'}';
}
/**
* 验证参数:就是验证上述注解的完整方法
* @return
*/
public void validateParams() throws Exception{
//调用JSR303验证工具,校验参数
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Student>> violations = validator.validate(this);
Iterator<ConstraintViolation<Student>> iter = violations.iterator();
if (iter.hasNext()) {
String errMessage = iter.next().getMessage();
throw new Exception("出错啦!!!!!"+errMessage);
}
}
}
student:
name: ${random.int[15484,254784]}
userName: ${student.userName2:无名}
age: 18
email: xxxx@qq.com
sex: true
birthday: 1993/01/01
location:
province: 湖北省
city: 襄阳市
area: 樊城区
#{province: "湖\n北省", city: 襄阳市, area: 樊城区}
hobbies: [足球,篮球,乒乓球]
#- 足球
#- 篮球
#- 乒乓球
skillList: [编程,金融]
#- 编程
#- 金融
pet: {nickName: wc, strain: 哈士奇}
#nickName: wc
#strain: 哈士奇
除了使用@ConfigurationProperties注入还可以用@Value单独注入
properties和yml读取的方式
如果想要读取指定properties文件中的数据可以加一个注解@PropertySource
使用SpringBoot进行Web开发
了解RESTful
了解RESTful之前首先回顾一下什么是URI
什么是URI
URI:统一资源标识符,服务器上的每一种资源,比如文档,图片,视频,程序等,都是由一个通用资源标识符(Uniform Resource Identifier 简称:URI)进行定位。
例如:https://github.com/git
URI、URL、URN的关系
REST是什么
REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
REST核心概念
- 网络上所有事物都被抽象为资源
- 每一个资源都有一个唯一得资源标识符
- 同一个资源具有多种表现形式 ,也就是资源的“表述”(Representation)比如:XML和JSON等,URI只是代表了资源的实体,并不能代表它的表现形式
- 对资源的各种操作不会改变资源标识符
- 所有的操作都是无状态的
什么是RESTful
遵守了REST原则的web服务,REST式的web服务是一种ROA(Resource-oriented Architecture,面向资源的架构)的应用,RESTful架构的一个核心概念是“资源”(Resource)。
在互联网中,客户端和服务端之间的互动传递的就只是资源的表述,我们上网的过程,就是调用资源的URI,获取它不同表现形式的过程。这种互动只能使用无状态协议HTTP,也就是说,服务端必须保存所有的状态,客户端可以使用HTTP的几个基本操作,包括GET(获取)、POST(创建)、PUT(更新)与DELETE(删除),使得服务端上的资源发生“状态转化”(State Transfer),也就是所谓的“表述性状态转移”。
方法 | URL | 功能 |
---|---|---|
GET | /users | 获取用户列表 |
GET | /users/1 | 获取id为1的用户 |
POST | /users | 创建一个用户,如果存在则修改 |
PUT | /users/1 | 替换id为1的用户全部数据 |
PATCH | /users/1 | 修改id为1的用户部分数据 |
DELETE | /users/1 | 删除id为1的用户 |
GET | /users | 获取用户列表 |
使用RESTful进行开发
@RestController
public class UserInfoController {
@Autowired
private UserInfoRepositry userInfoRepositry;
@RequestMapping(value = "user", method = RequestMethod.GET)
public List<UserEntity> findAll () {
return userInfoRepositry.findAll();
}
@RequestMapping(value = "user/{id}", method = RequestMethod.GET)
public UserEntity findById (@PathVariable int id) {
return userInfoRepositry.findById(id).get();
}
@RequestMapping(value = "user", method = RequestMethod.POST)
public UserEntity saveUser(@ModelAttribute UserEntity userEntity) {
return userInfoRepositry.save(userEntity);
}
@RequestMapping(value = "user", method = RequestMethod.PUT)
public UserEntity updateUser(@ModelAttribute UserEntity userEntity) {
return userInfoRepositry.saveAndFlush(userEntity);
}
@RequestMapping(value = "user/{id}", method = RequestMethod.DELETE)
public void deleteUser(@PathVariable int id) {
userInfoRepositry.deleteById(id);
}
}
还可以使用SpringDataRest 直接进行开发
首先引入依赖
<!--RESTFUL接口-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
添加JPA配置
#JPA配置
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.MySQLDialect
database: mysql
#自动创建数据库表 true :有的话删除创建 false: 有的话直接使用
generate-ddl: true
#运行环境
profiles:
active: dev
编写repositry添加@RepositoryRestResource注解,继承JpaRepository
@RepositoryRestResource(path = "userEntities")
public interface UserInfoRepositry extends JpaRepository<UserEntity, Integer> {
UserEntity findByUsername(@Param("userName") String userName);
}
这样我们就可以通过ip+端口+userEntities+资源路径访问到资源了。