Spring Boot - Create Generics Repositories

人盡茶涼 提交于 2019-12-24 19:57:37

问题


I have many services in my web application that do a classic CRUD operations, theses are Parameters section. In order to avoid creating for each entity class, a repository interface, I want to create a generic repository. I tried the code below but that only works if I have one controller.

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));
    }
}

回答1:


Unless you register your repos as Spring beans the Spring couldn't work with them. So first you should create repo interfaces (

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

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

But there is a good news - you can implement all typical (CRUD) methods in the abstract controller only, for example:

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());
    }
}

Then just register your concrete controllers to get working with all your entities:

@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);
    }
}

Demo: sb-generic-controller-demo.

P.S. Of cause this code has a demo purpose. In the real project you should move your business logic to the transactional service layer.



来源:https://stackoverflow.com/questions/51685615/spring-boot-create-generics-repositories

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!