You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否创建抽象类封装通用CRUD逻辑,让Service直接继承复用?

通用CRUD服务的实现方案

做完几个入门级项目后,我发现所有业务Service都围绕CRUD操作展开,因此想通过泛型封装通用CRUD逻辑,避免重复编写代码。以下是具体实现思路和优化后的代码:

核心设计逻辑

  • 定义泛型通用Service接口,统一CRUD方法规范
  • 基于JPA封装泛型Repository,复用JPA的持久层能力
  • 抽象类实现通用Service接口,封装CRUD基础逻辑
  • 业务Service继承抽象类,直接复用父类逻辑,按需扩展自定义业务

代码实现

1. 通用Service接口

public interface BasicService<T> {
    T add(T model);
    T update(T model, int id);
    void delete(int id);
    T getById(int id);
}

2. 通用Repository接口

@Repository
public interface BasicRepository<T> extends JpaRepository<T, Integer> {
}

3. 业务Service接口

public interface CarService extends BasicService<Car> {
    // 可在此定义Car业务特有的方法
}

4. 通用Service抽象实现类

这里修正了原代码中的语法错误,并补充了数据存在性校验,避免无意义操作或意外新增数据:

public abstract class BasicServiceImpl<T> implements BasicService<T> {

    private final BasicRepository<T> basicRepository;

    public BasicServiceImpl(BasicRepository<T> basicRepository) {
        this.basicRepository = basicRepository;
    }

    @Override
    public T getById(int id) {
        // 数据不存在时抛出异常,可根据业务调整为返回null或自定义异常
        return basicRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("请求的数据不存在"));
    }

    @Override
    @Transactional
    public void delete(int id) {
        // 先校验数据存在,再执行删除
        if (basicRepository.existsById(id)) {
            basicRepository.deleteById(id);
        }
    }

    @Override
    @Transactional
    public T update(T model, int id) {
        // 校验待更新数据存在,避免save操作变为新增
        if (!basicRepository.existsById(id)) {
            throw new RuntimeException("待更新的数据不存在");
        }
        return basicRepository.save(model);
    }

    @Override
    @Transactional
    public T add(T model) {
        return basicRepository.save(model);
    }
}

5. 业务Service实现类

修正了原代码的语法错误,并且如果不需要自定义逻辑,无需重写父类方法:

@Service
public class CarServiceImpl extends BasicServiceImpl<Car> implements CarService {

    // 注入业务专属Repository,父类会自动使用它处理CRUD
    public CarServiceImpl(CarRepository carRepository) {
        super(carRepository);
    }

    // 仅当需要自定义Car业务逻辑时才重写方法,例如:
    // @Override
    // public Car add(Car model) {
    //     // 新增前校验品牌不能为空
    //     if (model.getBrand() == null || model.getBrand().trim().isEmpty()) {
    //         throw new RuntimeException("车辆品牌不能为空");
    //     }
    //     return super.add(model);
    // }
}

优化建议

  • 自定义异常:替换代码中的RuntimeException为自定义业务异常,便于统一异常处理
  • 泛型主键:将主键类型也设为泛型(如BasicService<T, ID>),适配Long、String等不同主键类型
  • 分页与条件查询:在BasicService中添加分页、条件查询方法,进一步提升通用性
  • 参数校验:新增/更新方法中加入@Valid注解,结合JSR-380实现参数合法性校验

内容的提问来源于stack exchange,提问作者KingNotJoke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 03:30:49