该内容是 学习Spring boot项目时用到的基本api部分内容。包含了Restful Api 和 JWT 等常见网络请求和身份验证功能。

RESTful Api

RESTful接口

REST-> Representational State Transfer, an architecture constraint and rules.

架构约束条件和原则

RESTful -> 资源的状态性转移,在Web中资源就是URL(Uniform Resource Identifier)

如果符合REST 约束条件和原则,就是RESTful架构,HTTP是目前唯一的相关实例。

RESTful架构应该遵循统一的接口原则,应该使用标准的HTTP方法如GET, POST

遵循这个方法。

HTTP 常用语义

Post Put的区别

幂等性: 对象请求一次或者请求多次对系统产生的副作用是一致的

RESTful 接口URL命名原则:

1: HTTP方法后跟的URL必须是名词且统一成名词复数形式。

2: URL中不采用大小写混合的驼峰命名

例子: /users、 /users-fans; 反例: /getUsers、 /getUsersFans

RESTful接口分级原则:

一级用来定位资源分类,如/users即表示需要定位到用户相关中资源

二级仍用来定位具体某个资源,如/users/20表示id为20的用户。

/users/20/fans/1 -> id为20的用户的id为1的粉丝。

建议:是让我们的开发更加规范,而不是成为束缚我们开发的枷锁!

复杂GET查询请求命名:

1654589239005

/users?gender=male&sort=created-time-desc

/users?name=hellostar&gender=male&sort=created-time-desc

/users?size=10&no=1

通用功能

通用功能: 加解密工具(AES, RSA ,MD5)、Json数据返回类(通用的数据开发格式)

通用配置: Json信息转换配置,全局异常处理配置。

Json

轻量化的数据交换格式。

循环引用

fastjson 在做数据构建时,如果有两个一样的object,会直接把之前的object地址返回给前端。而真实的情况我们希望相同的内容可以展示两次,而不是为了偷懒引用之前的地址。

全局异常处理

handler包,处理器

用户功能开发

注册与登录

数据库表设计: 用户表、用户信息表

Autowired!

相关接口(API): RSA公钥、 用户注册、用户登录

JWT 生成用户令牌

基于session的用户身份验证

过程: 服务端验证浏览器携带的用户名和密码,验证通过后生成用户凭证保存在服务端(session), 浏览器再次访问时,服务端查询session,实现登录状态保持。

缺点:随着用户增多,服务端压力增大(实际用户凭证被保存在客户端了)。一旦浏览器cookie被攻击者拦截,容易受到跨站请求伪造攻击;分布式系统下扩展性不强。

基于token的身份验证

过程: 服务端验证浏览器携带的用户名和密码,验证通过后生成用户令牌(token)并返回给浏览器,再次访问时携带token,服务端校验token并返回相关数据。它用localstorage, 大小比cookie大很多,请求时可以不把token放在cookie中,而是放在请求头,body中。被跨站拦截的风险会低很多。

优点: token不储存在服务器,不会造成服务器压力; token可以存储在非cookie,安全性高; 分布式系统下扩展性强。

JWT 定义

JWT:全程是JSON Web Token, JWTs是一个规范,用于在空间受限环境下安全传递“声明""

声明: header: 头部, payload, signature.

优点: 跨语言支持,便于传输,易于扩展。

header: 声明类型,加密算法(SHA256).

payload: 存放有效信息,一般包含签发者,所面向的用户,接受方,过期时间,签发时间以及唯一身份标识。

JWT签名: 主要由头部、载荷和秘钥组合加密而成。

所有接口统一放在请求头中。

@Component 可以将user support以依赖的形式直接使用。

注意点

为何autowired 依赖注入不被推荐呢?-> 做法: 使用构造器注入

首先idea的建议是:

不建议直接在字段上进行依赖注入。Spring开发团队建议: 在Java Bean中永远使用构造方法进行依赖注入

Spring 有三种依赖注入的方法.

基于属性(filed)注入

就是在bean的变量上使用注解进行依赖注入,本质上通过反射的方式直接注入到fiel。

1
2
@Autowired
UserService userService;

基于set方法注入

通过对应变量的setXXX()方法以及在方法上面使用注解,来完成依赖注入。

比如:

1
2
3
4
5
6
private UserService userService;

@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}

说明: 在Spring 4.5 及更高版本中, setXXX上面的 @Autowired注解可忽略

基于Constructor 注入

将各个必须的依赖全部放在带有注解构造方法的参数中,并且在构造方法中完成initialization.

1
2
3
4
5
6
7
private final UserService userService;


@Autowired
public UserController(UserService userService) {
this.userService = userService;
}

Java 在初始化一个类时,是按照静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。所以在执行这个类的构造方法时,user对象尚未被注入,它的值还是 null。

NullPointerException 问题

不能有效的指明依赖。依赖注入对象为null。这种方法过于依赖容器了,当没有启动整个依赖容器时,这个类就不能运转,在反射时无法提供这个类需要的依赖。

依赖注入的核心思想之一就是被容器管理的类不应该依赖被容器管理的依赖,换成白话来说就是如果这个类使用了依赖注入的类,那么这个类摆脱了这几个依赖必须也能正常运行。然而使用变量注入的方式是不能保证这点的。

@Autowired 为Spring框架提供的注解,可以理解是Spring的亲儿子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IndexService {

void sayHello();
}

@Service
public class IndexServiceImpl implements IndexService {

@Override
public void sayHello() {
System.out.println("hello, this is IndexServiceImpl");
}
}

@Service
public class IndexServiceImpl2 implements IndexService {

@Override
public void sayHello() {
System.out.println("hello, this is IndexServiceImpl2");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootTest
public class Stest {

@Autowired
// @Qualifier("indexServiceImpl2")
IndexService indexService;

@Test
void gooo() {
Assertions.assertNotNull(indexService);
indexService.sayHello();
}

}

匹配bean 的过程:

1654784473430

@inject

1654784540019

@Resource

1654784569726

1654784840625