Apache Commons Digester

巴扎黑
巴扎黑オリジナル
2017-06-26 09:17:071532ブラウズ

前書き

前回の記事で Digester の基本的な使い方を説明しました。次に、この記事では主に次の内容を学習していきます。 binding を使用して、RulesModule インターフェース実装クラスを定義してルールの事前バインドを完了し、実行時にそれを再利用します

  1. xml を非同期的に解析します

  2. ${sys.user} などの XML 内の変数を解析します

  3. パラメーターのコンストラクター メソッドでオブジェクトが作成され、パラメーターは XML ノード データから取得されます

  4. Rules モジュールは事前にバインドされています - RulesModule インターフェイス

  5. これまでは、Digester を使用する基本的なプロセスは、ルールをバインドするたびにルールをバインドすることでした。プログラムが実行されているので、それらを解析します ;

実際、Digester の解析プロセスを変更し、開始時にルールセットを事前定義し、実行時に事前定義されたルールを再利用することができます;

これは少し曖昧かもしれませんが、次の Web アプリケーション シナリオを参照すると、より深く理解できるはずです。

サーブレット シナリオの例

Web 開発に精通している人はサーブレットについて知っているはずなので、ここでは詳しく説明しません。以下に示すように、

EmployeeServlet

:

なぜなら、サーブレットはシングルトンであり、Digester はスレッドセーフではないため、スレッドの安全性を確保するためにリクエストが行われるたびに新しい Digester オブジェクトを作成します。

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" ) ) );
        ...
}

それは簡単に見つかります。 上記のプログラムの欠点: コードは再利用されず、バインディング ルールはリクエストごとに繰り返す必要があります ただし、問題を解決するには

RuleSet
を使用できます。コードを再利用しない場合は、以下に示すように、
EmployeeRuleSet

ルール セット実装を定義します。
RuleSetInterface:

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" );
    }

}
それからサーブレットで次のように使用します。

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" ) ) );
        ...
    }

}
実際、個人的には、プライベート メソッドを直接記述してルールを追加する方が良いと考えています (笑)。ただし、次のような欠点があります。

ダイジェスター

オブジェクトはクライアントと高度に結合されており、クライアントによって直接作成されます

  1. 各解析呼び出しの前に、ルールを繰り返しバインドする必要があります

  2. バインドされているため、セマンティクスが非常に貧弱で、可読性も良くありません。

  3. それでは、ベスト プラクティスとは何でしょうか。その答えは、開始時にルールを事前にバインドし、事前にバインドしたルールを再利用することです。以下に示すように、実行時に -bound ルールを定義します:

    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();
        }
    
    }
  4. それからサーブレットで次のように使用します:

    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") ) );
            ...
        }
    
    }

    利点は明白です:

RulesModule

ルール バインディングの API は非常にセマンティックで、使いやすく、可読性が高くなります。

ルール バインディングの設定は完了するために起動フェーズに移行します。

  1. ダイジェスター オブジェクトはクライアントによって作成されません。

    DigesterLoader

    によって作成されました
  2. FromXmlRulesModule
  3. Except クラスはRulesModuleを実装しますインターフェースに加えて、ダイジェスター自体がを提供します

    XmlRulesModule クラス

から、これはすでに RulesModule

インターフェースを実装していますので、次のように使用できます

:

            DigesterLoader loader = DigesterLoader.newLoader(  .getResource( "myrule.xml"
完全な例 解析される次のような XML があるとします。 tまず、RulesModule インターフェイス実装クラスを定義します:
<employee>
    <firstName>Pi</firstName>
    <lastName>Chen</lastName>
    <address>
        <type>CITY</type>
        <city>HangZhou</city>
        <state>2</state>
    </address>
</employee>
クライアント クラスを作成します:
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();
    }

}
結果の印刷:

Pi Chen, CITY , HangZhou, 2
XML の非同期解析

非同期解析の場合、 asyncParse メソッドを直接呼び出すこともできますが、

digester
オブジェクトはスレッドセーフではないため、特別な注意が必要です。 以下は簡単な API 使用例です:

前の例に従って、同じ xml と RulesModule を使用します。実装クラス;
クライアントクラス:

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();
        }
    }
}
xml 変数解析 - Substitutor 抽象クラス

これは比較的単純で、VariableSubstitutor 実装クラス、ユーザー変換属性、および本体を定義します。以下に示す xml (${type} は変数):
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();
        }
    }
}

那么可以这样解析如上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

参考资料


代码参考


以上がApache Commons Digesterの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。