栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

自定义具有复合ID的实体的HATEOAS链接生成

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义具有复合ID的实体的HATEOAS链接生成

不幸的是,所有Spring Data JPA / Rest最高版本为2.1.0.RELEASE都无法立即满足你的需求。该源代码隐藏在Spring Data Commons / JPA本身中。Spring Data JPA仅支持

Id
和EmbeddedId作为标识符。

摘录

JpaPersistentPropertyImpl

static {    // [...]    annotations = new HashSet<Class<? extends Annotation>>();    annotations.add(Id.class);    annotations.add(EmbeddedId.class);    ID_ANNOTATIONS = annotations;}

Spring Data Commons不支持组合属性的概念。它彼此独立地对待一个类的每个属性。

当然,你可以修改Spring Data Rest。但这很麻烦,不能从根本上解决问题,并且降低了框架的灵活性。

这是hack。这应该给你一个解决问题的思路。

在你的配置中覆盖

repositoryExporterHandlerAdapter
并返回
CustomPersistentEntityResourceAssemblerArgumentResolver
。此外,覆盖
backendIdConverterRegistry
并添加
CustomBackendIdConverter
到已知列表
id converter

import org.springframework.beans.factory.ListableBeanFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.import;import org.springframework.data.rest.core.projection.ProxyProjectionFactory;import org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter;import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;import org.springframework.data.rest.webmvc.spi.BackendIdConverter;import org.springframework.data.rest.webmvc.support.HttpMethodHandlerMethodArgumentResolver;import org.springframework.data.web.config.EnableSpringDataWebSupport;import org.springframework.hateoas.ResourceProcessor;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.plugin.core.OrderAwarePluginRegistry;import org.springframework.plugin.core.PluginRegistry;import org.springframework.web.method.support.HandlerMethodArgumentResolver;import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;@Configuration@import(RepositoryRestMvcConfiguration.class)@EnableSpringDataWebSupportpublic class RestConfig extends RepositoryRestMvcConfiguration {    @Autowired(required = false) List<ResourceProcessor<?>> resourceProcessors = Collections.emptyList();    @Autowired    ListableBeanFactory beanFactory;    @Override    @Bean    public PluginRegistry<BackendIdConverter, Class<?>> backendIdConverterRegistry() {        List<BackendIdConverter> converters = new ArrayList<BackendIdConverter>(3);        converters.add(new CustomBackendIdConverter());        converters.add(BackendIdConverter.DefaultIdConverter.INSTANCE);        return OrderAwarePluginRegistry.create(converters);    }    @Bean    public RequestMappingHandlerAdapter repositoryExporterHandlerAdapter() {        List<HttpMessageConverter<?>> messageConverters = defaultMessageConverters();        configureHttpMessageConverters(messageConverters);        RepositoryRestHandlerAdapter handlerAdapter = new RepositoryRestHandlerAdapter(defaultMethodArgumentResolvers(),     resourceProcessors);        handlerAdapter.setMessageConverters(messageConverters);        return handlerAdapter;    }    private List<HandlerMethodArgumentResolver> defaultMethodArgumentResolvers()    {        CustomPersistentEntityResourceAssemblerArgumentResolver peraResolver = new CustomPersistentEntityResourceAssemblerArgumentResolver(     repositories(), entitylinks(), config().projectionConfiguration(), new ProxyProjectionFactory(beanFactory));        return Arrays.asList(pageableResolver(), sortResolver(), serverHttpRequestMethodArgumentResolver(),     repoRequestArgumentResolver(), persistentEntityArgumentResolver(),     resourcemetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE,     peraResolver, backendIdHandlerMethodArgumentResolver());    }}

创建

CustomBackendIdConverter
。此类负责呈现你的自定义实体ID:

import org.springframework.data.rest.webmvc.spi.BackendIdConverter;import java.io.Serializable;public class CustomBackendIdConverter implements BackendIdConverter {    @Override    public Serializable fromRequestId(String id, Class<?> entityType) {        return id;    }    @Override    public String toRequestId(Serializable id, Class<?> entityType) {        if(entityType.equals(Customer.class)) { Customer c = (Customer) id; return c.getId() + "_" +c.getStartVersion();        }        return id.toString();    }    @Override    public boolean supports(Class<?> delimiter) {        return true;    }}

CustomPersistentEntityResourceAssemblerArgumentResolver
反过来应该返回一个
CustomPersistentEntityResourceAssembler

import org.springframework.core.MethodParameter;import org.springframework.data.repository.support.Repositories;import org.springframework.data.rest.core.projection.ProjectionDefinitions;import org.springframework.data.rest.core.projection.ProjectionFactory;import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;import org.springframework.data.rest.webmvc.config.PersistentEntityResourceAssemblerArgumentResolver;import org.springframework.data.rest.webmvc.support.PersistentEntityProjector;import org.springframework.hateoas.Entitylinks;import org.springframework.web.bind.support.WebDataBinderFactory;import org.springframework.web.context.request.NativeWebRequest;import org.springframework.web.method.support.ModelAndViewContainer;public class CustomPersistentEntityResourceAssemblerArgumentResolver extends PersistentEntityResourceAssemblerArgumentResolver {    private final Repositories repositories;    private final Entitylinks entitylinks;    private final ProjectionDefinitions projectionDefinitions;    private final ProjectionFactory projectionFactory;    public CustomPersistentEntityResourceAssemblerArgumentResolver(Repositories repositories, Entitylinks entitylinks,      ProjectionDefinitions projectionDefinitions, ProjectionFactory projectionFactory) {        super(repositories, entitylinks,projectionDefinitions,projectionFactory);        this.repositories = repositories;        this.entitylinks = entitylinks;        this.projectionDefinitions = projectionDefinitions;        this.projectionFactory = projectionFactory;    }    public boolean supportsParameter(MethodParameter parameter) {        return PersistentEntityResourceAssembler.class.isAssignableFrom(parameter.getParameterType());    }    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {        String projectionParameter = webRequest.getParameter(projectionDefinitions.getParameterName());        PersistentEntityProjector projector = new PersistentEntityProjector(projectionDefinitions, projectionFactory,     projectionParameter);        return new CustomPersistentEntityResourceAssembler(repositories, entitylinks, projector);    }}

CustomPersistentEntityResourceAssembler
需要覆盖
getSelflinkFor
。如你所见,e
ntity.getIdProperty()
返回
Customer
类的id或
startVersion
属性,而该属性又被用于借助来检索实际值
BeanWrapper
。在这里,我们使用
instanceof
运算符将整个框架短路。因此,你的
Customer
班级应实施
Serializable
进一步处理。

import org.springframework.data.mapping.PersistentEntity;import org.springframework.data.mapping.model.BeanWrapper;import org.springframework.data.repository.support.Repositories;import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;import org.springframework.data.rest.webmvc.support.Projector;import org.springframework.hateoas.Entitylinks;import org.springframework.hateoas.link;import org.springframework.util.Assert;public class CustomPersistentEntityResourceAssembler extends PersistentEntityResourceAssembler {    private final Repositories repositories;    private final Entitylinks entitylinks;    public CustomPersistentEntityResourceAssembler(Repositories repositories, Entitylinks entitylinks, Projector projector) {        super(repositories, entitylinks, projector);        this.repositories = repositories;        this.entitylinks = entitylinks;    }    public link getSelflinkFor(Object instance) {        Assert.notNull(instance, "Domain object must not be null!");        Class<? extends Object> instanceType = instance.getClass();        PersistentEntity<?, ?> entity = repositories.getPersistentEntity(instanceType);        if (entity == null) { throw new IllegalArgumentException(String.format("Cannot create self link for %s! No persistent entity found!",         instanceType));        }        Object id;        //this is a hack for demonstration purpose. don't do this at home!        if(instance instanceof Customer) { id = instance;        } else { BeanWrapper<Object> wrapper = BeanWrapper.create(instance, null); id = wrapper.getProperty(entity.getIdProperty());        }        link resourcelink = entitylinks.linkToSingleResource(entity.getType(), id);        return new link(resourcelink.getHref(), link.REL_SELF);    }}

而已!你应该看到以下URI:

{  "_embedded" : {    "customers" : [ {      "name" : "test",      "_links" : {        "self" : {          "href" : "http://localhost:8080/demo/customers/1_1"        }      }    } ]  }}

恕我直言,如果你正在从事绿色项目,我建议你

IdClass
完全放弃并使用基于Long类的技术简单ID。这已通过Spring Data Rest 2.1.0.RELEASE,Spring data JPA 1.6.0.RELEASE和Spring framework 4.0.3RELEASE进行了测试。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/400508.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号