我有一个服务层,可以像这样 Autowiring 存储库
@Service
public class OrderService {
@Autowired
private OrderRepository repository;
public List<Order> retrieveOrders(String storeId) {
try {
return repository.getOrders(storeId)
} catch(Exception e) {
...
}
}
}
我有一个新的要求,根据商店编号,存储库查询逻辑应该改变。我正在考虑抽象我的存储库并使用工厂模式。当前存储库是一个接口(interface)并扩展了 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);
}
新要求规定,对于特定的 storeId,SQL 需要更改为如下内容:
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 查询。
我试图弄清楚如何根据 storeId 有条件地 @Autowire 存储库。我正在考虑创建一个工厂,但我不知道如何创建一个返回接口(interface)对象的工厂(我对java还很陌生,这可能很简单,但我还没有弄清楚)。如果我尝试将 Repository 接口(interface)转换为类,它会迫使我重写所有抽象 JpaRepository 方法,这是不必要的额外代码。
最佳答案
您已经走在正确的道路上了。我会解决这个问题,但创建一个返回正确 bean 接口(interface)的工厂方法。
此方法的唯一缺点是您无法 Autowiring 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 :在 3.003 秒内启动 FactoryApplication (JVM 运行了 3.615 秒) 订单(id=100) 订单(id=286)
希望这有帮助
关于java - Spring Boot - 如何创建不同 JpaRepository 接口(interface)的工厂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61576238/