1. Script de la Base de Datos (MySQL)
Desarrolla el siguiente script en tu servidor local utilizando la interfaz de PHPMyAdmin:
CREATE DATABASE IF NOT EXISTS MiEmpresa;
USE MiEmpresa;
CREATE TABLE empleados (
id_empleado INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(50) NOT NULL,
apellidos VARCHAR(100) NOT NULL,
anio_nacimiento INT NOT NULL,
edad INT NOT NULL,
sexo VARCHAR(15) NOT NULL,
areas_interes VARCHAR(200)
);
Asegúrate de que el servicio de MySQL esté corriendo en tu panel de control de XAMPP antes de ejecutar la sentencia.
2. Creación del Proyecto en el IDE
Utilizando el entorno de desarrollo de tu elección (Ej. NetBeans 29), realiza la siguiente configuración inicial:
- Crea un proyecto de tipo JAVA Application.
- Asigna al proyecto el nombre exacto de:
CRUD. - Importante: Desmarca la opción de crear la clase principal (
main), ya que la ejecución se controlará de manera independiente desde la interfaz gráfica más adelante.
3. Clase ConexionDB.java
Crea una clase llamada ConexionDB.java dentro del paquete CRUD. Esta clase se encarga exclusivamente de establecer la comunicación física con el servidor local de XAMPP.
package CRUD;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConexionDB {
private static final String URL = "jdbc:mysql://localhost:3306/MiEmpresa?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = ""; // Por defecto vacío en XAMPP
public Connection conectar() {
Connection conexion = null;
try {
// Carga dinámica del driver para compatibilidad
Class.forName("com.mysql.cj.jdbc.Driver");
conexion = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (ClassNotFoundException e) {
System.err.println("Error: No se encontró el Driver de MySQL: " + e.getMessage());
} catch (SQLException e) {
System.err.println("Error de conexión a la BD: " + e.getMessage());
}
return conexion;
}
}
4. Clase Empleado.java (Modelo / POJO)
Crea la clase Empleado.java dentro del paquete CRUD. Funciona como un molde o contenedor de transporte de datos entre las distintas capas lógicas del sistema.
package CRUD;
public class Empleado {
private int idEmpleado;
private String nombre;
private String apellidos;
private int anioNacimiento;
private int edad;
private String sexo;
private String areasInteres;
// Constructor vacío
public Empleado() {}
// Constructor completo
public Empleado(int idEmpleado, String nombre, String apellidos, int anioNacimiento, int edad, String sexo, String areasInteres) {
this.idEmpleado = idEmpleado;
this.nombre = nombre;
this.apellidos = apellidos;
this.anioNacimiento = anioNacimiento;
this.edad = edad;
this.sexo = sexo;
this.areasInteres = areasInteres;
}
// Getters y Setters
public int getIdEmpleado() { return idEmpleado; }
public void setIdEmpleado(int idEmpleado) { this.idEmpleado = idEmpleado; }
public String getNombre() { return nombre; }
public void setNombre(String nombre) { this.nombre = nombre; }
public String getApellidos() { return apellidos; }
public void setApellidos(String apellidos) { this.apellidos = apellidos; }
public int getAnioNacimiento() { return anioNacimiento; }
public void setAnioNacimiento(int anioNacimiento) { this.anioNacimiento = anioNacimiento; }
public int getEdad() { return edad; }
public void setEdad(int edad) { this.edad = edad; }
public String getSexo() { return sexo; }
public void setSexo(String sexo) { this.sexo = sexo; }
public String getAreasInteres() { return areasInteres; }
public void setAreasInteres(String areasInteres) { this.areasInteres = areasInteres; }
}
5. Clase EmpleadoDAO.java (Data Access Object)
Crea la clase EmpleadoDAO.java. Su objetivo esencial es la persistencia, encargándose de enviar y procesar las sentencias SQL (INSERT, SELECT, UPDATE, DELETE) directo en el motor de Base de Datos.
package CRUD;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class EmpleadoDAO {
private final ConexionDB conexionDB = new ConexionDB();
// 1. CREATE (Insertar)
public boolean agregar(Empleado emp) {
String sql = "INSERT INTO empleados (nombre, apellidos, anio_nacimiento, edad, sexo, areas_interes) VALUES (?, ?, ?, ?, ?, ?)";
try (Connection con = conexionDB.conectar();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, emp.getNombre());
ps.setString(2, emp.getApellidos());
ps.setInt(3, emp.getAnioNacimiento());
ps.setInt(4, emp.getEdad());
ps.setString(5, emp.getSexo());
ps.setString(6, emp.getAreasInteres());
return ps.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("Error al agregar: " + e.getMessage());
return false;
}
}
// 2. READ (Listar todos)
public List<Empleado> listar() {
List<Empleado> lista = new ArrayList<>();
String sql = "SELECT * FROM empleados";
try (Connection con = conexionDB.conectar();
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
Empleado emp = new Empleado();
emp.setIdEmpleado(rs.getInt("id_empleado"));
emp.setNombre(rs.getString("nombre"));
emp.setApellidos(rs.getString("apellidos"));
emp.setAnioNacimiento(rs.getInt("anio_nacimiento"));
emp.setEdad(rs.getInt("edad"));
emp.setSexo(rs.getString("sexo"));
emp.setAreasInteres(rs.getString("areas_interes"));
lista.add(emp);
}
} catch (SQLException e) {
System.err.println("Error al listar: " + e.getMessage());
}
return lista;
}
// 3. UPDATE (Modificar)
public boolean modificar(Empleado emp) {
String sql = "UPDATE empleados SET nombre=?, apellidos=?, anio_nacimiento=?, edad=?, sexo=?, areas_interes=? WHERE id_empleado=?";
try (Connection con = conexionDB.conectar();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, emp.getNombre());
ps.setString(2, emp.getApellidos());
ps.setInt(3, emp.getAnioNacimiento());
ps.setInt(4, emp.getEdad());
ps.setString(5, emp.getSexo());
ps.setString(6, emp.getAreasInteres());
ps.setInt(7, emp.getIdEmpleado());
return ps.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("Error al modificar: " + e.getMessage());
return false;
}
}
// 4. DELETE (Eliminar)
public boolean eliminar(int id) {
String sql = "DELETE FROM empleados WHERE id_empleado=?";
try (Connection con = conexionDB.conectar();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setInt(1, id);
return ps.executeUpdate() > 0;
} catch (SQLException e) {
System.err.println("Error al eliminar: " + e.getMessage());
return false;
}
}
}
6. Interfaz y Controlador: FrmEmpleados.java
Crea un formulario utilizando la biblioteca de javax.swing. Esta clase une la representación visual con los controladores de acción del CRUD. Es la clase que contiene el Método Principal Main ()
package CRUD;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Calendar;
import java.util.List;
public class FrmEmpleados extends JFrame {
// Componentes del Formulario
private JTextField txtNombre, txtApellidos, txtEdad, txtOtro;
private JComboBox cbAnioNacimiento;
private JRadioButton rbFemenino, rbMasculino;
private ButtonGroup grupoSexo;
private JCheckBox chkFutbol, chkVoleiball, chkOtro;
private JTable tblEmpleados;
private DefaultTableModel modeloTabla;
// Botones de Acción
private JButton btnAgregar, btnModificar, btnEliminar, btnCerrar;
// Instancia del DAO para operaciones
private final EmpleadoDAO empleadoDAO = new EmpleadoDAO();
private int idSeleccionado = -1; // Almacena el ID del registro seleccionado de la tabla
public FrmEmpleados() {
setTitle("Mantenimiento de Empleados");
setSize(850, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
initComponents();
listarEmpleados();
}
private void initComponents() {
// Contenedor principal con Layout nulo para posicionamiento absoluto fiel a la captura
JPanel panelPrincipal = new JPanel(null);
panelPrincipal.setBackground(new Color(245, 245, 245));
setContentPane(panelPrincipal);
// --- SECCIÓN: Datos Generales del Empleado ---
JPanel panelDatos = new JPanel(null);
panelDatos.setBounds(20, 20, 790, 240);
panelDatos.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), "Datos Generales del Empleado", TitledBorder.LEFT, TitledBorder.TOP, new Font("Arial", Font.BOLD, 12)));
panelPrincipal.add(panelDatos);
JLabel lblNombre = new JLabel("Nombre del emplea...");
lblNombre.setBounds(20, 30, 130, 25);
panelDatos.add(lblNombre);
txtNombre = new JTextField();
txtNombre.setBounds(160, 30, 150, 25);
panelDatos.add(txtNombre);
JLabel lblApellidos = new JLabel("Apellidos:");
lblApellidos.setBounds(20, 70, 130, 25);
panelDatos.add(lblApellidos);
txtApellidos = new JTextField();
txtApellidos.setBounds(160, 70, 610, 25);
panelDatos.add(txtApellidos);
JLabel lblAnio = new JLabel("Año de nacimiento:");
lblAnio.setBounds(20, 110, 130, 25);
panelDatos.add(lblAnio);
cbAnioNacimiento = new JComboBox<>();
int anioActual = Calendar.getInstance().get(Calendar.YEAR);
for (int i = anioActual; i >= 1920; i--) {
cbAnioNacimiento.addItem(i);
}
cbAnioNacimiento.setBounds(160, 110, 90, 25);
// Evento para calcular automáticamente la edad al cambiar el año de nacimiento
cbAnioNacimiento.addActionListener(e -> {
int anioSeleccionado = (int) cbAnioNacimiento.getSelectedItem();
txtEdad.setText(String.valueOf(anioActual - anioSeleccionado));
});
panelDatos.add(cbAnioNacimiento);
JLabel lblEdad = new JLabel("Edad:");
lblEdad.setBounds(270, 110, 40, 25);
panelDatos.add(lblEdad);
txtEdad = new JTextField("0");
txtEdad.setBounds(310, 110, 110, 25);
txtEdad.setEditable(false);
txtEdad.setBackground(Color.WHITE);
panelDatos.add(txtEdad);
JLabel lblSexo = new JLabel("Sexo:");
lblSexo.setBounds(450, 110, 40, 25);
panelDatos.add(lblSexo);
rbFemenino = new JRadioButton("Femenino");
rbFemenino.setBounds(490, 105, 100, 20);
rbFemenino.setOpaque(false);
rbMasculino = new JRadioButton("Masculino");
rbMasculino.setBounds(490, 125, 100, 20);
rbMasculino.setOpaque(false);
grupoSexo = new ButtonGroup();
grupoSexo.add(rbFemenino);
grupoSexo.add(rbMasculino);
panelDatos.add(rbFemenino);
panelDatos.add(rbMasculino);
JLabel lblInteres = new JLabel("Areas de Interés:");
lblInteres.setBounds(20, 170, 130, 25);
panelDatos.add(lblInteres);
chkFutbol = new JCheckBox("Fútbol");
chkFutbol.setBounds(160, 170, 80, 25);
chkFutbol.setOpaque(false);
panelDatos.add(chkFutbol);
chkVoleiball = new JCheckBox("Voleiball");
chkVoleiball.setBounds(250, 170, 90, 25);
chkVoleiball.setOpaque(false);
panelDatos.add(chkVoleiball);
chkOtro = new JCheckBox("Otro");
chkOtro.setBounds(370, 170, 60, 25);
chkOtro.setOpaque(false);
panelDatos.add(chkOtro);
txtOtro = new JTextField();
txtOtro.setBounds(430, 170, 340, 25);
panelDatos.add(txtOtro);
// --- SECCIÓN: Lista de Empleados ---
JPanel panelLista = new JPanel(null);
panelLista.setBounds(20, 280, 790, 210);
panelLista.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), "Lista de Empleados", TitledBorder.LEFT, TitledBorder.TOP, new Font("Arial", Font.BOLD, 12)));
panelPrincipal.add(panelLista);
modeloTabla = new DefaultTableModel(new Object[]{"Nombre", "Apellidos", "Año", "Edad", "Sexo", "Areas"}, 0);
tblEmpleados = new JTable(modeloTabla);
JScrollPane scrollPane = new JScrollPane(tblEmpleados);
scrollPane.setBounds(15, 25, 760, 165);
panelLista.add(scrollPane);
// Evento al dar clic sobre un registro de la JTable
tblEmpleados.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
cargarCamposDesdeTabla();
}
});
// --- SECCIÓN: Botones de Acción de la Interfaz ---
btnAgregar = new JButton("Agregar");
btnAgregar.setBounds(40, 510, 160, 40);
btnAgregar.addActionListener(e -> accionAgregar());
panelPrincipal.add(btnAgregar);
btnModificar = new JButton("Modificar");
btnModificar.setBounds(230, 510, 160, 40);
btnModificar.addActionListener(e -> accionModificar());
panelPrincipal.add(btnModificar);
btnEliminar = new JButton("Eliminar");
btnEliminar.setBounds(420, 510, 160, 40);
btnEliminar.addActionListener(e -> accionEliminar());
panelPrincipal.add(btnEliminar);
btnCerrar = new JButton("Cerrar");
btnCerrar.setBounds(610, 510, 160, 40);
btnCerrar.addActionListener(e -> System.exit(0));
panelPrincipal.add(btnCerrar);
}
// --- CONTROLADOR: Métodos Lógicos del CRUD ---
private void listarEmpleados() {
modeloTabla.setRowCount(0); // Vaciar tabla visual
List lista = empleadoDAO.listar();
// Usamos un ciclo for tradicional por índice para evitar conflictos de tipo 'Object'
for (int i = 0; i < lista.size(); i++) {
Empleado e = (Empleado) lista.get(i);
modeloTabla.addRow(new Object[]{
e.getNombre(),
e.getApellidos(),
e.getAnioNacimiento(),
e.getEdad(),
e.getSexo(),
e.getAreasInteres()
});
}
}
private void accionAgregar() {
Empleado emp = mapearFormulario();
if (emp != null) {
if (empleadoDAO.agregar(emp)) {
JOptionPane.showMessageDialog(this, "¡Empleado guardado exitosamente!");
limpiarFormulario();
listarEmpleados();
} else {
JOptionPane.showMessageDialog(this, "Error crítico al guardar en la BD.");
}
}
}
private void accionModificar() {
if (idSeleccionado == -1) {
JOptionPane.showMessageDialog(this, "Por favor, seleccione un empleado de la lista.");
return;
}
Empleado emp = mapearFormulario();
if (emp != null) {
emp.setIdEmpleado(idSeleccionado);
if (empleadoDAO.modificar(emp)) {
JOptionPane.showMessageDialog(this, "¡Registro actualizado!");
limpiarFormulario();
listarEmpleados();
} else {
JOptionPane.showMessageDialog(this, "Error al intentar modificar.");
}
}
}
private void accionEliminar() {
if (idSeleccionado == -1) {
JOptionPane.showMessageDialog(this, "Por favor, seleccione un empleado de la lista.");
return;
}
int confirmacion = JOptionPane.showConfirmDialog(this, "¿Está seguro de eliminar este registro?", "Confirmar eliminación", JOptionPane.YES_NO_OPTION);
if (confirmacion == JOptionPane.YES_OPTION) {
if (empleadoDAO.eliminar(idSeleccionado)) {
JOptionPane.showMessageDialog(this, "Empleado eliminado correctamente.");
limpiarFormulario();
listarEmpleados();
} else {
JOptionPane.showMessageDialog(this, "Error al eliminar el registro.");
}
}
}
private Empleado mapearFormulario() {
if (txtNombre.getText().trim().isEmpty() || txtApellidos.getText().trim().isEmpty()) {
JOptionPane.showMessageDialog(this, "Por favor ingrese Nombre y Apellidos.");
return null;
}
String sexo = "";
if (rbFemenino.isSelected()) sexo = "Femenino";
else if (rbMasculino.isSelected()) sexo = "Masculino";
else {
JOptionPane.showMessageDialog(this, "Seleccione el sexo del empleado.");
return null;
}
// Concatenación de Áreas de Interés como String plano legible
StringBuilder areas = new StringBuilder();
if (chkFutbol.isSelected()) areas.append("Fútbol, ");
if (chkVoleiball.isSelected()) areas.append("Voleiball, ");
if (chkOtro.isSelected() && !txtOtro.getText().trim().isEmpty()) {
areas.append(txtOtro.getText().trim()).append(", ");
}
String areasStr = areas.toString();
if (areasStr.endsWith(", ")) {
areasStr = areasStr.substring(0, areasStr.length() - 2);
}
Empleado emp = new Empleado();
emp.setNombre(txtNombre.getText().trim());
emp.setApellidos(txtApellidos.getText().trim());
emp.setAnioNacimiento((int) cbAnioNacimiento.getSelectedItem());
emp.setEdad(Integer.parseInt(txtEdad.getText()));
emp.setSexo(sexo);
emp.setAreasInteres(areasStr);
return emp;
}
private void cargarCamposDesdeTabla() {
int fila = tblEmpleados.getSelectedRow();
if (fila >= 0) {
// Recuperamos los datos del objeto directo en el DAO usando el índice
List lista = empleadoDAO.listar();
Empleado emp = (Empleado) lista.get(fila);
idSeleccionado = emp.getIdEmpleado(); // LLAVE PRIMARIA PARA EL UPDATE/DELETE
txtNombre.setText(emp.getNombre());
txtApellidos.setText(emp.getApellidos());
cbAnioNacimiento.setSelectedItem(emp.getAnioNacimiento());
txtEdad.setText(String.valueOf(emp.getEdad()));
if (emp.getSexo().equalsIgnoreCase("Femenino")) rbFemenino.setSelected(true);
else rbMasculino.setSelected(true);
// Reseteo de Checks
chkFutbol.setSelected(emp.getAreasInteres().contains("Fútbol"));
chkVoleiball.setSelected(emp.getAreasInteres().contains("Voleiball"));
// Si el texto almacenado tiene más cosas aparte de Fútbol y Voleiball, se mapea al campo "Otro"
String cleanAreas = emp.getAreasInteres().replace("Fútbol", "").replace("Voleiball", "").replace(",", "").trim();
if (!cleanAreas.isEmpty()) {
chkOtro.setSelected(true);
txtOtro.setText(cleanAreas);
} else {
chkOtro.setSelected(false);
txtOtro.setText("");
}
}
}
private void limpiarFormulario() {
txtNombre.setText("");
txtApellidos.setText("");
cbAnioNacimiento.setSelectedIndex(0);
txtEdad.setText("0");
grupoSexo.clearSelection();
chkFutbol.setSelected(false);
chkVoleiball.setSelected(false);
chkOtro.setSelected(false);
txtOtro.setText("");
idSeleccionado = -1;
}
public static void main(String[] args) {
// Ejecución de la interfaz con el hilo de Swing de forma segura
SwingUtilities.invokeLater(() -> new FrmEmpleados().setVisible(true));
}
}
7. Roles Funcionales de las Clases
Analiza el comportamiento y la responsabilidad de cada estructura generada en el proyecto:
| Clase | Rol Principal | Funcionalidad Clave |
|---|---|---|
| ConexionDB | Canal de Comunicación | Abre y gestiona el puente físico (Connection) entre Java y MySQL en XAMPP. |
| Empleado | Contenedor de Datos (POJO) | Molde que almacena en memoria los datos del empleado mediante Getters/Setters. |
| EmpleadoDAO | Persistencia (CRUD) | Ejecuta las consultas SQL (INSERT, SELECT, UPDATE, DELETE) en la BD. |
| FrmEmpleados | Interfaz y Controlador | Dibuja la pantalla, captura los clics del usuario y actualiza la tabla visual. |
8. Configuración de Dependencias (Driver SQL)
Para lograr la intercomunicación del sistema con la BD, vincula el conector oficial mediante alguno de los siguientes dos métodos:
Método A: Automatizado por Maven
| Paso | Acción en NetBeans | Datos a Ingresar |
|---|---|---|
| 1. Ubicar | Desplegar el árbol del proyecto; clic derecho en la carpeta Dependencies. | Ninguno |
| 2. Abrir | Seleccionar la opción Add Dependency... del menú. | Ninguno |
| 3. Llenar | Introducir coordenadas Maven oficiales del driver de MySQL. | Group ID: com.mysql Artifact ID: mysql-connector-j Version: 8.3.0 |
| 4. Finalizar | Clic en Add para descargar e indexar automáticamente. | Ninguno |
Método B: Configuración Manual (.JAR)
| Paso | Acción en NetBeans / Sistema | Detalle |
|---|---|---|
| 1. Descargar | Entrar al portal de MySQL y bajar el conector. | Elegir Platform Independent y descomprimir el zip para obtener el archivo mysql-connector-j-8.x.x.jar. |
| 2. Ubicar | Ir al panel Projects y expandir el árbol de carpetas. | Clic derecho sobre la carpeta Libraries (Bibliotecas). |
| 3. Agregar | Seleccionar la opción Add JAR/Folder... | Se abrirá un explorador de archivos integrado del IDE. |
| 4. Vincular | Buscar y seleccionar el archivo .jar extraído. | Clic en Abrir/Aceptar para enlazar la librería permanentemente. |