Spring Boot实现简单REST-API

设计模式之 依赖注入

「依赖注入」就是为了完成这样的 目标:将 依赖组件 的配置和使用分离开,以降低使用者与依赖之间的耦合度。

通过@component将类作为spring bean注入到spring container中,然后用 context.getBean 代替 new 来创建所需的对象 。值得注意的是,即使不显式创建,这些类也会被用单例模式自动创建好一个对象,等待被使用。如果要显式创建,必须用@Scope(value = “prototype”) 原型模式注解

对于有依赖的关系的对象,通过@Autowired 在spring container中自动寻找相应的类来建立依赖

预安装:

  • JDK: Java10.0.2
  • IDE: IDEA
  • 管理工具: Maven 3.6.1 Git

SDKMAN

然而在看很多教程的时候发现,java8用的比较多,我又不想卸载我的java10,于是找到了一个SDK管理工具用于管理java版本

安装指引 使用指引

另外该软件还可以管理Ant、Gradle、Maven、Springboot-cli、Groovy、Kotlin、Scala。可以说是java开发必备了

POSTMAN

在项目还没有开发出前端页面时,用于模拟发送HTTP请求

安装及使用

界面挺不错的

例:

POST –> localhost:8080/api/v1/person

Body – > raw ,JSON –> {内容}

UUID Generator

可在线生成UUID

IDEA相关配置

Maven配置本地仓库

在maven安装目录中的conf -> setting 中找到默认的本地仓库地址 为path/to/local/repo

新建一个本地仓库文件夹,并将地址替换 C:/Tools/maven/LocalWarehouse —–注意是另外写一行localrepository ,不是修改注释里面的

其实IDEA自带了maven,但是在这里设置为已经安装的相应配置。在IDEA的setting -> Build tools 中设置maven的所在目录为C:\Tools\maven\apache-maven-3.6.1 ,setting文件 C:\Tools\maven\apache-maven-3.6.1\conf\settings.xml和本地仓库C:\Tools\maven\LocalWarehouse

Git

在setting - > version control 中 Git已经自动检测到,Github输入账号密码即可

实践

学习视频

使用spring initializr 新建项目,在dependency的web中选择spring web

一个项目从数据层,服务层和用户接口层逐步去实现。

数据层

数据模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Person {
private final UUID id;
@NotBlank
private final String name;

public Person(@JsonProperty("id") UUID id,
@JsonProperty("name") String name) {
this.id = id;
this.name = name;
}

public UUID getId() {
return id;
}

public String getName() {
return name;
}
}
  • 输入的名字限制为非空
  • 格式为JSON

数据操作接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface PersonDao {
int insertPerson(UUID id, Person person);

default int insertPerson(Person person){
UUID id = UUID.randomUUID();
return insertPerson(id,person);
}

List<Person> selectAllPeople();

Optional<Person> selectPersonById(UUID id);

int deletePersonById(UUID id);

int updatePersonById(UUID id,Person person);
}
  • 如果只输入了姓名,则生成一个随机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
39
40
41
42
43
44
45
46
47
@Repository("fakeDao")
public class FakePersonDataAccessService implements PersonDao {

private static List<Person> DB = new ArrayList<>();

@Override
public int insertPerson(UUID id, Person person) {
DB.add(new Person(id,person.getName()));
return 1;
}

@Override
public List<Person> selectAllPeople() {
return DB;
}

@Override
public Optional<Person> selectPersonById(UUID id) {
return DB.stream()
.filter(person -> person.getId().equals(id))
.findFirst();
}

@Override
public int deletePersonById(UUID id) {
Optional<Person> personMaybe = selectPersonById(id);
if(!personMaybe.isPresent()){
return 0;
}
DB.remove(personMaybe.get());
return 1;
}

@Override
public int updatePersonById(UUID id, Person update) {
return selectPersonById(id)
.map(person ->{
int indexOfPersonToUpdate = DB.indexOf(person);
if(indexOfPersonToUpdate >= 0){
DB.set(indexOfPersonToUpdate, new Person(id, update.getName()));
return 1;
}
return 0;
})
.orElse(0);
}
}
  • 给数据仓库命名,可以方便后续service处转为其他类型的repository
  • 注意List的add/stream/set/remove等用法

服务层

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
@Service
public class PersonService {
public final PersonDao personDao;

@Autowired
public PersonService(@Qualifier("fakeDao") PersonDao personDao) {
this.personDao = personDao;
}

public int addPerson(Person person){
return personDao.insertPerson(person);
}

public List<Person> getAllPeople(){
return personDao.selectAllPeople();
}


public Optional<Person> getPersonById(UUID id){
return personDao.selectPersonById(id);
}

public int deletePerson(UUID id){
return personDao.deletePersonById(id);
}

public int updatePerson(UUID id, Person newPerson){
return personDao.updatePersonById(id, newPerson);
}
}
  • 注解为@service,明确作用
  • @Autowired 依赖注入 在spring container中自动寻找相应的类来建立依赖
  • @Qualifier(“fakeDao”) 按名查找
  • 服务层其实是在调用数据层的操作

用户接口层

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
@RequestMapping("api/v1/person")
@RestController
public class PersonController {
private final PersonService personService;

@Autowired
public PersonController(PersonService personService) {
this.personService = personService;
}

@PostMapping
public void addPerson( @Valid @NonNull @RequestBody Person person){
personService.addPerson(person);
}

@GetMapping
public List<Person> getAllPeople(){
return personService.getAllPeople();
}

@GetMapping(path = "{id}")
public Person getPersonById(@PathVariable("id") UUID id){
return personService.getPersonById(id)
.orElse(null);
}

@DeleteMapping(path = "{id}")
public void deletePersonById(@PathVariable("id") UUID id){
personService.deletePerson(id);
}

@PutMapping(path = "{id}")
public void updatePerson(@PathVariable("id") UUID id, @Valid @NonNull @RequestBody Person personToUpdate){
personService.updatePerson(id, personToUpdate);
}
}
  • @RequestMapping 指定HTTP路径
  • @RestController 明确控制器功能
  • @PostMapping @GetMapping @DeleteMapping @PutMapping 将HTTP类型与方法绑定
  • @PathVariable(“id”) 指定变量
  • @RequestBody 指定寻找部位

TIPS

  • IDEA换上了新出的Mono字体真是赏心悦目啊
  • 实现接口时,可以用快捷键 Ctrl + i
  • 最后通过mave打包出来的jar是可以直接运行的