问题
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