Spring Boot - Как создать фабрику из различных интерфейсов JpaRepository - PullRequest
0 голосов
/ 03 мая 2020

У меня есть сервисный слой, который автоматически связывает репозиторий, например:

@Service
public class OrderService {

    @Autowired
    private OrderRepository repository;

    public List<Order> retrieveOrders(String storeId) {
        try {

            return repository.getOrders(storeId)

        } catch(Exception e) {
            ...
        }
    }
}

У меня есть новое требование, что в зависимости от номера магазина логика запросов к репозиторию c должна меняться. Я думаю о том, чтобы абстрагировать свой репозиторий и использовать фабричный шаблон. Текущий репозиторий является интерфейсом и расширяет JpaRepository; более того, все его функции используют аннотацию @Query для определения JPQL. Это пример только с одной функцией, но в моем реальном репозитории есть несколько функций

public interface OrderRepository extends JpaRepository {

    @Query("select o " +
        " from Orders o " +
        " where o.storeId = :storeId")
    public List<Order> getOrders(@Param(value = "storeId") String storeId);

}

В новых требованиях говорится, что для определенного c storeId SQL необходимо изменить на что-то вроде this:

public interface OrderRepositoryStore886 extends JpaRepository {

    @Query("select o " +
        " from Order o " +
        " where o.storeId = :storeId " +
        "     and o.status IN (1,3,10,15) " +
        "     and EXISTS (SELECT c from CollabOrder WHERE c.orderId = o.orderId)")
    public List<Order> getOrders(@Param(value = "storeId") String storeId);

}

Однако все остальные хранилища должны использовать первый запрос SQL.

Я пытаюсь выяснить, как условно @Autowire хранилище на основе storeId. Я думал о создании фабрики, но я не знаю, как сделать фабрику, которая возвращает интерфейсные объекты (я все еще довольно новичок в java, это может быть тривиально, но я еще не выяснил это). И если я пытаюсь превратить интерфейс Repository в класс, это заставляет меня переопределить все абстрактные методы JpaRepository, что является ненужным дополнительным кодом.

1 Ответ

0 голосов
/ 03 мая 2020

Вы уже на правильном пути. Я бы решил проблему, но создав фабричный метод, который возвращает правильный интерфейс bean-компонента.

Единственный недостаток этого метода - то, что вы не можете автоматически связывать ваши bean-компоненты. Вы должны создавать их на лету.

create table orders
(
  id                      integer      not null,
  constraint pk_orders primary key(id)
);

@Entity
@Table(name = "orders")
@ToString
@Getter
@Setter
public class Order {

    @Id
    private long id;
}


public interface OrderRepository extends JpaRepository<Order, Long> {
    @Query("SELECT t FROM Order t")
    Order getOrder(String storeId);
}


@Repository
public interface OrderRepositoryStore100 extends OrderRepository {
    @Query("SELECT t FROM Order t WHERE t.id = 100")
    Order getOrder(@Param(value = "id") String storeId);
}

@Repository
public interface OrderRepositoryStore286 extends OrderRepository {
    @Query("SELECT t FROM Order t WHERE t.id = 286")
    Order getOrder(@Param(value = "id") String storeId);
}

public class OrderRepositoryStoreFactory {

    private static final String REPOSITORY_BASE_NAME = "orderRepositoryStore";

    public static OrderRepository getRepository(ApplicationContext context, String storeId) {

        return (OrderRepository) context.getBean(REPOSITORY_BASE_NAME + storeId);
    }
}

@Service
public class OrderService {

    @Autowired
    private ApplicationContext context;

    public Order retrieveOrders(String storeId) {
        try {

            OrderRepository repository = OrderRepositoryStoreFactory.getRepository(context, storeId);

            return repository.getOrder(storeId);

        } catch(Exception e) {
            return null;
        }
    }
}



@SpringBootApplication
public class FactoryApplication implements CommandLineRunner {

    @Autowired
    private ApplicationContext context;

    @Autowired
    private OrderService orderService;

    public static void main(String[] args) {
        SpringApplication.run(FactoryApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Order order = orderService.retrieveOrders("100");
        System.out.println(order);

        order = orderService.retrieveOrders("286");
        System.out.println(order);
    }
}

А вот вывод:

2020-05-03 20: 23: 34.567 INFO 33955 --- [main] com.factory .FactoryApplication: приложение FactoryApplication запущено через 3,003 секунды (JVM работает в течение 3,615) Порядок (id = 100 ) Порядок (id = 286 )

Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...