【问题标题】:How to have a common generic repository for Springboot JPA如何为 Spring Boot JPA 建立一个通用的通用存储库
【发布时间】:2021-02-19 02:57:06
【问题描述】:

这是我的模型:-

    @MappedSuperclass
public class IdCommon {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Version
    private Long version;

    @CreatedBy
    @Column(name = "created_by")
    private String createdBy;

    @CreatedDate
    private Instant created;

    @LastModifiedBy
    @Column(name = "updated_by")
    private String updatedBy;

    @LastModifiedDate
    private Instant updated;

}



    @Entity
@Table(name="TBL_EMPLOYEES")
public class EmployeeEntity extends IdCommon {
    
    @Column(name="first_name")
    private String firstName;
    
    @Column(name="last_name")
    private String lastName;
    
    @Column(name="email", nullable=false, length=200)
    private String email;
    
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "EmployeeEntity [id=" + 0 + ", firstName=" + firstName +
                ", lastName=" + lastName + ", email=" + email   + "]";
    }
}

我的存储库和服务:-

@Repository
public interface CommonRepository<E extends IdCommon> extends JpaRepository<E, Long>, 
JpaSpecificationExecutor<E> {

  }

 @Service
 public class EmployeeService {

//@Autowired
EmployeeRepository repository;

//@Autowired
CommonRepository<EmployeeEntity> commonRepository;

@Autowired
public EmployeeService(EmployeeRepository repository, CommonRepository<EmployeeEntity> commonRepository) {
    this.repository = repository;
    this.commonRepository = commonRepository;
}

public Page<EmployeeEntity> getAll(Pageable pageable){
    Specification<EmployeeEntity> specification = (Specification<EmployeeEntity>) (root, query, builder) -> null;
    return commonRepository.findAll(specification, pageable);
}
}

控制器:-

    @RestController
@RequestMapping(path = "/employee")
public class EmployeeController2 {

    @Autowired
    private EmployeeService employeeService;

    @GetMapping(path = "/all")

    @ApiImplicitParams({
            @ApiImplicitParam(name = "page", dataType = "integer", paramType = "query",
                    value = "page number"),
            @ApiImplicitParam(name = "size", dataType = "integer", paramType = "query",
                    value = "Number of records per page."),
    })
    public Page<EmployeeEntity> getAll(@RequestParam(value = "sortBy", required = false, defaultValue = "created") String sortBy,
                                       @ApiIgnore Pageable pageable,
                                       @ApiParam(value = "sortDirection (desc/asc)")
                                       @RequestParam(value = "sortDirection", required = false, defaultValue = "asc") String sortDirection){
        if (sortDirection.equals("desc")) {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by(sortBy).descending());
        } else {
            pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by(sortBy).ascending());
        }
        return employeeService.getAll(pageable);
    }
}

我收到了这个错误:-

: Servlet.service() 用于 servlet [dispatcherServlet] 的上下文中 path [] 抛出异常 [请求处理失败;嵌套异常 是 org.springframework.dao.InvalidDataAccessApiUsageException: 不是 实体:com.howtodoinjava.demo.model.IdCommon 类;嵌套异常 是 java.lang.IllegalArgumentException:不是实体:类 com.howtodoinjava.demo.model.IdCommon] 的根本原因

java.lang.IllegalArgumentException:不是实体:类 com.howtodoinjava.demo.model.IdCommon

正如上述错误所说,它不是实体。所以我在 IdCommon 中添加了@Entity 注释。然后我得到了新的错误:-

org.springframework.beans.factory.BeanCreationException: 错误 创建在类路径中定义的名称为“entityManagerFactory”的bean 资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: 调用 init 方法失败;嵌套异常是 org.hibernate.AnnotationException:一个实体不能用注释 @Entity 和 @MappedSuperclass: com.howtodoinjava.demo.model.IdCommon

我如何做到这一点?我的要求是具有通用存储库类型。我会有很多类似的实体。为了避免很多代码,我应该使用泛型。

【问题讨论】:

标签: java spring spring-boot hibernate spring-data-jpa


【解决方案1】:

现在已经有一段时间了,我希望您已经找到了解决方案。但是,对于面临同样问题的其他人,我会尝试找出您的解决方案不起作用的原因。

第一件事是你的存储库必须用 @NoRepositoryBean 注释,如下所示:

@NoRepositoryBean
public interface CommonRepository<E extends IdCommon> extends JpaRepository<E, Long>, JpaSpecificationExecutor<E> {}

并将在EmployeeRepository中扩展:

public interface EmployeeRepository extends CommonRepository<EmployeeEntity> {
    //you can override some or all of the methods if necessary
}

服务类大致相同:

@Service
public class EmployeeService {

    private EmployeeRepository empRepository;

    public EmployeeService(EmployeeRepository repository) {
        this.empRepository = repository;
    }

    public void saveEmployee(EmployeeEntity entity) {//I added this for a test
        empRepository.save(entity);
    }
    
    public Page<EmployeeEntity> getAll(Pageable pageable) {
        Specification<EmployeeEntity> specification = (Specification<EmployeeEntity>) (root, query, builder) -> null;
        return empRepository.findAll(specification, pageable);
    }
}

并使用CommandLineRunner 运行它(懒得添加控制器)

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private EmployeeService service;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        EmployeeEntity entity = new EmployeeEntity();
        entity.setEmail("aa@so.com");
        entity.setFirstName("First name");
        entity.setLastName("Last name");
        
        service.saveEmployee(entity);
        
        Page<EmployeeEntity> page = service.getAll(PageRequest.of(0, 1));
        page.getContent().stream().forEach(System.out::println); //output: EmployeeEntity [id=0, firstName=First name, lastName=Last name, email=aa@so.com]
    }

}

【讨论】:

  • 我收到此错误:*************************** 应用程序无法启动 ****** ********************* 描述:com.test.service.RevisionService 中构造函数的参数 0 需要一个 'com.test.service.RevisionRepository' 类型的 bean找不到。行动:考虑在你的配置中定义一个“com.test.service.RevisionRepository”类型的bean。我遵循与您的示例几乎相同的配置。
  • 问题似乎是包扫描问题,请检查您是否正在扫描所有必要的包。在您的情况下,必须扫描至少com.test.service
  • 看起来如果我将@NoRepositoryBean 更改为@Repository 然后它可以启动应用程序。但它不能满足我的重新装备。
  • 你尝试扫描所有的包吗?
  • 在同一个包中,我还有其他存储库,除了这个带有@NoRepositoryBean 的新存储库之外,它们工作正常。所以扫描不是这里的问题。如前所述,如果我更改为@Repository,那么它会启动,但最终它不会为我的设备提供服务。
猜你喜欢
  • 1970-01-01
  • 2018-12-03
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2020-11-28
  • 2021-11-07
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多