weixin-mp & pay

This commit is contained in:
jy.hu
2014-11-03 15:44:12 +08:00
parent c908581178
commit 45ce10141a
172 changed files with 5591 additions and 742 deletions
-30
View File
@@ -1,30 +0,0 @@
<assembly>
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>src/main</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.sh</include>
<include>*.bat</include>
</includes>
</fileSet>
<fileSet>
<directory>target/classes</directory>
<outputDirectory>/conf</outputDirectory>
<includes>
<include>*.properties</include>
<include>*.xml</include>
</includes>
</fileSet>
</fileSets>
</assembly>
@@ -1,785 +0,0 @@
package com.foxinmy.weixin4j.mp;
import java.io.File;
import java.io.IOException;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.model.WeixinAccountV2;
import com.foxinmy.weixin4j.model.WeixinAccountV3;
import com.foxinmy.weixin4j.mp.api.GroupApi;
import com.foxinmy.weixin4j.mp.api.HelperApi;
import com.foxinmy.weixin4j.mp.api.MassApi;
import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.api.MenuApi;
import com.foxinmy.weixin4j.mp.api.NotifyApi;
import com.foxinmy.weixin4j.mp.api.PayApi;
import com.foxinmy.weixin4j.mp.api.QrApi;
import com.foxinmy.weixin4j.mp.api.TmplApi;
import com.foxinmy.weixin4j.mp.api.UserApi;
import com.foxinmy.weixin4j.mp.model.Button;
import com.foxinmy.weixin4j.mp.model.CustomRecord;
import com.foxinmy.weixin4j.mp.model.Following;
import com.foxinmy.weixin4j.mp.model.Group;
import com.foxinmy.weixin4j.mp.model.MpArticle;
import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.User;
import com.foxinmy.weixin4j.mp.model.UserToken;
import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.msg.model.BaseMsg;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.mp.payment.v2.Order;
import com.foxinmy.weixin4j.mp.response.TemplateMessage;
import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 微信服务实现
*
* @className WeixinProxy
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class WeixinProxy {
private final MediaApi mediaApi;
private final NotifyApi notifyApi;
private final MassApi massApi;
private final UserApi userApi;
private final GroupApi groupApi;
private final MenuApi menuApi;
private final QrApi qrApi;
private final TmplApi tmplApi;
private final HelperApi helperApi;
private final PayApi payApi;
/**
* 默认采用文件存放Token跟配置文件中的appi信息
*/
public WeixinProxy() {
this(new FileTokenHolder());
}
/**
* 也可接受传递过来的appid跟appsecret
*
* @param appid
* @param appsecret
*/
public WeixinProxy(String appid, String appsecret) {
this(new FileTokenHolder(appid, appsecret));
}
public WeixinProxy(TokenHolder tokenApi) {
this.mediaApi = new MediaApi(tokenApi);
this.notifyApi = new NotifyApi(tokenApi);
this.massApi = new MassApi(tokenApi);
this.userApi = new UserApi(tokenApi);
this.groupApi = new GroupApi(tokenApi);
this.menuApi = new MenuApi(tokenApi);
this.qrApi = new QrApi(tokenApi);
this.tmplApi = new TmplApi(tokenApi);
this.helperApi = new HelperApi(tokenApi);
this.payApi = new PayApi(tokenApi);
}
/**
* 上传媒体文件
* <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常.
* </p>
*
* @param file
* 文件对象
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @throws IOException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MediaApi
*/
public String uploadMedia(File file, MediaType mediaType)
throws WeixinException, IOException {
return mediaApi.uploadMedia(file, mediaType);
}
/**
* 上传媒体文件
*
* @param bytes
* 媒体数据包
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(File, MediaType)}
*/
public String uploadMedia(String fileName, byte[] data, MediaType mediaType)
throws WeixinException {
return mediaApi.uploadMedia(fileName, data, mediaType);
}
/**
* 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param mediaType
* 媒体类型
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @throws IOException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MediaApi
*/
public File downloadMedia(String mediaId, MediaType mediaType)
throws WeixinException, IOException {
return mediaApi.downloadMedia(mediaId, mediaType);
}
/**
* 下载媒体文件
*
* @param mediaId
* @param mediaType
* @return 二进制数据包
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String, MediaType)}
*/
public byte[] downloadMediaData(String mediaId, MediaType mediaType)
throws WeixinException {
return mediaApi.downloadMediaData(mediaId, mediaType);
}
/**
* 发送客服消息(在48小时内不限制发送次数)
*
* @param notify
* 客服消息对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">发送客服消息</a>
* @see com.foxinmy.weixin4j.mp.msg.notify.TextNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ImageNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.MusicNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VideoNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VoiceNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/
public BaseResult sendNotify(BaseNotify notify) throws WeixinException {
return notifyApi.sendNotify(notify);
}
/**
* 发送图文消息
*
* @param touser
* 目标ID
* @param articles
* 图文列表
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.msg.model.Article
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/
public BaseResult sendNotify(String touser, List<Article> articles)
throws WeixinException {
return notifyApi.sendNotify(touser, articles);
}
/**
* 发送客服消息(不包含图文消息)
*
* @param touser
* 目标用户
* @param baseMsg
* 消息类型
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.msg.model.Text
* @see com.foxinmy.weixin4j.mp.msg.model.Image
* @see com.foxinmy.weixin4j.mp.msg.model.Music
* @see com.foxinmy.weixin4j.mp.msg.model.Video
* @see com.foxinmy.weixin4j.mp.msg.model.Voice
* @see com.foxinmy.weixin4j.mp.api.NotifyApi
*/
public BaseResult sendNotify(String touser, BaseMsg baseMsg)
throws WeixinException {
return notifyApi.sendNotify(touser, baseMsg);
}
/**
* 客服聊天记录
*
* @param openId
* 用户标识 可为空
* @param starttime
* 查询开始时间
* @param endtime
* 查询结束时间 每次查询不能跨日查询
* @param pagesize
* 每页大小 每页最多拉取1000条
* @param pageindex
* 查询第几页 从1开始
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.CustomRecord
* @see com.foxinmy.weixin4j.mp.api.NotifyApi
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%9C%8D%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95">查询客服聊天记录</a>
*/
public List<CustomRecord> getCustomRecord(String openId, long starttime,
long endtime, int pagesize, int pageindex) throws WeixinException {
return notifyApi.getCustomRecord(openId, starttime, endtime, pagesize,
pageindex);
}
/**
* 上传图文消息,一个图文消息支持1到10条图文
*
* @param articles
* 图片消息
* @return 媒体ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E7.B4.A0.E6.9D.90">上传图文消息</a>
* @see com.foxinmy.weixin4j.mp.model.MpArticle
* @see com.foxinmy.weixin4j.mp.api.MassApi
*/
public String uploadArticle(List<MpArticle> articles)
throws WeixinException {
return massApi.uploadArticle(articles);
}
/**
* 上传分组群发的视频素材
*
* @param mediaId
* 媒体文件中上传得到的Id
* @param title
* 标题 可为空
* @param desc
* 描述 可为空
* @return 上传后的ID
* @throws WeixinException
*
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
*/
public String uploadVideo(String mediaId, String title, String desc)
throws WeixinException {
return massApi.uploadVideo(mediaId, title, desc);
}
/**
* 分组群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param groupId
* 分组ID
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroupByOpenId(String)}
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()}
*/
public String massByGroup(String mediaId, MediaType mediaType,
String groupId) throws WeixinException {
return massApi.massByGroup(mediaId, mediaType, groupId);
}
/**
* 分组群发图文消息
*
* @param articles
* 图文消息列表
* @param groupId
* 分组ID
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.MpArticle
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(String,MediaType,String)}
*/
public String massArticleByGroup(List<MpArticle> articles, String groupId)
throws WeixinException {
return massApi.massArticleByGroup(articles, groupId);
}
/**
* openId群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param openIds
* openId列表
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject,String...)}
*/
public String massByOpenIds(String mediaId, MediaType mediaType,
String... openIds) throws WeixinException {
return massApi.massByOpenIds(mediaId, mediaType, openIds);
}
/**
* openId图文群发
*
* @param articles
* 图文消息列表
* @param openIds
* 目标ID列表
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.MpArticle
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(String,MediaType,String...)}
*/
public String massArticleByOpenIds(List<MpArticle> articles,
String... openIds) throws WeixinException {
return massApi.massArticleByOpenIds(articles, openIds);
}
/**
* 删除群发消息
* <p>
* 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片
* </p>
*
* @param msgid
* 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E5.88.A0.E9.99.A4.E7.BE.A4.E5.8F.91">删除群发</a>
* @see com.foxinmy.weixin4j.mp.api.MassApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#massByOpenIds(JSONObject, String...)
*/
public BaseResult deleteMassNews(String msgid) throws WeixinException {
return massApi.deleteMassNews(msgid);
}
/**
* 获取token
*
* @param code
* 用户授权后返回的code
* @return token对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token">获取用户token</a>
* @see com.foxinmy.weixin4j.mp.model.UserToken
* @see com.foxinmy.weixin4j.mp.api.UserApi
*/
public UserToken getAccessToken(String code) throws WeixinException {
return userApi.getAccessToken(code);
}
/**
* 获取用户信息
*
* @param token
* 授权票据
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E5.9B.9B.E6.AD.A5.EF.BC.9A.E6.8B.89.E5.8F.96.E7.94.A8.E6.88.B7.E4.BF.A1.E6.81.AF.28.E9.9C.80scope.E4.B8.BA_snsapi_userinfo.29">拉取用户信息</a>
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.mp.model.UserToken
* @see com.foxinmy.weixin4j.mp.api.UserApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#getAccessToken(String)}
*/
public User getUser(UserToken token) throws WeixinException {
return userApi.getUser(token);
}
/**
* 获取用户信息
* <p>
* 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的,对于不同公众号,
* 同一用户的openid不同),公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间
* </p>
*
* @param openId
* 用户对应的ID
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户信息</a>
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.mp.api.UserApi
*/
public User getUser(String openId) throws WeixinException {
return userApi.getUser(openId);
}
/**
* 获取用户一定数量(10000)的关注者列表
*
* @param nextOpenId
* 下一次拉取数据的openid
* @return 关注信息
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.mp.model.Following
* @see com.foxinmy.weixin4j.mp.api.UserApi
*/
public Following getFollowing(String nextOpenId) throws WeixinException {
return userApi.getFollowing(nextOpenId);
}
/**
* 获取用户全部的关注者列表
* <p>
* 当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求,
* 将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值
* </p>
*
* @return 用户对象集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.mp.model.Following
* @see com.foxinmy.weixin4j.mp.api.UserApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#getFollowing(String)}
*/
public List<User> getAllFollowing() throws WeixinException {
return userApi.getAllFollowing();
}
/**
* 设置用户备注名
*
* @param openId
* 用户ID
* @param remark
* 备注名
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a>
* @see com.foxinmy.weixin4j.mp.api.UserApi
*/
public BaseResult remarkUserName(String openId, String remark)
throws WeixinException {
return userApi.remarkUserName(openId, remark);
}
/**
* 创建分组
*
* @param name
* 组名称
* @return group对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E5.88.9B.E5.BB.BA.E5.88.86.E7.BB.84">创建分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.model.Group#toCreateJson()
* @see com.foxinmy.weixin4j.mp.api.GroupApi
*/
public Group createGroup(String name) throws WeixinException {
return groupApi.createGroup(name);
}
/**
* 查询所有分组
*
* @return 组集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E6.89.80.E6.9C.89.E5.88.86.E7.BB.84">查询所有分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.api.GroupApi
*/
public List<Group> getGroups() throws WeixinException {
return groupApi.getGroups();
}
/**
* 查询用户所在分组
*
* @param openId
* 用户对应的ID
* @return 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E7.94.A8.E6.88.B7.E6.89.80.E5.9C.A8.E5.88.86.E7.BB.84">查询用户所在分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.api.GroupApi
*/
public int getGroupByOpenId(String openId) throws WeixinException {
return groupApi.getGroupByOpenId(openId);
}
/**
* 修改分组名
*
* @param groupId
* 组ID
* @param name
* 组名称
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E4.BF.AE.E6.94.B9.E5.88.86.E7.BB.84.E5.90.8D">修改分组名</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson()
* @see com.foxinmy.weixin4j.mp.api.GroupApi
*/
public BaseResult modifyGroup(int groupId, String name)
throws WeixinException {
return groupApi.modifyGroup(groupId, name);
}
/**
* 移动分组
*
* @param openId
* 用户对应的ID
* @param groupId
* 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E7.A7.BB.E5.8A.A8.E7.94.A8.E6.88.B7.E5.88.86.E7.BB.84">移动分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.api.GroupApi
*/
public BaseResult moveGroup(String openId, int groupId)
throws WeixinException {
return groupApi.moveGroup(openId, groupId);
}
/**
* 自定义菜单
*
* @param btnList
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">创建自定义菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
* @see com.foxinmy.weixin4j.type.ButtonType
* @see com.foxinmy.weixin4j.mp.api.MenuApi
*/
public BaseResult createMenu(List<Button> btnList) throws WeixinException {
return menuApi.createMenu(btnList);
}
/**
* 查询菜单
*
* @return 菜单集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3">查询菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
* @see com.foxinmy.weixin4j.mp.api.MenuApi
*/
public List<Button> getMenu() throws WeixinException {
return menuApi.getMenu();
}
/**
* 删除菜单
*
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3">删除菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
* @see com.foxinmy.weixin4j.mp.api.MenuApi
*/
public BaseResult deleteMenu() throws WeixinException {
return menuApi.deleteMenu();
}
/**
* 生成带参数的二维码
*
* @param parameter
* @return byte数据包
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.QrApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(QRParameter parameter) throws WeixinException {
return qrApi.getQRData(parameter);
}
/**
* 生成带参数的二维码
*
* @param sceneId
* 场景值
* @param expireSeconds
* 过期秒数 如果小于等于0则 视为永久二维码
* @return byte数据包
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.QrApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(int sceneId, int expireSeconds)
throws WeixinException {
return qrApi.getQRData(sceneId, expireSeconds);
}
/**
* 生成带参数的二维码
* <p>
* 二维码分为临时跟永久两种,扫描时触发推送带参数事件
* </p>
*
* @param parameter
* 二维码参数
* @return 硬盘存储的文件对象
* @throws WeixinException
* @throws IOException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">二维码</a>
* @see com.foxinmy.weixin4j.mp.model.QRParameter
* @see com.foxinmy.weixin4j.mp.api.QrApi
*/
public File getQR(QRParameter parameter) throws WeixinException,
IOException {
return qrApi.getQR(parameter);
}
/**
* 发送模板消息
*
* @param message
* @return 发送结果
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息</a>
* @see com.foxinmy.weixin4j.mp.response.TemplateMessage
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
* @see com.foxinmy.weixin4j.mp.api.TmplApi
*/
public BaseResult sendTmplMessage(TemplateMessage tplMessage)
throws WeixinException {
return tmplApi.sendTmplMessage(tplMessage);
}
/**
* 长链接转短链接
*
* @param url
* @return 短链接
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%95%BF%E9%93%BE%E6%8E%A5%E8%BD%AC%E7%9F%AD%E9%93%BE%E6%8E%A5%E6%8E%A5%E5%8F%A3">长链接转短链接</a>
* @see com.foxinmy.weixin4j.mp.api.HelperApi
*/
public String getShorturl(String url) throws WeixinException {
return helperApi.getShorturl(url);
}
/**
* 发货通知
*
* @param weixinConfig
* V2版本
* @param transid
* 交易单号
* @param orderNo
* 订单号
* @param status
* 成功|失败
* @param statusMsg
* status为失败时携带的信息
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi
*/
public BaseResult deliverNotify(WeixinAccountV2 weixinConfig,
String transid, String orderNo, boolean status, String statusMsg)
throws WeixinException {
return payApi.deliverNotify(weixinConfig, transid, orderNo, status,
statusMsg);
}
/**
* 订单查询
*
* @param weixinConfig
* V2版本
* @param orderNo
* 订单号
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi
*/
public Order orderQuery(WeixinAccountV2 weixinConfig, String orderNo)
throws WeixinException {
return payApi.orderQuery(weixinConfig, orderNo);
}
/**
* 维权处理
*
* @param openId
* 用户ID
* @param feedbackId
* 维权单号
* @return
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
*/
public BaseResult updateFeedback(String openId, String feedbackId)
throws WeixinException {
return payApi.updateFeedback(openId, feedbackId);
}
/**
* native支付URL转短链接
*
* @param weixinConfig
* 商户配置
* @param url
* native支付URL
* @return 转换后的短链接
* @see com.foxinmy.weixin4j.mp.api.PayApi
* @throws WeixinException
*/
public String getShorturl(WeixinAccountV3 weixinConfig, String url)
throws WeixinException {
return payApi.getShorturl(weixinConfig, url);
}
@@ -1,52 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.response.BaseResponse;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.util.MessageUtil;
import com.foxinmy.weixin4j.xml.XStream;
/**
* 继承的类需实现execute(M inMessage)
*
* @className AbstractAction
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see
*/
public abstract class AbstractAction<M extends BaseMessage> implements
WeixinAction {
public abstract BaseResponse execute(M inMessage);
@SuppressWarnings("unchecked")
@Override
public String execute(String msg) throws DocumentException {
BaseMessage message = MessageUtil.xml2msg(msg);
if (message == null) {
Class<M> messageClass = getGenericType();
XStream xstream = XStream.get();
xstream.processAnnotations(messageClass);
xstream.alias("xml", messageClass);
return execute(xstream.fromXML(msg, messageClass)).toXml();
}
return execute((M) message).toXml();
}
@SuppressWarnings("unchecked")
private Class<M> getGenericType() {
Class<M> clazz = null;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = ((ParameterizedType) type);
Type[] args = ptype.getActualTypeArguments();
clazz = (Class<M>) args[0];
}
return clazz;
}
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.response.TextResponse;
import com.foxinmy.weixin4j.msg.BaseMessage;
/**
* 返回空白消息
*
* @className BlankAction
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see
*/
public class BlankAction<M extends BaseMessage> extends AbstractAction<M> {
@Override
public TextResponse execute(M inMessage) {
return new TextResponse("", inMessage);
}
}
@@ -1,22 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.response.TextResponse;
import com.foxinmy.weixin4j.msg.BaseMessage;
/**
* 显示调试信息
*
* @className DebugAction
* @author jy
* @date 2014年10月8日
* @since JDK 1.7
* @see
*/
public abstract class DebugAction<M extends BaseMessage> extends
AbstractAction<M> {
@Override
public TextResponse execute(M message) {
return new TextResponse(message.toString(), message);
}
}
@@ -1,19 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.ImageMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 图片消息响应
*
* @className ImageAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.ImageMessage
*/
@Action(msgType = MessageType.image)
public class ImageAction extends DebugAction<ImageMessage> {
}
@@ -1,19 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.LinkMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 链接消息响应
*
* @className LinkAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LinkMessage
*/
@Action(msgType = MessageType.link)
public class LinkAction extends DebugAction<LinkMessage> {
}
@@ -1,19 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.LocationMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 地理位置响应
*
* @className LocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.LocationMessage
*/
@Action(msgType = MessageType.location)
public class LocationAction extends DebugAction<LocationMessage> {
}
@@ -1 +0,0 @@
普通消息对应的Action
@@ -1,48 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import io.netty.handler.codec.http.QueryStringDecoder;
import java.util.List;
import java.util.Map;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.MessageUtil;
/**
* 用于校验消息安全性
*
* @className SignatureAction
* @author jy
* @date 2014年10月24日
* @since JDK 1.7
* @see
*/
@Action(msgType = MessageType.signature)
public class SignatureAction implements WeixinAction {
@Override
public String execute(String uri) throws DocumentException {
String[] paths = uri.split("\\?");
if (paths == null || paths.length < 2) {
return "";
}
QueryStringDecoder queryDecoder = new QueryStringDecoder(paths[1],
false);
Map<String, List<String>> parameters = queryDecoder.parameters();
String echostr = parameters.containsKey("echostr") ? parameters.get(
"echostr").get(0) : null;
String timestamp = parameters.containsKey("timestamp") ? parameters
.get("timestamp").get(0) : null;
String nonce = parameters.containsKey("nonce") ? parameters
.get("nonce").get(0) : null;
String signature = parameters.containsKey("signature") ? parameters
.get("signature").get(0) : null;
String token = ConfigUtil.getValue("app_token");
return MessageUtil.signature(token, echostr, timestamp, nonce,
signature);
}
}
@@ -1,24 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.mp.response.TextResponse;
import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 文字消息响应
*
* @className TextAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.TextMessage
*/
@Action(msgType = MessageType.text)
public class TextAction extends AbstractAction<TextMessage> {
@Override
public TextResponse execute(TextMessage inMessage) {
return new TextResponse("Hello World!", inMessage);
}
}
@@ -1,19 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.VideoMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 视频消息响应
*
* @className VideoAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VideoMessage
*/
@Action(msgType = MessageType.video)
public class VideoAction extends DebugAction<VideoMessage> {
}
@@ -1,19 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.VoiceMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 语音消息响应
*
* @className VoiceAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.VoiceMessage
*/
@Action(msgType = MessageType.voice)
public class VoiceAction extends DebugAction<VoiceMessage> {
}
@@ -1,18 +0,0 @@
package com.foxinmy.weixin4j.mp.action;
import org.dom4j.DocumentException;
/**
* 消息处理接口
*
* @className Action
* @author jy.hu
* @date 2014年10月2日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.action.AbstractAction
* @see com.foxinmy.weixin4j.mp.action.BlankAction
* @see com.foxinmy.weixin4j.mp.action.DebugAction
*/
public interface WeixinAction {
public String execute(String msg) throws DocumentException;
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.LocationEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 上报地理位置后触发
*
* @className LocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.location })
public class LocationAction extends DebugAction<LocationEventMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.MassEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 群发消息发送动作完成后触发
*
* @className MassSendAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.MassEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.massendjobfinish })
public class MassSendAction extends DebugAction<MassEventMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 菜单点击click事件时触发
*
* @className MenuClickAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.click })
public class MenuClickAction extends DebugAction<MenuEventMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 菜单发送地理位置时触发
*
* @className MenuLocationAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.location_select })
public class MenuLocationAction extends DebugAction<MenuLocationEventMessage> {
}
@@ -1,23 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 菜单发送图片时触发
*
* @className MenuPhotoAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage
*/
@Action(msgType = MessageType.event, eventType = {
EventType.pic_photo_or_album, EventType.pic_sysphoto,
EventType.pic_weixin })
public class MenuPhotoAction extends DebugAction<MenuPhotoEventMessage> {
}
@@ -1,22 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 菜单扫描时触发
*
* @className MenuScanAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.scancode_push,
EventType.scancode_waitmsg })
public class MenuScanAction extends DebugAction<MenuScanEventMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 菜单点击view事件时触发
*
* @className MenuViewAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.view })
public class MenuViewAction extends DebugAction<MenuEventMessage> {
}
@@ -1 +0,0 @@
事件消息对应的Action
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.ScanEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 扫描事件时触发
*
* @className ScanAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.scan })
public class ScanAction extends DebugAction<ScanEventMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 关注时触发
*
* @className SubscribeAction
* @author jy
* @date 2014年10月9日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.subscribe })
public class SubscribeAction extends DebugAction<ScribeEventMessage> {
}
@@ -1,22 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 模板消息发送动作完成时触发
*
* @className TemplateSendAction
* @author jy
* @date 2014年10月10日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.templatesendjobfinish })
public class TemplateSendAction extends
DebugAction<TemplatesendjobfinishMessage> {
}
@@ -1,21 +0,0 @@
package com.foxinmy.weixin4j.mp.action.event;
import com.foxinmy.weixin4j.mp.action.DebugAction;
import com.foxinmy.weixin4j.mp.mapping.Action;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 取消关注时触发
*
* @className UnsubscribeAction
* @author jy
* @date 2014年10月10日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
*/
@Action(msgType = MessageType.event, eventType = { EventType.unsubscribe })
public class UnsubscribeAction extends DebugAction<ScribeEventMessage> {
}
@@ -1,44 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.xml.XStream;
/**
*
* @className BaseApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class BaseApi {
protected final HttpRequest request = new HttpRequest();
protected final XStream xStream = XStream.get();
protected final Charset utf8 = StandardCharsets.UTF_8;
private final static ResourceBundle weixinBundle;
static {
weixinBundle = ResourceBundle
.getBundle("com/foxinmy/weixin4j/mp/api/weixin");
}
protected String getRequestUri(String key) {
String url = weixinBundle.getString(key);
Pattern p = Pattern.compile("(\\{[^\\}]*\\})");
Matcher m = p.matcher(url);
StringBuffer sb = new StringBuffer();
String sub = null;
while (m.find()) {
sub = m.group();
m.appendReplacement(sb,
getRequestUri(sub.substring(1, sub.length() - 1)));
}
m.appendTail(sb);
return sb.toString();
}
}
@@ -1,141 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Group;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 分组相关API
*
* @className GroupApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%
* BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3">分组接口</a>
* @see com.foxinmy.weixin4j.mp.model.Group
*/
public class GroupApi extends BaseApi {
private final TokenHolder tokenApi;
public GroupApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 创建分组
*
* @param name
* 组名称
* @return group对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E5.88.9B.E5.BB.BA.E5.88.86.E7.BB.84">创建分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.model.Group#toCreateJson()
*/
public Group createGroup(String name) throws WeixinException {
String group_create_uri = getRequestUri("group_create_uri");
Token token = tokenApi.getToken();
Group group = new Group(name);
Response response = request.post(
String.format(group_create_uri, token.getAccessToken()),
group.toCreateJson());
return response.getAsJson().getObject("group", Group.class);
}
/**
* 查询所有分组
*
* @return 组集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E6.89.80.E6.9C.89.E5.88.86.E7.BB.84">查询所有分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
*/
public List<Group> getGroups() throws WeixinException {
String group_get_uri = getRequestUri("group_get_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(group_get_uri,
token.getAccessToken()));
return JSON.parseArray(response.getAsJson().getString("groups"),
Group.class);
}
/**
* 查询用户所在分组
*
* @param openId
* 用户对应的ID
* @return 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E7.94.A8.E6.88.B7.E6.89.80.E5.9C.A8.E5.88.86.E7.BB.84">查询用户所在分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
*/
public int getGroupByOpenId(String openId) throws WeixinException {
String group_getid_uri = getRequestUri("group_getid_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(group_getid_uri, token.getAccessToken()),
String.format("{\"openid\":\"%s\"}", openId));
return response.getAsJson().getIntValue("groupid");
}
/**
* 修改分组名
*
* @param groupId
* 组ID
* @param name
* 组名称
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E4.BF.AE.E6.94.B9.E5.88.86.E7.BB.84.E5.90.8D">修改分组名</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.mp.model.Group#toModifyJson()
*/
public BaseResult modifyGroup(int groupId, String name)
throws WeixinException {
String group_modify_uri = getRequestUri("group_modify_uri");
Token token = tokenApi.getToken();
Group group = new Group(groupId, name);
Response response = request.post(
String.format(group_modify_uri, token.getAccessToken()),
group.toModifyJson());
return response.getAsResult();
}
/**
* 移动分组
*
* @param openId
* 用户对应的ID
* @param groupId
* 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E7.A7.BB.E5.8A.A8.E7.94.A8.E6.88.B7.E5.88.86.E7.BB.84">移动分组</a>
* @see com.foxinmy.weixin4j.mp.model.Group
*/
public BaseResult moveGroup(String openId, int groupId)
throws WeixinException {
String group_move_uri = getRequestUri("group_move_uri");
Token token = tokenApi.getToken();
Response response = request.post(String.format(group_move_uri,
token.getAccessToken()), String.format(
"{\"openid\":\"%s\",\"to_groupid\":%d}", openId, groupId));
return response.getAsResult();
}
}
@@ -1,47 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 辅助相关API
*
* @className HelperApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see
*/
public class HelperApi extends BaseApi {
private final TokenHolder tokenApi;
public HelperApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 长链接转短链接
*
* @param url
* @return 短链接
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%95%BF%E9%93%BE%E6%8E%A5%E8%BD%AC%E7%9F%AD%E9%93%BE%E6%8E%A5%E6%8E%A5%E5%8F%A3">长链接转短链接</a>
*/
public String getShorturl(String url) throws WeixinException {
String shorturl_uri = getRequestUri("shorturl_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("action", "long2short");
obj.put("long_url", url);
Response response = request.post(
String.format(shorturl_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("short_url");
}
}
@@ -1,269 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.io.File;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.MpArticle;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 群发相关API
*
* @className MassApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">群发接口</a>
* @see com.foxinmy.weixin4j.mp.model.MpArticle
*/
public class MassApi extends BaseApi {
private final TokenHolder tokenApi;
public MassApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 上传图文消息,一个图文消息支持1到10条图文
*
* @param articles
* 图片消息
* @return 媒体ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E7.B4.A0.E6.9D.90">上传图文消息</a>
* @see com.foxinmy.weixin4j.mp.model.MpArticle
*/
public String uploadArticle(List<MpArticle> articles)
throws WeixinException {
String article_upload_uri = getRequestUri("article_upload_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("articles", articles);
Response response = request.post(
String.format(article_upload_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("media_id");
}
/**
* 上传分组群发的视频素材
*
* @param mediaId
* 媒体文件中上传得到的Id
* @param title
* 标题 可为空
* @param desc
* 描述 可为空
* @return 上传后的ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
*/
public String uploadVideo(String mediaId, String title, String desc)
throws WeixinException {
String video_upload_uri = getRequestUri("video_upload_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("media_id", mediaId);
obj.put("title", title);
obj.put("description", desc);
Response response = request.post(
String.format(video_upload_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("media_id");
}
/**
* 分组群发
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核、服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @param jsonPara
* json格式的参数
* @param groupId
* 分组ID
* @return 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91">分组群发</a>
* @see com.foxinmy.weixin4j.mp.model.Group
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroupByOpenId(String)}
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()}
*/
private String massByGroup(JSONObject jsonPara, String groupId)
throws WeixinException {
String mass_group_uri = getRequestUri("mass_group_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_group_uri, token.getAccessToken()),
jsonPara.toJSONString());
return response.getAsJson().getString("msg_id");
}
/**
* openId群发
*
* @param jsonPara
* json格式的参数
* @param openIds
* 目标ID列表
* @return 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E6.A0.B9.E6.8D.AEOpenID.E5.88.97.E8.A1.A8.E7.BE.A4.E5.8F.91">openId群发</a>
* @see com.foxinmy.weixin4j.mp.model.User
*/
private String massByOpenIds(JSONObject jsonPara, String... openIds)
throws WeixinException {
String mass_openid_uri = getRequestUri("mass_openid_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_openid_uri, token.getAccessToken()),
jsonPara.toJSONString());
return response.getAsJson().getString("msg_id");
}
/**
* 分组群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param groupId
* 分组ID
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.Group
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroupByOpenId(String)}
* @see {@link com.foxinmy.weixin4j.mp.api.GroupApi#getGroups()}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroup(JSONObject,String)}
*/
public String massByGroup(String mediaId, MediaType mediaType,
String groupId) throws WeixinException {
JSONObject jsonPara = new JSONObject();
jsonPara.put("filter", new JSONObject().put("group_id", groupId));
jsonPara.put(mediaType.name(), new JSONObject().put(
mediaType == MediaType.text ? "content" : "media_id", mediaId));
jsonPara.put("msgtype", mediaType.name());
return massByGroup(jsonPara, groupId);
}
/**
* 分组群发图文消息
*
* @param articles
* 图文消息列表
* @param groupId
* 分组ID
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.MpArticle
* @see com.foxinmy.weixin4j.mp.model.Group
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroup(String,MediaType,String)}
*/
public String massArticleByGroup(List<MpArticle> articles, String groupId)
throws WeixinException {
String mediaId = uploadArticle(articles);
return massByGroup(mediaId, MediaType.mpnews, groupId);
}
/**
* openId群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param openIds
* openId列表
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(JSONObject,String...)}
*/
public String massByOpenIds(String mediaId, MediaType mediaType,
String... openIds) throws WeixinException {
JSONObject jsonPara = new JSONObject();
jsonPara.put("touser", openIds);
jsonPara.put(mediaType.name(), new JSONObject().put(
mediaType == MediaType.text ? "content" : "media_id", mediaId));
jsonPara.put("msgtype", mediaType.name());
return massByOpenIds(jsonPara, openIds);
}
/**
* openId图文群发
*
* @param articles
* 图文消息列表
* @param openIds
* 目标ID列表
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.MpArticle
* @see com.foxinmy.weixin4j.mp.model.User
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(String,MediaType,String...)}
*/
public String massArticleByOpenIds(List<MpArticle> articles,
String... openIds) throws WeixinException {
String mediaId = uploadArticle(articles);
return massByOpenIds(mediaId, MediaType.mpnews, openIds);
}
/**
* 删除群发消息
* <p>
* 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片
* </p>
*
* @param msgid
* 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E5.88.A0.E9.99.A4.E7.BE.A4.E5.8F.91">删除群发</a>
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massByOpenIds(JSONObject, String...)
*/
public BaseResult deleteMassNews(String msgid) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msgid", msgid);
String mass_delete_uri = getRequestUri("mass_delete_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_delete_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
@@ -1,141 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.http.entity.mime.content.ByteArrayBody;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.PartParameter;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.IOUtil;
/**
* 媒体相关API
*
* @className MediaApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传多媒体文件</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public class MediaApi extends BaseApi {
private final TokenHolder tokenApi;
public MediaApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 上传媒体文件
* <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常.
* </p>
*
* @param file
* 文件对象
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @throws IOException
* @throws
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public String uploadMedia(File file, MediaType mediaType)
throws WeixinException, IOException {
byte[] datas = IOUtil.toByteArray(new FileInputStream(file));
return uploadMedia(file.getName(), datas, mediaType);
}
/**
* 上传媒体文件
*
* @param bytes
* 媒体数据包
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)}
*/
public String uploadMedia(String fileName, byte[] bytes, MediaType mediaType)
throws WeixinException {
Token token = tokenApi.getToken();
String file_upload_uri = getRequestUri("file_upload_uri");
Response response = request.post(String.format(file_upload_uri,
token.getAccessToken(), mediaType.name()), new PartParameter(
"media", new ByteArrayBody(bytes, fileName)));
return response.getAsJson().getString("media_id");
}
/**
* 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param mediaType
* 媒体类型
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @throws IOException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public File downloadMedia(String mediaId, MediaType mediaType)
throws WeixinException, IOException {
String media_path = getRequestUri("media_path");
byte[] datas = downloadMediaData(mediaId, mediaType);
String filename = mediaId + "." + mediaType.getFormatType();
File file = new File(media_path + File.separator + filename);
if (file.exists()) {
return file;
}
FileOutputStream out = null;
try {
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
out.write(datas);
out.close();
return file;
}
/**
* 下载媒体文件
*
* @param mediaId
* @param mediaType
* @return 二进制数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String, MediaType)}
*/
public byte[] downloadMediaData(String mediaId, MediaType mediaType)
throws WeixinException {
Token token = tokenApi.getToken();
String file_download_uri = getRequestUri("file_download_uri");
Response response = request.get(String.format(file_download_uri,
token.getAccessToken(), mediaId));
return response.getBody();
}
}
@@ -1,88 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Button;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 菜单相关API
*
* @className MenuApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.model.Button
*/
public class MenuApi extends BaseApi {
private final TokenHolder tokenApi;
public MenuApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 自定义菜单
*
* @param btnList
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">创建自定义菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
*/
public BaseResult createMenu(List<Button> btnList) throws WeixinException {
String menu_create_uri = getRequestUri("menu_create_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("button", btnList);
Response response = request.post(
String.format(menu_create_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 查询菜单
*
* @return 菜单集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3">查询菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
*/
public List<Button> getMenu() throws WeixinException {
String menu_get_uri = getRequestUri("menu_get_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(menu_get_uri,
token.getAccessToken()));
String text = response.getAsJson().getJSONObject("menu")
.getString("button");
return JSON.parseArray(text, Button.class);
}
/**
* 删除菜单
*
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3">删除菜单</a>
* @see com.foxinmy.weixin4j.mp.model.Button
*/
public BaseResult deleteMenu() throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(menu_delete_uri,
token.getAccessToken()));
return response.getAsResult();
}
}
@@ -1,165 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.CustomRecord;
import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.msg.model.BaseMsg;
import com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 客服相关API
*
* @className NotifyApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">客服消息</a>
* @see com.foxinmy.weixin4j.mp.msg.notify.TextNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ImageNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.MusicNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VideoNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VoiceNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
*/
public class NotifyApi extends BaseApi {
private final TokenHolder tokenApi;
public NotifyApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 发送客服消息
*
* @param jsonPara
* @return
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">发送客服消息</a>
*/
private BaseResult sendNotify(String jsonPara) throws WeixinException {
String custom_notify_uri = getRequestUri("custom_notify_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(custom_notify_uri, token.getAccessToken()),
jsonPara);
return response.getAsResult();
}
/**
* 发送客服消息(在48小时内不限制发送次数)
*
* @param notify
* 客服消息对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">发送客服消息</a>
* @see com.foxinmy.weixin4j.mp.msg.notify.TextNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ImageNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.MusicNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VideoNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.VoiceNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
* @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)}
*/
public BaseResult sendNotify(BaseNotify notify) throws WeixinException {
return sendNotify(notify.toJson());
}
/**
* 发送图文消息
*
* @param touser
* 目标ID
* @param articles
* 图文列表
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.msg.model.Article
* @see com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify
*/
public BaseResult sendNotify(String touser, List<Article> articles)
throws WeixinException {
ArticleNotify notify = new ArticleNotify(touser);
notify.pushAll(articles);
return sendNotify(notify);
}
/**
* 发送客服消息(不包含图文消息)
*
* @param touser
* 目标用户
* @param baseMsg
* 消息类型
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.msg.model.Text
* @see com.foxinmy.weixin4j.mp.msg.model.Image
* @see com.foxinmy.weixin4j.mp.msg.model.Music
* @see com.foxinmy.weixin4j.mp.msg.model.Video
* @see com.foxinmy.weixin4j.mp.msg.model.Voice
* @see {@link com.foxinmy.weixin4j.mp.msg.model.BaseMsg#toNotifyJson()}
* @see {@link com.foxinmy.weixin4j.mp.api.NotifyApi#sendNotify(String)}
*/
public BaseResult sendNotify(String touser, BaseMsg baseMsg)
throws WeixinException {
StringBuilder jsonPara = new StringBuilder();
String mediaType = baseMsg.getMediaType().name();
jsonPara.append("{");
jsonPara.append("\"touser\":\"").append(touser).append("\",");
jsonPara.append("\"msgtype\":\"").append(mediaType).append("\",");
jsonPara.append("\"").append(mediaType).append("\":");
jsonPara.append(baseMsg.toNotifyJson()).append("}");
return sendNotify(jsonPara.toString());
}
/**
* 客服聊天记录
*
* @param openId
* 用户标识 可为空
* @param starttime
* 查询开始时间
* @param endtime
* 查询结束时间 每次查询不能跨日查询
* @param pagesize
* 每页大小 每页最多拉取1000条
* @param pageindex
* 查询第几页 从1开始
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.CustomRecord
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%9C%8D%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95">查询客服聊天记录</a>
*/
public List<CustomRecord> getCustomRecord(String openId, long starttime,
long endtime, int pagesize, int pageindex) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("openId", openId == null ? "" : openId);
obj.put("starttime", starttime);
obj.put("endtime", endtime);
obj.put("pagesize", pagesize > 1000 ? 1000 : pagesize);
obj.put("pageindex", pageindex);
String custom_record_uri = getRequestUri("custom_record_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(custom_record_uri, token.getAccessToken()),
obj.toJSONString());
String text = response.getAsJson().getString("recordlist");
return JSON.parseArray(text, CustomRecord.class);
}
}
@@ -1,112 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRParameter.QRType;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 二维码相关API
*
* @className QrApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">二维码支持</a>
*/
public class QrApi extends BaseApi {
private final TokenHolder tokenApi;
public QrApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 生成带参数的二维码
*
* @param parameter
* @return byte数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(QRParameter parameter) throws WeixinException {
Token token = tokenApi.getToken();
String qr_uri = getRequestUri("qr_ticket_uri");
Response response = request.post(
String.format(qr_uri, token.getAccessToken()),
parameter.toJson());
String ticket = response.getAsJson().getString("ticket");
qr_uri = getRequestUri("qr_image_uri");
response = request.get(String.format(qr_uri, ticket));
return response.getBody();
}
/**
* 生成带参数的二维码
*
* @param sceneId
* 场景值
* @param expireSeconds
* 过期秒数 如果小于等于0则 视为永久二维码
* @return byte数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(int sceneId, int expireSeconds)
throws WeixinException {
QRParameter parameter = new QRParameter(sceneId, QRType.TEMPORARY,
expireSeconds);
if (expireSeconds <= 0) {
parameter.setQrType(QRType.PERMANENCE);
}
return getQRData(parameter);
}
/**
* 生成带参数的二维码
* <p>
* 二维码分为临时跟永久两种,扫描时触发推送带参数事件
* </p>
*
* @param parameter
* 二维码参数
* @return 硬盘存储的文件对象
* @throws WeixinException
* @throws FileNotFoundException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">二维码</a>
* @see com.foxinmy.weixin4j.mp.model.QRParameter
*/
public File getQR(QRParameter parameter) throws WeixinException,
IOException {
String qr_path = getRequestUri("qr_path");
String filename = String.format("%s_%d_%d.jpg", parameter.getQrType()
.name(), parameter.getSceneId(), parameter.getExpireSeconds());
File file = new File(qr_path + File.separator + filename);
if (parameter.getQrType() == QRType.PERMANENCE && file.exists()) {
return file;
}
byte[] datas = getQRData(parameter);
FileOutputStream out = null;
try {
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
out.write(datas);
out.close();
return file;
}
}
@@ -1 +0,0 @@
API的实现
@@ -1,48 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.response.TemplateMessage;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 模板消息相关API
*
* @className TemplApi
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public class TmplApi extends BaseApi {
private final TokenHolder tokenApi;
public TmplApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 发送模板消息
*
* @param message
* @return 发送结果
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息</a>
* @see com.foxinmy.weixin4j.mp.response.TemplateMessage
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
public BaseResult sendTmplMessage(TemplateMessage tplMessage)
throws WeixinException {
Token token = tokenApi.getToken();
String template_send_uri = getRequestUri("template_send_uri");
Response response = request.post(
String.format(template_send_uri, token.getAccessToken()),
tplMessage.toJson());
return response.getAsResult();
}
}
@@ -1,181 +0,0 @@
package com.foxinmy.weixin4j.mp.api;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.Following;
import com.foxinmy.weixin4j.mp.model.User;
import com.foxinmy.weixin4j.mp.model.UserToken;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 用户相关API
*
* @className UserApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.model.User
*/
public class UserApi extends BaseApi {
private final TokenHolder tokenApi;
public UserApi(TokenHolder tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 获取token
*
* @param code
* 用户授权后返回的code
* @return token对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token">获取用户token</a>
* @see com.foxinmy.weixin4j.mp.model.UserToken
*/
public UserToken getAccessToken(String code) throws WeixinException {
String user_token_uri = getRequestUri("sns_user_token_uri");
Response response = request.get(String.format(user_token_uri, code));
return response.getAsObject(UserToken.class);
}
/**
* 获取用户信息
*
* @param token
* 授权票据
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E5.9B.9B.E6.AD.A5.EF.BC.9A.E6.8B.89.E5.8F.96.E7.94.A8.E6.88.B7.E4.BF.A1.E6.81.AF.28.E9.9C.80scope.E4.B8.BA_snsapi_userinfo.29">拉取用户信息</a>
* @see com.foxinmy.weixin4j.mp.model.User
* @see com.foxinmy.weixin4j.mp.model.UserToken
* {@link com.foxinmy.weixin4j.mp.api.UserApi#getAccessToken(String)}
*/
public User getUser(UserToken token) throws WeixinException {
String user_info_uri = getRequestUri("sns_user_info_uri");
Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), token.getOpenid()));
return response.getAsObject(User.class);
}
/**
* 获取用户信息
* <p>
* 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的,对于不同公众号,
* 同一用户的openid不同),公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间
* </p>
*
* @param openId
* 用户对应的ID
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户信息</a>
* @see com.foxinmy.weixin4j.mp.model.User
*/
public User getUser(String openId) throws WeixinException {
String user_info_uri = getRequestUri("api_user_info_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), openId));
return response.getAsObject(User.class);
}
/**
* 获取用户一定数量(10000)的关注者列表
*
* @param nextOpenId
* 下一次拉取数据的openid
* @return 关注信息
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.mp.model.Following
*/
public Following getFollowing(String nextOpenId) throws WeixinException {
String fllowing_uri = getRequestUri("following_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(fllowing_uri,
token.getAccessToken(), nextOpenId == null ? "" : nextOpenId));
Following following = response.getAsObject(Following.class);
if (following.getCount() > 0) {
List<String> openIds = JSON.parseArray(following.getDataJson()
.getString("openid"), String.class);
List<User> userList = new ArrayList<User>();
for (String openId : openIds) {
userList.add(getUser(openId));
}
following.setUserList(userList);
}
return following;
}
/**
* 获取用户全部的关注者列表
* <p>
* 当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求,
* 将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值
* </p>
*
* @return 用户对象集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.mp.model.Following
* @see com.foxinmy.weixin4j.mp.api.UserApi#getFollowing(String)
*/
public List<User> getAllFollowing() throws WeixinException {
List<User> userList = new ArrayList<User>();
String nextOpenId = null;
Following f = null;
for (;;) {
f = getFollowing(nextOpenId);
if (f.getCount() == 0) {
break;
}
userList.addAll(f.getUserList());
nextOpenId = f.getNextOpenId();
}
return userList;
}
/**
* 设置用户备注名
*
* @param openId
* 用户ID
* @param remark
* 备注名
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a>
*/
public BaseResult remarkUserName(String openId, String remark)
throws WeixinException {
String updateremark_uri = getRequestUri("updateremark_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("openid", openId);
obj.put("remark", remark);
Response response = request.post(
String.format(updateremark_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
}
@@ -1,73 +0,0 @@
# ----------------------------------------------------------------------------
# api\u9996\u9875
# http://mp.weixin.qq.com/wiki/index.php
# \u63a5\u53e3\u8c03\u7528\u8bf4\u660e
# http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%8F%A3%E9%A2%91%E7%8E%87%E9%99%90%E5%88%B6%E8%AF%B4%E6%98%8E
# ----------------------------------------------------------------------------
api_base_url=https://api.weixin.qq.com/cgi-bin
mp_base_url=https://mp.weixin.qq.com/cgi-bin
file_base_url=http://file.api.weixin.qq.com/cgi-bin
mch_base_url=https://api.mch.weixin.qq.com
# \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f
user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid={app_id}&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect
sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid={app_id}&secret={app_secret}&code=%s&grant_type=authorization_code
sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN
# \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f
api_user_info_uri={api_base_url}/user/info?access_token=%s&openid=%s&lang=zh_CN
# \u83b7\u53d6token
api_token_uri={api_base_url}/token?grant_type=client_credential&appid=%s&secret=%s
# \u83b7\u53d6\u4e8c\u7ef4\u7801
qr_ticket_uri={api_base_url}/qrcode/create?access_token=%s
qr_image_uri={mp_base_url}/showqrcode?ticket=%s
# \u4e0a\u4f20\u5a92\u4f53\u6587\u4ef6
file_upload_uri={file_base_url}/media/upload?access_token=%s&type=%s
# \u4e0b\u8f7d\u5a92\u4f53\u6587\u4ef6
file_download_uri={file_base_url}/media/get?access_token=%s&media_id=%s
# \u53d1\u9001\u5ba2\u670d\u6d88\u606f
custom_notify_uri={api_base_url}/message/custom/send?access_token=%s
# \u521b\u5efa\u5206\u7ec4
group_create_uri={api_base_url}/groups/create?access_token=%s
# \u67e5\u8be2\u5206\u7ec4
group_get_uri={api_base_url}/groups/get?access_token=%s
# \u67e5\u8be2\u7528\u6237\u6240\u5728\u5206\u7ec4
group_getid_uri={api_base_url}/groups/getid?access_token=%s
# \u4fee\u6539\u5206\u7ec4\u540d
group_modify_uri={api_base_url}/groups/update?access_token=%s
# \u79fb\u52a8\u7528\u6237\u5206\u7ec4
group_move_uri={api_base_url}/groups/members/update?access_token=%s
# \u83b7\u53d6\u5173\u6ce8\u7740
following_uri={api_base_url}/user/get?access_token=%s&next_openid=%s
# \u81ea\u5b9a\u4e49\u83dc\u5355
menu_create_uri={api_base_url}/menu/create?access_token=%s
# \u67e5\u8be2\u83dc\u5355
menu_get_uri={api_base_url}/menu/get?access_token=%s
# \u5220\u9664\u83dc\u5355
menu_delete_uri={api_base_url}/menu/delete?access_token=%s
# \u4e0a\u4f20\u56fe\u6587
article_upload_uri={api_base_url}/media/uploadnews?access_token=%s
# \u4e0a\u4f20\u89c6\u9891
video_upload_uri={file_base_url}/media/uploadvideo?access_token=%s
# \u5206\u7ec4\u7fa4\u53d1
mass_group_uri={api_base_url}/message/mass/sendall?access_token=%s
# openId\u7fa4\u53d1
mass_openid_uri={api_base_url}/message/mass/send?access_token=%s
# \u5220\u9664\u7fa4\u53d1
mass_delete_uri={api_base_url}/message/mass/delete?access_token=%s
# \u5ba2\u670d\u804a\u5929\u8bb0\u5f55
custom_record_uri={api_base_url}/customservice/getrecord?access_token=%s
# \u957f\u94fe\u63a5\u8f6c\u77ed\u94fe\u63a5
shorturl_uri={api_base_url}/shorturl?access_token=%s
p_shorturl_uri={mch_base_url}/tools/shorturl
# \u8bbe\u7f6e\u5907\u6ce8\u540d
updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s
# \u6a21\u677f\u6d88\u606f
template_send_uri={api_base_url}/message/template/send?access_token=%s
# \u67e5\u8be2\u8ba2\u5355
orderquery_uri={api_base_url}/pay/orderquery?access_token=%s
# \u53d1\u8d27\u901a\u77e5
delivernotify_uri={api_base_url}/pay/delivernotify?access_token=%s
# \u7ef4\u6743\u5904\u7406
payfeedback_update_uri={api_base_url}/payfeedback/update?access_token=%s&openid=%s&feedbackid=%s
@@ -1,29 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 获取默认的Mapping Key 如text,event_click
*
* @className AbstractActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public abstract class AbstractActionMapping implements ActionMapping {
protected String getMappingKey(String xmlMsg) throws DocumentException {
Document doc = DocumentHelper.parseText(xmlMsg);
String msgType = doc.selectSingleNode("/xml/MsgType").getStringValue();
if (msgType.equalsIgnoreCase(MessageType.event.name())) {
msgType += "_"
+ doc.selectSingleNode("/xml/Event").getStringValue();
}
return msgType.toLowerCase();
}
}
@@ -1,26 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
/**
* 标注
* @className Action
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see
*/
public @interface Action {
MessageType msgType();
EventType[] eventType() default {};
}
@@ -1,18 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
/**
* 可扩展的Mapping接口
*
* @className ActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see
*/
public interface ActionMapping {
public WeixinAction getAction(String xmlMsg) throws DocumentException;
}
@@ -1,59 +0,0 @@
package com.foxinmy.weixin4j.mp.mapping;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.dom4j.DocumentException;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.ClassUtil;
/**
* 注解实现的Mapping
*
* @className AnnotationActionMapping
* @author jy
* @date 2014年10月28日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.mapping.Action
*/
public class AnnotationActionMapping extends AbstractActionMapping {
private final Map<String, WeixinAction> actionMap;
public AnnotationActionMapping() {
actionMap = new HashMap<String, WeixinAction>();
Set<Class<?>> weixinActions = ClassUtil.getClasses(WeixinAction.class
.getPackage());
for (Class<?> clazz : weixinActions) {
Action action = clazz.getAnnotation(Action.class);
if (action == null) {
continue;
}
WeixinAction weixinAction = null;
try {
weixinAction = (WeixinAction) clazz.newInstance();
} catch (Exception e) {
continue;
}
MessageType msgType = action.msgType();
EventType[] eventTypes = action.eventType();
if (eventTypes != null && eventTypes.length > 0) {
for (EventType e : eventTypes) {
actionMap.put(
(msgType.name() + "_" + e.name()).toLowerCase(),
weixinAction);
}
continue;
}
actionMap.put(msgType.name().toLowerCase(), weixinAction);
}
}
public WeixinAction getAction(String xmlMsg) throws DocumentException {
String key = getMappingKey(xmlMsg);
return actionMap.get(key);
}
}
@@ -1,98 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
/**
* 网页授权结果
*
* @className AuthResult
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">网页授权获取用户基本资料</a>
*/
public class AuthResult implements Serializable {
private static final long serialVersionUID = 654855396163854805L;
/**
* 网页授权获取code
*
* @className AuthScope
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code">获取code</a>
*/
public enum AuthScope {
BASE("snsapi_base"), USERINFO("snsapi_userinfo");
private String name;
AuthScope(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public enum AuthCode {
OK, FAILED, REDIRECT
}
private AuthCode authCode;
private String location;
private UserToken accessToken;
public AuthResult(String location) {
this.location = location;
this.authCode = AuthCode.REDIRECT;
}
public AuthResult(UserToken accessToken) {
this.authCode = AuthCode.OK;
this.accessToken = accessToken;
}
public AuthResult(String location, AuthCode authCode) {
this.location = location;
this.authCode = authCode;
}
public AuthCode getAuthCode() {
return authCode;
}
public void setAuthCode(AuthCode authCode) {
this.authCode = authCode;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public UserToken getAccessToken() {
return accessToken;
}
public void setAccessToken(UserToken accessToken) {
this.accessToken = accessToken;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[AuthResult authCode=").append(authCode);
sb.append(", location=").append(location);
sb.append(", accessToken=").append(accessToken).append("]");
return sb.toString();
}
}
@@ -1,113 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.type.ButtonType;
/**
* 菜单按钮
* <p>
* 目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单,一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以"..."代替
* 请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来,建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果
* </p>
*
* @className Button
* @author jy.hu
* @date 2014年4月5日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.type.ButtonType
*/
public class Button implements Serializable {
private static final long serialVersionUID = -6422234732203854866L;
private String name;
private ButtonType type; // 菜单的响应动作类型
private String key; // click等点击类型必须
private String url; // view类型必须
@JSONField(name = "sub_button")
private List<Button> subs;
public Button() {
}
public Button(String name) {
this.name = name;
}
public Button(String name, String url) {
this.name = name;
this.url = url;
this.type = ButtonType.view;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ButtonType getType() {
return type;
}
public void setType(ButtonType type) {
this.type = type;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public List<Button> getSubs() {
return subs;
}
public void setSubs(List<Button> subs) {
this.subs = subs;
}
public Button pushSub(Button btn) {
if (this.subs == null) {
this.subs = new ArrayList<Button>();
}
this.subs.add(btn);
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[Button name=").append(name);
sb.append(" ,type=").append(type);
sb.append(" ,key=").append(key);
sb.append(" ,url=").append(url);
if (subs != null && !subs.isEmpty()) {
sb.append("{");
for (Button sub : subs) {
sb.append(sub.toString());
}
sb.append("}");
}
sb.append("]");
return sb.toString();
}
}
@@ -1,95 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.Date;
/**
* 客服聊天记录
*
* @className CustomRecord
* @author jy
* @date 2014年6月28日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%9C%8D%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95">客服聊天记录</a>
*/
public class CustomRecord implements Serializable {
private static final long serialVersionUID = -4024147769411601325L;
private String worker;// 客服账号
private String openid;// 用户的标识
private Opercode opercode;// 操作ID(会话状态)
private Date time;// 操作时间
private String text;// 聊天记录
public String getWorker() {
return worker;
}
public void setWorker(String worker) {
this.worker = worker;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public Opercode getOpercode() {
return opercode;
}
public void setOpercode(Opercode opercode) {
this.opercode = opercode;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public enum Opercode {
MISS(1000, "创建未接入会话"), ONLINE(1001, "接入会话"), CALL(1002, "主动发起会话"), CLOSE(
1004, "关闭会话"), RASE(1005, "抢接会话"), RECEIVE1(2001, "公众号收到消息"), SEND(
2002, "客服发送消息"), RECEIVE2(2003, "客服收到消息");
private int code;
private String desc;
Opercode(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[CustomRecord worker=").append(worker);
sb.append(" ,openid=").append(openid);
sb.append(" ,opercode=").append(opercode);
sb.append(" ,time=").append(time);
sb.append(" ,text=").append(text);
sb.append("]");
return sb.toString();
}
}
@@ -1,86 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 关注信息
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href=
* "http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8"
* >关注信息</a>
*/
public class Following implements Serializable {
private static final long serialVersionUID = 1917454368271027134L;
private int total;
private int count;
@JSONField(name = "data")
private JSONObject dataJson;
@JSONField(name = "next_openid")
private String nextOpenId;
private List<User> userList;
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public JSONObject getDataJson() {
return dataJson;
}
public void setDataJson(JSONObject dataJson) {
this.dataJson = dataJson;
}
public String getNextOpenId() {
return nextOpenId;
}
public void setNextOpenId(String nextOpenId) {
this.nextOpenId = nextOpenId;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[Following total=").append(total);
sb.append(", count=").append(count);
if (userList != null && !userList.isEmpty()) {
sb.append(", users={");
for (User u : userList) {
sb.append(u.toString());
}
sb.append("}");
}
sb.append(", nextOpenId=").append(nextOpenId).append("]");
return sb.toString();
}
}
@@ -1,88 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
/**
* 分组
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3">分组</a>
*/
public class Group implements Serializable {
private static final long serialVersionUID = 6979565973974005954L;
private int id;
private String name;
private int count;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public Group(int id, String name) {
this.id = id;
this.name = name;
}
public Group(String name) {
this.name = name;
}
public Group() {
}
/**
* 返回创建分组所需的json格式字符串
*
* @return {"group": {"id": 107, "name": "test"}}
*/
public String toCreateJson() {
return String.format("{\"group\":{\"id\":%s,\"name\":\"%s\"}}", id,
name);
}
/**
* 返回修改分组所需的json格式字符串
*
* @return {"group": {"id": 107, "name": "test"}}
*/
public String toModifyJson() {
return String.format("{\"group\":{\"id\":%s,\"name\":\"%s\"}}", id,
name);
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Group) {
return id == ((Group) obj).getId();
}
return super.equals(obj);
}
@Override
public String toString() {
return String.format("[Group id=%d ,name=%s ,count=%d]", id, name,
count);
}
}
@@ -1,93 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 群发图文消息
*
* @author jy.hu
* @date 2014年4月26日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E7.B4.A0.E6.9D.90">群发消息描述</a>
*/
public class MpArticle implements Serializable {
private static final long serialVersionUID = 5583479943661639234L;
@JSONField(name = "thumb_media_id")
private String thumbMediaId; // 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 非空
private String author;// 图文消息的作者 可为空
private String title;// 图文消息的标题 非空
@JSONField(name = "content_source_url")
private String url;// 在图文消息页面点击“阅读原文”后的页面 可为空
private String content;// 图文消息页面的内容,支持HTML标签 非空
private String digest;// 图文消息的描述 可为空
@JSONField(name = "show_cover_pic")
private short showCoverPic; // 是否显示封面,1为显示,0为不显示 可为空
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
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 getUrl() {
return url;
}
public void setUrl(String url) {
this.url = 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 short getShowCoverPic() {
return showCoverPic;
}
public void setShowCoverPic(short showCoverPic) {
this.showCoverPic = showCoverPic;
}
public MpArticle(String thumbMediaId, String title, String content) {
this.thumbMediaId = thumbMediaId;
this.title = title;
this.content = content;
}
public MpArticle() {
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MpArticle thumbMediaId=").append(thumbMediaId);
sb.append(", author=").append(author);
sb.append(", title=").append(title);
sb.append(", url=").append(url);
sb.append(", content=").append(content);
sb.append(", digest=").append(digest);
sb.append(", showCoverPic=").append(showCoverPic).append("]");
return sb.toString();
}
}
@@ -1,110 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 二维码参数对象
* <p>
* 目前有2种类型的二维码,分别是临时二维码和永久二维码,前者有过期时间,最大为1800秒,但能够生成较多数量,后者无过期时间,数量较少(目前参数只支持1--
* 100000)
* </p>
*
* @className QRParameter
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">生成带参数的二维码</a>
*/
public class QRParameter implements Serializable {
private static final long serialVersionUID = 6611187606558274253L;
public enum QRType {
TEMPORARY("QR_SCENE"), // 临时
PERMANENCE("QR_LIMIT_SCENE"); // 永久
private String name;
QRType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@XStreamAlias("expire_seconds")
private int expireSeconds; // 该二维码有效时间,以秒为单位。 最大不超过1800。
@XStreamAlias("action_name")
private QRType qrType; // 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久
@XStreamOmitField
@XStreamAlias("scene_id")
private int sceneId; // 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000
public int getExpireSeconds() {
return expireSeconds;
}
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public QRType getQrType() {
return qrType;
}
public void setQrType(QRType qrType) {
this.qrType = qrType;
}
public int getSceneId() {
return sceneId;
}
public void setSceneId(int sceneId) {
this.sceneId = sceneId;
}
public QRParameter(int expireSeconds, QRType qrType, int sceneId) {
this.expireSeconds = expireSeconds;
this.qrType = qrType;
this.sceneId = sceneId;
}
public QRParameter(QRType qrType, int sceneId) {
this(0, qrType, sceneId);
}
public QRParameter(int sceneId, int expireSeconds) {
this(0, null, sceneId);
}
public String toJson() {
/*
* XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
* public HierarchicalStreamWriter createWriter(Writer writer) { return
* new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE); } });
* xstream.setMode(XStream.NO_REFERENCES);
* xstream.autodetectAnnotations(true); if (this.qrType ==
* QRType.QR_LIMIT_SCENE) { xstream.omitField(QRParameter.class,
* "expire_seconds"); } return xstream.toXML(this);
*/
StringBuilder jsonBuilder = new StringBuilder("{");
jsonBuilder.append("\"action_name\":\"").append(qrType.getName()).append("\"");
if (this.qrType == QRType.TEMPORARY) {
jsonBuilder.append(",\"expire_seconds\":").append(expireSeconds);
}
jsonBuilder.append(",\"action_info\":").append(String.format("{\"scene\": {\"scene_id\": %d}}", sceneId));
jsonBuilder.append("}");
return jsonBuilder.toString();
}
@Override
public String toString() {
return "QRParameter [expireSeconds=" + expireSeconds + ", qrType=" + qrType + ", sceneId=" + sceneId + "]";
}
}
@@ -1,220 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
/**
* 用户对象
* <p>
* 当用户与公众号有交互时,可通过openid获取信息
* </p>
*
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户基本资料</a>
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String openid; // 用户的唯一标识
private String nickname; // 用户昵称
private int sex; // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
private String province; // 用户个人资料填写的省份
private String city; // 普通用户个人资料填写的城市
private String country; // 国家,如中国为CN
private String headimgurl; // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空
private String privilege; // 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom
private int subscribe; // 是否关注
private long subscribe_time; // 关注时间
private Lang language; // 使用语言
private String unionid; // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段
// 国家地区语言版本
public enum Lang {
zh_CN("简体"), zh_TW("繁体"), en("英语");
private String desc;
Lang(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
}
// 用户性别 值为1时是男性,值为2时是女性,值为0时是未知
public enum Gender {
male(1), female(2), unknown(0);
private int sex;
Gender(int sex) {
this.sex = sex;
}
public int getInt() {
return sex;
}
}
// (有0、46、64、96、132数值可选,0代表640*640正方形头像)
public enum Size {
small(46), middle1(64), middle2(96), big(132);
private int size;
Size(int size) {
this.size = size;
}
public int getInt() {
return size;
}
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getSex() {
return sex;
}
public Gender getGender() {
if (sex == 1) {
return Gender.male;
} else if (sex == 2) {
return Gender.female;
} else {
return Gender.unknown;
}
}
public void setSex(int sex) {
this.sex = sex;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadimgurl() {
return headimgurl;
}
public String getHeadimgurl(Size size) {
if (StringUtils.isNoneBlank(headimgurl)) {
StringBuilder sb = new StringBuilder(headimgurl);
return sb.replace(0, (headimgurl.length() - 1), size.getInt() + "")
.toString();
}
return "";
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public String getPrivilege() {
return privilege;
}
public void setPrivilege(String privilege) {
this.privilege = privilege;
}
public int getSubscribe() {
return subscribe;
}
public void setSubscribe(int subscribe) {
this.subscribe = subscribe;
}
public Lang getLanguage() {
return language;
}
public void setLanguage(Lang language) {
this.language = language;
}
public long getSubscribe_time() {
return subscribe_time;
}
public void setSubscribe_time(long subscribe_time) {
this.subscribe_time = subscribe_time;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof User) {
return openid.equals(((User) obj).getOpenid());
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[User openid=").append(openid);
sb.append(", nickname=").append(nickname);
sb.append(", sex=").append(sex);
sb.append(", province=").append(province);
sb.append(", city=").append(city);
sb.append(", country=").append(country);
sb.append(", headimgurl=").append(headimgurl);
sb.append(", privilege=").append(privilege);
sb.append(", language=").append(language);
sb.append(", subscribe_time=").append(subscribe_time);
sb.append(", unionid=").append(unionid);
sb.append(", subscribe=").append(subscribe).append("]");
return sb.toString();
}
}
@@ -1,45 +0,0 @@
package com.foxinmy.weixin4j.mp.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.Token;
/**
* 用户token 一般通过授权页面获得
*
* @className UserToken
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.mp.model.AuthResult
* @see com.foxinmy.weixin4j.mp.model.AuthResult.AuthScope
*/
public class UserToken extends Token {
private static final long serialVersionUID = 1L;
@JSONField(name = "refresh_token")
private String refreshToken;
private String scope;
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString() {
return "UserToken [refreshToken=" + refreshToken + ", scope=" + scope + ", getAccessToken()=" + getAccessToken() + ", getExpiresIn()=" + getExpiresIn() + ", getOpenid()=" + getOpenid() + ", getTime()=" + getTime() + "]";
}
}
@@ -1,75 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图文对象
*
* @className Article
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Article extends BaseMsg {
private static final long serialVersionUID = 1L;
private String title; // 图文消息标题
@XStreamAlias("description")
private String desc; // 图文消息描述
@XStreamAlias("picurl")
private String picUrl; // 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
private String url; // 点击图文消息跳转链接
public Article(String title, String desc, String picUrl, String url) {
this.title = title;
this.desc = desc;
this.picUrl = picUrl;
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
return "Article [title=" + title + ", desc=" + desc + ", picUrl="
+ picUrl + ", url=" + url + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.mpnews;
}
}
@@ -1,39 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ClassUtil;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;
public abstract class BaseMsg implements Serializable {
private static final long serialVersionUID = 1L;
private final static XStream xstream = new XStream(
new JsonHierarchicalStreamDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
static {
xstream.setMode(XStream.NO_REFERENCES);
xstream.autodetectAnnotations(true);
xstream.processAnnotations(ClassUtil.getClasses(
BaseNotify.class.getPackage()).toArray(new Class[0]));
}
public abstract MediaType getMediaType();
/**
* 客服消息json化,适用于客服消息接口
*
* @return {"touser": "to","msgtype": "text","text": {"content": "123"}}
*/
public String toNotifyJson() {
return xstream.toXML(this);
}
}
@@ -1,38 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图片对象
*
* @className Image
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Image extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
public Image(String mediaId) {
this.mediaId = mediaId;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public MediaType getMediaType() {
return MediaType.image;
}
}
@@ -1,93 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 音乐对象
*
* @className Music
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Music extends BaseMsg {
private static final long serialVersionUID = 1L;
private String title;
@XStreamAlias("description")
private String desc;
@XStreamAlias("musicurl")
private String musicUrl;
@XStreamAlias("hqmusicurl")
private String hqMusicUrl;
@XStreamAlias("thumb_media_id")
private String thumbMediaId;
public Music(String thumbMediaId) {
this(null, null, null, null, thumbMediaId);
}
public Music(String title, String desc, String musicUrl, String hqMusicUrl,
String thumbMediaId) {
this.title = title;
this.desc = desc;
this.musicUrl = musicUrl;
this.hqMusicUrl = hqMusicUrl;
this.thumbMediaId = thumbMediaId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getMusicUrl() {
return musicUrl;
}
public void setMusicUrl(String musicUrl) {
this.musicUrl = musicUrl;
}
public String getHqMusicUrl() {
return hqMusicUrl;
}
public void setHqMusicUrl(String hqMusicUrl) {
this.hqMusicUrl = hqMusicUrl;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
@Override
public String toString() {
return "Music [title=" + title + ", desc=" + desc + ", musicUrl="
+ musicUrl + ", hqMusicUrl=" + hqMusicUrl + ", thumbMediaId="
+ thumbMediaId + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.music;
}
}
@@ -1 +0,0 @@
不同的消息类型中的模型
@@ -1,40 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 文本对象
* @className Text
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Text extends BaseMsg {
private static final long serialVersionUID = 1L;
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Text(String content) {
this.content = content;
}
@Override
public String toString() {
return "Text [content=" + content + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.text;
}
}
@@ -1,88 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 视频对象
*
* @className Video
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Video extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
@XStreamAlias("thumb_media_id")
private String thumbMediaId;
private String title;
@XStreamAlias("description")
private String desc;
public Video(String mediaId) {
this(mediaId, null, null, null);
}
public Video(String mediaId, String thumbMediaId) {
this(mediaId, thumbMediaId, null, null);
}
public Video(String mediaId, String title, String desc) {
this(mediaId, null, title, desc);
}
public Video(String mediaId, String thumbMediaId, String title, String desc) {
this.mediaId = mediaId;
this.thumbMediaId = thumbMediaId;
this.title = title;
this.desc = desc;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Video [mediaId=" + mediaId + ", thumbMediaId=" + thumbMediaId
+ ", title=" + title + ", desc=" + desc + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.vedio;
}
}
@@ -1,38 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 语音对象
*
* @className Image
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Voice extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
public Voice(String mediaId) {
this.mediaId = mediaId;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public MediaType getMediaType() {
return MediaType.voice;
}
}
@@ -1,102 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import java.util.LinkedList;
import java.util.List;
import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 客服图文消息
*
* @className ArticleNotify
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">客服图文消息</a>
* @see com.foxinmy.weixin.msg.model.Article
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class ArticleNotify extends BaseNotify {
private static final int MAX_ARTICLE_COUNT = 10;
private static final long serialVersionUID = 1740696901128709998L;
public ArticleNotify() {
this(null);
}
public ArticleNotify(String touser) {
super(touser, ResponseType.news);
}
@XStreamAlias("news")
private News news;
@XStreamOmitField
private int count; // 图文消息个数,限制为10条以内
public void pushArticle(String title, String desc, String picUrl, String url) {
if ((count + 1) > MAX_ARTICLE_COUNT) {
return;
}
if (this.news == null) {
this.news = new News();
}
this.news.pushArticle(title, desc, picUrl, url);
count++;
}
public void pushAll(List<Article> articles) {
count = articles.size();
if (articles.size() > MAX_ARTICLE_COUNT) {
count = MAX_ARTICLE_COUNT;
articles = articles.subList(0, count);
}
if (this.news == null) {
this.news = new News();
}
this.news.setArticles(articles);
}
private static class News {
@XStreamAlias("articles")
private List<Article> articles;
public News() {
this.articles = new LinkedList<Article>();
}
public void pushArticle(String title, String desc, String picUrl,
String url) {
this.articles.add(new Article(title, desc, picUrl, url));
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Article article : articles) {
sb.append("{title=").append(article.getTitle());
sb.append(" ,description=").append(article.getDesc());
sb.append(" ,picUrl=").append(article.getPicUrl());
sb.append(" ,url=").append(article.getUrl()).append("}");
}
return sb.toString();
}
}
@Override
public String toString() {
return String.format(
"[ArticleNotify touser=%s ,msgtype=%s ,articles=%s]",
super.getTouser(), super.getMsgtype().name(),
this.news.toString());
}
}
@@ -1,75 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;
/**
* 客服消息基类(48小时内不限制发送次数)
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">发送客服消息</a>
*/
public class BaseNotify implements Serializable {
private static final long serialVersionUID = 7190233634431087729L;
private String touser;
private ResponseType msgtype;
public BaseNotify(ResponseType msgtype) {
this.msgtype = msgtype;
}
public BaseNotify(String touser, ResponseType msgtype) {
this.touser = touser;
this.msgtype = msgtype;
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public ResponseType getMsgtype() {
return msgtype;
}
public void setMsgtype(ResponseType msgtype) {
this.msgtype = msgtype;
}
/**
* 客服消息json化
*
* @return {"touser": "to","msgtype": "text","text": {"content": "123"}}
*/
public String toJson() {
XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
xstream.setMode(XStream.NO_REFERENCES);
xstream.autodetectAnnotations(true);
xstream.processAnnotations(this.getClass());
return xstream.toXML(this);
}
@Override
public String toString() {
return String.format("[BaseNotify touser=%s ,msgtype=%s]", touser,
msgtype.name());
}
}
@@ -1,47 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import com.foxinmy.weixin4j.mp.msg.model.Image;
import com.foxinmy.weixin4j.mp.type.ResponseType;
/**
* 客服图片消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">客服图片消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Image
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class ImageNotify extends BaseNotify {
private static final long serialVersionUID = -7698823863398518425L;
public ImageNotify() {
this(null, null);
}
public ImageNotify(String touser) {
this(null, touser);
}
public ImageNotify(String mediaId, String touser) {
super(touser, ResponseType.image);
this.pushMediaId(mediaId);
}
public void pushMediaId(String mediaId) {
this.image = new Image(mediaId);
}
private Image image;
@Override
public String toString() {
return String.format("[ImageNotify touser=%s ,msgtype=%s ,mediaId=%s]",
super.getTouser(), super.getMsgtype().name(),
this.image.getMediaId());
}
}
@@ -1,46 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import com.foxinmy.weixin4j.mp.msg.model.Music;
import com.foxinmy.weixin4j.mp.type.ResponseType;
/**
* 客服音乐消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">客服音乐消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Music
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class MusicNotify extends BaseNotify {
private static final long serialVersionUID = -7698823863398518425L;
public MusicNotify() {
this(null);
}
public MusicNotify(String touser) {
super(touser, ResponseType.music);
}
public void pushMusic(String musicurl, String hqUrl, String mediaId) {
this.music = new Music(null, null, musicurl, hqUrl, mediaId);
}
private Music music;
public void setMusic(Music music) {
this.music = music;
}
@Override
public String toString() {
return String.format("[MusicNotify touser=%s ,msgtype=%s ,music=%s]",
super.getTouser(), super.getMsgtype().name(),
this.music.toString());
}
}
@@ -1 +0,0 @@
客服消息
@@ -1,47 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import com.foxinmy.weixin4j.mp.msg.model.Text;
import com.foxinmy.weixin4j.mp.type.ResponseType;
/**
* 客服文本消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">客服文本消息</a>
* @see com.foxinmy.weixin.msg.model.Text
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class TextNotify extends BaseNotify {
private static final long serialVersionUID = -7698823863398518425L;
public TextNotify() {
this(null, null);
}
public TextNotify(String content) {
this(content,null);
}
public TextNotify(String content, String touser) {
super(touser, ResponseType.text);
this.text = new Text(content);
}
public void setContent(String content) {
this.text = new Text(content);
}
private Text text;
@Override
public String toString() {
return String.format("[TextNotify touser=%s ,msgtype=%s ,content=%s]",
super.getTouser(), super.getMsgtype().name(),
this.text.getContent());
}
}
@@ -1,46 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import com.foxinmy.weixin4j.mp.msg.model.Video;
import com.foxinmy.weixin4j.mp.type.ResponseType;
/**
* 客服视频消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">客服视频消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Video
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class VideoNotify extends BaseNotify {
private static final long serialVersionUID = -7698823863398518425L;
public VideoNotify() {
this(null);
}
public VideoNotify(String touser) {
super(touser, ResponseType.video);
}
public void pushVideo(String mediaId, String thumbMediaId) {
this.video = new Video(mediaId, thumbMediaId);
}
private Video video;
public void setVideo(Video video) {
this.video = video;
}
@Override
public String toString() {
return String.format("[VideoNotify touser=%s ,msgtype=%s ,video=%s]",
super.getTouser(), super.getMsgtype().name(),
this.video.toString());
}
}
@@ -1,47 +0,0 @@
package com.foxinmy.weixin4j.mp.msg.notify;
import com.foxinmy.weixin4j.mp.msg.model.Voice;
import com.foxinmy.weixin4j.mp.type.ResponseType;
/**
* 客服语音消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">客服语音消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Voice
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.mp.msg.notify.BaseNotify#toJson()
*/
public class VoiceNotify extends BaseNotify {
private static final long serialVersionUID = -7698823863398518425L;
public VoiceNotify() {
this(null, null);
}
public VoiceNotify(String touser) {
this(null, touser);
}
public VoiceNotify(String mediaId, String touser) {
super(touser, ResponseType.voice);
this.pushMediaId(mediaId);
}
public void pushMediaId(String mediaId) {
this.voice = new Voice(mediaId);
}
private Voice voice;
@Override
public String toString() {
return String.format("[VoiceNotify touser=%s ,msgtype=%s ,mediaId=%s]",
super.getTouser(), super.getMsgtype().name(),
this.voice.getMediaId());
}
}
@@ -1,103 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import java.util.LinkedList;
import com.foxinmy.weixin4j.mp.msg.model.Article;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复图文消息
*
* @className ArticleResponse
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">回复图文消息</a>
* @see com.foxinmy.weixin.msg.model.Article
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class ArticleResponse extends BaseResponse {
private static final int MAX_ARTICLE_COUNT = 10;
private static final long serialVersionUID = -7331603018352309317L;
public ArticleResponse(BaseMessage inMessage) {
super(ResponseType.news, inMessage);
}
@XStreamAlias("ArticleCount")
private int count; // 图文消息个数,限制为10条以内
@XStreamAlias("Articles")
private LinkedList<Article> articles;
public void pushArticle(String title, String desc, String picUrl, String url) {
if (this.articles == null) {
this.articles = new LinkedList<Article>();
}
if ((articles.size() + 1) > MAX_ARTICLE_COUNT) {
return;
}
this.articles.add(new Article(title, desc, picUrl, url));
}
public void pushFirstArticle(String title, String desc, String picUrl,
String url) {
if (this.articles == null) {
this.articles = new LinkedList<Article>();
}
this.articles.addFirst(new Article(title, desc, picUrl, url));
}
public void pushLastArticle(String title, String desc, String picUrl,
String url) {
if (this.articles == null) {
this.articles = new LinkedList<Article>();
}
this.articles.addLast(new Article(title, desc, picUrl, url));
}
public Article removeLastArticle() {
Article article = null;
if (this.articles != null) {
article = this.articles.removeLast();
}
return article;
}
public Article removeFirstArticle() {
if (this.articles != null) {
return this.articles.removeFirst();
}
return null;
}
public boolean isMaxCount() {
return this.articles.size() == MAX_ARTICLE_COUNT;
}
@Override
public String toXml() {
this.count = articles.size();
xmlStream.alias("item", Article.class);
xmlStream.aliasField("Title", Article.class, "title");
xmlStream.aliasField("Description", Article.class, "desc");
xmlStream.aliasField("PicUrl", Article.class, "picUrl");
xmlStream.aliasField("Url", Article.class, "url");
return xmlStream.toXML(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[BaseResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,articles=").append(this.articles.toString());
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1,122 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.util.ClassUtil;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;
/**
* 响应消息基类
* <p>
* <font color="red">回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,
* 假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试</font>
* </p>
*
* @className BaseResponse
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
*/
public class BaseResponse implements Serializable {
private static final long serialVersionUID = 7761192742840031607L;
protected final static XStream xmlStream = XStream.get();
private final static XStream jsonStream = new XStream(
new JsonHierarchicalStreamDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
@XStreamAlias("ToUserName")
private String toUserName; // 开发者微信号
@XStreamAlias("FromUserName")
private String fromUserName; // 发送方帐号(一个OpenID
@XStreamAlias("CreateTime")
private long createTime = System.currentTimeMillis(); // 消息创建时间 (整型)
@XStreamAlias("MsgType")
private ResponseType msgType; // 消息类型
static {
Class<?>[] classes = ClassUtil.getClasses(
BaseResponse.class.getPackage()).toArray(new Class[0]);
xmlStream.processAnnotations(classes);
jsonStream.setMode(XStream.NO_REFERENCES);
jsonStream.autodetectAnnotations(true);
jsonStream.processAnnotations(classes);
}
public BaseResponse(ResponseType msgType) {
this.msgType = msgType;
}
public BaseResponse(ResponseType msgType, BaseMessage inMessage) {
this(msgType, inMessage.getFromUserName(), inMessage.getToUserName());
}
public BaseResponse(ResponseType msgType, String toUserName,
String fromUserName) {
this.msgType = msgType;
this.toUserName = toUserName;
this.fromUserName = fromUserName;
}
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public ResponseType getMsgType() {
return msgType;
}
public void setMsgType(ResponseType msgType) {
this.msgType = msgType;
}
/**
* 消息对象转换为微信服务器接受的xml格式消息
*
* @return xml字符串
*/
public String toXml() {
return xmlStream.toXML(this);
}
/**
* 消息对象转换为微信服务器接受的json格式字符串
*
* @return json字符串
*/
public String toJson() {
return jsonStream.toXML(this);
}
}
@@ -1,59 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.msg.model.Image;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复图片消息
*
* @className ImageResponse
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">回复图片消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Image
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class ImageResponse extends BaseResponse {
private static final long serialVersionUID = 6998255203997554731L;
public ImageResponse(BaseMessage inMessage) {
this(null, inMessage);
}
public ImageResponse(String mediaId, BaseMessage inMessage) {
super(ResponseType.image, inMessage);
super.getMsgType().setMessageClass(ImageResponse.class);
this.pushMediaId(mediaId);
}
@XStreamAlias("Image")
private Image image;
public void pushMediaId(String mediaId) {
this.image = new Image(mediaId);
}
@Override
public String toXml() {
xmlStream.aliasField("MediaId", Image.class, "mediaId");
return xmlStream.toXML(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ImageResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,mediaId=").append(this.image.getMediaId());
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1,61 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.msg.model.Music;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复音乐消息
*
* @className MusicResponse
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">回复音乐消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Music
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class MusicResponse extends BaseResponse {
private static final long serialVersionUID = 4384403772658796395L;
public MusicResponse(BaseMessage inMessage) {
super(ResponseType.music, inMessage);
}
@XStreamAlias("Music")
private Music music;
public void pushMusic(String mediaId) {
this.music = new Music(mediaId);
}
public void setMusic(Music music) {
this.music = music;
}
@Override
public String toXml() {
xmlStream.aliasField("MediaId", Music.class, "musicUrl");
xmlStream.aliasField("Title", Music.class, "title");
xmlStream.aliasField("Description", Music.class, "desc");
xmlStream.aliasField("HQMusicUrl", Music.class, "hqMusicUrl");
xmlStream.aliasField("ThumbMediaId", Music.class, "thumbMediaId");
return xmlStream.toXML(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MusicResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,music=").append(music.toString());
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1 +0,0 @@
回复消息
@@ -1,122 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 模板消息
*
* @className TemplateMessage
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息</a>
*/
public class TemplateMessage implements Serializable {
private static final long serialVersionUID = 7950608393821661436L;
private String touser;
private String template_id;
private String url;
private String topcolor = "#FF0000";
private Map<String, Item> data;
public void pushData(String key, String value) {
this.data.put(key, new Item(value));
}
public TemplateMessage(String touser, String template_id, String title,
String url) {
this.touser = touser;
this.template_id = template_id;
this.url = url;
this.data = new HashMap<String, Item>();
pushData("first", title);
}
private static class Item implements Serializable {
private static final long serialVersionUID = 1L;
private String value;
private String color;
public Item(String value) {
this(value, "#173177");
}
public Item(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public String getColor() {
return color;
}
@Override
public String toString() {
return "$ [value=" + getValue() + ", color=" + getColor() + "]";
}
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public String getTemplate_id() {
return template_id;
}
public void setTemplate_id(String template_id) {
this.template_id = template_id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTopcolor() {
return topcolor;
}
public void setTopcolor(String topcolor) {
this.topcolor = topcolor;
}
public Map<String, Item> getData() {
return data;
}
public void setData(Map<String, Item> data) {
this.data = data;
}
@Override
public String toString() {
return "TemplateMessage [touser=" + touser + ", template_id="
+ template_id + ", url=" + url + ", topcolor=" + topcolor
+ ", data=" + data + "]";
}
@JSONField(serialize = false)
public String toJson() {
return JSON.toJSONString(this);
}
}
@@ -1,57 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复文本消息
*
* @className TextResponse
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">接收文本消息</a>
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">回复文本消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class TextResponse extends BaseResponse {
private static final long serialVersionUID = -7018053906644190260L;
public TextResponse() {
super(ResponseType.text);
}
public TextResponse(String content, BaseMessage inMessage) {
super(ResponseType.text, inMessage);
this.content = content;
}
@XStreamAlias("Content")
private String content; // 消息内容
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[TextResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,content=").append(content);
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1,27 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 转移消息到多客服端消息
*
* @className TransferResponse
* @author jy.hu
* @date 2014年6月28日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%B0%86%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E5%88%B0%E5%A4%9A%E5%AE%A2%E6%9C%8D">多客服转移消息</a>
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class TransferResponse extends BaseResponse {
private static final long serialVersionUID = -5479496746108594940L;
public TransferResponse(BaseMessage inMessage) {
super(ResponseType.transfer_customer_service, inMessage);
}
}
@@ -1,61 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.msg.model.Video;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复视频消息
*
* @className VideoResponse
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">回复视频消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Video
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class VideoResponse extends BaseResponse {
private static final long serialVersionUID = -1013075358679078381L;
public VideoResponse(BaseMessage inMessage) {
super(ResponseType.video, inMessage);
super.getMsgType().setMessageClass(VideoResponse.class);
}
@XStreamAlias("Video")
private Video video;
public void pushVideo(String mediaId) {
this.video = new Video(mediaId);
}
public void setVideo(Video video) {
this.video = video;
}
@Override
public String toXml() {
xmlStream.aliasField("MediaId", Video.class, "mediaId");
xmlStream.aliasField("Title", Video.class, "title");
xmlStream.aliasField("Description", Video.class, "desc");
xmlStream.omitField(Video.class, "thumbMediaId");
return xmlStream.toXML(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[VideoResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,video=").append(video.toString());
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1,59 +0,0 @@
package com.foxinmy.weixin4j.mp.response;
import com.foxinmy.weixin4j.mp.msg.model.Voice;
import com.foxinmy.weixin4j.mp.type.ResponseType;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复语音消息
*
* @className VoiceResponse
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a
* href="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#.E5.9B.9E.E5.A4.8D.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">回复语音消息</a>
* @see com.foxinmy.weixin4j.mp.msg.model.Voice
* @see com.foxinmy.weixin4j.mp.response.BaseResponse
* @see com.foxinmy.weixin4j.mp.response.BaseResponse#toXml()
*/
@XStreamAlias("xml")
public class VoiceResponse extends BaseResponse {
private static final long serialVersionUID = -7944926238652243793L;
public VoiceResponse(BaseMessage inMessage) {
this(null, inMessage);
}
public VoiceResponse(String mediaId, BaseMessage inMessage) {
super(ResponseType.voice, inMessage);
super.getMsgType().setMessageClass(VoiceResponse.class);
this.pushMediaId(mediaId);
}
@XStreamAlias("Voice")
private Voice voice;
public void pushMediaId(String mediaId) {
this.voice = new Voice(mediaId);
}
@Override
public String toXml() {
xmlStream.aliasField("MediaId", Voice.class, "mediaId");
return xmlStream.toXML(this);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[VoiceResponse ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,mediaId=").append(voice.getMediaId());
sb.append(" ,createTime=").append(super.getCreateTime()).append("]");
return sb.toString();
}
}
@@ -1 +0,0 @@
微信服务netty启动类
@@ -1,85 +0,0 @@
package com.foxinmy.weixin4j.mp.server;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import java.nio.charset.StandardCharsets;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.mp.action.WeixinAction;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping;
public class WeixinServerHandler extends ChannelInboundHandlerAdapter {
private final Logger log = LoggerFactory.getLogger(getClass());
private final ActionMapping actionMapping;
public WeixinServerHandler(ActionMapping actionMapping) {
this.actionMapping = actionMapping;
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws DocumentException {
if (msg instanceof FullHttpRequest) {
FullHttpRequest req = (FullHttpRequest) msg;
if (HttpHeaders.is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
return;
}
String xmlMsg = req.content().toString(StandardCharsets.UTF_8);
log.info("\n=================message in=================\n{}",
xmlMsg);
WeixinAction action = actionMapping.getAction(xmlMsg);
if (action == null) {
ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.NOT_FOUND));
return;
}
String content = action.execute(xmlMsg);
log.info("\n=================message out=================\n{}",
content);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
OK, Unpooled.copiedBuffer(content, StandardCharsets.UTF_8));
response.headers().set(CONTENT_TYPE, "text/plain;charset=utf-8");
response.headers().set(CONTENT_LENGTH,
response.content().readableBytes());
if (!HttpHeaders.isKeepAlive(req)) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
ctx.write(response);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
@@ -1,27 +0,0 @@
package com.foxinmy.weixin4j.mp.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import com.foxinmy.weixin4j.mp.mapping.ActionMapping;
import com.foxinmy.weixin4j.mp.mapping.AnnotationActionMapping;
public class WeixinServerInitializer extends ChannelInitializer<SocketChannel> {
private final ActionMapping actionMapping;
public WeixinServerInitializer() {
this.actionMapping = new AnnotationActionMapping();
}
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new HttpObjectAggregator(65536));
pipeline.addLast(new WeixinServerHandler(actionMapping));
}
}
@@ -1,3 +0,0 @@
模拟微信公众平台登陆
(模拟登录|启用开发者模式|修改服务器配置|修改回调地址|创建自定义菜单....more)
@@ -1,670 +0,0 @@
package com.foxinmy.weixin4j.mp.spider;
import java.io.Serializable;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.RandomUtil;
/**
* 模拟微信WEB登陆
*
* <p>
* (模拟登录|启用开发者模式|修改服务器配置|修改回调地址|创建自定义菜单....more)
* </p>
*
* @className WeixinExecutor
* @author jy
* @date 2014年8月15日
* @since JDK 1.7
* @see
*/
public class WeixinExecutor implements Serializable {
private static final long serialVersionUID = 4253859892138066462L;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final static Charset charset = StandardCharsets.UTF_8;
private final static Map<String, String> accountMap = new HashMap<String, String>() {
private static final long serialVersionUID = 1L;
{
put("名称", "name");
put("头像", "avatar");
put("登录邮箱", "loginEmail");
put("原始ID", "originalId");
put("微信号", "weixinNo");
put("类型", "accountType");
put("认证情况", "weixinVerify");
put("主体信息", "bodyInfo");
put("介绍", "introduce");
put("所在地址", "address");
put("二维码", "qrcodeUrl");
}
};
private AbstractHttpClient client;
private HttpHost host;
private JSONObject weixin;
// 服务器响应地址
private String pushurl;
// oauth授权回调地址
private String backurl;
// 服务器校验token
private String token;
// 公众号用户名
private String uname;
// 公众号密码
private String pwd;
// 登录时验证码(如果有)
private String imgcode;
// 当要求输入验证码时,cookie需带上
private String sig;
public WeixinExecutor(String backurl, String pushurl, String token,
String uname, String pwd, String imgcode, String sig) {
this.backurl = backurl;
this.pushurl = pushurl;
this.token = token;
this.uname = uname;
this.pwd = pwd;
this.imgcode = StringUtils.isBlank(imgcode) ? "" : imgcode;
this.sig = sig;
weixin = new JSONObject();
weixin.put("host", "mp.weixin.qq.com");
weixin.put("base", "https://mp.weixin.qq.com");
weixin.put("auth", "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN");
weixin.put(
"call",
"https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&token=%s&lang=zh_CN");
weixin.put("start",
"https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform");
weixin.put("back",
"https://mp.weixin.qq.com/merchant/myservice?action=set_oauth_domain&f=json");
weixin.put("verifycode",
"https://mp.weixin.qq.com/cgi-bin/verifycode?username=" + uname
+ "&r=%s");
weixin.put("bedeveloper",
"https://mp.weixin.qq.com/advanced/advanced?action=agreement");
List<BasicHeader> headers = new ArrayList<BasicHeader>();
headers.add(new BasicHeader("Origin", weixin.getString("base")));
headers.add(new BasicHeader("Connection", "keep-alive"));
headers.add(new BasicHeader(
"User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"));
client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.COOKIE_POLICY,
CookiePolicy.BROWSER_COMPATIBILITY);
client.getParams().setBooleanParameter(
"http.protocol.single-cookie-header", true);
client.getParams().setParameter(ClientPNames.DEFAULT_HEADERS, headers);
host = new HttpHost(weixin.getString("host"), -1, "https");
}
public JSONObject process() {
// 1.登陆微信公众号
step1_login();
int code = weixin.getIntValue("code");
if (code == 0) {
// 2.收集相关信息
step2_collect();
code = weixin.getIntValue("code");
// 3.填写服务器配置
// 3-1.未初始化账号
// 3-2.已配置账号
if (code == 0) {
step3_setting();
}
code = weixin.getIntValue("code");
// 4.修改网页授权地址
if (code == 0) {
step4_back();
}
// 5.创建底部菜单 (调用封装好的API)
// 5-1.订阅号
// 5-2.服务号
// 6.完成
}
return weixin;
}
/**
* step1:登录操作
*/
private void step1_login() {
HttpPost method = new HttpPost(weixin.getString("auth"));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("username", uname));
parameters.add(new BasicNameValuePair("pwd", DigestUtils.md5Hex(pwd
.getBytes())));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("imgcode", imgcode));
if (!StringUtils.isBlank(imgcode)) {
method.addHeader("Cookie", "sig=" + sig);
}
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step1_login--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getIntValue("ret")
+ body.getJSONObject("base_resp").getIntValue("ret")) {
case -1:
msg = "系统错误,请稍候再试。";
code = -1;
break;
case -2:
msg = "帐号或密码错误。";
code = 100;
break;
case -23:
msg = "您输入的帐号或者密码不正确,请重新输入。";
code = 101;
break;
case -21:
msg = "不存在该帐户。";
code = 102;
break;
case -7:
msg = "您目前处于访问受限状态。";
code = 103;
break;
case -8:
msg = "请输入图中的验证码";
code = 104;
break;
case -27:
msg = "您输入的验证码不正确,请重新输入";
code = 105;
break;
case -26:
msg = "该公众会议号已经过期,无法再登录使用。";
code = 106;
break;
case 0:
msg = "成功登录,正在跳转...";
break;
case -25:
msg = "海外帐号请在公众平台海外版登录,<a href=\"http://admin.wechat.com/\">点击登录</a>";
code = 107;
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
weixin.put(
"urlToken",
getQueryMap(body.getString("redirect_url")).get(
"token"));
weixin.put("indexUrl", String.format("%s%s",
weixin.getString("base"),
body.getString("redirect_url")));
weixin.put("step", "1");
} else {
if (code == 104 || code == 105) {
// 下载验证码
HttpGet get = new HttpGet(String.format(
weixin.getString("verifycode"),
System.currentTimeMillis()));
get.setHeaders(method.getAllHeaders());
response = client.execute(host, get);
StringBuffer base64 = new StringBuffer();
base64.append("data:")
.append(response.getFirstHeader("Content-Type")
.getValue()).append(";base64,");
base64.append(new String(
Base64.encodeBase64(IOUtil.toByteArray(response
.getEntity().getContent())), charset));
weixin.put("verifydata", base64.toString());
List<Cookie> cookieList = client.getCookieStore()
.getCookies();
for (Cookie cookie : cookieList) {
if (cookie.getName().equals("sig")) {
weixin.put("sig", cookie.getValue());
break;
}
}
}
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step1_login catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step2:收集信息
*/
private void step2_collect() {
String url = weixin.getString("indexUrl");
HttpGet method = new HttpGet(url);
try {
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step2_setting--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
Element ele = root.getElementById("menuBar")
.getElementsByTag("dl").last();
url = ele.getElementsByTag("a").last().absUrl("href");
weixin.put("developerUrl", url);
method.addHeader("Referer", url);
url = ele.previousElementSibling().getElementsByTag("a")
.first().absUrl("href");
weixin.put("settingUrl", url);
method.setURI(URI.create(url));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
line = response.getStatusLine();
weixin.put("step", "2-1");
// 公众号配置页面
if (line.getStatusCode() == HttpStatus.SC_OK) {
Elements eles = root.getElementById("settingArea")
.getElementsByTag("li");
String key, value;
for (Element element : eles) {
key = element.getElementsByTag("h4").first().text();
ele = element.getElementsByClass("meta_content")
.first();
if (ele.children().isEmpty()) {
value = ele.text();
} else {
if (ele.child(0).tagName().equalsIgnoreCase("a")) {
value = ele.child(0).absUrl("href");
} else if (ele.child(0).tagName()
.equalsIgnoreCase("img")) {
value = ele.child(0).absUrl("src");
} else {
value = ele.text();
}
}
weixin.put(accountMap.get(key), value);
}
weixin.put("isVerify", weixin.getString("weixinVerify")
.contains("微信认证"));
weixin.put("isService", weixin.getString("accountType")
.contains("服务号"));
weixin.put("isSubscribe", weixin.getString("accountType")
.contains("订阅号"));
value = weixin.getString("qrcodeUrl");
method.setURI(URI.create(value));
response = client.execute(host, method);
weixin.put("qrcodeData", IOUtil.toByteArray(response
.getEntity().getContent()));
weixin.put("step", "2-2");
// 开发者页面
method.addHeader("Referer", url);
method.setURI(URI.create(weixin.getString("developerUrl")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
line = response.getStatusLine();
if (line.getStatusCode() == HttpStatus.SC_OK) {
// 还没有成为开发者 2014.10-06 jy.hu
// 触发成为开发者动作
ele = root.getElementById("js_toBeDeveloper");
if (ele != null && ele.hasText()) {
HttpPost post = new HttpPost(URI.create(weixin
.getString("bedeveloper")));
post.addHeader("Referer", url);
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("token",
weixin.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("lang",
"zh_CN"));
parameters.add(new BasicNameValuePair("random",
System.currentTimeMillis() + ""));
post.setEntity(new UrlEncodedFormEntity(parameters,
charset));
response = client.execute(host, post);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
charset.name(), weixin.getString("base"));
line = response.getStatusLine();
logger.info(
"step2_bedeveloper--->status={},body=\n{}",
line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body()
.text());
if (body.getIntValue("ret") == 0) {
method.addHeader("Referer", url);
method.setURI(URI.create(weixin
.getString("developerUrl")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(),
charset.name(),
weixin.getString("base"));
} else {
weixin.put("code", "-100");
weixin.put("msg", "成为开发者失败!");
return;
}
}
}
// 初始化状态
// 配置未启用状态
// 配置已启用状态
eles = root.getElementsByClass("developer_info_opr");
if (eles != null && eles.hasText()) {
weixin.put("developerModifyUrl", eles.first()
.children().first().absUrl("href"));
weixin.put("status",
eles.text().contains("启用") ? "READY"
: "RUNNING");
} else {
weixin.put("status", "INIT");
}
// appid&appsecret
if (weixin.getBooleanValue("isService")
|| (weixin.getBooleanValue("isSubscribe") && weixin
.getBooleanValue("isVerify"))) {
eles = root
.getElementsByClass("developer_info_item")
.first().children().last()
.getElementsByClass("frm_controls");
weixin.put("appId", eles.first().text());
weixin.put("appSecret",
eles.last().text().replace("重置", "").trim());
}
weixin.put("step", "2-3");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step2_collect catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step3:填写配置
*/
private void step3_setting() {
HttpPost method = new HttpPost(String.format(weixin.getString("call"),
weixin.getString("urlToken")));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("url", pushurl));
parameters.add(new BasicNameValuePair("callback_token", token));
// EncodingAESKey | 消息加解密方式(明文0,兼容1,安全2)
parameters.add(new BasicNameValuePair("encoding_aeskey", RandomUtil
.generateString(43)));
parameters
.add(new BasicNameValuePair("callback_encrypt_mode", "0"));
parameters.add(new BasicNameValuePair("operation_seq", RandomUtil
.generateStringByNumberChar(9)));
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("developerModifyUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getIntValue("ret")
+ body.getJSONObject("base_resp").getIntValue("ret")) {
case -201:
msg = "无效的URL";
code = 200;
break;
case -202:
msg = "无效的Token";
code = 201;
break;
case -203:
msg = "操作频率太快,请休息一下。";
code = 202;
break;
case -204:
msg = "请先在设置页面完善当前帐号信息";
code = 203;
break;
case -205:
msg = "该URL可能存在安全风险,请检查";
code = 207;
case -301:
msg = "请求URL超时";
code = 204;
break;
case -302:
msg = "服务器没有正确响应Token验证,请稍后重试";
code = 205;
break;
case -104:
msg = "参数错误,请重新填写。";
code = 206;
break;
case 0:
msg = "配置成功..";
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
// 触发启用按钮
if (!weixin.getString("status").equals("RUNNING")) {
parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("token", weixin
.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("type", "2"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System
.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters,
charset));
method.setURI(URI.create(weixin.getString("start")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(),
weixin.getString("base"));
line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}",
line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret")
+ body.getJSONObject("base_resp")
.getIntValue("ret") != 0) {
weixin.put("code", 300);
weixin.put("msg", "启用开发者模式失败,请稍后再试!");
}
}
}
weixin.put("step", "3");
} else {
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step3_setting catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step4:修改回调
*/
private void step4_back() {
try {
if (weixin.getBooleanValue("isVerify")) {
HttpPost method = new HttpPost(weixin.getString("back"));
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("domain", backurl));
parameters.add(new BasicNameValuePair("token", weixin
.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System
.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("developerUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(),
charset.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step4_back--->status={},body=\n{}", line,
root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret")
+ body.getJSONObject("base_resp")
.getIntValue("ret") != 0) {
weixin.put("code", "400");
weixin.put("msg", "修改授权回调地址失败!");
}
weixin.put("step", "4");
}
} else {
logger.info("公众号尚未认证,放弃本次修改授权回调地址操作。{}", weixin);
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step4_back catch error", e);
} finally {
client.getConnectionManager().shutdown();
}
}
private Map<String, String> getQueryMap(String query) {
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
return map;
}
}
@@ -1,54 +0,0 @@
package com.foxinmy.weixin4j.mp.statrup;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import java.util.ResourceBundle;
import com.foxinmy.weixin4j.mp.server.WeixinServerInitializer;
/**
* 微信服务启动程序
*
* @className WeixinBootstrap
* @author jy
* @date 2014年10月12日
* @since JDK 1.7
* @see
*/
public final class WeixinServiceBootstrap {
private final static int port;
private final static int workerThreads;
static {
ResourceBundle config = ResourceBundle.getBundle("netty");
port = Integer.parseInt(config.getString("port"));
workerThreads = Integer.parseInt(config.getString("workerThreads"));
}
public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(workerThreads);
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler())
.childHandler(new WeixinServerInitializer());
Channel ch = b.bind(port).sync().channel();
System.err.println("weixin server startup OK:" + port);
ch.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
@@ -1,37 +0,0 @@
package com.foxinmy.weixin4j.mp.type;
import com.foxinmy.weixin4j.mp.response.ArticleResponse;
import com.foxinmy.weixin4j.mp.response.BaseResponse;
import com.foxinmy.weixin4j.mp.response.ImageResponse;
import com.foxinmy.weixin4j.mp.response.MusicResponse;
import com.foxinmy.weixin4j.mp.response.TextResponse;
import com.foxinmy.weixin4j.mp.response.TransferResponse;
import com.foxinmy.weixin4j.mp.response.VideoResponse;
import com.foxinmy.weixin4j.mp.response.VoiceResponse;
/**
*
* 响应类型
*
* @author jy.hu
*
*/
public enum ResponseType {
text(TextResponse.class), image(ImageResponse.class), voice(
VoiceResponse.class), video(VideoResponse.class), music(
MusicResponse.class), news(ArticleResponse.class), transfer_customer_service(
TransferResponse.class);
private Class<? extends BaseResponse> messageClass;
ResponseType(Class<? extends BaseResponse> messageClass) {
this.messageClass = messageClass;
}
public void setMessageClass(Class<? extends BaseResponse> messageClass) {
this.messageClass = messageClass;
}
public Class<? extends BaseResponse> getMessageClass() {
return messageClass;
}
}
@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- For assistance related to logback-translator or configuration -->
<!-- files in general, please contact the logback user mailing list -->
<!-- at http://www.qos.ch/mailman/listinfo/logback-user -->
<!-- -->
<!-- For professional support please see -->
<!-- http://www.qos.ch/shop/products/professionalSupport -->
<!-- -->
<configuration>
<!-- 控制台输出日志 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - %msg%n
</pattern>
</encoder>
</appender>
<!-- 文件输出指定项目日志 -->
<appender name="file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender -->
<!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy -->
<!--for further documentation -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/tmp/weixin/weixin.%d{yyyy-MM-dd}.log
</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<!-- 异步输出指定项目日志 -->
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file" />
</appender>
<logger name="org.apache" level="INFO">
<appender-ref ref="stdout" />
</logger>
<logger name="org.springframework" level="INFO">
<appender-ref ref="stdout" />
</logger>
<logger name="com.foxinmy.weixin4j" level="INFO">
<appender-ref ref="async" />
</logger>
</configuration>
@@ -1,2 +0,0 @@
port=8090
workerThreads=20
@@ -1,12 +0,0 @@
# \u516c\u4f17\u53f7\u4fe1\u606f
account={"appId":"wx4ab8f8de58159a57","appSecret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"token":"\u5f00\u653e\u8005\u7684token \u975e\u5fc5\u987b","openId":"\u516c\u4f17\u53f7\u7684openid \u975e\u5fc5\u987b",\
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7",\
"partnerId":"\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7","partnerKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5"}
# \u4f7f\u7528FileTokenHolder\u65f6token\u7684\u5b58\u653e\u8def\u5f84
token_path=/tmp/weixin/token
# \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84
qr_path=/tmp/weixin/qr
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84
media_path=/tmp/weixin/media
-142
View File
@@ -1,142 +0,0 @@
ulimit -n 110000
#JDK home
JAVA_HOME="/usr/local/java/"
#executing user
RUNNING_USER=root
#Run home
APP_HOME="/usr/local/weixin/weixin-service"
#main class
APP_MAINCLASS=com.foxinmy.weixin4j.mp.startup.WeixinServiceBootstrap
#classpath
CLASSPATH=$APP_HOME/classes
for i in "$APP_HOME"/lib/*.jar; do
CLASSPATH="$CLASSPATH":"$i"
done
CLASSPATH="$CLASSPATH":"$APP_HOME"/conf
#jvm options
JAVA_OPTS="-Xms256m -Xmx512m -Djava.awt.headless=true -XX:MaxPermSize=128m -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 -XX:+DisableExplicitGC -Xnoclassgc -Xverify:none"
#psid
psid=0
checkpid() {
javaps=`$JAVA_HOME/bin/jps -l | grep $APP_MAINCLASS`
if [ -n "$javaps" ]; then
psid=`echo $javaps | awk '{print $1}'`
else
psid=0
fi
}
###################################
#startup
###################################
start() {
checkpid
if [ $psid -ne 0 ]; then
echo "================================"
echo "warn: $APP_MAINCLASS already started! (pid=$psid)"
echo "================================"
else
echo -n "Starting $APP_MAINCLASS ..."
# JAVA_CMD="nohup $JAVA_HOME/bin/java $JAVA_OPTS -classpath $CLASSPATH $APP_MAINCLASS >/dev/null 2>&1 &"
JAVA_CMD="$JAVA_HOME/bin/java $JAVA_OPTS -classpath $CLASSPATH $APP_MAINCLASS &"
su - $RUNNING_USER -c "$JAVA_CMD"
checkpid
if [ $psid -ne 0 ]; then
echo "(pid=$psid) [OK]"
else
echo "[Failed]"
fi
fi
}
###################################
#stop
###################################
stop() {
checkpid
if [ $psid -ne 0 ]; then
echo -n "Stopping $APP_MAINCLASS ...(pid=$psid) "
su - $RUNNING_USER -c "kill -9 $psid"
if [ $? -eq 0 ]; then
echo "[OK]"
else
echo "[Failed]"
fi
checkpid
if [ $psid -ne 0 ]; then
stop
fi
else
echo "================================"
echo "warn: $APP_MAINCLASS is not running"
echo "================================"
fi
}
###################################
#status
###################################
status() {
checkpid
if [ $psid -ne 0 ]; then
echo "$APP_MAINCLASS is running! (pid=$psid)"
else
echo "$APP_MAINCLASS is not running"
fi
}
###################################
#info
###################################
info() {
echo "System Information:"
echo "****************************"
echo `head -n 1 /etc/issue`
echo `uname -a`
echo
echo "JAVA_HOME=$JAVA_HOME"
echo `$JAVA_HOME/bin/java -version`
echo
echo "APP_HOME=$APP_HOME"
echo "APP_MAINCLASS=$APP_MAINCLASS"
echo "****************************"
}
###################################
#access only 1 argument:{start|stop|restart|status|info}
###################################
case "$1" in
'start')
start
;;
'stop')
stop
;;
'restart')
stop
start
;;
'status')
status
;;
'info')
info
;;
*)
echo "Usage: $0 {start|stop|restart|status|info}"
exit 1
esac
exit 0
@@ -1,63 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.mp.api.GroupApi;
import com.foxinmy.weixin4j.mp.model.Group;
/**
* 用户分组测试
*
* @className GroupTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class GroupTest extends TokenTest {
private GroupApi groupApi;
@Before
public void init() {
groupApi = new GroupApi(tokenApi);
}
@Test
public void create() throws WeixinException {
Group group = groupApi.createGroup("my");
Assert.assertNotNull(group);
}
@Test
public void get() throws WeixinException {
List<Group> groups = groupApi.getGroups();
for (Group group : groups) {
System.out.println(group.toModifyJson());
}
Assert.assertEquals(1, groups.size());
}
@Test
public void getid() throws WeixinException {
int gid = groupApi.getGroupByOpenId("owGBft_vbBbOaQOmpEUE4xDLeRSU");
Assert.assertTrue(gid >= 0);
}
@Test
public void modify() throws WeixinException {
BaseResult result = groupApi.modifyGroup(100, "my1");
Assert.assertEquals(0, result.getErrcode());
}
@Test
public void move() throws WeixinException {
BaseResult result = groupApi.moveGroup("owGBft_vbBbOaQOmpEUE4xDLeRSU",
100);
Assert.assertEquals(0, result.getErrcode());
}
}
@@ -1,48 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 媒体上传下载测试
*
* @className MediaTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
* @see
*/
public class MediaTest extends TokenTest {
private MediaApi mediaApi;
@Before
public void init() {
mediaApi = new MediaApi(tokenApi);
}
@Test
public void upload() throws IOException, WeixinException {
File file = new File("/tmp/test.jpg");
String mediaId = mediaApi.uploadMedia(file, MediaType.image);
// vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay
Assert.assertNotNull(mediaId);
}
@Test
public void download() throws WeixinException, IOException {
File file = mediaApi
.downloadMedia(
"vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay",
MediaType.image);
Assert.assertTrue(file.exists());
}
}
@@ -1,64 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.mp.api.MenuApi;
import com.foxinmy.weixin4j.mp.model.Button;
import com.foxinmy.weixin4j.type.ButtonType;
/**
* 自定义菜单测试
*
* @className MenuTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class MenuTest extends TokenTest {
private MenuApi menuApi;
private List<Button> btnList;
@Before
public void init() {
menuApi = new MenuApi(tokenApi);
}
@Test
public void create() throws WeixinException {
btnList = new ArrayList<Button>();
Button b = new Button("click");
b.setType(ButtonType.click);
b.setKey("click");
btnList.add(b);
b = new Button("qq", "http://www.qq.com");
btnList.add(b);
BaseResult result = menuApi.createMenu(btnList);
Assert.assertEquals(0, result.getErrcode());
}
@Test
public void get() throws WeixinException {
btnList = menuApi.getMenu();
for (Button btn : btnList) {
System.out.println(btn);
}
Assert.assertEquals(1, btnList.size());
}
@Test
public void delete() throws WeixinException {
BaseResult result = menuApi.deleteMenu();
Assert.assertEquals(0, result.getErrcode());
}
}
@@ -1,44 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.mp.api.QrApi;
import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRParameter.QRType;
/**
* 二维码相关测试
*
* @className QRTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class QRTest extends TokenTest {
private QrApi qrApi;
@Before
public void init() {
qrApi = new QrApi(tokenApi);
}
@Test
public void temp_qr() throws WeixinException, IOException {
QRParameter qr = new QRParameter(1200, QRType.TEMPORARY, 2);
File file = qrApi.getQR(qr);
Assert.assertTrue(file.exists());
}
@Test
public void forever_qr() throws WeixinException, IOException {
QRParameter qr = new QRParameter(QRType.PERMANENCE, 1);
File file = qrApi.getQR(qr);
Assert.assertTrue(file.exists());
}
}
@@ -1,32 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* token测试
*
* @className TokenTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class TokenTest {
protected TokenHolder tokenApi;
@Before
public void setUp() {
tokenApi = new FileTokenHolder();
}
@Test
public void test() throws WeixinException {
Assert.assertNotNull(tokenApi.getToken());
}
}
@@ -1,51 +0,0 @@
package com.foxinmy.weixin4j.mp.test;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.mp.api.UserApi;
import com.foxinmy.weixin4j.mp.model.User;
/**
* 用户相关测试
*
* @className UserTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class UserTest extends TokenTest {
private UserApi userApi;
@Before
public void init() {
userApi = new UserApi(tokenApi);
}
@Test
public void getUser() throws WeixinException {
User user = userApi.getUser("owGBft_vbBbOaQOmpEUE4xDLeRSU");
Assert.assertNotNull(user);
}
@Test
public void following() throws WeixinException {
List<User> userList = userApi.getAllFollowing();
for (User user : userList) {
System.out.println(user);
}
Assert.assertTrue(!userList.isEmpty());
}
@Test
public void remark() throws WeixinException {
BaseResult result = userApi.remarkUserName(
"owGBft_vbBbOaQOmpEUE4xDLeRSU", "foo");
Assert.assertEquals(0, result.getErrcode());
}
}
@@ -1,179 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
/**
* 接收事件消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class EventMsgTest extends MessagePush {
private StringBuilder xmlSb = new StringBuilder();
/***************** event message *********************/
@Test
public void scribe() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void scan() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[SCAN]]></Event>");
xmlSb.append("<EventKey><![CDATA[SCENE_VALUE]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void scan_scribe() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml><ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("<EventKey><![CDATA[qrscene_123123]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[LOCATION]]></Event>");
xmlSb.append("<Latitude>23.137466</Latitude>");
xmlSb.append("<Longitude>113.352425</Longitude>");
xmlSb.append("<Precision>119.385040</Precision>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_click() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[EVENTKEY]]></EventKey>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_link() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[VIEW]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_scan() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[scancode_waitmsg]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>");
xmlSb.append("<ScanResult><![CDATA[1]]></ScanResult>");
xmlSb.append("</ScanCodeInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_photo() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[pic_weixin]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendPicsInfo><Count>1</Count>");
xmlSb.append("<PicList><item><PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>");
xmlSb.append("</item></PicList></SendPicsInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void menu_location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[location_select]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendLocationInfo><Location_X><![CDATA[23]]></Location_X>");
xmlSb.append("<Location_Y><![CDATA[113]]></Location_Y>");
xmlSb.append("<Scale><![CDATA[15]]></Scale>");
xmlSb.append("<Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>");
xmlSb.append("<Poiname><![CDATA[]]></Poiname></SendLocationInfo>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
}
@@ -1,144 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
/**
* 接受一般消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class InMsgTest extends MessagePush {
private StringBuilder xmlSb = new StringBuilder();
/***************** common message *********************/
@Test
public void text() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>1348831860</CreateTime>");
xmlSb.append("<MsgType><![CDATA[text]]></MsgType>");
xmlSb.append("<Content><![CDATA[this is a test]]></Content>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void image() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[image]]></MsgType>");
xmlSb.append("<PicUrl><![CDATA[this is a url]]></PicUrl>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void voice() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[voice]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<Format><![CDATA[Format]]></Format>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void re_voice() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[voice]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<Format><![CDATA[Format]]></Format>");
xmlSb.append("<Recognition><![CDATA[腾讯微信团队]]></Recognition>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void video() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[video]]></MsgType>");
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void location() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[location]]></MsgType>");
xmlSb.append("<Location_X>23.134521</Location_X>");
xmlSb.append("<Location_Y>113.358803</Location_Y>");
xmlSb.append("<Scale>20</Scale>");
xmlSb.append("<Label><![CDATA[位置信息]]></Label>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
@Test
public void link() throws WeixinException, IOException {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[link]]></MsgType>");
xmlSb.append("<Title><![CDATA[公众平台官网链接]]></Title>");
xmlSb.append("<Description><![CDATA[公众平台官网链接]]></Description>");
xmlSb.append("<Url><![CDATA[url]]></Url>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
String response = push(xmlSb.toString());
Assert.assertNotNull(response);
System.out.println(response);
}
}
@@ -1,93 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.mp.api.MassApi;
import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.model.MpArticle;
import com.foxinmy.weixin4j.mp.test.TokenTest;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 群发消息
*
* @className MpNewsTest
* @author jy
* @date 2014年4月27日
* @since JDK 1.7
* @see
*/
public class MassMsgTest extends TokenTest {
private MassApi massApi;
private MediaApi mediaApi;
@Before
public void init() {
this.massApi = new MassApi(tokenApi);
this.mediaApi = new MediaApi(tokenApi);
}
@Test
public void uploadArticle() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"),
MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
massApi.uploadArticle(articles);
}
@Test
public void uploadVideo() throws WeixinException {
String massId = massApi.uploadVideo("mediaId", "title", "desc");
Assert.assertTrue(massId != null);
}
@Test
public void massByGroup() throws WeixinException {
String massId = massApi.massByGroup("123", MediaType.image, "groupId");
Assert.assertTrue(massId != null);
}
@Test
public void massByOpenIds() throws WeixinException {
String massId = massApi
.massByOpenIds("123", MediaType.image, "openIds");
Assert.assertTrue(massId != null);
}
@Test
public void massArticleByGroup() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"),
MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
String massId = massApi.massArticleByGroup(articles, "0");
Assert.assertTrue(massId != null);
}
@Test
public void massArticleByOpenIds() throws IOException, WeixinException {
List<MpArticle> articles = new ArrayList<MpArticle>();
String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"),
MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
String massId = massApi.massArticleByOpenIds(articles,
"owGBft_vbBbOaQOmpEUE4xDLeRSU");
Assert.assertTrue(massId != null);
}
@Test
public void deleteMass() throws WeixinException {
BaseResult result = massApi.deleteMassNews("34182");
Assert.assertEquals(0, result.getErrcode());
}
}
@@ -1,48 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ResourceBundle;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import com.foxinmy.weixin4j.exception.WeixinException;
public class MessagePush {
private HttpClient httpClient;
private final HttpPost httpPost;
public MessagePush() {
this.httpClient = new DefaultHttpClient();
ResourceBundle config = ResourceBundle.getBundle("netty");
httpPost = new HttpPost();
httpPost.setURI(URI.create(String.format("http://localhost:%s",
Integer.parseInt(config.getString("port")))));
}
public String push(String xml) throws WeixinException, IOException {
httpPost.setEntity(new StringEntity(xml, StandardCharsets.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
StatusLine statusLine = httpResponse.getStatusLine();
int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new WeixinException(status + "", "request fail");
}
if (status == HttpStatus.SC_MOVED_PERMANENTLY
|| status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(status + "", "uri moved");
}
return EntityUtils.toString(httpResponse.getEntity(),
StandardCharsets.UTF_8);
}
}
@@ -1,104 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import java.io.File;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.BaseResult;
import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.api.NotifyApi;
import com.foxinmy.weixin4j.mp.msg.notify.ArticleNotify;
import com.foxinmy.weixin4j.mp.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.mp.msg.notify.ImageNotify;
import com.foxinmy.weixin4j.mp.msg.notify.MusicNotify;
import com.foxinmy.weixin4j.mp.msg.notify.TextNotify;
import com.foxinmy.weixin4j.mp.msg.notify.VideoNotify;
import com.foxinmy.weixin4j.mp.msg.notify.VoiceNotify;
import com.foxinmy.weixin4j.mp.test.TokenTest;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 客服消息测试
*
* @className MessageNotifyTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
* @see
*/
public class NotifyMsgTest extends TokenTest {
private NotifyApi notifyApi;
private MediaApi mediaApi;
@Before
public void init() {
notifyApi = new NotifyApi(tokenApi);
mediaApi = new MediaApi(tokenApi);
}
@Test
public void text() {
TextNotify notify = new TextNotify("123", "to");
System.out.println(notify.toJson());
}
@Test
public void image() {
ImageNotify notify = new ImageNotify("to");
notify.pushMediaId("123");
System.out.println(notify.toJson());
}
@Test
public void voice() {
VoiceNotify notify = new VoiceNotify("to");
notify.pushMediaId("123");
System.out.println(notify.toJson());
}
@Test
public void video() {
VideoNotify notify = new VideoNotify("to");
notify.pushVideo("123", "m123");
System.out.println(notify.toJson());
}
@Test
public void music() {
MusicNotify notify = new MusicNotify("to");
notify.pushMusic("url", "hqUrl", "mediaId");
System.out.println(notify.toJson());
}
@Test
public void article() {
ArticleNotify notify = new ArticleNotify("to");
notify.pushArticle("title1", "desc1", "picUrl1", "url1");
notify.pushArticle("title2", "desc2", "picUrl2", "url2");
System.out.println(notify.toJson());
}
@Test
public void send1() throws IOException, WeixinException {
BaseNotify notify = new TextNotify("this is a notify message!",
"owGBft_vbBbOaQOmpEUE4xDLeRSU");
BaseResult result = notifyApi.sendNotify(notify);
Assert.assertEquals(0, result.getErrcode());
}
@Test
public void send2() throws WeixinException, IOException {
String mediaId = mediaApi.uploadMedia(new File(
"/tmp/test.jpg"), MediaType.image);
ImageNotify imageNotify = new ImageNotify(
"owGBft_vbBbOaQOmpEUE4xDLeRSU");
imageNotify.pushMediaId(mediaId);
BaseResult result = notifyApi.sendNotify(imageNotify);
Assert.assertEquals(0, result.getErrcode());
}
}
@@ -1,73 +0,0 @@
package com.foxinmy.weixin4j.mp.test.msg;
import org.dom4j.DocumentException;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.mp.response.ArticleResponse;
import com.foxinmy.weixin4j.mp.response.ImageResponse;
import com.foxinmy.weixin4j.mp.response.MusicResponse;
import com.foxinmy.weixin4j.mp.response.VideoResponse;
import com.foxinmy.weixin4j.mp.response.VoiceResponse;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.TextMessage;
/**
* 发送消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class OutMsgTest {
private BaseMessage inMessage;
@Before
public void init() {
this.inMessage = new TextMessage();
this.inMessage.setFromUserName("fromusername");
this.inMessage.setToUserName("tousername");
}
@Test
public void text() throws DocumentException {
TextMessage message = new TextMessage("text", inMessage);
System.out.println(message.toXml());
}
@Test
public void image() {
ImageResponse message = new ImageResponse(inMessage);
message.pushMediaId("mediaId");
System.out.println(message.toXml());
}
@Test
public void voice() {
VoiceResponse message = new VoiceResponse(inMessage);
message.pushMediaId("mediaId");
System.out.println(message.toXml());
}
@Test
public void video() {
VideoResponse message = new VideoResponse(inMessage);
message.pushVideo("mediaId");
System.out.println(message.toXml());
}
@Test
public void music() {
MusicResponse message = new MusicResponse(inMessage);
message.pushMusic("mediaId");
System.out.println(message.toXml());
}
@Test
public void article() {
ArticleResponse message = new ArticleResponse(inMessage);
message.pushArticle("title1", "desc1", "picUrl1", "url1");
message.pushArticle("title2", "desc2", "picUrl2", "url2");
System.out.println(message.toXml());
}
}

Some files were not shown because too many files have changed in this diff Show More