Bean转换成xml格式
今天在调用机构的微信支付相关接口的时候,机构根据微信的规定,相关接口的入参必须为xml格式,格式如:
<xml>
<sign><![CDATA[80AAC36774B1144A5D00AA297B9D3B8D]]></sign>
<openid><![CDATA[oe59gt2SRLNflFCYoy1zZjHNab4g]]></openid>
<opertype>0</opertype>
<cardno><![CDATA[1000057017]]></cardno>
</xml>
在经过一番百度之后,发现了两个方法
1、用XStream转换成xml格式
OrganBalanceModel weixinBalanceRequest = new OrganBalanceModel();
weixinBalanceRequest.setSign("80AAC36774B1144A5D00AA297B9D3B8D");
weixinBalanceRequest.setOpenid("oe59gt2SRLNflFCYoy1zZjHNab4g");
weixinBalanceRequest.setOpertype("0");
weixinBalanceRequest.setCardno("1000057017");
XStream xStream = new XStream(new Xpp3Driver());
xStream.useAttributeFor(OrganBalanceModel.class);
String s = xStream.toXML(weixinBalanceRequest);
System.out.println(s);
转换成的xml格式如下:
<com.bangdao.project.common.model.OrganBalanceModel>
<sign>80AAC36774B1144A5D00AA297B9D3B8D</sign>
<openid>oe59gt2SRLNflFCYoy1zZjHNab4g</openid>
<opertype>0</opertype>
<cardno>1000057017</cardno>
</com.bangdao.project.common.model.OrganBalanceModel>
2、用JAXB转换成xml格式
public static void main(String[] args) throws JAXBException, IOException {
OrganBalanceModel weixinBalanceRequest = new OrganBalanceModel();
weixinBalanceRequest.setSign("80AAC36774B1144A5D00AA297B9D3B8D");
weixinBalanceRequest.setOpenid("oe59gt2SRLNflFCYoy1zZjHNab4g");
weixinBalanceRequest.setOpertype("0");
weixinBalanceRequest.setCardno("1000057017");
JAXBContext context = JAXBContext.newInstance(OrganBalanceModel.class);
OutputFormat of = new OutputFormat();
of.setCDataElements(
new String[] { "^conditionValue"});
of.setPreserveSpace(true);
of.setIndenting(true);
ByteArrayOutputStream op = new ByteArrayOutputStream();
XMLSerializer serializer = new XMLSerializer(op, of);
SAXResult result = new SAXResult(serializer.asContentHandler());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true);
marshaller.marshal(weixinBalanceRequest , result);
System.out.println(op.toString());
}
转换成的xml如下:
<organBalanceModel><cardno>1000057017</cardno><openid>oe59gt2SRLNflFCYoy1zZjHNab4g</openid><opertype>0</opertype><sign>80AAC36774B1144A5D00AA297B9D3B8D</sign></organBalanceModel>
这两种都可以转换成标准的xml格式,但是微信入参要求带CDATA的xml,就需要自定义转义的规则,但是JAXB比较麻烦,所以我选择了自定义XStream转义规则。
重写XStream的writeText方法,自定义转义规则,实现转换成带CDATA的xml:
private static XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
boolean cdata = true;
@SuppressWarnings("unchecked")
@Override
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
实现的xml格式如下:
<com.bangdao.project.common.model.OrganBalanceModel>
<sign><![CDATA[80AAC36774B1144A5D00AA297B9D3B8D]]></sign>
<openid><![CDATA[oe59gt2SRLNflFCYoy1zZjHNab4g]]></openid>
<opertype><![CDATA[0]]></opertype>
<cardno><![CDATA[1000057017]]></cardno>
</com.bangdao.project.common.model.OrganBalanceModel>
但是!!!微信的要求是opertype参数不带CDATA,也就是入参只是有的要用自定义规则。这样的话,全局直接改自定义规则是不现实的。在听完新宝岛之后,百度出来一种方法,就是自定义注解,需要带CDATA的参数,就加自定义注解,而不需要的就不带自定义注解,这样的方法就方便了许多,可以实现多种需求。
实现:
一、创建自定义注解@XStreamCDATA自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface XStreamCDATA {
}
二、创建XStreamFactory,改写XPPDriver
public class XstreamFactory {
public static XStream getXStream() {
final NameCoder nameCoder = new NoNameCoder();
XStream xStream = new XStream(new XppDomDriver(nameCoder) {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out, nameCoder) {
boolean cdataFlag = false;
Class<?> targetClass = null;
@Override
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
if (targetClass == null) {
targetClass = clazz;
}
cdataFlag = isCDATA(targetClass, name);
}
@Override
public void writeText(QuickWriter writer, String text) {
if (cdataFlag) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
return xStream;
}
private static boolean isCDATA(Class<?> clazz, String fieldAlias) {
//检查类本身
boolean cdataFlag = isExistCDATA(clazz, fieldAlias);
if (cdataFlag) {
return cdataFlag;
}
//继续检查父类
Class<?> superClazz = clazz.getSuperclass();
while (!superClazz.equals(Object.class)) {
cdataFlag = isExistCDATA(superClazz, fieldAlias);
if (cdataFlag) {
return cdataFlag;
}
superClazz = superClazz.getClass().getSuperclass();
}
return false;
}
/**
* 检查是否有 @XStreamCDATA 注解
* @param clazz clazz
* @param fieldAlias fieldAlias
* @return
*/
private static boolean isExistCDATA(Class<?> clazz, String fieldAlias) {
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(XStreamCDATA.class) != null) {
XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
if (xStreamAlias != null && fieldAlias.equals(xStreamAlias.value())) {
return true;
} else {
if (fieldAlias.equals(field.getName())) {
return true;
}
}
}
}
return false;
}
}
三、创建工具类
public class BeanXmlUtils {
private static final XStream xStream = XstreamFactory.getXStream();
/**
* 对象转xml
* @param obj 对象
* @return
*/
public static String toXml(Object obj) {
xStream.processAnnotations(obj.getClass());
return xStream.toXML(obj);
}
/**
* xml转对象
* @param xml
* @return
*/
public static Map CDATA2Map(String xml) {
Map retMap = new HashMap();
try {
StringReader read = new StringReader(xml);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
Document doc = (Document) sb.build(source);
// 指向根节点
Element root = doc.getRootElement();
List<Element> es = root.getChildren();
if (es != null && es.size() != 0) {
for (Element element : es) {
retMap.put(element.getName(), element.getValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return retMap;
}
}
四、创建对象类
@XStreamAlias("xml")
@ApiModel(description = "查询余额机构入参")
public class OrganBalanceModel {
/**
* md5摘要
*/
@XStreamCDATA
private String sign;
/**
* 微信的用户Id
*/
@XStreamAlias("openid")
@XStreamCDATA
private String openid;
/**
* 操作类型
*/
@XStreamAlias("opertype")
private String opertype;
/**
* 卡号
*/
@XStreamAlias("cardno")
@XStreamCDATA
private String cardno;
}