重构Weixin4jSettings...

This commit is contained in:
jinyu 2016-02-02 19:48:30 +08:00
parent baff97e9db
commit 8a9f93e54e
39 changed files with 636 additions and 1020 deletions

View File

@ -17,6 +17,10 @@
<artifactId>fastjson</artifactId> <artifactId>fastjson</artifactId>
<version>1.2.3</version> <version>1.2.3</version>
</dependency> </dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency> <dependency>
<groupId>commons-httpclient</groupId> <groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId> <artifactId>commons-httpclient</artifactId>

View File

@ -12,6 +12,7 @@ import java.nio.charset.Charset;
* @see * @see
*/ */
public final class Consts { public final class Consts {
public static final String WEIXIN4J = "weixin4j";
public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset UTF_8 = Charset.forName("UTF-8");
public static final Charset GBK = Charset.forName("GBK"); public static final Charset GBK = Charset.forName("GBK");
public static final String SUCCESS = "SUCCESS"; public static final String SUCCESS = "SUCCESS";

View File

@ -49,9 +49,9 @@ public class WeixinPayAccount extends WeixinAccount {
* 商户平台版本(V3)字段 * 商户平台版本(V3)字段
* *
* @param appId * @param appId
* 公众号唯一的身份ID * 公众号唯一的身份ID(必填)
* @param appSecret * @param appSecret
* 调用接口的凭证 * 调用接口的凭证(最好填写)
* @param paySignKey * @param paySignKey
* 支付密钥字符串(必填) * 支付密钥字符串(必填)
* @param mchId * @param mchId
@ -68,7 +68,7 @@ public class WeixinPayAccount extends WeixinAccount {
* @param appId * @param appId
* 公众号唯一的身份ID(必填) * 公众号唯一的身份ID(必填)
* @param appSecret * @param appSecret
* 调用接口的凭证(必填) * 调用接口的凭证(最好填写)
* @param paySignKey * @param paySignKey
* 支付密钥字符串(必填) * 支付密钥字符串(必填)
* @param mchId * @param mchId

View File

@ -30,11 +30,11 @@ import com.foxinmy.weixin4j.payment.mch.Redpacket;
import com.foxinmy.weixin4j.payment.mch.RedpacketRecord; import com.foxinmy.weixin4j.payment.mch.RedpacketRecord;
import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult; import com.foxinmy.weixin4j.payment.mch.RedpacketSendResult;
import com.foxinmy.weixin4j.payment.mch.RefundRecord; import com.foxinmy.weixin4j.payment.mch.RefundRecord;
import com.foxinmy.weixin4j.settings.Weixin4jPaySettings;
import com.foxinmy.weixin4j.type.BillType; import com.foxinmy.weixin4j.type.BillType;
import com.foxinmy.weixin4j.type.CurrencyType; import com.foxinmy.weixin4j.type.CurrencyType;
import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.TradeType; import com.foxinmy.weixin4j.type.TradeType;
import com.foxinmy.weixin4j.util.Weixin4jSettings;
/** /**
* 微信支付接口实现 * 微信支付接口实现
@ -52,26 +52,26 @@ public class WeixinPayProxy {
private final CouponApi couponApi; private final CouponApi couponApi;
private final CashApi cashApi; private final CashApi cashApi;
private final Weixin4jPaySettings settings; private final Weixin4jSettings settings;
/** /**
* 使用weixin4j.properties配置的支付账号信息 * 使用weixin4j.properties配置的支付账号信息
*/ */
public WeixinPayProxy() { public WeixinPayProxy() {
this(new Weixin4jPaySettings()); this(new Weixin4jSettings());
} }
/** /**
* *
* @param settings * @param settings
* 支付相关配置信息 * 支付相关配置信息
* @see com.foxinmy.weixin4j.settings.Weixin4jPaySettings * @see com.foxinmy.weixin4j.util.Weixin4jSettings
*/ */
public WeixinPayProxy(Weixin4jPaySettings settings) { public WeixinPayProxy(Weixin4jSettings settings) {
this.settings = settings; this.settings = settings;
this.pay3Api = new Pay3Api(settings.getPayAccount()); this.pay3Api = new Pay3Api(settings.getWeixinPayAccount());
this.couponApi = new CouponApi(settings.getPayAccount()); this.couponApi = new CouponApi(settings.getWeixinPayAccount());
this.cashApi = new CashApi(settings.getPayAccount()); this.cashApi = new CashApi(settings.getWeixinPayAccount());
} }
/** /**
@ -80,7 +80,7 @@ public class WeixinPayProxy {
* @return * @return
*/ */
public WeixinPayAccount getPayAccount() { public WeixinPayAccount getPayAccount() {
return this.settings.getPayAccount(); return this.settings.getWeixinPayAccount();
} }
/** /**
@ -467,7 +467,7 @@ public class WeixinPayProxy {
IdQuery idQuery, String outRefundNo, double totalFee) IdQuery idQuery, String outRefundNo, double totalFee)
throws WeixinException, IOException { throws WeixinException, IOException {
return pay3Api.refundApply( return pay3Api.refundApply(
new FileInputStream(settings.getCertificatePath()), idQuery, new FileInputStream(settings.getCertificateFile0()), idQuery,
outRefundNo, totalFee); outRefundNo, totalFee);
} }
@ -514,7 +514,7 @@ public class WeixinPayProxy {
*/ */
public File downloadBill(Date billDate, BillType billType) public File downloadBill(Date billDate, BillType billType)
throws WeixinException { throws WeixinException {
return pay3Api.downloadBill(billDate, billType, settings.getBillPath()); return pay3Api.downloadBill(billDate, billType, settings.getTmpdir0());
} }
/** /**
@ -551,7 +551,7 @@ public class WeixinPayProxy {
public ApiResult reverseOrder(IdQuery idQuery) throws WeixinException, public ApiResult reverseOrder(IdQuery idQuery) throws WeixinException,
IOException { IOException {
return pay3Api.reverseOrder( return pay3Api.reverseOrder(
new FileInputStream(settings.getCertificatePath()), idQuery); new FileInputStream(settings.getCertificateFile0()), idQuery);
} }
/** /**
@ -655,7 +655,7 @@ public class WeixinPayProxy {
public CouponResult sendCoupon(String couponStockId, String partnerTradeNo, public CouponResult sendCoupon(String couponStockId, String partnerTradeNo,
String openId) throws WeixinException, IOException { String openId) throws WeixinException, IOException {
return couponApi.sendCoupon( return couponApi.sendCoupon(
new FileInputStream(settings.getCertificatePath()), new FileInputStream(settings.getCertificateFile0()),
couponStockId, partnerTradeNo, openId, null); couponStockId, partnerTradeNo, openId, null);
} }
@ -721,7 +721,7 @@ public class WeixinPayProxy {
public RedpacketSendResult sendRedpack(Redpacket redpacket) public RedpacketSendResult sendRedpack(Redpacket redpacket)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi.sendRedpack( return cashApi.sendRedpack(
new FileInputStream(settings.getCertificatePath()), redpacket); new FileInputStream(settings.getCertificateFile0()), redpacket);
} }
/** /**
@ -750,8 +750,10 @@ public class WeixinPayProxy {
*/ */
public RedpacketRecord queryRedpack(String outTradeNo) public RedpacketRecord queryRedpack(String outTradeNo)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi.queryRedpack( return cashApi
new FileInputStream(settings.getCertificatePath()), outTradeNo); .queryRedpack(
new FileInputStream(settings.getCertificateFile0()),
outTradeNo);
} }
/** /**
@ -782,7 +784,7 @@ public class WeixinPayProxy {
public MPPaymentResult mpPayment(MPPayment mpPayment) public MPPaymentResult mpPayment(MPPayment mpPayment)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi.mchPayment( return cashApi.mchPayment(
new FileInputStream(settings.getCertificatePath()), mpPayment); new FileInputStream(settings.getCertificateFile0()), mpPayment);
} }
/** /**
@ -811,8 +813,10 @@ public class WeixinPayProxy {
*/ */
public MPPaymentRecord mpPaymentQuery(String outTradeNo) public MPPaymentRecord mpPaymentQuery(String outTradeNo)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi.mchPaymentQuery( return cashApi
new FileInputStream(settings.getCertificatePath()), outTradeNo); .mchPaymentQuery(
new FileInputStream(settings.getCertificateFile0()),
outTradeNo);
} }
/** /**

View File

@ -1,14 +0,0 @@
package com.foxinmy.weixin4j.settings;
/**
* 微信请求配置相关(待实现
*
* @className Weixin4jHttpSettings
* @author jy
* @date 2016年1月28日
* @since JDK 1.6
* @see
*/
public class Weixin4jHttpSettings {
}

View File

@ -1,108 +0,0 @@
package com.foxinmy.weixin4j.settings;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/**
* 微信支付配置相关
*
* @className Weixin4jPaySettings
* @author jy
* @date 2016年1月28日
* @since JDK 1.6
* @see
*/
public class Weixin4jPaySettings {
private final WeixinPayAccount payAccount;
public Weixin4jPaySettings() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
WeixinPayAccount.class));
}
public Weixin4jPaySettings(WeixinPayAccount payAccount) {
this.payAccount = payAccount;
}
/**
* 支付账号信息
*
* @return
*/
public WeixinPayAccount getPayAccount() {
return this.payAccount;
}
private String billPath;
/**
* 对账单保存路径
*
* @param billPath
* 硬盘目录
*/
public Weixin4jPaySettings billPath(String billPath) {
this.billPath = billPath;
return this;
}
/**
* 默认对账单保存路径
*/
public static final String DEFAULT_BILL_PATH = "/tmp/weixin4j/bill";
/**
* 对账单保存路径,默认值为{@link #DEFAULT_BILL_PATH}
*
* @return
*/
public String getBillPath() {
if (StringUtil.isBlank(billPath)) {
this.billPath = Weixin4jConfigUtil.getClassPathValue("bill.path",
DEFAULT_BILL_PATH);
}
return this.billPath;
}
private String certificatePath;
/**
* ca证书存放路径
*
* @param certificatePath
* 硬盘目录
* @return
*/
public Weixin4jPaySettings certificatePath(String certificatePath) {
this.certificatePath = certificatePath;
return this;
}
/**
* 默认ca证书存放路径
*/
public static final String DEFAULT_CAFILE_PATH = "classpath:ca.p12";
/**
* ca证书存放路径,默认值为{@link #DEFAULT_CAFILE_PATH}
*
* @return
*/
public String getCertificatePath() {
if (StringUtil.isBlank(certificatePath)) {
this.certificatePath = Weixin4jConfigUtil.getClassPathValue(
"certificate.path", DEFAULT_CAFILE_PATH);
}
return this.certificatePath;
}
@Override
public String toString() {
return "Weixin4jPaySettings [payAccount=" + payAccount + ", billPath="
+ getBillPath() + ", certificatePath=" + getCertificatePath()
+ "]";
}
}

View File

@ -1,168 +0,0 @@
package com.foxinmy.weixin4j.settings;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/**
* 微信基础配置相关
*
* @className Weixin4jSettings
* @author jy
* @date 2016年1月28日
* @since JDK 1.6
* @see
*/
public class Weixin4jSettings {
private final WeixinAccount account;
public Weixin4jSettings() {
this(Weixin4jConfigUtil.getWeixinAccount());
}
/**
*
* @param id
* 应用唯一标识 appid/corpid
* @param secret
* 应用接口密钥
*/
public Weixin4jSettings(String id, String secret) {
this(new WeixinAccount(id, secret));
}
public Weixin4jSettings(WeixinAccount account) {
this.account = account;
}
/**
* 微信账号信息
*/
public WeixinAccount getAccount() {
return this.account;
}
private String tokenPath;
/**
* 使用FileTokenStorager时token的存放路径
*
* @param tokenPath
* 硬盘目录
* @return
*/
public Weixin4jSettings setTokenPath(String tokenPath) {
this.tokenPath = tokenPath;
return this;
}
/**
* 默认token的存放路径
*/
public static final String DEFAULT_TOKEN_PATH = "/tmp/weixin4j/token";
/**
* 使用FileTokenStorager时token的存放路径,默认值为{@link #DEFAULT_TOKEN_PATH}
*/
public String getTokenPath() {
if (StringUtil.isBlank(tokenPath)) {
tokenPath = Weixin4jConfigUtil.getClassPathValue("token.path",
DEFAULT_TOKEN_PATH);
}
return tokenPath;
}
private String qrcodePath;
/**
* 二维码保存路径
*
* @param qrcodePath
* 硬盘目录
*/
public Weixin4jSettings setQrcodePath(String qrcodePath) {
this.qrcodePath = qrcodePath;
return this;
}
/**
* 默认二维码保存路径
*/
public static final String DEFAULT_QRCODE_PATH = "/tmp/weixin4j/qrcode";
/**
* 二维码保存路径,默认值为{@link #DEFAULT_QRCODE_PATH}
*/
public String getQrcodePath() {
if (StringUtil.isBlank(qrcodePath)) {
this.qrcodePath = Weixin4jConfigUtil.getClassPathValue(
"qrcode.path", DEFAULT_QRCODE_PATH);
}
return this.qrcodePath;
}
private String mediaPath;
/**
* 媒体文件保存路径
*
* @param mediaPath
* 硬盘目录
*/
public Weixin4jSettings setMediaPath(String mediaPath) {
this.mediaPath = mediaPath;
return this;
}
/**
* 默认媒体文件保存路径
*/
public static final String DEFAULT_MEDIA_PATH = "/tmp/weixin4j/media";
/**
* 媒体文件保存路径,默认值为{@link #DEFAULT_MEDIA_PATH}
*/
public String getMediaPath() {
if (StringUtil.isBlank(mediaPath)) {
this.mediaPath = Weixin4jConfigUtil.getClassPathValue("media.path",
DEFAULT_MEDIA_PATH);
}
return this.mediaPath;
}
private TokenStorager tokenStorager;
/**
* token存储
*
* @param tokenStorager
* @return
*/
public Weixin4jSettings setTokenStorager(TokenStorager tokenStorager) {
this.tokenStorager = tokenStorager;
return this;
}
/**
* 获取token存储方式 默认为FileTokenStorager
*
* @return
*/
public TokenStorager getTokenStorager() {
if (tokenStorager == null) {
this.tokenStorager = new FileTokenStorager(getTokenPath());
}
return this.tokenStorager;
}
@Override
public String toString() {
return "Weixin4jSettings [account=" + account + ", tokenPath="
+ getTokenPath() + ", qrcodePath=" + getQrcodePath()
+ ", mediaPath=" + getMediaPath() + ", tokenStorager="
+ getTokenStorager() + "]";
}
}

View File

@ -1,6 +1,5 @@
package com.foxinmy.weixin4j.util; package com.foxinmy.weixin4j.util;
import java.io.File;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -25,18 +24,6 @@ public class Weixin4jConfigUtil {
.getResource("").getPath(); .getResource("").getPath();
try { try {
weixinBundle = ResourceBundle.getBundle("weixin4j"); weixinBundle = ResourceBundle.getBundle("weixin4j");
File file = null;
for (String key : weixinBundle.keySet()) {
if (!key.endsWith(".path")) {
continue;
}
file = new File(getValue(key).replaceFirst(CLASSPATH_PREFIX,
CLASSPATH_VALUE));
if (!file.exists() && !file.mkdirs()) {
System.err.append(String.format("%s create fail.%n",
file.getAbsolutePath()));
}
}
} catch (MissingResourceException e) { } catch (MissingResourceException e) {
; ;
} }

View File

@ -0,0 +1,155 @@
package com.foxinmy.weixin4j.util;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.http.HttpParams;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenStorager;
/**
* 微信配置相关
*
* @className Weixin4jSettings
* @author jy
* @date 2016年1月28日
* @since JDK 1.6
* @see
*/
public class Weixin4jSettings {
/**
* 微信支付账号信息
*/
private WeixinPayAccount weixinPayAccount;
/**
* 微信账号信息
*/
private WeixinAccount weixinAccount;
/**
* Http参数
*/
private HttpParams httpParams;
/**
* token存储方式 默认为FileTokenStorager
*/
private TokenStorager tokenStorager;
/**
* 系统临时目录
*/
private String tmpdir;
/**
* 支付接口需要的证书文件(*.p12)
*/
private String certificateFile;
/**
* 默认使用weixin4j.properties配置的信息
*/
public Weixin4jSettings() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
WeixinPayAccount.class));
}
/**
* 支付代理接口
*
* @param weixinPayAccount
* 商户信息
* @param certificateFile
* 支付接口需要的证书文件(*.p12),比如退款接口
*/
public Weixin4jSettings(WeixinPayAccount weixinPayAccount,
String certificateFile) {
this.weixinPayAccount = weixinPayAccount;
this.certificateFile = certificateFile;
this.weixinAccount = new WeixinAccount(weixinPayAccount.getId(),
weixinPayAccount.getSecret());
}
/**
* 普通代理接口
*
* @param weixinAccount
*/
public Weixin4jSettings(WeixinAccount weixinAccount) {
this.weixinAccount = weixinAccount;
}
public WeixinPayAccount getWeixinPayAccount() {
return weixinPayAccount;
}
public WeixinAccount getWeixinAccount() {
return weixinAccount;
}
public HttpParams getHttpParams() {
return httpParams;
}
public HttpParams getHttpParams0() {
if (httpParams == null) {
return new HttpParams();
}
return httpParams;
}
public String getTmpdir() {
return tmpdir;
}
public String getTmpdir0() {
if (StringUtil.isBlank(tmpdir)) {
return Weixin4jConfigUtil.getClassPathValue("weixin4j.tmpdir",
System.getProperty("java.io.tmpdir"));
}
return tmpdir;
}
public TokenStorager getTokenStorager() {
return tokenStorager;
}
public TokenStorager getTokenStorager0() {
if (tokenStorager == null) {
return new FileTokenStorager(getTmpdir0());
}
return tokenStorager;
}
public String getCertificateFile() {
return certificateFile;
}
public String getCertificateFile0() {
if (StringUtil.isBlank(certificateFile)) {
return Weixin4jConfigUtil.getClassPathValue(
"weixin4j.certificate.file", "classpath:ca.p12");
}
return certificateFile;
}
public void setHttpParams(HttpParams httpParams) {
this.httpParams = httpParams;
}
public void setTmpdir(String tmpdir) {
this.tmpdir = tmpdir;
}
public void setTokenStorager(TokenStorager tokenStorager) {
this.tokenStorager = tokenStorager;
}
public void setCertificateFile(String certificateFile) {
this.certificateFile = certificateFile;
}
@Override
public String toString() {
return "Weixin4jSettings [weixinAccount=" + weixinAccount
+ ", httpParams=" + httpParams + ",tokenStorager="
+ tokenStorager + ", tmpdir=" + tmpdir + ", certificateFile= "
+ certificateFile + "]";
}
}

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.base.test;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.base.test;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;

View File

@ -0,0 +1,156 @@
package com.foxinmy.weixin4j.base.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import org.junit.Assert;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.exception.WeixinPayException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.payment.WeixinPayProxy;
import com.foxinmy.weixin4j.payment.mch.ApiResult;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.IdType;
import com.foxinmy.weixin4j.type.TradeType;
import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.Weixin4jSettings;
/**
* 支付测试商户平台
*
* @className PayTest
* @author jy
* @date 2016年1月30日
* @since JDK 1.7
* @see
*/
public class PayTest {
protected final static WeixinPayProxy PAY3;
protected final static WeixinPayAccount ACCOUNT3;
static {
ACCOUNT3 = new WeixinPayAccount("wx5518c745065b1f95",
"请填入v3版本的appSecret", "DTYUNJKL1234fghjkRTGHJNM345678fc",
"1298173301", null, null, null, null, null);
PAY3 = new WeixinPayProxy(new Weixin4jSettings(ACCOUNT3));
}
/**
* 商户证书文件
*/
protected File caFile = new File("证书文件如12333.p12");
@Test
public void orderQueryV3() throws WeixinException {
Order order = PAY3.orderQuery(new IdQuery("BY2016010800025",
IdType.TRADENO));
System.err.println(order);
String sign = order.getSign();
order.setSign(null);
String valiSign = DigestUtil
.paysignMd5(order, ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void refundQueryV3() throws WeixinException {
com.foxinmy.weixin4j.payment.mch.RefundRecord record = PAY3
.refundQuery(new IdQuery("TT_1427183696238", IdType.TRADENO));
System.err.println(record);
// 这里的验证签名需要把details循环拼接
String sign = record.getSign();
record.setSign(null);
String valiSign = DigestUtil.paysignMd5(record,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void downbillV3() throws WeixinException {
Calendar c = Calendar.getInstance();
System.err.println(c.getTime());
c.set(Calendar.YEAR, 2015);
c.set(Calendar.MONTH, 2);
c.set(Calendar.DAY_OF_MONTH, 24);
System.err.println(c.getTime());
File file = PAY3.downloadBill(c.getTime(), null);
System.err.println(file);
}
@Test
public void refundV3() throws WeixinException, IOException {
IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO);
com.foxinmy.weixin4j.payment.mch.RefundResult result = PAY3
.refundApply(new FileInputStream(caFile), idQuery, "TT_R"
+ System.currentTimeMillis(), 0.01d, 0.01d, null,
"10020674");
System.err.println(result);
String sign = result.getSign();
result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void nativeV3() throws WeixinException {
MchPayPackage payPackageV3 = new MchPayPackage(ACCOUNT3,
"oyFLst1bqtuTcxK-ojF8hOGtLQao", "native测试", "T0001", 0.1d,
"notify_url", "127.0.0.1", TradeType.NATIVE);
payPackageV3.setProductId("0001");
PrePay prePay = null;
try {
prePay = PAY3.createPrePay(payPackageV3);
} catch (WeixinPayException e) {
e.printStackTrace();
}
System.err.println(prePay);
}
@Test
public void closeOrder() throws WeixinException {
ApiResult result = PAY3.closeOrder("D111");
System.err.println(result);
String sign = result.getSign();
result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void shortUrl() throws WeixinException {
String url = "weixin://wxpay/bizpayurl?xxxxxx";
String shortUrl = PAY3.getPayShorturl(url);
System.err.println(shortUrl);
}
@Test
public void interfaceReport() throws WeixinException {
String interfaceUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
int executeTime = 2500;
String outTradeNo = null;
String ip = "127.0.0.1";
Date time = new Date();
XmlResult returnXml = new XmlResult("SUCCESS", "");
returnXml.setResultCode("SUCCESS");
returnXml = PAY3.interfaceReport(interfaceUrl, executeTime, outTradeNo,
ip, time, returnXml);
System.err.println(returnXml);
}
}

View File

@ -35,70 +35,6 @@ weixin4j-mp
如何使用 如何使用
-------- --------
0.maven依赖(1.6.6,2015-12-31 released)
<dependency>
<groupId>com.foxinmy</groupId>
<artifactId>weixin4j-mp</artifactId>
<version>1.6.6</version>
</dependency>
1.需新增或拷贝`weixin4j.properties`文件到项目的`classpath`
weixin4j.properties说明
| 属性名 | 说明 |
| :---------- | :-------------- |
| weixin4j.account | 微信公众号信息 `json格式`(使用new WeixinProxy()缺省构造器时须填写) |
| weixin4j.token.path | 使用FileTokenStorager时token保存的物理路径(非必须填写) |
| weixin4j.qrcode.path | 调用二维码接口时保存二维码图片的物理路径(非必须填写) |
| weixin4j.media.path | 调用媒体接口时保存媒体文件的物理路径(非必须填写) |
| weixin4j.bill.path | 调用下载对账单接口保存文件的物理路径(非必须填写) |
| weixin4j.certificate.file | 调用某些接口(支付相关)强制需要auth的ca授权文件(按须填写) |
| weixin4j.user.oauth.redirect.uri | 调用OauthApi接口时需要填写的重定向路径(非必须填写) |
完整填写示例(properties中换行用右斜杆\\)
weixin4j.account={"id":"appid","secret":"appsecret",\
"mchId":"V3.x版本下的微信商户号 微信支付时需要填入",\
"certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\
"partnerId":"V2版本下的财付通的商户号 微信支付时需要填入",\
"partnerKey":"V2版本下的财付通商户权限密钥Key 微信支付时需要填入",\
"paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"}
# 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token
# 二维码保存路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.qrcode.path=/tmp/weixin4j/qrcode
# 媒体文件保存路径(如果不填则默认为Weixin4jConst#DEFAULT_MEDIA_PATH)
weixin4j.media.path=/tmp/weixin4j/media
# 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill
# ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12)
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
# classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
# 用户oauth授权后重定向的url(在使用OauthApi时填写)
weixin4j.user.oauth.redirect.uri=http://xxx
2.实例化微信公众号接口代理对象,调用具体的API方法
// 微信公众号API 使用classpath的weixin4j.properties
WeixinProxy weixinProxy = new WeixinProxy();
// 直接传入公众号信息
// weixinProxy = new WeixinProxy(appid,appsecret);
weixinProxy.getUser(openId);
// 微信支付API 使用classpath的weixin4j.properties
WeixinPayProxy weixinPayProxy = new WeixinPayProxy();
// 直接构造WexinAccount对象
// weixinPayProxy = new WeixinPayProxy(weixinAccount);
weixinPayProxy.orderQuery(idQuery);
> 针对`token`存储有两种方案,`File存储`/`Redis存储`,当然也可自己实现`TokenStorager`,默认使用文件(xml)的方式保存token,如果环境中支持`redis`,建议使用[RedisTokenStorager](../weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java).
>
> WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenStorager());
> // weixinProxy = new WeixinProxy(new RedisTokenStorager(appid,appsecret));
[更新LOG](./CHANGE.md) [更新LOG](./CHANGE.md)
---------------------- ----------------------

View File

@ -47,7 +47,6 @@ import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.mp.type.DatacubeType; import com.foxinmy.weixin4j.mp.type.DatacubeType;
import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.mp.type.IndustryType;
import com.foxinmy.weixin4j.mp.type.Lang; import com.foxinmy.weixin4j.mp.type.Lang;
import com.foxinmy.weixin4j.settings.Weixin4jSettings;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.tuple.MassTuple; import com.foxinmy.weixin4j.tuple.MassTuple;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
@ -55,6 +54,7 @@ import com.foxinmy.weixin4j.tuple.MpVideo;
import com.foxinmy.weixin4j.tuple.Tuple; import com.foxinmy.weixin4j.tuple.Tuple;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.type.TicketType; import com.foxinmy.weixin4j.type.TicketType;
import com.foxinmy.weixin4j.util.Weixin4jSettings;
/** /**
* 微信公众平台接口实现 * 微信公众平台接口实现
@ -92,13 +92,13 @@ public class WeixinProxy {
/** /**
* *
* @param settings * @param settings
* 配置信息 * 微信配置信息
* @see com.foxinmy.weixin4j.settings.Weixin4jSettings * @see com.foxinmy.weixin4j.util.Weixin4jSettings
*/ */
public WeixinProxy(Weixin4jSettings settings) { public WeixinProxy(Weixin4jSettings settings) {
this(new TokenHolder(new WeixinTokenCreator(settings.getAccount() this(new TokenHolder(new WeixinTokenCreator(settings.getWeixinAccount()
.getId(), settings.getAccount().getSecret()), .getId(), settings.getWeixinAccount().getSecret()),
settings.getTokenStorager())); settings.getTokenStorager0()));
this.settings = settings; this.settings = settings;
} }
@ -129,7 +129,7 @@ public class WeixinProxy {
* @return * @return
*/ */
public WeixinAccount getWeixinAccount() { public WeixinAccount getWeixinAccount() {
return this.settings.getAccount(); return this.settings.getWeixinAccount();
} }
/** /**
@ -222,29 +222,6 @@ public class WeixinProxy {
return mediaApi.uploadMedia(isMaterial, is, fileName); return mediaApi.uploadMedia(isMaterial, is, fileName);
} }
/**
* 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param isMaterial
* 是否下载永久素材
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html">上传下载说明</a>
* @see com.foxinmy.weixin4j.mp.api.MediaApi
* @see {@link #downloadMedia(String)}
*/
public File downloadMediaFile(String mediaId, boolean isMaterial)
throws WeixinException {
return mediaApi.downloadMediaFile(mediaId, isMaterial,
settings.getMediaPath());
}
/** /**
* 下载媒体文件 * 下载媒体文件
* *
@ -1192,19 +1169,6 @@ public class WeixinProxy {
return qrApi.createQR(parameter); return qrApi.createQR(parameter);
} }
/**
* 生成带参数的二维码
*
* @return 硬盘存储的文件对象
* @param parameter
* 二维码参数
* @throws WeixinException
* @see {@link #createQR(QRParameter)}
*/
public File createQRFile(QRParameter parameter) throws WeixinException {
return qrApi.createQRFile(parameter, settings.getQrcodePath());
}
/** /**
* 设置所属行业(每月可修改行业1次账号仅可使用所属行业中相关的模板) * 设置所属行业(每月可修改行业1次账号仅可使用所属行业中相关的模板)
* *

View File

@ -1,12 +1,8 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -228,63 +224,6 @@ public class MediaApi extends MpApi {
} }
} }
/**
* 下载媒体素材
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param isMaterial
* 是否下载永久素材
* @param mediaPath
* 媒体素材保存路径
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体文件</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材</a>
* @see {@link #downloadMedia(String,boolean)}
*/
public File downloadMediaFile(String mediaId, boolean isMaterial,
String mediaPath) throws WeixinException {
final String prefixName = String.format("%s.", mediaId);
File[] files = new File(mediaPath).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(prefixName);
}
});
if (files.length > 0) {
return files[0];
}
MediaDownloadResult result = downloadMedia(mediaId, isMaterial);
File file = new File(mediaPath + File.separator + result.getFileName());
OutputStream os = null;
try {
if (file.createNewFile()) {
os = new FileOutputStream(file);
os.write(result.getContent());
} else {
throw new WeixinException(String.format("create file fail:%s",
file.getAbsolutePath()));
}
} catch (IOException e) {
throw new WeixinException(e);
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
;
}
}
return file;
}
/** /**
* 下载媒体素材 * 下载媒体素材
* *

View File

@ -40,11 +40,7 @@ import com.foxinmy.weixin4j.mp.payment.v2.RefundRecordV2;
import com.foxinmy.weixin4j.mp.payment.v2.RefundResultV2; import com.foxinmy.weixin4j.mp.payment.v2.RefundResultV2;
import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.payment.PayRequest; import com.foxinmy.weixin4j.payment.PayRequest;
import com.foxinmy.weixin4j.settings.Weixin4jSettings;
import com.foxinmy.weixin4j.settings.Weixin4jPaySettings;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.type.BillType; import com.foxinmy.weixin4j.type.BillType;
import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.RefundType; import com.foxinmy.weixin4j.type.RefundType;
@ -54,6 +50,7 @@ import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.MapUtil; import com.foxinmy.weixin4j.util.MapUtil;
import com.foxinmy.weixin4j.util.RandomUtil; import com.foxinmy.weixin4j.util.RandomUtil;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jSettings;
import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
/** /**
@ -67,27 +64,22 @@ import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
*/ */
public class Pay2Api extends MpApi { public class Pay2Api extends MpApi {
private final Weixin4jPaySettings settings; private final Weixin4jSettings settings;
private final TokenHolder tokenHolder; private final TokenHolder tokenHolder;
public Pay2Api() { public Pay2Api() {
this(new Weixin4jPaySettings()); this(new Weixin4jSettings());
} }
public Pay2Api(Weixin4jPaySettings settings) { public Pay2Api(Weixin4jSettings settings) {
this(settings, new FileTokenStorager( this.tokenHolder = new TokenHolder(new WeixinTokenCreator(settings
Weixin4jSettings.DEFAULT_TOKEN_PATH)); .getWeixinAccount().getId(), settings.getWeixinAccount()
} .getSecret()), settings.getTokenStorager0());
public Pay2Api(Weixin4jPaySettings settings, TokenStorager tokenStorager) {
this.settings = settings; this.settings = settings;
this.tokenHolder = new TokenHolder(
new WeixinTokenCreator(settings.getPayAccount().getId(),
settings.getPayAccount().getSecret()), tokenStorager);
} }
public WeixinPayAccount getPayAccount() { public WeixinPayAccount getPayAccount() {
return this.settings.getPayAccount(); return this.settings.getWeixinPayAccount();
} }
/** /**
@ -142,7 +134,7 @@ public class Pay2Api extends MpApi {
double totalFee, String notifyUrl, String createIp, String attach, double totalFee, String notifyUrl, String createIp, String attach,
Date timeStart, Date timeExpire, double transportFee, Date timeStart, Date timeExpire, double transportFee,
double productFee, String goodsTag) { double productFee, String goodsTag) {
PayPackageV2 payPackage = new PayPackageV2(settings.getPayAccount() PayPackageV2 payPackage = new PayPackageV2(getPayAccount()
.getPartnerId(), body, outTradeNo, totalFee, notifyUrl, .getPartnerId(), body, outTradeNo, totalFee, notifyUrl,
createIp); createIp);
payPackage.setAttach(attach); payPackage.setAttach(attach);
@ -458,8 +450,8 @@ public class Pay2Api extends MpApi {
String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate);
String fileName = String.format("%s_%s_%s.txt", formatBillDate, String fileName = String.format("%s_%s_%s.txt", formatBillDate,
billType.name().toLowerCase(), getPayAccount().getId()); billType.name().toLowerCase(), getPayAccount().getId());
File file = new File(String.format("%s/%s", settings.getBillPath(), File file = new File(String.format("%s/weixin4j_bill_%s",
fileName)); settings.getTmpdir0(), fileName));
if (file.exists()) { if (file.exists()) {
return file; return file;
} }

View File

@ -1,9 +1,6 @@
package com.foxinmy.weixin4j.mp.api; package com.foxinmy.weixin4j.mp.api;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
@ -62,49 +59,4 @@ public class QrApi extends MpApi {
} }
return result; return result;
} }
/**
* 生成带参数的二维码
* <p>
* 二维码分为临时跟永久两种,扫描时触发推送带参数事件
* </p>
*
* @param parameter
* 二维码参数
* @param qrcodePath
* 二维码保存路径
* @return 硬盘存储的文件对象
* @throws WeixinException
* @see <a
* href="mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">二维码</a>
* @see #createQR(QRParameter)
* @see com.foxinmy.weixin4j.mp.model.QRParameter
*/
public File createQRFile(QRParameter parameter, String qrcodePath)
throws WeixinException {
String filename = String.format("%s_%s_%d.jpg", parameter.getQrType()
.name(), parameter.getSceneValue(), parameter
.getExpireSeconds());
File file = new File(qrcodePath + File.separator + filename);
if (parameter.getQrType().ordinal() > 0 && file.exists()) {
return file;
}
QRResult qrResult = createQR(parameter);
OutputStream os = null;
try {
os = new FileOutputStream(file);
os.write(qrResult.getContent());
} catch (IOException e) {
throw new WeixinException(e);
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
;
}
}
return file;
}
} }

View File

@ -1,3 +0,0 @@
NotifyMessage: (客服消息)[http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html#.E5.AE.A2.E6.9C.8D.E6.8E.A5.E5.8F.A3-.E5.8F.91.E6.B6.88.E6.81.AF]
TemplateMessage: (模板消息)[http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html]

View File

@ -48,7 +48,7 @@ public class WeixinTicketCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_mp_ticket_%s_%s", appid, ticketType.name()); return String.format("weixin4j_mp_ticket_%s_%s", appid, ticketType.name());
} }
@Override @Override

View File

@ -40,7 +40,7 @@ public class WeixinTokenCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_mp_token_%s", appid); return String.format("weixin4j_mp_token_%s", appid);
} }
@Override @Override

View File

@ -1,24 +1,22 @@
# \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 \u8bf7\u6309\u9700\u586b\u5199
weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "mchId":"\u5fae\u4fe1\u5546\u6237\u53f7 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\ "certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\
"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\ "partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u8001\u7248\u672c\u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"}
# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) # weixin4j\u7684\u4e34\u65f6\u76ee\u5f55
weixin4j.token.path=/tmp/weixin4j/token # \u53ef\u80fd\u5b58\u653etoken\u6587\u4ef6\u3001\u4e8c\u7ef4\u7801\u6587\u4ef6\u3001\u5a92\u4f53\u6587\u4ef6\u3001\u5bf9\u8d26\u5355\u6587\u4ef6\u7b49
# \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) # \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6java.io.tmpdir\u4e34\u65f6\u76ee\u5f55
weixin4j.qrcode.path=/tmp/weixin4j/qrcode weixin4j.tmpdir=
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH) # \u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84
weixin4j.media.path=/tmp/weixin4j/media # classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199
# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH) # weixin4j.certificate.file=classpath:xxxxx.p12
weixin4j.bill.path=/tmp/weixin4j/bill # \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6
# ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12)
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
# \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) # \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199)
weixin4j.user.oauth.redirect.uri= weixin4j.user.oauth.redirect.uri=

View File

@ -92,13 +92,6 @@ public class MediaTest extends TokenTest {
System.err.println(mediaId); System.err.println(mediaId);
} }
@Test
public void download2() throws WeixinException, IOException {
File file = mediaApi.downloadMediaFile("8790403529", true,
"/tmp/weixin4j/media");
Assert.assertTrue(file.exists());
}
@Test @Test
public void downloadArticle() throws WeixinException { public void downloadArticle() throws WeixinException {
List<MpArticle> articles = mediaApi.downloadArticle("17385064953"); List<MpArticle> articles = mediaApi.downloadArticle("17385064953");

View File

@ -1,44 +1,34 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.mp.test;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.exception.WeixinPayException;
import com.foxinmy.weixin4j.http.weixin.XmlResult;
import com.foxinmy.weixin4j.model.WeixinPayAccount; import com.foxinmy.weixin4j.model.WeixinPayAccount;
import com.foxinmy.weixin4j.mp.api.Pay2Api; import com.foxinmy.weixin4j.mp.api.Pay2Api;
import com.foxinmy.weixin4j.payment.WeixinPayProxy;
import com.foxinmy.weixin4j.payment.mch.ApiResult;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.settings.Weixin4jPaySettings;
import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.IdType; import com.foxinmy.weixin4j.type.IdType;
import com.foxinmy.weixin4j.type.TradeType; import com.foxinmy.weixin4j.util.Weixin4jSettings;
import com.foxinmy.weixin4j.util.DigestUtil;
/**
* 支付测试V2版本 2014年9月之前申请微信支付的公众号
*
* @className PayTest
* @author jy
* @date 2016年1月30日
* @since JDK 1.7
* @see
*/
public class PayTest { public class PayTest {
protected final static Pay2Api PAY2; protected final static Pay2Api PAY2;
protected final static WeixinPayProxy PAY3;
protected final static WeixinPayAccount ACCOUNT2; protected final static WeixinPayAccount ACCOUNT2;
protected final static WeixinPayAccount ACCOUNT3;
static { static {
ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret",
"请填入v2版本的paysignkey", null, null, null, null, "请填入v2版本的paysignkey", null, null, null, null,
"请填入v2版本的partnerId", "请填入v2版本的partnerKey"); "请填入v2版本的partnerId", "请填入v2版本的partnerKey");
PAY2 = new Pay2Api(new Weixin4jPaySettings(ACCOUNT2)); PAY2 = new Pay2Api(new Weixin4jSettings(ACCOUNT2));
ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret",
"请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null,
null);
PAY3 = new WeixinPayProxy(new Weixin4jPaySettings(ACCOUNT3));
} }
/** /**
* 商户证书文件 * 商户证书文件
@ -62,7 +52,6 @@ public class PayTest {
public void refundQueryV2() throws WeixinException { public void refundQueryV2() throws WeixinException {
System.err.println(PAY2.refundQuery(new IdQuery("D14123000004", System.err.println(PAY2.refundQuery(new IdQuery("D14123000004",
IdType.TRADENO))); IdType.TRADENO)));
refundQueryV3();
} }
@Test @Test
@ -74,110 +63,4 @@ public class PayTest {
File file = PAY2.downloadBill(c.getTime(), null); File file = PAY2.downloadBill(c.getTime(), null);
System.err.println(file); System.err.println(file);
} }
@Test
public void orderQueryV3() throws WeixinException {
Order order = PAY3.orderQuery(new IdQuery("T0002", IdType.TRADENO));
System.err.println(order);
String sign = order.getSign();
order.setSign(null);
String valiSign = DigestUtil
.paysignMd5(order, ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void refundQueryV3() throws WeixinException {
com.foxinmy.weixin4j.payment.mch.RefundRecord record = PAY3
.refundQuery(new IdQuery("TT_1427183696238", IdType.TRADENO));
System.err.println(record);
// 这里的验证签名需要把details循环拼接
String sign = record.getSign();
record.setSign(null);
String valiSign = DigestUtil.paysignMd5(record,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void downbillV3() throws WeixinException {
Calendar c = Calendar.getInstance();
System.err.println(c.getTime());
c.set(Calendar.YEAR, 2015);
c.set(Calendar.MONTH, 2);
c.set(Calendar.DAY_OF_MONTH, 24);
System.err.println(c.getTime());
File file = PAY3.downloadBill(c.getTime(), null);
System.err.println(file);
}
@Test
public void refundV3() throws WeixinException, IOException {
IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO);
com.foxinmy.weixin4j.payment.mch.RefundResult result = PAY3
.refundApply(new FileInputStream(caFile), idQuery, "TT_R"
+ System.currentTimeMillis(), 0.01d, 0.01d, null,
"10020674");
System.err.println(result);
String sign = result.getSign();
result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void nativeV3() throws WeixinException {
MchPayPackage payPackageV3 = new MchPayPackage(ACCOUNT3,
"oyFLst1bqtuTcxK-ojF8hOGtLQao", "native测试", "T0001", 0.1d,
"notify_url", "127.0.0.1", TradeType.NATIVE);
payPackageV3.setProductId("0001");
PrePay prePay = null;
try {
prePay = PAY3.createPrePay(payPackageV3);
} catch (WeixinPayException e) {
e.printStackTrace();
}
System.err.println(prePay);
}
@Test
public void closeOrder() throws WeixinException {
ApiResult result = PAY3.closeOrder("D111");
System.err.println(result);
String sign = result.getSign();
result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign);
}
@Test
public void shortUrl() throws WeixinException {
String url = "weixin://wxpay/bizpayurl?xxxxxx";
String shortUrl = PAY3.getPayShorturl(url);
System.err.println(shortUrl);
}
@Test
public void interfaceReport() throws WeixinException {
String interfaceUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
int executeTime = 2500;
String outTradeNo = null;
String ip = "127.0.0.1";
Date time = new Date();
XmlResult returnXml = new XmlResult("SUCCESS", "");
returnXml.setResultCode("SUCCESS");
returnXml = PAY3.interfaceReport(interfaceUrl, executeTime, outTradeNo,
ip, time, returnXml);
System.err.println(returnXml);
}
} }

View File

@ -1,6 +1,5 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.mp.test;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.junit.Assert; import org.junit.Assert;
@ -10,6 +9,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.mp.api.QrApi; import com.foxinmy.weixin4j.mp.api.QrApi;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRResult;
/** /**
* 二维码相关测试 * 二维码相关测试
@ -29,23 +29,21 @@ public class QRTest extends TokenTest {
@Test @Test
public void temp_qr() throws WeixinException, IOException { public void temp_qr() throws WeixinException, IOException {
File file = qrApi.createQRFile(QRParameter.createTemporary(1200, 1200), QRResult result = qrApi.createQR(QRParameter
"/tmp/weixin4j/qrcode"); .createTemporary(1200, 1200));
Assert.assertTrue(file.exists()); Assert.assertTrue(!result.getTicket().isEmpty());
} }
@Test @Test
public void forever_qr_int() throws WeixinException, IOException { public void forever_qr_int() throws WeixinException, IOException {
File file = qrApi.createQRFile(QRParameter.createPermanenceInt(2), QRResult result = qrApi.createQR(QRParameter.createPermanenceInt(2));
"/tmp/weixin4j/qrcode"); Assert.assertTrue(!result.getTicket().isEmpty());
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.createQRFile( QRResult result = qrApi.createQR(QRParameter
QRParameter.createPermanenceStr("1200中文"), .createPermanenceStr("1200中文"));
"/tmp/weixin4j/qrcode"); Assert.assertTrue(!result.getTicket().isEmpty());
Assert.assertTrue(file.exists());
} }
} }

View File

@ -36,81 +36,6 @@ weixin4j-qy
如何使用 如何使用
-------- --------
0.maven依赖(1.6.6,2015-12-31 released)
<dependency>
<groupId>com.foxinmy</groupId>
<artifactId>weixin4j-qy</artifactId>
<version>1.6.6</version>
</dependency>
1.需新增或拷贝`weixin4j.properties`文件到项目的`classpath`
weixin4j.properties说明
| 属性名 | 说明 |
| :---------- | :-------------- |
| weixin4j.account | 微信企业号信息 `json格式`(使用new WeixinProxy()缺省构造器时须填写) |
| weixin4j.token.path | 使用FileTokenStorager时token保存的物理路径(非必须填写) |
| weixin4j.media.path | 调用媒体接口时保存媒体文件的物理路径(非必须填写) |
| weixin4j.bill.path | 调用下载对账单接口保存文件的物理路径(非必须填写) |
| weixin4j.certificate.file | 调用某些接口(支付相关)强制需要auth的ca授权文件(非必须填写) |
| weixin4j.user.oauth.redirect.uri | 企业号用户身份授权后重定向的url(OauthApi接口) |
| weixin4j.third.oauth.redirect.uri | 企业号第三方提供商授权后重定向的url(OauthApi接口) |
| weixin4j.suite.oauth.redirect.uri | 企业号第三方应用套件授权后重定向的url(OauthApi接口) |
示例(properties中换行用右斜杆\\)
weixin4j.account={"id":"corpid","secret":"corpsecret",\
"suites":[{"id":"应用套件的id","secret":"应用套件的secret"}],\
"providerSecret":"第三方提供商secret(企业号登陆)",\
"chatSecret":"消息服务secret(企业号消息服务,暂时没用到)",\
"mchId":"微信商户号 微信支付时需要填入",\
"certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\
"paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"}
# 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token
# 二维码保存路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.qrcode.path=/tmp/weixin4j/qrcode
# 媒体文件保存路径(如果不填则默认为Weixin4jConst#DEFAULT_MEDIA_PATH)
weixin4j.media.path=/tmp/weixin4j/media
# 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill
# ca证书存放的完整路径
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
# classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
# 企业号用户身份授权后重定向的url(在使用OauthApi时填写)
weixin4j.user.oauth.redirect.uri=
# 企业号第三方提供商授权后重定向的url(在使用OauthApi时填写)
weixin4j.third.oauth.redirect.uri=
# 企业号第三方应用套件授权后重定向的url(在使用OauthApi时填写)
weixin4j.suite.oauth.redirect.uri=
2.实例化微信企业号接口代理对象,调用具体的API方法
// 微信企业号API 使用classpath的weixin4j.properties
WeixinProxy weixinProxy = new WeixinProxy();
// 直接传入企业号信息
// weixinProxy = new WeixinProxy(corpid,corpsecret);
weixinProxy.getUser(userid);
// 微信支付API 使用classpath的weixin4j.properties
WeixinPayProxy weixinPayProxy = new WeixinPayProxy();
// 直接构造WexinAccount对象
// weixinPayProxy = new WeixinPayProxy(weixinAccount);
weixinPayProxy.orderQuery(idQuery);
// 微信第三方应用API 使用classpath的weixin4j.properties
WeixinSuiteProxy weixinSuiteProxy = new WeixinSuiteProxy();
// 直接传入套件信息
//weixinSuiteProxy = new WeixinSuiteProxy(suiteId,suiteSecret);
weixinSuiteProxy.api().getOAuthInfo(authCorpid);
> 针对`token`存储有两种方案,`File存储`/`Redis存储`,当然也可自己实现`TokenStorager`,默认使用文件(xml)的方式保存token,如果环境中支持`redis`,建议使用[RedisTokenStorager](../weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java).
> WeixinProxy weixinProxy = new WeixinProxy(new RedisTokenStorager());
> // weixinProxy = new WeixinProxy(new RedisTokenStorager(corpid,corpsecret));
[更新LOG](./CHANGE.md) [更新LOG](./CHANGE.md)
---------------------- ----------------------

View File

@ -1,6 +1,5 @@
package com.foxinmy.weixin4j.qy; package com.foxinmy.weixin4j.qy;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
@ -48,11 +47,11 @@ import com.foxinmy.weixin4j.qy.type.ChatType;
import com.foxinmy.weixin4j.qy.type.InviteType; import com.foxinmy.weixin4j.qy.type.InviteType;
import com.foxinmy.weixin4j.qy.type.KfType; import com.foxinmy.weixin4j.qy.type.KfType;
import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.qy.type.UserStatus;
import com.foxinmy.weixin4j.settings.Weixin4jSettings;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.type.TicketType; import com.foxinmy.weixin4j.type.TicketType;
import com.foxinmy.weixin4j.util.Weixin4jSettings;
/** /**
* 微信企业号接口实现 * 微信企业号接口实现
@ -90,13 +89,13 @@ public class WeixinProxy {
/** /**
* *
* @param settings * @param settings
* 配置信息 * 微信配置信息
* @see com.foxinmy.weixin4j.settings.Weixin4jSettings * @see com.foxinmy.weixin4j.util.Weixin4jSettings
*/ */
public WeixinProxy(Weixin4jSettings settings) { public WeixinProxy(Weixin4jSettings settings) {
this(new TokenHolder(new WeixinTokenCreator(settings.getAccount() this(new TokenHolder(new WeixinTokenCreator(settings.getWeixinAccount()
.getId(), settings.getAccount().getSecret()), .getId(), settings.getWeixinAccount().getSecret()),
settings.getTokenStorager())); settings.getTokenStorager0()));
this.settings = settings; this.settings = settings;
} }
@ -116,8 +115,8 @@ public class WeixinProxy {
TokenHolder suiteTokenHolder) { TokenHolder suiteTokenHolder) {
this(new TokenHolder(new WeixinTokenSuiteCreator(perCodeHolder, this(new TokenHolder(new WeixinTokenSuiteCreator(perCodeHolder,
suiteTokenHolder), suiteTokenHolder.getTokenStorager())); suiteTokenHolder), suiteTokenHolder.getTokenStorager()));
this.settings = new Weixin4jSettings(perCodeHolder.getAuthCorpId(), this.settings = new Weixin4jSettings(new WeixinAccount(
null); perCodeHolder.getAuthCorpId(), null));
} }
/** /**
@ -156,7 +155,7 @@ public class WeixinProxy {
* @return * @return
*/ */
public WeixinAccount getWeixinAccount() { public WeixinAccount getWeixinAccount() {
return this.settings.getAccount(); return this.settings.getWeixinAccount();
} }
/** /**
@ -345,25 +344,6 @@ public class WeixinProxy {
return mediaApi.uploadMedia(agentid, is, fileName); return mediaApi.uploadMedia(agentid, is, fileName);
} }
/**
* 下载媒体文件
*
* @param agentid
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId
* 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link #downloadMedia(int,String)}
*/
public File downloadMediaFile(int agentid, String mediaId)
throws WeixinException {
return mediaApi.downloadMediaFile(agentid, mediaId,
settings.getMediaPath());
}
/** /**
* 下载媒体文件 * 下载媒体文件
* *

View File

@ -3,7 +3,6 @@ package com.foxinmy.weixin4j.qy;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.api.ProviderApi; import com.foxinmy.weixin4j.qy.api.ProviderApi;
@ -11,14 +10,11 @@ import com.foxinmy.weixin4j.qy.api.SuiteApi;
import com.foxinmy.weixin4j.qy.model.OUserInfo; import com.foxinmy.weixin4j.qy.model.OUserInfo;
import com.foxinmy.weixin4j.qy.model.WeixinQyAccount; import com.foxinmy.weixin4j.qy.model.WeixinQyAccount;
import com.foxinmy.weixin4j.qy.suite.SuiteTicketHolder; import com.foxinmy.weixin4j.qy.suite.SuiteTicketHolder;
import com.foxinmy.weixin4j.qy.suite.Weixin4jSuiteSettings;
import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator; import com.foxinmy.weixin4j.qy.token.WeixinProviderTokenCreator;
import com.foxinmy.weixin4j.qy.type.LoginTargetType; import com.foxinmy.weixin4j.qy.type.LoginTargetType;
import com.foxinmy.weixin4j.settings.Weixin4jSettings;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
* 微信第三方应用接口实现 * 微信第三方应用接口实现
@ -36,72 +32,52 @@ public class WeixinSuiteProxy {
private Map<String, SuiteApi> suiteMap; private Map<String, SuiteApi> suiteMap;
private ProviderApi providerApi; private ProviderApi providerApi;
private final Weixin4jSuiteSettings suiteSettings;
public WeixinSuiteProxy() { public WeixinSuiteProxy() {
this(Weixin4jSettings.DEFAULT_TOKEN_PATH); this(new Weixin4jSuiteSettings());
} }
/** /**
* *
* @param tokenPath * @param suiteSettings
* 使用文件存储token的保存路径 * 套件信息配置
*/ */
public WeixinSuiteProxy(String tokenPath) { public WeixinSuiteProxy(Weixin4jSuiteSettings suiteSettings) {
this(new FileTokenStorager(tokenPath)); this.suiteSettings = suiteSettings;
} if (suiteSettings.getWeixinAccount().getSuiteAccounts() != null) {
/**
*
* @param tokenStorager
* token存储
*/
public WeixinSuiteProxy(TokenStorager tokenStorager) {
this(tokenStorager, JSON.parseObject(
Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class));
}
/**
*
* @param tokenStorager
* token存储
* @param suites
* 套件信息 必填项
*/
public WeixinSuiteProxy(TokenStorager tokenStorager,
WeixinQyAccount weixinAccount) {
this(tokenStorager, weixinAccount.getId(), weixinAccount
.getProviderSecret(), weixinAccount.suitesToArray());
}
/**
*
* @param tokenStorager
* token存储
* @param providerCorpId
* 服务商的企业号ID <font color="red">使用服务商API时必填项</font>
* @param providerSecret
* 服务商secret <font color="red">使用服务商API时必填项</font>
* @param suites
* 套件信息 <font color="red">使用套件API时必填项</font>
*/
public WeixinSuiteProxy(TokenStorager tokenStorager, String providerCorpId,
String providerSecret, WeixinAccount... suites) {
if (suites != null) {
this.suiteMap = new HashMap<String, SuiteApi>(); this.suiteMap = new HashMap<String, SuiteApi>();
for (WeixinAccount suite : suites) { for (WeixinAccount suite : suiteSettings.getWeixinAccount()
.getSuiteAccounts()) {
this.suiteMap.put(suite.getId(), new SuiteApi( this.suiteMap.put(suite.getId(), new SuiteApi(
new SuiteTicketHolder(suite.getId(), suite.getSecret(), new SuiteTicketHolder(suite.getId(), suite.getSecret(),
tokenStorager))); suiteSettings.getTokenStorager0())));
this.suiteMap.put(null, suiteMap.get(suites[0].getId())); this.suiteMap.put(
null,
suiteMap.get(suiteSettings.getWeixinAccount()
.getSuiteAccounts().get(0).getId()));
} }
} }
if (StringUtil.isNotBlank(providerCorpId) if (StringUtil.isNotBlank(suiteSettings.getWeixinAccount().getId())
&& StringUtil.isNotBlank(providerSecret)) { && StringUtil.isNotBlank(suiteSettings.getWeixinAccount()
.getProviderSecret())) {
this.providerApi = new ProviderApi(new TokenHolder( this.providerApi = new ProviderApi(new TokenHolder(
new WeixinProviderTokenCreator(providerCorpId, new WeixinProviderTokenCreator(suiteSettings
providerSecret), tokenStorager)); .getWeixinAccount().getId(), suiteSettings
.getWeixinAccount().getProviderSecret()),
suiteSettings.getTokenStorager0()));
} }
} }
/**
* 企业号信息
*
* @return
*/
public WeixinQyAccount getWeixinAccount() {
return this.suiteSettings.getWeixinAccount();
}
/** /**
* 只关注第一个套件获取API(如果只有一个套件 * 只关注第一个套件获取API(如果只有一个套件
* *

View File

@ -1,12 +1,8 @@
package com.foxinmy.weixin4j.qy.api; package com.foxinmy.weixin4j.qy.api;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -190,57 +186,6 @@ public class MediaApi extends QyApi {
} }
} }
/**
* 下载媒体文件
*
* @param agentid
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param mediaPath
* 媒体素材保存路径
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link #downloadMedia(int,String)}
*/
public File downloadMediaFile(int agentid, String mediaId, String mediaPath)
throws WeixinException {
final String prefixName = String.format("%d_%s.", agentid, mediaId);
File[] files = new File(mediaPath).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(prefixName);
}
});
if (files.length > 0) {
return files[0];
}
MediaDownloadResult result = downloadMedia(agentid, mediaId);
File file = new File(mediaPath + File.separator + result.getFileName());
OutputStream os = null;
try {
if (file.createNewFile()) {
os = new FileOutputStream(file);
os.write(result.getContent());
} else {
throw new WeixinException(String.format("create file fail:%s",
file.getAbsolutePath()));
}
} catch (IOException e) {
throw new WeixinException(e);
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
;
}
}
return file;
}
/** /**
* 下载媒体文件 * 下载媒体文件
* *

View File

@ -23,7 +23,7 @@ public class WeixinQyAccount extends WeixinAccount {
/** /**
* 多个应用套件信息 * 多个应用套件信息
*/ */
private List<WeixinAccount> suites; private List<WeixinAccount> suiteAccounts;
/** /**
* 第三方提供商secret(企业号登陆) * 第三方提供商secret(企业号登陆)
*/ */
@ -36,32 +36,30 @@ public class WeixinQyAccount extends WeixinAccount {
/** /**
* *
* @param corpid * @param corpid
* 企业ID * 企业ID 必填
* @param corpsecret * @param corpsecret
* 管理组的凭证密钥 * 管理组的凭证密钥 使用普通接口(WeixinProxy对象)必须填写
* @param suiteId * @param suites
* 应用套件的id * 应用套件集合 使用套件接口(WeixinSuiteProxy#SuiteApi)必须填写
* @param suiteSecret
* 应用套件的secret
* @param providerSecret * @param providerSecret
* 第三方提供商secret(企业号登陆) * 第三方提供商secret(企业号登陆) 使用服务商接口(WeixinSuiteProxy#ProviderApi)必填项
* @param chatSecret * @param chatSecret
* 消息服务secret(企业号聊天) * 消息服务secret(企业号聊天) 暂无用途
*/ */
@JSONCreator @JSONCreator
public WeixinQyAccount(@JSONField(name = "id") String corpid, public WeixinQyAccount(@JSONField(name = "id") String corpid,
@JSONField(name = "secret") String corpsecret, @JSONField(name = "secret") String corpsecret,
@JSONField(name = "suites") List<WeixinAccount> suites, @JSONField(name = "suites") List<WeixinAccount> suiteAccounts,
@JSONField(name = "providerSecret") String providerSecret, @JSONField(name = "providerSecret") String providerSecret,
@JSONField(name = "chatSecret") String chatSecret) { @JSONField(name = "chatSecret") String chatSecret) {
super(corpid, corpsecret); super(corpid, corpsecret);
this.suites = suites; this.suiteAccounts = suiteAccounts;
this.providerSecret = providerSecret; this.providerSecret = providerSecret;
this.chatSecret = chatSecret; this.chatSecret = chatSecret;
} }
public List<WeixinAccount> getSuites() { public List<WeixinAccount> getSuiteAccounts() {
return suites; return suiteAccounts;
} }
public String getProviderSecret() { public String getProviderSecret() {
@ -72,15 +70,15 @@ public class WeixinQyAccount extends WeixinAccount {
return chatSecret; return chatSecret;
} }
public WeixinAccount[] suitesToArray() { public WeixinAccount[] suiteAccountsToArray() {
return suites != null ? suites return suiteAccounts != null ? suiteAccounts
.toArray(new WeixinAccount[suites.size()]) : null; .toArray(new WeixinAccount[suiteAccounts.size()]) : null;
} }
@Override @Override
public String toString() { public String toString() {
return "WeixinQyAccount [" + super.toString() + ", suites=" + suites return "WeixinQyAccount [" + super.toString() + ", suiteAccounts="
+ ", providerSecret=" + providerSecret + ", chatSecret=" + suiteAccounts + ", providerSecret=" + providerSecret
+ chatSecret + "]"; + ", chatSecret=" + chatSecret + "]";
} }
} }

View File

@ -0,0 +1,124 @@
package com.foxinmy.weixin4j.qy.suite;
import java.util.Arrays;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.http.HttpParams;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.model.WeixinQyAccount;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/**
* 微信第三方套件配置相关
*
* @className Weixin4jSuiteSettings
* @author jy
* @date 2016年1月28日
* @since JDK 1.6
* @see
*/
public class Weixin4jSuiteSettings {
/**
* 微信企业号信息
*/
private final WeixinQyAccount weixinAccount;
/**
* Http参数
*/
private HttpParams httpParams;
/**
* token存储方式 默认为FileTokenStorager
*/
private TokenStorager tokenStorager;
/**
* 系统临时目录
*/
private String tmpdir;
/**
* 默认使用weixin4j.properties配置的信息
*/
public Weixin4jSuiteSettings() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"),
WeixinQyAccount.class));
}
/**
*
* @param providerCorpId
* 服务商的企业号ID <font color="red">使用服务商API时必填项</font>
* @param providerSecret
* 服务商secret <font color="red">使用服务商API时必填项</font>
* @param suites
* 套件信息 <font color="red">使用套件API时必填项</font>
*/
public Weixin4jSuiteSettings(String providerCorpId, String providerSecret,
WeixinAccount... suites) {
this.weixinAccount = new WeixinQyAccount(providerCorpId, null,
Arrays.asList(suites), providerSecret, null);
}
private Weixin4jSuiteSettings(WeixinQyAccount weixinAccount) {
this.weixinAccount = weixinAccount;
}
public WeixinQyAccount getWeixinAccount() {
return weixinAccount;
}
public HttpParams getHttpParams() {
return httpParams;
}
public HttpParams getHttpParams0() {
if (httpParams == null) {
return new HttpParams();
}
return httpParams;
}
public String getTmpdir() {
return tmpdir;
}
public String getTmpdir0() {
if (StringUtil.isBlank(tmpdir)) {
return Weixin4jConfigUtil.getClassPathValue("weixin4j.tmpdir",
System.getProperty("java.io.tmpdir"));
}
return tmpdir;
}
public TokenStorager getTokenStorager() {
return tokenStorager;
}
public TokenStorager getTokenStorager0() {
if (tokenStorager == null) {
return new FileTokenStorager(getTmpdir0());
}
return tokenStorager;
}
public void setHttpParams(HttpParams httpParams) {
this.httpParams = httpParams;
}
public void setTmpdir(String tmpdir) {
this.tmpdir = tmpdir;
}
public void setTokenStorager(TokenStorager tokenStorager) {
this.tokenStorager = tokenStorager;
}
@Override
public String toString() {
return "Weixin4jSuiteSettings [weixinAccount=" + weixinAccount
+ ", httpParams=" + httpParams + ",tokenStorager="
+ tokenStorager + ", tmpdir=" + tmpdir + "]";
}
}

View File

@ -42,7 +42,7 @@ public class WeixinSuitePreCodeCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_suite_precode_%s", suiteId); return String.format("weixin4j_qy_suite_precode_%s", suiteId);
} }
@Override @Override

View File

@ -36,7 +36,7 @@ public class WeixinSuiteTokenCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_suite_token_%s", ticketHolder.getSuiteId()); return String.format("weixin4j_qy_suite_token_%s", ticketHolder.getSuiteId());
} }
@Override @Override

View File

@ -42,7 +42,7 @@ public class WeixinTokenSuiteCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_token_suite_%s:%s", return String.format("weixin4j_qy_token_suite_%s:%s",
perCodeHolder.getSuiteId(), perCodeHolder.getAuthCorpId() perCodeHolder.getSuiteId(), perCodeHolder.getAuthCorpId()
); );

View File

@ -40,7 +40,7 @@ public class WeixinProviderTokenCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_provider_token_%s", corpid); return String.format("weixin4j_qy_provider_token_%s", corpid);
} }
@Override @Override

View File

@ -45,7 +45,7 @@ public class WeixinTicketCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_ticket_%s_%s", corpid, ticketType.name()); return String.format("weixin4j_qy_ticket_%s_%s", corpid, ticketType.name());
} }
@Override @Override

View File

@ -40,7 +40,7 @@ public class WeixinTokenCreator implements TokenCreator {
@Override @Override
public String getCacheKey() { public String getCacheKey() {
return String.format("wx_qy_token_%s", corpid); return String.format("weixin4j_qy_token_%s", corpid);
} }
@Override @Override

View File

@ -1,5 +1,6 @@
# \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 \u8bf7\u6309\u9700\u586b\u5199
weixin4j.account={"id":"wx5132afc5da26d661","secret":"GsnKLVDI1pWArdB60Ze4iP2cwFvcW5KCAs2vLJldipilmSYxtbkcAiBcGSHHvu_I",\ weixin4j.account={"id":"wx5132afc5da26d661","secret":"GsnKLVDI1pWArdB60Ze4iP2cwFvcW5KCAs2vLJldipilmSYxtbkcAiBcGSHHvu_I",\
"suites":[{"id":"\u5e94\u7528\u5957\u4ef6\u7684id","secret":"\u5e94\u7528\u5957\u4ef6\u7684secret"}],\ "suites":[{"id":"\u5e94\u7528\u5957\u4ef6\u7684id","secret":"\u5e94\u7528\u5957\u4ef6\u7684secret"}],\
"providerSecret":"\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546secret(\u4f01\u4e1a\u53f7\u767b\u9646)",\ "providerSecret":"\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546secret(\u4f01\u4e1a\u53f7\u767b\u9646)",\
@ -8,16 +9,15 @@ weixin4j.account={"id":"wx5132afc5da26d661","secret":"GsnKLVDI1pWArdB60Ze4iP2cwF
"certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\ "certificateKey":"\u52a0\u8f7d\u652f\u4ed8\u8bc1\u4e66\u6587\u4ef6\u7684\u5bc6\u7801 \u5982\u679c\u4e0d\u586b\u5199\u5219\u9ed8\u8ba4\u83b7\u53d6mchId\u4f5c\u4e3a\u5bc6\u7801",\
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"} "paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u5fae\u4fe1\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"}
# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH) # weixin4j\u7684\u4e34\u65f6\u76ee\u5f55
weixin4j.token.path=/tmp/weixin4j/token # \u53ef\u80fd\u5b58\u653etoken\u6587\u4ef6\u3001\u4e8c\u7ef4\u7801\u6587\u4ef6\u3001\u5a92\u4f53\u6587\u4ef6\u3001\u5bf9\u8d26\u5355\u6587\u4ef6\u7b49
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH) # \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6java.io.tmpdir\u4e34\u65f6\u76ee\u5f55
weixin4j.media.path=/tmp/weixin4j/media weixin4j.tmpdir=
# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH) # \u5fae\u4fe1\u652f\u4ed8\u67d0\u4e9b\u63a5\u53e3\u9700\u8981\u7684ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84
weixin4j.bill.path=/tmp/weixin4j/bill # classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199
# ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12) # weixin4j.certificate.file=classpath:xxxxx.p12
# \u4e3a\u7a7a\u65f6\u5219\u83b7\u53d6classpath\u6839\u76ee\u5f55\u4e0b\u7684ca.p12\u6587\u4ef6
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
# classpath\u8def\u5f84\u4e0b\u53ef\u4ee5\u8fd9\u4e48\u5199(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
# \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199) # \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199)
weixin4j.user.oauth.redirect.uri= weixin4j.user.oauth.redirect.uri=

View File

@ -44,12 +44,11 @@ public class MediaTest extends TokenTest {
@Test @Test
public void download() throws WeixinException, IOException { public void download() throws WeixinException, IOException {
File file = mediaApi MediaDownloadResult result = mediaApi
.downloadMediaFile( .downloadMedia(
0, 0,
"1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw", "1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw");
"/tmp/weixin4j/media"); Assert.assertTrue(result.getContent().length > 0);
Assert.assertTrue(file.exists());
} }
@Test @Test

View File

@ -1,39 +1,39 @@
package com.foxinmy.weixin4j.qy.test; package com.foxinmy.weixin4j.qy.test;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator; import com.foxinmy.weixin4j.qy.token.WeixinTokenCreator;
import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
* token测试 * token测试
* *
* @className TokenTest * @className TokenTest
* @author jy.hu * @author jy.hu
* @date 2014年4月10日 * @date 2014年4月10日
* @since JDK 1.6 * @since JDK 1.6
*/ */
public class TokenTest { public class TokenTest {
protected TokenHolder tokenHolder; protected TokenHolder tokenHolder;
@Before @Before
public void setUp() { public void setUp() {
WeixinAccount weixinAccount = Weixin4jConfigUtil.getWeixinAccount(); WeixinAccount weixinAccount = Weixin4jConfigUtil.getWeixinAccount();
tokenHolder = new TokenHolder(new WeixinTokenCreator( tokenHolder = new TokenHolder(new WeixinTokenCreator(
weixinAccount.getId(), weixinAccount.getSecret()), weixinAccount.getId(), weixinAccount.getSecret()),
new FileTokenStorager(Weixin4jConfigUtil.getValue("token.path", new FileTokenStorager(Weixin4jConfigUtil.getValue("token.path",
"/tmp/weixin4j/token"))); "/tmp/weixin4j/token")));
} }
@Test @Test
public void test() throws WeixinException { public void test() throws WeixinException {
Assert.assertNotNull(tokenHolder.getToken()); Assert.assertNotNull(tokenHolder.getToken());
} }
} }