Un problema común en aplicaciones complejas, es cuando deseas desarrollar una aplicación que consume multiples bases de datos de acuerdo al país, area, cliente, etc. Una decisión común para resolver este problema es crear diferentes repositorios de código para cada uno, el problema es al momento de mantener el código y actualizaciones al sistema.
En este post explicaremos como podemos contar con un solo código que se pueda conectar a diferentes bases de datos de acuerdo a una configuración.
Paso 1 Creando bases de datos
El primer paso será crear dos bases de datos, una será utilizada para almacenar usuarios de Estados unidos y la otra para México:
create database us_users; use us_users; CREATE TABLE USER( USER_ID INTEGER PRIMARY KEY AUTO_INCREMENT, USERNAME VARCHAR(100) NOT NULL, PASSWORD VARCHAR(100) NOT NULL ); INSERT INTO USER (USERNAME,PASSWORD)VALUES('emma','superSecret'); INSERT INTO USER (USERNAME,PASSWORD)VALUES('john','smith'); INSERT INTO USER (USERNAME,PASSWORD)VALUES('kc','helloworld');
Lo anterior creará una tabla de usuarios para Estados Unidos junto con algunos registros de ejemplo.
create database mx_users; use mx_users; CREATE TABLE USER( USER_ID INTEGER PRIMARY KEY AUTO_INCREMENT, USERNAME VARCHAR(100) NOT NULL, PASSWORD VARCHAR(100) NOT NULL ); INSERT INTO USER (USERNAME,PASSWORD)VALUES('Alejandro','superSecreta'); INSERT INTO USER (USERNAME,PASSWORD)VALUES('Pedro','Pablito'); INSERT INTO USER (USERNAME,PASSWORD)VALUES('Pancho','Pantera');
Lo anterior creará una tabla de usuarios para México junto con algunos registros de ejemplo.
Paso 2 Configurado el proyecto
El proyecto se creará con Spring boot con las siguientes dependencias:
https://github.com/raidentrance/spring-multiple-db/blob/master/pom.xml
Con lo anterior tendremos todo lo necesario para trabajar con spring-mvc y con spring-jdbc.
Paso 3 Creando la clase aplicación
Una vez que tenemos configurado spring boot tendremos que crear la clase aplicación, que será quien inicie nuestra api.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; /** * @author raidentrance * */ @SpringBootApplication public class SampleApplication extends SpringBootServletInitializer{ @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(SampleApplication.class); } public static void main(String[] args) { SpringApplication.run(SampleApplication.class, args); } }
Para ejecutar nuestra aplicación solo ejecutaremos la clase anterior y los servicios se expondrán de forma exitosa.
Paso 4 Configurando datasources
El siguiente paso será configurar nuestros datasources, para esto crearemos un paquete llamado com.devs4j.example.config.db con la siguiente clase:
import javax.sql.DataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author raidentrance * */ @Configuration public class DataSourceConfig { @Bean @ConditionalOnProperty(name = "market", havingValue = "mx") public DataSource mxDatasource() { return DataSourceBuilder.create().driverClassName("com.mysql.jdbc.Driver") .url("jdbc:mysql://localhost:3306/mx_users").username("root").password("root").build(); } @Bean @ConditionalOnProperty(name = "market", havingValue = "us") public DataSource usDatasource() { return DataSourceBuilder.create().driverClassName("com.mysql.jdbc.Driver") .url("jdbc:mysql://localhost:3306/us_users").username("root").password("root").build(); } }
Como se puede ver se crearon 2 datasources cada uno apuntando a una base de datos diferente, como se puede ver se hace uso de @ConditionalOnProperty, esto significa que creará el bean siempre y cuando se cumpla con la condición que define, que en este caso es que el valor de la propiedad market sea igual a us o mx. Otro punto importante es que solo un bean se creará, en caso contrario Spring no sabría que bean inyectar.
Paso 5 Creando el modelo de nuestra aplicación
Una vez que creamos la tabla, el siguiente paso será crear una clase que la represente, para esto crearemos la siguiente clase:
/** * @author raidentrance * */ public class User { private Integer id; private String username; private String password; public User() { } public User(Integer id, String username, String password) { super(); this.id = id; this.username = username; this.password = password; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
Se creará un objeto de la clase User por cada registro que se desee devolver.
Paso 6 Creando un DAO de spring jdbc
El siguiente paso será hacer uso de Spring jdbc para ejecutar una consulta a nuestra base de datos, para esto crearemos el siguiente DAO (Data access object):
import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; import com.devs4j.example.model.User; /** * @author raidentrance * */ @Component public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; private static final String GET_ALL = "select * from user"; public List getUsers() { return jdbcTemplate.query(GET_ALL, new RowMapper() { @Override public User mapRow(ResultSet rs, int rowNum) throws SQLException { return new User(rs.getInt(1), rs.getString(2), rs.getString(3)); } }); } }
Nuestro DAO solo cuenta con un método que devuelve todos los usuarios en la tabla.
Paso 7 Creando un Service de spring
En este ejemplo no es tan necesario, pero lo crearemos para que quede clara la capa de servicios en nuestro servicio:
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.devs4j.example.dao.UserDao; import com.devs4j.example.model.User; /** * @author raidentrance * */ @Service public class UserService { @Autowired private UserDao dao; public List getUsers() { return dao.getUsers(); } }
El servicio UserService utilizará al DAO creado previamente para obtener la información de los usuarios a devolver.
Paso 8 Creando el Controller
Una vez hecho lo anterior, el siguiente paso será crear un controller que expondrá la información obtenida vía HTTP a través de un servicio REST:
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.devs4j.example.model.User; import com.devs4j.example.service.UserService; /** * @author raidentrance * */ @RestController @RequestMapping("/api") public class UserController { @Autowired private UserService service; @RequestMapping("/users") @ResponseBody public ResponseEntity getUsers() { return new ResponseEntity(service.getUsers(), HttpStatus.OK); } }
Como se puede ver se expondrá un endpoint GET /api/users que devolverá la lista de usuarios.
Paso 9 Creando nuestro archivo application.properties
Por último crearemos un archivo llamado application.properties en el folder /src/main/resources con lo siguiente:
market=mx
Lo anterior definirá el mercado que utilizará la aplicación, en este caso será México.
Paso 10 Probando la aplicación
Una vez que tenemos todo lo anterior, el último paso será probar el api, para esto ejecutaremos nuestra aplicación (recordando que el mercado que definimos fue México) y abriremos la url http://localhost:8080/api/users con la siguiente salida:
[ { "id": 5, "username": "Alejandro", "password": "superSecreta" }, { "id": 6, "username": "Pedro", "password": "Pablito" }, { "id": 7, "username": "Pancho", "password": "Pantera" } ]
Como podemos ver los usuarios que se muestran son los que definimos en la base de datos de México, ahora modificaremos el archivo application.properties con lo siguiente:
market=us
Una vez hecho esto ejecutaremos nuevamente la aplicación e invocaremos de nuevo la url http://localhost:8080/api/users con la siguiente salida:
[ { "id": 1, "username": "emma", "password": "superSecret" }, { "id": 2, "username": "john", "password": "smith" }, { "id": 3, "username": "kc", "password": "helloworld" } ]
Como vemos ahora estamos obteniendo la información de la base de datos de Estados Unidos.
Puedes encontrar el código completo en el siguiente link https://github.com/raidentrance/spring-multiple-db/blob/master/pom.xml.
Si te gusta el contenido y quieres enterarte cuando realicemos un post nuevo síguenos en nuestras redes sociales https://twitter.com/geeks_mx y https://www.facebook.com/geeksJavaMexico/.
Autor: Alejandro Agapito Bautista
Twitter: @raidentrance
Contacto:raidentrance@gmail.com