新增企业号工程并完成【部门管理】【成员管理】【标签管理】三个接口

This commit is contained in:
jy.hu 2014-11-19 21:26:11 +08:00
parent f4aec9dc99
commit 5b213cd87f
69 changed files with 2741 additions and 466 deletions

View File

@ -81,6 +81,18 @@ weixin4j
* 2014-11-17
+ **weixin4j-mp**: 新增`冲正``被扫支付`接口
* 2014-11-19
+ **weixin4j-base**: 新增`WeixinQyAccount`企业号账号信息类
+ **weixin4j-qy**: 得到`weixin4j-qy``weixin4j-qy-server`工程
+ **weixin4j-qy**: 新增`部门管理`接口
+ **weixin4j-qy**: 新增`用户管理`接口
+ **weixin4j-qy**: 新增`标签管理`接口
接下来
------

23
pom.xml
View File

@ -131,6 +131,29 @@
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven.assembly.plugin.version}</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<resources>
<resource>
<directory>src/main/java</directory>

View File

@ -25,4 +25,8 @@ weixin4j-base
* 2014-11-15
+ 新增`aes加密解密`函数
+ 新增`aes加密解密`函数
* 2014-11-19
+ 新增`WeixinQyAccount`企业号账号信息类

View File

@ -11,7 +11,7 @@
<desc>system error</desc>
<text>系统繁忙</text>
</error>
<!-- 公众平台API错误 -->
<!-- 公众平台&企业号API错误 -->
<error>
<code>40001</code>
<desc>invalid credential</desc>
@ -32,6 +32,14 @@
<desc>invalid media type</desc>
<text>不合法的媒体文件类型</text>
</error>
<error>
<code>40005</code>
<text>不合法的文件类型</text>
</error>
<error>
<code>40006</code>
<text>不合法的文件大小</text>
</error>
<error>
<code>40007</code>
<desc>invalid media_id</desc>
@ -102,6 +110,14 @@
<desc>invalid button url size</desc>
<text>不合法的url长度</text>
</error>
<error>
<code>40021</code>
<text>不合法的菜单版本号</text>
</error>
<error>
<code>40022</code>
<text>不合法的子菜单级数</text>
</error>
<error>
<code>40023</code>
<desc>invalid sub button size</desc>
@ -127,6 +143,10 @@
<desc>invalid sub button url size</desc>
<text>不合法的子菜单按钮url长度</text>
</error>
<error>
<code>40028</code>
<text>不合法的自定义菜单使用员工</text>
</error>
<error>
<code>40029</code>
<desc>invalid code</desc>
@ -137,6 +157,22 @@
<desc>invalid refresh_token</desc>
<text>不合法的refresh_token</text>
</error>
<error>
<code>40031</code>
<text>不合法的UserID列表</text>
</error>
<error>
<code>40032</code>
<text>不合法的UserID列表长度</text>
</error>
<error>
<code>40033</code>
<text>不合法的请求字符,不能包含\uxxxx格式的字符</text>
</error>
<error>
<code>40035</code>
<text>不合法的参数</text>
</error>
<error>
<code>40036</code>
<desc>invalid template_id size</desc>
@ -147,11 +183,27 @@
<desc>invalid template_id</desc>
<text>不合法的template_id</text>
</error>
<error>
<code>40038</code>
<text>不合法的请求格式</text>
</error>
<error>
<code>40039</code>
<desc>invalid url size</desc>
<text>不合法的url长度</text>
</error>
<error>
<code>40040</code>
<text>不合法的插件token</text>
</error>
<error>
<code>40041</code>
<text>不合法的插件id</text>
</error>
<error>
<code>40042</code>
<text>不合法的插件会话</text>
</error>
<error>
<code>40048</code>
<desc>invalid url domain</desc>
@ -167,10 +219,82 @@
<desc>invalid button url domain</desc>
<text>不合法的菜单按钮url域名</text>
</error>
<error>
<code>40056</code>
<text>不合法的agentid</text>
</error>
<error>
<code>40057</code>
<text>不合法的callbackurl</text>
</error>
<error>
<code>40058</code>
<text>不合法的红包参数</text>
</error>
<error>
<code>40059</code>
<text>不合法的上报地理位置标志位</text>
</error>
<error>
<code>40060</code>
<text>设置上报地理位置标志位时没有设置callbackurl</text>
</error>
<error>
<code>40061</code>
<text>设置应用头像失败</text>
</error>
<error>
<code>40062</code>
<text>不合法的应用模式</text>
</error>
<error>
<code>40063</code>
<text>红包参数为空</text>
</error>
<error>
<code>40064</code>
<text>管理组名字已存在</text>
</error>
<error>
<code>40065</code>
<text>不合法的管理组名字长度</text>
</error>
<error>
<code>40066</code>
<desc>invalid url</desc>
<text>不合法的url</text>
<desc>invalid url/department</desc>
<text>不合法的url/不合法的部门列表</text>
</error>
<error>
<code>40067</code>
<text>标题长度不合法</text>
</error>
<error>
<code>40068</code>
<text>不合法的标签ID</text>
</error>
<error>
<code>40069</code>
<text>不合法的标签ID列表</text>
</error>
<error>
<code>40070</code>
<text>列表中所有标签用户ID都不合法</text>
</error>
<error>
<code>40071</code>
<text>不合法的标签名字,标签名字已经存在</text>
</error>
<error>
<code>40072</code>
<text>不合法的标签名字长度</text>
</error>
<error>
<code>40073</code>
<text>不合法的openid</text>
</error>
<error>
<code>40074</code>
<text>news消息不支持指定为高保密消息</text>
</error>
<error>
<code>41001</code>
@ -222,6 +346,38 @@
<desc>missing url</desc>
<text>缺失url参数</text>
</error>
<error>
<code>41011</code>
<text>缺少agentid</text>
</error>
<error>
<code>41012</code>
<text>缺少应用头像mediaid</text>
</error>
<error>
<code>41013</code>
<text>缺少应用名字</text>
</error>
<error>
<code>41014</code>
<text>缺少应用描述</text>
</error>
<error>
<code>41015</code>
<text>缺少Content</text>
</error>
<error>
<code>41016</code>
<text>缺少标题</text>
</error>
<error>
<code>41017</code>
<text>缺少标签ID</text>
</error>
<error>
<code>41018</code>
<text>缺少标签名字</text>
</error>
<error>
<code>42001</code>
<desc>access_token expired</desc>
@ -237,6 +393,10 @@
<desc>code expired</desc>
<text>code超时</text>
</error>
<error>
<code>42004</code>
<text>插件token超时</text>
</error>
<error>
<code>43001</code>
<desc>require GET method</desc>
@ -257,6 +417,34 @@
<desc>require subscribe</desc>
<text>需要订阅关系</text>
</error>
<error>
<code>43005</code>
<text>需要好友关系</text>
</error>
<error>
<code>43006</code>
<text>需要订阅</text>
</error>
<error>
<code>43007</code>
<text>需要授权</text>
</error>
<error>
<code>43008</code>
<text>需要支付授权</text>
</error>
<error>
<code>43009</code>
<text>需要员工已关注</text>
</error>
<error>
<code>43010</code>
<text>需要处于回调模式</text>
</error>
<error>
<code>43011</code>
<text>需要企业授权</text>
</error>
<error>
<code>44001</code>
<desc>empty media data</desc>
@ -342,6 +530,10 @@
<desc>template size out of limit</desc>
<text>模板大小超过限制</text>
</error>
<error>
<code>45015</code>
<text>回复时间超过限制</text>
</error>
<error>
<code>45016</code>
<desc>can't modify sys group</desc>
@ -357,11 +549,176 @@
<desc>too many group now, no need to add new</desc>
<text>组数量过多</text>
</error>
<error>
<code>45024</code>
<text>账号数量超过上限</text>
</error>
<error>
<code>46001</code>
<text>不存在媒体数据</text>
</error>
<error>
<code>46002</code>
<text>不存在的菜单版本</text>
</error>
<error>
<code>46003</code>
<text>不存在的菜单数据</text>
</error>
<error>
<code>46004</code>
<text>不存在的员工</text>
</error>
<error>
<code>47001</code>
<text>解析JSON/XML内容错误</text>
</error>
<error>
<code>48002</code>
<text>Api禁用</text>
</error>
<error>
<code>50001</code>
<desc>api unauthorized</desc>
<desc>api/redirect_uri unauthorized</desc>
<text>接口未授权</text>
</error>
<error>
<code>50002</code>
<text>员工不在权限范围</text>
</error>
<error>
<code>50003</code>
<text>应用已停用</text>
</error>
<error>
<code>50004</code>
<text>员工状态不正确(未关注状态)</text>
</error>
<error>
<code>50005</code>
<text>企业已禁用</text>
</error>
<!-- 企业号API错误 -->
<error>
<code>60001</code>
<text>部门长度不符合限制</text>
</error>
<error>
<code>60002</code>
<text>部门层级深度超过限制</text>
</error>
<error>
<code>60003</code>
<text>部门不存在</text>
</error>
<error>
<code>60004</code>
<text>父亲部门不存在</text>
</error>
<error>
<code>60005</code>
<text>不允许删除有成员的部门</text>
</error>
<error>
<code>60006</code>
<text>不允许删除有子部门的部门</text>
</error>
<error>
<code>60007</code>
<text>不允许删除根部门</text>
</error>
<error>
<code>60008</code>
<text>部门名称已存在</text>
</error>
<error>
<code>60009</code>
<text>部门名称含有非法字符</text>
</error>
<error>
<code>60010</code>
<text>部门存在循环关系</text>
</error>
<error>
<code>60011</code>
<text>管理员权限不足(user/department/agent)无权限</text>
</error>
<error>
<code>60012</code>
<text>不允许删除默认应用</text>
</error>
<error>
<code>60013</code>
<text>不允许关闭应用</text>
</error>
<error>
<code>60014</code>
<text>不允许开启应用</text>
</error>
<error>
<code>60015</code>
<text>不允许修改默认应用可见范围</text>
</error>
<error>
<code>60016</code>
<text>不允许删除存在成员的标签</text>
</error>
<error>
<code>60017</code>
<text>不允许设置企业</text>
</error>
<error>
<code>60102</code>
<text>UserID已存在</text>
</error>
<error>
<code>60103</code>
<text>手机号码不合法</text>
</error>
<error>
<code>60104</code>
<text>手机号码已存在</text>
</error>
<error>
<code>60105</code>
<text>邮箱不合法</text>
</error>
<error>
<code>60106</code>
<text>邮箱已存在</text>
</error>
<error>
<code>60107</code>
<text>微信号不合法</text>
</error>
<error>
<code>60108</code>
<text>微信号已存在</text>
</error>
<error>
<code>60109</code>
<text>QQ号已存在</text>
</error>
<error>
<code>60110</code>
<text>部门个数超出限制</text>
</error>
<error>
<code>60111</code>
<text>UserID不存在</text>
</error>
<error>
<code>60112</code>
<text>成员姓名不合法</text>
</error>
<error>
<code>60113</code>
<text>身份认证信息(微信号/手机/邮箱)不能同时为空</text>
</error>
<error>
<code>60114</code>
<text>性别不合法</text>
</error>
<!-- 语义理解API错误 -->
<error>
<code>7000000</code>

View File

@ -11,4 +11,12 @@ public final class Consts {
public static final String AES = "AES";
public static final String PROTOCOL_FILE = "file";
public static final String PROTOCOL_JAR = "jar";
public static final String MP_ASSESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
public static final String QY_ASSESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s";
public static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
public static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay";
public static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s&timestamp=%s&noncestr=%s";
public static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s";
}

View File

@ -0,0 +1,14 @@
package com.foxinmy.weixin4j.model;
/**
* 用户性别
*
* @className Gender
* @author jy
* @date 2014年11月5日
* @since JDK 1.7
* @see
*/
public enum Gender {
male, female, unknown;
}

View File

@ -2,48 +2,51 @@ package com.foxinmy.weixin4j.model;
import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
/**
* 微信账信息
* 微信账号信息
*
* @className WeixinAccount
* @author jy
* @date 2014年8月17
* @date 2014年11月18
* @since JDK 1.7
* @see
*/
public class WeixinAccount implements Serializable {
private static final long serialVersionUID = 3689999353867189585L;
public abstract class WeixinAccount implements Serializable {
private static final long serialVersionUID = -6001008896414323534L;
// 唯一的身份标识
private String id;
// 调用接口的密钥
private String secret;
private String token;
// 支付场景下为用户的openid 其余情况可能是公众号的原始ID
private String openId;
// 公众号身份的唯一标识
private String appId;
// 公众平台接口 API 的权限获取所需密钥 Key
private String appSecret;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
private String paySignKey;
// 安全模式下的加密密钥
private String encodingAesKey;
// 财付通商户身份的标识
private String partnerId;
// 财付通商户权限密钥Key
private String partnerKey;
// 微信支付商户号V3.x版本
private String mchId;
// 微信支付分配的设备号
private String deviceInfo;
// 微信支付版本号(如果无则按照mchId来做判断)
private int version;
// 是否已经认证
private boolean isAlive;
// 是否是服务号
private boolean isService;
// 是否是订阅号
private boolean isSubscribe;
public abstract String getTokenUrl();
public WeixinAccount() {
}
public WeixinAccount(String id, String secret) {
this.id = id;
this.secret = secret;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getToken() {
return token;
@ -53,30 +56,6 @@ public class WeixinAccount implements Serializable {
this.token = token;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
public String getEncodingAesKey() {
return encodingAesKey;
}
@ -85,130 +64,9 @@ public class WeixinAccount implements Serializable {
this.encodingAesKey = encodingAesKey;
}
public String getPaySignKey() {
return paySignKey;
}
public void setPaySignKey(String paySignKey) {
this.paySignKey = paySignKey;
}
public String getPartnerId() {
return partnerId;
}
public void setPartnerId(String partnerId) {
this.partnerId = partnerId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getDeviceInfo() {
return deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public boolean getIsAlive() {
return isAlive;
}
public void setIsAlive(Boolean isAlive) {
this.isAlive = isAlive;
}
public boolean getIsService() {
return isService;
}
public void setIsService(Boolean isService) {
this.isService = isService;
}
public boolean getIsSubscribe() {
return isSubscribe;
}
public void setIsSubscribe(Boolean isSubscribe) {
this.isSubscribe = isSubscribe;
}
public int getVersion() {
if (version == 0) {
return StringUtils.isNotBlank(mchId) ? 3 : 2;
}
return version;
}
public void setVersion(int version) {
this.version = version;
}
public WeixinAccount() {
}
public WeixinAccount(String appId, String appSecret) {
this.appId = appId;
this.appSecret = appSecret;
}
/**
* V3版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param mchId
*/
public WeixinAccount(String appId, String appSecret, String paySignKey,
String mchId) {
this(appId, appSecret);
this.paySignKey = paySignKey;
this.mchId = mchId;
}
/**
* V2版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param partnerId
* @param partnerKey
*/
public WeixinAccount(String appId, String appSecret, String paySignKey,
String partnerId, String partnerKey) {
this(appId, appSecret);
this.paySignKey = paySignKey;
this.partnerId = partnerId;
this.partnerKey = partnerKey;
}
@Override
public String toString() {
return "WeixinAccount [token=" + token + ", openId=" + openId
+ ", appId=" + appId + ", appSecret=" + appSecret
+ ", encodingAesKey=" + encodingAesKey + ", paySignKey="
+ paySignKey + ", partnerId=" + partnerId + ", partnerKey="
+ partnerKey + ", mchId=" + mchId + ", deviceInfo="
+ deviceInfo + ", isAlive=" + isAlive + ", isService="
+ isService + ", isSubscribe=" + isSubscribe + "]";
return "WeixinAccount [id=" + id + ", secret=" + secret + ", token="
+ token + ", encodingAesKey=" + encodingAesKey + "]";
}
}

View File

@ -0,0 +1,178 @@
package com.foxinmy.weixin4j.model;
import org.apache.commons.lang3.StringUtils;
/**
* 微信公众平台信息
*
* @className WeixinMpAccount
* @author jy
* @date 2014年8月17日
* @since JDK 1.7
* @see
*/
public class WeixinMpAccount extends WeixinAccount {
private static final long serialVersionUID = 3689999353867189585L;
// 支付场景下为用户的openid 其余情况可能是公众号的原始ID
private String openId;
// 公众号支付请求中用于加密的密钥 Key,可验证商户唯一身份,PaySignKey 对应于支付场景中的 appKey
private String paySignKey;
// 财付通商户身份的标识
private String partnerId;
// 财付通商户权限密钥Key
private String partnerKey;
// 微信支付商户号V3.x版本
private String mchId;
// 微信支付分配的设备号
private String deviceInfo;
// 微信支付版本号(如果无则按照mchId来做判断)
private int version;
// 是否已经认证
private boolean isAlive;
// 是否是服务号
private boolean isService;
// 是否是订阅号
private boolean isSubscribe;
@Override
public String getTokenUrl() {
return String.format(Consts.MP_ASSESS_TOKEN_URL, getId(), getSecret());
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getPaySignKey() {
return paySignKey;
}
public void setPaySignKey(String paySignKey) {
this.paySignKey = paySignKey;
}
public String getPartnerId() {
return partnerId;
}
public void setPartnerId(String partnerId) {
this.partnerId = partnerId;
}
public String getPartnerKey() {
return partnerKey;
}
public void setPartnerKey(String partnerKey) {
this.partnerKey = partnerKey;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getDeviceInfo() {
return deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public boolean getIsAlive() {
return isAlive;
}
public void setIsAlive(Boolean isAlive) {
this.isAlive = isAlive;
}
public boolean getIsService() {
return isService;
}
public void setIsService(Boolean isService) {
this.isService = isService;
}
public boolean getIsSubscribe() {
return isSubscribe;
}
public void setIsSubscribe(Boolean isSubscribe) {
this.isSubscribe = isSubscribe;
}
public int getVersion() {
if (version == 0) {
return StringUtils.isNotBlank(mchId) ? 3 : 2;
}
return version;
}
public void setVersion(int version) {
this.version = version;
}
public WeixinMpAccount() {
}
public WeixinMpAccount(String appId, String appSecret) {
super(appId, appSecret);
}
/**
* V3版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param mchId
*/
public WeixinMpAccount(String appId, String appSecret, String paySignKey,
String mchId) {
this(appId, appSecret);
this.paySignKey = paySignKey;
this.mchId = mchId;
}
/**
* V2版本字段
*
* @param appId
* @param appSecret
* @param paySignKey
* @param partnerId
* @param partnerKey
*/
public WeixinMpAccount(String appId, String appSecret, String paySignKey,
String partnerId, String partnerKey) {
this(appId, appSecret);
this.paySignKey = paySignKey;
this.partnerId = partnerId;
this.partnerKey = partnerKey;
}
@Override
public String toString() {
return "WeixinMpAccount [openId=" + openId + ", paySignKey="
+ paySignKey + ", partnerId=" + partnerId + ", partnerKey="
+ partnerKey + ", mchId=" + mchId + ", deviceInfo="
+ deviceInfo + ", version=" + version + ", isAlive=" + isAlive
+ ", isService=" + isService + ", isSubscribe=" + isSubscribe
+ ", getId()=" + getId() + ", getSecret()=" + getSecret()
+ ", getToken()=" + getToken() + ", getEncodingAesKey()="
+ getEncodingAesKey() + "]";
}
}

View File

@ -0,0 +1,34 @@
package com.foxinmy.weixin4j.model;
/**
* 微信企业号信息
*
* @className WeixinQyAccount
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see
*/
public class WeixinQyAccount extends WeixinAccount {
private static final long serialVersionUID = 3689999353867189585L;
public WeixinQyAccount() {
}
public WeixinQyAccount(String corpid, String corpsecret) {
super(corpid, corpsecret);
}
@Override
public String getTokenUrl() {
return String.format(Consts.QY_ASSESS_TOKEN_URL, getId(), getSecret());
}
@Override
public String toString() {
return "WeixinQyAccount [getTokenUrl()=" + getTokenUrl() + ", getId()="
+ getId() + ", getSecret()=" + getSecret() + ", getToken()="
+ getToken() + ", getEncodingAesKey()=" + getEncodingAesKey()
+ "]";
}
}

View File

@ -1,15 +1,8 @@
package com.foxinmy.weixin4j.msg;
import java.io.Writer;
import com.foxinmy.weixin4j.model.BaseMsg;
import com.foxinmy.weixin4j.type.MessageType;
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;
/**
* 普通消息基类
@ -26,32 +19,12 @@ import com.thoughtworks.xstream.io.json.JsonWriter;
public class BaseMessage extends BaseMsg {
private static final long serialVersionUID = 7761192742840031607L;
private 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("MsgType")
private MessageType msgType; // 消息类型
@XStreamAlias("MsgId")
private long msgId; // 消息ID
static {
Class<?>[] classes = ClassUtil.getClasses(
TextMessage.class.getPackage()).toArray(new Class[0]);
xmlStream.processAnnotations(classes);
xmlStream.omitField(BaseMessage.class, "msgId");
jsonStream.setMode(XStream.NO_REFERENCES);
jsonStream.autodetectAnnotations(true);
jsonStream.processAnnotations(classes);
jsonStream.omitField(BaseMessage.class, "msgId");
}
public BaseMessage(MessageType msgType) {
this.msgType = msgType;
}
@ -79,25 +52,4 @@ public class BaseMessage extends BaseMsg {
}
return false;
}
/**
* 消息对象转换为微信服务器接受的xml格式消息
*
* @return xml字符串
*/
public String toXml() {
Class<? extends BaseMessage> targetClass = getMsgType()
.getMessageClass();
xmlStream.alias("xml", targetClass);
return xmlStream.toXML(this);
}
/**
* 消息对象转换为微信服务器接受的json格式字符串
*
* @return json字符串
*/
public String toJson() {
return jsonStream.toXML(this);
}
}

View File

@ -2,10 +2,11 @@ package com.foxinmy.weixin4j.token;
import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 获取weixin.properties中的appid&appsecret信息
* 获取weixin.properties中的id&secret信息
*
* @className AbstractTokenHolder
* @author jy
@ -14,12 +15,18 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
* @see
*/
public abstract class AbstractTokenHolder implements TokenHolder {
protected final String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
protected final HttpRequest request = new HttpRequest();
private final WeixinAccount weixinAccount;
public AbstractTokenHolder() {
this.weixinAccount = ConfigUtil.getWeixinAccount();
protected final HttpRequest request = new HttpRequest();
protected final WeixinAccount weixinAccount;
public AbstractTokenHolder(AccountType accountType) {
if (accountType == AccountType.MP) {
this.weixinAccount = ConfigUtil.getWeixinMpAccount();
} else if (accountType == AccountType.QY) {
this.weixinAccount = ConfigUtil.getWeixinQyAccount();
} else {
this.weixinAccount = null;
}
}
public AbstractTokenHolder(WeixinAccount weixinAccount) {

View File

@ -13,6 +13,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.xml.XStream;
@ -24,23 +25,20 @@ import com.foxinmy.weixin4j.xml.XStream;
* @date 2014年9月27日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">微信公众平台获取token说明</a>
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8">微信企业号获取token说明</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class FileTokenHolder extends AbstractTokenHolder {
public FileTokenHolder() {
super();
public FileTokenHolder(AccountType accountType) {
super(accountType);
}
public FileTokenHolder(WeixinAccount weixinAccount) {
super(weixinAccount);
}
public FileTokenHolder(String appid, String appsecret) {
this(new WeixinAccount(appid, appsecret));
}
/**
* 获取token
* <p>
@ -55,14 +53,13 @@ public class FileTokenHolder extends AbstractTokenHolder {
*/
@Override
public Token getToken() throws WeixinException {
String appid = getAccount().getAppId();
String appsecret = getAccount().getAppSecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
String id = weixinAccount.getId();
if (StringUtils.isBlank(id) || StringUtils.isBlank(weixinAccount.getSecret())) {
throw new IllegalArgumentException(
"appid or appsecret not be null!");
"id or secret not be null!");
}
File token_file = new File(String.format("%s/token_%s.xml",
ConfigUtil.getValue("token_path"), appid));
ConfigUtil.getValue("token_path"), id));
Token token = null;
Calendar ca = Calendar.getInstance();
long now_time = ca.getTimeInMillis();
@ -78,8 +75,7 @@ public class FileTokenHolder extends AbstractTokenHolder {
} else {
token_file.createNewFile();
}
String api_token_uri = String.format(tokenUrl, appid, appsecret);
Response response = request.get(api_token_uri);
Response response = request.get(weixinAccount.getTokenUrl());
token = response.getAsObject(new TypeReference<Token>() {
});
token.setTime(now_time);

View File

@ -11,6 +11,7 @@ import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.type.AccountType;
/**
* 基于redis保存的Token获取类
@ -20,7 +21,10 @@ import com.foxinmy.weixin4j.model.WeixinAccount;
* @date 2014年9月27日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">微信公众平台获取token说明</a>
* @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8"
* >微信企业号获取token说明</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class RedisTokenHolder extends AbstractTokenHolder {
@ -37,47 +41,39 @@ public class RedisTokenHolder extends AbstractTokenHolder {
this.jedisPool = new JedisPool(poolConfig, host, port);
}
public RedisTokenHolder() {
this("localhost", 6379);
}
public RedisTokenHolder(String host, int port) {
super();
public RedisTokenHolder(String host, int port, AccountType accountType) {
super(accountType);
createPool(host, port);
}
public RedisTokenHolder(AccountType accountType) {
this("localhost", 6379, accountType);
}
public RedisTokenHolder(WeixinAccount weixinAccount) {
this(weixinAccount, "localhost", 6379);
this("localhost", 6379, weixinAccount);
}
public RedisTokenHolder(String appId, String appSecret, String host,
int port) {
this(new WeixinAccount(appId, appSecret), host, port);
}
public RedisTokenHolder(WeixinAccount weixinAccount, String host, int port) {
public RedisTokenHolder(String host, int port, WeixinAccount weixinAccount) {
super(weixinAccount);
createPool(host, port);
}
@Override
public Token getToken() throws WeixinException {
String appid = getAccount().getAppId();
String appsecret = getAccount().getAppSecret();
if (StringUtils.isBlank(appid) || StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException(
"appid or appsecret not be null!");
String id = weixinAccount.getId();
if (StringUtils.isBlank(id)
|| StringUtils.isBlank(weixinAccount.getSecret())) {
throw new IllegalArgumentException("id or secret not be null!");
}
Token token = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String key = String.format("token:%s", appid);
String key = String.format("token:%s", id);
String accessToken = jedis.get(key);
if (StringUtils.isBlank(accessToken)) {
String api_token_uri = String
.format(tokenUrl, appid, appsecret);
token = request.get(api_token_uri).getAsObject(
token = request.get(weixinAccount.getTokenUrl()).getAsObject(
new TypeReference<Token>() {
});
jedis.setex(key, token.getExpiresIn() - 3,

View File

@ -18,6 +18,5 @@ import com.foxinmy.weixin4j.model.WeixinAccount;
*/
public interface TokenHolder {
public WeixinAccount getAccount();
public Token getToken() throws WeixinException;
}

View File

@ -0,0 +1,14 @@
package com.foxinmy.weixin4j.type;
/**
* 账号类型
*
* @className AccountType
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see
*/
public enum AccountType {
MP, QY
}

View File

@ -5,7 +5,8 @@ import java.util.ResourceBundle;
import java.util.Set;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.model.WeixinQyAccount;
/**
* 商户配置工具类
@ -33,8 +34,13 @@ public class ConfigUtil {
return weixinBundle.getString(key);
}
public static WeixinAccount getWeixinAccount() {
public static WeixinMpAccount getWeixinMpAccount() {
String text = getValue("account");
return JSON.parseObject(text, WeixinAccount.class);
return JSON.parseObject(text, WeixinMpAccount.class);
}
public static WeixinQyAccount getWeixinQyAccount() {
String text = getValue("account");
return JSON.parseObject(text, WeixinQyAccount.class);
}
}

View File

@ -19,29 +19,6 @@
</modules>
<build>
<finalName>weixin4j-mp</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${maven.assembly.plugin.version}</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>

View File

@ -46,7 +46,7 @@ weixin.properties说明
示例(properties中换行用右斜杆\\)
> account={"appId":"appId","appSecret":"appSecret",
> account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 非必须","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」需要填入",
> "mchId":"V3.x版本下的微信商户号",
@ -69,7 +69,6 @@ weixin.properties说明
3.针对`token`存储有两种方案,`File存储`/`Redis存储`,当然也可自己实现`TokenHolder`(继承`AbstractTokenHolder`并重写`getToken`方法),默认使用文件(xml)的方式保存token,如果环境中支持`redis`,建议使用`RedisTokenHolder`.
WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenHolder());
// weixinProxy = new WeixinProxy(new RedisTokenHolder(appid,appsecret));
// weixinProxy = new WeixinProxy(new RedisTokenHolder(weixinAccount));
4.`mvn package`.

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>weixin4j-mp-api</artifactId>
<name>weixin4j-mp-api</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp/weixin4j-api</url>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp/weixin4j-mp-api</url>
<description>微信公众号API</description>
<build>
<finalName>weixin4j-mp-api</finalName>

View File

@ -10,7 +10,7 @@ import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.api.CustomApi;
import com.foxinmy.weixin4j.mp.api.GroupApi;
import com.foxinmy.weixin4j.mp.api.HelperApi;
@ -45,10 +45,11 @@ import com.foxinmy.weixin4j.mp.type.BillType;
import com.foxinmy.weixin4j.mp.type.IdQuery;
import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.AccountType;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 微信服务实现
* 微信公众平台接口实现
*
* @className WeixinProxy
* @author jy.hu
@ -74,18 +75,18 @@ public class WeixinProxy {
* 默认采用文件存放Token信息
*/
public WeixinProxy() {
this(new FileTokenHolder());
this(new FileTokenHolder(AccountType.MP));
}
/**
* appid,appsecret<br/>
* appid,appsecret<br>
* <font color="red">将无法调用支付相关接口</font>
*
* @param appid
* @param appsecret
*/
public WeixinProxy(String appid, String appsecret) {
this(new FileTokenHolder(appid, appsecret));
this(new WeixinMpAccount(appid, appsecret));
}
/**
@ -93,7 +94,7 @@ public class WeixinProxy {
*
* @param weixinAccount
*/
public WeixinProxy(WeixinAccount weixinAccount) {
public WeixinProxy(WeixinMpAccount weixinAccount) {
this(new FileTokenHolder(weixinAccount));
}
@ -793,7 +794,7 @@ public class WeixinProxy {
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.PayApi
*/
public Order orderQueryV2(WeixinAccount weixinAccount, String outTradeNo)
public Order orderQueryV2(WeixinMpAccount weixinAccount, String outTradeNo)
throws WeixinException {
return payApi.orderQueryV2(outTradeNo);
}

View File

@ -8,7 +8,7 @@ import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.model.SemQuery;
import com.foxinmy.weixin4j.mp.model.SemResult;
import com.foxinmy.weixin4j.token.TokenHolder;
@ -65,10 +65,10 @@ public class HelperApi extends BaseApi {
* @throws WeixinException
*/
public SemResult semantic(SemQuery semQuery) throws WeixinException {
WeixinAccount weixinAccount = tokenHolder.getAccount();
WeixinMpAccount weixinAccount = (WeixinMpAccount) tokenHolder.getAccount();
String semantic_uri = getRequestUri("semantic_uri");
Token token = tokenHolder.getToken();
semQuery.appid(weixinAccount.getAppId());
semQuery.appid(weixinAccount.getId());
Response response = request.post(
String.format(semantic_uri, token.getAccessToken()),
semQuery.toJson());

View File

@ -41,7 +41,7 @@ import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.http.SSLHttpRequest;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.ApiResult;
import com.foxinmy.weixin4j.mp.payment.PayUtil;
import com.foxinmy.weixin4j.mp.payment.Refund;
@ -70,11 +70,11 @@ import com.foxinmy.weixin4j.util.RandomUtil;
*/
public class PayApi extends BaseApi {
private final TokenHolder tokenHolder;
private final WeixinAccount weixinAccount;
private final WeixinMpAccount weixinAccount;
public PayApi(TokenHolder tokenHolder) {
this.tokenHolder = tokenHolder;
this.weixinAccount = tokenHolder.getAccount();
this.weixinAccount = (WeixinMpAccount) tokenHolder.getAccount();
}
/**
@ -101,7 +101,7 @@ public class PayApi extends BaseApi {
Token token = tokenHolder.getToken();
Map<String, String> param = new HashMap<String, String>();
param.put("appid", weixinAccount.getAppId());
param.put("appid", weixinAccount.getId());
param.put("appkey", weixinAccount.getPaySignKey());
param.put("openid", openId);
param.put("transid", transid);
@ -142,14 +142,14 @@ public class PayApi extends BaseApi {
String timestamp = DateUtil.timestamp2string();
JSONObject obj = new JSONObject();
obj.put("appid", weixinAccount.getAppId());
obj.put("appid", weixinAccount.getId());
obj.put("appkey", weixinAccount.getPaySignKey());
obj.put("package", sb.toString());
obj.put("timestamp", timestamp);
String signature = PayUtil.paysignSha(obj, null);
obj.clear();
obj.put("appid", weixinAccount.getAppId());
obj.put("appid", weixinAccount.getId());
obj.put("package", sb.toString());
obj.put("timestamp", timestamp);
obj.put("app_signature", signature);
@ -494,7 +494,7 @@ public class PayApi extends BaseApi {
String _billDate = DateUtil.fortmat2yyyyMMdd(billDate);
String bill_path = ConfigUtil.getValue("bill_path");
String fileName = String.format("%s_%s_%s.xls", _billDate, billType
.name().toLowerCase(), weixinAccount.getAppId());
.name().toLowerCase(), weixinAccount.getId());
File file = new File(String.format("%s/%s", bill_path, fileName));
if (file.exists()) {
return file;
@ -592,7 +592,7 @@ public class PayApi extends BaseApi {
*/
private Map<String, String> baseMapV3(IdQuery idQuery) {
Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getAppId());
map.put("appid", weixinAccount.getId());
map.put("mch_id", weixinAccount.getMchId());
map.put("nonce_str", RandomUtil.generateString(16));
if (StringUtils.isNotBlank(weixinAccount.getDeviceInfo())) {

View File

@ -1,5 +1,6 @@
package com.foxinmy.weixin4j.mp.api;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response;
@ -39,9 +40,9 @@ public class TmplApi extends BaseApi {
throws WeixinException {
Token token = tokenHolder.getToken();
String template_send_uri = getRequestUri("template_send_uri");
String para = JSON.toJSONString(tplMessage);
Response response = request.post(
String.format(template_send_uri, token.getAccessToken()),
tplMessage.toJson());
String.format(template_send_uri, token.getAccessToken()), para);
return response.getAsJsonResult();
}

View File

@ -48,7 +48,7 @@ public class UserApi extends BaseApi {
WeixinAccount weixinAccount = tokenHolder.getAccount();
String user_token_uri = getRequestUri("sns_user_token_uri");
Response response = request.get(String.format(user_token_uri,
weixinAccount.getAppId(), weixinAccount.getAppSecret(), code));
weixinAccount.getId(), weixinAccount.getSecret(), code));
return response.getAsObject(new TypeReference<OauthToken>() {
});

View File

@ -55,11 +55,10 @@ public class Group implements Serializable {
/**
* 返回创建分组所需的json格式字符串
*
* @return {"group": {"id": 107, "name": "test"}}
* @return {"group": {"name": "test"}}
*/
public String toCreateJson() {
return String.format("{\"group\":{\"id\":%s,\"name\":\"%s\"}}", id,
name);
return String.format("{\"group\":{\"name\":\"%s\"}}", name);
}
/**

View File

@ -4,8 +4,8 @@ import java.io.Serializable;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.Gender;
import com.foxinmy.weixin4j.mp.type.FaceSize;
import com.foxinmy.weixin4j.mp.type.Gender;
import com.foxinmy.weixin4j.mp.type.Lang;
/**

View File

@ -4,6 +4,7 @@ import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.mp.type.ResponseType;
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;
@ -22,6 +23,21 @@ public class BaseNotify implements Serializable {
private static final long serialVersionUID = 7190233634431087729L;
private final static XStream jsonStream = new XStream(
new JsonHierarchicalStreamDriver() {
public HierarchicalStreamWriter createWriter(Writer writer) {
return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);
}
});
static {
Class<?>[] classes = ClassUtil
.getClasses(BaseNotify.class.getPackage())
.toArray(new Class[0]);
jsonStream.setMode(XStream.NO_REFERENCES);
jsonStream.autodetectAnnotations(true);
jsonStream.processAnnotations(classes);
}
private String touser;
private ResponseType msgtype;
@ -56,15 +72,7 @@ public class BaseNotify implements Serializable {
* @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);
return jsonStream.toXML(this);
}
@Override

View File

@ -4,7 +4,7 @@ import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.util.RandomUtil;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@ -33,10 +33,10 @@ public class MicroPayPackage extends PayPackage {
}
public MicroPayPackage(WeixinAccount weixinAccount, String body,
public MicroPayPackage(WeixinMpAccount weixinAccount, String body,
String attach, String out_trade_no, double total_fee,
String spbill_create_ip, String auth_code) {
this(weixinAccount.getAppId(), weixinAccount.getMchId(), weixinAccount
this(weixinAccount.getId(), weixinAccount.getMchId(), weixinAccount
.getDeviceInfo(), RandomUtil.generateString(16), body, attach,
out_trade_no, total_fee, spbill_create_ip, null, null, null,
auth_code);

View File

@ -12,7 +12,7 @@ import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.http.XmlResult;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayNotifyV2;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayFeedback;
@ -46,7 +46,7 @@ public class PayAction {
public JSONObject jsPay() {
JSONObject obj = new JSONObject();
PayPackage payPackage = null;
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
// V3 支付
payPackage = new PayPackageV3(weixinAccount, "用户openid", "商品描述",
"系统内部订单号", 1d, "IP地址", TradeType.JSAPI);
@ -111,7 +111,7 @@ public class PayAction {
log.info("jspay_notify_orderinfo,{}", objMap);
JsPayNotify payNotify = XStream.get(inputStream, JsPayNotify.class);
log.info("jspay_notify_userinfo,{}", payNotify);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
// 验证财付通签名
String sign = objMap.get("sign");
objMap.remove("sign");
@ -153,7 +153,7 @@ public class PayAction {
log.info("jaapi_notify_order_info:", order);
String sign = order.getSign();
order.setSign(null);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
String valid_sign = PayUtil.paysignMd5(order,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
@ -187,7 +187,7 @@ public class PayAction {
NativePayNotifyV2 payNotify = XStream.get(inputStream,
NativePayNotifyV2.class);
log.info("native_pay_notify,{}", payNotify);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
String sign = payNotify.getPaySign();
payNotify.setPaySign(null);
payNotify.setSignType(null);
@ -227,7 +227,7 @@ public class PayAction {
NativePayNotifyV3.class);
String sign = payNotify.getSign();
payNotify.setSign(null);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
String valid_sign = PayUtil.paysignMd5(payNotify,
weixinAccount.getPaySignKey());
log.info("微信签名----->sign={},vaild_sign={}", sign, valid_sign);
@ -272,7 +272,7 @@ public class PayAction {
public String warning(InputStream inputStream) {
PayWarn payWarn = XStream.get(inputStream, PayWarn.class);
log.info("pay_warning,{}", payWarn);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
String sign = payWarn.getPaySign();
payWarn.setPaySign(null);
payWarn.setSignType(null);
@ -293,7 +293,7 @@ public class PayAction {
public String feedback(InputStream inputStream) {
PayFeedback feedback = XStream.get(inputStream, PayFeedback.class);
log.info("pay_feedback_info:{}", feedback);
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
WeixinMpAccount weixinAccount = ConfigUtil.getWeixinMpAccount();
// 验证微信签名
Map<String, String> obj = new HashMap<String, String>();
obj.put("openid", feedback.getOpenId());

View File

@ -13,7 +13,8 @@ import com.foxinmy.weixin4j.exception.PayException;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.v2.JsPayRequestV2;
import com.foxinmy.weixin4j.mp.payment.v2.NativePayResponseV2;
import com.foxinmy.weixin4j.mp.payment.v2.PayPackageV2;
@ -37,11 +38,6 @@ import com.foxinmy.weixin4j.xml.XStream;
* @see
*/
public class PayUtil {
private static final String UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
private static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay";
private static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s&timestamp=%s&noncestr=%s";
private static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s";
/**
* 生成JSAPI字符串
*
@ -53,7 +49,7 @@ public class PayUtil {
* @throws PayException
*/
public static String createPayJsRequestJson(PayPackage payPackage,
WeixinAccount weixinAccount) throws PayException {
WeixinMpAccount weixinAccount) throws PayException {
if (payPackage instanceof PayPackageV2) {
return createPayJsRequestJsonV2((PayPackageV2) payPackage,
weixinAccount);
@ -74,7 +70,7 @@ public class PayUtil {
* @return
*/
public static String createPayJsRequestJsonV2(PayPackageV2 payPackage,
WeixinAccount weixinAccount) {
WeixinMpAccount weixinAccount) {
if (StringUtils.isBlank(payPackage.getPartner())) {
payPackage.setPartner(weixinAccount.getPartnerId());
}
@ -101,7 +97,7 @@ public class PayUtil {
* @return
*/
public static String createPayJsRequestJsonV2(String body, String orderNo,
double orderFee, String ip, WeixinAccount weixinAccount) {
double orderFee, String ip, WeixinMpAccount weixinAccount) {
PayPackageV2 payPackage = new PayPackageV2(body, orderNo, orderFee, ip);
payPackage.setPartner(weixinAccount.getPartnerId());
return createPayJsRequestJsonV2(payPackage, weixinAccount);
@ -168,7 +164,7 @@ public class PayUtil {
*/
public static String createPayJsRequestJsonV3(String openId, String body,
String orderNo, double orderFee, String ip, String notifyUrl,
WeixinAccount weixinAccount) throws PayException {
WeixinMpAccount weixinAccount) throws PayException {
PayPackageV3 payPackage = new PayPackageV3(weixinAccount, openId, body,
orderNo, orderFee, ip, TradeType.JSAPI);
payPackage.setNotify_url(notifyUrl);
@ -186,7 +182,7 @@ public class PayUtil {
* @throws PayException
*/
public static String createPayJsRequestJsonV3(PayPackageV3 payPackage,
WeixinAccount weixinAccount) throws PayException {
WeixinMpAccount weixinAccount) throws PayException {
String paySignKey = weixinAccount.getPaySignKey();
payPackage.setSign(paysignMd5(payPackage, paySignKey));
PrePay prePay = createPrePay(payPackage);
@ -201,7 +197,7 @@ public class PayUtil {
String payJsRequestXml = XStream.to(payPackage).replaceAll("__", "_");
HttpRequest request = new HttpRequest();
try {
Response response = request.post(UNIFIEDORDER, payJsRequestXml);
Response response = request.post(Consts.UNIFIEDORDER, payJsRequestXml);
prePay = response.getAsObject(new TypeReference<PrePay>() {
});
} catch (WeixinException e) {
@ -263,17 +259,17 @@ public class PayUtil {
* 与订单ID等价
* @return
*/
public String createNativePayRequestURLV2(WeixinAccount weixinAccount,
public String createNativePayRequestURLV2(WeixinMpAccount weixinAccount,
String productId) {
Map<String, String> map = new HashMap<String, String>();
String timestamp = DateUtil.timestamp2string();
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("appid", weixinAccount.getId());
map.put("timestamp", timestamp);
map.put("noncestr", noncestr);
map.put("productid", productId);
String sign = paysignSha(map, weixinAccount.getPaySignKey());
return String.format(NATIVEURLV2, sign, weixinAccount.getAppId(),
return String.format(Consts.NATIVEURLV2, sign, weixinAccount.getId(),
productId, timestamp, noncestr);
}
@ -286,29 +282,29 @@ public class PayUtil {
* 与订单ID等价
* @return
*/
public String createNativePayRequestURLV3(WeixinAccount weixinAccount,
public String createNativePayRequestURLV3(WeixinMpAccount weixinAccount,
String productId) {
Map<String, String> map = new HashMap<String, String>();
String timestamp = DateUtil.timestamp2string();
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("appid", weixinAccount.getId());
map.put("mch_id", weixinAccount.getMchId());
map.put("time_stamp", timestamp);
map.put("nonce_str", noncestr);
map.put("product_id", productId);
String sign = paysignMd5(map, weixinAccount.getPaySignKey());
return String.format(NATIVEURLV3, sign, weixinAccount.getAppId(),
return String.format(Consts.NATIVEURLV3, sign, weixinAccount.getId(),
weixinAccount.getMchId(), productId, timestamp, noncestr);
}
public static String createNativePayRequestV2(WeixinAccount weixinAccount,
public static String createNativePayRequestV2(WeixinMpAccount weixinAccount,
PayPackageV2 payPackage) {
NativePayResponseV2 payRequest = new NativePayResponseV2(weixinAccount,
payPackage);
Map<String, String> map = new HashMap<String, String>();
String timestamp = DateUtil.timestamp2string();
String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getAppId());
map.put("appid", weixinAccount.getId());
map.put("timestamp", timestamp);
map.put("noncestr", noncestr);
map.put("package", payRequest.getPackageInfo());
@ -336,12 +332,12 @@ public class PayUtil {
* @param weixinAccount
* 商户信息
* @return 返回数据
* @see {@link com.foxinmy.weixin4j.mp.payment.PayUtil#createMicroPay(MicroPayPackage, WeixinAccount)}
* @see {@link com.foxinmy.weixin4j.mp.payment.PayUtil#createMicroPay(MicroPayPackage, WeixinMpAccount)}
* @throws WeixinException
*/
public static com.foxinmy.weixin4j.mp.payment.v3.Order createMicroPay(
String authCode, String body, String attach, String orderNo,
double orderFee, String ip, WeixinAccount weixinAccount)
double orderFee, String ip, WeixinMpAccount weixinAccount)
throws WeixinException {
MicroPayPackage payPackage = new MicroPayPackage(weixinAccount, body,
attach, orderNo, orderFee, ip, authCode);
@ -359,13 +355,13 @@ public class PayUtil {
* @throws WeixinException
*/
public static com.foxinmy.weixin4j.mp.payment.v3.Order createMicroPay(
MicroPayPackage payPackage, WeixinAccount weixinAccount)
MicroPayPackage payPackage, WeixinMpAccount weixinAccount)
throws WeixinException {
String sign = paysignMd5(payPackage, weixinAccount.getPaySignKey());
payPackage.setSign(sign);
String para = XStream.to(payPackage).replaceAll("__", "_");
HttpRequest request = new HttpRequest();
Response response = request.post(MICROPAYURL, para);
Response response = request.post(Consts.MICROPAYURL, para);
return response
.getAsObject(new TypeReference<com.foxinmy.weixin4j.mp.payment.v3.Order>() {
});

View File

@ -5,7 +5,7 @@ import java.beans.Transient;
import org.apache.commons.codec.digest.DigestUtils;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.PayRequest;
import com.foxinmy.weixin4j.util.MapUtil;
@ -28,8 +28,8 @@ public class JsPayRequestV2 extends PayRequest {
private static final long serialVersionUID = -5972173459255255197L;
public JsPayRequestV2(WeixinAccount weixinAccount, PayPackageV2 payPackage) {
this.setAppId(weixinAccount.getAppId());
public JsPayRequestV2(WeixinMpAccount weixinAccount, PayPackageV2 payPackage) {
this.setAppId(weixinAccount.getId());
this.setPackageInfo(package2string(payPackage,
weixinAccount.getPartnerKey()));
}

View File

@ -1,6 +1,6 @@
package com.foxinmy.weixin4j.mp.payment.v2;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
@ -21,7 +21,7 @@ public class NativePayResponseV2 extends JsPayRequestV2 {
@XStreamAlias("RetErrMsg")
private String retMsg;
public NativePayResponseV2(WeixinAccount weixinAccount,
public NativePayResponseV2(WeixinMpAccount weixinAccount,
PayPackageV2 payPackage) {
super(weixinAccount, payPackage);
this.retCode = "0";

View File

@ -4,7 +4,7 @@ import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.payment.PayPackage;
import com.foxinmy.weixin4j.mp.type.TradeType;
import com.foxinmy.weixin4j.util.RandomUtil;
@ -38,17 +38,17 @@ public class PayPackageV3 extends PayPackage {
}
public PayPackageV3(WeixinAccount weixinAccount, String openId,
public PayPackageV3(WeixinMpAccount weixinAccount, String openId,
String body, String out_trade_no, double total_fee,
String spbill_create_ip, TradeType tradeType) {
this(weixinAccount, openId, body, null, out_trade_no, total_fee,
spbill_create_ip, null, tradeType);
}
public PayPackageV3(WeixinAccount weixinAccount, String openId,
public PayPackageV3(WeixinMpAccount weixinAccount, String openId,
String body, String attach, String out_trade_no, double total_fee,
String spbill_create_ip, String notify_url, TradeType tradeType) {
this(weixinAccount.getAppId(), weixinAccount.getMchId(), weixinAccount
this(weixinAccount.getId(), weixinAccount.getMchId(), weixinAccount
.getDeviceInfo(), RandomUtil.generateString(16), body, attach,
out_trade_no, total_fee, spbill_create_ip, null, null, null,
notify_url, tradeType, openId, null);

View File

@ -1,16 +1,11 @@
package com.foxinmy.weixin4j.mp.response;
import java.io.Writer;
import com.foxinmy.weixin4j.model.BaseMsg;
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;
/**
* 响应消息基类
@ -28,26 +23,15 @@ public class BaseResponse extends BaseMsg {
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("MsgType")
private ResponseType msgType; // 消息类型
static {
Class<?>[] classes = ClassUtil.getClasses(
BaseResponse.class.getPackage()).toArray(new Class[0]);
xmlStream.autodetectAnnotations(true);
xmlStream.processAnnotations(classes);
jsonStream.setMode(XStream.NO_REFERENCES);
jsonStream.autodetectAnnotations(true);
jsonStream.processAnnotations(classes);
}
@XStreamAlias("MsgType")
private ResponseType msgType; // 消息类型
public BaseResponse(ResponseType msgType) {
this.msgType = msgType;
@ -59,7 +43,7 @@ public class BaseResponse extends BaseMsg {
public BaseResponse(ResponseType msgType, String toUserName,
String fromUserName) {
super(toUserName,fromUserName);
super(toUserName, fromUserName);
this.msgType = msgType;
}
@ -78,17 +62,6 @@ public class BaseResponse extends BaseMsg {
* @return xml字符串
*/
public String toXml() {
Class<? extends BaseResponse> targetClass = msgType.getMessageClass();
xmlStream.alias("xml", targetClass);
return xmlStream.toXML(this);
}
/**
* 消息对象转换为微信服务器接受的json格式字符串
*
* @return json字符串
*/
public String toJson() {
return jsonStream.toXML(this);
}
}

View File

@ -1,13 +1,9 @@
package com.foxinmy.weixin4j.mp.response;
import java.beans.Transient;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 模板消息
*
@ -115,10 +111,4 @@ public class TemplateMessage implements Serializable {
+ template_id + ", url=" + url + ", topcolor=" + topcolor
+ ", data=" + data + "]";
}
@Transient
@JSONField(serialize = false)
public String toJson() {
return JSON.toJSONString(this);
}
}

View File

@ -1,23 +0,0 @@
package com.foxinmy.weixin4j.mp.type;
/**
* 用户性别
* @className Gender
* @author jy
* @date 2014年11月5日
* @since JDK 1.7
* @see
*/
public enum Gender {
male(1), female(2), unknown(0);
private int sex;
Gender(int sex) {
this.sex = sex;
}
public int getInt() {
return sex;
}
}

View File

@ -1,6 +1,6 @@
# \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath
# \u516c\u4f17\u53f7\u4fe1\u606f
account={"appId":"wx4ab8f8de58159a57","appSecret":"1d4eb0f4bf556aaed539f30ed05ca795",\
account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"token":"\u5f00\u653e\u8005\u7684token \u975e\u5fc5\u987b","openId":"\u516c\u4f17\u53f7\u7684openid \u975e\u5fc5\u987b",\
"encodingAesKey":"\u516c\u4f17\u53f7\u8bbe\u7f6e\u4e86\u52a0\u5bc6\u65b9\u5f0f\u4e14\u4e3a\u300c\u5b89\u5168\u6a21\u5f0f\u300d\u65f6\u9700\u8981\u586b\u5165",\
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7",\

View File

@ -7,6 +7,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.AccountType;
/**
* token测试
@ -22,7 +23,7 @@ public class TokenTest {
@Before
public void setUp() {
tokenHolder = new FileTokenHolder();
tokenHolder = new FileTokenHolder(AccountType.MP);
}
@Test

View File

@ -1,7 +1,7 @@
weixin4j-mp-server
==================
微信netty服务
微信公众平台netty服务
------------
功能列表
@ -26,7 +26,7 @@ weixin4j-mp-server
示例(properties中换行用右斜杆\\)
> account={"appId":"appId","appSecret":"appSecret",
> account={"id":"appId","secret":"appSecret",
> "token":"开放者的token 非必须","openId":"公众号的openid 非必须",
> "encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",
> "mchId":"V3.x版本下的微信商户号",

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>weixin4j-mp-server</artifactId>
<name>weixin4j-mp-server</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp/weixin4j-server</url>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-mp/weixin4j-mp-server</url>
<description>微信公众号服务</description>
<build>
<finalName>weixin-mp-server</finalName>

View File

@ -13,7 +13,7 @@ import org.apache.http.Consts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.model.HttpWeixinMessage;
import com.foxinmy.weixin4j.mp.type.EncryptType;
import com.foxinmy.weixin4j.util.ConfigUtil;
@ -37,7 +37,7 @@ public class WeixinMessageDecoder extends
@Override
protected void decode(ChannelHandlerContext ctx, FullHttpRequest req,
List<Object> out) throws Exception {
WeixinAccount account = ConfigUtil.getWeixinAccount();
WeixinMpAccount mpAccount = ConfigUtil.getWeixinMpAccount();
String xmlContent = req.content().toString(Consts.UTF_8);
HttpWeixinMessage message = new HttpWeixinMessage();
if (StringUtils.isNotBlank(xmlContent)) {
@ -72,10 +72,10 @@ public class WeixinMessageDecoder extends
message.setXmlContent(xmlContent);
if (message.getEncryptType() == EncryptType.AES) {
message.setXmlContent(MessageUtil.aesDecrypt(account.getAppId(),
account.getEncodingAesKey(), message.getEncryptContent()));
message.setXmlContent(MessageUtil.aesDecrypt(mpAccount.getId(),
mpAccount.getEncodingAesKey(), message.getEncryptContent()));
}
message.setToken(account.getToken());
message.setToken(mpAccount.getToken());
out.add(message);
}
}

View File

@ -11,7 +11,7 @@ import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinMpAccount;
import com.foxinmy.weixin4j.mp.response.BaseResponse;
import com.foxinmy.weixin4j.mp.util.HttpUtil;
import com.foxinmy.weixin4j.util.ConfigUtil;
@ -45,13 +45,13 @@ public class WeixinMessageEncoder extends MessageToMessageEncoder<BaseResponse>
@Override
protected void encode(ChannelHandlerContext ctx, BaseResponse response,
List<Object> out) throws Exception {
WeixinAccount account = ConfigUtil.getWeixinAccount();
WeixinMpAccount mpAccount = ConfigUtil.getWeixinMpAccount();
String xmlContent = response.toXml();
String nonce = RandomUtil.generateString(32);
String timestamp = DateUtil.timestamp2string();
String encrtypt = MessageUtil.aesEncrypt(account.getAppId(),
account.getEncodingAesKey(), xmlContent);
String msgSignature = MessageUtil.signature(account.getToken(), nonce,
String encrtypt = MessageUtil.aesEncrypt(mpAccount.getId(),
mpAccount.getEncodingAesKey(), xmlContent);
String msgSignature = MessageUtil.signature(mpAccount.getToken(), nonce,
timestamp, encrtypt);
Map<String, String> map = new HashMap<String, String>();
map.put("Encrypt", encrtypt);

View File

@ -1,5 +1,5 @@
# \u516c\u4f17\u53f7\u4fe1\u606f
account={"appId":"wx4ab8f8de58159a57","appSecret":"1d4eb0f4bf556aaed539f30ed05ca795",\
account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"token":"\u5f00\u653e\u8005\u7684token \u975e\u5fc5\u987b","openId":"\u516c\u4f17\u53f7\u7684openid \u975e\u5fc5\u987b",\
"encodingAesKey":"\u516c\u4f17\u53f7\u8bbe\u7f6e\u4e86\u52a0\u5bc6\u65b9\u5f0f\u4e14\u4e3a\u300c\u5b89\u5168\u6a21\u5f0f\u300d\u9700\u8981\u586b\u5165",\
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7",\

View File

@ -1,17 +1,27 @@
weixin4j-qy
===========
@(weixin4j)[企业号]
微信[企业号](http://qydev.weixin.qq.com/wiki/index.php)开发工具包
[微信企业号](http://qydev.weixin.qq.com/wiki/index.php)开发工具包
---------------------------------------------------------------
功能列表
-------
* **weixin4j-qy-api**
如何使用
--------
+ DepartApi `部门管理API`
+ UserApi `成员管理API`
+ TagApi `标签管理API`
更新LOG
-------
* 2014-11-19
+ 得到`weixin4j-qy-api``weixin4j-qy-server`工程
+ **weixin4j-qy-api**: 新增部门管理接口
+ **weixin4j-qy-api**: 新增用户管理接口
+ **weixin4j-qy-api**: 新增标签管理接口

View File

@ -10,6 +10,18 @@
</parent>
<artifactId>weixin4j-qy</artifactId>
<name>weixin4j-qy</name>
<packaging>pom</packaging>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-qy</url>
<description>微信企业号工具包</description>
<modules>
<module>weixin4j-qy-api</module>
<module>weixin4j-qy-server</module>
</modules>
<dependencies>
<dependency>
<groupId>com.foxinmy.weixin4j</groupId>
<artifactId>weixin4j-base</artifactId>
<version>${weixin4j.base.version}</version>
</dependency>
</dependencies>
</project>

28
weixin4j-qy/weixin4j-qy-api/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# eclipse ignore
*.settings/*
/.project
/.classpath
/.tomcatplugin
# maven ignore
target/*
# other ignore
*.log
*.tmp
Thumbs.db
/target/
.DS_Store

View File

@ -0,0 +1,56 @@
weixin4j-qy-api
===============
[微信企业号](http://qydev.weixin.qq.com/wiki/index.php)开发工具包
---------------------------------------------------------------
功能列表
-------
* DepartApi `部门管理API`
* UserApi `成员管理API`
* TagApi `标签管理API`
如何使用
--------
1.API工程可以单独打包到其他项目中使用,需新增或拷贝`weixin.properties`文件到项目的`classpath`
weixin.properties说明
| 属性名 | 说明 |
| :---------- | :-------------- |
| account | 微信企业号信息 `json格式` |
| token_path | 使用FileTokenHolder时token保存的物理路径 |
示例(properties中换行用右斜杆\\)
> account={"id":"corpid","secret":"corpsecret",
> "token":"开放者的token 非必须",
> "encodingAesKey":"AES加密密钥"}
> token_path=/tmp/weixin/token <br/>
2.实例化一个`WeixinProxy`对象,调用API
WeixinProxy weixinProxy = new WeixinProxy();
// weixinProxy = new WeixinProxy(corpid,corpsecret);
// weixinProxy = new WeixinProxy(weixinAccount);
weixinProxy.getUser(userid);
3.针对`token`存储有两种方案,`File存储`/`Redis存储`,当然也可自己实现`TokenHolder`(继承`AbstractTokenHolder`并重写`getToken`方法),默认使用文件(xml)的方式保存token,如果环境中支持`redis`,建议使用`RedisTokenHolder`.
WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenHolder());
// weixinProxy = new WeixinProxy(new RedisTokenHolder(weixinAccount));
4.`mvn package`.
更新LOG
-------
* 2014-11-19
+ 新增`部门管理`接口
+ 新增`用户管理`接口
+ 新增`标签管理`接口

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.foxinmy.weixin4j</groupId>
<artifactId>weixin4j-qy</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>weixin4j-qy-api</artifactId>
<name>weixin4j-qy-api</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-qy/weixin4j-qy-api</url>
<description>微信企业号API</description>
<build>
<finalName>weixin4j-qy-api</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,31 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>full</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/classes</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>/**</include>
</includes>
<excludes>
<exclude>*.properties</exclude>
<exclude>*.xml</exclude>
</excludes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<unpack>true</unpack>
<includes>
<include>com.foxinmy.weixin4j:weixin4j-base</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>

View File

@ -0,0 +1,344 @@
package com.foxinmy.weixin4j.qy;
import java.util.List;
import com.alibaba.fastjson.JSONArray;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.model.WeixinQyAccount;
import com.foxinmy.weixin4j.qy.api.DepartApi;
import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.model.Department;
import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.FileTokenHolder;
import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.type.AccountType;
/**
* 微信企业号接口实现
*
* @className WeixinProxy
* @author jy
* @date 2014年11月19日
* @since JDK 1.7
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class WeixinProxy {
private final DepartApi departApi;
private final UserApi userApi;
private final TagApi tagApi;
/**
* 默认采用文件存放Token信息
*/
public WeixinProxy() {
this(new FileTokenHolder(AccountType.QY));
}
/**
* appid,appsecret
*
* @param appid
* @param appsecret
*/
public WeixinProxy(String corpid, String corpsecret) {
this(new WeixinQyAccount(corpid, corpsecret));
}
/**
* WeixinAccount对象
*
* @param weixinAccount
*/
public WeixinProxy(WeixinQyAccount weixinAccount) {
this(new FileTokenHolder(weixinAccount));
}
/**
* TokenHolder对象
*
* @param tokenHolder
*/
public WeixinProxy(TokenHolder tokenHolder) {
this.departApi = new DepartApi(tokenHolder);
this.userApi = new UserApi(tokenHolder);
this.tagApi = new TagApi(tokenHolder);
}
/**
* 创建部门(根部门的parentid为1)
*
* @param depart
* 部门对象
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E5.88.9B.E5.BB.BA.E9.83.A8.E9.97.A8">创建部门说明</a>
* @see com.foxinmy.weixin4j.qy.api.DepartApi
* @return 部门ID
* @throws WeixinException
*/
public int createDepart(Department depart) throws WeixinException {
return departApi.createDepart(depart);
}
/**
* 更新部门(如果非必须的字段未指定 则不更新该字段之前的设置值)
*
* @param depart
* 部门对象
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E6.9B.B4.E6.96.B0.E9.83.A8.E9.97.A8">更新部门说明</a>
* @see com.foxinmy.weixin4j.qy.api.DepartApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateDepart(Department depart) throws WeixinException {
return departApi.updateDepart(depart);
}
/**
* 查询部门列表(以部门的order字段从小到大排列)
*
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8">获取部门列表</a>
* @see com.foxinmy.weixin4j.qy.api.DepartApi
* @return 部门列表
* @throws WeixinException
*/
public List<Department> listDepart() throws WeixinException {
return departApi.listDepart();
}
/**
* 删除部门(不能删除根部门不能删除含有子部门成员的部门)
*
* @param departId
* 部门ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E5.88.A0.E9.99.A4.E9.83.A8.E9.97.A8">删除部门说明</a>
* @see com.foxinmy.weixin4j.qy.api.DepartApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteDepart(int departId) throws WeixinException {
return departApi.deleteDepart(departId);
}
/**
* 创建成员
*
* @param user
* 成员对象
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E5.88.9B.E5.BB.BA.E6.88.90.E5.91.98">创建成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult createUser(User user) throws WeixinException {
return userApi.createUser(user);
}
/**
* 更新用户(如果非必须的字段未指定 则不更新该字段之前的设置值)
*
* @param user
* 成员对象
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E6.9B.B4.E6.96.B0.E6.88.90.E5.91.98">更新成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateUser(User user) throws WeixinException {
return userApi.updateUser(user);
}
/**
* 获取成员
*
* @param userid
* 成员唯一ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E8.8E.B7.E5.8F.96.E6.88.90.E5.91.98">获取成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 成员对象
* @throws WeixinException
*/
public User getUser(String userid) throws WeixinException {
return userApi.getUser(userid);
}
/**
* 获取部门成员
*
* @param departId
* 部门ID 必须
* @param fetchChild
* 是否递归获取子部门下面的成员 非必须
* @param userStatus
* 成员状态 status可叠加 非必须
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98">获取部门成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 成员列表
* @throws WeixinException
*/
public List<User> listUser(int departId, boolean fetchChild,
UserStatus userStatus) throws WeixinException {
return userApi.listUser(departId, fetchChild, userStatus);
}
/**
* 获取部门下所有状态成员(不进行递归)
*
* @param departId
* 部门ID
* @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#listUser(int, boolean,UserStatus)}
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 成员列表
* @throws WeixinException
*/
public List<User> listUser(int departId) throws WeixinException {
return userApi.listUser(departId);
}
/**
* 删除成员
*
* @param userid
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98">删除成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.UserApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteUser(String userid) throws WeixinException {
return userApi.deleteUser(userid);
}
/**
* 创建标签(创建的标签属于管理组;默认为未加锁状态)
*
* @param tagName
* 标签名称
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.9B.E5.BB.BA.E6.A0.87.E7.AD.BE">创建标签说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 标签ID
* @throws WeixinException
*/
public int createTag(String tagName) throws WeixinException {
return tagApi.createTag(tagName);
}
/**
* 更新标签(管理组必须是指定标签的创建者)
*
* @param tagId
* 标签ID
* @param tagName
* 标签名称
* @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97"
* >更新标签说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateTag(int tagId, String tagName)
throws WeixinException {
return tagApi.updateTag(tagId, tagName);
}
/**
* 删除标签(管理组必须是指定标签的创建者 并且标签的成员列表为空)
*
* @param tagId
* 标签ID
* @return 处理结果
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.A0.E9.99.A4.E6.A0.87.E7.AD.BE">删除标签说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @throws WeixinException
*/
public JsonResult deleteTag(int tagId) throws WeixinException {
return tagApi.deleteTag(tagId);
}
/**
* 获取标签列表
*
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 标签列表
* @throws WeixinException
*/
public JSONArray listTag() throws WeixinException {
return tagApi.listTag();
}
/**
* 获取标签成员(管理组须拥有获取标签成员的接口权限标签须对管理组可见返回列表仅包含管理组管辖范围的成员)
*
* @param tagId
* 标签ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">获取标签成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 成员列表
* @throws WeixinException
*/
public List<User> getTagUsers(int tagId) throws WeixinException {
return tagApi.getTagUsers(tagId);
}
/**
* 新增标签成员(标签对管理组可见且未加锁成员属于管理组管辖范围)<br>
* <font color="red">若部分userid非法则在text中体现</font>
*
* @param tagId
* 标签ID
* @param userIds
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.A2.9E.E5.8A.A0.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">新增标签成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult addTagUsers(int tagId, List<String> userIds)
throws WeixinException {
return tagApi.addTagUsers(tagId, userIds);
}
/**
* 删除标签成员(标签对管理组可见且未加锁成员属于管理组管辖范围)<br>
* <font color="red">若部分userid非法则在text中体现</font>
*
* @param tagId
* 标签ID
* @param userIds
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.A0.E9.99.A4.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">删除标签成员说明</a>
* @see com.foxinmy.weixin4j.qy.api.TagApi
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteTagUsers(int tagId, List<String> userIds)
throws WeixinException {
return tagApi.deleteTagUsers(tagId, userIds);
}
}

View File

@ -0,0 +1,57 @@
package com.foxinmy.weixin4j.qy.api;
import java.util.Map;
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.Map2ObjectConverter;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.core.ClassLoaderReference;
import com.thoughtworks.xstream.mapper.DefaultMapper;
/**
*
* @className BaseApi
* @author jy.hu
* @date 2014年11月18日
* @since JDK 1.7
* @see <a href="http://qydev.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class BaseApi {
protected final HttpRequest request = new HttpRequest();
protected final static XStream mapXstream = XStream.get();
private final static ResourceBundle weixinBundle;
static {
weixinBundle = ResourceBundle
.getBundle("com/foxinmy/weixin4j/qy/api/weixin");
mapXstream.alias("xml", Map.class);
mapXstream.registerConverter(new Map2ObjectConverter(new DefaultMapper(
new ClassLoaderReference(XStream.class.getClassLoader()))));
}
protected String map2xml(Map<?, ?> map) {
return mapXstream.toXML(map).replaceAll("__", "_");
}
@SuppressWarnings("unchecked")
protected Map<String, String> xml2map(String xml) {
return mapXstream.fromXML(xml, Map.class);
}
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();
}
}

View File

@ -0,0 +1,110 @@
package com.foxinmy.weixin4j.qy.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.JsonResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.Department;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 部门API
*
* @className DepartApi
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8">管理部门说明</a>
*/
public class DepartApi extends BaseApi {
private final TokenHolder tokenHolder;
public DepartApi(TokenHolder tokenHolder) {
this.tokenHolder = tokenHolder;
}
/**
* 创建部门(根部门的parentid为1)
*
* @param depart
* 部门对象
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E5.88.9B.E5.BB.BA.E9.83.A8.E9.97.A8">创建部门说明</a>
* @return 部门ID
* @throws WeixinException
*/
public int createDepart(Department depart) throws WeixinException {
String department_create_uri = getRequestUri("department_create_uri");
JSONObject obj = (JSONObject) JSON.toJSON(depart);
obj.remove("id");
Token token = tokenHolder.getToken();
Response response = request.post(
String.format(department_create_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getIntValue("id");
}
/**
* 更新部门(如果非必须的字段未指定 则不更新该字段之前的设置值)
*
* @param depart
* 部门对象
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E6.9B.B4.E6.96.B0.E9.83.A8.E9.97.A8">更新部门说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateDepart(Department depart) throws WeixinException {
String department_update_uri = getRequestUri("department_update_uri");
JSONObject obj = (JSONObject) JSON.toJSON(depart);
Token token = tokenHolder.getToken();
Response response = request.post(
String.format(department_update_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJsonResult();
}
/**
* 查询部门列表(以部门的order字段从小到大排列)
*
* @see com.foxinmy.weixin4j.qy.model.Department
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E5.88.97.E8.A1.A8">获取部门列表</a>
* @return 部门列表
* @throws WeixinException
*/
public List<Department> listDepart() throws WeixinException {
String department_list_uri = getRequestUri("department_list_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(department_list_uri,
token.getAccessToken()));
return JSON.parseArray(response.getAsJson().getString("department"),
Department.class);
}
/**
* 删除部门(不能删除根部门不能删除含有子部门成员的部门)
*
* @param departId
* 部门ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8#.E5.88.A0.E9.99.A4.E9.83.A8.E9.97.A8">删除部门说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteDepart(int departId) throws WeixinException {
String department_delete_uri = getRequestUri("department_delete_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(department_delete_uri,
token.getAccessToken(), departId));
return response.getAsJsonResult();
}
}

View File

@ -0,0 +1,179 @@
package com.foxinmy.weixin4j.qy.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 标签API
*
* @className TagApi
* @author jy
* @date 2014年11月19日
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE">管理标签</a>
*/
public class TagApi extends BaseApi {
private final TokenHolder tokenHolder;
public TagApi(TokenHolder tokenHolder) {
this.tokenHolder = tokenHolder;
}
/**
* 创建标签(创建的标签属于管理组;默认为未加锁状态)
*
* @param tagName
* 标签名称
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.9B.E5.BB.BA.E6.A0.87.E7.AD.BE">创建标签说明</a>
* @return 标签ID
* @throws WeixinException
*/
public int createTag(String tagName) throws WeixinException {
String tag_create_uri = getRequestUri("tag_create_uri");
Token token = tokenHolder.getToken();
Response response = request.post(
String.format(tag_create_uri, token.getAccessToken()),
String.format("{\"tagname\":\"%s\"}", tagName));
return response.getAsJson().getIntValue("tagid");
}
/**
* 更新标签(管理组必须是指定标签的创建者)
*
* @param tagId
* 标签ID
* @param tagName
* 标签名称
* @see <a href=
* "http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E6.9B.B4.E6.96.B0.E6.A0.87.E7.AD.BE.E5.90.8D.E5.AD.97"
* >更新标签说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateTag(int tagId, String tagName)
throws WeixinException {
String tag_update_uri = getRequestUri("tag_update_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_update_uri,
token.getAccessToken()), String.format(
"{\"tagid\":%d,\"tagname\":\"%s\"}", tagId, tagName));
return response.getAsJsonResult();
}
/**
* 删除标签(管理组必须是指定标签的创建者 并且标签的成员列表为空)
*
* @param tagId
* 标签ID
* @return 处理结果
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.A0.E9.99.A4.E6.A0.87.E7.AD.BE">删除标签说明</a>
* @throws WeixinException
*/
public JsonResult deleteTag(int tagId) throws WeixinException {
String tag_delete_uri = getRequestUri("tag_delete_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_delete_uri,
token.getAccessToken(), tagId));
return response.getAsJsonResult();
}
/**
* 获取标签列表
*
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E5.88.97.E8.A1.A8">获取标签列表说明</a>
* @return 标签列表
* @throws WeixinException
*/
public JSONArray listTag() throws WeixinException {
String tag_list_uri = getRequestUri("tag_list_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_list_uri,
token.getAccessToken()));
return response.getAsJson().getJSONArray("taglist");
}
/**
* 获取标签成员(管理组须拥有获取标签成员的接口权限标签须对管理组可见返回列表仅包含管理组管辖范围的成员)
*
* @param tagId
* 标签ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E8.8E.B7.E5.8F.96.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">获取标签成员说明</a>
* @return 成员列表
* @throws WeixinException
*/
public List<User> getTagUsers(int tagId) throws WeixinException {
String tag_get_user_uri = getRequestUri("tag_get_user_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(tag_get_user_uri,
token.getAccessToken(), tagId));
return JSON.parseArray(response.getAsJson().getString("userlist"),
User.class);
}
/**
* 新增标签成员(标签对管理组可见且未加锁成员属于管理组管辖范围)<br>
* <font color="red">若部分userid非法则在text中体现</font>
*
* @param tagId
* 标签ID
* @param userIds
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.A2.9E.E5.8A.A0.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">新增标签成员说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult addTagUsers(int tagId, List<String> userIds)
throws WeixinException {
String tag_add_user_uri = getRequestUri("tag_add_user_uri");
return excuteUsers(tag_add_user_uri, tagId, userIds);
}
/**
* 删除标签成员(标签对管理组可见且未加锁成员属于管理组管辖范围)<br>
* <font color="red">若部分userid非法则在text中体现</font>
*
* @param tagId
* 标签ID
* @param userIds
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%A0%87%E7%AD%BE#.E5.88.A0.E9.99.A4.E6.A0.87.E7.AD.BE.E6.88.90.E5.91.98">删除标签成员说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteTagUsers(int tagId, List<String> userIds)
throws WeixinException {
String tag_delete_user_uri = getRequestUri("tag_delete_user_uri");
return excuteUsers(tag_delete_user_uri, tagId, userIds);
}
private JsonResult excuteUsers(String uri, int tagId, List<String> userIds)
throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("tagid", tagId);
obj.put("userlist", userIds);
Token token = tokenHolder.getToken();
Response response = request.post(
String.format(uri, token.getAccessToken()), obj.toJSONString());
obj = response.getAsJson();
JsonResult result = JSON.toJavaObject(obj, JsonResult.class);
result.setText(obj.getString("invalidlist"));
return result;
}
}

View File

@ -0,0 +1,159 @@
package com.foxinmy.weixin4j.qy.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.JsonResult;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.TokenHolder;
/**
* 成员API
*
* @className UserApi
* @author jy
* @date 2014年11月19日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98">管理成员说明</a>
*/
public class UserApi extends BaseApi {
private final TokenHolder tokenHolder;
public UserApi(TokenHolder tokenHolder) {
this.tokenHolder = tokenHolder;
}
/**
* 创建成员
*
* @param user
* 成员对象
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E5.88.9B.E5.BB.BA.E6.88.90.E5.91.98">创建成员说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult createUser(User user) throws WeixinException {
String user_create_uri = getRequestUri("user_create_uri");
return excute(user_create_uri, user);
}
/**
* 更新用户(如果非必须的字段未指定 则不更新该字段之前的设置值)
*
* @param user
* 成员对象
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E6.9B.B4.E6.96.B0.E6.88.90.E5.91.98">更新成员说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult updateUser(User user) throws WeixinException {
String user_update_uri = getRequestUri("user_update_uri");
return excute(user_update_uri, user);
}
private JsonResult excute(String uri, User user) throws WeixinException {
JSONObject obj = (JSONObject) JSON.toJSON(user);
Object extattr = obj.remove("extattr");
if (extattr != null) {
JSONObject attrs = new JSONObject();
attrs.put("attrs", extattr);
obj.put("extattr", attrs);
}
Token token = tokenHolder.getToken();
Response response = request.post(
String.format(uri, token.getAccessToken()), obj.toJSONString());
return response.getAsJsonResult();
}
/**
* 获取成员
*
* @param userid
* 成员唯一ID
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E8.8E.B7.E5.8F.96.E6.88.90.E5.91.98">获取成员说明</a>
* @return 成员对象
* @throws WeixinException
*/
public User getUser(String userid) throws WeixinException {
String user_get_uri = getRequestUri("user_get_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_get_uri,
token.getAccessToken(), userid));
JSONObject obj = response.getAsJson();
Object attrs = obj.getJSONObject("extattr").remove("attrs");
if (attrs != null) {
obj.put("extattr", attrs);
}
return JSON.toJavaObject(obj, User.class);
}
/**
* 获取部门成员
*
* @param departId
* 部门ID 必须
* @param fetchChild
* 是否递归获取子部门下面的成员 非必须
* @param userStatus
* 成员状态 status可叠加 非必须
* @see com.foxinmy.weixin4j.qy.model.User
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98">获取部门成员说明</a>
* @return 成员列表
* @throws WeixinException
*/
public List<User> listUser(int departId, boolean fetchChild,
UserStatus userStatus) throws WeixinException {
String user_list_uri = getRequestUri("user_list_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_list_uri,
token.getAccessToken(), departId, fetchChild ? 1 : 0,
userStatus.getVal()));
return JSON.parseArray(response.getAsJson().getString("userlist"),
User.class);
}
/**
* 获取部门下所有状态成员(不进行递归)
*
* @param departId
* 部门ID
* @see {@link com.foxinmy.weixin4j.qy.api.UserApi#listUser(int, boolean,UserStatus)}
* @return 成员列表
* @throws WeixinException
*/
public List<User> listUser(int departId) throws WeixinException {
return listUser(departId, false, UserStatus.BOTH);
}
/**
* 删除成员
*
* @param userid
* 成员ID
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98#.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98">删除成员说明</a>
* @return 处理结果
* @throws WeixinException
*/
public JsonResult deleteUser(String userid) throws WeixinException {
String user_delete_uri = getRequestUri("user_delete_uri");
Token token = tokenHolder.getToken();
Response response = request.post(String.format(user_delete_uri,
token.getAccessToken(), userid));
return response.getAsJsonResult();
}
}

View File

@ -0,0 +1,39 @@
# ----------------------------------------------------------------------------
# api\u9996\u9875
# http://qydev.weixin.qq.com/wiki/index.php
# ----------------------------------------------------------------------------
api_base_url=https://qyapi.weixin.qq.com/cgi-bin
# \u521b\u5efa\u90e8\u95e8
department_create_uri={api_base_url}/department/create?access_token=%s
# \u66f4\u65b0\u90e8\u95e8
department_update_uri={api_base_url}/department/update?access_token=%s
# \u90e8\u95e8\u5217\u8868
department_list_uri={api_base_url}/department/list?access_token=%s
# \u5220\u9664\u90e8\u95e8
department_delete_uri={api_base_url}/department/delete?access_token=%s&id=%d
# \u521b\u5efa\u6210\u5458
user_create_uri={api_base_url}/user/create?access_token=%s
# \u66f4\u65b0\u6210\u5458
user_update_uri={api_base_url}/user/update?access_token=%s
# \u83b7\u53d6\u6210\u5458
user_get_uri={api_base_url}/user/get?access_token=%s&userid=%s
# \u83b7\u53d6\u90e8\u95e8\u6210\u5458
user_list_uri={api_base_url}/user/simplelist?access_token=%s&department_id=%d&fetch_child=%d&status=%d
# \u5220\u9664\u6210\u5458
user_delete_uri={api_base_url}/user/delete?access_token=%s&userid=%s
# \u521b\u5efa\u6807\u7b7e
tag_create_uri={api_base_url}/tag/create?access_token=%s
# \u66f4\u65b0\u6807\u7b7e
tag_update_uri={api_base_url}/tag/update?access_token=%s
# \u5220\u9664\u6807\u7b7e
tag_delete_uri={api_base_url}/tag/delete?access_token=%s&tagid=%d
# \u83b7\u53d6\u6807\u7b7e
tag_list_uri={api_base_url}/tag/list?access_token=%s
# \u83b7\u53d6\u6807\u7b7e\u6210\u5458
tag_get_user_uri={api_base_url}/tag/get?access_token=%s&tagid=%d
# \u6dfb\u52a0\u6807\u7b7e\u6210\u5458
tag_add_user_uri={api_base_url}/tag/addtagusers?access_token=%s
# \u5220\u9664\u6807\u7b7e\u6210\u5458
tag_delete_user_uri={api_base_url}/tag/deltagusers?access_token=%s

View File

@ -0,0 +1,74 @@
package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable;
/**
* 部门对象
*
* @className Department
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E9%83%A8%E9%97%A8">管理部门说明</a>
*/
public class Department implements Serializable {
private static final long serialVersionUID = -2567893218591084288L;
private int id; // 部门ID
private String name; // 部门名称长度限制为1~64个字符
private int parentid;// 父亲部门id根部门id为1
private int order;// 在父部门中的次序从1开始数字越大排序越靠后
public Department() {
}
public Department(String name) {
this(name, 1, 1);
}
public Department(String name, int parentid, int order) {
this.name = name;
this.parentid = parentid;
this.order = order;
}
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 getParentid() {
return parentid;
}
public void setParentid(int parentid) {
this.parentid = parentid;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + ", parentid="
+ parentid + ", order=" + order + "]";
}
}

View File

@ -0,0 +1,40 @@
package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable;
public class NameValue implements Serializable {
private static final long serialVersionUID = -348620146718819093L;
private String name;
private String value;
public NameValue() {
}
public NameValue(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public void setName(String name) {
this.name = name;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "NameValue [name=" + name + ", value=" + value + "]";
}
}

View File

@ -0,0 +1,203 @@
package com.foxinmy.weixin4j.qy.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.Gender;
import com.foxinmy.weixin4j.qy.type.UserStatus;
/**
* 部门成员对象
*
* @className User
* @author jy
* @date 2014年11月19日
* @since JDK 1.7
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E6%88%90%E5%91%98">管理成员说明</a>
*/
public class User implements Serializable {
private static final long serialVersionUID = 4747301605060801611L;
private String userid;// 员工UserID对应管理端的帐号企业内必须唯一长度为1~64个字符
private String name;// 成员名称长度为1~64个字符
private List<Integer> department;// 成员所属部门id列表注意每个部门的直属员工上限为1000个
private String position;// 职位信息长度为0~64个字符
private String mobile;// 手机号码企业内必须唯一mobile/weixinid/email三者不能同时为空
private int gender;// 性别gender=0表示男=1表示女默认gender=0
private String tel;// 办公电话长度为0~64个字符
private String email;// 邮箱长度为0~64个字符企业内必须唯一
private String weixinid;// 微信号企业内必须唯一
private String avatar;// 头像url如果要获取小图将url最后的"/0"改成"/64"即可
private int status;// 关注状态: 1=已关注2=已冻结4=未关注
private List<NameValue> extattr;// 扩展属性扩展属性需要在WEB管理端创建后才生效否则忽略未知属性的赋值
public User() {
this.extattr = new ArrayList<NameValue>();
}
public User(String userid, String name) {
this(userid, name, null, null, null);
}
/**
* mobile/weixinid/email三者不能同时为空
*
* @param userid
* @param name
* @param tel
* @param email
* @param weixinid
*/
public User(String userid, String name, String tel, String email,
String weixinid) {
this.userid = userid;
this.name = name;
this.tel = tel;
this.email = email;
this.weixinid = weixinid;
this.extattr = new ArrayList<NameValue>();
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getDepartment() {
return department;
}
public void setDepartment(List<Integer> department) {
this.department = department;
}
public void setDepartment(Integer... department) {
this.department = Arrays.asList(department);
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public int getGender() {
return gender;
}
@JSONField(serialize = false)
public Gender getEnumGender() {
if (gender == 0) {
return Gender.male;
} else if (gender == 1) {
return Gender.female;
} else {
return Gender.unknown;
}
}
public void setGender(int gender) {
this.gender = gender;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getWeixinid() {
return weixinid;
}
public void setWeixinid(String weixinid) {
this.weixinid = weixinid;
}
@JSONField(serialize = false)
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
@JSONField(serialize = false)
public UserStatus getStatus() {
for (UserStatus userStatus : UserStatus.values()) {
if (userStatus.getVal() == status) {
return userStatus;
}
}
return null;
}
public void setStatus(int status) {
this.status = status;
}
public List<NameValue> getExtattr() {
return extattr;
}
public void setExtattr(List<NameValue> extattr) {
this.extattr = extattr;
}
public void setExtattr(NameValue... extattr) {
this.extattr = Arrays.asList(extattr);
}
public void pushExattr(String name, String value) {
pushExattr(new NameValue(name, value));
}
public void pushExattr(NameValue nameValue) {
extattr.add(nameValue);
}
@Override
public String toString() {
return "User [userid=" + userid + ", name=" + name + ", department="
+ department + ", position=" + position + ", mobile=" + mobile
+ ", gender=" + gender + ", tel=" + tel + ", email=" + email
+ ", weixinid=" + weixinid + ", avatar=" + avatar + ", status="
+ status + ", extattr=" + extattr + "]";
}
}

View File

@ -0,0 +1,26 @@
package com.foxinmy.weixin4j.qy.type;
/**
* 成员状态
*
* @className UserStatus
* @author jy
* @date 2014年11月19日
* @since JDK 1.7
* @see
*/
public enum UserStatus {
BOTH(0), // 0=全部
FOLLOW(1), // 1=已关注
FROZEN(2), // 2=已冻结
UNFOLLOW(4);// 4=未关注
private int val;
UserStatus(int val) {
this.val = val;
}
public int getVal() {
return val;
}
}

View File

@ -0,0 +1,13 @@
# \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath
# \u4f01\u4e1a\u53f7\u4fe1\u606f
account={"id":"wxd9d9fa581a07cefd","secret":"7tr6FXh2NORvqq1la9CVwxV0xZWGsRSgI6tfqd3-JFc9E2p7UukNNYeKoOTLe0Ru",\
"token":"gp2eGT5mIpngr",\
"encodingAesKey":"BRYfV4zPFUJb3v3MySNBg1ERKE3vyyMRoScu76vFySv"\
}
# \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

View File

@ -0,0 +1,58 @@
package com.foxinmy.weixin4j.qy.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.JsonResult;
import com.foxinmy.weixin4j.qy.api.DepartApi;
import com.foxinmy.weixin4j.qy.model.Department;
/**
* 部门API测试
*
* @className DepartTest
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see
*/
public class DepartTest extends TokenTest {
public DepartApi departApi;
@Before
public void init() {
this.departApi = new DepartApi(tokenHolder);
}
@Test
public void create() throws WeixinException {
Department depart = new Department("苦逼组");
int id = departApi.createDepart(depart);
Assert.assertTrue(id > 0);
}
@Test
public void update() throws WeixinException {
Department depart = new Department("苦逼组111");
depart.setId(2);
JsonResult result = departApi.updateDepart(depart);
Assert.assertEquals("updated", result.getDesc());
}
@Test
public void list() throws WeixinException {
List<Department> list = departApi.listDepart();
Assert.assertFalse(list.isEmpty());
System.out.println(list);
}
@Test
public void delete() throws WeixinException {
JsonResult result = departApi.deleteDepart(2);
Assert.assertEquals("deleted", result.getDesc());
}
}

View File

@ -0,0 +1,77 @@
package com.foxinmy.weixin4j.qy.test;
import java.util.Arrays;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.fastjson.JSONArray;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.JsonResult;
import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.model.User;
/**
* 部门API测试
*
* @className DepartTest
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see
*/
public class TagTest extends TokenTest {
public TagApi tagApi;
@Before
public void init() {
this.tagApi = new TagApi(tokenHolder);
}
@Test
public void create() throws WeixinException {
int tagId = tagApi.createTag("coder");
Assert.assertTrue(tagId > 0);
}
@Test
public void update() throws WeixinException {
JsonResult result = tagApi.updateTag(1, "coder456");
Assert.assertEquals("updated", result.getDesc());
}
@Test
public void getUsers() throws WeixinException {
List<User> listUser = tagApi.getTagUsers(1);
Assert.assertFalse(listUser.isEmpty());
System.out.println(listUser);
}
@Test
public void addUsers() throws WeixinException {
JsonResult result = tagApi.addTagUsers(1, Arrays.asList("jinyu"));
Assert.assertEquals("ok", result.getDesc());
}
@Test
public void deleteUsers() throws WeixinException {
JsonResult result = tagApi.deleteTagUsers(1, Arrays.asList("jinyu"));
Assert.assertEquals("ok", result.getDesc());
System.out.println(result);
}
@Test
public void list() throws WeixinException {
JSONArray tags = tagApi.listTag();
Assert.assertFalse(tags.isEmpty());
System.out.println(tags);
}
@Test
public void delete() throws WeixinException {
JsonResult result = tagApi.deleteTag(3);
Assert.assertEquals("deleted", result.getDesc());
}
}

View File

@ -0,0 +1,33 @@
package com.foxinmy.weixin4j.qy.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;
import com.foxinmy.weixin4j.type.AccountType;
/**
* token测试
*
* @className TokenTest
* @author jy.hu
* @date 2014年4月10日
* @since JDK 1.7
*/
public class TokenTest {
protected TokenHolder tokenHolder;
@Before
public void setUp() {
tokenHolder = new FileTokenHolder(AccountType.QY);
}
@Test
public void test() throws WeixinException {
Assert.assertNotNull(tokenHolder.getToken());
}
}

View File

@ -0,0 +1,70 @@
package com.foxinmy.weixin4j.qy.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.JsonResult;
import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.model.User;
/**
* 部门API测试
*
* @className DepartTest
* @author jy
* @date 2014年11月18日
* @since JDK 1.7
* @see
*/
public class UserTest extends TokenTest {
public UserApi userApi;
@Before
public void init() {
this.userApi = new UserApi(tokenHolder);
}
@Test
public void create() throws WeixinException {
User user = new User("u001", "jack");
user.setMobile("13500000000");
user.setDepartment(1);
user.pushExattr("爱好", "code");
JsonResult result = userApi.createUser(user);
Assert.assertEquals("created", result.getDesc());
}
@Test
public void update() throws WeixinException {
User user = new User("u001", "ted");
user.setMobile("13500000000");
user.setDepartment(1);
user.pushExattr("爱好", "code");
JsonResult result = userApi.updateUser(user);
Assert.assertEquals("updated", result.getDesc());
}
@Test
public void get() throws WeixinException {
User user = userApi.getUser("u001");
Assert.assertTrue(user != null);
System.out.println(user);
}
@Test
public void list() throws WeixinException {
List<User> userList = userApi.listUser(1);
Assert.assertFalse(userList.isEmpty());
System.out.println(userList);
}
@Test
public void delete() throws WeixinException {
JsonResult result = userApi.deleteUser("u001");
Assert.assertEquals("deleted", result.getDesc());
}
}

View File

@ -0,0 +1,28 @@
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
*~
# eclipse ignore
*.settings/*
/.project
/.classpath
/.tomcatplugin
# maven ignore
target/*
# other ignore
*.log
*.tmp
Thumbs.db
/target/
.DS_Store

View File

@ -0,0 +1,22 @@
weixin4j-qy-server
==================
微信企业号netty服务
------------
功能列表
-------
* `netty构建服务器`
* `消息分发`
如何使用
--------
更新LOG
-------
* 2014-11-19
+ 得到`weixin4j-qy-server`工程

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.foxinmy.weixin4j</groupId>
<artifactId>weixin4j-qy</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>weixin4j-qy-server</artifactId>
<name>weixin4j-qy-server</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-qy/weixin4j-qy-server</url>
<description>微信企业号工具包</description>
<build>
<finalName>weixin-qy-server</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,36 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>/lib</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>com/foxinmy/weixin4j/qy</directory>
<includes>
<include>**/*.md</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.sh</include>
<include>*.bat</include>
</includes>
</fileSet>
<fileSet>
<directory>src/main/resources</directory>
<outputDirectory>/conf</outputDirectory>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,142 @@
ulimit -n 110000
#JDK home
JAVA_HOME="/usr/local/java/"
#executing user
RUNNING_USER=root
#Run home
APP_HOME="/usr/local/weixin/weixin-mp-server"
#main class
APP_MAINCLASS=com.foxinmy.weixin4j.mp.startup.WeixinServerBootstrap
#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