我只是盯着spring-dataspring-data-rest ,我真的很想利用这些工具所提供的优势。 在大多数情况下,基本功能非常适合我的用例,但是在某些情况下,我需要大量定制基础功能,并有选择地分配一些存储库以继承我所追求的定制功能。

为了更好地解释该问题,在spring-data ,有2个可能的接口,您可以从中继承功能, CrudRepositoryPagingAndSortingRepository 我想添加第三个,让我们说PesimisticRepository

PesimisticRepository所做的全部工作就是以不同方式处理已删除@Entity的概念。 删除的实体是其删除属性为NOT NULL实体。 这意味着可以由PesimisticRepository处理的@Entity必须具有已删除的属性。

所有这些都是可能的,我实际上已经在几年前实现了。 (如果您有兴趣,可以在这里查看)

我目前使用spring-data的尝试如下:

PagingAndSortingRepository的扩展

package com.existanze.xxx.datastore.repositories;

import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.io.Serializable;


@NoRepositoryBean
public interface PesimisticRepository<T,ID extends Serializable> extends PagingAndSortingRepository<T,ID> {
}

为此,我提供了扩展JPARepository的默认实现

package com.existanze.xxx.datastore.repositories;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.Serializable;
import java.util.Date;


public class JpaPesimisticRepository<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements PesimisticRepository<T,ID> {


    private final EntityManager entityManager;

    public JpaPesimisticRepository(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    @Transactional
    public Page<T> findAll(Specification<T> spec, Pageable pageable) {

        CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
        CriteriaQuery<T> criteriaQuery = cb.createQuery(getDomainClass());
        Root<T> from = criteriaQuery.from(this.getDomainClass());
        Predicate deleted = cb.equal(from.get("deleted"), cb.nullLiteral(Date.class));
        criteriaQuery.select(from).where(deleted);
        TypedQuery<T> query = this.entityManager.createQuery(criteriaQuery);
        return pageable == null ? new PageImpl<T>(query.getResultList()) : readPage(query, pageable, spec);

    }

}

然后,对于希望使用悲观方法处理删除的所有bean,我将其定义为

package com.existanze.xxx.datastore.repositories;

import com.existanze.xxx.domain.Phone;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;


@RepositoryRestResource
public interface PhoneRepository extends PesimisticRepository<Phone,Integer> {



}

重要的是要解释为什么我希望重写这些方法而不是提供自定义方法,例如findAllButDeleted 原因是因为我也希望将悲观删除删除到spring-data-rest 这样,生成的HTTP端点将不需要任何形式的自定义。

这似乎仅对findAll方法有效。 但是,对于其余方法,将抛出当前异常。

$ curl http://localhost:8881/phones/23

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>
<title>Error 500 </title>
</head>
<body>
<h2>HTTP ERROR: 500</h2>
<p>Problem accessing /phones/23. Reason:
<pre>    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: object is not an instance of declaring class; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class</pre></p>
<hr /><i><small>Powered by Jetty://</small></i>
</body>
</html>

此外,我已经阅读了文档,该文档使您可以更改所有存储库的默认JpaRepository,但是同样,我需要在每个存储库的基础上执行此操作。

我希望我已经足够描述性了。 如果有什么需要更好的解释,请在评论部分告诉我。

#1楼 票数:4

您可以创建一个自定义存储库,如下所示:

package com.brunocesar.custom.repository.support;

import java.io.Serializable;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;

import com.brunocesar.custom.entity.CustomAbstractEntity;

@NoRepositoryBean
public interface CustomGenericRepository<E extends CustomAbstractEntity, PK extends Serializable> extends
        JpaRepository<E, PK>, JpaSpecificationExecutor<E> {

    EntityManager getEntityManager();

}

package com.brunocesar.custom.repository.support.impl;

import java.io.Serializable;
import java.util.Calendar;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.brunocesar.custom.entity.CustomAbstractEntity;
import com.brunocesar.custom.repository.support.CustomGenericRepository;

@Transactional(readOnly = true)
public class CustomGenericRepositoryImpl<E extends CustomAbstractEntity, PK extends Serializable> extends
        SimpleJpaRepository<E, PK> implements CustomGenericRepository<E, PK> {

    private final EntityManager entityManager;
    private final JpaEntityInformation<E, ?> entityInformation;

    public CustomGenericRepositoryImpl(final JpaEntityInformation<E, ?> entityInformation,
            final EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
        this.entityInformation = entityInformation;
    }

    @Override
    @Transactional
    public void delete(final E entity) {
        Assert.notNull(entity, "Entity object must not be null!");
        entity.setChangeDate(Calendar.getInstance().getTime());
        entity.setDeleted(true);
    }

    @Override
    public List<E> findAll() {
        return super.findAll(this.isRemoved());
    }

    @Override
    public E findOne(final PK pk) {
        return this.findOne(this.isRemovedByID(pk));
    }

    private Specification<E> isRemoved() {
        return new Specification<E>() {

            @Override
            public Predicate toPredicate(final Root<E> root, final CriteriaQuery<?> query, final CriteriaBuilder cb) {
                return cb.isFalse(root.<Boolean> get("deleted"));
            }

        };
    }

    private Specification<E> isRemovedByID(final PK pk) {
        return new Specification<E>() {

            @Override
            public Predicate toPredicate(Root<E> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Predicate id = cb.equal(root.get("id"), pk);
                final Predicate hidden = cb.isFalse(root.<Boolean> get("deleted"));
                return cb.and(id, hidden);
            }

        };
    }

    @Override
    public EntityManager getEntityManager() {
        return this.entityManager;
    }

    protected JpaEntityInformation<E, ?> getEntityInformation() {
        return this.entityInformation;
    }

}

您也将需要一个自定义工厂bean来设置您的自定义存储库。 看起来像这样:

package com.brunocesar.custom.repository.support.factory;

import java.io.Serializable;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;

import com.brunocesar.custom.repository.support.impl.CustomGenericRepositoryImpl;

public class CustomGenericRepositoryFactoryBean<T extends JpaRepository<S, ID>, S, ID extends Serializable> extends
        JpaRepositoryFactoryBean<T, S, ID> {

    @Override
    protected RepositoryFactorySupport createRepositoryFactory(final EntityManager entityManager) {
        return new RepositoryFactory(entityManager);
    }

    private static class RepositoryFactory extends JpaRepositoryFactory {

        public RepositoryFactory(final EntityManager entityManager) {
            super(entityManager);
        }

        @Override
        @SuppressWarnings({"unchecked", "rawtypes"})
        protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(
                final RepositoryMetadata metadata, final EntityManager entityManager) {
            final JpaEntityInformation<?, Serializable> entityInformation = this.getEntityInformation(metadata
                    .getDomainType());
            return new CustomGenericRepositoryImpl(entityInformation, entityManager);
        }

        @Override
        protected Class<?> getRepositoryBaseClass(final RepositoryMetadata metadata) {
            return CustomGenericRepositoryImpl.class;
        }

    }

}

最后是应用程序上下文配置。

通用存储库配置如下所示:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        p:dataSource-ref="dataSource" p:jpaProperties-ref="jpaProperties" p:jpaVendorAdapter-ref="jpaVendorAdapter"/>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />

<jpa:repositories base-package="com.brunocesar.repository"
    transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory" />

和自定义,像这样(您可以使用或不使用分离的EMF和事务管理器):

<bean id="entityManagerFactoryCustom" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
    p:dataSource-ref="dataSource" p:jpaProperties-ref="jpaProperties" p:jpaVendorAdapter-ref="jpaVendorAdapter"/>

<bean id="transactionManagerCustom" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactoryCustom" />

<jpa:repositories base-package="com.brunocesar.custom.repository,com.brunocesar.custom.repository.support"
    factory-class="com.brunocesar.custom.repository.support.factory.CustomGenericRepositoryFactoryBean"
    transaction-manager-ref="transactionManagerCustom" entity-manager-factory-ref="entityManagerFactoryCustom" />

示例1,使用JpaRepository:

package com.brunocesar.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.brunocesar.entity.CommonEntity;

@Repository
public interface CommonRepository extends JpaRepository<CommonEntity, Long> {

}

示例2,使用自定义存储库:

package com.brunocesar.custom.repository;

import org.springframework.stereotype.Repository;

import com.brunocesar.custom.entity.CustomEntity;
import com.brunocesar.custom.repository.support.CustomGenericRepository;

@Repository
public interface CustomRepository extends CustomGenericRepository<CustomEntity, Long> {

}

这是我通常所做的工作。 如果需要,我可以创建一个基本应用程序作为示例。

  ask by Fotis Paraskevopoulos translate from so

未解决问题?本站智能推荐:

1回复

spring-data-rest发布的自定义jpa存储库方法

我已经在jpa存储库中添加了一个自定义方法,详见http://docs.spring.io/spring-data/data-jpa/docs/1.0.x/reference/html/#repositories.custom-implementations 据我所知,当我使用spring-
1回复

spring-data-rest,与jointable的多种关系

是否可以公开使用连接实体(包含额外数据列)的多人关系,下面是我的实体; 我试图在REST中显示“购买”,我将“产品”作为工作REST映射的示例; 所以,如果我发送REST呼叫; [GET http:// localhost:8080 / webapp / users / 1] 它
1回复

添加软链接属性spring-data-rest?

我有一个简单的问题。 试想一下,我有一个实体类,该实体类映射到带有列的表。 我只需要向同一类引入一个新属性,该属性的值需要从另一个表的列中获取(我的意思是软链接)。 我知道这不是一个干净的要求。 反正有可能吗?
1回复

关于一对多关系的Spring-data-restNullPointerException

我正在开发具有spring-data-rest的应用程序。 在我拥有的每个OneToMany关系中,当我尝试使用一侧上的链接访问集合的元素时,都会收到NullPointerException 。 我已经在春季数据静止的Jira上报告了此问题,但仍未解决。 我想知道的是,是否有人在弹簧数据
1回复

如何在SpringData@Repository查找方法中指定默认排序?

低于唯一的方式(不是那么“干净”恕我直言)? 我希望@SortDefault和@PageableDefault类的东西,但它只适用于(REST)控制器,不适用于Spring Data REST。 另外: 如何为默认排序指定多个列? 如何指定计算列,即涉及CASE WHEN或函数
1回复

SpringDataJpa是否支持存储库继承以及如何做?

我有一个由以下内容组成的简单实体继承树: abstract class Item (id, ...)class Chart extends Item (...)class Table extends Item (...) 每个类都有自己的存储库: ItemRepository , ChartR
1回复

在spring-data-jpa上添加spring-data-rest

我创建了一个maven项目,并添加了我需要的所有依赖项。 我有一些使用spring-data-jpa的存储库,我添加了一些集成测试。 现在我需要添加它的spring-data-rest ontop,如果据我所知它是基于springmvc。 但我找到的所有例子,我都需要添加spring b
1回复

Spring-data-restPOST链接抛出Null-Pointer异常

我有一个名为StockLevel的实体和另一个名为Version的实体,它们的关系如下: 现在我想通过Spring-Data-REST创建一个新的StockLevel ,所以我发出以下POST请求到http://somedomain.com:8111/storefront/rest/stoc