Indice

''openUploadUI()''

Panoramica

openUploadUI() apre un'interfaccia grafica per il caricamento di file che invia i file selezionati al server, dove vengono elaborati da uno script Groovy specificato dallo sviluppatore.

L'UI offre:

UI minimale, nessun parametro: openuploadui_1.jpg

UI che mostra la selezione corrente openuploadui_2.jpg

Notifica standard si avvenuto caricamento in base al messaggio ritornato dal groovy openuploadui_3.jpg


Firma della funzione

openUploadUI(scriptName, options)
Parametro Tipo Obbligatorio Descrizione
scriptName String Nome in notazione dot del Groovy script da eseguire sul server (es. “mypackage.ImportScript”). L'estensione .groovy viene aggiunta automaticamente.
options Object No Oggetto di configurazione opzionale. Tutti i sotto-parametri sono opzionali.

Parametri di ''options''

Testo e istruzioni

Parametro Tipo Default Descrizione
instructions String null Testo di istruzioni mostrato all'utente in un'area stilizzata (gwInstructionsArea) sopra la drop zone. Accetta HTML.

openuploadui_4.jpg


Comportamento upload

Parametro Tipo Default Descrizione
autoupload Boolean false Se true, l'upload parte automaticamente non appena i file vengono selezionati o trascinati. Il pulsante “Carica” non viene mostrato.
multiple Boolean false Se true, permette la selezione e il caricamento di più file contemporaneamente. Se false e l'utente trascina più file, viene preso solo il primo.
maxUploadSizeMB Number null Dimensione massima totale in MB (somma di tutti i file selezionati). Se superata, il pulsante “Carica” viene disabilitato e viene mostrato un messaggio di errore. null = nessun limite.
allowedExtensions String[] null Array di estensioni consentite senza il punto iniziale (es. ['pdf', 'xlsx']). La restrizione viene propagata anche al file picker dell'OS tramite l'attributo accept. null = tutti i tipi consentiti.

Posizionamento UI

Parametro Tipo Default Descrizione
containerRef String | Widget | Node null Se assente, l'UI si apre in un FloatingPane. Se presente, l'UI viene inserita all'interno del contenitore indicato. Valori accettati: widget id (String), DOM node id (String), oggetto widget Dojo (ha .domNode), nodo DOM diretto.
dimensions Object {w:600, h:600} Dimensioni del FloatingPane in pixel. Ignorato se containerRef è presente. Formato: {w: 800, h: 500}.
modal Boolean false Se true, il FloatingPane apre in modalità modale. Ignorato se containerRef è presente.
useCookie Boolean false Se true, la posizione e le dimensioni del FloatingPane vengono salvate in localStorage e ripristinate alla successiva apertura. Ignorato se containerRef è presente.

Esempio di validazione fallita openuploadui_5.jpg

Esempio con utilizzo esteso dei parametri: openuploadui_6.jpg

Notifiche e callback

Parametro Tipo Default Descrizione
useToaster Boolean false Se true, la notifica di successo viene mostrata via messageToaster invece di showOkDialog(). Gli errori usano sempre showErrorDialog() salvo errorCallback personalizzato.
callback Function null Funzione chiamata dopo una risposta di successo. Riceve come unico argomento il JsonServerResponse completo. Se assente, viene usata la notifica predefinita (dialog o toaster).
errorCallback Function null Funzione chiamata in caso di errore. Riceve {success: false, description: String}. Se assente, viene chiamata showErrorDialog().

Parametri aggiuntivi per il Groovy

Parametro Tipo Default Descrizione
parameters Object null Mappa di parametri aggiuntivi da passare allo script Groovy nel binding. Vedi sezione Variabili disponibili nel Groovy.

Comportamento al successo

Modalità apertura Comportamento on success
FloatingPane + showOkDialog (default) Il FloatingPane si chiude quando l'utente clicca OK nel dialog.
FloatingPane + useToaster: true Il FloatingPane si chiude immediatamente; poi compare il toaster.
FloatingPane + callback personalizzato Il FloatingPane si chiude immediatamente dopo il callback.
containerRef + showOkDialog (default) L'UI si reimposta allo stato iniziale (vuota) quando l'utente clicca OK.
containerRef + useToaster: true L'UI si reimposta allo stato iniziale immediatamente; poi compare il toaster.
containerRef + callback personalizzato L'UI si reimposta allo stato iniziale immediatamente dopo il callback.

Variabili disponibili nel Groovy

Lo script Groovy riceve nel Binding le seguenti variabili:

Specifiche dell'upload

Variabile Tipo Descrizione
file MultipartFile Il primo file caricato (o null se nessun file).
files MultipartFile[] Array di tutti i file caricati.
parametersMap HashMap<String, Object> Mappa dei parametri aggiuntivi passati tramite options.parameters.
parameters HashMap<String, Object> Alias di parametersMap.
<chiave> Object Ogni entry di parameters è anche disponibile come variabile individuale nel binding (es. parameters: {userId: 42} → la variabile userId vale 42).
jsonServerResponse JsonServerResponse L'oggetto di risposta. Disponibile per lettura; success e description vengono applicati dal Map restituito dallo script.

Variabili di sessione (aggiunte da ''addSessionObjectInfo'')

Variabile Tipo Descrizione
gw_activeUser String Utente attivo.
gw_activeGroup String Gruppo attivo.
gw_activeScopes List Scope attivi (definizioni).
gw_activeScopeList List<Map> Scope attivi (forma leggibile).
gw_projectName String Nome del progetto.
gw_solutionCode String Codice soluzione dalla configurazione.

Servizi (aggiunti automaticamente da ''runScript'')

Variabile Tipo Descrizione
services HashMap Tutti i servizi registrati nel GwRegistry.
log Logger Logger Log4j per il Groovy script.
applicationContext ApplicationContext Contesto Spring.
environment Environment Variabili d'ambiente Spring.
ogni servizio vario Ogni servizio è anche disponibile come variabile individuale.

Contratto della risposta

Il controller legge esclusivamente il Map restituito dallo script per determinare successo e messaggio:

Chiave Tipo Descrizione
success Boolean true → operazione riuscita; false → fallimento
message String Messaggio mostrato all'utente (nel dialog o nel toaster)

Lo script può aggiungere dati extra alla risposta tramite jsonServerResponse.addResponseObject(“key”, value), accessibili nel callback JS come resp.responseHashMap.key.

<note warning> Attenzione: se lo script restituisce null o un tipo non-Map, il controller lancia una RuntimeException e l'upload viene considerato fallito. </note>


Template standard di Groovy script

// Script in: mypackage/ImportScript.groovy  →  scriptName: "mypackage.ImportScript"
 
def result = [:]
def success = false
def message = null
 
try {
    // Variabili disponibili nel binding:
    //   file           {MultipartFile}   – primo file caricato (o null se assente)
    //   files          {MultipartFile[]} – tutti i file caricati
    //   parametersMap  {Map}             – parametri extra inviati dal JS (alias: parameters)
    //   <chiave>       {Object}          – ogni entry di parametersMap è disponibile individualmente
    //   gw_activeUser, gw_activeGroup, gw_projectName, gw_projectPath, ...
    //   services, log, applicationContext, environment, ...
 
    def parameterValue = parametersMap.parameter_name
 
    // ... elaborazione ...
    byte[] bytes = file.getBytes()
    // ...
 
    success = true
    message = 'file(s) correctly processed'
 
} catch (Exception e) {
    log.error(e.getMessage(), e)
    success = false
    message = 'ko'
} finally {
    result.success = success
    result.message = message
}
 
return result

Esempi di utilizzo

1 — Uso minimo (solo ''scriptName'')

// Apre il FloatingPane default 600×600.
// L'utente seleziona un file e clicca "Carica".
// Al successo compare showOkDialog con il messaggio del server.
 
openUploadUI('mypackage.SimpleImport');

2 — ''instructions''

// Mostra un'area di testo con istruzioni sopra la drop zone.
 
openUploadUI('mypackage.SimpleImport', {
    instructions: 'Carica il file di importazione in formato Excel.<br>' +
                  'Il file non deve superare le 1000 righe.'
});

3 — ''autoupload''

// L'upload parte automaticamente non appena il file viene selezionato/trascinato.
// Il pulsante "Carica" non compare.
 
openUploadUI('mypackage.QuickProcess', {
    autoupload: true
});

4 — ''multiple''

// Permette la selezione e il caricamento di più file in una sola chiamata.
// Il server riceve files[] con tutti i file.
 
openUploadUI('mypackage.BatchImport', {
    multiple: true
});

5 — ''maxUploadSizeMB''

// Impedisce l'upload se la dimensione totale supera 5 MB.
// Il bottone "Carica" viene disabilitato e compare un messaggio localizzato.
 
openUploadUI('mypackage.DocumentUpload', {
    maxUploadSizeMB: 5
});

6 — ''allowedExtensions''

// Accetta solo file PDF e Word. La restrizione vale sia per il drag&drop
// sia per il file picker dell'OS (attributo accept).
 
openUploadUI('mypackage.DocumentImport', {
    allowedExtensions: ['pdf', 'doc', 'docx']
});

7 — ''containerRef'' (widget id)

// L'UI viene inserita nel widget Dojo con id "myContentPane"
// invece di aprire un FloatingPane.
 
openUploadUI('mypackage.EmbeddedUpload', {
    containerRef: 'myContentPane'
});

8 — ''containerRef'' (nodo DOM)

// L'UI viene inserita direttamente in un nodo DOM.
 
var container = document.getElementById('uploadArea');
openUploadUI('mypackage.EmbeddedUpload', {
    containerRef: container
});

9 — ''dimensions''

// Il FloatingPane viene aperto con dimensioni personalizzate.
 
openUploadUI('mypackage.LargeImport', {
    dimensions: { w: 800, h: 500 }
});

// Il FloatingPane viene aperto in modalità modale:
// l'utente non può interagire con il resto della pagina finché non chiude il pannello.
 
openUploadUI('mypackage.CriticalImport', {
    modal: true
});

11 — ''useCookie''

// La posizione e le dimensioni del FloatingPane vengono salvate in localStorage.
// Alla successiva apertura il pannello si riposiziona dove era stato lasciato.
 
openUploadUI('mypackage.RecurringImport', {
    useCookie: true
});

12 — ''useToaster''

// Il messaggio di successo appare nel MessageToaster invece che in un dialog.
// Utile quando si vuole una notifica non bloccante.
 
openUploadUI('mypackage.SilentImport', {
    useToaster: true
});

13 — ''parameters''

// Passa parametri aggiuntivi al Groovy script.
// Nel binding saranno disponibili come:
//   parametersMap["targetTable"], parameters["targetTable"]  → "anagrafica"
//   targetTable  → "anagrafica"   (variabile individuale)
//   overwrite    → true           (variabile individuale)
 
openUploadUI('mypackage.TableImport', {
    parameters: {
        targetTable: 'anagrafica',
        overwrite:   true,
        userId:      42
    }
});

Lato Groovy:

log.info("Importazione in tabella: ${targetTable}, overwrite: ${overwrite}")
// oppure
log.info("Tabella: ${parametersMap.targetTable}")

14 — ''callback''

// Callback personalizzato al successo: riceve il JsonServerResponse completo.
// Il FloatingPane si chiude ugualmente dopo il callback.
 
openUploadUI('mypackage.ImportWithResult', {
    callback: function(resp) {
        var importedCount = resp.responseHashMap.result.importedCount;
        showOkDialog({ message: 'Importati ' + importedCount + ' record.' });
        // aggiorna la datagrid aperta
        refreshDatagrid();
    }
});

15 — ''errorCallback''

// Gestione personalizzata degli errori di rete o di script.
 
openUploadUI('mypackage.CriticalImport', {
    errorCallback: function(err) {
        console.error('Upload fallito:', err.description);
        showErrorDialog('Errore durante il caricamento: ' + err.description);
        // logica di ripristino personalizzata
        rollbackLocalState();
    }
});

16 — Tutti i parametri combinati

openUploadUI('reportistica.ImportazioneExcel', {
 
    // Istruzioni per l'utente
    instructions: 'Carica il file Excel con i dati da importare.<br>' +
                  'Sono ammessi solo file .xlsx e .xls, max 10 MB.',
 
    // Selezione e validazione
    multiple:          false,
    allowedExtensions: ['xlsx', 'xls'],
    maxUploadSizeMB:   10,
    autoupload:        false,
 
    // Posizionamento: FloatingPane personalizzato
    containerRef:      null,
    dimensions:        { w: 750, h: 550 },
    modal:             true,
    useCookie:         false,
 
    // Parametri extra per il Groovy
    parameters: {
        projectCode:  gwProjectName,
        targetEntity: 'Dipendenti',
        dryRun:       false
    },
 
    // Notifica di successo non bloccante
    useToaster: false,
 
    // Callback di successo personalizzato
    callback: function(resp) {
        var result = resp.responseHashMap.result;
        showOkDialog({
            message: 'Importazione completata.<br>' +
                     'Record inseriti: <b>' + result.insertedRows + '</b><br>' +
                     'Errori: <b>' + result.errorRows + '</b>'
        });
        topic.publish('myApp/dataChanged', { entity: 'Dipendenti' });
    },
 
    // Gestione errori personalizzata
    errorCallback: function(err) {
        showErrorDialog('Importazione fallita: ' + err.description);
    }
});

Casi d'uso

CU-01 — Importazione dati da file Excel

L'utente carica un file .xlsx contenente anagrafiche. Il Groovy legge il file riga per riga (con Apache POI, già disponibile tramite i servizi nel binding) e inserisce o aggiorna i record nel database.

openUploadUI('import.AnagraficaImport', {
    instructions:      'File Excel con le colonne: Cognome, Nome, CF, Email.',
    allowedExtensions: ['xlsx', 'xls'],
    maxUploadSizeMB:   2,
    useToaster:        true,
    callback: function(resp) {
        datagridAnagrafica.refresh();
    }
});

CU-02 — Caricamento allegato a una scheda (embedded)

L'UI viene visualizzata all'interno di un pannello del dettaglio scheda già aperto, senza aprire un nuovo FloatingPane. Al successo, la lista allegati viene aggiornata.

openUploadUI('allegati.CaricaAllegato', {
    containerRef:      dijit.registry.byId('attachmentsTab'),
    allowedExtensions: ['pdf', 'jpg', 'png', 'docx'],
    maxUploadSizeMB:   20,
    parameters:        { itemId: currentItemId, className: 'Pratica' },
    callback: function(resp) {
        refreshAttachmentsList();
    }
});

CU-03 — Upload multiplo di immagini con auto-invio

L'utente trascina più immagini contemporaneamente. L'upload parte senza necessità di cliccare alcun pulsante. Il Groovy ridimensiona e archivia le immagini.

openUploadUI('media.ImageUploader', {
    instructions:      'Trascina le immagini o usa il pulsante Sfoglia. Formati ammessi: JPG, PNG, WEBP.',
    multiple:          true,
    autoupload:        true,
    allowedExtensions: ['jpg', 'jpeg', 'png', 'webp'],
    maxUploadSizeMB:   50,
    dimensions:        { w: 700, h: 480 },
    useToaster:        true
});

CU-04 — Importazione configurazione da JSON

Un amministratore carica un file di configurazione. Il Groovy valida il JSON, applica la configurazione e restituisce un report dettagliato. L'UI si apre in modalità modale per impedire operazioni concorrenti.

openUploadUI('admin.ConfigImport', {
    instructions:      "Carica il file di configurazione esportato. Attenzione: l'operazione è irreversibile.",
    allowedExtensions: ['json'],
    maxUploadSizeMB:   1,
    modal:             true,
    parameters:        { environment: 'production', validateOnly: false },
    callback: function(resp) {
        var report = resp.responseHashMap.result;
        showOkDialog({
            message: 'Configurazione applicata.<br>Voci aggiornate: ' + report.updatedKeys
        });
    },
    errorCallback: function(err) {
        showErrorDialog('Configurazione non valida: ' + err.description);
    }
});

CU-05 — Sostituzione di un documento con versionamento

L'utente rimpiazza un documento esistente. Il Groovy archivia la versione precedente e salva quella nuova, restituendo metadati sulla versione creata.

openUploadUI('documenti.SostituisciDocumento', {
    allowedExtensions: ['pdf'],
    maxUploadSizeMB:   30,
    useCookie:         true,
    parameters: {
        documentId:  currentDocumentId,
        keepHistory: true
    },
    callback: function(resp) {
        var meta = resp.responseHashMap.result;
        messageToaster.setContent(
            'Versione ' + meta.versionNumber + ' salvata.', 'message'
        );
        messageToaster.show();
        reloadDocumentDetail(currentDocumentId);
    }
});

CU-06 — Importazione batch da più file CSV

L'ufficio carica più file CSV (uno per categoria) in un'unica operazione. Il Groovy li elabora in sequenza e produce un report consolidato.

openUploadUI('batch.MultiCSVImport', {
    instructions:      'Seleziona tutti i file CSV da importare in una volta sola.',
    multiple:          true,
    allowedExtensions: ['csv'],
    maxUploadSizeMB:   25,
    dimensions:        { w: 700, h: 500 },
    parameters:        { separator: ';', encoding: 'UTF-8' },
    callback: function(resp) {
        var r = resp.responseHashMap.result;
        showOkDialog({
            message: 'Elaborati ' + r.filesProcessed + ' file.<br>' +
                     'Righe importate: ' + r.totalRows + '<br>' +
                     'Errori: ' + r.totalErrors
        });
        refreshReportDashboard();
    }
});

CU-07 — Validazione preventiva (dry run)

Prima di un import definitivo, l'utente può eseguire una validazione “dry run” che non scrive sul database ma restituisce l'elenco degli errori trovati.

function apriValidazione(isDryRun) {
    openUploadUI('import.ValidatedImport', {
        instructions: isDryRun
            ? 'Modalità VERIFICA: nessun dato verrà scritto nel database.'
            : 'Modalità IMPORTAZIONE: i dati verranno scritti nel database.',
        allowedExtensions: ['xlsx'],
        maxUploadSizeMB:   5,
        parameters: {
            dryRun:      isDryRun,
            targetTable: 'Contratti'
        },
        callback: function(resp) {
            var r = resp.responseHashMap.result;
            if (isDryRun) {
                showOkDialog({
                    message: 'Verifica completata.<br>' +
                             'Righe valide: ' + r.validRows + '<br>' +
                             'Righe con errori: ' + r.errorRows
                });
            } else {
                messageToaster.setContent('Importati ' + r.insertedRows + ' record.', 'message');
                messageToaster.show();
            }
        }
    });
}
 
// Uso:
apriValidazione(true);   // solo verifica
apriValidazione(false);  // importazione reale

Note tecniche

Formato della risposta del server

Il controller restituisce sempre un JsonServerResponse in formato JSON:

{
  "success": true,
  "description": "Operazione eseguita con successo",
  "errorDetailList": [],
  "responseHashMap": {
    "result": { ... }
  }
}

Il campo result contiene il valore di ritorno dello script Groovy.

Dimensione massima upload lato server

La dimensione massima lato server è configurata in dispatcher-servlet.xml tramite CommonsMultipartResolver. Il parametro maxUploadSizeMB in openUploadUI è una validazione client-side che si aggiunge (non sostituisce) al limite server.

Compatibilità con ''containerRef''

Quando si usa containerRef, l'UI occupa il 100% dello spazio disponibile nel contenitore (width: 100%; height: 100%). Il contenitore deve avere una dimensione definita (es. height esplicita o essere un ContentPane Dojo con layout calcolato).

Variabili globali richieste

La funzione dipende dalle seguenti variabili globali definite dalla pagina JSP:

Variabile Provenienza Uso
gwContextPath i18nGlobalMessages.jsp Base URL delle richieste
gwProjectName project.jsp Path variable del controller
selectLabel i18nGlobalMessages.jsp Titolo del FloatingPane
uploadLabel i18nGlobalMessages.jsp Label del pulsante “Carica”
gwUploadDropFilesLabel i18nGlobalMessages.jsp Testo della drop zone
gwUploadBrowseLabel i18nGlobalMessages.jsp Label pulsante “Sfoglia”
gwUploadSizeLimitExceededLabel i18nGlobalMessages.jsp Messaggio di errore dimensione
gwUploadInvalidExtensionLabel i18nGlobalMessages.jsp Messaggio di errore estensione
generalErrorMessage i18nGlobalMessages.jsp Messaggio di errore generico

Note

Issue di riferimento: #1824
File sorgente JS: gw-commons-web/…/debug/js/gwCommons.js
Controller: gw-webclient/…/controller/commons/UploadToGroovyController.java
Endpoint: POST /{projectName}/uploadToGroovy