簡體   English   中英

在基於 Spring Boot 的應用程序中使用 REST API 輸入在運行時設置模式名稱

[英]Set schema name at run time using REST API input in spring boot based application

postgres數據庫中,模式名稱被設置為買家 ID (因此,如果買家 ID 是buyer_2213,那么模式名稱將是buyer_2213 )。 這些模式有多個表,並且這些表具有所有模式的通用結構。

現在,我正在使用 Spring Boot 編寫 REST API 以從這些架構中獲取買家數據,但由於架構名稱依賴於買家 ID ,因此我必須編寫手動查詢並且無法為此使用 JPA 功能。

有什么方法可以使用 REST API 請求參數將架構名稱設置為實體。 因此,在下面的實體中,我們可以使用在buyerController 中定義的API 調用中傳遞的buyerId來設置模式

  @Entity
  @Table(name="buyer_table", schema="set_it_using_API_input")
  public class BuyerTable{
    ...
  }


  @RestController
  @RequestMapping("/buyer")
  public class BuyerController{
    
    @GetMapping("/{buyerId}")
    public void getBuyerData(@PathVariable(required = true) String buyerId){
      ...
    }
  }

此外,買家 ID 與登錄用戶不同(將此情況視為嘗試獲取買家詳細信息的管理員用戶),並且將僅作為 API 請求參數提供(或作為 API 輸入的任何其他方式)。 因此我找不到與相關的內容

我終於找到了一個可行的解決方案。 此解決方案主要使用此處的配置,但更具體地針對我的問題要求。

這個想法顯然是使用AbstractDataSource並且數據源配置與此處顯示的非常相似,只是模式名稱將使用可以從 API 邏輯內部調用的setter 設置
首先,我們需要編寫一個AbstractDataSource的實現,它看起來像這樣:

public class BuyerSchemaDataSource extends AbstractDataSource {

    private LoadingCache<String, DataSource> dataSources = createCache();

    public void setSchemaName(String schemaName){
        this.schemaName = schemaName;
    }

    @Override public Connection getConnection() throws SQLException {
        try {
            return determineTargetDataSource().getConnection();
        } catch (ExecutionException e) {
            //print exception
            return null;
        }
    }

    @Override public Connection getConnection(String username, String password)
        throws SQLException {
        try {
            return determineTargetDataSource().getConnection(username,password);
        } catch (ExecutionException e) {
            //print exception
            return null;
        }
    }

    private DataSource determineTargetDataSource() throws ExecutionException {
        if(!utils.isNullOrEmpty(schemaName)){
            return dataSources.get(schemaName);
        }
        return buildDataSourceFromSchema(null);
    }

    private LoadingCache<String, DataSource> createCache(){
        return CacheBuilder.newBuilder()
            .maximumSize(100)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build(new CacheLoader<String, DataSource>() {
                @Override public DataSource load(String key) throws Exception {
                    return buildDataSourceFromSchema(key);
                }
            });
    }

    private DataSource buildDataSourceForSchema(String schema) {
        // e.g. of property: "jdbc:postgresql://localhost:5432/mydatabase?currentSchema="
        String url = env.getRequiredProperty("spring.datasource.url") + schema;
        return DataSourceBuilder.create()
            .driverClassName(env.getRequiredProperty("spring.datasource.driverClassName"))
            [...]
            .url(url)
            .build();
    }
}


現在,就像任何其他數據源一樣,它可以在 spring 配置文件中使用,如下所示:
 @Configuration @EnableTransactionManagement @EnableJpaRepositories(entityManagerFactoryRef = "schemaSpecificEntityManagerFactory", transactionManagerRef = "schemaSpecificTransactionManager") public class SchemaSpecificConfig { @Bean(name = "schemaSpecificDataSource") public DataSource schemaSpecificDataSource(){ return new BuyerSchemaDataSource(); } @Bean(name = "schemaSpecificEntityManagerFactory") public LocalContainerEntityManagerFactoryBean schemaSpecificEntityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("schemaSpecificDataSource") DataSource dataSource) { HashMap<String, Object> properties = new HashMap<>(); properties.put("hibernate.hbm2ddl.auto", "update"); properties.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect"); return builder.dataSource(dataSource).properties(properties) .persistenceUnit("SchemaSpecific").build(); } @Bean(name = "schemaSpecificTransactionManager") public PlatformTransactionManager schemaSpecificTransactionManager( @Qualifier("schemaSpecificEntityManagerFactory") EntityManagerFactory schemaSpecificEntityManagerFactory) { return new JpaTransactionManager(schemaSpecificEntityManagerFactory); } }

現在,可以從控制器中的 API 邏輯內部調用在 BuyerSchemaDataSource 中定義的 setSchema() 方法。

這看起來是一個糟糕的解決方法,但我沒有找到比這更好的方法,並且感謝所有建議/編輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM