Spring Boot父类继承JpaRepository、JpaSpecificationExecutor的坑

那些坑

本猿最近因需求要做一个Spring Boot项目,封装一个BaseDao继承JpaRepository、JpaSpecificationExecutor,然后其他的dao接口继承BaseDao类而省代码。忽然脑一抽就把其他的dao接口除了继承BaseDao还继承了JpaRepository、JpaSpecificationExecutor。然后配置完了一运行就一直报我的serviceImpl那个父类实现类basedao未注入、找不到。
经过我一番的debug发现我还是来到运行控制台的报错地方,此时觉得spring工程的可配置文件它不香吗?非得和SpringBoot刚!!!

在这里插入图片描述



少说虚话,多做正事。各位兄die准备起飞!!!



工具:IDEA



创建工程

首先创建一个Spring Boot工程,在此提供一些之前创建的项目过程参考一下。
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述




配置application.yml

在这里插入图片描述

server:
  port: 8081
  tomcat:
    uri-encoding: UTF-8
  servlet:
    context-path: /private_kitechen

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/myreport?useUnicode=true&characterEncoding=utf-8&useLegacyDatetimeCode=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password:

  jpa:
    database-platform: org.hibernate.dialect.MySQL5Dialect
    show-sql: true

  http:
    encoding:
      force: true
      charset: UTF-8
      enabled: true






搭建基本包

我们的包创建跟项目启动文件(private_kitchen)同一目录。
在这里插入图片描述




配置启动类等相关配置

注意这里的注解上的路径是实测可以扫描到的。
在这里插入图片描述

package com.study.it.private_kitchen;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import javax.annotation.PostConstruct;
import java.util.TimeZone;

@SpringBootApplication
@ComponentScan(basePackages = "com.study.it.*")
@EntityScan("com.study.it.entity")
@EnableJpaRepositories("com.study.it.dao")
public class PrivateKitchenApplication {

    // 当时时区,本猿的电脑也是脑抽时区相差12小时
    @PostConstruct
    void started(){
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }

    // 启动类
    public static void main(String[] args) {
        SpringApplication.run(PrivateKitchenApplication.class, args);
    }

}


ServletInitializer类
在这里插入图片描述






把实体类连爬带滚给拖进来

还要配置实体类里面
在这里插入图片描述在这里插入图片描述





配置父接口BaseDao

在这里插入图片描述

package com.study.it.base;

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

import java.io.Serializable;

public interface BaseDao<T> extends JpaRepository<T, Serializable>, JpaSpecificationExecutor<T> {

}






配置其他dao接口继承BaseDao

这样有自定义的方法也可以加入里面去。
在这里插入图片描述






配置父接口BaseService

这个接口定义增删改查、分页等等的公用方法
在这里插入图片描述

package com.study.it.service;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

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

public interface BaseService<T> {
    void add(T o);
    void edit(T o);
    void remove(Serializable id);

    List<T> findAll();
    T findById(Serializable id);
    T findOne(Specification<T> dc);
    List<T> findList(Specification<T> dc);
    Page<T> findPage(Specification<T> dc, Pageable pp);
    long findCount(Specification<T> dc);
}






配置其他service继承BaseService

在这里插入图片描述

package com.study.it.service;

import com.study.it.entity.Admin;

public interface AdminService extends BaseService<Admin> {

}






配置父实现类BaseServiceImpl

在这里插入图片描述

package com.study.it.service.impl;
import com.study.it.base.BaseDao;
import com.study.it.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

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

//不能写@Service,因为这个是当父类用的,帮子类节约代码,子类才是真正出场的对象
public abstract class BaseServiceImpl<T> implements BaseService<T> {
    @Autowired
    protected BaseDao<T> dao;
    @Override
    @Transactional
    public void add(T o) {
        dao.save(o);
    }

    @Override
    @Transactional
    public void edit(T o) {
        dao.save(o);
    }

    @Override
    @Transactional
    public void remove(Serializable id) {
        dao.deleteById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> findAll() {
       return dao.findAll();
    }

    @Override
    @Transactional(readOnly = true)
    public T findById(Serializable id) {
        return dao.getOne(id);
    }

    @Override
    @Transactional(readOnly = true)
    public T findOne(Specification<T> dc) {
        return dao.findOne(dc).get();
       /* Optional<T> one = dao.findOne(dc);
        if(one.isPresent())
           return  one.get();//返回一个特殊类型,用get()取回对象
        return null;*/
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> findList(Specification<T> dc) {
        return dao.findAll(dc);
    }

    @Override
    @Transactional(readOnly = true)
    public Page<T> findPage(Specification<T> dc, Pageable pp) {
        return dao.findAll(dc,pp);
    }

    @Override
    @Transactional(readOnly = true)
    public long findCount(Specification<T> dc) {
        return dao.count(dc);
    }
}






配置其他实现类serviceImpl继承BaseServiceImpl

在这里插入图片描述

package com.study.it.service.impl;

import com.study.it.dao.AdminDao;
import com.study.it.entity.Admin;
import com.study.it.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("adminservice")
public class AdminServiceImpl extends BaseServiceImpl<Admin> implements AdminService {

    @Autowired
    private AdminDao adminDao;

}







在这里插入图片描述




最后奉上spring Boot的模糊查询并分页的小例子

这个一个根据关键字查询Teacher集合。

@RequestMapping(value = "/findall", method = RequestMethod.POST)
    public Page<Teacher> selectAll(
            @RequestParam(value = "page", defaultValue = "1") int page
            , String subject
    ){
        Specification<Teacher> dc = new Specification<Teacher>() {
            @Override
            public Predicate toPredicate(
                    Root<Teacher> root
                    , CriteriaQuery<?> query
                    , CriteriaBuilder cb
            ) {
                List<Predicate> cdts = new ArrayList<>();

                if (subject != null && !subject.isEmpty()){
                    cdts.add(cb.like(root.get("subjects"), "%" + subject + "%"));
                }

                return cb.and(cdts.toArray(new Predicate[cdts.size()]));
            }
        };
        Pageable pb =
                PageRequest.of(page - 1, 10, Sort.by(Sort.Order.desc("id")));

        return service.findPage(dc, pb);
    }






结束

在这里插入图片描述

### JPA 中 `JpaSpecificationExecutor` 与 `JpaRepository` 的区别 #### 功能对比 `JpaRepository` 提供了一组标准的 CRUD 方法以及分页和排序功能,适用于大多数基本的数据访问需求。通过继承 `JpaRepository<T, ID>` 接口,开发者可以立即获得诸如保存、删除、查找等常用操作的支持[^4]。 而 `JpaSpecificationExecutor` 则专注于动态查询构建的功能。它允许使用 Specifications 来创建复杂的条件组合,从而实现更灵活多变的查询逻辑。Specifications 可以看作是一种可重用的查询片段定义方式,能够方便地拼接多个查询条件来满足不同的业务需求。 ```java public interface IBigDao extends JpaRepository<BigEntity, Long>, JpaSpecificationExecutor<BigEntity> { BigEntity findByAlarmContentAndAlarmState(String alarmContent, EAlarmState alarmState); } ``` 此代码展示了如何在一个自定义仓库接口中同时集成这两种能力,既保留了基础的操作又增强了高级查询的能力。 #### 使用场景 对于简单的数据存取任务或者固定模式下的检索请求来说,仅依赖于 `JpaRepository` 就已经足够强大并易于维护;然而当面对复杂且变化频繁的查询要求时,则推荐引入 `JpaSpecificationExecutor` 。这不仅有助于提高代码复用率,还能让应用程序更好地适应未来可能发生的改动或扩展。 #### 继承关系说明 值得注意的是,在 Spring Data JPA 的设计体系里,`QueryByExampleExecutor` 被视为 `JpaRepository` 的父级接口之一,意味着所有实现了前者特性的库也会自动拥有后者的一部分行为特性[^3]。不过这里提到的关系并不直接影响到 `JpaSpecificationExecutor` 和 `JpaRepository` 之间的差异比较。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值