Modernization Tutorial
Este tutorial te guiará a modernizar una aplicación Java Swing existente integrándola con webforJ utilizando el WebswingConnector. Aprenderás cómo hacer que una aplicación de escritorio tradicional sea accesible por la web y agregar de manera incremental características modernas de la web, como diálogos basados en la web y formularios interactivos utilizando componentes de webforJ.
Antes de comenzar este tutorial, completa los pasos de Configuración y Preparación para configurar tu servidor Webswing y los ajustes de CORS.
El código fuente completo de este tutorial está disponible en GitHub: webforj/webforj-webswing-integration-tutorial
El escenario
Imagina que tienes una aplicación de gestión de clientes construida con Swing que ha estado en producción durante años. Funciona bien, pero ahora los usuarios esperan acceso web y una interfaz moderna. En lugar de reescribir desde cero, usarás Webswing para hacerla accesible por la web de inmediato y luego agregar de manera incremental características modernas de la web, como diálogos y formularios basados en la web utilizando componentes de webforJ.
Punto de partida: la aplicación Swing
La aplicación Swing de ejemplo es una tabla de clientes con operaciones CRUD típicas. Como muchas aplicaciones empresariales de Swing, sigue patrones estándar:
public class Application {
private List<Customer> customers;
private DefaultTableModel model;
private JTable table;
private void createTable() {
String[] columnNames = { "Nombre", "Empresa", "Correo" };
model = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
table = new JTable(model);
table.setRowHeight(30);
table.setRowSelectionAllowed(true);
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
// Manejar doble clic para editar
}
}
});
}
private void showEditDialog(Customer customer) {
JTextField nameField = new JTextField(customer.getName());
JTextField companyField = new JTextField(customer.getCompany());
JTextField emailField = new JTextField(customer.getEmail());
Object[] fields = {
"Nombre:", nameField,
"Empresa:", companyField,
"Correo:", emailField
};
int result = JOptionPane.showConfirmDialog(null, fields, "Editar Cliente",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
}
}
Esta aplicación funciona perfectamente como una aplicación de escritorio, pero carece de accesibilidad web. Los usuarios deben instalar Java y ejecutar el archivo JAR localmente.
Paso 1: hacerlo consciente de Webswing
El primer paso es hacer que la aplicación Swing detecte si está en ejecución bajo Webswing. Esto le permite adaptar su comportamiento sin romper la compatibilidad de escritorio.
Detectar el entorno Webswing
Agrega la dependencia de la API de Webswing a tu proyecto Swing:
<dependency>
<groupId>org.webswing</groupId>
<artifactId>webswing-api</artifactId>
<version>25.1</version>
</dependency>
Luego modifica tu aplicación para detectar el tiempo de ejecución de Webswing:
private void initWebswing() {
api = WebswingUtil.getWebswingApi();
isWebswing = api != null;
if (isWebswing) {
setupWebswingListeners();
}
}
La clave aquí es que WebswingUtil.getWebswingApi() devuelve null cuando se ejecuta como una aplicación de escritorio normal, lo que permite mantener la compatibilidad dual.
Adaptar el comportamiento para la implementación web
Con la detección en su lugar, ahora puedes adaptar el comportamiento de la aplicación. El cambio más importante es cómo se manejan las interacciones del usuario:
private void handleDoubleClick(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
if (row >= 0 && row < customers.size()) {
Customer customer = customers.get(row);
if (isWebswing) {
api.sendActionEvent("select-customer", gson.toJson(customer), null);
} else {
showEditDialog(customer);
}
}
}
Al ramificar el comportamiento de acuerdo con el valor de isWebswing, la base de código puede manejar ambos entornos.
Paso 2: crear el envoltorio de webforJ
Ahora que la aplicación Swing puede comunicarse a través de eventos, crea una aplicación webforJ que embebe la aplicación Swing y agrega características modernas de la web, como diálogos y formularios basados en la web.
Configurando el conector
El componente WebswingConnector embebe tu aplicación alojada en Webswing dentro de una vista de webforJ:
@Route("/")
public class CustomerTableView extends Composite<FlexLayout> {
private final FlexLayout self = getBoundComponent();
public CustomerTableView(@Value("${webswing.connector.url}") String webswingUrl) {
WebswingConnector connector = new WebswingConnector(webswingUrl);
connector.setSize("100vw", "100vh");
self.add(connector);
}
}
El conector se conecta a tu servidor Webswing, estableciendo un canal de comunicación bidireccional.
Manejo de eventos desde Swing
Cuando la aplicación Swing envía eventos (como cuando un usuario hace doble clic en una fila), el conector los recibe:
connector.onAction(event -> {
switch (event.getActionName()) {
case "select-customer":
event.getActionData().ifPresent(data -> {
JsonObject customer = JsonParser.parseString(data).getAsJsonObject();
CustomerForm dialog = new CustomerForm(customer);
self.add(dialog);
dialog.onSave(() -> {
Gson gson = new Gson();
connector.performAction("update-customer", gson.toJson(customer));
});
});
break;
}
});
Ahora, en lugar del diálogo de Swing, los usuarios ven un formulario web moderno construido con componentes de webforJ.
Paso 3: comunicación bidireccional
La integración se vuelve poderosa cuando la comunicación fluye en ambas direcciones. La aplicación webforJ puede enviar actualizaciones de vuelta a la aplicación Swing, manteniendo sincronizadas ambas interfaces.
Enviando actualizaciones a Swing
Después de que el usuario edita un cliente en el diálogo de webforJ:
dialog.onSave(() -> {
// Enviar el cliente actualizado de vuelta a Swing
connector.performAction("update-customer", gson.toJson(customer));
});
Procesando actualizaciones en Swing
La aplicación Swing escucha estas actualizaciones y refresca su display:
private void setupWebswingListeners() {
api.addBrowserActionListener(event -> {
if ("update-customer".equals(event.getActionName())) {
Customer updated = gson.fromJson(event.getData(), Customer.class);
updateCustomer(updated);
}
});
}
Beneficios de la arquitectura
Este enfoque ofrece varias ventajas sobre una reescritura completa:
Implementación web inmediata
Tu aplicación Swing se vuelve accesible por la web de inmediato sin cambios en el código. Los usuarios pueden acceder a ella a través de un navegador mientras trabajas en mejoras.
Mejora progresiva
Comienza reemplazando solo el diálogo de edición, luego reemplaza gradualmente más componentes:
- Fase 1: Ember la aplicación Swing completa, reemplaza solo el diálogo de edición
- Fase 2: Agregar navegación y menús de webforJ alrededor de la aplicación embebida
- Fase 3: Reemplazar la tabla con una tabla de webforJ, manteniendo Swing para características insustituibles
- Fase 4: Finalmente reemplazar todos los componentes Swing
Mitigación de riesgos
Dado que la aplicación Swing original sigue siendo funcional, puedes:
- Retroceder a la implementación de escritorio si es necesario
- Probar nuevas características junto a las existentes
- Migrar a los usuarios gradualmente
- Mantener la misma lógica de negocio