[Java] Exemple Publipostage fait "a la main"

Vos meilleures macros et portions de code sont publiées dans cette section.
Aucun support sur une question de programmation ici !

Modérateur : Vilains modOOs

Règles du forum
Aucune question dans cette section !
Celle-ci rassemble les meilleures macros et portions de code. Vous pouvez en revanche commenter ou argumenter le code exposé. Vous pouvez même remercier l'auteur (cela fait toujours plaisir) en indiquant par exemple dans quel cadre ou contexte vous en avez eu l'utilité.
Si vous avez à poster quelque chose, faites-le depuis la section Macros et API et demandez à un modérateur de l'y déplacer.
yolpo
Fraîchement OOthentifié
Messages : 8
Inscription : 27 juil. 2009 14:44

[Java] Exemple Publipostage fait "a la main"

Message par yolpo »

Voici un exemple de publipostage fait par du code java. Je me permet de poster mon code car j'aurais fortement apprécier d'avoir ce genre d'exemple quand j'ai commencer a l'écrire. mes classes sont relativement Brut : a vous de prendre ce qui vous interresse et d'amélioré l'algorithme qui ne me convainc pas trop tel quel...

L'objectif est de pouvoir inséré dans le document généré d'autre requête et table que dans un publipostage classique par Open Office.

On a donc un modèle de publipostage avec des champs de mailing inséré dedans grâce a Open office.



Tout d'abord un singleton pour créer le context et quelques objet et interface dont nous auront besoin. Noter la methode reload qui permet de palier a un bug d'openoffice : On capte l'exception "Connection reset" et on reload le singleton..

Code : Tout sélectionner

package Office;

import com.sun.star.beans.XPropertySet;
import com.sun.star.bridge.XBridge;
import com.sun.star.bridge.XBridgeFactory;
import com.sun.star.comp.helper.Bootstrap;
import com.sun.star.comp.helper.BootstrapException;
import com.sun.star.connection.XConnection;
import com.sun.star.connection.XConnector;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.lib.unoloader.UnoLoader;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.XCurrentContext;
import java.io.IOException;
import ooo.connector.BootstrapSocketConnector;

/**
 *
 * @author Yolpo
 */
public class SingletonOOo {

    private XCurrentContext xCurCont = null;
    private XComponentContext xContext = null;
    private static SingletonOOo oOo = null;
    private XMultiComponentFactory serviceManager = null;
    private Object desktop = null;
    private XComponentLoader loader = null;
    private static XBridge bridge;
    private Object mxMSF;
    public static final String DEFAULT_CONNECTION_STRING = "socket,host=localhost,port=8100";


    
    private SingletonOOo() throws BootstrapException, Exception{
            try {
                openConnectionOpenOffice();
            } catch (Exception e) {
                throw new java.lang.Exception(e);
            }
    }
    //permet de réaffecter mes variable quand la connection a reset : Probleme connu d'openoffice en java.
    public static synchronized void reload() throws BootstrapException, Exception{
        oOo = new SingletonOOo();
    }
    public static synchronized SingletonOOo GetInstance() throws BootstrapException, Exception{

        if(oOo == null || bridge == null){
            oOo = new SingletonOOo();
        }
        return oOo;
    }
    public XMultiComponentFactory getServiceManager() throws BootstrapException, Exception {

        return serviceManager;
    }

    public XComponentContext getXContext() throws BootstrapException, Exception {

        return xContext;
    }
    public XComponentLoader getLoader() throws BootstrapException, Exception {

        return loader;
    }
    public void openConnectionOpenOffice()
        {
        System.out.println("Ici");
            try
            {
               //un timer en cas de reload : pour que le process ait le temps d'etre kill avant le reload..
                Thread.sleep(2000);
                xContext = BootstrapSocketConnector.bootstrap("C:\\Program Files\\OpenOffice.org 3\\program\\soffice.exe");
                if (xContext == null)
                    System.out.println("mxComponentContext is null");

                // Création de l'objet de type Connector permettant de créer une
                // connection entre java et OOo
                Object x = xContext.getServiceManager().createInstanceWithContext("com.sun.star.connection.Connector", xContext);
                XConnector xConnector = (XConnector) UnoRuntime.queryInterface(XConnector.class, x);

                // Création de la connection entre java et OOo
                XConnection connection = xConnector.connect(DEFAULT_CONNECTION_STRING);
                if (connection == null)System.out.println("Connection est null");

                // Création du bridge, étape très importante pour pouvoir
                // fermer OOo sans avoir à faire un system.exit();
                // Le bridge est créé suivant la connection connection et le
                // protocol de discussion urp
                x = xContext.getServiceManager().createInstanceWithContext("com.sun.star.bridge.BridgeFactory", xContext);

                XBridgeFactory xBridgeFactory = (XBridgeFactory) UnoRuntime.queryInterface(XBridgeFactory.class, x);
                if (xBridgeFactory == null)System.out.println("Bdridge est null");

                bridge = xBridgeFactory.createBridge("", "urp", connection, null);

                // Création de la XMultiComponentFactory qui permettra d'avoir
                // acces aux services tels que le mailmerge
                XComponent xComponent = (XComponent) UnoRuntime.queryInterface(XComponent.class, bridge);
                if (bridge == null)System.out.println("Bridge null");
                x = bridge.getInstance("StarOffice.ServiceManager");
                serviceManager = (XMultiComponentFactory) UnoRuntime.queryInterface(XMultiComponentFactory.class, x);

                XPropertySet xProperySet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, serviceManager);

                Object oDefaultContext = xProperySet.getPropertyValue("DefaultContext");

                xContext = (XComponentContext) UnoRuntime.queryInterface(XComponentContext.class, oDefaultContext);

                serviceManager = xContext.getServiceManager();

                desktop = serviceManager.createInstanceWithContext(
                 "com.sun.star.frame.Desktop", xContext  );

                 loader = ( XComponentLoader )UnoRuntime.queryInterface( XComponentLoader.class, desktop );

                if (mxMSF == null)
                {
                    mxMSF = (XMultiServiceFactory) UnoRuntime.queryInterface(XMultiServiceFactory.class, serviceManager);
                }

            }
            catch (Exception exception)
            {
                System.err.println(exception);
            }
}
    public void closeConnectionOpenOffice()
        {
            XComponent xcomponent = (XComponent) UnoRuntime.queryInterface(XComponent.class, bridge);
            xcomponent.dispose();
        }
    
}


Après on crée une classe mère qui comprendras des méthodes qui pourront servir a chaque scénario (voir plus bas) de publipostage.

Code : Tout sélectionner

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package p0;


import Office.SingletonOOo;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import com.sun.star.beans.PropertyValue;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
/**
 *
 * @author Yolpo
 */
public class PublipostJava {

    private XComponentContext context = null;
    private XComponent document = null;
    private XMultiComponentFactory serviceManager = null;
    XComponentLoader loader = null;
    
    public PublipostJava() { }

    /**
     * Créer un document
     * <p>
     * @return
     *     Le document construit
     * @param templateFile
     *     Le template du document
     * @param isUserEditable
     *     True = permet au user d'éditer le doc
     *     False = interdit au user d'éditer le doc
     */
    public XComponent createDoc(String templateFile,boolean isUserEditable) throws java.lang.Exception {

        // Get Context et service manager de SingletonOOo
        if (context == null) {
                context = SingletonOOo.GetInstance().getXContext();
                serviceManager = SingletonOOo.GetInstance().getServiceManager();
                loader = SingletonOOo.GetInstance().getLoader();
        }
        

        // get XComponentLoader. pour load le doc.

         

        // Propriété générale du document (voir com.sun.star.document.MediaDescriptor).

        ArrayList<PropertyValue> props = new ArrayList<PropertyValue>();
        PropertyValue p = null;
        if (templateFile != null) {
            // Autorise l'utilisation d'un Template.
            p = new PropertyValue();
            p.Name = "AsTemplate";
            p.Value = new Boolean (true);
            props.add(p);
        }
            // Rend le document invisible.
        p = new PropertyValue();
        p.Name = "Hidden";
        p.Value = new Boolean(true);
        props.add(p);

        PropertyValue[] properties = new PropertyValue[props.size()];
        props.toArray(properties);

        // Création du document
        // (voir com.sun.star.frame.XComponentLoader pour détails).

        if (templateFile != null) {

            // Créer une copie du template. pour travailler dessus.
            if (loader == null){

                context = SingletonOOo.GetInstance().getXContext();
                serviceManager = SingletonOOo.GetInstance().getServiceManager();
                loader = SingletonOOo.GetInstance().getLoader();

                }
        }
        String templateFileURL = filePathToURL(templateFile);
        document = loader.loadComponentFromURL(
        templateFileURL,    // URL du temlpate
        "_blank",           // Nom de la fenetre (_blank en cré une nouvelle).
        0,                  // On ne cherche pas de flag.
        properties);        // Propriétées.

        return document;

    }
    /**
     * Sauver un doc donné a l'url donnée au format pdf.
     * <p>
     * @param document
     *      Le document a sauvegarder (XComponent)
     * @param saveFile
     *      Url complete du fichier (String)
     * @param format
     *      Le format final (MS word, pdf , odt etc) (Enum OOo voir Filtername dans API)
     * @param overwrite
     *      Doit-on écraser le fichier si il existe deja.(boolean)
     */
    protected synchronized void storeDocComponent(XComponent xDoc, String storeUrl) throws java.lang.Exception {
        XStorable xStorable = (XStorable)UnoRuntime.queryInterface(XStorable.class, xDoc);
        storeUrl = filePathToURL(storeUrl);
        PropertyValue[] storeProps = new PropertyValue[2];
        storeProps[0] = new PropertyValue();
        storeProps[0].Name = "FilterName";
        storeProps[0].Value = "writer_pdf_Export";
        storeProps[1] = new PropertyValue();
        storeProps[1].Name = "Overwrite";
        storeProps[1].Value = new Boolean(true);
        xStorable.storeToURL(storeUrl, storeProps);
        //xDoc.dispose();
        XComponent xComp = (XComponent) UnoRuntime.queryInterface(XComponent.class, xStorable);
        xComp.dispose();
    }

    /** Converti si besoin l'url. */
    private String filePathToURL(String file) {
        File f = new File(file);
        StringBuffer sb = new StringBuffer("file:///");
        try {
            sb.append(f.getCanonicalPath().replace('\\', '/'));
        } catch (IOException e) {
        }
        return sb.toString();
    }

    /**
     * @param args
     */

}

Et enfin le scénario de publipostage fille de la classe ci dessus ou vous pouvez mettre ce que vous voulez. Ici il y a une method pour remplir les champs de mailing et une pour remplir un tableau.

Code : Tout sélectionner

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package p0.scenario;

import com.sun.star.beans.PropertyVetoException;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.beans.XPropertySet;
import com.sun.star.container.NoSuchElementException;
import com.sun.star.container.XEnumeration;
import com.sun.star.container.XEnumerationAccess;
import com.sun.star.container.XIndexAccess;
import com.sun.star.container.XNameAccess;
import com.sun.star.lang.IllegalArgumentException;
import com.sun.star.lang.IndexOutOfBoundsException;
import com.sun.star.lang.WrappedTargetException;
import com.sun.star.lang.XComponent;
import com.sun.star.table.XTableRows;
import com.sun.star.text.XText;
import com.sun.star.text.XTextField;
import com.sun.star.text.XTextFieldsSupplier;
import com.sun.star.text.XTextTable;
import com.sun.star.text.XTextTablesSupplier;
import com.sun.star.uno.UnoRuntime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import p0.PublipostJava;

/**
 *
 * @author Jalin
 */
public class ScenarioBleu extends PublipostJava{

    Map mesvaleurs = new HashMap();
    String[][] maTable;
    XComponent document = null;
    String prefix;
    String[] mesIndex = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"};

    public ScenarioBleu(String templateDoc,Boolean bool, String prefix, Map mesVal, String[][] matab) throws Exception{
        super();
        this.mesvaleurs = mesVal;
        maTable = matab;
        this.prefix = prefix;
        document = createDoc(templateDoc,bool);
        populChamp();
        popultable();
            //Enregistrement du doc avec url complete.(voir méthode storeDocComponent)
            storeDocComponent(document, "C:/partage/"+prefix+".pdf");
    }

    /**
     * Remplir les champs de mailing
     * <p>
     * @void
     *     Method qui modifie la variable de classe document donc pas de return
     * @param XComponent document
     *     le document
     * @param mesvaleurs
     *     Clé : champ a cherché dans le doc
     *     valeur : String pour affecter sa valeur au champ.
     */
    private void populChamp() throws UnknownPropertyException,PropertyVetoException, NoSuchElementException, WrappedTargetException, IllegalArgumentException{

        //Acces au Champs de mailing
        XTextFieldsSupplier fieldSupplier = (XTextFieldsSupplier)UnoRuntime.queryInterface(XTextFieldsSupplier.class, document);
        XEnumerationAccess xEnumField = fieldSupplier.getTextFields();
        //Création d'un itérateur pour boucler dessus
        Iterator iter = mesvaleurs.entrySet().iterator();
        //Remplacement des champs par les données qui conviennent.
            while (iter.hasNext())
                {
                    Map.Entry ent = (Entry) iter.next();
                    String cle = (String) ent.getKey();
                    String valeur = (String) ent.getValue();
                    //Enum des textfield du document pour boucler dessus.
                    XEnumeration xEnum = xEnumField.createEnumeration();
                    while (xEnum.hasMoreElements()){
                        //Récupération du textfield
                        XTextField text = (XTextField) UnoRuntime.queryInterface(XTextField.class, xEnum.nextElement());
                        XPropertySet xPropertySet = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, text);
                        // Test et affectation du contenu si match.
                        if (xPropertySet.getPropertyValue("Content").equals(cle))
                        xPropertySet.setPropertyValue("Content", valeur);
                        }
                }
    }

    /**
     * Remplir le tableau.
     * <p>
     * @void
     *     Method qui modifie la variable de classe document donc pas de return
     * @param XComponent document
     *     le document
     * @param maTable
     *     Tableau a 2 dimensions qui contient les données a inséré dans le tableau
     */
    private void popultable() throws IndexOutOfBoundsException, WrappedTargetException {

        XText xCellText = null;
        String contenu = "";

        //Acces au table existante du document
        XTextTablesSupplier xTablesSupplier = (XTextTablesSupplier) UnoRuntime.queryInterface(XTextTablesSupplier.class, document );
        XNameAccess xNamedTables = xTablesSupplier.getTextTables();

        //Index des Tables existantes
        XIndexAccess xIndexedTables = (XIndexAccess) UnoRuntime.queryInterface(XIndexAccess.class, xNamedTables);

        //Pour chaque table ( Dans mon cas a priori une seule)
        for (int i = 0; i < xIndexedTables.getCount(); i++) {
            //Récupération de l'interface Table
            Object table = xIndexedTables.getByIndex(i);
            XTextTable xTextTable = (XTextTable) UnoRuntime.queryInterface(XTextTable.class, table);
            //Récupération de sa collection de lignes
            XTableRows rows = xTextTable.getRows();
            //On enleve toutes les linges sauf celles des en-têtes
            rows.removeByIndex(1,(rows.getCount()-2));
            //On insere autant de ligne dont on a besoin.
            rows.insertByIndex(rows.getCount(), maTable[0].length-1);
            //Remplissage de gauche vers droite et de haut vers le bas en commencant par la 2eme ligne(La premiere contenant les titres).
            for (int j = 0; j<maTable[0].length; j++){
                for (int k = 0;k<maTable.length;k++){
                    contenu = maTable[k][j];
                    //Récupération d'une cellule.
                    xCellText = (XText) UnoRuntime.queryInterface (XText.class, xTextTable.getCellByName (mesIndex[k]+(j+2)) );
                    //Remplissage de la cellule
                    xCellText.setString(contenu);
                }
            }
        }

    }
}

Voila. J'èspere que ca aideras la communauté qui ma bien aidé pour faire ces quelques classes. Hésitez pas si vous voyez des choses a améliorer... et surtout n'oubliez pas de captez l"exception "Connection reset quand vous generez un doc. Ca reset aléatiorement entre de 200 a 2000 doc généré en moyenne.

ca donne un truc du genre :

Code : Tout sélectionner

try {
            new ScenarioBleu(templateDoc, false,name,map,monTab);
            }
            catch (Exception e){
                System.out.println("Connection reset... : ");
                KillSOffice.killOpenOffice();
                SingletonOOo.reload();
                System.out.println("Singleton Reload");
                new ScenarioBleu(templateDoc, false,name,map,monTab);
            }
            finally{
                System.out.println("Tout va bien, pfiouuuu");
            }
Dernière modification par Flip le 11 août 2009 09:57, modifié 1 fois.
Raison : Modif balisage titre
OpenOffice 2.4 sous Windows XP