Maison  >  Article  >  Java  >  Digesteur Apache Commons

Digesteur Apache Commons

巴扎黑
巴扎黑original
2017-06-26 09:17:071518parcourir

Avant-propos

L'article précédent a donné une introduction de base à Digester, et nous avons déjà compris l'utilisation de base de Digester. Ensuite, nous continuerons à apprendre ses fonctionnalités associées. Cet article couvre principalement le contenu suivant :

  1. Liaison du module de règles, complétez la pré-liaison des règles en définissant une classe d'implémentation d'interface RulesModule et réutilisez-la au moment de l'exécution

  2. Analyse asynchrone xml

  3. Analyser les variables en XML, telles que ${sys.user}

  4. Utiliser le constructeur avec des paramètres pour créer des objets, et les paramètres proviennent des données du nœud XML

Les modules de règles sont pré-liés - Interface RulesModule

Avant cela, notre processus de base d'utilisation de Digester consistait à lier les règles à chaque fois que le programme est en cours d'exécution puis les analyse ;

En fait, nous pouvons modifier le processus d'analyse de Digester, prédéfinir l'ensemble de règles au démarrage, puis réutiliser les règles prédéfinies au moment de l'exécution

Peut-être ; c'est un peu vague, vous pouvez jeter un œil au scénario d'application Web suivant et vous devriez avoir une compréhension plus approfondie

Exemple de scénario de servlet

Ceux qui sont familiers avec le développement Web devraient déjà le faire ; Je connais le servlet, donc je n'entrerai pas dans les détails ici. Maintenant, supposons qu'il y ait un EmployeeServlet, comme indiqué ci-dessous :

Puisque le servlet est un singleton et que le Digester n'est pas un thread-. sûr, nous en émettrons un nouveau à chaque fois qu'il sera demandé. Un objet Dgester pour assurer la sécurité des threads, écrit comme suit :

public class EmployeeServlet  extends HttpServlet
{public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException
    {
        Digester digester = new Digester();
        digester.setNamespaceAware( true );
        digester.setXIncludeAware( true );
        digester.addObjectCreate( "employee", Employee.class );
        digester.addCallMethod( "employee/firstName", "setFirstName", 0 );
        digester.addCallMethod( "employee/lastName", "setLastName", 0 );

        digester.addObjectCreate( "employee/address", Address.class );
        digester.addCallMethod( "employee/address/type", "setType", 0 );
        digester.addCallMethod( "employee/address/city", "setCity", 0 );
        digester.addCallMethod( "employee/address/state", "setState", 0 );
        digester.addSetNext( "employee/address", "addAddress" );

        Employee employee = digester.parse( openStream( req.getParameter( "employeeId" ) ) );
        ...
}

On peut facilement trouver le inconvénients du programme ci-dessus : le code n'est pas réutilisé à chaque fois. Chaque requête doit être liée à la règle à plusieurs reprises
Cependant, nous pouvons utiliser RuleSet pour résoudre le problème de l'absence de réutilisation de code ; illustré ci-dessous, définissez une EmployeeRuleSet implémentation d'un ensemble de règlesRuleSetInterface :

public class EmployeeRuleSet  implements RuleSet
{public void addRuleInstances( Digester digester )
    {
        digester.addObjectCreate( "employee", Employee.class );
        digester.addCallMethod( "employee/firstName", "setFirstName", 0 );
        digester.addCallMethod( "employee/lastName", "setLastName", 0 );

        digester.addObjectCreate( "employee/address", Address.class );
        digester.addCallMethod( "employee/address/type", "setType", 0 );
        digester.addCallMethod( "employee/address/city", "setCity", 0 );
        digester.addCallMethod( "employee/address/state", "setState", 0 );
        digester.addSetNext( "employee/address", "addAddress" );
    }

}

Ensuite, utilisez-la comme ceci dans le servlet :

public class EmployeeServlet  extends HttpServlet
{private final RuleSet employeeRuleSet = new EmployeeRuleSet();public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException
    {
        Digester digester = new Digester();
        digester.setNamespaceAware( true );
        digester.setXIncludeAware( true );

        employeeRuleSet.addRuleInstances( digester );

        Employee employee = digester.parse( openStream( req.getParameter( "employeeId" ) ) );
        ...
    }

}

Évidemment, il n'y a aucun moyen de faire cela. Mauvais (en fait, je pense personnellement qu'il vaut mieux écrire une méthode privée et ajouter des règles directement, haha), mais elle a ce qui suit inconvénients :

  1. RuleSet n'est pas réellement une configuration, c'est juste pour Le digesteur est simplement lié aux règles

  2. digesteurL'objet est fortement couplé au client et est créé directement par le client ;

  3. Avant chaque appel d'analyse , les règles contraignantes doivent être répétées

  4. Lors de la liaison des règles, mauvaise sémantique et mauvaise lisibilité

Alors, quelle est la meilleure pratique ? La réponse est d'utiliser l'interface RulesModule pour nous aider à pré-lier les règles au démarrage, puis lors de l'exécution, il suffit de réutiliser les règles pré-liées, comme indiqué ci-dessous :

Définir une classe d'implémentation d'interface RulesModule :

class EmployeeModuleextends AbstractRulesModule
{

    @Overrideprotected void configure()
    {
        forPattern( "employee" ).createObject().ofType( Employee.class );
        forPattern( "employee/firstName" ).setBeanProperty();
        forPattern( "employee/lastName" ).setBeanProperty();

        forPattern( "employee/address" ).createObject().ofType( Address.class ).then().setNext( "addAddress");
        forPattern( "employee/address/type" ).setBeanProperty();
        forPattern( "employee/address/city" ).setBeanProperty();
        forPattern( "employee/address/state" ).setBeanProperty();
    }

}
Puis dans La servlet s'utilise comme ceci :

public class EmployeeServletextends HttpServlet
{private final DigesterLoader loader = newLoader( new EmployeeModule() )
        .setNamespaceAware( true )
        .setXIncludeAware( true );public void doGet(HttpServletRequest req, HttpServletResponse res)throws ServletException, IOException
    {
        Digester digester = loader.newDigester()

        Employee employee = digester.parse( openStream( req.getParameter("employeeId") ) );
        ...
    }

}
Les avantages sont évident :

  1. RulesModuleL'API pour la liaison de règles est très sémantique, facile à utiliser et très lisible ; La configuration de la liaison des règles est déplacée vers la phase de démarrage

  2. L'objet digesteur n'est pas créé par le client, mais est
  3. créé par

    DigesterLoader; FromXmlRulesModule

En plus de

écrire votre propre classe pour implémente l'interface RulesModule,

digester lui-même fournit une

classe FromXmlRulesModule a déjà implémenté le RulesModule Nous pouvons utiliser comme ceci : Exemple complet

Supposons qu'il y ait un fichier XML comme suit, à analyser
            DigesterLoader loader = DigesterLoader.newLoader(  .getResource( "myrule.xml"

Démarrez l'encodage, commencez par définir la classe d'implémentation d'interface A RulesModule :

<employee>
    <firstName>Pi</firstName>
    <lastName>Chen</lastName>
    <address>
        <type>CITY</type>
        <city>HangZhou</city>
        <state>2</state>
    </address>
</employee>

Écrire la classe client :

package apache.commons.digester3.example.rulesbinder.module;import org.apache.commons.digester3.binder.AbstractRulesModule;import apache.commons.digester3.example.rulesbinder.pojo.Address;import apache.commons.digester3.example.rulesbinder.pojo.Employee;/**
 * 
 * 
 * @author    
 * @version   2017年6月5日 */public class EmployeeModule extends AbstractRulesModule {

    @Overrideprotected void configure() {
        forPattern("employee").createObject().ofType(Employee.class);
        forPattern("employee/firstName").setBeanProperty();
        forPattern("employee/lastName").setBeanProperty();

        forPattern("employee/address").createObject().ofType(Address.class).then().setNext("addAddress");
        forPattern("employee/address/type").setBeanProperty();
        forPattern("employee/address/city").setBeanProperty();
        forPattern("employee/address/state").setBeanProperty();
    }

}

Impression des résultats :

Pi Chen, CITY, HangZhou, 2
package apache.commons.digester3.example.rulesbinder;import java.io.IOException;import org.apache.commons.digester3.Digester;import org.apache.commons.digester3.binder.DigesterLoader;import org.xml.sax.SAXException;import apache.commons.digester3.example.rulesbinder.module.EmployeeModule;import apache.commons.digester3.example.rulesbinder.pojo.Address;import apache.commons.digester3.example.rulesbinder.pojo.Employee;import apache.commons.digester3.example.simpletest.ExampleMain;/**
 * 
 * 
 * @author    
 * @version   2017年6月5日 */public class DigesterLoaderMain {private static DigesterLoader dl = DigesterLoader.newLoader(new EmployeeModule())
            .setNamespaceAware(false);public static void main(String[] args) {try {
            
            Digester digester = dl.newDigester();
            Employee employee = digester.parse(ExampleMain.class.getClassLoader().getResourceAsStream("employee.xml"));

            System.out.print(employee.getFirstName() + " ");
            System.out.print(employee.getLastName() + ", ");for (Address a : employee.getAddressList()) {
                System.out.print(a.getType() + ", ");
                System.out.print(a.getCity() + ", ");
                System.out.println(a.getState());
            }

        } catch (IOException e) {

            e.printStackTrace();
        } catch (SAXException e) {

            e.printStackTrace();
        }
    }
}
Asynchrone analyse XML

Si vous souhaitez analyser de manière asynchrone, appelez simplement la méthode asyncParse directement, mais vous devez faire particulièrement attention car
digesteur

Les objets ne sont pas thread-safe . Ce qui suit est un exemple simple d'utilisation de l'API :

Suivez l'exemple précédent et utilisez le même XML et le même RulesModule pour implémenter la classe Classe client :

.

Classe abstraite d'analyse de variables XML-Substitutor

C'est relativement simple. Définissez une classe d'implémentation VariableSubstitutor et l'utilisateur convertit les attributs et les valeurs de variable définis dans le corps ;
package apache.commons.digester3.example.rulesbinder;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.Future;import org.apache.commons.digester3.Digester;import org.apache.commons.digester3.binder.DigesterLoader;import apache.commons.digester3.example.rulesbinder.module.EmployeeModule;import apache.commons.digester3.example.rulesbinder.pojo.Address;import apache.commons.digester3.example.rulesbinder.pojo.Employee;import apache.commons.digester3.example.simpletest.ExampleMain;/**
 * 
 * @author    
 * @version   2017年6月5日 */public class AsyncParseMain {private static DigesterLoader dl = DigesterLoader.newLoader(new EmployeeModule())
            .setNamespaceAware(false).setExecutorService(Executors.newSingleThreadExecutor());public static void main(String[] args) {try {
            
            Digester digester = dl.newDigester();
            Future<Employee> future = digester.asyncParse(ExampleMain.class.getClassLoader().getResourceAsStream("employee.xml"));

            Employee employee = future.get();
            
            System.out.print(employee.getFirstName() + " ");
            System.out.print(employee.getLastName() + ", ");for (Address a : employee.getAddressList()) {
                System.out.print(a.getType() + ", ");
                System.out.print(a.getCity() + ", ");
                System.out.println(a.getState());
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
Supposons qu'il existe un fichier XML comme indiqué ci-dessous (où ${type} est une variable) :

那么可以这样解析如上xml:

package apache.commons.digester3.example.rulesbinder;import java.io.IOException;import java.util.HashMap;import java.util.Map;import org.apache.commons.digester3.Digester;import org.apache.commons.digester3.Substitutor;import org.apache.commons.digester3.binder.DigesterLoader;import org.apache.commons.digester3.substitution.MultiVariableExpander;import org.apache.commons.digester3.substitution.VariableSubstitutor;import org.xml.sax.SAXException;import apache.commons.digester3.example.rulesbinder.module.EmployeeModule;import apache.commons.digester3.example.rulesbinder.pojo.Address;import apache.commons.digester3.example.rulesbinder.pojo.Employee;import apache.commons.digester3.example.simpletest.ExampleMain;/**
 * 
 * 
 * @author 
 * @version 2017年6月5日 */public class SubstitutionMain
{private static DigesterLoader dl = DigesterLoader.newLoader(new EmployeeModule())
        .setNamespaceAware(false);public static void main(String[] args)
    {try{// set up the variables the input xml can referenceMap<String, Object> vars = new HashMap<String, Object>();
            vars.put("user.name", "me");
            vars.put("type", "boss");// map ${varname} to the entries in the var mapMultiVariableExpander expander = new MultiVariableExpander();
            expander.addSource("$", vars);// allow expansion in both xml attributes and element textSubstitutor substitutor = new VariableSubstitutor(expander);

            Digester digester = dl.newDigester();
            digester.setSubstitutor(substitutor);

            Employee employee = digester
                .parse(ExampleMain.class.getClassLoader().getResourceAsStream("employee$.xml"));

            System.out.print(employee.getFirstName() + " ");
            System.out.print(employee.getLastName() + ", ");for (Address a : employee.getAddressList())
            {
                System.out.print(a.getType() + ", ");
                System.out.print(a.getCity() + ", ");
                System.out.println(a.getState());
            }

        }catch (IOException e)
        {

            e.printStackTrace();
        }catch (SAXException e)
        {

            e.printStackTrace();
        }
    }
}

带参构造方法使用示例

简单地说,就是在使用ObjectCreateRule规则的时候,能够传递xml中的值(属性值、body值)给构造方法使用;

如下是一个待解析的xml:

<root>
  <bean super="false"><rate>9.99</rate>
  </bean></root>

那么可以这样解析:

package apache.commons.digester3.example.rulesbinder;import java.io.IOException;import org.apache.commons.digester3.Digester;import org.apache.commons.digester3.ObjectCreateRule;import org.apache.commons.digester3.binder.DigesterLoader;import org.xml.sax.SAXException;import apache.commons.digester3.example.rulesbinder.module.EmployeeModule;import apache.commons.digester3.example.rulesbinder.pojo.Address;import apache.commons.digester3.example.rulesbinder.pojo.Employee;import apache.commons.digester3.example.rulesbinder.pojo.MyBean;import apache.commons.digester3.example.simpletest.ExampleMain;/**
 * 
 * 
 * @author 
 * @version 2017年6月5日 */public class ConstructorParamsMain
{public static void main(String[] args)
    {try{

            ObjectCreateRule createRule = new ObjectCreateRule(MyBean.class);
            createRule.setConstructorArgumentTypes(Double.class, Boolean.class);

            Digester digester = new Digester();
            digester.addRule("root/bean", createRule);
            digester.addCallParam("root/bean", 1, "super");
            digester.addCallParam("root/bean/rate", 0);

            MyBean myBean = digester.parse(ConstructorParamsMain.class.getClassLoader()
                .getResourceAsStream("constructor-params.xml"));

            System.out.println(myBean.getRate());
            System.out.println(myBean.isSuper_());

        }catch (IOException e)
        {

            e.printStackTrace();
        }catch (SAXException e)
        {

            e.printStackTrace();
        }
    }
}

结果打印:

9.99
false

参考资料


代码参考


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn