Java 在基于spring boot的应用程序中使用RESTAPI输入在运行时设置架构名称
在postgres数据库中,模式名称设置为买方id(因此,如果买方id为买方2213,则模式名称将为买方2213)。这些模式有多个表,这些表具有所有模式的公共结构 现在,我正在使用SpringBoot编写RESTAPI,以从这些模式中获取买方数据,但由于模式名称依赖于买方id,因此我必须编写手动查询,并且无法使用JPA特性 是否有任何方法可以使用RESTAPI请求参数将模式名设置为实体。所以,在下面的实体中,我们可以使用在BuyerController中定义的API调用中传递的buyerId设置模式: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设置
@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()方法。
这看起来是一个糟糕的解决方法,但我没有找到比这更好的方法,所有建议/编辑都非常感谢。