Controller

  • Controller에 Service를 연결시키는 부분도 CrudController로 추상화한다.
  • 제네릭 타입으로 CrudController로 Req, Res, Entity 타입을 전달한다.
//com/example/study/controller/api/ItemApiController.java

@RestController
@RequestMapping("/api/item")
public class ItemApiController extends CrudController<ItemApiRequest, ItemApiResponse, Item> {

}

CrudController 추상 클래스

  • Controller에서 제네릭 타입(Req, Res, Entity)을 받고 해당 엔티티에 해당되는 Service를 찾아 주입받는다.
  • CrudInterface를 상속받아 CRUD 메소드를 구현한다.
@Component //@Autowired로 주입받기 위함
public abstract class CrudController<Req, Res, Entity> implements CrudInterface<Req, Res> {

	//Controller에 Service를 연결시키는 부분
	//Entity 타입에 해당되는 Service를 찾아 주입
	@Autowired(required = false) //있을 수도 없을 수도 있음
	protected BaseService<Req, Res, Entity> baseService;

	@Override
	@PostMapping("")
	public Header<Res> create(@RequestBody Header<Req> request){
		return baseService.create(request);
	}
	
	@Override
	@GetMapping("{id}")
	public Header<Res> read(@PathVariable Long id){
		return baseService.read(id);
	}
	
	@Override
	@PutMapping("")
	public Header<Res> update(@RequestBody Header<Req> request){
		return baseService.update(request);
	}
	
	@Override
	@DeleteMapping("{id}")
	public Header delete(@PathVariable Long id){
		return baseService.delete(id);
	}
}

Service

  • Service에 Repository를 연결하는 부분을 BaseService로 추상화한다.
  • 제네릭 타입으로 BaseService로 Req, Res, Entity 타입을 전달한다.
  • 단, Service에서 CRUD에 대해서는 반드시 오버라이딩 해야한다.
//com/example/study/service/ItemApiLogicService.java

@Service
public class ItemApiLogicService extends BaseService<ItemApiRequest, ItemApiResponse, Item> {
	
	@Autowired
	private PartnerRepository partnerRepository;
	
	@Override
	public Header<ItemApiResponse> create(Header<ItemApiRequest> request) {
		return Optional.ofNullable(request.getData())
				.map(body -> {
					Item item = Item.builder()
							.status(body.getStatus())
							.name(body.getName())
							.title(body.getTitle())
							.content(body.getContent())
							.price(body.getPrice())
							.brandName(body.getBrandName())
							.registeredAt(LocalDateTime.now())
							.partner(partnerRepository.getOne(body.getPartnerId()))
							.build();
					return item;
				})
				.map(newItem -> baseRepository.save(newItem)) //baseRepository 사용
				.map(newItem -> response(newItem))
				.orElseGet(() -> Header.ERROR("데이터 없음"));
	}
    //...
}

BaseService 추상 클래스

//com/example/study/service/BaseService.java

@Component //@Autowired로 주입받기 위함
public abstract class BaseService<Req, Res, Entity> implements CrudInterface<Req, Res> {
	
	//Service에 Repository를 연결시키는 부분
	//JpaRepository 중에 해당 Entity와 타입을 가진 Repository를 찾아 주입
	@Autowired(required = false) //있을 수도 없을 수도 있음
	protected JpaRepository<Entity, Long> baseRepository;
}