XML学习笔记(七):使用freemark与apache填充xml模板

来源:互联网 发布:电气工程绘图软件 编辑:程序博客网 时间:2024/06/10 19:52

前言

1、在实际项目中,对于xml的解析的使用,除了dom4j和jaxb以外,xml模板的使用也是常有的事情,如短信模板,邮件模板,或者ESB的使用,都会涉及到xml模板的情况。

2、对于xml模板的使用与解析,dom4j当然是万能的,但是freemark与apache 有很好的封装的方法可以使用。

3、freemark:需要的jar包为,freemarker.jar(Configuration.java),spring-context-support.jar(FreeMarkerTemplateUtils.java).

4、apache:velocity.jar(VelocityContext.java 和 VelocityEngine)


一、模板 

1、位置:模板user-request.xml 



2、代码:xml模板的使用具有一定的格式:如${name} 或者$!{name}

<?xml version="1.0" encoding="utf-8" standalone="yes"?><USER>    <AGE>${age}</AGE>    <NAME>${name}</NAME>    <PhoneList>        <UserPhone>            <num>${num1}</num>            <type>${type1}</type>        </UserPhone>        <UserPhone>            <num>${num2}</num>            <type>${type2}</type>        </UserPhone>    </PhoneList>    <UserAddress>        <HomeAddress>${homeAddress}</HomeAddress>        <WorkAddress>${workAddress}</WorkAddress>    </UserAddress></USER>


3、模板对应的Bean数据

1)Bean数据的使用,看实际情况,正常来说可还是需要的,专门负责数据传输的DTO 。

2)这边的Bean数据,沿用了Jaxb的数据(XML学习笔记(六):Jaxb负责xml与javaBean映射)。

package xml.code.bean;import java.util.List;/** *  * UserBean.java * * @title User的传输数据类 * @description * @author SAM-SHO  * @Date 2014-11-25 */public class UserBean {private String name;private String key;private String age;private UserAddress userAddress;//地址private List<UserPhone> phoneList ;//手机public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}public UserAddress getUserAddress() {return userAddress;}public void setUserAddress(UserAddress userAddress) {this.userAddress = userAddress;}public List<UserPhone> getPhoneList() {return phoneList;}public void setPhoneList(List<UserPhone> phoneList) {this.phoneList = phoneList;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}}
package xml.code.bean;public class UserPhone {private String type;//电话号码类型private String num;//电话号码public String getType() {return type;}public void setType(String type) {this.type = type;}public String getNum() {return num;}public void setNum(String num) {this.num = num;}}

package xml.code.bean;public class UserAddress {private String homeAddress;//家庭地址private String workAddress;//公司地址public String getHomeAddress() {return homeAddress;}public void setHomeAddress(String homeAddress) {this.homeAddress = homeAddress;}public String getWorkAddress() {return workAddress;}public void setWorkAddress(String workAddress) {this.workAddress = workAddress;}}



二、使用 FreeMarker

1、代码

/** * 使用FreeMarker填充xml 模板 *  * @param tUserBean * @return */public String getUserRequestXml(UserBean tUserBean) {// 定义局部变量String templatePath = "/templete/"; // 报文模板路径String templateFileName = "user-request.xml"; // 报文模板文件名String requestXml = ""; // 请求报文Configuration config = new Configuration();try {// 方式1 绝对路径// config.setDirectoryForTemplateLoading(new// File("D:/apache-worksapce/MyEclipseNewWork2014/JavaTool/resources/templete"));// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板// 方式2-最常用 利用classloaderconfig.setClassForTemplateLoading(this.getClass(), "/");Template template = config.getTemplate(templatePath + templateFileName, "UTF-8");// 报文模板// 方式3 需要 servletContext// config.setServletContextForTemplateLoading("", "/ftl"); //就是/WebRoot/ftl目录。// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板// 设置模板参数Map<String, Object> content = new HashMap<String, Object>();content.put("name", tUserBean.getName());content.put("age", tUserBean.getAge());content.put("num1", tUserBean.getPhoneList().get(0).getNum());content.put("num2", tUserBean.getPhoneList().get(1).getNum());content.put("type1", tUserBean.getPhoneList().get(0).getType());content.put("type2", tUserBean.getPhoneList().get(1).getType());content.put("homeAddress", tUserBean.getUserAddress().getHomeAddress());content.put("workAddress", tUserBean.getUserAddress().getWorkAddress());requestXml = FreeMarkerTemplateUtils.processTemplateIntoString(template, content);if (requestXml == null || "".equals(requestXml)) {return null;}} catch (IOException e) {e.printStackTrace();} catch (TemplateException e) {e.printStackTrace();}// 返回报文字符串return requestXml;}

2、分析:


1)模板的获取方式有三种:

①、绝对路径:

// 方式1 绝对路径// config.setDirectoryForTemplateLoading(new// File("D:/apache-worksapce/MyEclipseNewWork2014/JavaTool/resources/templete"));// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板


②、相对路径,原理为类加载器。网上一些其他文章的分析都是错误的,这边的取得是类加载器的路劲,而不是这个类本身的路径。

// 方式2-最常用 利用classloaderconfig.setClassForTemplateLoading(this.getClass(), "/");Template template = config.getTemplate(templatePath + templateFileName, "UTF-8");// 报文模板


③、需要使用 ServletContext 

// 方式3 需要 servletContext// config.setServletContextForTemplateLoading("", "/ftl"); //就是/WebRoot/ftl目录。// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板


④、获取配置文件的方式,详见文章:

Servlet学习笔记(四):Servlet的请求与响应以及ServletContext详解

java进阶(六):Java类加载器


2)设置模板参数,注意key 与 模板${key}的一致性。

3)使用 FreeMarkerTemplateUtils.processTemplateIntoString() 即可得到结合好的xml数据。FreeMarkerTemplateUtils 类是 spring 中的封装。

4)测试:

UserBean tUserBean = new UserBean();tUserBean.setName("SAM-SHO");tUserBean.setAge("27");tUserBean.setKey("属性111");UserAddress tUserAddress = new UserAddress();tUserAddress.setWorkAddress("苏州园区");tUserAddress.setHomeAddress("苏州高新区");tUserBean.setUserAddress(tUserAddress);List<UserPhone> phoneList = new ArrayList<UserPhone>();UserPhone tUserPhone = new UserPhone();tUserPhone.setType("移动");tUserPhone.setNum("13612345678");phoneList.add(tUserPhone);tUserPhone = new UserPhone();tUserPhone.setType("联通");tUserPhone.setNum("13798765432");phoneList.add(tUserPhone);tUserBean.setPhoneList(phoneList);ObjectAndXmlHandler handler = new ObjectAndXmlHandler();// 1- FreeMarkerString tRequestXml = handler.getUserRequestXml(tUserBean);System.out.println(tRequestXml);

【输出】

得到的xml文件: <?xml version="1.0" encoding="utf-8" standalone="yes"?><USER>    <AGE>27</AGE>    <NAME>SAM-SHO</NAME>    <PhoneList>        <UserPhone>            <num>13612345678</num>            <type>移动</type>        </UserPhone>        <UserPhone>            <num>13798765432</num>            <type>联通</type>        </UserPhone>    </PhoneList>    <UserAddress>        <HomeAddress>苏州高新区</HomeAddress>        <WorkAddress>苏州园区</WorkAddress>    </UserAddress></USER>



三、使用 apache的 velocity 

1、这边封装了一个工具类,主要是两个类型的方法

1)填充模板的方法,填充内容至工程中的模板。

2)封装的内容写入字符串模板中。

package xml.code.templete.util;import java.io.StringReader;import java.io.StringWriter;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import java.util.Properties;import org.apache.velocity.Template;import org.apache.velocity.VelocityContext;import org.apache.velocity.app.VelocityEngine;/** *  * TemplateTool.java *  * @title 封装的工具类 * @description * @author SAM-SHO * @Date 2014-11-28 */public class TemplateTool {/** * 填充模板的方法 * @param context * @param tmdir * @param tmFile * @return */public static String fill(VelocityContext context, String tmdir, String tmFile) {String result = "";try {Properties p = new Properties();p.setProperty("file.resource.loader.path", tmdir);VelocityEngine ve = new VelocityEngine();ve.init(p);Template t = ve.getTemplate(tmFile);StringWriter writer = new StringWriter();t.merge(context, writer);result = writer.toString();writer.close();} catch (Exception e) {e.printStackTrace();}return result;}/** * 填充模板的方法 *  * @param context *            封装的数据 * @param tmdir *            路径 * @param tmFile *            文件名 * @param inputEncode *            入编码 * @param ouputEncode *            出编码 * @return */public static String fill(VelocityContext context, String tmdir, String tmFile, String inputEncode, String ouputEncode) {String result = "";try {Properties p = new Properties();p.setProperty("file.resource.loader.path", tmdir);p.setProperty("ISO-8859-1", "UTF-8");p.setProperty("input.encoding", inputEncode);p.setProperty("output.encoding", ouputEncode);VelocityEngine ve = new VelocityEngine();ve.init(p);Template t = ve.getTemplate(tmFile);StringWriter writer = new StringWriter();t.merge(context, writer);result = writer.toString();writer.close();} catch (Exception e) {e.printStackTrace();}return result;}/** * 封装的内容写入字符串模板中 *  * @param context * @param templateString * @return */public static String fill(VelocityContext context, String templateString) {String result = "";try {VelocityEngine ve = new VelocityEngine();ve.init();StringWriter writer = new StringWriter();StringReader reader = new StringReader(templateString);ve.evaluate(context, writer, "temp", reader);result = writer.toString();} catch (Exception e) {e.printStackTrace();}return result;}public static String test(int i) {return "array:" + i;}/** * 测试 *  * @param args * @throws Exception */public static void main(String[] args) throws Exception {ArrayList<Object> list = new ArrayList<Object>();Map<String,String> map = new HashMap<String,String>();map.put("name", "Cow");map.put("price", "100.00");list.add(map);map = new HashMap<String,String>();map.put("name", "Eagle");map.put("price", "59.99");list.add(map);map = new HashMap<String,String>();map.put("name", "Shark");map.put("price", "3.99");list.add(map);VelocityContext context = new VelocityContext();context.put("TemplateTool", new TemplateTool());context.put("workAddress", list);context.put("num", Integer.valueOf(10));context.put("name", "SAM-SHO");context.put("homeAddress", "苏州高新区");context.put("age", "27");// 1-写入项目中定义的模板String tmdir = TemplateTool.class.getClassLoader().getResource("templete/").getPath();String result = fill(context, tmdir, "user-request.xml", "UTF-8", "UTF-8");System.out.println("写入工程模板 :    \r\n" + result);// 2-写入字符串模板String result2 = fill(context, "${name},${homeAddress}");System.out.println("写入字符串模板:   " + result2);}}

【测试输出】

写入工程模板 :    <?xml version="1.0" encoding="utf-8" standalone="yes"?><USER>    <AGE>27</AGE>    <NAME>SAM-SHO</NAME>    <PhoneList>        <UserPhone>            <num>${num1}</num>            <type>${type1}</type>        </UserPhone>        <UserPhone>            <num>${num2}</num>            <type>${type2}</type>        </UserPhone>    </PhoneList>    <UserAddress>        <HomeAddress>苏州高新区</HomeAddress>        <WorkAddress>[{price=100.00, name=Cow}, {price=59.99, name=Eagle}, {price=3.99, name=Shark}]</WorkAddress>    </UserAddress></USER>写入字符串模板:   SAM-SHO,苏州高新区


2、使用 TemplateTool 填充模板。

1)方法:

/** * 利用apache 填充xml 模板 * @param tUserBean * @return */public String getRequestMsg(UserBean tUserBean) {// 定义局部变量String templatePath = "/templete/"; // 报文模板路径String templateFileName = "user-request.xml"; // 报文模板文件名String requestXml = "";// 构建请求报文,并转换成报文字符串VelocityContext content = new VelocityContext();content.put("name", tUserBean.getName());content.put("age", tUserBean.getAge());content.put("num1", tUserBean.getPhoneList().get(0).getNum());content.put("num2", tUserBean.getPhoneList().get(1).getNum());content.put("type1", tUserBean.getPhoneList().get(0).getType());content.put("type2", tUserBean.getPhoneList().get(1).getType());content.put("homeAddress", tUserBean.getUserAddress().getHomeAddress());content.put("workAddress", tUserBean.getUserAddress().getWorkAddress());requestXml = TemplateTool.fill(content, this.getClass().getResource(templatePath).getPath(), templateFileName, "GBK", "GBK");if (requestXml == null || "".equals(requestXml)) {return null;}// 返回报文字符串return requestXml;}

2)测试:

// 2-apache.velocityString tRequestXml = handler.getRequestMsg(tUserBean);System.out.println("apache.velocity 得到的xml文件: \r\n" +tRequestXml);

【输出】

// 2-apache.velocityString tRequestXml = handler.getRequestMsg(tUserBean);System.out.println("apache.velocity 得到的xml文件: \r\n" +tRequestXml);


四、把两种类型的解析方式进行封装。

package xml.code.templete.util;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.log4j.Logger;import org.apache.velocity.VelocityContext;import org.springframework.stereotype.Component;import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;import xml.code.bean.UserAddress;import xml.code.bean.UserBean;import xml.code.bean.UserPhone;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;/** *  * ObjectAndXmlHandler.java *  * @title xml模板使用 * @description 利用 freemarker 和 apache.velocity * @author SAM-SHO * @Date 2014-11-27 */@Componentpublic class ObjectAndXmlHandler {Logger logger = Logger.getLogger(this.getClass());public static void main(String[] args) {UserBean tUserBean = new UserBean();tUserBean.setName("SAM-SHO");tUserBean.setAge("27");tUserBean.setKey("属性111");UserAddress tUserAddress = new UserAddress();tUserAddress.setWorkAddress("苏州园区");tUserAddress.setHomeAddress("苏州高新区");tUserBean.setUserAddress(tUserAddress);List<UserPhone> phoneList = new ArrayList<UserPhone>();UserPhone tUserPhone = new UserPhone();tUserPhone.setType("移动");tUserPhone.setNum("13612345678");phoneList.add(tUserPhone);tUserPhone = new UserPhone();tUserPhone.setType("联通");tUserPhone.setNum("13798765432");phoneList.add(tUserPhone);tUserBean.setPhoneList(phoneList);ObjectAndXmlHandler handler = new ObjectAndXmlHandler();// 1- FreeMarker//String tRequestXml = handler.getUserRequestXml(tUserBean);//System.out.println("FreeMarker 得到的xml文件: \r\n" + tRequestXml);// 2-apache.velocityString tRequestXml = handler.getRequestMsg(tUserBean);System.out.println("apache.velocity 得到的xml文件: \r\n" +tRequestXml);}/** * 使用FreeMarker填充xml 模板 *  * @param tUserBean * @return */public String getUserRequestXml(UserBean tUserBean) {// 定义局部变量String templatePath = "/templete/"; // 报文模板路径String templateFileName = "user-request.xml"; // 报文模板文件名String requestXml = ""; // 请求报文Configuration config = new Configuration();try {// 方式1 绝对路径// config.setDirectoryForTemplateLoading(new// File("D:/apache-worksapce/MyEclipseNewWork2014/JavaTool/resources/templete"));// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板// 方式2-最常用 利用classloaderconfig.setClassForTemplateLoading(this.getClass(), "/");Template template = config.getTemplate(templatePath + templateFileName, "UTF-8");// 报文模板// 方式3 需要 servletContext// config.setServletContextForTemplateLoading("", "/ftl"); //就是/WebRoot/ftl目录。// Template template = config.getTemplate(templateFileName ,"UTF-8");// 报文模板// 设置模板参数Map<String, Object> content = new HashMap<String, Object>();content.put("name", tUserBean.getName());content.put("age", tUserBean.getAge());content.put("num1", tUserBean.getPhoneList().get(0).getNum());content.put("num2", tUserBean.getPhoneList().get(1).getNum());content.put("type1", tUserBean.getPhoneList().get(0).getType());content.put("type2", tUserBean.getPhoneList().get(1).getType());content.put("homeAddress", tUserBean.getUserAddress().getHomeAddress());content.put("workAddress", tUserBean.getUserAddress().getWorkAddress());requestXml = FreeMarkerTemplateUtils.processTemplateIntoString(template, content);if (requestXml == null || "".equals(requestXml)) {return null;}} catch (IOException e) {e.printStackTrace();} catch (TemplateException e) {e.printStackTrace();}// 返回报文字符串return requestXml;}/** * 利用apache 填充xml 模板 * @param tUserBean * @return */public String getRequestMsg(UserBean tUserBean) {// 定义局部变量String templatePath = "/templete/"; // 报文模板路径String templateFileName = "user-request.xml"; // 报文模板文件名String requestXml = "";// 构建请求报文,并转换成报文字符串VelocityContext content = new VelocityContext();content.put("name", tUserBean.getName());content.put("age", tUserBean.getAge());content.put("num1", tUserBean.getPhoneList().get(0).getNum());content.put("num2", tUserBean.getPhoneList().get(1).getNum());content.put("type1", tUserBean.getPhoneList().get(0).getType());content.put("type2", tUserBean.getPhoneList().get(1).getType());content.put("homeAddress", tUserBean.getUserAddress().getHomeAddress());content.put("workAddress", tUserBean.getUserAddress().getWorkAddress());requestXml = TemplateTool.fill(content, this.getClass().getResource(templatePath).getPath(), templateFileName, "GBK", "GBK");if (requestXml == null || "".equals(requestXml)) {return null;}// 返回报文字符串return requestXml;}}

0 0