前言

上一篇对Digester做了基本介绍,也已经了解了Digester的基本使用方法,接下来将继续学习其相关特性,本篇主要涉及以下几个内容:规则模块绑定,通过定义一个RulesModule接口实现类来完成规则的预先绑定,运行时重复使用

异步解析xml

解析xml中的变量,如${sys.user}

使用带参数的构造方法创建对象,参数来自xml节点数据

规则模块预先绑定 - RulesModule接口

在此之前,我们使用Digester的基本流程都是每次在程序运行时绑定规则,然后解析;

事实上,我们可以改变Digester的解析流程,启动的时候预先定义规则集,然后在运行的时候重复使用预先定义的规则;

可能这样说比较空泛,可以看一下如下一个Web应用场景,应该就会有一个比较深刻的理解了;

servlet场景例子

熟悉Web开发的应该都知道servlet了,这里就不细说了,假设有一个EmployeeServlet,如下所示:

由于servlet是单例的,而且Digester不是线程安全的,所以我们会在每次请求的的时候,new出一个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规则集实现RuleSet接口:

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

}

}

然后在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" ) ) );

...

}

}

很显然这样做是没有错误的(其实,个人觉得还不如直接写一个私有方法,添加规则,哈哈),但是有如下缺点:RuleSet实际上并不是配置,只是给digester绑定下规则而已;

digester对象与客户端耦合度比较高,直接由客户端创建;

每次解析调用前,都需要重复绑定规则

规则绑定的时候,语义性很差,可读性不好;

那么,最佳实践是什么呢,答案是使用RulesModule接口,帮助我们启动时预先绑定规则,然后运行的时候,重复使用预先绑定的规则即可,如下所示:

定义一个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();

}

}

然后在servlet这样使用:

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语义化很强,使用简便,可读性高;

规则绑定的配置移到了启动阶段来完成;

digester对象不是由客户端来创建,而是通过DigesterLoader创建;

FromXmlRulesModule

除了自己编写类实现RulesModule接口外,digester自身提供了一个FromXmlRulesModule类,就已经实现了RulesModule接口,我们可以这样使用:

DigesterLoader loader = DigesterLoader.newLoader( .getResource( "myrule.xml"

完整例子

假设有一个xml如下,待解析

Pi

Chen

CITY

HangZhou

2

开始编码,首先,定义一个RulesModule接口实现类:

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();

}

}

编写客户端类:

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();

}

}

}

结果打印:Pi Chen, CITY, HangZhou, 2

异步解析XML

异步解析的话,直接调用asyncParse方法即可,不过需要特别注意,因为digester对象并不是线程安全的,如下是一个简单的API使用示例:

承接上一个例子,使用同样的xml和RulesModule实现类;

客户端类:

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 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变量解析-Substitutor抽象类

这个比较简单,定义一个VariableSubstitutor实现类,用户转换属性和body中定义的变量值;

假设有一个xml如下所示,(其中${type}为变量):

Pi

Chen

${type}

HangZhou

2

那么可以这样解析如上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 vars = new HashMap();

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:

9.99

那么可以这样解析:

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

参考资料

代码参考

java digester_Apache Commons Digester相关推荐

  1. JBOSS java.lang.NoClassDefFoundError: org/apache/commons/digester/RuleSet

    经常在启动JBOSS的时候,发现在myeclipse的console中报错java.lang.NoClassDefFoundError: org/apache/commons/digester/Rul ...

  2. java commons-chain_Apache commons chain 初探

    Apache commons chain 是什么 Apache common chain 是对责任链设计模式的改造封装,让使用者更加方便的使用. 简单回顾一下责任链设计模式 在阎宏博士的<JAV ...

  3. java中commons意思_java的Commons包简介

    Jakarta Commons是Jakarta的一个子项目,目的是创建和维护独立于其他框架和产品的程序包(packages).Jakarta Commons项目源于重用,其中的程序包必须确保能够重用. ...

  4. Java Apache Commons Collection3.2.1 理解Transformer 接口

    Java Apache Commons Collection3.2.1 理解Transformer 接口 引言 Transformer 接口 InvokerTransformer MapTransfo ...

  5. java Apache Commons jar包简介

    一.Commons BeanUtils 说明:针对Bean的一个工具集.由于Bean往往是有一堆get和set组成,所以BeanUtils也是在此基础上进行一些包装. 二.Commons CLI 说明 ...

  6. java truevfs_Java-Apache Commons VFS:使用FTP

    我正在尝试通过FTP使用Apache Commons VFS.在我的FTP上,具有文件和文件夹的下一个结构: / /test /test/in /test/in/file1.txt /test/in/ ...

  7. Apache java文件比对,Java Apache Commons的字符串比较

    1、使用Apache Commons的equals()实现字符串比较 StringUtils类的equals()方法是String类方法equals()的增强版,它会处理null值:assertTha ...

  8. java apache commons_使用java apache commons下载文件?

    如果您正在寻找一种获取下载前总字节数的方法,您可以从http响应中的Content-Length头部获取此值. 如果您只想在下载后的最终字节数,最简单的方法是检查您要写入的文件大小. 但是,如果要显示 ...

  9. java apache commons_Apache commons(Java常用工具包)简介

    Apache Commons是一个非常有用的工具包,解决各种实际的通用问题,下面是一个简述表,详细信息访问http://jakarta.apache.org/commons/index.html Be ...

  10. digester java_[jakarta-commons] 使用Digester解释xml获取java对象(代码入注规则 或 配置规则 任你选!)...

    # re: [jakarta-commons] 使用Digester解释xml获取java对象(代码入注规则 或 配置规则 任你选!) 2009-11-09 10:27 | Java小子 楼主,运行起 ...

最新文章

  1. zz SOA推荐书籍列表
  2. js 字符串转成货币格式, js转货币
  3. opengl加载显示3D模型gltf类型文件
  4. 从应用开发角度认识 K8s
  5. 从技术角度聊聊,短视频为何让人停不下来?
  6. python扫描端口脚本_python写的端口扫描脚本
  7. C#LeetCode刷题之#874-模拟行走机器人​​​​​​​(Walking Robot Simulation)
  8. Mosquitto 0 15 开源MQTT v3 1 Broker
  9. Python学习—2048小游戏等4个小练习
  10. static 结构体_C++基础-static
  11. 点击场景中的物件无法定位到Hierarchy
  12. sklearn 线性回归算法+boston房价数据集
  13. jquery 常见特效_常见jQuery错误的解决方案
  14. 基于STM32的(NB-IOT(BC26))温湿度监测系统
  15. 汇率的思维导图模板下载方法
  16. ros_arduino_bridge功能包集的使用
  17. 汉语拼音字母n和l、in和ing的发音有什么区别?
  18. matlab曲线拟合
  19. 对话系统中的中文自然语言理解 (NLU) 任务介绍
  20. 图形学初步----------多边形填充算法

热门文章

  1. 常用APP签名存档以及获取签名的几种方式介绍
  2. 数学-线性代数:线性代数
  3. Poker Ⅱ 机械键盘使用说明书
  4. 在MacOS下为2K显示器开启HiDPI
  5. 在 WSO2 ESB 5.0.0 中使用 MyBatis 框架
  6. 如何调试 chrome插件
  7. Endnote x7.5 破解 注册 激活
  8. 类似endnote_除了EndNote,竟还有如此强大的文献管理软件!重点是正版免费!
  9. openssl生成key和pem文件
  10. 北航计算机学院考研英语一还是二,2020北京航空航天大学计算机考研考试科目知多少?...