Programa ejemplo en Java (Maven) que vuelca un archivo Excel (.xlsx) a una base de datos MySQL y viceversa.
Este programa genérico en Java es un ejercicio simple que permite:
- Leer un libro Excel y volcarlo a una base de datos MySQL.
- Escribir desde una base de datos MySQL a un fichero Excel.
- Configurar la conexión y los ficheros de entrada/salida mediante un archivo
config.properties.
El programa lee la configuración de la base de datos de un fichero de propiedades de Java y, con Apache POI, procesa las hojas del Excel:
- El nombre de cada hoja se convierte en el nombre de la tabla.
- La primera fila define los nombres de los atributos.
- La segunda fila se utiliza para inferir el tipo de dato de cada columna.
La estructura principal es el libro, que contiene una lista de tablas, y cada tabla contiene tuplas con nombre de campo y tipo de dato.
Con argumentos:
excel2database -f fichero.xlsx -db agendaSin argumentos (modo por defecto): Se utiliza la configuración definida manualmente en el archivo config.properties.
Asegúrate de tener instalado Java (JDK 8 o superior) y Maven.
Instalamos las dependencias Maven:
- apache poi
- apache poi ooxml
- mysql
Creamos el archivo config.properties:
# 1.- Usuario de la base de datos
user=root
# 2.- Contraseña del usuario de la BBDD
password=s83n38DGB8d72
# 3.- Charset Unicode para evitar problemas con acentos o caracteres especiales
useUnicode=yes
# 4.- Ajuste de zona horaria para JDBC compatible
useJDBCCompliantTimezoneShift=true
# 5.- Puerto de conexión MySQL
port=33307
# 6.- Nombre de la base de datos
database=agenda
# 7.- Host de la BBDD (localhost indica que está en la misma máquina)
host=localhost
# 8.- Tipo de driver de base de datos
driver=MySQL
# 9.- Archivo de salida para exportar datos (BBDD → Excel)
outputFile=datos/salida.xlsx
# 10.- Archivo de entrada para importar datos (Excel → BBDD)
inputFile=datos/entrada.xlsx
# 11.- Desactivar SSL para conexiones locales
useSSL=false
# 12.- Configurar zona horaria del servidor
serverTimezone=Europe/Madrid
# 13.- Permitir recuperación de clave pública (requerido para MySQL 8+)
allowPublicKeyRetrieval=true
# 14.- Acción que se ejecutará al iniciar Excel2Database
# Puede ser "download" (exportar BBDD → Excel)
action=download
# 15.- Acción alternativa para importar Excel → BBDD
# action=save
# 16.- Archivo de Excel que se usará como entrada para "save"
file=datos/entrada/test.xlsx
# 17.- Archivo de Excel donde se guardarán los datos exportados para "download"
fileDownload=datos/salida/salidatest.xlsx
En producción jamás debemos de usar estos parámetros:
useSSL=false: No encripta la conexión.allowPublicKeyRetrieval=true: No comprueba el certificado (como el candado rojo del navegador)
Con Apache POI puedes inspeccionar el tipo de dato almacenado en una celda de Excel (.xlsx) y actuar según corresponda. Cuando trabajas con una celda (Cell), POI te permite preguntar su tipo con:
cell.getCellType()Esto devuelve un valor del enum CellType, que puede ser:
Tipo (CellType) |
Significado |
|---|---|
NUMERIC |
Número (entero o decimal, o incluso fecha/hora si el formato lo indica) |
STRING |
Texto |
BOOLEAN |
Verdadero/Falso |
FORMULA |
Celda con una fórmula |
BLANK |
Celda vacía |
ERROR |
Celda con error |
Excel almacena las fechas y horas como números (un número de días desde el 1/1/1900). Para distinguirlas, Apache POI ofrece un método:
DateUtil.isCellDateFormatted(cell)Si devuelve true, el contenido es una fecha o una hora, y puedes obtenerla así:
Date fecha = cell.getDateCellValue();Si no, puedes tratarlo como número:
double valor = cell.getNumericCellValue();En Excel, todos los números se almacenan como double internamente. No existe distinción “formal” entre enteros y decimales dentro del archivo. Por eso, Apache POI siempre te devuelve NUMERIC y cell.getNumericCellValue() da un double. Como Excel no distingue formalmente entre ellos: ambos son NUMERIC, podemos comprobarlo fácilmente así:
double valor = cell.getNumericCellValue();
if (valor == Math.floor(valor)) {
System.out.println("Entero: " + (int) valor);
} else {
System.out.println("Decimal: " + valor);
}Un ejemplo de cómo hacer la detección sería:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.DateUtil;
public class ExcelUtils {
private static final double EPSILON = 1e-10;
/**
* Devuelve un String indicando el tipo de dato de la celda.
* Puede ser: Entero, Decimal, Texto, Booleano, Fecha, Vacía, Fórmula, Error
*/
public static String getTipoDato(Cell cell) {
if (cell == null) {
return "Vacía";
}
switch (cell.getCellType()) {
case STRING:
return "Texto";
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
return "Fecha";
} else {
double valor = cell.getNumericCellValue();
if (Math.abs(valor - Math.floor(valor)) < EPSILON) {
return "Entero";
} else {
return "Decimal";
}
}
case BOOLEAN:
return "Booleano";
case FORMULA:
// Puedes decidir si quieres evaluar la fórmula o solo indicar que es fórmula
return "Fórmula";
case BLANK:
return "Vacía";
case ERROR:
return "Error";
default:
return "Desconocido";
}
}
}Para crear una base de datos en MySQL hacemos:
create database `agenda`;Para borrar una base de datos en MySQL hacemos:
drop database `agenda`;CREATE DATABASE `agenda` COLLATE 'utf16_spanish_ci';Crear una tabla de personas:
DROP TABLE IF EXISTS `personas`;
CREATE TABLE `personas` (
`nombre` varchar(100) NOT NULL,
`apellidos` varchar(300) NOT NULL,
`email` varchar(100),
`telefono` varchar(12),
`genero` enum('FEMENINO','MASCULINO','NEUTRO','OTRO') NOT NULL,
`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE='InnoDB';
DROP TABLE IF EXISTS `probando`;
CREATE TABLE `probando` (
`idprobando` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`probando` VARCHAR(100),
`movidas` VARCHAR(100),
`teleco` VARCHAR(100),
`aaaaa` VARCHAR(100),
`puesweso` VARCHAR(100)
) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_spanish_ci;
INSERT INTO `personas` (nombre, apellidos, email, telefono, genero)
VALUES
('GABRIEL', 'VAZQUEZ CASTRO', 'gvazcas@mail2webtop.com', '771234646', 'MASCULINO'),
('OSCAR', 'MUÑOZ ORTIZ', 'omunort@mlb.bounce.ed10.net', '684390051', 'MASCULINO'),
('LIDIA', 'IGLESIAS MOYA', 'liglmoy@mail2saudi.com', '717631732', 'FEMENINO'),
('MOHAMED', 'HERRERA MARIN', 'mhermar@interburp.com', '750292099', 'MASCULINO'),
('MARIA SOLEDAD', 'MORENO MORENO', 'mmormor@mail.ru', '720699755', 'NEUTRO'),
('RAMON', 'SANTOS SOTO', 'rsansot@outlook.it', '622708296', 'MASCULINO'),
('MARIA ROSA', 'GARRIDO LEON', 'mgarleo@i.ua', '701354268', 'NEUTRO'),
('PAU', 'PEÑA RODRIGUEZ', 'ppenrod@unforgettable.com', '621041509', 'OTRO'),
('FRANCISCO JOSE', 'CRESPO MARIN', 'fcremar@dfwatson.com', '682207168', 'NEUTRO');
INSERT INTO `probando` (probando, movidas, teleco, aaaaa, puesweso)
VALUES
('prueba1', 'movidas1', 'teleco1', 'aaaaa1', 'puesweso1'),
('prueba2', 'movidas2', 'teleco2', 'aaaaa2', 'puesweso2'),
('prueba3', 'movidas3', 'teleco3', 'aaaaa3', 'puesweso3'),
('prueba4', 'movidas4', 'teleco4', 'aaaaa4', 'puesweso4'),
('prueba5', 'movidas5', 'teleco5', 'aaaaa5', 'puesweso5'),
('prueba6', 'movidas6', 'teleco6', 'aaaaa6', 'puesweso6'),
('prueba7', 'movidas7', 'teleco7', 'aaaaa7', 'puesweso7'),
('prueba8', 'movidas8', 'teleco8', 'aaaaa8', 'puesweso8'),
('prueba9', 'movidas9', 'teleco9', 'aaaaa9', 'puesweso9');
SELECT * FROM `personas` LIMIT 50;
SELECT * FROM `personas` LIMIT 5 OFFSET 10;# Este repositorio es un ejemplo educativo.
# No usar credenciales en texto plano en producción.
# Se recomienda añadir tests unitarios para validar la conversión Excel ↔ MySQL.