您的位置:首页 > 移动开发 > 微信开发

微信公众平台_发送被动响应消息接口 实体类转换为xml工具类

2014-07-01 11:07 344 查看
首先,微信公众平台发送被动响应消息接口官网wiki:

http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF

如,回复文本消息必须是如下格式:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>

回复图片消息格式:

<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[media_id]]></MediaId>
</Image>
</xml>


不得不吐槽下,这个回复消息格式不是json格式也罢,甚至连xml格式都不是。用传统的JOX(PS:不想用DOM)是无法将实体类直接转成这个API要求的xml格式的,吐槽归吐槽,但人家TX店大欺客,你不用也得用。

下面讲下笔者这里的处理方法-->

首先,有一个rsp模板类:

/**
* 被动响应消息模板基类,其他Msg类需extends其
* 注:Msg类属性命名方式未遵循驼峰模式,因为需要和微信接口定义保持一致。
* @author will_awoke
* @version 2014-6-24
* @see TemplateRspMsg
* @since
*/
public class TemplateRspMsg
{

// 响应消息时,接收方帐号(收到的OpenID)
protected String ToUserName;

// 响应消息时,开发者微信号(公众平台原始ID)
protected String FromUserName;

// 消息创建时间  Long型
protected String CreateTime;

// 消息类型
protected String MsgType;

/**
* 构造器
*/
public TemplateRspMsg()
{

}

//setter getter

public String getMsgType()
{
return MsgType;
}

//protected for msgTypeSetter
protected void setMsgType(String msgType)
{
MsgType = msgType;
}

public String getFromUserName()
{
return FromUserName;
}

public void setFromUserName(String fromUserName)
{
FromUserName = fromUserName;
}

public String getToUserName()
{
return ToUserName;
}

public void setToUserName(String toUserName)
{
ToUserName = toUserName;
}

public String getCreateTime()
{
return CreateTime;
}

public void setCreateTime(String createTime)
{
CreateTime = createTime;
}

}

文本类回复消息类,extends 模板类:

/**
* 文本类响应消息 MsgType=text
* @author will_awoke
* @version 2014-6-24
* @see TextRspMsg
* @since
*/
public class TextRspMsg extends TemplateRspMsg
{

//文本消息内容
private String Content;

/**
* 构造器,同时初始化MsgType
*/
public TextRspMsg()
{
setMsgType("text");
}

@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("TextRspMsg [Content=").append(Content).append(", ToUserName=").append(
ToUserName).append(", FromUserName=").append(FromUserName).append(", CreateTime=").append(
CreateTime).append(", MsgType=").append(MsgType).append("]");
return builder.toString();
}

//setter getter

public String getContent()
{
return Content;
}

public void setContent(String content)
{
Content = content;
}

}


图片类回复消息类,extends 模板类:

import java.util.HashMap;
import java.util.Map;

/**
* 图片类型客服消息
* @author will_awoke
* @version 2014-6-25
* @see ImageRspMsg
* @since
*/
public class ImageRspMsg extends TemplateRspMsg
{

//用于拼装形如  <Image><MediaId><![CDATA[media_id]]></MediaId></Image>专有属性
private Map<String, Object> Image;

/**
* 构造器,同时初始化MsgType
*/
public ImageRspMsg()
{
setMsgType("image");
}

/**
* 格式化成符合微信API要求的实体
* @param ToUserName 普通用户openid
* @param FromUserName  开发者微信号(公众平台原始ID)
* @param MediaId  通过上传多媒体文件,得到的id。
* @return 符合API要求的实体
* @see
*/
public ImageRspMsg xmlFormatBean(String ToUserName, String FromUserName, String MediaId)
{
this.setToUserName(ToUserName);
this.setFromUserName(FromUserName);
//由于微信服务端需要的时间整形是以秒为单位的,故需要除以1000L
this.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000L));
Map<String, Object> map = new HashMap<String, Object>();
map.put("MediaId", MediaId);
this.setImage(map);
return this;
}

//setter getter

public Map<String, Object> getImage()
{
return Image;
}

public void setImage(Map<String, Object> image)
{
Image = image;
}

}


下面是核心工具类:

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.xx.wechat.model.rsp.ImageRspMsg;
import com.xx.wechat.model.rsp.TextRspMsg;

/**
*
* 将被动响应消息实体类转换成符合微信接口API要求的xml格式。
* 如:
* <xml>
* <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime>
* <MsgType><![CDATA[image]]></MsgType>
* <Image>
*   <MediaId><![CDATA[media_id]]></MediaId>
* </Image>
* </xml>
* 注意:根节点是xml而非实体名,且无xml头文件,每个节点的首字母是大写。
* 而此功能是JOX转换不具有的,故造此轮子工具类
* 另请参见:wechat.model.rsp包
*
* @author will_awoke
* @version 2014-6-25
* @see Bean2WeChatXml
* @since
*/
public class Bean2WeChatXml
{

/**
* 将实体类转换成符合微信接口API要求的xml格式
* @param obj
* @return
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @see
*/
@SuppressWarnings("rawtypes")
public static String beanToXML(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
StringBuffer sb = new StringBuffer("<xml>\n");

Class clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();

//父类Class
Class superClass = clazz.getSuperclass();
Field[] superFields = superClass.getDeclaredFields();

//拼装自身的字段和字段值
String fieldName = null;
Object mapObj = null;
for (Field field : fields)
{
field.setAccessible(true);
fieldName = field.getName();//获得字段名
mapObj = field.get(obj);//获得字段值

//如果字段是Map类型,形如ImageRspMsg类中Map字段
if (mapObj instanceof Map)
{
//迭代map集合
StringBuffer mapFieldValue = new StringBuffer("");
String key = "";
Map castMap = (Map)mapObj;
Iterator iterator = castMap.keySet().iterator();
while (iterator.hasNext())
{
//迭代
key = (String)iterator.next();
mapFieldValue.append("<").append(key).append(">");
                    //调用value的toString方法
                    mapFieldValue.append("<![CDATA[").append(castMap.get(key).toString()).append("]]>");
                    mapFieldValue.append("</").append(key).append(">\n");
}
sb.append("<").append(fieldName).append(">\n");
                sb.append(mapFieldValue); //map集合内的迭代结果,勿加CDATA
                sb.append("</").append(fieldName).append(">\n");
}
//字段非Map类型,则按照String类型处理(获得value时直接调用toString方法)
else
{
 sb.append("<").append(fieldName).append(">");
                 sb.append("<![CDATA[").append(mapObj.toString()).append("]]>");
                 sb.append("</").append(fieldName).append(">\n");
}
}

//拼装父类的字段和字段值
String superFieldName = "";
for (Field field : superFields)
{
field.setAccessible(true);
superFieldName = field.getName();

sb.append("<").append(superFieldName).append(">");
            sb.append("<![CDATA[").append(field.get(obj).toString()).append("]]>");
            sb.append("</").append(superFieldName).append(">\n");

}
sb.append("</xml>");

return sb.toString();
}

/**
* @param args
* @see
*/
public static void main(String[] args)
throws Exception
{
TextRspMsg rsp = new TextRspMsg();
rsp.setToUserName("ToUserName");
rsp.setFromUserName("FromUserName");
rsp.setCreateTime(String.valueOf(System.currentTimeMillis()));
rsp.setContent("您好!welcome to subscribe will's public ...");

System.out.println(JoxUtil.beanToXML(rsp));
System.out.println(beanToXML(rsp));

ImageRspMsg image = new ImageRspMsg();
image.xmlFormatBean("ToUserName", "FromUserName", "MediaId");
System.out.println("\n" + beanToXML(image));
}

}

这个是console输出结果:

<?xml version="1.0" encoding="UTF-8"?>
<TextRspMsg>
<content>您好!welcome to subscribe will's public ...</content>
<createTime>1404286867859</createTime>
<fromUserName>FromUserName</fromUserName>
<msgType>text</msgType>
<toUserName>ToUserName</toUserName>
</TextRspMsg>

<xml>
<Content><![CDATA[您好!welcome to subscribe will's public ...]]></Content>
<ToUserName><![CDATA[ToUserName]]></ToUserName>
<FromUserName><![CDATA[FromUserName]]></FromUserName>
<CreateTime><![CDATA[1404286867859]]></CreateTime>
<MsgType><![CDATA[text]]></MsgType>
</xml>

<xml>
<Image>
<MediaId><![CDATA[MediaId]]></MediaId>
</Image>
<ToUserName><![CDATA[ToUserName]]></ToUserName>
<FromUserName><![CDATA[FromUserName]]></FromUserName>
<CreateTime><![CDATA[1404286868]]></CreateTime>
<MsgType><![CDATA[image]]></MsgType>
</xml>


可以看到传统的JOX转换来的xml是有header部分的,且多了个TextRspMsg节点,子节点都是小写(这里,JOX内部在转换为xml的时候会遵循Java命名格式,将所有的属性的首字符改成小写,所以,即使把实体类的字段属性故意写成大写也不行。)而用Bean2WeChatXml工具类转化来的xml就能完全满足API格式要求了,这也就是造这个轮子的意义所在。

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