精简WeixinAccount类及其配置文件

This commit is contained in:
jinyu 2015-07-29 10:58:41 +08:00
parent 0cca9d6d02
commit 954ee2175c
23 changed files with 256 additions and 268 deletions

View File

@ -382,3 +382,12 @@
+ 精简函数上的@link注释 + 精简函数上的@link注释
+ 新增媒体文件上传、下载结果类([MediaUploadResult.java](./weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaUploadResult.java),[MediaDownloadResult.java](./weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaDownloadResult.java)) + 新增媒体文件上传、下载结果类([MediaUploadResult.java](./weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaUploadResult.java),[MediaDownloadResult.java](./weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaDownloadResult.java))
* 2015-07-29
+ 精简WeixinAccount类及其配置文件
+ **weixin4j-mp**: 新增二维码结果类[QRResult.java](./weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java)并将二维码接口[QRApi.java](./weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java)名称变更为createQR和createQRFile
+ **weixin4j-mp**: [Oauth授权](./weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java)跳转的uri在配置文件的属性名改为`oauth_redirect_uri`

View File

@ -34,7 +34,7 @@ public class Button implements Serializable {
* *
* @see com.foxinmy.weixin4j.type.ButtonType * @see com.foxinmy.weixin4j.type.ButtonType
*/ */
private String type; private ButtonType type;
/** /**
* 菜单KEY值,根据type的类型而定,用于消息接口推送,不超过128字节. * 菜单KEY值,根据type的类型而定,用于消息接口推送,不超过128字节.
* <p> * <p>
@ -43,7 +43,9 @@ public class Button implements Serializable {
* <p> * <p>
* 使用API设置的自定义菜单</br> * 使用API设置的自定义菜单</br>
* clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album * clickscancode_pushscancode_waitmsgpic_sysphotopic_photo_or_album
* </br> pic_weixinlocation_select保存为keyview保存为url;media_idview_limited保存为media_id * </br>
* pic_weixinlocation_select保存为keyview保存为url;media_idview_limited
* 保存为media_id
* </p> * </p>
* </p> * </p>
*/ */
@ -64,13 +66,13 @@ public class Button implements Serializable {
* 菜单显示的名称 * 菜单显示的名称
* @param content * @param content
* 当buttonType为view时content设置为url,否则为key. * 当buttonType为view时content设置为url,否则为key.
* @param buttonType * @param type
* 按钮类型 * 按钮类型
*/ */
public Button(String name, String content, ButtonType buttonType) { public Button(String name, String content, ButtonType type) {
this.name = name; this.name = name;
this.content = content; this.content = content;
this.type = buttonType.name(); this.type = type;
} }
public String getName() { public String getName() {
@ -81,16 +83,11 @@ public class Button implements Serializable {
this.name = name; this.name = name;
} }
public String getType() { public ButtonType getType() {
return type; return type;
} }
@JSONField(serialize = false, deserialize = false) public void setType(ButtonType type) {
public ButtonType getFormatType() {
return ButtonType.valueOf(type);
}
public void setType(String type) {
this.type = type; this.type = type;
} }

View File

@ -2,6 +2,9 @@ package com.foxinmy.weixin4j.model;
import java.io.Serializable; import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONCreator;
import com.alibaba.fastjson.annotation.JSONField;
/** /**
* 微信账号信息 * 微信账号信息
* *
@ -12,6 +15,7 @@ import java.io.Serializable;
* @see * @see
*/ */
public class WeixinAccount implements Serializable { public class WeixinAccount implements Serializable {
private static final long serialVersionUID = -6001008896414323534L; private static final long serialVersionUID = -6001008896414323534L;
/** /**
@ -22,17 +26,10 @@ public class WeixinAccount implements Serializable {
* 调用接口的密钥 * 调用接口的密钥
*/ */
private String secret; private String secret;
private String token;
/**
* 安全模式下的加密密钥
*/
private String encodingAesKey;
public WeixinAccount() { @JSONCreator
public WeixinAccount(@JSONField(name = "id") String id,
} @JSONField(name = "secret") String secret) {
public WeixinAccount(String id, String secret) {
this.id = id; this.id = id;
this.secret = secret; this.secret = secret;
} }
@ -45,33 +42,8 @@ public class WeixinAccount implements Serializable {
return secret; return secret;
} }
public void setId(String id) {
this.id = id;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getEncodingAesKey() {
return encodingAesKey;
}
public void setEncodingAesKey(String encodingAesKey) {
this.encodingAesKey = encodingAesKey;
}
@Override @Override
public String toString() { public String toString() {
return "id=" + id + ", secret=" + secret + ", token=" + token return "id=" + id + ", secret=" + secret;
+ ", encodingAesKey=" + encodingAesKey;
} }
} }

View File

@ -53,42 +53,28 @@ public class WeixinPayAccount extends WeixinAccount {
* @param appSecret * @param appSecret
* 调用接口的凭证 * 调用接口的凭证
* @param paySignKey * @param paySignKey
* 支付密钥字符串 * 支付密钥字符串(必填)
* @param mchId * @param mchId
* 微信支付分配的商户号 * 微信支付分配的商户号(V3版本必填)
* @param partnerId 财付通的商户号(V2版本必填)
* @param partnerKey 财付通商户权限密钥Key(V2版本必填)
* @param subMchId 微信支付分配的子商户号受理模式下必填(商户平台版)
* @param deviceInfo 微信支付分配的设备号(商户平台版)
*/ */
@JSONCreator @JSONCreator
public WeixinPayAccount(@JSONField(name = "appId") String appId, public WeixinPayAccount(@JSONField(name = "id") String appId,
@JSONField(name = "appSecret") String appSecret, @JSONField(name = "secret") String appSecret,
@JSONField(name = "paySignKey") String paySignKey,
@JSONField(name = "mchId") String mchId) {
super(appId, appSecret);
this.paySignKey = paySignKey;
this.mchId = mchId;
}
/**
* V2版本字段
*
* @param appId
* 公众号唯一的身份ID
* @param appSecret
* 调用接口的凭证
* @param paySignKey
* 支付密钥字符串
* @param partnerId
* 财付通账号的ID
* @param partnerKey
* 财付通账号的key
*/
@JSONCreator
public WeixinPayAccount(@JSONField(name = "appId") String appId,
@JSONField(name = "appSecret") String appSecret,
@JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "paySignKey") String paySignKey,
@JSONField(name = "mchId") String mchId,
@JSONField(name = "subMchId") String subMchId,
@JSONField(name = "deviceInfo") String deviceInfo,
@JSONField(name = "partnerId") String partnerId, @JSONField(name = "partnerId") String partnerId,
@JSONField(name = "partnerKey") String partnerKey) { @JSONField(name = "partnerKey") String partnerKey) {
super(appId, appSecret); super(appId, appSecret);
this.paySignKey = paySignKey; this.paySignKey = paySignKey;
this.mchId = mchId;
this.subMchId = subMchId;
this.deviceInfo = deviceInfo;
this.partnerId = partnerId; this.partnerId = partnerId;
this.partnerKey = partnerKey; this.partnerKey = partnerKey;
} }
@ -126,9 +112,10 @@ public class WeixinPayAccount extends WeixinAccount {
@Override @Override
public String toString() { public String toString() {
return "WeixinPayAccount [paySignKey=" + paySignKey + ", partnerId=" return "WeixinPayAccount [" + super.toString() + ", paySignKey="
+ partnerId + ", partnerKey=" + partnerKey + ", mchId=" + mchId + paySignKey + ", partnerId=" + partnerId + ", partnerKey="
+ ", subMchId=" + subMchId + ", deviceInfo=" + deviceInfo + partnerKey + ", mchId=" + mchId + ", subMchId=" + subMchId
+ ", version=" + version + "]"; + ", deviceInfo=" + deviceInfo + ", version=" + getVersion()
+ "]";
} }
} }

View File

@ -67,7 +67,7 @@ public class Video implements NotifyTuple {
} }
/** /**
* 企业号 * 企业号 & 公众号群发
* *
* @param mediaId * @param mediaId
* @param title * @param title

View File

@ -121,3 +121,9 @@
* 2015-07-04 * 2015-07-04
+ released 1.5.1 + released 1.5.1
* 2015-07-29
+ 新增二维码结果类[QRResult.java](./src/main/java/com/foxinmy/weixin4j/mp/model/QRResult.java)并将二维码接口[QRApi.java](./weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java)名称变更为createQR和createQRFile
+ [Oauth授权](./src/main/java/com/foxinmy/weixin4j/mp/api/OauthApi.java)跳转的uri在配置文件的属性名改为`oauth_redirect_uri`

View File

@ -62,17 +62,14 @@ weixin4j.properties说明
| media_path | 调用媒体接口时保存媒体文件的物理路径 | | media_path | 调用媒体接口时保存媒体文件的物理路径 |
| bill_path | 调用下载对账单接口保存excel文件的物理路径 | | bill_path | 调用下载对账单接口保存excel文件的物理路径 |
| ca_file | 调用某些接口(支付相关)强制需要auth的ca授权文件 | | ca_file | 调用某些接口(支付相关)强制需要auth的ca授权文件 |
| redirect_uri | 调用OauthApi接口时需要填写的重定向路径 | | oauth_redirect_uri | 调用OauthApi接口时需要填写的重定向路径 |
示例(properties中换行用右斜杆\\) 示例(properties中换行用右斜杆\\)
account={"id":"appId","secret":"appSecret",\ account={"id":"appId","secret":"appSecret",\
"token":"开放者的token",\
"encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",\
"mchId":"V3.x版本下的微信商户号",\ "mchId":"V3.x版本下的微信商户号",\
"partnerId":"V2版本下的财付通的商户号",\ "partnerId":"V2版本下的财付通的商户号",\
"partnerKey":"V2版本下的财付通商户权限密钥Key",\ "partnerKey":"V2版本下的财付通商户权限密钥Key",\
"version":"针对微信支付的版本号(2,3),如果不填则按照mchId非空与否来判断",\
"paySignKey":"微信支付中调用API的密钥"} "paySignKey":"微信支付中调用API的密钥"}
token_path=/tmp/weixin4j/token token_path=/tmp/weixin4j/token
@ -84,7 +81,7 @@ weixin4j.properties说明
#classpath路径下:ca_file=classpath:xxxxx.p12 #classpath路径下:ca_file=classpath:xxxxx.p12
#公众号登陆授权的重定向路径(使用OauthApi时需要填写) #公众号登陆授权的重定向路径(使用OauthApi时需要填写)
redirect_uri=http://xxx oauth_redirect_uri=http://xxx
2.实例化微信企业号接口实现对象,调用具体的API方法 2.实例化微信企业号接口实现对象,调用具体的API方法

View File

@ -36,6 +36,7 @@ import com.foxinmy.weixin4j.mp.model.KfAccount;
import com.foxinmy.weixin4j.mp.model.KfSession; import com.foxinmy.weixin4j.mp.model.KfSession;
import com.foxinmy.weixin4j.mp.model.MenuSetting; import com.foxinmy.weixin4j.mp.model.MenuSetting;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRResult;
import com.foxinmy.weixin4j.mp.model.SemQuery; import com.foxinmy.weixin4j.mp.model.SemQuery;
import com.foxinmy.weixin4j.mp.model.SemResult; import com.foxinmy.weixin4j.mp.model.SemResult;
import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.model.User;
@ -641,22 +642,6 @@ public class WeixinProxy {
return massApi.uploadVideo(video); return massApi.uploadVideo(video);
} }
/**
* 分组群发
*
* @param tuple
* 消息元件
* @param groupId
* 分组ID
* @return 群发后的消息ID
* @see {@link #massMessage(MassTuple,boolean,int)}
* @throws WeixinException
*/
public String massByGroupId(MassTuple tuple, int groupId)
throws WeixinException {
return massApi.massByGroupId(tuple, groupId);
}
/** /**
* 群发消息 * 群发消息
* <p> * <p>
@ -685,9 +670,9 @@ public class WeixinProxy {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">根据分组群发</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">根据分组群发</a>
*/ */
public String massMessage(MassTuple tuple, boolean isToAll, int groupId) public String massByGroupId(MassTuple tuple, boolean isToAll, int groupId)
throws WeixinException { throws WeixinException {
return massApi.massMessage(tuple, isToAll, groupId); return massApi.massByGroupId(tuple, isToAll, groupId);
} }
/** /**
@ -1072,26 +1057,16 @@ public class WeixinProxy {
* *
* @param parameter * @param parameter
* 二维码参数 * 二维码参数
* @return byte数据包 * @return 二维码结果对象
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.QRResult
* @see com.foxinmy.weixin4j.mp.model.QRParameter * @see com.foxinmy.weixin4j.mp.model.QRParameter
* @see com.foxinmy.weixin4j.mp.api.QrApi * @see com.foxinmy.weixin4j.mp.api.QrApi
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a> * href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a>
*/ */
public byte[] getQRData(QRParameter parameter) throws WeixinException { public QRResult createQR(QRParameter parameter) throws WeixinException {
return qrApi.getQRData(parameter); return qrApi.createQR(parameter);
}
/**
* 生成带参数的二维码
*
* @return 二维码图片解析后的地址 开发者可根据该地址自行生成需要的二维码图片
* @throws WeixinException
* @see {@link #getQRData(QRParameter)}
*/
public String getQRUrl(QRParameter parameter) throws WeixinException {
return qrApi.getQRUrl(parameter);
} }
/** /**
@ -1099,10 +1074,10 @@ public class WeixinProxy {
* *
* @return 硬盘存储的文件对象 * @return 硬盘存储的文件对象
* @throws WeixinException * @throws WeixinException
* @see {@link #getQRData(QRParameter)} * @see {@link #createQR(QRParameter)}
*/ */
public File getQRFile(QRParameter parameter) throws WeixinException { public File createQRFile(QRParameter parameter) throws WeixinException {
return qrApi.getQRFile(parameter); return qrApi.createQRFile(parameter);
} }
/** /**

View File

@ -85,22 +85,6 @@ public class MassApi extends MpApi {
/** /**
* 分组群发 * 分组群发
*
* @param tuple
* 消息元件
* @param groupId
* 分组ID
* @return 群发后的消息ID
* @see {@link com.foxinmy.weixin4j.mp.api.MassApi#massMessage(MassTuple,boolean,int)}
* @throws WeixinException
*/
public String massByGroupId(MassTuple tuple, int groupId)
throws WeixinException {
return massMessage(tuple, false, groupId);
}
/**
* 群发消息
* <p> * <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息, * 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕 * 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
@ -126,7 +110,7 @@ public class MassApi extends MpApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">根据分组群发</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">根据分组群发</a>
*/ */
public String massMessage(MassTuple tuple, boolean isToAll, int groupId) public String massByGroupId(MassTuple tuple, boolean isToAll, int groupId)
throws WeixinException { throws WeixinException {
if (tuple instanceof MpNews) { if (tuple instanceof MpNews) {
MpNews _news = (MpNews) tuple; MpNews _news = (MpNews) tuple;
@ -175,7 +159,7 @@ public class MassApi extends MpApi {
public String massArticleByGroupId(List<MpArticle> articles, int groupId) public String massArticleByGroupId(List<MpArticle> articles, int groupId)
throws WeixinException { throws WeixinException {
String mediaId = uploadArticle(articles); String mediaId = uploadArticle(articles);
return massByGroupId(new MpNews(mediaId), groupId); return massByGroupId(new MpNews(mediaId), false, groupId);
} }
/** /**

View File

@ -57,17 +57,18 @@ public class MenuApi extends MpApi {
public String process(Object object, String name, public String process(Object object, String name,
Object value) { Object value) {
if (object instanceof Button && name.equals("content")) { if (object instanceof Button && name.equals("content")) {
ButtonType buttonType = ((Button) object) ButtonType buttonType = ((Button) object).getType();
.getFormatType(); if (buttonType != null) {
if (buttonType == ButtonType.view) { if (ButtonType.view == buttonType) {
return "url"; return "url";
} else if (buttonType == ButtonType.media_id } else if (ButtonType.media_id == buttonType
|| buttonType == ButtonType.view_limited) { || ButtonType.view_limited == buttonType) {
return "media_id"; return "media_id";
} else { } else {
return "key"; return "key";
} }
} }
}
return name; return name;
} }
})); }));
@ -117,8 +118,8 @@ public class MenuApi extends MpApi {
public JsonResult deleteMenu() throws WeixinException { public JsonResult deleteMenu() throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri"); String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
WeixinResponse response = weixinClient.get(String.format(menu_delete_uri, WeixinResponse response = weixinClient.get(String.format(
token.getAccessToken())); menu_delete_uri, token.getAccessToken()));
return response.getAsJsonResult(); return response.getAsJsonResult();
} }

View File

@ -32,7 +32,7 @@ public class OauthApi extends MpApi {
*/ */
public String getAuthorizeURL() { public String getAuthorizeURL() {
String appId = DEFAULT_WEIXIN_ACCOUNT.getId(); String appId = DEFAULT_WEIXIN_ACCOUNT.getId();
String redirectUri = ConfigUtil.getValue("redirect_uri"); String redirectUri = ConfigUtil.getValue("oauth_redirect_uri");
return getAuthorizeURL(appId, redirectUri, "state", "snsapi_login"); return getAuthorizeURL(appId, redirectUri, "state", "snsapi_login");
} }

View File

@ -5,11 +5,12 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRResult;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst; import com.foxinmy.weixin4j.util.Weixin4jConst;
@ -37,42 +38,25 @@ public class QrApi extends MpApi {
* *
* @param parameter * @param parameter
* 二维码参数 * 二维码参数
* @return 二维码图片解析后的地址 开发者可根据该地址自行生成需要的二维码图片 * @return 二维码结果对象
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.QRResult
* @see com.foxinmy.weixin4j.mp.model.QRParameter
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a> * href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a>
*/ */
public String getQRUrl(QRParameter parameter) throws WeixinException { public QRResult createQR(QRParameter parameter) throws WeixinException {
return doQR(parameter).getString("url");
}
private JSONObject doQR(QRParameter parameter) throws WeixinException {
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
String qr_uri = getRequestUri("qr_ticket_uri"); String qr_uri = getRequestUri("qr_ticket_uri");
WeixinResponse response = weixinClient.post( WeixinResponse response = weixinClient.post(
String.format(qr_uri, token.getAccessToken()), String.format(qr_uri, token.getAccessToken()),
parameter.getContent()); parameter.getContent());
return response.getAsJson(); QRResult result = response.getAsObject(new TypeReference<QRResult>() {
} });
qr_uri = getRequestUri("qr_image_uri");
/** response = weixinClient.get(String.format(qr_uri, result.getTicket()));
* 生成带参数的二维码 result.setContent(response.getContent());
* return result;
* @param parameter
* 二维码参数
* @return byte数据包
* @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.QRParameter
* @see <a
* href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a>
*/
public byte[] getQRData(QRParameter parameter) throws WeixinException {
String ticket = doQR(parameter).getString("ticket");
String qr_uri = getRequestUri("qr_image_uri");
WeixinResponse response = weixinClient.get(String
.format(qr_uri, ticket));
return response.getContent();
} }
/** /**
@ -87,9 +71,10 @@ public class QrApi extends MpApi {
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">二维码</a> * href="mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">二维码</a>
* @see #createQR(QRParameter)
* @see com.foxinmy.weixin4j.mp.model.QRParameter * @see com.foxinmy.weixin4j.mp.model.QRParameter
*/ */
public File getQRFile(QRParameter parameter) throws WeixinException { public File createQRFile(QRParameter parameter) throws WeixinException {
String qr_path = ConfigUtil.getValue("qr_path", String qr_path = ConfigUtil.getValue("qr_path",
Weixin4jConst.DEFAULT_QRCODE_PATH); Weixin4jConst.DEFAULT_QRCODE_PATH);
String filename = String.format("%s_%s_%d.jpg", parameter.getQrType() String filename = String.format("%s_%s_%d.jpg", parameter.getQrType()
@ -99,11 +84,11 @@ public class QrApi extends MpApi {
if (parameter.getQrType().ordinal() > 0 && file.exists()) { if (parameter.getQrType().ordinal() > 0 && file.exists()) {
return file; return file;
} }
byte[] datas = getQRData(parameter); QRResult qrResult = createQR(parameter);
OutputStream os = null; OutputStream os = null;
try { try {
os = new FileOutputStream(file); os = new FileOutputStream(file);
os.write(datas); os.write(qrResult.getContent());
} catch (IOException e) { } catch (IOException e) {
throw new WeixinException(e.getMessage()); throw new WeixinException(e.getMessage());
} finally { } finally {
@ -111,7 +96,7 @@ public class QrApi extends MpApi {
if (os != null) { if (os != null) {
os.close(); os.close();
} }
} catch (IOException ignore) { } catch (IOException e) {
; ;
} }
} }

View File

@ -0,0 +1,65 @@
package com.foxinmy.weixin4j.mp.model;
import java.io.Serializable;
import java.util.Arrays;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 二维码
*
* @className QRResult
* @author jy
* @date 2015年7月29日
* @since JDK 1.7
* @see
*/
public class QRResult implements Serializable {
private static final long serialVersionUID = 7730781702153258151L;
private String ticket;
private String url;
@JSONField(name = "expire_seconds")
private int expireSeconds;
private byte[] content;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getExpireSeconds() {
return expireSeconds;
}
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
@Override
public String toString() {
return "QRResult [ticket=" + ticket + ", url=" + url
+ ", expireSeconds=" + expireSeconds + ", content="
+ Arrays.toString(content) + "]";
}
}

View File

@ -1,10 +1,7 @@
# \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath # \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath
# \u516c\u4f17\u53f7\u4fe1\u606f # \u516c\u4f17\u53f7\u4fe1\u606f
account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"token":"\u5f00\u653e\u8005\u7684token",\
"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 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"version":2,\
"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"}
@ -23,4 +20,4 @@ ca_file=/tmp/weixin4j/xxxxx.p12
# ca_file=classpath:xxxxx.pfx # ca_file=classpath:xxxxx.pfx
# oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url # oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url
redirect_uri= oauth_redirect_uri=

View File

@ -30,7 +30,8 @@ public class CouponTest {
protected final static WeixinPayProxy WEIXINPAY; protected final static WeixinPayProxy WEIXINPAY;
protected final static WeixinPayAccount ACCOUNT; protected final static WeixinPayAccount ACCOUNT;
static { static {
ACCOUNT = new WeixinPayAccount("appid", "appsecret", "paysign", "mchid"); ACCOUNT = new WeixinPayAccount("appid", "appsecret", "paysign",
"mchid", null, null, null, null);
WEIXINPAY = new WeixinPayProxy(ACCOUNT); WEIXINPAY = new WeixinPayProxy(ACCOUNT);
} }
protected final File caFile = new File("证书文件路径(*.p12)"); protected final File caFile = new File("证书文件路径(*.p12)");

View File

@ -58,7 +58,7 @@ public class MassTest extends TokenTest {
@Test @Test
public void massByGroupId() throws WeixinException { public void massByGroupId() throws WeixinException {
String msgId = massApi.massByGroupId(new Image("mediaId"), 0); String msgId = massApi.massByGroupId(new Image("mediaId"), true, 0);
Assert.assertTrue(msgId != null); Assert.assertTrue(msgId != null);
} }

View File

@ -33,11 +33,12 @@ public class PayTest {
private final static WeixinPayAccount ACCOUNT3; private final static WeixinPayAccount ACCOUNT3;
static { static {
ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret",
"请填入v3版本的paysignkey", "请填入v2版本的partnerId", "请填入v2版本的partnerKey"); "请填入v2版本的paysignkey", null, null, null, "请填入v2版本的partnerId",
"请填入v2版本的partnerKey");
PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager(ConfigUtil.getValue( PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager(ConfigUtil.getValue(
"token_path", "/tmp/weixin4j/token"))); "token_path", "/tmp/weixin4j/token")));
ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret", ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret",
"请填入v3版本的paysignkey", "请填入v3版本的mchid"); "请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null);
PAY3 = new WeixinPayProxy(ACCOUNT3); PAY3 = new WeixinPayProxy(ACCOUNT3);
} }

View File

@ -29,19 +29,19 @@ public class QRTest extends TokenTest {
@Test @Test
public void temp_qr() throws WeixinException, IOException { public void temp_qr() throws WeixinException, IOException {
File file = qrApi.getQRFile(QRParameter.createTemporary(1200, 1200)); File file = qrApi.createQRFile(QRParameter.createTemporary(1200, 1200));
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }
@Test @Test
public void forever_qr_int() throws WeixinException, IOException { public void forever_qr_int() throws WeixinException, IOException {
File file = qrApi.getQRFile(QRParameter.createPermanenceInt(1200)); File file = qrApi.createQRFile(QRParameter.createPermanenceInt(1200));
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }
@Test @Test
public void forever_qr_str() throws WeixinException, IOException { public void forever_qr_str() throws WeixinException, IOException {
File file = qrApi.getQRFile(QRParameter.createPermanenceStr("1200中文")); File file = qrApi.createQRFile(QRParameter.createPermanenceStr("1200中文"));
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }
} }

View File

@ -2,9 +2,15 @@ package com.foxinmy.weixin4j.mp.test;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.FileReader; import java.io.FileReader;
import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.payment.v2.RefundRecordV2; import com.foxinmy.weixin4j.mp.payment.v2.RefundRecordV2;
import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.Order;
@ -99,6 +105,26 @@ public class XmlstreamTest {
com.foxinmy.weixin4j.payment.mch.RefundRecord.class)); com.foxinmy.weixin4j.payment.mch.RefundRecord.class));
} }
public static String errorXml() {
StringBuffer xml = new StringBuffer();
String url = "http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E";
try {
Document doc = Jsoup.parse(new URL(url), 5000);
Elements eles = doc.getElementsByTag("tr");
for (Element ele : eles) {
xml.append("<error>");
xml.append("<code>").append(ele.child(0).text())
.append("</code>");
xml.append("<text>").append(ele.child(1).text())
.append("</text>");
xml.append("</error>");
}
} catch (Exception e) {
e.printStackTrace();
}
return xml.toString();
}
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// map2xml(); // map2xml();
// xml2map(); // xml2map();
@ -106,13 +132,15 @@ public class XmlstreamTest {
// System.err.println(xml2refundRecordV2()); // System.err.println(xml2refundRecordV2());
// xml2refundRecordV3(); // xml2refundRecordV3();
// object2xmlWithoutRootElement(); // object2xmlWithoutRootElement();
/*RefundRecord refundRecord = xml2refundRecordV2(); /*
System.err.println(refundRecord); * RefundRecord refundRecord = xml2refundRecordV2();
String sign = refundRecord.getSign(); * System.err.println(refundRecord); String sign =
refundRecord.setSign(null); * refundRecord.getSign(); refundRecord.setSign(null); String validSign
String validSign = PayUtil.paysignMd5(refundRecord, "paysignkey"); * = PayUtil.paysignMd5(refundRecord, "paysignkey");
System.err.println("sign=" + sign + ",validSign=" + validSign); * System.err.println("sign=" + sign + ",validSign=" + validSign);
System.err.println(ListsuffixResultSerializer * System.err.println(ListsuffixResultSerializer
.serializeToXML(refundRecord));*/ * .serializeToXML(refundRecord));
*/
// System.out.println(errorXml());
} }
} }

View File

@ -59,8 +59,8 @@ weixin4j.properties说明
account={"id":"corpid","secret":"corpsecret",\ account={"id":"corpid","secret":"corpsecret",\
"token":"企业号中应用在回调模式下的token",\ "token":"企业号中应用在回调模式下的token",\
"encodingAesKey":"企业号中应用在回调模式下AES加密密钥",\ "providerSecret:"第三方提供商secret(企业号登陆)",\
"providerSecret:"提供商的secret"} "chatSecret":"消息服务secret(企业号聊天)"}
token_path=/tmp/weixin4j/token token_path=/tmp/weixin4j/token
media_path=/tmp/weixin4j/media media_path=/tmp/weixin4j/media

View File

@ -60,17 +60,18 @@ public class MenuApi extends QyApi {
public String process(Object object, String name, public String process(Object object, String name,
Object value) { Object value) {
if (object instanceof Button && name.equals("content")) { if (object instanceof Button && name.equals("content")) {
ButtonType buttonType = ((Button) object) ButtonType buttonType = ((Button) object).getType();
.getFormatType(); if (buttonType != null) {
if (buttonType == ButtonType.view) { if (ButtonType.view == buttonType) {
return "url"; return "url";
} else if (buttonType == ButtonType.media_id } else if (ButtonType.media_id == buttonType
|| buttonType == ButtonType.view_limited) { || ButtonType.view_limited == buttonType) {
return "media_id"; return "media_id";
} else { } else {
return "key"; return "key";
} }
} }
}
return name; return name;
} }
})); }));
@ -124,8 +125,8 @@ public class MenuApi extends QyApi {
public JsonResult deleteMenu(int agentid) throws WeixinException { public JsonResult deleteMenu(int agentid) throws WeixinException {
String menu_delete_uri = getRequestUri("menu_delete_uri"); String menu_delete_uri = getRequestUri("menu_delete_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
WeixinResponse response = weixinClient.get(String.format(menu_delete_uri, WeixinResponse response = weixinClient.get(String.format(
token.getAccessToken(), agentid)); menu_delete_uri, token.getAccessToken(), agentid));
return response.getAsJsonResult(); return response.getAsJsonResult();
} }

View File

@ -1,5 +1,7 @@
package com.foxinmy.weixin4j.qy.model; package com.foxinmy.weixin4j.qy.model;
import com.alibaba.fastjson.annotation.JSONCreator;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
/** /**
@ -17,19 +19,33 @@ public class WeixinQyAccount extends WeixinAccount {
private static final long serialVersionUID = 3689999353867189585L; private static final long serialVersionUID = 3689999353867189585L;
public WeixinQyAccount(){
}
/** /**
* *
* @param corpid * @param corpid
* 企业ID * 企业ID
* @param corpsecret * @param corpsecret
* 管理组的凭证密钥 * 管理组的凭证密钥
* @param suiteId
* 应用套件的id
* @param suiteSecret
* 应用套件的secret
* @param providerSecret
* 第三方提供商secret(企业号登陆)
* @param chatSecret
* 消息服务secret(企业号聊天)
*/ */
public WeixinQyAccount(String corpid, String corpsecret) { @JSONCreator
public WeixinQyAccount(@JSONField(name = "id") String corpid,
@JSONField(name = "secret") String corpsecret,
@JSONField(name = "suiteId") String suiteId,
@JSONField(name = "suiteSecret") String suiteSecret,
@JSONField(name = "providerSecret") String providerSecret,
@JSONField(name = "chatSecret") String chatSecret) {
super(corpid, corpsecret); super(corpid, corpsecret);
this.suiteId = suiteId;
this.suiteSecret = suiteSecret;
this.providerSecret = providerSecret;
this.chatSecret = chatSecret;
} }
/** /**
@ -41,65 +57,34 @@ public class WeixinQyAccount extends WeixinAccount {
*/ */
private String suiteSecret; private String suiteSecret;
/** /**
* 应用套件token,用于生成签名,校验回调请求的合法性后续所有托管的企业产生的回调消息都使用该值来解密 * 第三方提供商secret(企业号登陆)
*/
private String suiteToken;
/**
* 应用套件encodingAesKey,回调消息加解密参数是AES密钥的Base64编码用于解密回调消息内容对应的密文
* 后续所有托管的企业产生的回调消息都使用该值来解密
*/
private String suiteEncodingAesKey;
/**
* 提供商的secret
*/ */
private String providerSecret; private String providerSecret;
/**
* 消息服务secret(企业号聊天)
*/
private String chatSecret;
public String getSuiteId() { public String getSuiteId() {
return suiteId; return suiteId;
} }
public void setSuiteId(String suiteId) {
this.suiteId = suiteId;
}
public String getSuiteSecret() { public String getSuiteSecret() {
return suiteSecret; return suiteSecret;
} }
public void setSuiteSecret(String suiteSecret) {
this.suiteSecret = suiteSecret;
}
public String getSuiteToken() {
return suiteToken;
}
public void setSuiteToken(String suiteToken) {
this.suiteToken = suiteToken;
}
public String getSuiteEncodingAesKey() {
return suiteEncodingAesKey;
}
public void setSuiteEncodingAesKey(String suiteEncodingAesKey) {
this.suiteEncodingAesKey = suiteEncodingAesKey;
}
public String getProviderSecret() { public String getProviderSecret() {
return providerSecret; return providerSecret;
} }
public void setProviderSecret(String providerSecret) { public String getChatSecret() {
this.providerSecret = providerSecret; return chatSecret;
} }
@Override @Override
public String toString() { public String toString() {
return "WeixinQyAccount [" + super.toString() + ", suiteId=" + suiteId return "WeixinQyAccount [" + super.toString() + ", suiteId=" + suiteId
+ ", suiteSecret=" + suiteSecret + ", suiteToken=" + suiteToken + ", suiteSecret=" + suiteSecret + ", providerSecret="
+ ", suiteEncodingAesKey=" + suiteEncodingAesKey + providerSecret + ", chatSecret=" + chatSecret + "]";
+ ", providerSecret=" + providerSecret + "]";
} }
} }

View File

@ -1,12 +1,9 @@
# \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath # \u6d4b\u8bd5\u4e4b\u7528 \u6b63\u5f0f\u73af\u5883\u4e0bcopy\u4e00\u4efd\u5230classpath
# \u4f01\u4e1a\u53f7\u4fe1\u606f # \u4f01\u4e1a\u53f7\u4fe1\u606f
account={"id":"wx6d13cc18002bb2e5","secret":"vcCOTIb-cOzWWhL5r_qKVlfzdpInEEKPRz3K-5ezn-Xt48-tOkxPqEE5XbKLXXFn",\ account={"id":"wx6d13cc18002bb2e5","secret":"vcCOTIb-cOzWWhL5r_qKVlfzdpInEEKPRz3K-5ezn-Xt48-tOkxPqEE5XbKLXXFn",\
"token":"gp2eGT5mIpngr",\
"encodingAesKey":"BRYfV4zPFUJb3v3MySNBg1ERKE3vyyMRoScu76vFySv",\
"suiteId":"\u5e94\u7528\u5957\u4ef6\u7684id","suiteSecret":"\u5e94\u7528\u5957\u4ef6\u7684secret",\ "suiteId":"\u5e94\u7528\u5957\u4ef6\u7684id","suiteSecret":"\u5e94\u7528\u5957\u4ef6\u7684secret",\
"suiteToken":"\u5e94\u7528\u5957\u4ef6\u7684token",\ "providerSecret":"\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546secret(\u4f01\u4e1a\u53f7\u767b\u9646)",\
"suiteEncodingAesKey":"\u5e94\u7528\u5957\u4ef6\u7684encodingAesKey",\ "chatSecret":"\u6d88\u606f\u670d\u52a1secret(\u4f01\u4e1a\u53f7\u804a\u5929)"}
"providerSecret":"\u63d0\u4f9b\u5546\u7684secret"}
# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84 # \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84
token_path=/tmp/weixin4j/token token_path=/tmp/weixin4j/token