Grails ZKUI – Téléverser un fichier

Si vous utilisez Grails et ZKUI, puis que vous tentez de téléverser un fichier en utilisant un bouton ou autre, vous risquez de ne pas réussir à suivre l’exemple de base sur le site principal de ZK. Voici la solution complète.

Avant de tomber sur cet article, vous avez surement déjà trouvé une discussion sur le site officiel. Ma solution inclue ce qui est là avec le petit ajout que j’ai dû trouver à la dure et que j’ai ajouté à la discussion. Cet article se veut donc être un résumé de la petite recette.

Sitemesh

Premièrement, ZK possède un contrôleur spécial qui ne doit pas interférer avec Sitemesh (l’outil pour gérer les modèles de vues). Le url appelé pour téléverser des fichiers est le zkau/upload . Pour le désactiver, éditez le fichier WEB-INF/sitemesh.xml et ajoutez ces deux lignes dans l’élément principal:

<property name="decorators-file" value="/WEB-INF/decorators.xml" />
<excludes file="${decorators-file}" />

Ensuite, éditez le fichier WEB-INF/decorators.xml et mettez tout ce qui suit:

<decorators defaultdir="/decorators">
  <excludes>
    <pattern>/zkau/*</pattern>
  </excludes>
</decorators>

Commons Multipart

Pour gérer les téléversements, Grails utilise la librairie de Apache qui est le Commons Multipart. Le problème ici est que ZK utilise la même librairie. Lors d’un envoi, le premier va consommer le fichier et le second ne recevra rien. C’est ce qui fait que l’événement UploadEvent a un média vide si le multipart de Grails n’est pas désactivé. Pour le désactiver, éditez le fichier conf/Config.groovy et ajoutez les trois lignes suivantes:

// Disable the multipart resolver for enabling ZK fileupload
grails.disableCommonsMultipart = true
grails.web.disable.multipart = true

Par contre, vous ne pourrez pas faire cela si vous utilisez le multipart ailleurs comme dans un téléversement normal ou si vous utiliser g:actionSubmit.

Exemple de code utilisant le MVVM

Si vous utilisez les .zul ou des composeurs, vous pouvez utiliser l’exemple sur le site officiel. Pour les autres, le fichier GSP de votre vue a besoin de:

<z:window id="main" viewModel="@id('vm') @init('temporary.zkFileUploadVM')" apply="org.zkoss.bind.BindComposer">
  <z:button label="Button" upload="true,maxsize=-1,native" onUpload="@command('upload')"/>
</z:window>

Et votre VM doit avoir la commande suivante:

@Command("upload")
public void upload(@ContextParam(ContextType.BIND_CONTEXT) BindContext ctx) {
  UploadEvent event = (UploadEvent)ctx.getTriggerEvent();
  println("upload ${event} - ${event.media}");
}