【问题标题】:Spring Boot - Create Generics RepositoriesSpring Boot - 创建泛型存储库
【发布时间】:2018-08-04 12:35:06
【问题描述】:

我的 Web 应用程序中有许多服务执行经典的 CRUD 操作,这些是参数部分。为了避免为每个实体类创建一个存储库接口,我想创建一个通用存储库。我尝试了下面的代码,但只有在我有一个控制器时才有效。

public class BaseController<T extends BaseEntity> {

    @Autowired
    protected JpaRepository<T, Integer> dao;
}
@RestController
@RequestMapping("matieres")
@Api(value = "Matieres", tags = {"Parametrages"})
public class MatiereController extends BaseController<Matiere> {

    @GetMapping
    public Page<Matiere> find(
            @RequestParam(defaultValue = "0", required = false, name="page") Integer page,
            @RequestParam(defaultValue = "20", required = false, name="size") Integer size) {
        return this.dao.findAll(PageRequest.of(page, size));
    }

    @PostMapping
    public ResponseEntity<Matiere> create(@RequestBody Matiere matiere) {
        return ResponseEntity.ok(this.dao.save(matiere));
    }
}

【问题讨论】:

  • 你的目标是什么,会发生什么?有什么例外吗?
  • 我的目标是创建一个通用存储库或控制器,而不是为每个实体类创建一个存储库接口。我有这些异常说明:com.simba.controllers.BaseController 中的字段 dao 需要一个找不到的 'org.springframework.data.jpa.repository.JpaRepository' 类型的 bean。行动:考虑在你的配置中定义一个“org.springframework.data.jpa.repository.JpaRepository”类型的bean。

标签: spring-boot spring-repositories


【解决方案1】:

除非您将存储库注册为 Spring bean,否则 Spring 无法使用它们。所以首先你应该创建 repo 接口(

public interface UserRepo extends JpaRepository<User, Long> {}

public interface PersonRepo extends JpaRepository<Person, Long> {}

但是有一个好消息——你可以只在抽象控制器中实现所有典型的(CRUD)方法,例如:

public abstract class AbstractController<T> {

    protected final JpaRepository<T, Long> repo;

    public AbstractController(JpaRepository<T, Long> repo) {
        this.repo = repo;
    }

    @GetMapping
    public List<T> getAll() {
        return repo.findAll();
    }

    @GetMapping("/{id}")
    public ResponseEntity getOne(@PathVariable("id") Long id) {
        return repo.findById(id)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public T create(@RequestBody T entity) {
        return repo.save(entity);
    }

    @PatchMapping("/{id}")
    public ResponseEntity update(@PathVariable("id") Long id, @RequestBody T source) {
        return repo.findById(id)
                .map(target -> { BeanUtils.copyProperties(source, target, "id"); return target; })
                .map(repo::save)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    @DeleteMapping("/{id}")
    public ResponseEntity delete(@PathVariable("id") Long id) {
        return repo.findById(id)
                .map(entity -> { repo.delete(entity); return entity; })
                .map(t -> ResponseEntity.noContent().build())
                .orElse(ResponseEntity.notFound().build());
    }
}

然后只需注册您的具体控制器即可与您的所有实体一起工作:

@RestController
@RequestMapping("/people")
public class PersonController extends AbstractController<Person> {
    public PersonController(PersonRepo repo) {
        super(repo);
    }
}
@RequestMapping("/users")
public class UserController extends AbstractController<User> {
    public UserController(UserRepo repo) {
        super(repo);
    }
}

演示:sb-generic-controller-demo.

附:当然,此代码具有演示目的。在实际项目中,您应该将业务逻辑移至事务服务层。

【讨论】:

  • 嗨@Cepr0 感谢这个解决方案,所以我绝对应该创建接口。谢谢
  • @podisto 不客气,但如果对您有帮助,请不要忘记接受/投票)
  • 除了 jdbc 怎么办?
猜你喜欢
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 2022-11-19
  • 2017-08-08
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多