您的位置:首页 > 运维架构 > Apache

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

2014-11-29 09:14 459 查看
前言

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-最常用 利用classloader
config.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-最常用 利用classloader
config.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- FreeMarker
String 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.velocity
String tRequestXml = handler.getRequestMsg(tUserBean);
System.out.println("apache.velocity 得到的xml文件: \r\n" +tRequestXml);


【输出】

// 2-apache.velocity
String 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
*/
@Component
public 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.velocity
String 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-最常用 利用classloader
config.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;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: