Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在基于spring boot的应用程序中使用RESTAPI输入在运行时设置架构名称_Java_Spring_Postgresql_Spring Boot - Fatal编程技术网

Java 在基于spring boot的应用程序中使用RESTAPI输入在运行时设置架构名称

Java 在基于spring boot的应用程序中使用RESTAPI输入在运行时设置架构名称,java,spring,postgresql,spring-boot,Java,Spring,Postgresql,Spring Boot,在postgres数据库中,模式名称设置为买方id(因此,如果买方id为买方2213,则模式名称将为买方2213)。这些模式有多个表,这些表具有所有模式的公共结构 现在,我正在使用SpringBoot编写RESTAPI,以从这些模式中获取买方数据,但由于模式名称依赖于买方id,因此我必须编写手动查询,并且无法使用JPA特性 是否有任何方法可以使用RESTAPI请求参数将模式名设置为实体。所以,在下面的实体中,我们可以使用在BuyerController中定义的API调用中传递的buyerId设置

postgres数据库中,模式名称设置为买方id(因此,如果买方id为买方2213,则模式名称将为买方2213)。这些模式有多个表,这些表具有所有模式的公共结构

现在,我正在使用SpringBoot编写RESTAPI,以从这些模式中获取买方数据,但由于模式名称依赖于买方id,因此我必须编写手动查询,并且无法使用JPA特性

是否有任何方法可以使用RESTAPI请求参数将模式名设置为实体。所以,在下面的实体中,我们可以使用在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输入的任何其他方式)。因此,我无法找到与

相关的内容,我终于找到了一个有效的解决方案。此解决方案主要使用来自的配置,但更具体地针对my question需求

这个想法显然是要使用,并且数据源配置与中所示的非常相似,只需使用setter设置模式名称,即可从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();
    }
}

公共类BuyerSchemaDataSource扩展了AbstractDataSource{
私有加载缓存数据源=createCache();
public void setSchemaName(字符串schemaName){
this.schemaName=schemaName;
}
@重写公共连接getConnection()引发SQLException{
试一试{
返回determinateTargetDataSource().getConnection();
}捕获(执行例外){
//打印异常
返回null;
}
}
@重写公共连接getConnection(字符串用户名、字符串密码)
抛出SQLException{
试一试{
返回determinateTargetDataSource().getConnection(用户名、密码);
}捕获(执行例外){
//打印异常
返回null;
}
}
私有数据源determinateDatasource()引发ExecutionException{
如果(!utils.isNullOrEmpty(schemaName)){
返回dataSources.get(schemaName);
}
返回buildDataSourceFromSchema(null);
}
私有加载缓存createCache(){
返回CacheBuilder.newBuilder()
.最大尺寸(100)
.expireAfterWrite(10,时间单位:分钟)
.build(新的缓存加载程序(){
@重写公共数据源加载(字符串键)引发异常{
返回buildDataSourceFromSchema(键);
}
});
}
私有数据源buildDataSourceForSchema(字符串模式){
//例如财产:“jdbc:postgresql://localhost:5432/mydatabase?currentSchema="
字符串url=env.getRequiredProperty(“spring.datasource.url”)+schema;
返回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);
    }
}

@配置
@启用事务管理
@EnableJParepositions(entityManagerFactoryRef=“SchemaSpecificeEntityManagerFactory”,
transactionManagerRef=“SchemaSpecifictTransactionManager”)
公共类SchemaSpecificConfig{
@Bean(name=“schemaSpecificDataSource”)
公共数据源schemaSpecificDataSource(){
返回新的BuyerSchemaDataSource();
}
@Bean(name=“schemaSpecificEntityManagerFactory”)
公共LocalContainerEntityManagerFactoryBean方案特定实体管理器工厂(
EntityManagerFactoryBuilder生成器,@Qualifier(“schemaSpecificDataSource”)数据源(数据源){
HashMap属性=新建HashMap();
properties.put(“hibernate.hbm2ddl.auto”、“update”);
properties.put(“hibernate.dialogue”、“org.hibernate.dialogue.postgresqldialdialogue”);
返回builder.dataSource(dataSource).properties(properties)
.persistenceUnit(“SchemaSpecific”).build();
}
@Bean(name=“schemaSpecificTransactionManager”)
公共平台交易管理器方案特定交易管理器(
@限定符(“SchemaSpecificeEntityManagerFactory”)EntityManagerFactory SchemaSpecificeEntityManagerFactory){
返回新的JpaTransactionManager(SchemaSpecificeEntityManagerFactory);
}
}

现在,可以从控制器中的API逻辑内部调用BuyerSchemaDataSource中定义的setSchema()方法。

这看起来是一个糟糕的解决方法,但我没有找到比这更好的方法,所有建议/编辑都非常感谢。