当前位置: 首页 > 知识库问答 >
问题:

如果使用JsonSubTypes,HATEOAS链接是错误的

权承
2023-03-14

我在Mongo中使用Spring data rest来公开一个具有多个子类型的类。当我这样做时,HATEOAS是根据实际实例化的类型而不是常见的基类型划分结果。这会导致链接不正确,并使分页无用,因为它是一个混合类型列表。

我已经尝试过将@Relation标签显式地添加到所有相关的类中,但似乎没有任何效果。不管有没有它,我都会得到同样的结果。

我正在使用spring boot依赖项2.1.8.RELEASE与spring boot-starter数据rest和spring云依赖项Greenwich.SR1

基类:

@Relation(collectionRelation = "notifications", value="notifications")
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "notificationType")
@JsonSubTypes({
        @JsonSubTypes.Type(value = ModelNotification.class, name = Notification.MODEL_NOTIFICATION),
        @JsonSubTypes.Type(value = BasicNotification.class, name = Notification.BASIC_NOTIFICATION)
})
public class Notification extends UUIDEntity implements Serializable {
    private static final long serialVersionUID = 8199210081144334378L;

    public static final String MODEL_NOTIFICATION = "MODEL_NOTIFICATION";
    public static final String BASIC_NOTIFICATION = "BASIC_NOTIFICATION";

    public enum Severity {
        TRACE,
        DEBUG,
        INFO,
        WARN,
        ERROR,
        FATAL
    }

    public Notification() {
        this.notificationType = BASIC_NOTIFICATION;
    }

    @JsonProperty("notificationType")
    private String notificationType;

    @JsonProperty("createdDate")
    @CreatedDate
    private Instant createdDate;

    @JsonProperty("lastModifiedDate")
    @LastModifiedDate
    private Instant lastModifiedDate;

    @JsonProperty("createdBy")
    @CreatedBy
    private String createdBy;

    @JsonProperty("lastModifiedBy")
    @LastModifiedBy
    private String lastModifiedBy;

    @JsonProperty("severity")
    private Severity severity;

    @JsonProperty("message")
    private String message;

无附加成员版本:

@Relation(collectionRelation = "notifications", value="notifications")
public class BasicNotification extends Notification implements Serializable {
    private static final long serialVersionUID = 8063077545983014320L;
}

和扩展版本:

@Relation(collectionRelation = "notifications", value="notifications")
public class ModelNotification extends Notification implements Serializable {
    private static final long serialVersionUID = 3700576594274374440L;

    @JsonProperty("storedModel")
    private StoredModel storedModel;

    public ModelNotification() {
        super();
        this.setNotificationType(Notification.MODEL_NOTIFICATION);
    }

如果添加了@Relation标签,我希望所有结果都出现在通知下,这是Spring data restendpoint的正确url。请注意,所有endpoint都正常工作,但只有HATEOAS的东西不正确,捆绑会产生问题。访问时: /api/notifications

我回来了:

{
  "_embedded" : {
    "modelNotifications" : [ {
      "notificationType" : "MODEL_NOTIFICATION",
      "createdDate" : "2019-10-02T15:53:42.127Z",
      "lastModifiedDate" : "2019-10-02T15:53:42.127Z",
...
[SNIP FOR BREVITY]
...
        } ]
      },
      "_links" : {
        "self" : {
          "href" : "http://fastscore:8088/api/modelNotification/ef81c342-29d3-48fb-bab3-d416e80bc5f6"
        },
        "modelNotification" : {
          "href" : "http://fastscore:8088/api/modelNotification/ef81c342-29d3-48fb-bab3-d416e80bc5f6"
        }
      }
    } ],
    "notifications" : [ {
      "notificationType" : "BASIC_NOTIFICATION",
      "createdDate" : "2019-10-02T15:52:10.261Z",
      "lastModifiedDate" : "2019-10-02T15:52:10.261Z",
      "createdBy" : "anonymousUser",
      "lastModifiedBy" : "anonymousUser",
      "severity" : "INFO",
      "message" : "Interval Process Completed Successfully",
      "_links" : {
        "self" : {
          "href" : "http://fastscore:8088/api/notifications/93fa5d6b-1457-4fa6-976c-cfdddc422976"
        },
        "notification" : {
          "href" : "http://fastscore:8088/api/notifications/93fa5d6b-1457-4fa6-976c-cfdddc422976"
        }
      }

...
[SNIP]
...
    }, 
  },
  "_links" : {
    "self" : {
      "href" : "http://fastscore:8088/api/notifications{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://fastscore:8088/api/profile/notifications"
    },
    "search" : {
      "href" : "http://fastscore:8088/api/notifications/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 4,
    "totalPages" : 1,
    "number" : 0
  }
}

这显然看起来是不正确的,因为ModelNotiations不是Spring数据Restendpoint。此外,这会使分页变得毫无用处,就好像我有很多通知,分页只适用于那些通知,即使我只有一个通知,我每次都会收到ModelNotiations…所以在第二页,我会收到第二页通知,但即使我只有一个条目,第二页上仍然有ModelNotiations。

这种方式使得 HATEOAS 支持无法与Spring数据Rest一起使用。

共有1个答案

金瑞
2023-03-14

好吧,在玩了一整天之后,@Relation标签似乎在这种情况下根本不起作用。所以我决定找一个工作。我所做的是实现一个RelProvider来正确检查继承,并返回正确的集合名称:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class NotificationRelProvider implements RelProvider {
    @Override
    public String getItemResourceRelFor(Class<?> aClass) {
        return "notification";
    }

    @Override
    public String getCollectionResourceRelFor(Class<?> aClass) {
        return "notifications";
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return Notification.class.isAssignableFrom(aClass);
    }
}

然后,我标记了spring data rest存储库,如文档中所述:

@ExposesResourceFor(Notification.class)
@RepositoryRestResource()
public interface NotificationRepository extends MongoRepository<Notification, UUID> {
    List<Notification> findAllBySeverityOrderByCreatedDateDesc(@Param("severity") Notification.Severity severity);
}

这样做之后,我现在得到了正确的和预期的行为:

 "_embedded" : {
    "notifications" : [ {
      "notificationType" : "BASIC_NOTIFICATION",
      "createdDate" : "2019-10-02T23:06:16.802Z",
      "lastModifiedDate" : "2019-10-02T23:06:16.802Z",
      "createdBy" : "anonymousUser",
      "lastModifiedBy" : "anonymousUser",
      "severity" : "INFO",
      "message" : "Interval Process Completed Successfully",
      "_links" : {
        "self" : {
          "href" : "http://fastscore:8088/api/notifications/eb214276-2880-43e0-8c7f-1519b1e7e343"
        },
        "notification" : {
          "href" : "http://fastscore:8088/api/notifications/eb214276-2880-43e0-8c7f-1519b1e7e343"
        }
      }
    }, {
      "notificationType" : "MODEL_NOTIFICATION",
      "createdDate" : "2019-10-02T23:07:32.649Z",
      "lastModifiedDate" : "2019-10-02T23:07:32.649Z",
      "createdBy" : "anonymousUser",
      "lastModifiedBy" : "anonymousUser",
....

因此,这解决了原始错误,但这是一种手动过程,而不仅仅是使用文档中描述的注释。不幸的是,这意味着我必须为存储库中的每个基类创建一个RelProvider类,但至少它可以工作并可用于分页。

 类似资料:
  • 问题1:就REST API而言,这是在Spring Hateoas中处理关系的正确方式吗? 问题2:如何将控制器中的url解析为数据上的可用句柄(例如,对适当控制器/方法的引用、主键等) 研究

  • 我正在使用sping-boot-2.2.1和sping-HATEOAS。超媒体链接工作正常,但是我在返回链接时看到了属性,请在这里找到下面的代码作为参考和github中的项目, 终点: a)将返回集合模型= 和 b) 将返回列表 控制器。Java 实际反应 预期反应: 我试过了 Spring数据RestdefaultMediaType=application/json spring.hateoas

  • 我如何描述HAL中的帖子链接? 我正在设计一个带有HATEOAS约束的RESTful API,类似于Wikipedia的HATEOAS示例,但用HAL JSON表示(为了清晰起见,删除了scheme、host等): 为了执行“转移”操作,客户大概会这样做: 通过GET调用“transfer”链接会在“transfers”中创建一个新的ressource。但是创建一个新资源并不是幂等的,它“感觉”不

  • 如您所见,我获得了整个party搜索的链接,但没有获得单个party对象的链接。(我想我的问题类似于这个问题:如何在子资源中添加HATEOAS链接),但我不太确定,所以我发布了我自己的。 任何帮助都将不胜感激!谢谢!

  • 我使用的是spring-boot:1.3.3、spring-hateoas:0.19.0和spring-data-rest-core:2.4.4。 这是Spring-Hateoas提供的内容的例子。过了一段时间,我将我的应用程序切换到SSL。

  • 我正在使用配置了@EnableHypermediaSupport(类型=HAL)的Spring Boot和Spring Hateoas。虽然这在基本场景中效果很好,但我希望能够向链接添加其他属性。例如,很容易返回将呈现以下链接的链接: 我想做的是向something rel中的对象添加更多属性。例如: 在不创建自己的DTO的情况下,最好的方法是什么(最好使用ControlllerLinkBuild