Java 关于: 在常规的@Repository界面中定义自定义方法(除了Spring数据方法之外) 在任何地方(甚至不需要在同一个包中)创建一个类MyEntityRepositoryImpl(@Impl后缀是魔法),该类只实现自定义方法,并注释@Component**(@Repository将不起作用)。 这个类甚至可以通过@Autowired注入MyEntityRepository,以便在自定义方法中使用 例子:
实体类别(完整性): 存储库接口:Java 关于: 在常规的@Repository界面中定义自定义方法(除了Spring数据方法之外) 在任何地方(甚至不需要在同一个包中)创建一个类MyEntityRepositoryImpl(@Impl后缀是魔法),该类只实现自定义方法,并注释@Component**(@Repository将不起作用)。 这个类甚至可以通过@Autowired注入MyEntityRepository,以便在自定义方法中使用 例子:,java,spring-data,spring-data-jpa,Java,Spring Data,Spring Data Jpa,实体类别(完整性): 存储库接口: public class AccountRepositoryImpl implements AccountRepositoryCustom { @Autowired @Lazy AccountRepository accountRepository; /* Optional - if you need it */ public void customMethod() { ... } } package myapp.dom
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@Autowired
@Lazy
AccountRepository accountRepository; /* Optional - if you need it */
public void customMethod() { ... }
}
package myapp.domain.myentity;
@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
// EXAMPLE SPRING DATA METHOD
List<MyEntity> findByCommentEndsWith(String x);
List<MyEntity> doSomeHql(Long id); // custom method, code at *Impl class below
List<MyEntity> useTheRepo(Long id); // custom method, code at *Impl class below
}
public interface UserCustomRepository {
List<User> findAllUsersBySomeCriteria(UserCriteriaRequest criteriaRequest);
}
就这样,除了您已经拥有的SpringDataRepo接口之外,不需要任何其他接口
我发现的唯一可能的缺点是:
类中的自定义方法被编译器标记为未使用,因此Impl
建议@SuppressWarnings(“未使用”)
- 您有一个
类的限制。(而在常规片段接口实现中,您可以有很多。)Impl
- 如果您将
类放在不同的包中,并且您的测试只使用Impl
,那么您必须将@DataJpaTest
添加到测试中,以便Spring加载它@ComponentScan(“package.of.the.Impl.clazz”)
public interface MyRepository <T, ID extends Serializable> extends JpaRepository<T, ID>
{
void sharedCustomMethod( ID id );
}
公共接口MyRepository扩展了JpaRepository
{
作废sharedCustomMethod(ID);
}
现在,您的各个存储库接口将扩展此中间接口,而不是存储库接口,以包括声明的功能
接下来,创建一个中间接口的实现,该接口扩展了特定于持久性技术的存储库基类。然后,此类将充当存储库代理的自定义基类
public class MyRepositoryImpl <T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID>
{
private EntityManager entityManager;
// There are two constructors to choose from, either can be used.
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager)
{
super( domainClass, entityManager );
// This is the recommended method for accessing inherited class dependencies.
this.entityManager = entityManager;
}
public void sharedCustomMethod( ID id )
{
// implementation goes here
}
}
公共类MyRepositoryImpl扩展了SimpleParepository实现MyRepository
{
私人实体管理者实体管理者;
//有两个构造函数可供选择,任何一个都可以使用。
公共MyRepositoryImpl(类domainClass,EntityManager EntityManager)
{
超级(域类、实体管理器);
//这是访问继承的类依赖项的推荐方法。
this.entityManager=entityManager;
}
公共无效sharedCustomMethod(ID)
{
//实现就在这里
}
}
我使用SimpleParepository作为存储库实现的基类,并在接口中添加自定义方法,例如:
public interface UserRepository {
User FindOrInsert(int userId);
}
@Repository
public class UserRepositoryImpl extends SimpleJpaRepository implements UserRepository {
private RedisClient redisClient;
public UserRepositoryImpl(RedisClient redisClient, EntityManager em) {
super(User.class, em);
this.redisClient = redisClient;
}
@Override
public User FindOrInsert(int userId) {
User u = redisClient.getOrSet("test key.. User.class, () -> {
Optional<User> ou = this.findById(Integer.valueOf(userId));
return ou.get();
});
…………
return u;
}
公共接口用户存储库{
用户FindOrInsert(int userId);
}
@存储库
公共类UserRepositoryImpl扩展了SimpleParepository实现了UserRepository{
私人再贴现客户;
公共用户RepositoryImpl(RedisClient、EntityManager em){
super(User.class,em);
this.redisClient=redisClient;
}
@凌驾
公共用户FindOrInsert(int userId){
用户u=redisClient.getOrSet(“测试键..User.class,()->”{
可选ou=this.findById(Integer.valueOf(userId));
返回ou.get();
});
…………
返回u;
}
我喜欢Danila的解决方案并开始使用它,但团队中没有人喜欢为每个存储库创建4个类。Danila的解决方案是这里唯一一个让您在Impl类中使用Spring数据方法的解决方案。不过,我找到了一种只使用一个类的方法:
public interface UserRepository extends MongoAccess, PagingAndSortingRepository<User> {
List<User> getByUsername(String username);
default List<User> getByUsernameCustom(String username) {
// Can call Spring Data methods!
findAll();
// Can write your own!
MongoOperations operations = getMongoOperations();
return operations.find(new Query(Criteria.where("username").is(username)), User.class);
}
}
其中BeanAccessor是:
@Component
public class BeanAccessor implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getSingleton(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getSingleton(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanAccessor.applicationContext = applicationContext;
}
}
@组件
公共类BeanAccessor实现ApplicationContextAware{
私有静态应用上下文应用上下文;
公共静态T getSingleton(类clazz){
返回applicationContext.getBean(clazz);
}
公共静态T getSingleton(字符串beanName,类clazz){
返回applicationContext.getBean(beanName,clazz);
}
@凌驾
public void setApplicationContext(ApplicationContext ApplicationContext)抛出BeansException{
BeanAccessor.applicationContext=applicationContext;
}
}
不幸的是,您不能在接口中使用@Autowire。您可以将bean自动连接到MongoAccessImpl中,并在接口中提供访问它的方法,但Spring数据崩溃了。我认为它甚至不希望看到与PagingAndSortingRepository间接关联的Impl。我在使用mongo和Spring时遇到了这个问题。所以让我们假设we使用MongoRepository提供基本crud操作,假设我们需要使用mongoTemplate实现一些自定义条件查询操作。要实现一个接口来为crud和自定义注入存储库,我们需要指定: 自定义接口:
public class AccountRepositoryImpl implements AccountRepositoryCustom {
@Autowired
@Lazy
AccountRepository accountRepository; /* Optional - if you need it */
public void customMethod() { ... }
}
package myapp.domain.myentity;
@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
// EXAMPLE SPRING DATA METHOD
List<MyEntity> findByCommentEndsWith(String x);
List<MyEntity> doSomeHql(Long id); // custom method, code at *Impl class below
List<MyEntity> useTheRepo(Long id); // custom method, code at *Impl class below
}
public interface UserCustomRepository {
List<User> findAllUsersBySomeCriteria(UserCriteriaRequest criteriaRequest);
}
公共接口UserCustomRepository{
列出findAllUsersBySomeCriteria(UserCriteriaRequest-criteriaRequest);
}
UserRepository接口“必须”首先扩展UserCustomRepository,然后扩展MongoRepository
@Repository
public interface UserRepository extends UserCustomRepository, MongoRepository<User, ObjectId> {
}
@存储库
公共接口UserRepository扩展了UserCustomRepository,MongoRepository{
}
UserRepositoryImpl必须与带有*Impl后缀的crud接口具有相同的名称
@Component
@NoArgsConstructor
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class UserRepositoryImpl implements UserCustomRepository {
private MongoTemplate mongoTemplate;
@Override
public List<User> findAllUsersBySomeCriteria(UserCriteriaRequest criteriaRequest){
//some impl
}
}
@组件
@诺尔格构装师
@AllArgsConstructor(onConstructor=@_uuz(@Autowired))
公共类UserRepositoryImpl实现UserCustomRepository{
私有MongoTemplate MongoTemplate;
@凌驾
公共列表FindAllUserBySomeCriteria(UserCriteriaRequest-criteriaRequest){
//一些简单的
}
}
让我们impl一些服务-这里我们只注入UserRepository接口,并使用来自crud repository和自定义类impl的方法
@Service
@NoArgsConstructor
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class UserService {
private UserRepository userReposityry;
public List<User> getUserByCriteria(UserCriteriaRequest request) {
userRepository.findById(request.getUserId); // Crud repository method
userRepository.findAllUsersBySomeCriteria(request); // custom method.
}
}
@服务
@诺尔格构装师
@AllArgsConstructor(onConstructor=@_uuz(@Autowired))
公共类用户服务{
私人用户
package myapp.infrastructure.myentity;
@Component // Must be @Component !!
public class MyEntityRepositoryImpl { // must have the exact repo name + Impl !!
@PersistenceContext
private EntityManager entityManager;
@Autowired
private MyEntityRepository myEntityRepository;
@SuppressWarnings("unused")
public List<MyEntity> doSomeHql(Long id) {
String hql = "SELECT eFROM MyEntity e WHERE e.id = :id";
TypedQuery<MyEntity> query = entityManager.createQuery(hql, MyEntity.class);
query.setParameter("id", id);
return query.getResultList();
}
@SuppressWarnings("unused")
public List<MyEntity> useTheRepo(Long id) {
List<MyEntity> es = doSomeHql(id);
es.addAll(myEntityRepository.findByCommentEndsWith("DO"));
es.add(myEntityRepository.findById(2L).get());
return es;
}
}
// You just autowire the the MyEntityRepository as usual
// (the Impl class is just impl detail, the clients don't even know about it)
@Service
public class SomeService {
@Autowired
private MyEntityRepository myEntityRepository;
public void someMethod(String x, long y) {
// call any method as usual
myEntityRepository.findByCommentEndsWith(x);
myEntityRepository.doSomeHql(y);
}
}
public interface MyRepository <T, ID extends Serializable> extends JpaRepository<T, ID>
{
void sharedCustomMethod( ID id );
}
public class MyRepositoryImpl <T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID>
{
private EntityManager entityManager;
// There are two constructors to choose from, either can be used.
public MyRepositoryImpl(Class<T> domainClass, EntityManager entityManager)
{
super( domainClass, entityManager );
// This is the recommended method for accessing inherited class dependencies.
this.entityManager = entityManager;
}
public void sharedCustomMethod( ID id )
{
// implementation goes here
}
}
public interface UserRepository {
User FindOrInsert(int userId);
}
@Repository
public class UserRepositoryImpl extends SimpleJpaRepository implements UserRepository {
private RedisClient redisClient;
public UserRepositoryImpl(RedisClient redisClient, EntityManager em) {
super(User.class, em);
this.redisClient = redisClient;
}
@Override
public User FindOrInsert(int userId) {
User u = redisClient.getOrSet("test key.. User.class, () -> {
Optional<User> ou = this.findById(Integer.valueOf(userId));
return ou.get();
});
…………
return u;
}
public interface UserRepository extends MongoAccess, PagingAndSortingRepository<User> {
List<User> getByUsername(String username);
default List<User> getByUsernameCustom(String username) {
// Can call Spring Data methods!
findAll();
// Can write your own!
MongoOperations operations = getMongoOperations();
return operations.find(new Query(Criteria.where("username").is(username)), User.class);
}
}
public interface MongoAccess {
default MongoOperations getMongoOperations() {
return BeanAccessor.getSingleton(MongoOperations.class);
}
}
@Component
public class BeanAccessor implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getSingleton(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getSingleton(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanAccessor.applicationContext = applicationContext;
}
}
public interface UserCustomRepository {
List<User> findAllUsersBySomeCriteria(UserCriteriaRequest criteriaRequest);
}
@Repository
public interface UserRepository extends UserCustomRepository, MongoRepository<User, ObjectId> {
}
@Component
@NoArgsConstructor
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class UserRepositoryImpl implements UserCustomRepository {
private MongoTemplate mongoTemplate;
@Override
public List<User> findAllUsersBySomeCriteria(UserCriteriaRequest criteriaRequest){
//some impl
}
}
@Service
@NoArgsConstructor
@AllArgsConstructor(onConstructor = @__(@Autowired))
public class UserService {
private UserRepository userReposityry;
public List<User> getUserByCriteria(UserCriteriaRequest request) {
userRepository.findById(request.getUserId); // Crud repository method
userRepository.findAllUsersBySomeCriteria(request); // custom method.
}
}