SpringBoot构建REST服务(转载)

参考:

https://blog.csdn.net/ZhangCurie/article/details/118638225

https://blog.csdn.net/fatalflower/article/details/112380594

一、概述

有时候我们在面向资源编程时资源有很多操作,但是暴露给调用者的api都是孤立的。

使用RESTful的开发风格,支持我们将对资源的操作状态转移关联起来。

Richardson 提出了REST一种 成熟度模型,我们称之为Richardson Maturity Model,这种模式将REST按照成熟度划分为4个等级

  • Level0:使用HTTP作为WEB服务的传输方式,以REST样式公开SOAP Web服务
  • Level1:使用适当的URI(使用名词)公开资源,这种方式提出了资源的概念
  • Level2:资源使用正确的URI + HTTP方法,比如更新用户就用put方式,查询用get方式
  • Level3:使用HATEOAS(作为应用程序状态引擎的超媒体),在资源的表达中包含了链接信息,客户端可以在链接信息中发现可以执行的操作

举一个具体的例子,我们有一个地图,地图上要显示一些点位,点击点位可以显示当前点位的详细信息。

那我们至少应该有两个接口,比如:

getMapPointList();//点位列表
getMapPointDetail(String pid);//点位详情

那么当前端调用者看到第一个接口时,他可能想要知道某个具体点位的详情信息如何获取。

如果依照我们之前的开发方式,他应该去翻swagger文档,根据API名称再加上自己的经验得到第二个接口。

 

返回来一样,如果有新来了一个开发人员,他需要根据点位详情在前端做一些调整。但是这个接口需要传入一个参数pid,pid是什么,从哪里来,他不知道。

RESTful开发风格,建议我们将某个资源相关的所有连接在接口中给出来。让调用者不用再去翻文档就可以知道针对这个资源的所有操作。

二、实战

其实在接口中硬编码上相关的link也是可以的,但会增加我们的工作量。

还好有一个现成的工具可以。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

如果和swagger一起使用,可能会报错。

Parameter 0 of method linkDiscoverers in org.springframework.hateoas.config.HateoasConfiguration

 

这个时候需要增加一个配置信息。

@Bean
    public LinkDiscoverers discoverers() {
        List<LinkDiscoverer> plugins = new ArrayList<>();
        plugins.add(new CollectionJsonLinkDiscoverer());
        return new LinkDiscoverers(SimplePluginRegistry.create(plugins));
    }

好了,假如我们现在有一个资源叫做Metadata,我们需要在这个实体类上继承一个类RepresentationModel,类内部什么也不需要做。

@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "metadata")
public class Metadata extends RepresentationModel<Metadata> implements Serializable {
    private static final long serialVersionUID = 5536708482983535120L;

    @ApiModelProperty("uid:唯一标识")
    private String uid;

    @ApiModelProperty("名称")
    private String name;
    
   //...


}

针对这个资源,我们可以一次性返回一个资源list.controller代码如下:

@ApiOperation("获取所有元数据")
    @GetMapping("metadatas")
    public BaseResponse<List<Metadata>> metadatas() {
        List<Metadata> metaDatas = metadataService.getMetaData();

        return BaseResponse.success(metaDatas);
    }

 

postman执行一下,显示如下

 

 我们拿到了metadata的资源list,然并软,可以在这些资源上做什么操作呢?不知道!

当然,后端自己是知道的,因为操作都写在代码里。那这些怎么能让外部调用者知道呢?

 /**
     * 使用指定UID获取一个Metadata对象
     *
     * @param uid
     * @return
     */
    @ApiOperation("获取元数据")
    @GetMapping("metadata")
    public BaseResponse<Metadata> getMetadata(@RequestParam String uid) {
        Metadata byUid = metadataService.getByUid(uid);
        byUid.add(linkTo(methodOn(MetadataController.class).getMetadata(uid)).withSelfRel().withType("GET"));
        byUid.add(linkTo(methodOn(MetadataController.class).metadatas()).withRel("metadatas").withType("GET"));
        return BaseResponse.success(byUid);
    }


/**
     * 新建一个Metadata,底层实现replace into
     *
     * @param obj
     * @return
     */
    @EventPoint
    @ApiOperation("添加元数据")
    @PostMapping("metadata")
    public BaseResponse<Void> addMetadata(@RequestBody Metadata obj) {
        metadataService.addMetadata(obj);
        return BaseResponse.success(null);
    }

    /**
     * 更新一个metadata,底层实现update
     *
     * @param obj
     * @return
     */
    @EventPoint
    @ApiOperation("更新元数据")
    @PutMapping("updateMetadata")
    public BaseResponse<Void> updateMetadata(@RequestBody Metadata obj) {
        metadataService.updateMetadata(obj);
        return BaseResponse.success(null);
    }

    @EventPoint
    @ApiOperation("删除元数据")
    @DeleteMapping("deleteMetadata")
    public BaseResponse<Void> deleteMetadata(@RequestParam String uid) {
        metadataService.deleteMetadata(uid);
        return BaseResponse.success(null);
    }

基于hateoas,我们只需要修改一下metadatas的代码,即可将这个资源的所有操作暴露给前端调用者。

@ApiOperation("获取所有元数据")
    @GetMapping("metadatas")
    public BaseResponse<List<Metadata>> metadatas() {
        List<Metadata> metaDatas = metadataService.getMetaData();
        for (Metadata metaData : metaDatas) {
            metaData.add(linkTo(methodOn(MetadataController.class).getMetadata(metaData.getUid())).withRel("metadata").withType("GET"));
            metaData.add(linkTo(methodOn(MetadataController.class).addMetadata(metaData)).withRel("metadata").withType("POST"));
            metaData.add(linkTo(methodOn(MetadataController.class).updateMetadata(metaData)).withRel("updateMetadata").withType("PUT"));
            metaData.add(linkTo(methodOn(MetadataController.class).deleteMetadata(metaData.getUid())).withRel("deleteMetadata").withType("DELETE"));
        }
        return BaseResponse.success(metaDatas);
    }

postman再执行一下,可以看到,除了元数据原有的信息之外,还多了其他的link信息。

 

posted @ 2022-06-28 11:29  Mars.wang  阅读(151)  评论(0编辑  收藏  举报