Java 如何使用Spring-HATEAOS-RepresentationModel/Dto中的独立实体
我使用的是SpringBoot2.2.7、SpringHateAOS1.0、SpringJPA、SpringDataREST和Hibernate。我用一个复杂的模型创建了一个服务器REST 到目前为止,我部署了API,在数据REST允许的情况下向世界公开实体。所以我的DTO等于我的实体(即使我有几个Spring投影)。 然而,经过多次阅读,我发现我所做的并不是最佳实践,我想将Java 如何使用Spring-HATEAOS-RepresentationModel/Dto中的独立实体,java,spring,spring-boot,spring-hateoas,Java,Spring,Spring Boot,Spring Hateoas,我使用的是SpringBoot2.2.7、SpringHateAOS1.0、SpringJPA、SpringDataREST和Hibernate。我用一个复杂的模型创建了一个服务器REST 到目前为止,我部署了API,在数据REST允许的情况下向世界公开实体。所以我的DTO等于我的实体(即使我有几个Spring投影)。 然而,经过多次阅读,我发现我所做的并不是最佳实践,我想将实体与Dto分开,以保留HATEOAS 我查找了一些复杂的示例,但没有发现任何对实际应用程序真正有用的东西。我知道HATE
实体
与Dto
分开,以保留HATEOAS
我查找了一些复杂的示例,但没有发现任何对实际应用程序真正有用的东西。我知道HATEOAS的使用并不多,但我在客户机上做了很多努力来利用它
我正在寻找一种在我的数据库上执行查询、获取数据并将其转换为Dto的简洁方法
要将数据从Entity
复制到Dto
,我使用的是Mapstructs:我希望尽可能减少样板代码
假设我有这个实体:
@Entity
@Data
@Builder
public class EntityA implements Persistable<Long>, Serializable{
private long id;
private String
//other fields
}
@实体
@资料
@建筑商
公共类EntityA实现可持久化、可序列化{
私人长id;
私有字符串
//其他领域
}
这个实体呢
@实体
@Data
@Builder
public class EntityB implements Persistable<Long>, Serializable{
@ToString.Exclude
@NotNull
@OnDelete(action = OnDeleteAction.CASCADE)
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private Document document;
//other fields
}
@数据
@建筑商
公共类EntityB实现可持久化、可序列化{
@ToString.Exclude
@NotNull
@OnDelete(action=OnDeleteAction.CASCADE)
@manytone(fetch=FetchType.LAZY,可选=false)
私人文件;
//其他领域
}
我将实体存储库创建为:
@Transactional
@PreAuthorize("isAuthenticated()")
public interface ContactRepository extends JpaRepository<EntityA, Long>, ContactCustomRepository<EntityA, Long>, JpaSpecificationExecutor<EntityA> {
}
@Transactional
@预授权(“isAuthenticated()”)
公共接口ContactRepository扩展了JpaRepository、ContactCustomRepository、JpaSpecificationExecutor{
}
我的控制器是:
@RepositoryRestController
@PreAuthorize("isAuthenticated()")
@Log4j2
public class EntityAController {
@GetMapping(path = "/entityA/{id:[0-9]+}")
public ResponseEntity<?> get(@PathVariable(value = "id") long id) {
return ResponseEntity.ok(/*assembler??*/.toModel(myservice.get(id)));
}
@RepositoryRestController
@预授权(“isAuthenticated()”)
@Log4j2
公共类实体控制器{
@GetMapping(path=“/entityA/{id:[0-9]+}”)
公共响应属性获取(@PathVariable(value=“id”)长id){
返回ResponseEntity.ok(/*汇编程序???*/.toModel(myservice.get(id));
}
我还缺少一些难题:如何定义Dto以及如何创建一个不需要复制Dto中已经定义的代码的汇编器
我试图将Dto创建为:
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonRootName(value = "entityA")
@Relation(collectionRelation = "entitiesA")
@Builder
public class EntityAModel extends RepresentationModel<EntityA> implements Serializable {
private long id;
private String
//other fields
}
@数据
@AllArgsConstructor
@EqualsAndHashCode(callSuper=false)
@JsonRootName(value=“entityA”)
@关系(collectionRelation=“entitiesA”)
@建筑商
公共类EntityAModel扩展了RepresentationModel,实现了可序列化{
私人长id;
私有字符串
//其他领域
}
关于实体B,我更不确定:
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@JsonRootName(value = "entityB")
@Relation(collectionRelation = "entitiesB")
@Builder
public class EntityBModel extends RepresentationModel<EntityB> implements Serializable {
private EntityA entityA;
//other fields
}
@数据
@AllArgsConstructor
@EqualsAndHashCode(callSuper=false)
@JsonRootName(value=“entityB”)
@关系(collectionRelation=“entitiesB”)
@建筑商
公共类EntityBModel扩展了RepresentationModel实现了可序列化{
私人实体a实体a;
//其他领域
}
我创建了一个通用汇编程序:
/**
* A {@link SimpleRepresentationModelAssembler} that mixes together a Spring web controller and a
* {@link LinkRelationProvider} to build links upon a certain strategy.
*
* @author Greg Turnquist
*/
public class SimpleIdentifiableRepresentationModelAssembler<T> implements SimpleRepresentationModelAssembler<T> {
/**
* The Spring MVC class for the object from which links will be built.
*/
private final Class<?> controllerClass;
/**
* A {@link LinkRelationProvider} to look up names of links as options for resource paths.
*/
@Getter
private final LinkRelationProvider relProvider;
/**
* A {@link Class} depicting the object's type.
*/
@Getter
private final Class<?> resourceType;
/**
* Default base path as empty.
*/
@Getter
@Setter
private String basePath = "";
/**
* Default a assembler based on Spring MVC controller, resource type, and {@link LinkRelationProvider}. With this
* combination of information, resources can be defined.
*
* @param controllerClass - Spring MVC controller to base links off of
* @param relProvider
* @see #setBasePath(String) to adjust base path to something like "/api"/
*/
public SimpleIdentifiableRepresentationModelAssembler(Class<?> controllerClass, LinkRelationProvider relProvider) {
this.controllerClass = controllerClass;
this.relProvider = relProvider;
// Find the "T" type contained in "T extends Identifiable<?>", e.g.
// SimpleIdentifiableRepresentationModelAssembler<User> -> User
this.resourceType = GenericTypeResolver.resolveTypeArgument(this.getClass(),
SimpleIdentifiableRepresentationModelAssembler.class);
}
/**
* Alternate constructor that falls back to {@link EvoInflectorLinkRelationProvider}.
*
* @param controllerClass
*/
public SimpleIdentifiableRepresentationModelAssembler(Class<?> controllerClass) {
this(controllerClass, new EvoInflectorLinkRelationProvider());
}
/**
* Add single item self link based on the object and link back to aggregate root of the {@literal T} domain type using
* {@link LinkRelationProvider#getCollectionResourceRelFor(Class)}}.
*
* @param resource
*/
@Override
public void addLinks(EntityModel<T> resource) {
resource.add(getCollectionLinkBuilder().slash(getId(resource)).withSelfRel());
resource.add(getCollectionLinkBuilder().withRel(this.relProvider.getCollectionResourceRelFor(this.resourceType)));
}
private Object getId(EntityModel<T> resource) {
Field id = ReflectionUtils.findField(this.resourceType, "id");
ReflectionUtils.makeAccessible(id);
return ReflectionUtils.getField(id, resource.getContent());
}
/**
* Add a self link to the aggregate root.
*
* @param resources
*/
@Override
public void addLinks(CollectionModel<EntityModel<T>> resources) {
resources.add(getCollectionLinkBuilder().withSelfRel());
}
/**
* Build up a URI for the collection using the Spring web controller followed by the resource type transformed by the
* {@link LinkRelationProvider}. Assumption is that an {@literal EmployeeController} serving up {@literal Employee}
* objects will be serving resources at {@code /employees} and {@code /employees/1}. If this is not the case, simply
* override this method in your concrete instance, or resort to overriding {@link #addLinks(EntityModel)} and
* {@link #addLinks(CollectionModel)} where you have full control over exactly what links are put in the individual
* and collection resources.
*
* @return
*/
protected LinkBuilder getCollectionLinkBuilder() {
WebMvcLinkBuilder linkBuilder = linkTo(this.controllerClass);
for (String pathComponent : (getPrefix() + this.relProvider.getCollectionResourceRelFor(this.resourceType))
.split("/")) {
if (!pathComponent.isEmpty()) {
linkBuilder = linkBuilder.slash(pathComponent);
}
}
return linkBuilder;
}
/**
* Provide opportunity to override the base path for the URI.
*/
private String getPrefix() {
return getBasePath().isEmpty() ? "" : getBasePath() + "/";
}
}
/**
*混合了SpringWeb控制器和
*{@LinkRelationProvider}在特定策略上建立链接。
*
*@作者格雷格·特恩奎斯特
*/
公共类SimpleIdentifiableRepresentationModelAssembler实现SimpleRepresentationModelAssembler{
/**
*将从中构建链接的对象的Spring MVC类。
*/
私有最终类控制器类;
/**
*一个{@LinkRelationProvider},用于查找作为资源路径选项的链接名称。
*/
@吸气剂
私人最终链接RelationProvider relProvider;
/**
*描述对象类型的{@link Class}。
*/
@吸气剂
私有最终类资源类型;
/**
*默认基本路径为空。
*/
@吸气剂
@塞特
私有字符串basePath=“”;
/**
*基于SpringMVC控制器、资源类型和{@link-LinkRelationProvider}的默认汇编程序
*结合信息,可以定义资源。
*
*@param controllerClass-从Spring MVC控制器到基本链路
*@param relProvider
*@see#setBasePath(String)将基本路径调整为“/api”之类的内容/
*/
公共SimpleIdentifiableRepresentationModelAssembler(类controllerClass,LinkRelationProvider relProvider){
this.controllerClass=controllerClass;
this.relProvider=relProvider;
//查找“T”中包含的“T”类型,例如。
//SimpleIdentifiableRepresentationModelAssembler->User
this.resourceType=GenericTypeResolver.resolveTypeArgument(this.getClass(),
SimpleIdentifiableRepresentationModelAssembler.class);
}
/**
*返回到{@link-evoinfactorlinkrelationprovider}的备用构造函数。
*
*@param控制器类
*/
公共SimpleIdentifiableRepresentationModelAssembler(类控制器类){
这(controllerClass,新的EvoIncomectorLinkRelationProvider());
}
/**
*基于对象添加单项自链接,并使用
*{@LinkRelationProvider#getCollectionResourceRelFor(类)}。
*
*@param资源
*/
@凌驾
公共void addLinks(EntityModel资源){
add(getCollectionLinkBuilder().slash(getId(resource)).withSelfRel());
add(getCollectionLinkBuilder().withRel(this.relProvider.getCollectionResourceRelFor(this.resourceType)));
}
私有对象getId(EntityModel资源){
字段id=ReflectionUtils.findField(this.resourceType,“id”);
ReflectionUtils.makeAccessible(id);
返回ReflectionUtils.getField(id,resource.getContent());
}
/**
*向聚合根添加自链接。
*
*@param资源
*/
@凌驾
公共void addLinks(CollectionModel资源){
resources.add(getCollectionLi
@Component
public
class EntityAModelAssembler extends SimpleIdentifiableRepresentationModelAssembler<EntityAModel> {
DocumentFullModelAssembler() {
super(EntityAController.class);
}
}