first commit
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
package com.ehsaniara.multidatasource;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class DemoApplication {
|
||||||
|
|
||||||
|
public final static String MODEL_PACKAGE = "com.ehsaniara.multidatasource.model";
|
||||||
|
|
||||||
|
public final static Properties JPA_PROPERTIES = new Properties() {{
|
||||||
|
put("hibernate.dialect", "org.hibernate.dialect.PostgreSQL10Dialect");
|
||||||
|
put("hibernate.hbm2ddl.auto", "update");
|
||||||
|
put("hibernate.ddl-auto", "update");
|
||||||
|
put("show-sql", "true");
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(DemoApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.ehsaniara.multidatasource.configurations;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
import static com.ehsaniara.multidatasource.DemoApplication.JPA_PROPERTIES;
|
||||||
|
import static com.ehsaniara.multidatasource.DemoApplication.MODEL_PACKAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("spring.datasource-read")
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@EnableJpaRepositories(
|
||||||
|
entityManagerFactoryRef = "entityManagerFactoryRead",
|
||||||
|
transactionManagerRef = "transactionManagerRead",
|
||||||
|
basePackages = {"com.ehsaniara.multidatasource.repository.readRepository"}
|
||||||
|
)
|
||||||
|
public class DataSourceConfigRead extends HikariConfig {
|
||||||
|
|
||||||
|
public final static String PERSISTENCE_UNIT_NAME = "read";
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HikariDataSource dataSourceRead() {
|
||||||
|
return new HikariDataSource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalContainerEntityManagerFactoryBean entityManagerFactoryRead(
|
||||||
|
final HikariDataSource dataSourceRead) {
|
||||||
|
|
||||||
|
return new LocalContainerEntityManagerFactoryBean() {{
|
||||||
|
setDataSource(dataSourceRead);
|
||||||
|
setPersistenceProviderClass(HibernatePersistenceProvider.class);
|
||||||
|
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
|
||||||
|
setPackagesToScan(MODEL_PACKAGE);
|
||||||
|
setJpaProperties(JPA_PROPERTIES);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager transactionManagerRead(EntityManagerFactory entityManagerFactoryRead) {
|
||||||
|
return new JpaTransactionManager(entityManagerFactoryRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.ehsaniara.multidatasource.configurations;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
import static com.ehsaniara.multidatasource.DemoApplication.JPA_PROPERTIES;
|
||||||
|
import static com.ehsaniara.multidatasource.DemoApplication.MODEL_PACKAGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("spring.datasource-write")
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@EnableJpaRepositories(
|
||||||
|
entityManagerFactoryRef = "entityManagerFactoryWrite",
|
||||||
|
transactionManagerRef = "transactionManagerWrite",
|
||||||
|
basePackages = {"com.ehsaniara.multidatasource.repository.writeRepository"}
|
||||||
|
)
|
||||||
|
public class DataSourceConfigWrite extends HikariConfig {
|
||||||
|
|
||||||
|
public final static String PERSISTENCE_UNIT_NAME = "write";
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HikariDataSource dataSourceWrite() {
|
||||||
|
return new HikariDataSource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LocalContainerEntityManagerFactoryBean entityManagerFactoryWrite(
|
||||||
|
final HikariDataSource dataSourceWrite) {
|
||||||
|
|
||||||
|
return new LocalContainerEntityManagerFactoryBean() {{
|
||||||
|
setDataSource(dataSourceWrite);
|
||||||
|
setPersistenceProviderClass(HibernatePersistenceProvider.class);
|
||||||
|
setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
|
||||||
|
setPackagesToScan(MODEL_PACKAGE);
|
||||||
|
setJpaProperties(JPA_PROPERTIES);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlatformTransactionManager transactionManagerWrite(EntityManagerFactory entityManagerFactoryWrite) {
|
||||||
|
return new JpaTransactionManager(entityManagerFactoryWrite);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.ehsaniara.multidatasource.controller;
|
||||||
|
|
||||||
|
import com.ehsaniara.multidatasource.handler.ResourceNotFoundException;
|
||||||
|
import com.ehsaniara.multidatasource.model.Customer;
|
||||||
|
import com.ehsaniara.multidatasource.service.CustomerService;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class CustomerControllerImpl {
|
||||||
|
|
||||||
|
private final CustomerService customerService;
|
||||||
|
|
||||||
|
public CustomerControllerImpl(CustomerService customerService) {
|
||||||
|
this.customerService = customerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/customer/{id}", method = RequestMethod.GET)
|
||||||
|
public Customer getCustomer(@PathVariable("id") Long id) {
|
||||||
|
|
||||||
|
return customerService.getCustomer(id).orElseThrow(() -> new ResourceNotFoundException("Invalid Customer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/customer", method = RequestMethod.POST)
|
||||||
|
public Customer createCustomer(@RequestBody Customer customer) {
|
||||||
|
return customerService.createCustomer(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(path = "/customer", method = RequestMethod.PUT)
|
||||||
|
public Customer updateCustomer(@RequestBody Customer customer) {
|
||||||
|
return customerService.updateCustomer(customer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.ehsaniara.multidatasource.handler;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.hibernate.exception.SQLGrammarException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@ControllerAdvice
|
||||||
|
public class ExceptionHandlerControllerAdvice {
|
||||||
|
|
||||||
|
@ExceptionHandler(ResourceNotFoundException.class)
|
||||||
|
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||||
|
@ResponseBody
|
||||||
|
public ExceptionResponse handleResourceNotFound(final ResourceNotFoundException exception,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
log.error(exception.getMessage());
|
||||||
|
|
||||||
|
ExceptionResponse error = new ExceptionResponse();
|
||||||
|
error.setMessage(exception.getMessage());
|
||||||
|
error.setUrl(request.getRequestURI());
|
||||||
|
error.setStatus(HttpStatus.NOT_FOUND.value());
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(IllegalStateException.class)
|
||||||
|
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||||
|
@ResponseBody
|
||||||
|
public ExceptionResponse handleIllegalStateException(final IllegalStateException exception,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
log.error(exception.getMessage());
|
||||||
|
|
||||||
|
ExceptionResponse error = new ExceptionResponse();
|
||||||
|
error.setMessage(exception.getMessage());
|
||||||
|
error.setUrl(request.getRequestURI());
|
||||||
|
error.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(IllegalArgumentException.class)
|
||||||
|
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||||
|
@ResponseBody
|
||||||
|
public ExceptionResponse handleIllegalArgumentException(final IllegalArgumentException exception,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
log.error(exception.getMessage());
|
||||||
|
|
||||||
|
ExceptionResponse error = new ExceptionResponse();
|
||||||
|
error.setMessage(exception.getMessage());
|
||||||
|
error.setUrl(request.getRequestURI());
|
||||||
|
error.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(SQLGrammarException.class)
|
||||||
|
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
@ResponseBody
|
||||||
|
public ExceptionResponse handleSQLGrammarException(final SQLGrammarException exception,
|
||||||
|
final HttpServletRequest request) {
|
||||||
|
log.error(exception.getMessage());
|
||||||
|
|
||||||
|
ExceptionResponse error = new ExceptionResponse();
|
||||||
|
error.setMessage("SQL Exception");
|
||||||
|
error.setUrl(request.getRequestURI());
|
||||||
|
error.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
// @ExceptionHandler(Exception.class)
|
||||||
|
// @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
// @ResponseBody
|
||||||
|
// public ExceptionResponse handleException(final Exception exception,
|
||||||
|
// final HttpServletRequest request) {
|
||||||
|
// log.error(exception.getMessage());
|
||||||
|
//
|
||||||
|
// ExceptionResponse error = new ExceptionResponse();
|
||||||
|
// error.setErrorMessage(exception.getMessage());
|
||||||
|
// error.setUrl(request.getRequestURI());
|
||||||
|
//
|
||||||
|
// return error;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.ehsaniara.multidatasource.handler;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
public class ExceptionResponse {
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
private String error;
|
||||||
|
private String url;
|
||||||
|
private long status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.ehsaniara.multidatasource.handler;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||||
|
public class ResourceNotFoundException extends RuntimeException {
|
||||||
|
public ResourceNotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.ehsaniara.multidatasource.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@ToString
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@Entity
|
||||||
|
public class Customer {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ehsaniara.multidatasource.repository.readRepository;
|
||||||
|
|
||||||
|
import com.ehsaniara.multidatasource.model.Customer;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
public interface CustomerReadRepository extends CrudRepository<Customer, Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ehsaniara.multidatasource.repository.writeRepository;
|
||||||
|
|
||||||
|
import com.ehsaniara.multidatasource.model.Customer;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
public interface CustomerWriteRepository extends CrudRepository<Customer, Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ehsaniara.multidatasource.service;
|
||||||
|
|
||||||
|
import com.ehsaniara.multidatasource.model.Customer;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
public interface CustomerService {
|
||||||
|
|
||||||
|
Optional<Customer> getCustomer(Long id);
|
||||||
|
|
||||||
|
Customer createCustomer(Customer customer);
|
||||||
|
|
||||||
|
Customer updateCustomer(Customer customer);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.ehsaniara.multidatasource.service;
|
||||||
|
|
||||||
|
import com.ehsaniara.multidatasource.model.Customer;
|
||||||
|
import com.ehsaniara.multidatasource.repository.readRepository.CustomerReadRepository;
|
||||||
|
import com.ehsaniara.multidatasource.repository.writeRepository.CustomerWriteRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Jay Ehsaniara, Dec 30 2019
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CustomerServiceImpl implements CustomerService {
|
||||||
|
|
||||||
|
private final CustomerReadRepository customerReadRepository;
|
||||||
|
private final CustomerWriteRepository customerWriteRepository;
|
||||||
|
|
||||||
|
public CustomerServiceImpl(CustomerReadRepository customerReadRepository, CustomerWriteRepository customerWriteRepository) {
|
||||||
|
this.customerReadRepository = customerReadRepository;
|
||||||
|
this.customerWriteRepository = customerWriteRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Customer> getCustomer(Long id) {
|
||||||
|
return customerReadRepository.findById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer createCustomer(Customer customer) {
|
||||||
|
|
||||||
|
Assert.notNull(customer, "Invalid customer");
|
||||||
|
Assert.isNull(customer.getId(), "customer id should be null");
|
||||||
|
Assert.notNull(customer.getName(), "Invalid customer name");
|
||||||
|
|
||||||
|
return customerWriteRepository.save(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer updateCustomer(Customer customer) {
|
||||||
|
|
||||||
|
Assert.notNull(customer, "Invalid customer");
|
||||||
|
Assert.notNull(customer.getId(), "Invalid customer id");
|
||||||
|
|
||||||
|
return customerWriteRepository.save(customer);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main/resources/application.yml
Normal file
25
src/main/resources/application.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
spring:
|
||||||
|
datasource-write:
|
||||||
|
driver-class-name: org.postgresql.Driver
|
||||||
|
jdbc-url: jdbc:postgresql://localhost:5432/demo
|
||||||
|
username: 'postgres'
|
||||||
|
password: 'postgres_user_for_db_write'
|
||||||
|
platform: postgresql
|
||||||
|
hikari:
|
||||||
|
idle-timeout: 10000
|
||||||
|
maximum-pool-size: 10
|
||||||
|
minimum-idle: 5
|
||||||
|
pool-name: WriteHikariPool
|
||||||
|
|
||||||
|
datasource-read:
|
||||||
|
driver-class-name: org.postgresql.Driver
|
||||||
|
jdbc-url: jdbc:postgresql://localhost:5433/demo
|
||||||
|
username: 'postgres'
|
||||||
|
password: 'postgres_user_for_db_read'
|
||||||
|
platform: postgresql
|
||||||
|
hikari:
|
||||||
|
idle-timeout: 10000
|
||||||
|
maximum-pool-size: 10
|
||||||
|
minimum-idle: 5
|
||||||
|
pool-name: ReadHikariPool
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.ehsaniara.multidatasource;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class DemoApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user