I have a configuration class to configure a sqlite database connection. Here I do configure it manually.
@Configuration
@EnableJpaRepositories(basePackages = "fr.company.dashboard.io.repository")
public class DBConfiguration {
private final ApplicationProperties applicationProperties;
@Autowired
public DBConfiguration(ApplicationProperties applicationProperties) {
this.applicationProperties = applicationProperties;
}
@Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(applicationProperties.getProperty("hibernate.connection.driverClassName"));
dataSource.setUrl(applicationProperties.getProperty("url"));
dataSource.setUsername(applicationProperties.getProperty("user"));
dataSource.setPassword(applicationProperties.getProperty("password"));
return dataSource;
}
}
I would like to set the database by using an API get method which includes the database name in the URL
CodePudding user response:
You need firstly, to change the scope of the bean to be "request", then pass the parameters you want to the been like this:
@Scope("request")
@bean
public DataSource dataSource(String dbName){
......
......
return dataSource;
}
And on your controller, you should do something like that,
@Controller
public class YourController{
@Autowired
private BeanFactory beanFactory;
@RequestMapping("/")
public String exFunc(){
String dbName = "....."
DataSource dataSource =
beanFactory.getBean(DataSource.class, dbName);
}
}
CodePudding user response:
In my case, I have multiple sqlite db in a same folder. I changed my controller in order to retrieve the database name from entry point:
@RestController
@RequestMapping("/dbfiles")
public class AppController {
private final AppService appService;
private final DataSourceContextHolder dataSourceContextHolder;
@Autowired
public DatabaseListController(AppService AppService,
DataSourceContextHolder dataSourceContextHolder) {
this.appService= appService;
this.dataSourceContextHolder = dataSourceContextHolder;
}
@GetMapping("/{dbName}")
public List<AppResponse> getAll(@PathVariable("dbName") String dbName) throws IOException {
Set<String> databases = Utils.getDatabaseList();
if(databases.contains(dbName) || databases.contains(dbName ".db")) {
dataSourceContextHolder.setBranchContext(dbName);
}
List<AppResponse> returnValue = new ArrayList<>();
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
List<AppResponse> appResponses = appService.getAll();
returnValue = modelMapper.map(
appResponses ,
new TypeToken<List<AppDto>>() {}.getType()
);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(returnValue);
System.out.println(json);
return returnValue;
}
}
I used a component class where i pass the database name:
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class DataSourceContextHolder {
private static ThreadLocal<String> threadLocal;
public DataSourceContextHolder() {
threadLocal = new ThreadLocal<>();
}
public void setBranchContext(String dbName) {
threadLocal.set(dbName);
}
public String getBranchContext() {
return threadLocal.get();
}
public static void clearBranchContext() {
threadLocal.remove();
}
}
I also created a DataSourceRouting class that handles at start the databases:
@Component
public class DataSourceRouting extends AbstractRoutingDataSource {
private DataSourceContextHolder dataSourceContextHolder;
private DataSourceConfig dataSourceConfig;
public DataSourceRouting(DataSourceContextHolder dataSourceContextHolder,
DataSourceConfig dataSourceConfig) throws IOException {
this.dataSourceContextHolder = dataSourceContextHolder;
this.dataSourceConfig = dataSourceConfig;
Map<Object, Object> dataSourceMap = new HashMap<>();
Set<String> databases = Utils.getDatabaseList();
databases.forEach(database -> {
DataSource dataSource = dataSourceBuilder(database);
dataSourceMap.put(database, dataSource);
this.setDefaultTargetDataSource(dataSource);
});
this.setTargetDataSources(dataSourceMap);
}
private DataSource dataSourceBuilder(String database) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(dataSourceConfig.getDriverClassName());
dataSource.setUrl(dataSourceConfig.getUrl() database);
dataSource.setUsername(dataSourceConfig.getUsername());
dataSource.setPassword(dataSourceConfig.getPassword());
return dataSource;
}
@Override
protected Object determineCurrentLookupKey() {
//System.out.println(dataSourceContextHolder.getBranchContext().toString());
return dataSourceContextHolder.getBranchContext();
}
}
I created a POJO that reads in application.properties :
@Component
@ConfigurationProperties(prefix="datasource")
@Getter @Setter
public class DataSourceConfig {
private String url;
private String password;
private String username;
private String driverClassName;
}
This code allow to pass the database name and to make queries on the right one. As the databases have the same structure, I do output the correct values as expected.