Restful HATEOAS的使用3 _* C! T0 P: Y' n
) N7 r$ b! o3 N: y3 k! U1 B1.Restful定义. ~/ l4 E- B- Y+ A. N* a- g
Rest是一种软件架构与设计风格, 并非一套标准, 只提供了一些原则与约定条件。
" G9 B1 ]8 \- L. j( G. O3 uRESTful提供了一组架构约束,当作为一个整体服务来应用时,强调组件交互的可伸缩性、
9 {7 ]; b% x. S. Q接口的通用性、组件的独⽴部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件。 C Z1 Y( m( i6 k2 T3 A
满足这些约束条件和原则的应用程序或设计就是Restful。# f z% d7 g% f
2.基本了解下,等级2使用比较多。
# c6 F3 Q9 I, `) a- U等级2加入了HTTP方法处理:
$ ~8 Y2 K$ E$ |9 G; i$ Z& U2 c+ `3 X( u9 S7 t; P0 E8 E1 e7 k/ H
URI
1 ?3 Q; l" L4 R, N$ M# O | HTTP方法( _3 H; d7 Z. ]7 f% p( j' I' z, V
| 说明
. d3 q3 K0 Y8 E2 D# n" E | /order/3 }$ R8 E+ D' A
| GET
; @# }/ C/ \ ~8 Q. Q5 @0 v' Y) O* M | 获取所有订单信息
4 x5 t5 P1 [4 t; F E# N/ S | /order/
2 }2 _0 L% L( n4 i | POST
/ Y9 \3 b' c; v5 m7 V3 A3 e | 增加新的订单信息! B( e5 W; J" d. V/ w
| /order/{id}/ T, n+ ]# W1 \" D9 v
| GET, p: U( D# q; D# {
| 获取指定的订单信息) N( V: R& j& n
| /order/{id}
: t' Y- u* F6 {( n: F) t | DELETE* j1 {9 }) _- q' F+ V2 {0 r2 d
| 删除指定的订单信息
) @6 b/ Y7 @ Y. q | /order/{id}
4 ~1 q7 ~$ b _7 o | PUT. i2 f( o6 ]" l- H# D; Q5 d
| 修改指定的订单信息
! `' X$ @& O7 i' T5 o | ! R+ V6 H9 k: Z+ ^/ c& T8 Q7 m" n
等级3为超媒体控制(HATEOAS), 也是最为成熟的Rest模型。也是这次使用的。. z% |; ^4 ^' \- _
3 T* F: g. o- }, i1 u
7 @3 |: Q, f9 u& X
3.良好的URI规范
4 o; \$ T: l5 a9 s; `: j" h; a7 ~8 y$ {% o
- URI的路径采用斜杠分隔符(/)来表示资源之间的层次关系。
1 ^, v) e, I0 b0 n9 X - URI的路径使用逗号(,)与分号(;)来表示非层次元素。
9 p5 t, p. j3 \# R/ I' w - URI的查询部分,使用与符号(&)来分割参数。
* O9 }9 S. r! J4 l - URI中避免出现文件扩展名(例:.jsp、.json、.xml、.html)6 `1 s3 H0 Y8 e- ~
2.springboot使用HATEOAS ^8 a1 V- C* u6 B# K& G) j9 l
/ x& g8 u. ?' g# ~; O7 n" h
采用Spring Data Rest 实现 Hypermedia规范 W2 _* n) S- x/ l1 H
设计两个服务, 订单服务和股票服务, 两个服务遵循Hateoas风格。3 [, s! V$ ^1 U% |. `
/ f8 J+ I+ B6 z/ z) I$ q
- Step 1: 通过Restful的Hypermedia模型调用股票服务, 查询并打印股票信息。
3 o6 a6 D$ S& c8 a( w - Step 2: 通过HTTP PUT动作更新股票价格。
0 U5 K5 L. l4 _$ D8 n% t - Step 3: 重新调用股票信息接口,打印股票名称与价格。
: w6 M8 n$ d' B* d9 a$ I3 K - Step 4: 以上步骤操作成功后, 订单服务调用自身接口, 生成订单信息
& f1 c8 E. Z& ?0 X- a4 i* T 2.1 工程说明' r5 G, `5 d! f9 u6 {" }4 o( m
1 f% t$ t9 I, F8 ` c
2 Q( M6 i. i. f n7 }
) Y. c$ Y( C- S/ {# I; R; m2 J6 Z( ^
$ G' y8 \' a' D) O4 X* r; p' j& p
9 ^6 W4 K* Z& a0 i
数据层采用spring data jpa,spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。
* ?! \& S2 g/ n. o5 ?6 A% z本工程侧重Hateoas的理解, 数据库采用简化的H2内存数据库, 重新启动服务数据消失
. K2 N! W3 x' U/ o/ W7 a/ J& z; N8 y- F; G
- hateoas-demo父级工程 父级工程, 负责子工程依赖与打包管理。 POM依赖:( p1 j) t) t8 R
' s e7 N1 Q1 a, j$ e+ h8 O" S+ p+ J& v. i, C- l8 K
<dependencies> <!-- spring boot 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data jpa 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- Spring Restful实现组件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.jadira.usertype</groupId> <artifactId>usertype.core</artifactId> <version>6.0.1.GA</version> </dependency> <!-- 增加Jackson的Hibernate类型支持 --> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-hibernate5</artifactId> <version>2.9.8</version> </dependency> <!-- 增加Jackson XML支持 --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.9.0</version> </dependency> <!-- 常用工具依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <!-- H2内存型数据库的依赖 --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <!-- lombok 插件依赖 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>2.2启动股票服务验证
% X( x* d/ e# Z; m* D
; |9 M- ~$ Q# U- 启动股票服务,通过HTTP访问, 来查看Rest接口信息! q8 J" I1 p& n$ V- B
- 地址: http://127.0.0.1:8080/- B$ s$ e i3 t) N f6 L% o3 T( |
3 a/ `& m, T; x# u# ~/ c8 s8 n
g9 v1 a7 `5 Y4 Q$ }4 k) j( j可以看到我们定义的/stocks接口
1 C4 j' Q( V) D" C地址: http://127.0.0.1:8080/stocks
! U/ u5 s" U9 n/ L' Z- P' l0 N4 I7 r3 ?5 j; G; d5 p
! R/ U; h& ?: B& F a/ \
2.3启动订单服务验证+ N7 _ v" u% ?; o+ N9 Y2 F
& \4 |+ s- C1 J; c' Z% R- a
- 启动订单服务, 完整验证四个步骤处理流程。
% [2 _- W% J6 \3 `- i0 t 6 X( m% N c, R1 j( p
条件: 订单服务, 预期是修改中国平安的股票, 从价格68.6改成68.9;# `0 q' e5 v& `) ]8 _' [; W
新增订单信息: 股票名称建设银行,用户名是mirson, 交易数量为1000, 价格为99.9。) \; O: s+ J6 b% a8 ?) B0 C `
/** * 服务启动后执行 * @param args * @throws Exception */ @Override public void run(ApplicationArguments args) throws Exception { Link stocksLink = getLink(ROOT_URI,"stocksEntities"); // Step 1: 查询股票信息 queryStocks(stocksLink); // Step 2: 更新股票价格 Link updateLink= getLink(ROOT_URI.resolve("stocks/1"),"stocksEntity"); Resource<StocksEntity> americano = updateStocks(updateLink); // Step 3: 重新查询打印股票信息 queryStocks(stocksLink); // Step 4: 生成订单信息 OrderEntity order = OrderEntity.builder() .user("mirson") .stockName("建设银行") .volume(1000) .price(99.9) .build(); orderRepository.save(order); }控制台看到修改记录
$ Q9 G) d, ?4 F" T7 a+ D! y0 S( A! \+ o, w2 z! H
$ j `+ z5 w7 m1 q
2.查看order服务的订单信息
) I7 n A+ }- X# [7 A9 o% \8 w地址: http://127.0.0.1:8082/order , j# B/ M# E* x# u- y. [$ W
{ "_embedded" : { "orderEntities" : [ { "createTime" : "2022-07-02T16:29:57.061+0000", "updateTime" : "2022-07-02T16:29:57.061+0000", "user" : "mirson", "stockName" : "建设银行", "volume" : 1000, "price" : 99.9, "_links" : { "self" : { "href" : "http://127.0.0.1:8082/order/1" }, "orderEntity" : { "href" : "http://127.0.0.1:8082/order/1" } } } ] }, "_links" : { "self" : { "href" : "http://127.0.0.1:8082/order{?page,size,sort}", "templated" : true }, "profile" : { "href" : "http://127.0.0.1:8082/profile/order" }, "search" : { "href" : "http://127.0.0.1:8082/order/search" } }, "page" : { "size" : 20, "totalElements" : 1, "totalPages" : 1, "number" : 0 }}7 |3 o& P7 }5 n% ~
- 生成了我们新增的订单信息。此外还可以通过Postman来模拟增删改查操作, Spring Data Rest都帮我们做好封装。
9 X, R& T+ L0 m - 通过Spring Data Rest整个实现流程非常简单, 没有Controller层, 这正是Restful的设计风格, 以资源为对象, 无需过多的流程,转换处理。& K; B' h5 u6 c: l
3. 总结# P; E. {9 g# e
3 J- k4 i2 ^, V$ N" {& i8 Y% c; i- n( d9 P. y4 b3 }! o: q6 C
- 理解整体服务结构设计, 如何整合Spring Data Rest 实现 Hypermedia规范。* _% ~' M. a9 a
- 如何编写HATEOAS服务, 客户端的调用实现方式。
9 k5 ?8 {; z" F! u9 ~ |