新增Weixin4jSettings配置类

This commit is contained in:
jinyu 2016-01-29 09:38:47 +08:00
parent c4bf06d372
commit 2e2d207e76
46 changed files with 717 additions and 464 deletions

View File

@ -630,3 +630,7 @@
* 2016-01-26 * 2016-01-26
+ weixin4j-qy:新增上传图文消息内的图片接口 + weixin4j-qy:新增上传图文消息内的图片接口
* 2016-01-29
+ 新增Weixin4jSettings配置类

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.foxinmy</groupId> <groupId>com.foxinmy</groupId>
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>1.6.6</version> <version>1.6.7</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>weixin4j</name> <name>weixin4j</name>
<url>https://github.com/foxinmy/weixin4j</url> <url>https://github.com/foxinmy/weixin4j</url>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.foxinmy</groupId> <groupId>com.foxinmy</groupId>
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>1.6.6</version> <version>1.6.7</version>
</parent> </parent>
<artifactId>weixin4j-base</artifactId> <artifactId>weixin4j-base</artifactId>
<name>weixin4j-base</name> <name>weixin4j-base</name>

View File

@ -5,11 +5,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor; import com.foxinmy.weixin4j.http.weixin.WeixinRequestExecutor;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* API基础 * API基础
@ -45,21 +40,4 @@ public abstract class BaseApi {
m.appendTail(sb); m.appendTail(sb);
return sb.toString(); return sb.toString();
} }
/**
* 默认使用weixin4j.properties文件中的公众号信息
*/
public final static WeixinAccount DEFAULT_WEIXIN_ACCOUNT;
/**
* 默认token使用File的方式存储
*/
public final static TokenStorager DEFAULT_TOKEN_STORAGER;
static {
DEFAULT_WEIXIN_ACCOUNT = Weixin4jConfigUtil.getWeixinAccount();
DEFAULT_TOKEN_STORAGER = new FileTokenStorager(
Weixin4jConfigUtil.getValue("token.path",
Weixin4jConst.DEFAULT_TOKEN_PATH));
}
} }

View File

@ -48,7 +48,7 @@ public class CashApi {
* 发放红包 企业向微信用户个人发现金红包 * 发放红包 企业向微信用户个人发现金红包
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param redpacket * @param redpacket
* 红包信息 * 红包信息
* @return 发放结果 * @return 发放结果
@ -71,7 +71,7 @@ public class CashApi {
WeixinResponse response = null; WeixinResponse response = null;
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor response = weixinExecutor
.post(redpacket.getTotalNum() > 1 ? PayURLConsts.MCH_REDPACK_GROUPSEND_URL .post(redpacket.getTotalNum() > 1 ? PayURLConsts.MCH_REDPACK_GROUPSEND_URL
: PayURLConsts.MCH_REDPACKSEND_URL, param); : PayURLConsts.MCH_REDPACKSEND_URL, param);
@ -92,7 +92,7 @@ public class CashApi {
* 查询红包记录 * 查询红包记录
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param outTradeNo * @param outTradeNo
* 商户发放红包的商户订单号 * 商户发放红包的商户订单号
* @return 红包记录 * @return 红包记录
@ -116,7 +116,7 @@ public class CashApi {
WeixinResponse response = null; WeixinResponse response = null;
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor.post(PayURLConsts.MCH_REDPACKQUERY_URL, response = weixinExecutor.post(PayURLConsts.MCH_REDPACKQUERY_URL,
param); param);
} finally { } finally {
@ -136,7 +136,7 @@ public class CashApi {
* 企业付款 实现企业向个人付款针对部分有开发能力的商户 提供通过API完成企业付款的功能 比如目前的保险行业向客户退保给付理赔 * 企业付款 实现企业向个人付款针对部分有开发能力的商户 提供通过API完成企业付款的功能 比如目前的保险行业向客户退保给付理赔
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param mpPayment * @param mpPayment
* 付款信息 * 付款信息
* @return 付款结果 * @return 付款结果
@ -160,7 +160,7 @@ public class CashApi {
WeixinResponse response = null; WeixinResponse response = null;
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor.post(PayURLConsts.MCH_ENPAYMENT_URL, response = weixinExecutor.post(PayURLConsts.MCH_ENPAYMENT_URL,
param); param);
} finally { } finally {
@ -184,7 +184,7 @@ public class CashApi {
* 企业付款查询 用于商户的企业付款操作进行结果查询返回付款操作详细结果 * 企业付款查询 用于商户的企业付款操作进行结果查询返回付款操作详细结果
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param outTradeNo * @param outTradeNo
* 商户调用企业付款API时使用的商户订单号 * 商户调用企业付款API时使用的商户订单号
* @return 付款记录 * @return 付款记录
@ -206,7 +206,7 @@ public class CashApi {
WeixinResponse response = null; WeixinResponse response = null;
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor.post(PayURLConsts.MCH_ENPAYQUERY_URL, response = weixinExecutor.post(PayURLConsts.MCH_ENPAYQUERY_URL,
param); param);
} finally { } finally {

View File

@ -44,7 +44,7 @@ public class CouponApi {
* 发放代金券(需要证书) * 发放代金券(需要证书)
* *
* @param ca * @param ca
* 证书文件(后缀为*.p12) * 后缀为*.p12的证书文件
* @param couponStockId * @param couponStockId
* 代金券批次id * 代金券批次id
* @param partnerTradeNo * @param partnerTradeNo
@ -81,7 +81,7 @@ public class CouponApi {
WeixinResponse response = null; WeixinResponse response = null;
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor.post(PayURLConsts.MCH_COUPONSEND_URL, response = weixinExecutor.post(PayURLConsts.MCH_COUPONSEND_URL,
param); param);
} finally { } finally {

View File

@ -29,12 +29,12 @@ import com.foxinmy.weixin4j.payment.MicroPayPackage;
import com.foxinmy.weixin4j.payment.PayURLConsts; import com.foxinmy.weixin4j.payment.PayURLConsts;
import com.foxinmy.weixin4j.payment.mch.APPPayRequest; import com.foxinmy.weixin4j.payment.mch.APPPayRequest;
import com.foxinmy.weixin4j.payment.mch.ApiResult; import com.foxinmy.weixin4j.payment.mch.ApiResult;
import com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult;
import com.foxinmy.weixin4j.payment.mch.JSAPIPayRequest; import com.foxinmy.weixin4j.payment.mch.JSAPIPayRequest;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
import com.foxinmy.weixin4j.payment.mch.MchPayRequest; import com.foxinmy.weixin4j.payment.mch.MchPayRequest;
import com.foxinmy.weixin4j.payment.mch.NATIVEPayRequest; import com.foxinmy.weixin4j.payment.mch.NATIVEPayRequest;
import com.foxinmy.weixin4j.payment.mch.NativePayResponse; import com.foxinmy.weixin4j.payment.mch.NativePayResponse;
import com.foxinmy.weixin4j.payment.mch.OpenIdResult;
import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.payment.mch.RefundRecord; import com.foxinmy.weixin4j.payment.mch.RefundRecord;
@ -51,8 +51,6 @@ 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.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
import com.foxinmy.weixin4j.xml.XmlStream; import com.foxinmy.weixin4j.xml.XmlStream;
@ -496,7 +494,7 @@ public class Pay3Api {
* </p> * </p>
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
@ -539,7 +537,7 @@ public class Pay3Api {
map.put("sign", sign); map.put("sign", sign);
String param = XmlStream.map2xml(map); String param = XmlStream.map2xml(map);
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
response = weixinExecutor.post(PayURLConsts.MCH_REFUNDAPPLY_URL, response = weixinExecutor.post(PayURLConsts.MCH_REFUNDAPPLY_URL,
param); param);
} finally { } finally {
@ -559,7 +557,7 @@ public class Pay3Api {
* 退款申请(全额退款) * 退款申请(全额退款)
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
@ -582,7 +580,7 @@ public class Pay3Api {
* color="red">调用扣款接口后请勿立即调用撤销,需要等待5秒以上先调用查单接口,如果没有确切的返回,再调用撤销</font></br> * color="red">调用扣款接口后请勿立即调用撤销,需要等待5秒以上先调用查单接口,如果没有确切的返回,再调用撤销</font></br>
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
@ -594,7 +592,7 @@ public class Pay3Api {
throws WeixinException { throws WeixinException {
try { try {
WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor( WeixinRequestExecutor weixinExecutor = new WeixinSSLRequestExecutor(
weixinAccount.getMchId(), ca); weixinAccount.getCertificateKey(), ca);
Map<String, String> map = baseMap(idQuery); Map<String, String> map = baseMap(idQuery);
String sign = DigestUtil.paysignMd5(map, String sign = DigestUtil.paysignMd5(map,
weixinAccount.getPaySignKey()); weixinAccount.getPaySignKey());
@ -681,13 +679,15 @@ public class Pay3Api {
* @param billType * @param billType
* 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单 * 下载对账单的类型 ALL,返回当日所有订单信息, 默认值 SUCCESS,返回当日成功支付的订单
* REFUND,返回当日退款订单 * REFUND,返回当日退款订单
* @param billPath
* 对账单保存路径
* @return excel表格 * @return excel表格
* @since V3 * @since V3
* @see <a * @see <a
* href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单API</a> * href="http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单API</a>
* @throws WeixinException * @throws WeixinException
*/ */
public File downloadBill(Date billDate, BillType billType) public File downloadBill(Date billDate, BillType billType, String billPath)
throws WeixinException { throws WeixinException {
if (billDate == null) { if (billDate == null) {
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
@ -698,11 +698,9 @@ public class Pay3Api {
billType = BillType.ALL; billType = BillType.ALL;
} }
String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate);
String bill_path = Weixin4jConfigUtil.getValue("bill.path",
Weixin4jConst.DEFAULT_BILL_PATH);
String fileName = String.format("%s_%s_%s.txt", formatBillDate, String fileName = String.format("%s_%s_%s.txt", formatBillDate,
billType.name().toLowerCase(), weixinAccount.getId()); billType.name().toLowerCase(), weixinAccount.getId());
File file = new File(String.format("%s/%s", bill_path, fileName)); File file = new File(String.format("%s/%s", billPath, fileName));
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
@ -820,13 +818,12 @@ public class Pay3Api {
* @param authCode * @param authCode
* 扫码支付授权码设备读取用户微信中的条码或者二维码信息 * 扫码支付授权码设备读取用户微信中的条码或者二维码信息
* @return 查询结果 * @return 查询结果
* @see com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult * @see com.foxinmy.weixin4j.payment.mch.OpenIdResult
* @see <a * @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9">授权码查询OPENID</a> * href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9">授权码查询OPENID</a>
* @throws WeixinException * @throws WeixinException
*/ */
public AuthCodeOpenIdResult authCode2openId(String authCode) public OpenIdResult authCode2openId(String authCode) throws WeixinException {
throws WeixinException {
Map<String, String> map = baseMap(null); Map<String, String> map = baseMap(null);
map.put("auth_code", authCode); map.put("auth_code", authCode);
String sign = DigestUtil.paysignMd5(map, weixinAccount.getPaySignKey()); String sign = DigestUtil.paysignMd5(map, weixinAccount.getPaySignKey());
@ -834,7 +831,7 @@ public class Pay3Api {
String param = XmlStream.map2xml(map); String param = XmlStream.map2xml(map);
WeixinResponse response = weixinExecutor.post( WeixinResponse response = weixinExecutor.post(
PayURLConsts.MCH_AUTHCODE_OPENID_URL, param); PayURLConsts.MCH_AUTHCODE_OPENID_URL, param);
return response.getAsObject(new TypeReference<AuthCodeOpenIdResult>() { return response.getAsObject(new TypeReference<OpenIdResult>() {
}); });
} }

View File

@ -32,6 +32,10 @@ public class WeixinPayAccount extends WeixinAccount {
* 微信支付分配的商户号(商户平台版) * 微信支付分配的商户号(商户平台版)
*/ */
private String mchId; private String mchId;
/**
* 加载支付证书文件的密码(商户平台版)
*/
private String certificateKey;
/** /**
* 微信支付分配的子商户号受理模式下必填(商户平台版) * 微信支付分配的子商户号受理模式下必填(商户平台版)
*/ */
@ -40,10 +44,6 @@ public class WeixinPayAccount extends WeixinAccount {
* 微信支付分配的设备号(商户平台版) * 微信支付分配的设备号(商户平台版)
*/ */
private String deviceInfo; private String deviceInfo;
/**
* 微信支付版本号(如果无则按照mchId来做判断)
*/
private int version;
/** /**
* 商户平台版本(V3)字段 * 商户平台版本(V3)字段
@ -57,8 +57,9 @@ public class WeixinPayAccount extends WeixinAccount {
* @param mchId * @param mchId
* 微信支付分配的商户号(必填) * 微信支付分配的商户号(必填)
*/ */
public WeixinPayAccount(String appId, String appSecret, String paySignKey, String mchId) { public WeixinPayAccount(String appId, String appSecret, String paySignKey,
this(appId, appSecret, paySignKey, mchId, null, null, null, null); String mchId) {
this(appId, appSecret, paySignKey, mchId, null, null, null, null, null);
} }
/** /**
@ -72,6 +73,8 @@ public class WeixinPayAccount extends WeixinAccount {
* 支付密钥字符串(必填) * 支付密钥字符串(必填)
* @param mchId * @param mchId
* 微信支付分配的商户号(V3商户平台版必填) * 微信支付分配的商户号(V3商户平台版必填)
* @param certificateKey
* 加载支付证书文件的密码(商户平台版)
* @param subMchId * @param subMchId
* 微信支付分配的子商户号受理模式下必填(V3商户平台版 非必须) * 微信支付分配的子商户号受理模式下必填(V3商户平台版 非必须)
* @param deviceInfo * @param deviceInfo
@ -82,13 +85,19 @@ public class WeixinPayAccount extends WeixinAccount {
* 财付通商户权限密钥Key(V2版本必填) * 财付通商户权限密钥Key(V2版本必填)
*/ */
@JSONCreator @JSONCreator
public WeixinPayAccount(@JSONField(name = "id") String appId, @JSONField(name = "secret") String appSecret, public WeixinPayAccount(@JSONField(name = "id") String appId,
@JSONField(name = "paySignKey") String paySignKey, @JSONField(name = "mchId") String mchId, @JSONField(name = "secret") String appSecret,
@JSONField(name = "subMchId") String subMchId, @JSONField(name = "deviceInfo") String deviceInfo, @JSONField(name = "paySignKey") String paySignKey,
@JSONField(name = "partnerId") String partnerId, @JSONField(name = "partnerKey") String partnerKey) { @JSONField(name = "mchId") String mchId,
@JSONField(name = "certificateKey") String certificateKey,
@JSONField(name = "subMchId") String subMchId,
@JSONField(name = "deviceInfo") String deviceInfo,
@JSONField(name = "partnerId") String partnerId,
@JSONField(name = "partnerKey") String partnerKey) {
super(appId, appSecret); super(appId, appSecret);
this.paySignKey = paySignKey; this.paySignKey = paySignKey;
this.mchId = mchId; this.mchId = mchId;
this.certificateKey = certificateKey;
this.subMchId = subMchId; this.subMchId = subMchId;
this.deviceInfo = deviceInfo; this.deviceInfo = deviceInfo;
this.partnerId = partnerId; this.partnerId = partnerId;
@ -119,17 +128,16 @@ public class WeixinPayAccount extends WeixinAccount {
return deviceInfo; return deviceInfo;
} }
public int getVersion() { public String getCertificateKey() {
if (version == 0) { return StringUtil.isBlank(certificateKey) ? mchId : certificateKey;
return StringUtil.isNotBlank(mchId) ? 3 : 2;
}
return version;
} }
@Override @Override
public String toString() { public String toString() {
return "WeixinPayAccount [" + super.toString() + ", paySignKey=" + paySignKey + ", partnerId=" + partnerId return "WeixinPayAccount [" + super.toString() + ", paySignKey="
+ ", partnerKey=" + partnerKey + ", mchId=" + mchId + ", subMchId=" + subMchId + ", deviceInfo=" + paySignKey + ", partnerId=" + partnerId + ", partnerKey="
+ deviceInfo + ", version=" + getVersion() + "]"; + partnerKey + ", mchId=" + mchId + ", certificateKey="
+ getCertificateKey() + ", subMchId=" + subMchId
+ ", deviceInfo=" + deviceInfo + "]";
} }
} }

View File

@ -6,7 +6,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Date; import java.util.Date;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.api.CashApi; import com.foxinmy.weixin4j.api.CashApi;
import com.foxinmy.weixin4j.api.CouponApi; import com.foxinmy.weixin4j.api.CouponApi;
import com.foxinmy.weixin4j.api.Pay3Api; import com.foxinmy.weixin4j.api.Pay3Api;
@ -18,25 +17,24 @@ import com.foxinmy.weixin4j.payment.coupon.CouponDetail;
import com.foxinmy.weixin4j.payment.coupon.CouponResult; import com.foxinmy.weixin4j.payment.coupon.CouponResult;
import com.foxinmy.weixin4j.payment.coupon.CouponStock; import com.foxinmy.weixin4j.payment.coupon.CouponStock;
import com.foxinmy.weixin4j.payment.mch.ApiResult; import com.foxinmy.weixin4j.payment.mch.ApiResult;
import com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult;
import com.foxinmy.weixin4j.payment.mch.MPPayment; import com.foxinmy.weixin4j.payment.mch.MPPayment;
import com.foxinmy.weixin4j.payment.mch.MPPaymentRecord; import com.foxinmy.weixin4j.payment.mch.MPPaymentRecord;
import com.foxinmy.weixin4j.payment.mch.MPPaymentResult; import com.foxinmy.weixin4j.payment.mch.MPPaymentResult;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
import com.foxinmy.weixin4j.payment.mch.MchPayRequest; import com.foxinmy.weixin4j.payment.mch.MchPayRequest;
import com.foxinmy.weixin4j.payment.mch.NativePayResponse; import com.foxinmy.weixin4j.payment.mch.NativePayResponse;
import com.foxinmy.weixin4j.payment.mch.OpenIdResult;
import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.payment.mch.Redpacket; 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.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* 微信支付接口实现 * 微信支付接口实现
@ -54,26 +52,26 @@ public class WeixinPayProxy {
private final CouponApi couponApi; private final CouponApi couponApi;
private final CashApi cashApi; private final CashApi cashApi;
private final WeixinPayAccount payAccount; private final Weixin4jPaySettings settings;
/** /**
* 使用weixin4j.properties配置的账号信息 * 使用weixin4j.properties配置的支付账号信息
*/ */
public WeixinPayProxy() { public WeixinPayProxy() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), this(new Weixin4jPaySettings());
WeixinPayAccount.class));
} }
/** /**
* *
* @param weixinAccount * @param settings
* 支付相关的公众号账号信息 * 支付相关配置信息
* @see com.foxinmy.weixin4j.settings.Weixin4jPaySettings
*/ */
public WeixinPayProxy(WeixinPayAccount payAccount) { public WeixinPayProxy(Weixin4jPaySettings settings) {
this.payAccount = payAccount; this.settings = settings;
this.pay3Api = new Pay3Api(payAccount); this.pay3Api = new Pay3Api(settings.getPayAccount());
this.couponApi = new CouponApi(payAccount); this.couponApi = new CouponApi(settings.getPayAccount());
this.cashApi = new CashApi(payAccount); this.cashApi = new CashApi(settings.getPayAccount());
} }
/** /**
@ -82,9 +80,7 @@ public class WeixinPayProxy {
* @return * @return
*/ */
public WeixinPayAccount getPayAccount() { public WeixinPayAccount getPayAccount() {
// clone ... return this.settings.getPayAccount();
String text = JSON.toJSONString(payAccount);
return JSON.parseObject(text, WeixinPayAccount.class);
} }
/** /**
@ -429,7 +425,7 @@ public class WeixinPayProxy {
* </p> * </p>
* *
* @param ca * @param ca
* 证书文件(后缀为*.p12) * 后缀为*.p12的证书文件
* @param idQuery * @param idQuery
* 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级: * 商户系统内部的订单号, transaction_id out_trade_no 二选一,如果同时存在优先级:
* transaction_id> out_trade_no * transaction_id> out_trade_no
@ -461,7 +457,7 @@ public class WeixinPayProxy {
} }
/** /**
* 退款申请(全额退款)采用properties中配置的ca文件 * 退款申请(全额退款)
* *
* @throws IOException * @throws IOException
* *
@ -470,12 +466,9 @@ public class WeixinPayProxy {
public com.foxinmy.weixin4j.payment.mch.RefundResult refundApply( public com.foxinmy.weixin4j.payment.mch.RefundResult refundApply(
IdQuery idQuery, String outRefundNo, double totalFee) IdQuery idQuery, String outRefundNo, double totalFee)
throws WeixinException, IOException { throws WeixinException, IOException {
return pay3Api return pay3Api.refundApply(
.refundApply( new FileInputStream(settings.getCertificatePath()), idQuery,
new FileInputStream(Weixin4jConfigUtil outRefundNo, totalFee);
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
idQuery, outRefundNo, totalFee);
} }
/** /**
@ -521,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); return pay3Api.downloadBill(billDate, billType, settings.getBillPath());
} }
/** /**
@ -546,7 +539,7 @@ public class WeixinPayProxy {
} }
/** /**
* 冲正撤销:默认采用properties中配置的ca文件 * 冲正撤销
* *
* @param idQuery * @param idQuery
* transaction_idout_trade_no 二选一 * transaction_idout_trade_no 二选一
@ -557,12 +550,8 @@ public class WeixinPayProxy {
*/ */
public ApiResult reverseOrder(IdQuery idQuery) throws WeixinException, public ApiResult reverseOrder(IdQuery idQuery) throws WeixinException,
IOException { IOException {
return pay3Api return pay3Api.reverseOrder(
.reverseOrder( new FileInputStream(settings.getCertificatePath()), idQuery);
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
idQuery);
} }
/** /**
@ -635,7 +624,7 @@ public class WeixinPayProxy {
* 发放代金券(需要证书) * 发放代金券(需要证书)
* *
* @param ca * @param ca
* 证书文件(后缀为*.p12) * 后缀为*.p12的证书文件
* @param couponStockId * @param couponStockId
* 代金券批次id * 代金券批次id
* @param partnerTradeNo * @param partnerTradeNo
@ -659,17 +648,14 @@ public class WeixinPayProxy {
} }
/** /**
* 发放代金券采用properties中配置的ca文件 * 发放代金券
* *
* @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendCoupon(InputStream, String, String, String, String)} * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendCoupon(InputStream, String, String, String, String)}
*/ */
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 return couponApi.sendCoupon(
.sendCoupon( new FileInputStream(settings.getCertificatePath()),
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
couponStockId, partnerTradeNo, openId, null); couponStockId, partnerTradeNo, openId, null);
} }
@ -711,7 +697,7 @@ public class WeixinPayProxy {
* 发放红包 企业向微信用户个人发现金红包 * 发放红包 企业向微信用户个人发现金红包
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param redpacket * @param redpacket
* 红包信息 * 红包信息
* @return 发放结果 * @return 发放结果
@ -728,25 +714,21 @@ public class WeixinPayProxy {
} }
/** /**
* 发放红包采用properties中配置的ca文件 * 发放红包
* *
* @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendRedpack(InputStream, Redpacket)} * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#sendRedpack(InputStream, Redpacket)}
*/ */
public RedpacketSendResult sendRedpack(Redpacket redpacket) public RedpacketSendResult sendRedpack(Redpacket redpacket)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi return cashApi.sendRedpack(
.sendRedpack( new FileInputStream(settings.getCertificatePath()), redpacket);
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
redpacket);
} }
/** /**
* 查询红包记录 * 查询红包记录
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param outTradeNo * @param outTradeNo
* 商户发放红包的商户订单号 * 商户发放红包的商户订单号
* @return 红包记录 * @return 红包记录
@ -762,25 +744,21 @@ public class WeixinPayProxy {
} }
/** /**
* 查询红包采用properties中配置的ca文件 * 查询红包
* *
* @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#queryRedpack(InputStream,String)} * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#queryRedpack(InputStream,String)}
*/ */
public RedpacketRecord queryRedpack(String outTradeNo) public RedpacketRecord queryRedpack(String outTradeNo)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi return cashApi.queryRedpack(
.queryRedpack( new FileInputStream(settings.getCertificatePath()), outTradeNo);
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
outTradeNo);
} }
/** /**
* 企业付款 实现企业向个人付款针对部分有开发能力的商户 提供通过API完成企业付款的功能 比如目前的保险行业向客户退保给付理赔 * 企业付款 实现企业向个人付款针对部分有开发能力的商户 提供通过API完成企业付款的功能 比如目前的保险行业向客户退保给付理赔
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param mpPayment * @param mpPayment
* 付款信息 * 付款信息
* @return 付款结果 * @return 付款结果
@ -797,25 +775,21 @@ public class WeixinPayProxy {
} }
/** /**
* 企业付款采用properties中配置的ca文件 * 企业付款
* *
* @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPayment(InputStream, MPPayment)} * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPayment(InputStream, MPPayment)}
*/ */
public MPPaymentResult mpPayment(MPPayment mpPayment) public MPPaymentResult mpPayment(MPPayment mpPayment)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi return cashApi.mchPayment(
.mchPayment( new FileInputStream(settings.getCertificatePath()), mpPayment);
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
mpPayment);
} }
/** /**
* 企业付款查询 用于商户的企业付款操作进行结果查询返回付款操作详细结果 * 企业付款查询 用于商户的企业付款操作进行结果查询返回付款操作详细结果
* *
* @param ca * @param ca
* 证书文件(V3版本后缀为*.p12) * 后缀为*.p12的证书文件
* @param outTradeNo * @param outTradeNo
* 商户调用企业付款API时使用的商户订单号 * 商户调用企业付款API时使用的商户订单号
* @return 付款记录 * @return 付款记录
@ -831,18 +805,14 @@ public class WeixinPayProxy {
} }
/** /**
* 企业付款查询采用properties中配置的ca文件 * 企业付款查询
* *
* @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPaymentQuery(InputStream, String)} * @see {@link com.foxinmy.weixin4j.payment.WeixinPayProxy#mpPaymentQuery(InputStream, String)}
*/ */
public MPPaymentRecord mpPaymentQuery(String outTradeNo) public MPPaymentRecord mpPaymentQuery(String outTradeNo)
throws WeixinException, IOException { throws WeixinException, IOException {
return cashApi return cashApi.mchPaymentQuery(
.mchPaymentQuery( new FileInputStream(settings.getCertificatePath()), outTradeNo);
new FileInputStream(Weixin4jConfigUtil
.getClassPathValue("certificate.file",
Weixin4jConst.DEFAULT_CAFILE_PATH)),
outTradeNo);
} }
/** /**
@ -852,15 +822,14 @@ public class WeixinPayProxy {
* 扫码支付授权码设备读取用户微信中的条码或者二维码信息 * 扫码支付授权码设备读取用户微信中的条码或者二维码信息
* @return 查询结果 * @return 查询结果
* @see com.foxinmy.weixin4j.api.CashApi * @see com.foxinmy.weixin4j.api.CashApi
* @see com.foxinmy.weixin4j.payment.mch.AuthCodeOpenIdResult * @see com.foxinmy.weixin4j.payment.mch.OpenIdResult
* @see <a * @see <a
* href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9">授权码查询OPENID</a> * href="https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_13&index=9">授权码查询OPENID</a>
* @throws WeixinException * @throws WeixinException
*/ */
public AuthCodeOpenIdResult authCode2openId(String authCode) public OpenIdResult authCode2openId(String authCode) throws WeixinException {
throws WeixinException {
return pay3Api.authCode2openId(authCode); return pay3Api.authCode2openId(authCode);
} }
public final static String VERSION = "1.6.6"; public final static String VERSION = "1.6.7";
} }

View File

@ -80,7 +80,6 @@ public class CouponDetail extends ApiResult {
@XmlElement(name = "coupon_type") @XmlElement(name = "coupon_type")
@JSONField(name = "coupon_type") @JSONField(name = "coupon_type")
private int couponType; private int couponType;
/** /**
* 代金券描述 * 代金券描述
*/ */

View File

@ -5,6 +5,8 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlRootElement;
import com.alibaba.fastjson.annotation.JSONField;
/** /**
* Native支付回调时POST的信息 * Native支付回调时POST的信息
* *
@ -16,14 +18,20 @@ import javax.xml.bind.annotation.XmlRootElement;
*/ */
@XmlRootElement @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class NativePayNotify extends ApiResult { public class NativePayNotify extends OpenIdResult {
private static final long serialVersionUID = 4515471400239795492L; private static final long serialVersionUID = 4515471400239795492L;
/**
* 用户是否关注公众账号,Y- 关注,N-未关注,仅在公众 账号类型支付有效
*/
@XmlElement(name = "is_subscribe")
@JSONField(name = "is_subscribe")
private String isSubscribe;
/** /**
* 产品ID 可视为订单ID * 产品ID 可视为订单ID
*/ */
@XmlElement(name = "product_id") @XmlElement(name = "product_id")
@JSONField(name = "product_id")
private String productId; private String productId;
protected NativePayNotify() { protected NativePayNotify() {
@ -34,9 +42,13 @@ public class NativePayNotify extends ApiResult {
return productId; return productId;
} }
public String getIsSubscribe() {
return isSubscribe;
}
@Override @Override
public String toString() { public String toString() {
return "NativePayNotify [productId=" + productId + ", " return "NativePayNotify [productId=" + productId + ", isSubscribe="
+ super.toString() + "]"; + isSubscribe + ", " + super.toString() + "]";
} }
} }

View File

@ -10,7 +10,7 @@ import com.alibaba.fastjson.annotation.JSONField;
/** /**
* authcode2openid * authcode2openid
* *
* @className AuthCodeOpenIdResult * @className OpenIdResult
* @author jy * @author jy
* @date 2015年7月23日 * @date 2015年7月23日
* @since JDK 1.6 * @since JDK 1.6
@ -18,7 +18,7 @@ import com.alibaba.fastjson.annotation.JSONField;
*/ */
@XmlRootElement @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class AuthCodeOpenIdResult extends ApiResult { public class OpenIdResult extends ApiResult {
private static final long serialVersionUID = 902743989722741814L; private static final long serialVersionUID = 902743989722741814L;
@ -35,7 +35,7 @@ public class AuthCodeOpenIdResult extends ApiResult {
@Override @Override
public String toString() { public String toString() {
return "AuthCodeOpenIdResult [openId=" + openId + ", " return "OpenIdResult [openId=" + openId + ", "
+ super.toString() + "]"; + super.toString() + "]";
} }
} }

View File

@ -144,10 +144,6 @@ public class Redpacket implements Serializable {
return amtType; return amtType;
} }
public void setAmtType(String amtType) {
this.amtType = amtType;
}
public String getClientIp() { public String getClientIp() {
return clientIp; return clientIp;
} }

View File

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

View File

@ -0,0 +1,108 @@
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

@ -0,0 +1,168 @@
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

@ -44,7 +44,7 @@ public interface CacheStorager<T> {
T evict(String cacheKey); T evict(String cacheKey);
/** /**
* 清除所有缓存对象(<font color="red">请慎重</a>) * 清除所有缓存对象(<font color="red">请慎重</font>)
*/ */
void clear(); void clear();
} }

View File

@ -1,11 +1,16 @@
package com.foxinmy.weixin4j.util; package com.foxinmy.weixin4j.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.payment.mch.NativePayNotify;
import com.foxinmy.weixin4j.xml.XmlStream;
/** /**
* 签名工具类 * 签名工具类
@ -130,4 +135,12 @@ public final class DigestUtil {
return sb.toString(); return sb.toString();
} }
public static void main(String[] args) throws FileNotFoundException {
NativePayNotify notify = XmlStream.fromXML(new FileInputStream(
new File("/Users/jy/Downloads/weixin4j.xml")),
NativePayNotify.class);
notify.setSign(null);
System.err.println(paysignMd5(notify, "GATFzDwbQdbbci3QEQxX2rUBvwTrsMiZ"));
}
} }

View File

@ -75,7 +75,7 @@ public class Weixin4jConfigUtil {
value = getValue(key); value = getValue(key);
} catch (MissingResourceException e) { } catch (MissingResourceException e) {
; ;
}catch (NullPointerException e){ } catch (NullPointerException e) {
; ;
} }
return value; return value;
@ -88,8 +88,7 @@ public class Weixin4jConfigUtil {
* @return * @return
*/ */
public static String getClassPathValue(String key) { public static String getClassPathValue(String key) {
return new File(getValue(key).replaceFirst(CLASSPATH_PREFIX, return getValue(key).replaceFirst(CLASSPATH_PREFIX, CLASSPATH_VALUE);
CLASSPATH_VALUE)).getPath();
} }
/** /**
@ -99,18 +98,18 @@ public class Weixin4jConfigUtil {
* @return * @return
*/ */
public static String getClassPathValue(String key, String defaultValue) { public static String getClassPathValue(String key, String defaultValue) {
return new File(getValue(key, defaultValue).replaceFirst( return getValue(key, defaultValue).replaceFirst(CLASSPATH_PREFIX,
CLASSPATH_PREFIX, CLASSPATH_VALUE)).getPath(); CLASSPATH_VALUE);
} }
public static WeixinAccount getWeixinAccount() { public static WeixinAccount getWeixinAccount() {
if (weixinBundle == null) {
return null;
}
WeixinAccount account = null; WeixinAccount account = null;
try { try {
account = JSON account = JSON
.parseObject(getValue("account"), WeixinAccount.class); .parseObject(getValue("account"), WeixinAccount.class);
} catch (NullPointerException e) {
System.err
.println("'weixin4j.account' key not found in weixin4j.properties.");
} catch (MissingResourceException e) { } catch (MissingResourceException e) {
System.err System.err
.println("'weixin4j.account' key not found in weixin4j.properties."); .println("'weixin4j.account' key not found in weixin4j.properties.");

View File

@ -1,33 +0,0 @@
package com.foxinmy.weixin4j.util;
/**
* 常量配置
*
* @className Weixin4jConst
* @author jy
* @date 2015年7月1日
* @since JDK 1.6
* @see
*/
public final class Weixin4jConst {
/**
* 使用FileTokenStorager时token的存放路径
*/
public static final String DEFAULT_TOKEN_PATH = "/tmp/weixin4j/token";
/**
* 二维码保存路径
*/
public static final String DEFAULT_QRCODE_PATH = "/tmp/weixin4j/qrcode";
/**
* 媒体文件保存路径
*/
public static final String DEFAULT_MEDIA_PATH = "/tmp/weixin4j/media";
/**
* 对账单保存路径
*/
public static final String DEFAULT_BILL_PATH = "/tmp/weixin4j/bill";
/**
* ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12)
*/
public static final String DEFAULT_CAFILE_PATH = "classpath:ca.p12";
}

View File

@ -67,7 +67,9 @@ public class HttpClientTest {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
for(int i=0;i<100000;i++){
test1(); test1();
}
System.out.println("---------------------"); System.out.println("---------------------");
test2(); test2();
System.out.println("---------------------"); System.out.println("---------------------");

View File

@ -58,21 +58,27 @@ weixin4j.properties说明
完整填写示例(properties中换行用右斜杆\\) 完整填写示例(properties中换行用右斜杆\\)
weixin4j.account={"id":"appId","secret":"appSecret",\ weixin4j.account={"id":"appid","secret":"appsecret",\
"mchId":"V3.x版本下的微信商户号",\ "mchId":"V3.x版本下的微信商户号 微信支付时需要填入",\
"partnerId":"V2版本下的财付通的商户号",\ "certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\
"partnerKey":"V2版本下的财付通商户权限密钥Key",\ "partnerId":"V2版本下的财付通的商户号 微信支付时需要填入",\
"paySignKey":"微信支付中调用API的密钥"} "partnerKey":"V2版本下的财付通商户权限密钥Key 微信支付时需要填入",\
"paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"}
# 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token weixin4j.token.path=/tmp/weixin4j/token
# 二维码保存路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.qrcode.path=/tmp/weixin4j/qrcode weixin4j.qrcode.path=/tmp/weixin4j/qrcode
# 媒体文件保存路径(如果不填则默认为Weixin4jConst#DEFAULT_MEDIA_PATH)
weixin4j.media.path=/tmp/weixin4j/media weixin4j.media.path=/tmp/weixin4j/media
# 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill weixin4j.bill.path=/tmp/weixin4j/bill
# ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12) # ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12)
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
#classpath路径下:weixin4j.certificate.file=classpath:xxxxx.p12 # classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
#公众号登陆授权的重定向路径(使用OauthApi时需要填写) # 用户oauth授权后重定向的url(在使用OauthApi时填写)
weixin4j.user.oauth.redirect.uri=http://xxx weixin4j.user.oauth.redirect.uri=http://xxx
2.实例化微信公众号接口代理对象,调用具体的API方法 2.实例化微信公众号接口代理对象,调用具体的API方法

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.foxinmy</groupId> <groupId>com.foxinmy</groupId>
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>1.6.6</version> <version>1.6.7</version>
</parent> </parent>
<artifactId>weixin4j-mp</artifactId> <artifactId>weixin4j-mp</artifactId>
<name>weixin4j-mp</name> <name>weixin4j-mp</name>

View File

@ -14,6 +14,7 @@ import com.foxinmy.weixin4j.model.MediaItem;
import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.MediaRecord;
import com.foxinmy.weixin4j.model.MediaUploadResult; import com.foxinmy.weixin4j.model.MediaUploadResult;
import com.foxinmy.weixin4j.model.Pageable; import com.foxinmy.weixin4j.model.Pageable;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.api.CustomApi;
import com.foxinmy.weixin4j.mp.api.DataApi; import com.foxinmy.weixin4j.mp.api.DataApi;
import com.foxinmy.weixin4j.mp.api.GroupApi; import com.foxinmy.weixin4j.mp.api.GroupApi;
@ -21,7 +22,6 @@ import com.foxinmy.weixin4j.mp.api.HelperApi;
import com.foxinmy.weixin4j.mp.api.MassApi; import com.foxinmy.weixin4j.mp.api.MassApi;
import com.foxinmy.weixin4j.mp.api.MediaApi; import com.foxinmy.weixin4j.mp.api.MediaApi;
import com.foxinmy.weixin4j.mp.api.MenuApi; import com.foxinmy.weixin4j.mp.api.MenuApi;
import com.foxinmy.weixin4j.mp.api.MpApi;
import com.foxinmy.weixin4j.mp.api.NotifyApi; import com.foxinmy.weixin4j.mp.api.NotifyApi;
import com.foxinmy.weixin4j.mp.api.QrApi; import com.foxinmy.weixin4j.mp.api.QrApi;
import com.foxinmy.weixin4j.mp.api.TmplApi; import com.foxinmy.weixin4j.mp.api.TmplApi;
@ -47,8 +47,8 @@ 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.token.TokenStorager;
import com.foxinmy.weixin4j.tuple.MassTuple; import com.foxinmy.weixin4j.tuple.MassTuple;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.tuple.MpVideo; import com.foxinmy.weixin4j.tuple.MpVideo;
@ -80,45 +80,26 @@ public class WeixinProxy {
private final DataApi dataApi; private final DataApi dataApi;
private final TokenHolder tokenHolder; private final TokenHolder tokenHolder;
private String appId; private Weixin4jSettings settings;
/** /**
* 默认使用文件方式保存token使用weixin4j.properties配置的账号信息 * 默认使用文件方式保存token使用weixin4j.properties配置的账号信息
*/ */
public WeixinProxy() { public WeixinProxy() {
this(MpApi.DEFAULT_TOKEN_STORAGER); this(new Weixin4jSettings());
}
/**
* 默认使用weixin4j.properties配置的账号信息
*
* @param tokenStorager
*/
public WeixinProxy(TokenStorager tokenStorager) {
this(MpApi.DEFAULT_WEIXIN_ACCOUNT.getId(), MpApi.DEFAULT_WEIXIN_ACCOUNT
.getSecret(), tokenStorager);
} }
/** /**
* *
* @param appid * @param settings
* @param appsecret * 配置信息
* @see com.foxinmy.weixin4j.settings.Weixin4jSettings
*/ */
public WeixinProxy(String appid, String appsecret) { public WeixinProxy(Weixin4jSettings settings) {
this(appid, appsecret, MpApi.DEFAULT_TOKEN_STORAGER); this(new TokenHolder(new WeixinTokenCreator(settings.getAccount()
} .getId(), settings.getAccount().getSecret()),
settings.getTokenStorager()));
/** this.settings = settings;
*
* @param appid
* @param appsecret
* @param tokenStorager
*/
public WeixinProxy(String appid, String appsecret,
TokenStorager tokenStorager) {
this(new TokenHolder(new WeixinTokenCreator(appid, appsecret),
tokenStorager));
this.appId = appid;
} }
/** /**
@ -143,12 +124,12 @@ public class WeixinProxy {
} }
/** /**
* 获取appid * 获取微信账号信息
* *
* @return * @return
*/ */
public String getAppId() { public WeixinAccount getWeixinAccount() {
return this.appId; return this.settings.getAccount();
} }
/** /**
@ -168,8 +149,9 @@ public class WeixinProxy {
* @return * @return
*/ */
public TokenHolder getTicketHolder(TicketType ticketType) { public TokenHolder getTicketHolder(TicketType ticketType) {
return new TokenHolder(new WeixinTicketCreator(this.appId, ticketType, return new TokenHolder(new WeixinTicketCreator(getWeixinAccount()
this.tokenHolder), this.tokenHolder.getTokenStorager()); .getId(), ticketType, this.tokenHolder),
this.tokenHolder.getTokenStorager());
} }
/** /**
@ -248,10 +230,8 @@ public class WeixinProxy {
* *
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @param mediaType
* 媒体类型
* @param isMaterial * @param isMaterial
* 是否永久素材 * 是否下载永久素材
* @return 写入硬盘后的文件对象 * @return 写入硬盘后的文件对象
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
@ -261,7 +241,8 @@ public class WeixinProxy {
*/ */
public File downloadMediaFile(String mediaId, boolean isMaterial) public File downloadMediaFile(String mediaId, boolean isMaterial)
throws WeixinException { throws WeixinException {
return mediaApi.downloadMediaFile(mediaId, isMaterial); return mediaApi.downloadMediaFile(mediaId, isMaterial,
settings.getMediaPath());
} }
/** /**
@ -1215,11 +1196,13 @@ public class WeixinProxy {
* 生成带参数的二维码 * 生成带参数的二维码
* *
* @return 硬盘存储的文件对象 * @return 硬盘存储的文件对象
* @param parameter
* 二维码参数
* @throws WeixinException * @throws WeixinException
* @see {@link #createQR(QRParameter)} * @see {@link #createQR(QRParameter)}
*/ */
public File createQRFile(QRParameter parameter) throws WeixinException { public File createQRFile(QRParameter parameter) throws WeixinException {
return qrApi.createQRFile(parameter); return qrApi.createQRFile(parameter, settings.getQrcodePath());
} }
/** /**
@ -1463,5 +1446,5 @@ public class WeixinProxy {
return dataApi.datacube(datacubeType, date); return dataApi.datacube(datacubeType, date);
} }
public final static String VERSION = "1.6.6"; public final static String VERSION = "1.6.7";
} }

View File

@ -48,8 +48,6 @@ import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.ObjectId;
import com.foxinmy.weixin4j.util.RegexUtil; import com.foxinmy.weixin4j.util.RegexUtil;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
import com.foxinmy.weixin4j.util.WeixinErrorUtil; import com.foxinmy.weixin4j.util.WeixinErrorUtil;
/** /**
@ -238,7 +236,11 @@ public class MediaApi extends MpApi {
* *
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @param isMaterial
* 是否下载永久素材
* @param mediaPath
* 媒体素材保存路径
* @return 写入硬盘后的文件对象
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体文件</a> * href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体文件</a>
@ -246,12 +248,10 @@ public class MediaApi extends MpApi {
* href="http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材</a> * href="http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材</a>
* @see {@link #downloadMedia(String,boolean)} * @see {@link #downloadMedia(String,boolean)}
*/ */
public File downloadMediaFile(String mediaId, boolean isMaterial) public File downloadMediaFile(String mediaId, boolean isMaterial,
throws WeixinException { String mediaPath) throws WeixinException {
String media_path = Weixin4jConfigUtil.getValue("media.path",
Weixin4jConst.DEFAULT_MEDIA_PATH);
final String prefixName = String.format("%s.", mediaId); final String prefixName = String.format("%s.", mediaId);
File[] files = new File(media_path).listFiles(new FilenameFilter() { File[] files = new File(mediaPath).listFiles(new FilenameFilter() {
@Override @Override
public boolean accept(File dir, String name) { public boolean accept(File dir, String name) {
return name.startsWith(prefixName); return name.startsWith(prefixName);
@ -261,7 +261,7 @@ public class MediaApi extends MpApi {
return files[0]; return files[0];
} }
MediaDownloadResult result = downloadMedia(mediaId, isMaterial); MediaDownloadResult result = downloadMedia(mediaId, isMaterial);
File file = new File(media_path + File.separator + result.getFileName()); File file = new File(mediaPath + File.separator + result.getFileName());
OutputStream os = null; OutputStream os = null;
try { try {
if (file.createNewFile()) { if (file.createNewFile()) {

View File

@ -7,11 +7,12 @@ 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.Consts; import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.mp.model.OauthToken; import com.foxinmy.weixin4j.mp.model.OauthToken;
import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.model.User;
import com.foxinmy.weixin4j.mp.type.Lang; import com.foxinmy.weixin4j.mp.type.Lang;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
* oauth授权 * oauth授权
@ -25,13 +26,23 @@ import com.foxinmy.weixin4j.util.StringUtil;
*/ */
public class OauthApi extends MpApi { public class OauthApi extends MpApi {
private final WeixinAccount account;
public OauthApi() {
this(Weixin4jConfigUtil.getWeixinAccount());
}
public OauthApi(WeixinAccount account) {
this.account = account;
}
/** /**
* @see {@link #getAuthorizeURL(String, String,String)} * @see {@link #getAuthorizeURL(String, String,String)}
* *
* @return 请求授权的URL * @return 请求授权的URL
*/ */
public String getAuthorizeURL() { public String getAuthorizeURL() {
String appId = DEFAULT_WEIXIN_ACCOUNT.getId(); String appId = account.getId();
String redirectUri = Weixin4jConfigUtil String redirectUri = Weixin4jConfigUtil
.getValue("user.oauth.redirect.uri"); .getValue("user.oauth.redirect.uri");
return getAuthorizeURL(appId, redirectUri, "state", "snsapi_base"); return getAuthorizeURL(appId, redirectUri, "state", "snsapi_base");
@ -67,8 +78,7 @@ public class OauthApi extends MpApi {
* @return * @return
*/ */
public OauthToken getOauthToken(String code) throws WeixinException { public OauthToken getOauthToken(String code) throws WeixinException {
return getOauthToken(code, DEFAULT_WEIXIN_ACCOUNT.getId(), return getOauthToken(code, account.getId(), account.getSecret());
DEFAULT_WEIXIN_ACCOUNT.getSecret());
} }
/** /**
@ -100,7 +110,7 @@ public class OauthApi extends MpApi {
* @return * @return
*/ */
public OauthToken refreshToken(String refreshToken) throws WeixinException { public OauthToken refreshToken(String refreshToken) throws WeixinException {
return refreshToken(DEFAULT_WEIXIN_ACCOUNT.getId(), refreshToken); return refreshToken(account.getId(), refreshToken);
} }
/** /**

View File

@ -40,6 +40,9 @@ 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.token.TokenStorager;
import com.foxinmy.weixin4j.type.BillType; import com.foxinmy.weixin4j.type.BillType;
@ -51,8 +54,6 @@ 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.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer; import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
/** /**
@ -66,23 +67,27 @@ import com.foxinmy.weixin4j.xml.ListsuffixResultDeserializer;
*/ */
public class Pay2Api extends MpApi { public class Pay2Api extends MpApi {
private final WeixinPayAccount weixinAccount; private final Weixin4jPaySettings settings;
private final TokenHolder tokenHolder; private final TokenHolder tokenHolder;
public Pay2Api() { public Pay2Api() {
this(JSON.parseObject(Weixin4jConfigUtil.getValue("account"), this(new Weixin4jPaySettings());
WeixinPayAccount.class));
} }
public Pay2Api(WeixinPayAccount weixinAccount) { public Pay2Api(Weixin4jPaySettings settings) {
this(weixinAccount, DEFAULT_TOKEN_STORAGER); this(settings, new FileTokenStorager(
Weixin4jSettings.DEFAULT_TOKEN_PATH));
} }
public Pay2Api(WeixinPayAccount weixinAccount, TokenStorager tokenStorager) { public Pay2Api(Weixin4jPaySettings settings, TokenStorager tokenStorager) {
this.weixinAccount = weixinAccount; this.settings = settings;
this.tokenHolder = new TokenHolder(new WeixinTokenCreator( this.tokenHolder = new TokenHolder(
weixinAccount.getId(), weixinAccount.getSecret()), new WeixinTokenCreator(settings.getPayAccount().getId(),
tokenStorager); settings.getPayAccount().getSecret()), tokenStorager);
}
public WeixinPayAccount getPayAccount() {
return this.settings.getPayAccount();
} }
/** /**
@ -137,20 +142,20 @@ 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( PayPackageV2 payPackage = new PayPackageV2(settings.getPayAccount()
weixinAccount.getPartnerId(), body, outTradeNo, totalFee, .getPartnerId(), body, outTradeNo, totalFee, notifyUrl,
notifyUrl, createIp); createIp);
payPackage.setAttach(attach); payPackage.setAttach(attach);
payPackage.setTimeStart(timeStart); payPackage.setTimeStart(timeStart);
payPackage.setTimeExpire(timeExpire); payPackage.setTimeExpire(timeExpire);
payPackage.setTransportFee(transportFee); payPackage.setTransportFee(transportFee);
payPackage.setProductFee(productFee); payPackage.setProductFee(productFee);
payPackage.setGoodsTag(goodsTag); payPackage.setGoodsTag(goodsTag);
PayRequest payRequest = new PayRequest(weixinAccount.getId(), PayRequest payRequest = new PayRequest(getPayAccount().getId(),
DigestUtil.packageSign(payPackage, DigestUtil.packageSign(payPackage, getPayAccount()
weixinAccount.getPartnerKey())); .getPartnerKey()));
payRequest.setPaySign(DigestUtil.paysignSha(payRequest, payRequest.setPaySign(DigestUtil.paysignSha(payRequest, getPayAccount()
weixinAccount.getPaySignKey())); .getPaySignKey()));
payRequest.setSignType(SignType.SHA1); payRequest.setSignType(SignType.SHA1);
return JSON.toJSONString(payRequest); return JSON.toJSONString(payRequest);
} }
@ -166,14 +171,14 @@ public class Pay2Api extends MpApi {
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
String timestamp = DateUtil.timestamp2string(); String timestamp = DateUtil.timestamp2string();
String noncestr = RandomUtil.generateString(16); String noncestr = RandomUtil.generateString(16);
map.put("appid", weixinAccount.getId()); map.put("appid", getPayAccount().getId());
map.put("timestamp", timestamp); map.put("timestamp", timestamp);
map.put("noncestr", noncestr); map.put("noncestr", noncestr);
map.put("productid", productId); map.put("productid", productId);
map.put("appkey", weixinAccount.getPaySignKey()); map.put("appkey", getPayAccount().getPaySignKey());
String sign = DigestUtil.paysignSha(map, null); String sign = DigestUtil.paysignSha(map, null);
String ordernative_v2_uri = getRequestUri("ordernative_v2_uri"); String ordernative_v2_uri = getRequestUri("ordernative_v2_uri");
return String.format(ordernative_v2_uri, sign, weixinAccount.getId(), return String.format(ordernative_v2_uri, sign, getPayAccount().getId(),
productId, timestamp, noncestr); productId, timestamp, noncestr);
} }
@ -193,23 +198,23 @@ public class Pay2Api extends MpApi {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(idQuery.getType().getName()).append("=") sb.append(idQuery.getType().getName()).append("=")
.append(idQuery.getId()); .append(idQuery.getId());
sb.append("&partner=").append(weixinAccount.getPartnerId()); sb.append("&partner=").append(getPayAccount().getPartnerId());
String part = sb.toString(); String part = sb.toString();
sb.append("&key=").append(weixinAccount.getPartnerKey()); sb.append("&key=").append(getPayAccount().getPartnerKey());
String sign = DigestUtil.MD5(sb.toString()).toUpperCase(); String sign = DigestUtil.MD5(sb.toString()).toUpperCase();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
sb.append(part).append("&sign=").append(sign); sb.append(part).append("&sign=").append(sign);
String timestamp = DateUtil.timestamp2string(); String timestamp = DateUtil.timestamp2string();
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("appid", weixinAccount.getId()); obj.put("appid", getPayAccount().getId());
obj.put("appkey", weixinAccount.getPaySignKey()); obj.put("appkey", getPayAccount().getPaySignKey());
obj.put("package", sb.toString()); obj.put("package", sb.toString());
obj.put("timestamp", timestamp); obj.put("timestamp", timestamp);
String signature = DigestUtil.paysignSha(obj, null); String signature = DigestUtil.paysignSha(obj, null);
obj.clear(); obj.clear();
obj.put("appid", weixinAccount.getId()); obj.put("appid", getPayAccount().getId());
obj.put("package", sb.toString()); obj.put("package", sb.toString());
obj.put("timestamp", timestamp); obj.put("timestamp", timestamp);
obj.put("app_signature", signature); obj.put("app_signature", signature);
@ -271,20 +276,20 @@ public class Pay2Api extends MpApi {
// 填写为 1.0 ,操作员密码为明文 // 填写为 1.0 ,操作员密码为明文
// 填写为 1.1 ,操作员密码为 MD5(密码) // 填写为 1.1 ,操作员密码为 MD5(密码)
map.put("service_version", "1.1"); map.put("service_version", "1.1");
map.put("partner", weixinAccount.getPartnerId()); map.put("partner", getPayAccount().getPartnerId());
map.put("out_refund_no", outRefundNo); map.put("out_refund_no", outRefundNo);
map.put("total_fee", DateUtil.formaFee2Fen(totalFee)); map.put("total_fee", DateUtil.formaFee2Fen(totalFee));
map.put("refund_fee", DateUtil.formaFee2Fen(refundFee)); map.put("refund_fee", DateUtil.formaFee2Fen(refundFee));
map.put(idQuery.getType().getName(), idQuery.getId()); map.put(idQuery.getType().getName(), idQuery.getId());
if (StringUtil.isBlank(opUserId)) { if (StringUtil.isBlank(opUserId)) {
opUserId = weixinAccount.getPartnerId(); opUserId = getPayAccount().getPartnerId();
} }
map.put("op_user_id", opUserId); map.put("op_user_id", opUserId);
if (mopara != null && !mopara.isEmpty()) { if (mopara != null && !mopara.isEmpty()) {
map.putAll(mopara); map.putAll(mopara);
} }
String sign = DigestUtil.paysignMd5(map, String sign = DigestUtil.paysignMd5(map, getPayAccount()
weixinAccount.getPartnerKey()); .getPartnerKey());
map.put("sign", sign.toUpperCase()); map.put("sign", sign.toUpperCase());
SSLContext ctx = null; SSLContext ctx = null;
@ -319,8 +324,8 @@ public class Pay2Api extends MpApi {
KeyManagerFactory kmf = KeyManagerFactory KeyManagerFactory kmf = KeyManagerFactory
.getInstance(com.foxinmy.weixin4j.model.Consts.SunX509); .getInstance(com.foxinmy.weixin4j.model.Consts.SunX509);
ks = KeyStore.getInstance(com.foxinmy.weixin4j.model.Consts.PKCS12); ks = KeyStore.getInstance(com.foxinmy.weixin4j.model.Consts.PKCS12);
ks.load(ca, weixinAccount.getPartnerId().toCharArray()); ks.load(ca, getPayAccount().getPartnerId().toCharArray());
kmf.init(ks, weixinAccount.getPartnerId().toCharArray()); kmf.init(ks, getPayAccount().getPartnerId().toCharArray());
ctx = SSLContext.getInstance(com.foxinmy.weixin4j.model.Consts.TLS); ctx = SSLContext.getInstance(com.foxinmy.weixin4j.model.Consts.TLS);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
@ -451,23 +456,22 @@ public class Pay2Api extends MpApi {
billType = BillType.ALL; billType = BillType.ALL;
} }
String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate); String formatBillDate = DateUtil.fortmat2yyyyMMdd(billDate);
String bill_path = Weixin4jConfigUtil.getValue("bill.path",
Weixin4jConst.DEFAULT_BILL_PATH);
String fileName = String.format("%s_%s_%s.txt", formatBillDate, String fileName = String.format("%s_%s_%s.txt", formatBillDate,
billType.name().toLowerCase(), weixinAccount.getId()); billType.name().toLowerCase(), getPayAccount().getId());
File file = new File(String.format("%s/%s", bill_path, fileName)); File file = new File(String.format("%s/%s", settings.getBillPath(),
fileName));
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
String downloadbill_uri = getRequestUri("downloadbill_v2_uri"); String downloadbill_uri = getRequestUri("downloadbill_v2_uri");
Map<String, String> map = new LinkedHashMap<String, String>(); Map<String, String> map = new LinkedHashMap<String, String>();
map.put("spid", weixinAccount.getPartnerId()); map.put("spid", getPayAccount().getPartnerId());
map.put("trans_time", DateUtil.fortmat2yyyy_MM_dd(billDate)); map.put("trans_time", DateUtil.fortmat2yyyy_MM_dd(billDate));
map.put("stamp", DateUtil.timestamp2string()); map.put("stamp", DateUtil.timestamp2string());
map.put("cft_signtype", "0"); map.put("cft_signtype", "0");
map.put("mchtype", Integer.toString(billType.getVal())); map.put("mchtype", Integer.toString(billType.getVal()));
map.put("key", weixinAccount.getPartnerKey()); map.put("key", getPayAccount().getPartnerKey());
String sign = DigestUtil.MD5(MapUtil.toJoinString(map, false, false)); String sign = DigestUtil.MD5(MapUtil.toJoinString(map, false, false));
map.put("sign", sign.toLowerCase()); map.put("sign", sign.toLowerCase());
WeixinResponse response = weixinExecutor.get(downloadbill_uri, map); WeixinResponse response = weixinExecutor.get(downloadbill_uri, map);
@ -517,9 +521,10 @@ public class Pay2Api extends MpApi {
String refundquery_uri = getRequestUri("refundquery_v2_uri"); String refundquery_uri = getRequestUri("refundquery_v2_uri");
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
map.put("input_charset", Consts.UTF_8.name()); map.put("input_charset", Consts.UTF_8.name());
map.put("partner", weixinAccount.getPartnerId()); map.put("partner", getPayAccount().getPartnerId());
map.put(idQuery.getType().getName(), idQuery.getId()); map.put(idQuery.getType().getName(), idQuery.getId());
String sign = DigestUtil.paysignMd5(map, weixinAccount.getPartnerKey()); String sign = DigestUtil.paysignMd5(map, getPayAccount()
.getPartnerKey());
map.put("sign", sign.toLowerCase()); map.put("sign", sign.toLowerCase());
WeixinResponse response = weixinExecutor.get(refundquery_uri, map); WeixinResponse response = weixinExecutor.get(refundquery_uri, map);
return ListsuffixResultDeserializer.deserialize(response.getAsString(), return ListsuffixResultDeserializer.deserialize(response.getAsString(),
@ -549,8 +554,8 @@ public class Pay2Api extends MpApi {
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
map.put("appid", weixinAccount.getId()); map.put("appid", getPayAccount().getId());
map.put("appkey", weixinAccount.getPaySignKey()); map.put("appkey", getPayAccount().getPaySignKey());
map.put("openid", openId); map.put("openid", openId);
map.put("transid", transid); map.put("transid", transid);
map.put("out_trade_no", outTradeNo); map.put("out_trade_no", outTradeNo);

View File

@ -13,8 +13,6 @@ import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.QRResult; import com.foxinmy.weixin4j.mp.model.QRResult;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* 二维码相关API * 二维码相关API
@ -55,7 +53,8 @@ public class QrApi extends MpApi {
QRResult result = response.getAsObject(new TypeReference<QRResult>() { QRResult result = response.getAsObject(new TypeReference<QRResult>() {
}); });
qr_uri = getRequestUri("qr_image_uri"); qr_uri = getRequestUri("qr_image_uri");
response = weixinExecutor.get(String.format(qr_uri, result.getTicket())); response = weixinExecutor
.get(String.format(qr_uri, result.getTicket()));
try { try {
result.setContent(IOUtil.toByteArray(response.getBody())); result.setContent(IOUtil.toByteArray(response.getBody()));
} catch (IOException e) { } catch (IOException e) {
@ -72,6 +71,8 @@ public class QrApi extends MpApi {
* *
* @param parameter * @param parameter
* 二维码参数 * 二维码参数
* @param qrcodePath
* 二维码保存路径
* @return 硬盘存储的文件对象 * @return 硬盘存储的文件对象
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
@ -79,13 +80,12 @@ public class QrApi extends MpApi {
* @see #createQR(QRParameter) * @see #createQR(QRParameter)
* @see com.foxinmy.weixin4j.mp.model.QRParameter * @see com.foxinmy.weixin4j.mp.model.QRParameter
*/ */
public File createQRFile(QRParameter parameter) throws WeixinException { public File createQRFile(QRParameter parameter, String qrcodePath)
String qr_path = Weixin4jConfigUtil.getValue("qrcode.path", throws WeixinException {
Weixin4jConst.DEFAULT_QRCODE_PATH);
String filename = String.format("%s_%s_%d.jpg", parameter.getQrType() String filename = String.format("%s_%s_%d.jpg", parameter.getQrType()
.name(), parameter.getSceneValue(), parameter .name(), parameter.getSceneValue(), parameter
.getExpireSeconds()); .getExpireSeconds());
File file = new File(qr_path + File.separator + filename); File file = new File(qrcodePath + File.separator + filename);
if (parameter.getQrType().ordinal() > 0 && file.exists()) { if (parameter.getQrType().ordinal() > 0 && file.exists()) {
return file; return file;
} }

View File

@ -1,23 +1,24 @@
# \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
weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\ weixin4j.account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
"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 \u5fae\u4fe1\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",\ "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",\
"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",\ "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",\
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \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 \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"}
# \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84 # \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token weixin4j.token.path=/tmp/weixin4j/token
# \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84 # \u4e8c\u7ef4\u7801\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.qrcode.path=/tmp/weixin4j/qrcode weixin4j.qrcode.path=/tmp/weixin4j/qrcode
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 # \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH)
weixin4j.media.path=/tmp/weixin4j/media weixin4j.media.path=/tmp/weixin4j/media
# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84 # \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill weixin4j.bill.path=/tmp/weixin4j/bill
# ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12) # 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 # 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 # weixin4j.certificate.file=classpath:xxxxx.pfx
# \u7528\u6237oauth\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url # \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

@ -94,7 +94,8 @@ public class MediaTest extends TokenTest {
@Test @Test
public void download2() throws WeixinException, IOException { public void download2() throws WeixinException, IOException {
File file = mediaApi.downloadMediaFile("8790403529", true); File file = mediaApi.downloadMediaFile("8790403529", true,
"/tmp/weixin4j/media");
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }

View File

@ -19,12 +19,11 @@ import com.foxinmy.weixin4j.payment.mch.ApiResult;
import com.foxinmy.weixin4j.payment.mch.MchPayPackage; import com.foxinmy.weixin4j.payment.mch.MchPayPackage;
import com.foxinmy.weixin4j.payment.mch.Order; import com.foxinmy.weixin4j.payment.mch.Order;
import com.foxinmy.weixin4j.payment.mch.PrePay; import com.foxinmy.weixin4j.payment.mch.PrePay;
import com.foxinmy.weixin4j.token.FileTokenStorager; 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.type.TradeType;
import com.foxinmy.weixin4j.util.DigestUtil; import com.foxinmy.weixin4j.util.DigestUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
public class PayTest { public class PayTest {
protected final static Pay2Api PAY2; protected final static Pay2Api PAY2;
@ -33,14 +32,13 @@ public class PayTest {
protected final static WeixinPayAccount ACCOUNT3; 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, "请填入v2版本的partnerId", "请填入v2版本的paysignkey", null, null, null, null,
"请填入v2版本的partnerKey"); "请填入v2版本的partnerId", "请填入v2版本的partnerKey");
PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager( PAY2 = new Pay2Api(new Weixin4jPaySettings(ACCOUNT2));
Weixin4jConfigUtil
.getValue("token.path", "/tmp/weixin4j/token")));
ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret", ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret",
"请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null); "请填入v3版本的paysignkey", "请填入v3版本的mchid", null, null, null, null,
PAY3 = new WeixinPayProxy(ACCOUNT3); null);
PAY3 = new WeixinPayProxy(new Weixin4jPaySettings(ACCOUNT3));
} }
/** /**
* 商户证书文件 * 商户证书文件
@ -55,7 +53,6 @@ public class PayTest {
@Test @Test
public void refundV2() throws WeixinException { public void refundV2() throws WeixinException {
File caFile = new File("证书文件如12333.pfx");
IdQuery idQuery = new IdQuery("D15020300005", IdType.TRADENO); IdQuery idQuery = new IdQuery("D15020300005", IdType.TRADENO);
System.err.println(PAY2.refundApply(caFile, idQuery, "1422925555037", System.err.println(PAY2.refundApply(caFile, idQuery, "1422925555037",
16d, 16d, "1221928801", "111111", null, null, null)); 16d, 16d, "1221928801", "111111", null, null, null));
@ -84,7 +81,8 @@ public class PayTest {
System.err.println(order); System.err.println(order);
String sign = order.getSign(); String sign = order.getSign();
order.setSign(null); order.setSign(null);
String valiSign = DigestUtil.paysignMd5(order, ACCOUNT3.getPaySignKey()); String valiSign = DigestUtil
.paysignMd5(order, ACCOUNT3.getPaySignKey());
System.err System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign)); .println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign); Assert.assertEquals(valiSign, sign);
@ -98,7 +96,8 @@ public class PayTest {
// 这里的验证签名需要把details循环拼接 // 这里的验证签名需要把details循环拼接
String sign = record.getSign(); String sign = record.getSign();
record.setSign(null); record.setSign(null);
String valiSign = DigestUtil.paysignMd5(record, ACCOUNT3.getPaySignKey()); String valiSign = DigestUtil.paysignMd5(record,
ACCOUNT3.getPaySignKey());
System.err System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign)); .println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign); Assert.assertEquals(valiSign, sign);
@ -118,7 +117,6 @@ public class PayTest {
@Test @Test
public void refundV3() throws WeixinException, IOException { public void refundV3() throws WeixinException, IOException {
File caFile = new File("签名文件如123.p12");
IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO); IdQuery idQuery = new IdQuery("TT_1427183696238", IdType.TRADENO);
com.foxinmy.weixin4j.payment.mch.RefundResult result = PAY3 com.foxinmy.weixin4j.payment.mch.RefundResult result = PAY3
.refundApply(new FileInputStream(caFile), idQuery, "TT_R" .refundApply(new FileInputStream(caFile), idQuery, "TT_R"
@ -127,7 +125,8 @@ public class PayTest {
System.err.println(result); System.err.println(result);
String sign = result.getSign(); String sign = result.getSign();
result.setSign(null); result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign)); .println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign); Assert.assertEquals(valiSign, sign);
@ -154,7 +153,8 @@ public class PayTest {
System.err.println(result); System.err.println(result);
String sign = result.getSign(); String sign = result.getSign();
result.setSign(null); result.setSign(null);
String valiSign = DigestUtil.paysignMd5(result, ACCOUNT3.getPaySignKey()); String valiSign = DigestUtil.paysignMd5(result,
ACCOUNT3.getPaySignKey());
System.err System.err
.println(String.format("sign=%s,valiSign=%s", sign, valiSign)); .println(String.format("sign=%s,valiSign=%s", sign, valiSign));
Assert.assertEquals(valiSign, sign); Assert.assertEquals(valiSign, sign);

View File

@ -29,19 +29,23 @@ 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)); File file = qrApi.createQRFile(QRParameter.createTemporary(1200, 1200),
"/tmp/weixin4j/qrcode");
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.createQRFile(QRParameter.createPermanenceInt(2)); File file = qrApi.createQRFile(QRParameter.createPermanenceInt(2),
"/tmp/weixin4j/qrcode");
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.createQRFile(QRParameter.createPermanenceStr("1200中文")); File file = qrApi.createQRFile(
QRParameter.createPermanenceStr("1200中文"),
"/tmp/weixin4j/qrcode");
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }
} }

View File

@ -168,3 +168,7 @@
* 2016-01-23 * 2016-01-23
+ 新增获取客服列表接口 + 新增获取客服列表接口
* 2016-01-26
+ 新增上传图文消息内的图片接口

View File

@ -25,13 +25,13 @@ weixin4j-qy
* PartyApi `部门管理API` * PartyApi `部门管理API`
* ProviderApi `服务商API` * ProviderApi `服务商API`
* SuiteApi `第三方应用API` * SuiteApi `第三方应用API`
* TagApi `标签管理API` * TagApi `标签管理API`
* UserApi `成员管理API` * UserApi `成员管理API`
如何使用 如何使用
@ -62,24 +62,31 @@ weixin4j.properties说明
weixin4j.account={"id":"corpid","secret":"corpsecret",\ weixin4j.account={"id":"corpid","secret":"corpsecret",\
"suites":[{"id":"应用套件的id","secret":"应用套件的secret"}],\ "suites":[{"id":"应用套件的id","secret":"应用套件的secret"}],\
"providerSecret:"第三方提供商secret(企业号登陆)",\ "providerSecret":"第三方提供商secret(企业号登陆)",\
"chatSecret":"消息服务secret(企业号消息服务,暂时没用到)"} "chatSecret":"消息服务secret(企业号消息服务,暂时没用到)",\
"mchId":"微信商户号 微信支付时需要填入",\
"certificateKey":"加载支付证书文件的密码 如果不填写则默认获取mchId作为密码",\
"paySignKey":"微信支付中调用API的密钥 微信支付时需要填入"}
# 使用FileTokenStorager时token的存放路径(如果不填则默认为Weixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token 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 weixin4j.media.path=/tmp/weixin4j/media
# 对账单保存路径(如果不填则默认为Weixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill weixin4j.bill.path=/tmp/weixin4j/bill
# ca证书存放的完整路径 (证书文件后缀为*.p12) # ca证书存放的完整路径
weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12 weixin4j.certificate.file=/tmp/weixin4j/xxxxx.p12
#classpath路径下:weixin4j.certificate.file=classpath:xxxxx.p12 # classpath路径下可以这么写(如果不填则默认为Weixin4jConst#DEFAULT_CAFILE_PATH)
# weixin4j.certificate.file=classpath:xxxxx.pfx
#企业号用户身份授权后重定向的url(使用OauthApi时需要填写) # 企业号用户身份授权后重定向的url(在使用OauthApi时填写)
weixin4j.user.oauth.redirect.uri=http://xxx weixin4j.user.oauth.redirect.uri=
# 企业号第三方提供商授权后重定向的url(在使用OauthApi时填写)
#企业号第三方管理员授权后重定向的url(使用OauthApi时需要填写) weixin4j.third.oauth.redirect.uri=
weixin4j.third.oauth.redirect.uri=http://xxx # 企业号第三方应用套件授权后重定向的url(在使用OauthApi时填写)
weixin4j.suite.oauth.redirect.uri=
#企业号第三方应用套件授权后重定向的url(使用OauthApi时需要填写)
weixin4j.suite.oauth.redirect.uri=http://xxx
2.实例化微信企业号接口代理对象,调用具体的API方法 2.实例化微信企业号接口代理对象,调用具体的API方法

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.foxinmy</groupId> <groupId>com.foxinmy</groupId>
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>1.6.6</version> <version>1.6.7</version>
</parent> </parent>
<artifactId>weixin4j-qy</artifactId> <artifactId>weixin4j-qy</artifactId>
<name>weixin4j-qy</name> <name>weixin4j-qy</name>

View File

@ -14,6 +14,7 @@ import com.foxinmy.weixin4j.model.MediaItem;
import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.MediaRecord;
import com.foxinmy.weixin4j.model.MediaUploadResult; import com.foxinmy.weixin4j.model.MediaUploadResult;
import com.foxinmy.weixin4j.model.Pageable; import com.foxinmy.weixin4j.model.Pageable;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.qy.api.AgentApi; import com.foxinmy.weixin4j.qy.api.AgentApi;
import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.BatchApi;
import com.foxinmy.weixin4j.qy.api.ChatApi; import com.foxinmy.weixin4j.qy.api.ChatApi;
@ -22,7 +23,6 @@ import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.qy.api.MenuApi; import com.foxinmy.weixin4j.qy.api.MenuApi;
import com.foxinmy.weixin4j.qy.api.NotifyApi; import com.foxinmy.weixin4j.qy.api.NotifyApi;
import com.foxinmy.weixin4j.qy.api.PartyApi; import com.foxinmy.weixin4j.qy.api.PartyApi;
import com.foxinmy.weixin4j.qy.api.QyApi;
import com.foxinmy.weixin4j.qy.api.TagApi; import com.foxinmy.weixin4j.qy.api.TagApi;
import com.foxinmy.weixin4j.qy.api.UserApi; import com.foxinmy.weixin4j.qy.api.UserApi;
import com.foxinmy.weixin4j.qy.message.ChatMessage; import com.foxinmy.weixin4j.qy.message.ChatMessage;
@ -47,6 +47,7 @@ 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.token.TokenStorager; import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
@ -76,50 +77,27 @@ public class WeixinProxy {
private final ChatApi chatApi; private final ChatApi chatApi;
private final TokenHolder tokenHolder; private final TokenHolder tokenHolder;
private String corpId;
private Weixin4jSettings settings;
/** /**
* 默认使用文件方式保存token使用weixin4j.properties配置的账号信息 * 默认使用文件方式保存token使用weixin4j.properties配置的账号信息
*/ */
public WeixinProxy() { public WeixinProxy() {
this(QyApi.DEFAULT_TOKEN_STORAGER); this(new Weixin4jSettings());
}
/**
* 默认使用weixin4j.properties配置的账号信息
*
* @param tokenStorager
* token存储策略
*/
public WeixinProxy(TokenStorager tokenStorager) {
this(QyApi.DEFAULT_WEIXIN_ACCOUNT.getId(), QyApi.DEFAULT_WEIXIN_ACCOUNT
.getSecret(), tokenStorager);
}
/**
* corpid,corpsecret
*
* @param corpid
* @param corpsecret
*/
public WeixinProxy(String corpid, String corpsecret) {
this(corpid, corpsecret, QyApi.DEFAULT_TOKEN_STORAGER);
} }
/** /**
* *
* @param corpid * @param settings
* 企业号ID * 配置信息
* @param corpsecret * @see com.foxinmy.weixin4j.settings.Weixin4jSettings
* 企业号secret
* @param tokenStorager
* 企业号token存储器
*/ */
public WeixinProxy(String corpid, String corpsecret, public WeixinProxy(Weixin4jSettings settings) {
TokenStorager tokenStorager) { this(new TokenHolder(new WeixinTokenCreator(settings.getAccount()
this(new TokenHolder(new WeixinTokenCreator(corpid, corpsecret), .getId(), settings.getAccount().getSecret()),
tokenStorager)); settings.getTokenStorager()));
this.corpId = corpid; this.settings = settings;
} }
/** /**
@ -133,7 +111,7 @@ public class WeixinProxy {
public WeixinProxy(WeixinTokenSuiteCreator tokenCreator, public WeixinProxy(WeixinTokenSuiteCreator tokenCreator,
TokenStorager tokenStorager) { TokenStorager tokenStorager) {
this(new TokenHolder(tokenCreator, tokenStorager)); this(new TokenHolder(tokenCreator, tokenStorager));
this.corpId = tokenCreator.getAuthCorpId(); this.settings = new Weixin4jSettings(tokenCreator.getAuthCorpId(), null);
} }
/** /**
@ -167,12 +145,12 @@ public class WeixinProxy {
} }
/** /**
* 企业号ID * 获取微信账号信息
* *
* @return * @return
*/ */
public String getCorpId() { public WeixinAccount getWeixinAccount() {
return this.corpId; return this.settings.getAccount();
} }
/** /**
@ -183,8 +161,9 @@ public class WeixinProxy {
* @return * @return
*/ */
public TokenHolder getTicketHolder(TicketType ticketType) { public TokenHolder getTicketHolder(TicketType ticketType) {
return new TokenHolder(new WeixinTicketCreator(this.corpId, ticketType, return new TokenHolder(new WeixinTicketCreator(getWeixinAccount()
this.tokenHolder), this.tokenHolder.getTokenStorager()); .getId(), ticketType, this.tokenHolder),
this.tokenHolder.getTokenStorager());
} }
/** /**
@ -312,6 +291,25 @@ public class WeixinProxy {
return menuApi.deleteMenu(agentid); return menuApi.deleteMenu(agentid);
} }
/**
* 上传图文消息内的图片:用于上传图片到企业号服务端接口返回图片url请注意该url仅可用于图文消息的发送
* 且每个企业每天最多只能上传100张图片
*
* @param is
* 图片数据
* @param fileName
* 文件名
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E5%9B%BE%E6%96%87%E6%B6%88%E6%81%AF%E5%86%85%E7%9A%84%E5%9B%BE%E7%89%87">上传图文消息内的图片</a>
* @return 图片url
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @throws WeixinException
*/
public String uploadImage(InputStream is, String fileName)
throws WeixinException {
return mediaApi.uploadImage(is, fileName);
}
/** /**
* 上传媒体文件 * 上传媒体文件
* <p> * <p>
@ -348,7 +346,7 @@ public class WeixinProxy {
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>) * 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @return 写入硬盘后的文件对象
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MediaApi * @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
@ -356,7 +354,8 @@ public class WeixinProxy {
*/ */
public File downloadMediaFile(int agentid, String mediaId) public File downloadMediaFile(int agentid, String mediaId)
throws WeixinException { throws WeixinException {
return mediaApi.downloadMediaFile(agentid, mediaId); return mediaApi.downloadMediaFile(agentid, mediaId,
settings.getMediaPath());
} }
/** /**
@ -1334,5 +1333,5 @@ public class WeixinProxy {
return chatApi.sendChatMessage(message); return chatApi.sendChatMessage(message);
} }
public final static String VERSION = "1.6.6"; public final static String VERSION = "1.6.7";
} }

View File

@ -3,19 +3,22 @@ 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;
import com.foxinmy.weixin4j.qy.api.QyApi;
import com.foxinmy.weixin4j.qy.api.SuiteApi; 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.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.token.TokenStorager;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
* 微信第三方应用接口实现 * 微信第三方应用接口实现
@ -34,20 +37,16 @@ public class WeixinSuiteProxy {
private ProviderApi providerApi; private ProviderApi providerApi;
public WeixinSuiteProxy() { public WeixinSuiteProxy() {
this(QyApi.DEFAULT_TOKEN_STORAGER); this(Weixin4jSettings.DEFAULT_TOKEN_PATH);
} }
/** /**
* *
* @param suiteId * @param tokenPath
* 应用ID * 使用文件存储token的保存路径
* @param suiteSecret
* 应用secret
* @throws WeixinException
*/ */
public WeixinSuiteProxy(String suiteId, String suiteSecret) { public WeixinSuiteProxy(String tokenPath) {
this(QyApi.DEFAULT_TOKEN_STORAGER, null, null, new WeixinAccount( this(new FileTokenStorager(tokenPath));
suiteId, suiteSecret));
} }
/** /**
@ -56,7 +55,8 @@ public class WeixinSuiteProxy {
* token存储 * token存储
*/ */
public WeixinSuiteProxy(TokenStorager tokenStorager) { public WeixinSuiteProxy(TokenStorager tokenStorager) {
this(tokenStorager, QyApi.DEFAULT_WEIXIN_ACCOUNT); this(tokenStorager, JSON.parseObject(
Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class));
} }
/** /**
@ -76,14 +76,14 @@ public class WeixinSuiteProxy {
* *
* @param tokenStorager * @param tokenStorager
* token存储 * token存储
* @param corpId * @param providerCorpId
* 服务商的企业号ID <font color="red">使用服务商API时必填项</font> * 服务商的企业号ID <font color="red">使用服务商API时必填项</font>
* @param providerSecret * @param providerSecret
* 服务商secret <font color="red">使用服务商API时必填项</font> * 服务商secret <font color="red">使用服务商API时必填项</font>
* @param suites * @param suites
* 套件信息 <font color="red">使用套件API时必填项</font> * 套件信息 <font color="red">使用套件API时必填项</font>
*/ */
public WeixinSuiteProxy(TokenStorager tokenStorager, String corpId, public WeixinSuiteProxy(TokenStorager tokenStorager, String providerCorpId,
String providerSecret, WeixinAccount... suites) { String providerSecret, WeixinAccount... suites) {
if (suites != null) { if (suites != null) {
this.suiteMap = new HashMap<String, SuiteApi>(); this.suiteMap = new HashMap<String, SuiteApi>();
@ -94,11 +94,11 @@ public class WeixinSuiteProxy {
this.suiteMap.put(null, suiteMap.get(suites[0].getId())); this.suiteMap.put(null, suiteMap.get(suites[0].getId()));
} }
} }
if (StringUtil.isNotBlank(corpId) if (StringUtil.isNotBlank(providerCorpId)
&& StringUtil.isNotBlank(providerSecret)) { && StringUtil.isNotBlank(providerSecret)) {
this.providerApi = new ProviderApi(new TokenHolder( this.providerApi = new ProviderApi(new TokenHolder(
new WeixinProviderTokenCreator(corpId, providerSecret), new WeixinProviderTokenCreator(providerCorpId,
tokenStorager)); providerSecret), tokenStorager));
} }
} }
@ -160,5 +160,5 @@ public class WeixinSuiteProxy {
return providerApi.getLoginUrl(corpId, targetType, agentId); return providerApi.getLoginUrl(corpId, targetType, agentId);
} }
public final static String VERSION = "1.6.6"; public final static String VERSION = "1.6.7";
} }

View File

@ -51,8 +51,6 @@ import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.ObjectId;
import com.foxinmy.weixin4j.util.RegexUtil; import com.foxinmy.weixin4j.util.RegexUtil;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
import com.foxinmy.weixin4j.util.WeixinErrorUtil; import com.foxinmy.weixin4j.util.WeixinErrorUtil;
/** /**
@ -199,17 +197,17 @@ public class MediaApi extends QyApi {
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>) * 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @param mediaPath
* 媒体素材保存路径
* @return 写入硬盘后的文件对象
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
* @see {@link #downloadMedia(int,String)} * @see {@link #downloadMedia(int,String)}
*/ */
public File downloadMediaFile(int agentid, String mediaId) public File downloadMediaFile(int agentid, String mediaId, String mediaPath)
throws WeixinException { throws WeixinException {
String media_path = Weixin4jConfigUtil.getValue("media.path",
Weixin4jConst.DEFAULT_MEDIA_PATH);
final String prefixName = String.format("%d_%s.", agentid, mediaId); final String prefixName = String.format("%d_%s.", agentid, mediaId);
File[] files = new File(media_path).listFiles(new FilenameFilter() { File[] files = new File(mediaPath).listFiles(new FilenameFilter() {
@Override @Override
public boolean accept(File dir, String name) { public boolean accept(File dir, String name) {
return name.startsWith(prefixName); return name.startsWith(prefixName);
@ -219,7 +217,7 @@ public class MediaApi extends QyApi {
return files[0]; return files[0];
} }
MediaDownloadResult result = downloadMedia(agentid, mediaId); MediaDownloadResult result = downloadMedia(agentid, mediaId);
File file = new File(media_path + File.separator + result.getFileName()); File file = new File(mediaPath + File.separator + result.getFileName());
OutputStream os = null; OutputStream os = null;
try { try {
if (file.createNewFile()) { if (file.createNewFile()) {

View File

@ -4,6 +4,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Consts;
import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil; import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
@ -21,6 +22,15 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E6%8E%88%E6%9D%83">企业号第三方套件应用授权说明</a> * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E6%8E%88%E6%9D%83">企业号第三方套件应用授权说明</a>
*/ */
public class OauthApi extends QyApi { public class OauthApi extends QyApi {
private final WeixinAccount account;
public OauthApi() {
this(Weixin4jConfigUtil.getWeixinAccount());
}
public OauthApi(WeixinAccount account) {
this.account = account;
}
/** /**
* 企业号用户身份授权 * 企业号用户身份授权
@ -30,7 +40,7 @@ public class OauthApi extends QyApi {
* @return 请求授权的URL * @return 请求授权的URL
*/ */
public String getUserAuthorizeURL() { public String getUserAuthorizeURL() {
String corpId = DEFAULT_WEIXIN_ACCOUNT.getId(); String corpId = account.getId();
String redirectUri = Weixin4jConfigUtil String redirectUri = Weixin4jConfigUtil
.getValue("user.oauth.redirect.uri"); .getValue("user.oauth.redirect.uri");
return getUserAuthorizeURL(corpId, redirectUri, "state"); return getUserAuthorizeURL(corpId, redirectUri, "state");
@ -69,7 +79,7 @@ public class OauthApi extends QyApi {
* @return 请求授权的URL * @return 请求授权的URL
*/ */
public String getThirdAuthorizeURL() { public String getThirdAuthorizeURL() {
String corpId = DEFAULT_WEIXIN_ACCOUNT.getId(); String corpId = account.getId();
String redirectUri = Weixin4jConfigUtil String redirectUri = Weixin4jConfigUtil
.getValue("third.oauth.redirect.uri"); .getValue("third.oauth.redirect.uri");
return getThirdAuthorizeURL(corpId, redirectUri, "state"); return getThirdAuthorizeURL(corpId, redirectUri, "state");

View File

@ -2,10 +2,7 @@ package com.foxinmy.weixin4j.qy.api;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.api.BaseApi; import com.foxinmy.weixin4j.api.BaseApi;
import com.foxinmy.weixin4j.qy.model.WeixinQyAccount;
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
/** /**
* 微信企业号API * 微信企业号API
@ -20,16 +17,9 @@ import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
public class QyApi extends BaseApi { public class QyApi extends BaseApi {
private final static ResourceBundle WEIXIN_BUNDLE; private final static ResourceBundle WEIXIN_BUNDLE;
/**
* 默认使用weixin4j.properties文件中的企业号信息
*/
public final static WeixinQyAccount DEFAULT_WEIXIN_ACCOUNT;
static { static {
WEIXIN_BUNDLE = ResourceBundle WEIXIN_BUNDLE = ResourceBundle
.getBundle("com/foxinmy/weixin4j/qy/api/weixin"); .getBundle("com/foxinmy/weixin4j/qy/api/weixin");
DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject(
Weixin4jConfigUtil.getValue("account"), WeixinQyAccount.class);
} }
@Override @Override

View File

@ -47,9 +47,6 @@ public class SuiteApi extends QyApi {
* *
* @param suiteTicketHolder * @param suiteTicketHolder
* 套件ticket存取 * 套件ticket存取
* @param tokenStorager
* 应用token存储器
* @throws WeixinException
*/ */
public SuiteApi(SuiteTicketHolder suiteTicketHolder) { public SuiteApi(SuiteTicketHolder suiteTicketHolder) {
this.suiteTicketHolder = suiteTicketHolder; this.suiteTicketHolder = suiteTicketHolder;

View File

@ -1,26 +1,29 @@
# \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
weixin4j.account={"id":"id","secret":"secret",\ 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)",\
"chatSecret":"\u6d88\u606f\u670d\u52a1secret(\u4f01\u4e1a\u53f7\u6d88\u606f\u670d\u52a1,\u6682\u65f6\u6ca1\u7528\u5230)"} "chatSecret":"\u6d88\u606f\u670d\u52a1secret(\u4f01\u4e1a\u53f7\u6d88\u606f\u670d\u52a1,\u6682\u65f6\u6ca1\u7528\u5230)",\
"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",\
"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 # \u4f7f\u7528FileTokenStorager\u65f6token\u7684\u5b58\u653e\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_TOKEN_PATH)
weixin4j.token.path=/tmp/weixin4j/token weixin4j.token.path=/tmp/weixin4j/token
# \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84 # \u5a92\u4f53\u6587\u4ef6\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_MEDIA_PATH)
weixin4j.media.path=/tmp/weixin4j/media weixin4j.media.path=/tmp/weixin4j/media
# \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84 # \u5bf9\u8d26\u5355\u4fdd\u5b58\u8def\u5f84(\u5982\u679c\u4e0d\u586b\u5219\u9ed8\u8ba4\u4e3aWeixin4jConst#DEFAULT_BILL_PATH)
weixin4j.bill.path=/tmp/weixin4j/bill weixin4j.bill.path=/tmp/weixin4j/bill
# ca\u8bc1\u4e66\u5b58\u653e\u7684\u5b8c\u6574\u8def\u5f84 (V2\u7248\u672c\u540e\u7f00\u4e3a*.pfx,V3\u7248\u672c\u540e\u7f00\u4e3a*.p12) # 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 # 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 # weixin4j.certificate.file=classpath:xxxxx.pfx
# \u4f01\u4e1a\u53f7\u7528\u6237\u8eab\u4efd\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url # \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=
# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url # \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u63d0\u4f9b\u5546\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199)
weixin4j.third.oauth.redirect.uri= weixin4j.third.oauth.redirect.uri=
# \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url # \u4f01\u4e1a\u53f7\u7b2c\u4e09\u65b9\u5e94\u7528\u5957\u4ef6\u6388\u6743\u540e\u91cd\u5b9a\u5411\u7684url(\u5728\u4f7f\u7528OauthApi\u65f6\u586b\u5199)
weixin4j.suite.oauth.redirect.uri= weixin4j.suite.oauth.redirect.uri=

View File

@ -47,7 +47,8 @@ public class MediaTest extends TokenTest {
File file = mediaApi File file = mediaApi
.downloadMediaFile( .downloadMediaFile(
0, 0,
"1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw"); "1y0NWE5ochkfOoiyJsPwQ3Wg7gsyRHNp8SveqhGXY_1rOH7OcOMwfHDg8KH6s88osq59AfS3BX-MBBKvERB7Bvw",
"/tmp/weixin4j/media");
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }

View File

@ -28,8 +28,8 @@ public class TokenTest {
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( new FileTokenStorager(Weixin4jConfigUtil.getValue("token.path",
"token.path", "/tmp/weixin4j/token"))); "/tmp/weixin4j/token")));
} }
@Test @Test

View File

@ -5,10 +5,10 @@
<parent> <parent>
<groupId>com.foxinmy</groupId> <groupId>com.foxinmy</groupId>
<artifactId>weixin4j</artifactId> <artifactId>weixin4j</artifactId>
<version>1.6.6</version> <version>1.6.7</version>
</parent> </parent>
<artifactId>weixin4j-server</artifactId> <artifactId>weixin4j-server</artifactId>
<version>1.1.5</version> <version>1.1.6</version>
<name>weixin4j-server</name> <name>weixin4j-server</name>
<url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-server</url> <url>https://github.com/foxinmy/weixin4j/tree/master/weixin4j-server</url>
<description>微信消息netty服务器</description> <description>微信消息netty服务器</description>

View File

@ -315,5 +315,5 @@ public final class WeixinServerBootstrap {
return this; return this;
} }
public final static String VERSION = "1.1.5"; public final static String VERSION = "1.1.6";
} }