| @@ -1,17 +1,78 @@ | |||
| package chanjarster.weixin.api; | |||
| public class WxConsts { | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| public static final String MSG_TEXT = "text"; | |||
| public static final String MSG_IMAGE = "image"; | |||
| public static final String MSG_VOICE = "voice"; | |||
| public static final String MSG_MUSIC = "music"; | |||
| public static final String MSG_VIDEO = "video"; | |||
| public static final String MSG_NEWS = "news"; | |||
| public static final String MSG_LOCATION = "location"; | |||
| public static final String MSG_LINK = "link"; | |||
| public static final String MSG_EVENT = "event"; | |||
| public class WxConsts { | |||
| /////////////////////// | |||
| // 微信推送过来的消息的类型,和发送给微信xml格式消息的消息类型 | |||
| /////////////////////// | |||
| public static final String XML_MSG_TEXT = "text"; | |||
| public static final String XML_MSG_IMAGE = "image"; | |||
| public static final String XML_MSG_VOICE = "voice"; | |||
| public static final String XML_MSG_VIDEO = "video"; | |||
| public static final String XML_MSG_NEWS = "news"; | |||
| public static final String XML_MSG_MUSIC = "news"; | |||
| public static final String XML_MSG_LOCATION = "location"; | |||
| public static final String XML_MSG_LINK = "link"; | |||
| public static final String XML_MSG_EVENT = "event"; | |||
| /////////////////////// | |||
| // 客服消息的消息类型 | |||
| /////////////////////// | |||
| public static final String CUSTOM_MSG_TEXT = "text"; | |||
| public static final String CUSTOM_MSG_IMAGE = "image"; | |||
| public static final String CUSTOM_MSG_VOICE = "voice"; | |||
| public static final String CUSTOM_MSG_VIDEO = "video"; | |||
| public static final String CUSTOM_MSG_MUSIC = "music"; | |||
| public static final String CUSTOM_MSG_NEWS = "news"; | |||
| /////////////////////// | |||
| // 群发消息的消息类型 | |||
| /////////////////////// | |||
| public static final String MASS_MSG_NEWS = "mpnews"; | |||
| public static final String MASS_MSG_TEXT = "text"; | |||
| public static final String MASS_MSG_VOICE = "voice"; | |||
| public static final String MASS_MSG_IMAGE = "image"; | |||
| public static final String MASS_MSG_VIDEO = "mpvideo"; | |||
| /////////////////////// | |||
| // 群发消息后微信端推送给服务器的反馈消息 | |||
| /////////////////////// | |||
| public static final String MASS_ST_SUCCESS = "send success"; | |||
| public static final String MASS_ST_FAIL = "send fail"; | |||
| public static final String MASS_ST_涉嫌广告 = "err(10001)"; | |||
| public static final String MASS_ST_涉嫌政治 = "err(20001)"; | |||
| public static final String MASS_ST_涉嫌社会 = "err(20004)"; | |||
| public static final String MASS_ST_涉嫌色情 = "err(20002)"; | |||
| public static final String MASS_ST_涉嫌违法犯罪 = "err(20006)"; | |||
| public static final String MASS_ST_涉嫌欺诈 = "err(20008)"; | |||
| public static final String MASS_ST_涉嫌版权 = "err(20013)"; | |||
| public static final String MASS_ST_涉嫌互推_互相宣传 = "err(22000)"; | |||
| public static final String MASS_ST_涉嫌其他 = "err(21000)"; | |||
| /** | |||
| * 群发反馈消息代码所对应的文字描述 | |||
| */ | |||
| public static final Map<String, String> MASS_ST_2_DESC = new HashMap<String, String>(); | |||
| static { | |||
| MASS_ST_2_DESC.put(MASS_ST_SUCCESS, "发送成功"); | |||
| MASS_ST_2_DESC.put(MASS_ST_FAIL, "发送失败"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌广告, "涉嫌广告"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌政治, "涉嫌政治"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌社会, "涉嫌社会"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌色情, "涉嫌色情"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌违法犯罪, "涉嫌违法犯罪"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌欺诈, "涉嫌欺诈"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌版权, "涉嫌版权"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌互推_互相宣传, "涉嫌互推_互相宣传"); | |||
| MASS_ST_2_DESC.put(MASS_ST_涉嫌其他, "涉嫌其他"); | |||
| } | |||
| /////////////////////// | |||
| // 微信端推送过来的事件类型 | |||
| /////////////////////// | |||
| public static final String EVT_SUBSCRIBE = "subscribe"; | |||
| public static final String EVT_UNSUBSCRIBE = "unsubscribe"; | |||
| public static final String EVT_SCAN = "SCAN"; | |||
| @@ -20,25 +81,20 @@ public class WxConsts { | |||
| public static final String EVT_VIEW = "VIEW"; | |||
| public static final String EVT_MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH"; | |||
| /////////////////////// | |||
| // 上传多媒体文件的类型 | |||
| /////////////////////// | |||
| public static final String MEDIA_IMAGE = "image"; | |||
| public static final String MEDIA_VOICE = "voice"; | |||
| public static final String MEDIA_VIDEO = "video"; | |||
| public static final String MEDIA_THUMB = "thumb"; | |||
| /////////////////////// | |||
| // 文件类型 | |||
| /////////////////////// | |||
| public static final String FILE_JPG = "jpeg"; | |||
| public static final String FILE_MP3 = "mp3"; | |||
| public static final String FILE_ARM = "arm"; | |||
| public static final String FILE_MP4 = "mp4"; | |||
| public static final String ST_SEND_SUCCESS = "send success"; | |||
| public static final String ST_SEND_FAIL = "send fail"; | |||
| public static final String ST_涉嫌广告 = "err(10001)"; | |||
| public static final String ST_涉嫌政治 = "err(20001)"; | |||
| public static final String ST_涉嫌社会 = "err(20004)"; | |||
| public static final String ST_涉嫌色情 = "err(20002)"; | |||
| public static final String ST_涉嫌违法犯罪 = "err(20006)"; | |||
| public static final String ST_涉嫌欺诈 = "err(20008)"; | |||
| public static final String ST_涉嫌版权 = "err(20013)"; | |||
| public static final String ST_涉嫌互推_互相宣传 = "err(22000)"; | |||
| public static final String ST_涉嫌其他 = "err(21000)"; | |||
| } | |||
| @@ -5,8 +5,13 @@ import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxMassMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassVideo; | |||
| import chanjarster.weixin.bean.WxMenu; | |||
| import chanjarster.weixin.bean.result.WxUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMassMaterialUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMassSendResult; | |||
| import chanjarster.weixin.bean.result.WxMediaUploadResult; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| /** | |||
| @@ -58,7 +63,7 @@ public interface WxService { | |||
| * @param inputStream 输入流 | |||
| * @throws WxErrorException | |||
| */ | |||
| public WxUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException; | |||
| public WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException; | |||
| /** | |||
| * @see #uploadMedia(String, String, InputStream) | |||
| @@ -66,7 +71,7 @@ public interface WxService { | |||
| * @param file | |||
| * @throws WxErrorException | |||
| */ | |||
| public WxUploadResult uploadMedia(String mediaType, File file) throws WxErrorException; | |||
| public WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| @@ -90,6 +95,40 @@ public interface WxService { | |||
| */ | |||
| public void sendCustomMessage(WxCustomMessage message) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 上传群发用的图文消息,上传后才能群发图文消息 {@link #sendMassMessage(WxMassMessage)} | |||
| * | |||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 | |||
| * </pre> | |||
| * @param news | |||
| * @throws WxErrorException | |||
| */ | |||
| public WxMassMaterialUploadResult uploadMassNews(WxMassNews news) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 上传群发用的视频,上传后才能群发视频消息 {@link #sendMassMessage(WxMassMessage)} | |||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 | |||
| * </pre> | |||
| * @return | |||
| * @throws WxErrorException | |||
| */ | |||
| public WxMassMaterialUploadResult uploadMassVideo(WxMassVideo video) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 群发消息 | |||
| * 如果发送图文消息,必须先使用 {@link #uploadMassNews(WxMassNews)} 获得media_id,然后再发送 | |||
| * 如果发送视频消息,必须先使用 {@link #uploadMassVideo(WxMassVideo)} 获得media_id,然后再发送 | |||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口 | |||
| * </pre> | |||
| * @param message | |||
| * @throws WxErrorException | |||
| * @return | |||
| */ | |||
| public WxMassSendResult sendMassMessage(WxMassMessage message) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 自定义菜单创建接口 | |||
| @@ -18,9 +18,14 @@ import org.apache.http.impl.client.HttpClients; | |||
| import chanjarster.weixin.bean.WxAccessToken; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxMassMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassVideo; | |||
| import chanjarster.weixin.bean.WxMenu; | |||
| import chanjarster.weixin.bean.result.WxError; | |||
| import chanjarster.weixin.bean.result.WxUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMassMaterialUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMassSendResult; | |||
| import chanjarster.weixin.bean.result.WxMediaUploadResult; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| import chanjarster.weixin.util.fs.FileUtil; | |||
| import chanjarster.weixin.util.http.MediaDownloadRequestExecutor; | |||
| @@ -137,11 +142,11 @@ public class WxServiceImpl implements WxService { | |||
| } | |||
| } | |||
| public WxUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { | |||
| public WxMediaUploadResult uploadMedia(String mediaType, String fileType, InputStream inputStream) throws WxErrorException, IOException { | |||
| return uploadMedia(mediaType,FileUtil.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType)); | |||
| } | |||
| public WxUploadResult uploadMedia(String mediaType, File file) throws WxErrorException { | |||
| public WxMediaUploadResult uploadMedia(String mediaType, File file) throws WxErrorException { | |||
| String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?type=" + mediaType; | |||
| return execute(new MediaUploadRequestExecutor(), url, file); | |||
| } | |||
| @@ -151,6 +156,24 @@ public class WxServiceImpl implements WxService { | |||
| return execute(new MediaDownloadRequestExecutor(), url, "media_id=" + media_id); | |||
| } | |||
| public WxMassMaterialUploadResult uploadMassNews(WxMassNews news) throws WxErrorException { | |||
| String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews"; | |||
| String responseContent = execute(new SimplePostRequestExecutor(), url, news.toJson()); | |||
| return WxMassMaterialUploadResult.fromJson(responseContent); | |||
| } | |||
| public WxMassMaterialUploadResult uploadMassVideo(WxMassVideo video) throws WxErrorException { | |||
| String url = " https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo"; | |||
| String responseContent = execute(new SimplePostRequestExecutor(), url, video.toJson()); | |||
| return WxMassMaterialUploadResult.fromJson(responseContent); | |||
| } | |||
| public WxMassSendResult sendMassMessage(WxMassMessage message) throws WxErrorException { | |||
| String url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall"; | |||
| String responseContent = execute(new SimplePostRequestExecutor(), url, message.toJson()); | |||
| return WxMassSendResult.fromJson(responseContent); | |||
| } | |||
| /** | |||
| * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | |||
| * @param executor | |||
| @@ -3,6 +3,7 @@ package chanjarster.weixin.bean; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import chanjarster.weixin.api.WxConsts; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| @@ -32,6 +33,19 @@ public class WxCustomMessage { | |||
| public String getMsgtype() { | |||
| return msgtype; | |||
| } | |||
| /** | |||
| * <pre> | |||
| * 请使用 | |||
| * {@link WxConsts#CUSTOM_MSG_TEXT} | |||
| * {@link WxConsts#CUSTOM_MSG_IMAGE} | |||
| * {@link WxConsts#CUSTOM_MSG_VOICE} | |||
| * {@link WxConsts#CUSTOM_MSG_MUSIC} | |||
| * {@link WxConsts#CUSTOM_MSG_VIDEO} | |||
| * {@link WxConsts#CUSTOM_MSG_NEWS} | |||
| * </pre> | |||
| * @param msgtype | |||
| */ | |||
| public void setMsgtype(String msgtype) { | |||
| this.msgtype = msgtype; | |||
| } | |||
| @@ -0,0 +1,96 @@ | |||
| package chanjarster.weixin.bean; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import chanjarster.weixin.api.WxConsts; | |||
| import chanjarster.weixin.bean.result.WxMassMaterialUploadResult; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * 群发消息 | |||
| * | |||
| * @author chanjarster | |||
| */ | |||
| public class WxMassMessage { | |||
| protected List<String> touser = new ArrayList<String>(); | |||
| protected String group_id; | |||
| protected String msgtype; | |||
| protected String content; | |||
| protected String media_id; | |||
| public WxMassMessage() { | |||
| super(); | |||
| } | |||
| /** | |||
| * 利用上传群发所用的素材的结果,构造群发消息 | |||
| * @param r | |||
| * @return | |||
| */ | |||
| public WxMassMessage(WxMassMaterialUploadResult r) { | |||
| setMedia_id(r.getMedia_id()); | |||
| if("video".equals(r.getType())) { | |||
| setMsgtype(WxConsts.MASS_MSG_VIDEO); | |||
| } else { | |||
| setMsgtype(r.getType()); | |||
| } | |||
| } | |||
| public String getMsgtype() { | |||
| return msgtype; | |||
| } | |||
| /** | |||
| * <pre> | |||
| * 请使用 | |||
| * {@link WxConsts#MASS_MSG_IMAGE} | |||
| * {@link WxConsts#MASS_MSG_NEWS} | |||
| * {@link WxConsts#MASS_MSG_TEXT} | |||
| * {@link WxConsts#MASS_MSG_VIDEO} | |||
| * {@link WxConsts#MASS_MSG_VOICE} | |||
| * </pre> | |||
| * @param msgtype | |||
| */ | |||
| public void setMsgtype(String msgtype) { | |||
| this.msgtype = msgtype; | |||
| } | |||
| public String getContent() { | |||
| return content; | |||
| } | |||
| public void setContent(String content) { | |||
| this.content = content; | |||
| } | |||
| public String getMedia_id() { | |||
| return media_id; | |||
| } | |||
| public void setMedia_id(String media_id) { | |||
| this.media_id = media_id; | |||
| } | |||
| public String toJson() { | |||
| return WxGsonBuilder.INSTANCE.create().toJson(this); | |||
| } | |||
| public List<String> getTouser() { | |||
| return touser; | |||
| } | |||
| public void setTouser(List<String> touser) { | |||
| this.touser = touser; | |||
| } | |||
| public String getGroup_id() { | |||
| return group_id; | |||
| } | |||
| public void setGroup_id(String group_id) { | |||
| this.group_id = group_id; | |||
| } | |||
| } | |||
| @@ -0,0 +1,102 @@ | |||
| package chanjarster.weixin.bean; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * 群发时用到的图文消息素材 | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class WxMassNews { | |||
| protected List<WxMassNewsArticle> articles = new ArrayList<WxMassNewsArticle>(); | |||
| public List<WxMassNewsArticle> getArticles() { | |||
| return articles; | |||
| } | |||
| public void setArticles(List<WxMassNewsArticle> articles) { | |||
| this.articles = articles; | |||
| } | |||
| public String toJson() { | |||
| return WxGsonBuilder.INSTANCE.create().toJson(this); | |||
| } | |||
| public static class WxMassNewsArticle { | |||
| /** | |||
| * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 | |||
| */ | |||
| protected String thumb_media_id; | |||
| /** | |||
| * 图文消息的作者 | |||
| */ | |||
| protected String author; | |||
| /** | |||
| * (必填) 图文消息的标题 | |||
| */ | |||
| protected String title; | |||
| /** | |||
| * 在图文消息页面点击“阅读原文”后的页面 | |||
| */ | |||
| protected String content_source_url; | |||
| /** | |||
| * (必填) 图文消息页面的内容,支持HTML标签 | |||
| */ | |||
| protected String content; | |||
| /** | |||
| * 图文消息的描述 | |||
| */ | |||
| protected String digest; | |||
| /** | |||
| * 是否显示封面,1为显示,0为不显示 | |||
| */ | |||
| protected boolean show_cover_pic; | |||
| public String getThumb_media_id() { | |||
| return thumb_media_id; | |||
| } | |||
| public void setThumb_media_id(String thumb_media_id) { | |||
| this.thumb_media_id = thumb_media_id; | |||
| } | |||
| public String getAuthor() { | |||
| return author; | |||
| } | |||
| public void setAuthor(String author) { | |||
| this.author = author; | |||
| } | |||
| public String getTitle() { | |||
| return title; | |||
| } | |||
| public void setTitle(String title) { | |||
| this.title = title; | |||
| } | |||
| public String getContent_source_url() { | |||
| return content_source_url; | |||
| } | |||
| public void setContent_source_url(String content_source_url) { | |||
| this.content_source_url = content_source_url; | |||
| } | |||
| public String getContent() { | |||
| return content; | |||
| } | |||
| public void setContent(String content) { | |||
| this.content = content; | |||
| } | |||
| public String getDigest() { | |||
| return digest; | |||
| } | |||
| public void setDigest(String digest) { | |||
| this.digest = digest; | |||
| } | |||
| public boolean isShow_cover_pic() { | |||
| return show_cover_pic; | |||
| } | |||
| public void setShow_cover_pic(boolean show_cover_pic) { | |||
| this.show_cover_pic = show_cover_pic; | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| package chanjarster.weixin.bean; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * 群发时用到的视频素材 | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class WxMassVideo { | |||
| protected String media_id; | |||
| protected String title; | |||
| protected String description; | |||
| public String getTitle() { | |||
| return title; | |||
| } | |||
| public void setTitle(String title) { | |||
| this.title = title; | |||
| } | |||
| public String getDescription() { | |||
| return description; | |||
| } | |||
| public void setDescription(String description) { | |||
| this.description = description; | |||
| } | |||
| public String toJson() { | |||
| return WxGsonBuilder.INSTANCE.create().toJson(this); | |||
| } | |||
| } | |||
| @@ -9,6 +9,7 @@ import javax.xml.bind.annotation.XmlElement; | |||
| import javax.xml.bind.annotation.XmlRootElement; | |||
| import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||
| import chanjarster.weixin.api.WxConsts; | |||
| import chanjarster.weixin.util.xml.AdapterCDATA; | |||
| import chanjarster.weixin.util.xml.XmlTransformer; | |||
| @@ -159,9 +160,35 @@ public class WxXmlMessage { | |||
| CreateTime = createTime; | |||
| } | |||
| /** | |||
| * <pre> | |||
| * 当接受用户消息时,可能会获得以下值: | |||
| * {@link WxConsts#XML_MSG_TEXT} | |||
| * {@link WxConsts#XML_MSG_IMAGE} | |||
| * {@link WxConsts#XML_MSG_VOICE} | |||
| * {@link WxConsts#XML_MSG_VIDEO} | |||
| * {@link WxConsts#XML_MSG_LOCATION} | |||
| * {@link WxConsts#XML_MSG_LINK} | |||
| * {@link WxConsts#XML_MSG_EVENT} | |||
| * </pre> | |||
| * @return | |||
| */ | |||
| public String getMsgType() { | |||
| return MsgType; | |||
| } | |||
| /** | |||
| * <pre> | |||
| * 当发送消息的时候使用: | |||
| * {@link WxConsts#XML_MSG_TEXT} | |||
| * {@link WxConsts#XML_MSG_IMAGE} | |||
| * {@link WxConsts#XML_MSG_VOICE} | |||
| * {@link WxConsts#XML_MSG_VIDEO} | |||
| * {@link WxConsts#XML_MSG_NEWS} | |||
| * {@link WxConsts#XML_MSG_MUSIC} | |||
| * </pre> | |||
| * @param msgType | |||
| */ | |||
| public void setMsgType(String msgType) { | |||
| MsgType = msgType; | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| package chanjarster.weixin.bean.result; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * 上传群发所用的素材的结果 | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class WxMassMaterialUploadResult { | |||
| protected String type; | |||
| protected String media_id; | |||
| protected long created_at; | |||
| public String getType() { | |||
| return type; | |||
| } | |||
| public void setType(String type) { | |||
| this.type = type; | |||
| } | |||
| public String getMedia_id() { | |||
| return media_id; | |||
| } | |||
| public void setMedia_id(String media_id) { | |||
| this.media_id = media_id; | |||
| } | |||
| public long getCreated_at() { | |||
| return created_at; | |||
| } | |||
| public void setCreated_at(long created_at) { | |||
| this.created_at = created_at; | |||
| } | |||
| public static WxMassMaterialUploadResult fromJson(String json) { | |||
| return WxGsonBuilder.create().fromJson(json, WxMassMaterialUploadResult.class); | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return "WxUploadResult [type=" + type + ", media_id=" + media_id + ", created_at=" + created_at + "]"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| package chanjarster.weixin.bean.result; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * <pre> | |||
| * 群发消息一发送就返回的结果 | |||
| * | |||
| * 真正的群发消息是否发送成功要看 | |||
| * http://mp.weixin.qq.com/wiki/index.php?title=高级群发接口#.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81.E7.BE.A4.E5.8F.91.E7.BB.93.E6.9E.9C | |||
| * | |||
| * </pre> | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class WxMassSendResult { | |||
| protected String errcode; | |||
| protected String errmsg; | |||
| protected String msg_id; | |||
| public String getErrcode() { | |||
| return errcode; | |||
| } | |||
| public void setErrcode(String errcode) { | |||
| this.errcode = errcode; | |||
| } | |||
| public String getErrmsg() { | |||
| return errmsg; | |||
| } | |||
| public void setErrmsg(String errmsg) { | |||
| this.errmsg = errmsg; | |||
| } | |||
| public String getMsg_id() { | |||
| return msg_id; | |||
| } | |||
| public void setMsg_id(String msg_id) { | |||
| this.msg_id = msg_id; | |||
| } | |||
| public static WxMassSendResult fromJson(String json) { | |||
| return WxGsonBuilder.create().fromJson(json, WxMassSendResult.class); | |||
| } | |||
| } | |||
| @@ -2,7 +2,7 @@ package chanjarster.weixin.bean.result; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| public class WxUploadResult { | |||
| public class WxMediaUploadResult { | |||
| protected String type; | |||
| protected String media_id; | |||
| @@ -33,8 +33,8 @@ public class WxUploadResult { | |||
| this.created_at = created_at; | |||
| } | |||
| public static WxUploadResult fromJson(String json) { | |||
| return WxGsonBuilder.create().fromJson(json, WxUploadResult.class); | |||
| public static WxMediaUploadResult fromJson(String json) { | |||
| return WxGsonBuilder.create().fromJson(json, WxMediaUploadResult.class); | |||
| } | |||
| public String getThumb_media_id() { | |||
| @@ -11,7 +11,7 @@ import org.apache.http.entity.ContentType; | |||
| import org.apache.http.entity.mime.MultipartEntityBuilder; | |||
| import chanjarster.weixin.bean.result.WxError; | |||
| import chanjarster.weixin.bean.result.WxUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMediaUploadResult; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| /** | |||
| @@ -19,10 +19,10 @@ import chanjarster.weixin.exception.WxErrorException; | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class MediaUploadRequestExecutor implements RequestExecutor<WxUploadResult, File> { | |||
| public class MediaUploadRequestExecutor implements RequestExecutor<WxMediaUploadResult, File> { | |||
| @Override | |||
| public WxUploadResult execute(String uri, File file) throws WxErrorException, ClientProtocolException, IOException { | |||
| public WxMediaUploadResult execute(String uri, File file) throws WxErrorException, ClientProtocolException, IOException { | |||
| HttpPost httpPost = new HttpPost(uri); | |||
| if (file != null) { | |||
| HttpEntity entity = MultipartEntityBuilder | |||
| @@ -38,7 +38,7 @@ public class MediaUploadRequestExecutor implements RequestExecutor<WxUploadResul | |||
| if (error.getErrcode() != 0) { | |||
| throw new WxErrorException(error); | |||
| } | |||
| return WxUploadResult.fromJson(responseContent); | |||
| return WxMediaUploadResult.fromJson(responseContent); | |||
| } | |||
| } | |||
| @@ -32,25 +32,25 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
| messageJson.addProperty("touser", message.getTouser()); | |||
| messageJson.addProperty("msgtype", message.getMsgtype()); | |||
| if (WxConsts.MSG_TEXT.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_TEXT.equals(message.getMsgtype())) { | |||
| JsonObject text = new JsonObject(); | |||
| text.addProperty("content", message.getContent()); | |||
| messageJson.add("text", text); | |||
| } | |||
| if (WxConsts.MSG_IMAGE.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_IMAGE.equals(message.getMsgtype())) { | |||
| JsonObject image = new JsonObject(); | |||
| image.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("image", image); | |||
| } | |||
| if (WxConsts.MSG_VOICE.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_VOICE.equals(message.getMsgtype())) { | |||
| JsonObject voice = new JsonObject(); | |||
| voice.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("voice", voice); | |||
| } | |||
| if (WxConsts.MSG_VIDEO.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_VIDEO.equals(message.getMsgtype())) { | |||
| JsonObject video = new JsonObject(); | |||
| video.addProperty("media_id", message.getMedia_id()); | |||
| video.addProperty("thumb_media_id", message.getThumb_media_id()); | |||
| @@ -59,7 +59,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
| messageJson.add("video", video); | |||
| } | |||
| if (WxConsts.MSG_MUSIC.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_MUSIC.equals(message.getMsgtype())) { | |||
| JsonObject music = new JsonObject(); | |||
| music.addProperty("title", message.getTitle()); | |||
| music.addProperty("description", message.getDescription()); | |||
| @@ -69,7 +69,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
| messageJson.add("music", music); | |||
| } | |||
| if (WxConsts.MSG_NEWS.equals(message.getMsgtype())) { | |||
| if (WxConsts.CUSTOM_MSG_NEWS.equals(message.getMsgtype())) { | |||
| JsonArray articleJsonArray = new JsonArray(); | |||
| for (WxArticle article : message.getArticles()) { | |||
| JsonObject articleJson = new JsonObject(); | |||
| @@ -1,6 +1,8 @@ | |||
| package chanjarster.weixin.util.json; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxMassMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMenu; | |||
| import com.google.gson.Gson; | |||
| @@ -14,6 +16,8 @@ public class WxGsonBuilder { | |||
| INSTANCE.disableHtmlEscaping(); | |||
| INSTANCE.registerTypeAdapter(WxCustomMessage.class, new WxCustomMessageGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxMenu.class, new WxMenuGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxMassNews.class, new WxMassNewsGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxMassMessage.class, new WxMassMessageGsonAdapter()); | |||
| } | |||
| public static Gson create() { | |||
| @@ -0,0 +1,74 @@ | |||
| /* | |||
| * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||
| * | |||
| * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||
| * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||
| * arose from modification of the original source, or other redistribution of this source | |||
| * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||
| */ | |||
| package chanjarster.weixin.util.json; | |||
| import java.lang.reflect.Type; | |||
| import chanjarster.weixin.api.WxConsts; | |||
| import chanjarster.weixin.bean.WxMassMessage; | |||
| import com.google.gson.JsonArray; | |||
| import com.google.gson.JsonElement; | |||
| import com.google.gson.JsonObject; | |||
| import com.google.gson.JsonPrimitive; | |||
| import com.google.gson.JsonSerializationContext; | |||
| import com.google.gson.JsonSerializer; | |||
| /** | |||
| * | |||
| * @author qianjia | |||
| * | |||
| */ | |||
| public class WxMassMessageGsonAdapter implements JsonSerializer<WxMassMessage> { | |||
| public JsonElement serialize(WxMassMessage message, Type typeOfSrc, JsonSerializationContext context) { | |||
| JsonObject messageJson = new JsonObject(); | |||
| if (message.getTouser().size() > 0) { | |||
| JsonArray sub = new JsonArray(); | |||
| for(String openId : message.getTouser()) { | |||
| sub.add(new JsonPrimitive(openId)); | |||
| } | |||
| messageJson.add("touser", sub); | |||
| } else { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("group_id", message.getGroup_id()); | |||
| messageJson.add("filter", sub); | |||
| } | |||
| if (WxConsts.MASS_MSG_NEWS.equals(message.getMsgtype())) { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("mpnews", sub); | |||
| } | |||
| if (WxConsts.MASS_MSG_TEXT.equals(message.getMsgtype())) { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("content", message.getContent()); | |||
| messageJson.add("text", sub); | |||
| } | |||
| if (WxConsts.MASS_MSG_VOICE.equals(message.getMsgtype())) { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("voice", sub); | |||
| } | |||
| if (WxConsts.MASS_MSG_IMAGE.equals(message.getMsgtype())) { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("image", sub); | |||
| } | |||
| if (WxConsts.MASS_MSG_VIDEO.equals(message.getMsgtype())) { | |||
| JsonObject sub = new JsonObject(); | |||
| sub.addProperty("media_id", message.getMedia_id()); | |||
| messageJson.add("mpvideo", sub); | |||
| } | |||
| messageJson.addProperty("msgtype", message.getMsgtype()); | |||
| return messageJson; | |||
| } | |||
| } | |||
| @@ -0,0 +1,56 @@ | |||
| /* | |||
| * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||
| * | |||
| * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||
| * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||
| * arose from modification of the original source, or other redistribution of this source | |||
| * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||
| */ | |||
| package chanjarster.weixin.util.json; | |||
| import java.lang.reflect.Type; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassNews.WxMassNewsArticle; | |||
| import com.google.gson.JsonArray; | |||
| import com.google.gson.JsonElement; | |||
| import com.google.gson.JsonObject; | |||
| import com.google.gson.JsonSerializationContext; | |||
| import com.google.gson.JsonSerializer; | |||
| /** | |||
| * | |||
| * @author qianjia | |||
| * | |||
| */ | |||
| public class WxMassNewsGsonAdapter implements JsonSerializer<WxMassNews> { | |||
| public JsonElement serialize(WxMassNews message, Type typeOfSrc, JsonSerializationContext context) { | |||
| JsonObject newsJson = new JsonObject(); | |||
| JsonArray articleJsonArray = new JsonArray(); | |||
| for (WxMassNewsArticle article : message.getArticles()) { | |||
| JsonObject articleJson = new JsonObject(); | |||
| articleJson.addProperty("thumb_media_id", article.getThumb_media_id()); | |||
| articleJson.addProperty("title", article.getTitle()); | |||
| articleJson.addProperty("content", article.getContent()); | |||
| if (null != article.getAuthor()) { | |||
| articleJson.addProperty("author", article.getAuthor()); | |||
| } | |||
| if (null != article.getContent_source_url()) { | |||
| articleJson.addProperty("content_source_url", article.getContent_source_url()); | |||
| } | |||
| if (null != article.getDigest()) { | |||
| articleJson.addProperty("digest", article.getDigest()); | |||
| } | |||
| articleJson.addProperty("show_cover_pic", article.isShow_cover_pic() ? "1" : "0"); | |||
| articleJsonArray.add(articleJson); | |||
| } | |||
| newsJson.add("articles", articleJsonArray); | |||
| return newsJson; | |||
| } | |||
| } | |||
| @@ -21,18 +21,18 @@ public class WxMessageRouterTest { | |||
| this.router = new WxMessageRouter(); | |||
| router | |||
| .rule() | |||
| .msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
| .handler(new WxEchoMessageHandler(sb, "COMBINE_4")) | |||
| .end() | |||
| .rule() | |||
| .msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") | |||
| .handler(new WxEchoMessageHandler(sb, "COMBINE_3")) | |||
| .end() | |||
| .rule() | |||
| .msgType(WxConsts.MSG_TEXT).event(WxConsts.EVT_CLICK) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) | |||
| .handler(new WxEchoMessageHandler(sb, "COMBINE_2")) | |||
| .end() | |||
| .rule().msgType(WxConsts.MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.MSG_TEXT)).end() | |||
| .rule().msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() | |||
| .rule().event(WxConsts.EVT_CLICK).handler(new WxEchoMessageHandler(sb, WxConsts.EVT_CLICK)).end() | |||
| .rule().eventKey("KEY_1").handler(new WxEchoMessageHandler(sb, "KEY_1")).end() | |||
| .rule().content("CONTENT_1").handler(new WxEchoMessageHandler(sb, "CONTENT_1")).end() | |||
| @@ -54,7 +54,7 @@ public class WxMessageRouterTest { | |||
| @DataProvider(name="messages-1") | |||
| public Object[][] messages2() { | |||
| WxXmlMessage message1 = new WxXmlMessage(); | |||
| message1.setMsgType(WxConsts.MSG_TEXT); | |||
| message1.setMsgType(WxConsts.XML_MSG_TEXT); | |||
| WxXmlMessage message2 = new WxXmlMessage(); | |||
| message2.setEvent(WxConsts.EVT_CLICK); | |||
| @@ -69,22 +69,22 @@ public class WxMessageRouterTest { | |||
| message5.setContent("BLA"); | |||
| WxXmlMessage c2 = new WxXmlMessage(); | |||
| c2.setMsgType(WxConsts.MSG_TEXT); | |||
| c2.setMsgType(WxConsts.XML_MSG_TEXT); | |||
| c2.setEvent(WxConsts.EVT_CLICK); | |||
| WxXmlMessage c3 = new WxXmlMessage(); | |||
| c3.setMsgType(WxConsts.MSG_TEXT); | |||
| c3.setMsgType(WxConsts.XML_MSG_TEXT); | |||
| c3.setEvent(WxConsts.EVT_CLICK); | |||
| c3.setEventKey("KEY_1"); | |||
| WxXmlMessage c4 = new WxXmlMessage(); | |||
| c4.setMsgType(WxConsts.MSG_TEXT); | |||
| c4.setMsgType(WxConsts.XML_MSG_TEXT); | |||
| c4.setEvent(WxConsts.EVT_CLICK); | |||
| c4.setEventKey("KEY_1"); | |||
| c4.setContent("CONTENT_1"); | |||
| return new Object[][] { | |||
| new Object[] { message1, WxConsts.MSG_TEXT + "," }, | |||
| new Object[] { message1, WxConsts.XML_MSG_TEXT + "," }, | |||
| new Object[] { message2, WxConsts.EVT_CLICK + "," }, | |||
| new Object[] { message3, "KEY_1," }, | |||
| new Object[] { message4, "CONTENT_1," }, | |||
| @@ -19,7 +19,7 @@ import org.testng.annotations.Test; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxMenu; | |||
| import chanjarster.weixin.bean.WxMenu.WxMenuButton; | |||
| import chanjarster.weixin.bean.result.WxUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMediaUploadResult; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| import chanjarster.weixin.util.xml.XmlTransformer; | |||
| @@ -54,7 +54,7 @@ public class WxServiceTest { | |||
| public void sendCustomMessage() throws WxErrorException { | |||
| WxXmlConfigStorage configProvider = (WxXmlConfigStorage) wxService.wxConfigStorage; | |||
| WxCustomMessage message = new WxCustomMessage(); | |||
| message.setMsgtype(WxConsts.MSG_TEXT); | |||
| message.setMsgtype(WxConsts.CUSTOM_MSG_TEXT); | |||
| message.setTouser(configProvider.getOpenId()); | |||
| message.setContent("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>"); | |||
| @@ -79,7 +79,7 @@ public class WxServiceTest { | |||
| @Test(dependsOnMethods = { "testRefreshAccessToken" }, dataProvider="uploadMedia", enabled = true) | |||
| public void testUploadMedia1(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { | |||
| InputStream inputStream = ClassLoader.getSystemResourceAsStream(fileName); | |||
| WxUploadResult res = wxService.uploadMedia(mediaType, fileType, inputStream); | |||
| WxMediaUploadResult res = wxService.uploadMedia(mediaType, fileType, inputStream); | |||
| Assert.assertNotNull(res.getType()); | |||
| Assert.assertNotNull(res.getCreated_at()); | |||
| Assert.assertTrue(res.getMedia_id() != null || res.getThumb_media_id() != null); | |||
| @@ -12,7 +12,7 @@ public class WxCustomMessageTest { | |||
| public void testTextReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_TEXT); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_TEXT); | |||
| reply.setContent("sfsfdsdf"); | |||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||
| } | |||
| @@ -20,7 +20,7 @@ public class WxCustomMessageTest { | |||
| public void testImageReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_IMAGE); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_IMAGE); | |||
| reply.setMedia_id("MEDIA_ID"); | |||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||
| } | |||
| @@ -28,7 +28,7 @@ public class WxCustomMessageTest { | |||
| public void testVoiceReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_VOICE); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_VOICE); | |||
| reply.setMedia_id("MEDIA_ID"); | |||
| Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); | |||
| } | |||
| @@ -36,7 +36,7 @@ public class WxCustomMessageTest { | |||
| public void testVideoReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_VIDEO); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_VIDEO); | |||
| reply.setMedia_id("MEDIA_ID"); | |||
| reply.setThumb_media_id("MEDIA_ID"); | |||
| reply.setTitle("TITLE"); | |||
| @@ -47,7 +47,7 @@ public class WxCustomMessageTest { | |||
| public void testMusicReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_MUSIC); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_MUSIC); | |||
| reply.setThumb_media_id("MEDIA_ID"); | |||
| reply.setDescription("DESCRIPTION"); | |||
| reply.setTitle("TITLE"); | |||
| @@ -59,7 +59,7 @@ public class WxCustomMessageTest { | |||
| public void testNewsReply() { | |||
| WxCustomMessage reply = new WxCustomMessage(); | |||
| reply.setTouser("OPENID"); | |||
| reply.setMsgtype(WxConsts.MSG_NEWS); | |||
| reply.setMsgtype(WxConsts.CUSTOM_MSG_NEWS); | |||
| WxArticle article1 = new WxArticle(); | |||
| article1.setUrl("URL"); | |||
| @@ -39,7 +39,7 @@ public class WxXmlMessageTest { | |||
| Assert.assertEquals(wxMessage.getToUserName(), "toUser"); | |||
| Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); | |||
| Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||
| Assert.assertEquals(wxMessage.getMsgType(), WxConsts.MSG_TEXT); | |||
| Assert.assertEquals(wxMessage.getMsgType(), WxConsts.XML_MSG_TEXT); | |||
| Assert.assertEquals(wxMessage.getContent(), "this is a test"); | |||
| Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); | |||
| Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); | |||
| @@ -66,7 +66,7 @@ public class WxXmlMessageTest { | |||
| wxMessage.setToUserName("toUser"); | |||
| wxMessage.setFromUserName("fromUser"); | |||
| wxMessage.setCreateTime(new Long(1348831860l)); | |||
| wxMessage.setMsgType(WxConsts.MSG_TEXT); | |||
| wxMessage.setMsgType(WxConsts.XML_MSG_TEXT); | |||
| wxMessage.setContent("this is a test"); | |||
| wxMessage.setMsgId(new Long(1234567890123456l)); | |||
| wxMessage.setPicUrl("this is a url"); | |||