Browse Source

微信支付代码

huangct 8 years ago
parent
commit
ee55a788b3

+ 44 - 0
donate-service/src/main/java/com/uas/service/donate/WxPayConfiguration.java

@@ -0,0 +1,44 @@
+package com.uas.service.donate;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ConditionalOnClass(WxPayService.class)
+@EnableConfigurationProperties(WxPayProperties.class)
+public class WxPayConfiguration {
+    @Autowired
+    private WxPayProperties properties;
+
+    @Bean
+    @ConditionalOnMissingBean
+    public WxPayConfig config() {
+        WxPayConfig payConfig = new WxPayConfig();
+        payConfig.setAppId(this.properties.getAppId());
+        payConfig.setMchId(this.properties.getMchId());
+        payConfig.setMchKey(this.properties.getMchKey());
+        payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
+        payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
+        payConfig.setKeyPath(this.properties.getKeyPath());
+        payConfig.setNotifyUrl(this.properties.getNotifyURL());
+
+        return payConfig;
+    }
+
+    @Bean
+    //@ConditionalOnMissingBean
+    public WxPayService wxPayService(WxPayConfig payConfig) {
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+        return wxPayService;
+    }
+
+}

+ 110 - 0
donate-service/src/main/java/com/uas/service/donate/WxPayProperties.java

@@ -0,0 +1,110 @@
+package com.uas.service.donate;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * wxpay pay properties
+ *
+ * @author huangct
+ */
+@ConfigurationProperties(locations = "classpath:config/wechat.properties", prefix = "pay")
+public class WxPayProperties {
+    /**
+     * 设置微信公众号的appid
+     */
+    private String appId;
+
+    /**
+     * 微信支付商户号
+     */
+    private String mchId;
+
+    /**
+     * 微信支付商户密钥
+     */
+    private String mchKey;
+
+    /**
+     * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
+     */
+    private String subAppId;
+
+    /**
+     * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
+     */
+    private String subMchId;
+
+    /**
+     * apiclient_cert.p12的文件的绝对路径
+     */
+    private String keyPath;
+
+    /**
+     * 微信异步通知路径
+     */
+    private String notifyURL;
+
+    public String getAppId() {
+        return this.appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getMchId() {
+        return mchId;
+    }
+
+    public void setMchId(String mchId) {
+        this.mchId = mchId;
+    }
+
+    public String getMchKey() {
+        return mchKey;
+    }
+
+    public void setMchKey(String mchKey) {
+        this.mchKey = mchKey;
+    }
+
+    public String getSubAppId() {
+        return subAppId;
+    }
+
+    public void setSubAppId(String subAppId) {
+        this.subAppId = subAppId;
+    }
+
+    public String getSubMchId() {
+        return subMchId;
+    }
+
+    public void setSubMchId(String subMchId) {
+        this.subMchId = subMchId;
+    }
+
+    public String getKeyPath() {
+        return this.keyPath;
+    }
+
+    public void setKeyPath(String keyPath) {
+        this.keyPath = keyPath;
+    }
+
+    public String getNotifyURL() {
+        return notifyURL;
+    }
+
+    public void setNotifyURL(String notifyURL) {
+        this.notifyURL = notifyURL;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringBuilder.reflectionToString(this,
+                ToStringStyle.MULTI_LINE_STYLE);
+    }
+}

+ 447 - 0
donate-service/src/main/java/com/uas/service/donate/api/WxPayApi.java

@@ -0,0 +1,447 @@
+package com.uas.service.donate.api;
+
+import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.bean.coupon.*;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
+import com.github.binarywang.wxpay.bean.request.*;
+import com.github.binarywang.wxpay.bean.result.*;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.util.Date;
+import java.util.Map;
+
+
+/**
+ * <pre>
+ *  注意此controller类实现接口WxPayService(implements WxPayService ),
+ *  仅是为了方便演示所有接口的使用,以免漏掉某一个新增加的接口,实际使用时无需如此实现。
+ *  </pre>
+ *
+ * @author Binary Wang
+ */
+@Service
+public class WxPayApi implements WxPayService{
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Resource(name = "wxPayService")
+    private WxPayService wxPayService;
+
+    /**
+     * <pre>
+     * 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
+     * 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
+     * 需要调用查询接口的情况:
+     * ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
+     * ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
+     * ◆ 调用被扫支付API,返回USERPAYING的状态;
+     * ◆ 调用关单或撤销接口API之前,需确认支付状态;
+     * 接口地址:https://api.mch.weixin.qq.com/pay/orderquery
+     * </pre>
+     *
+     * @param transactionId 微信订单号 required = false
+     * @param outTradeNo    商户系统内部的订单号,当没提供transactionId时需要传这个。 required = false
+     */
+    @Override
+    public WxPayOrderQueryResult queryOrder(String transactionId,String outTradeNo)
+            throws WxPayException {
+        return this.wxPayService.queryOrder(transactionId, outTradeNo);
+    }
+
+    /**
+     * <pre>
+     * 关闭订单
+     * 应用场景
+     * 以下情况需要调用关单接口:
+     * 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
+     * 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
+     * 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。
+     * 接口地址:https://api.mch.weixin.qq.com/pay/closeorder
+     * 是否需要证书:   不需要。
+     * </pre>
+     *
+     * @param outTradeNo 商户系统内部的订单号
+     */
+    @Override
+    public WxPayOrderCloseResult closeOrder(String outTradeNo) {
+        try {
+            WxPayOrderCloseResult orderCloseResult = this.wxPayService.closeOrder(outTradeNo);
+            return orderCloseResult;
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    @Override
+    public <T> T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
+        return this.wxPayService.createOrder(request);
+    }
+
+    /**
+     * 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
+     * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
+     * 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
+     *
+     * @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
+     */
+    @Override
+    public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException {
+        return this.wxPayService.unifiedOrder(request);
+    }
+
+    /**
+     * 不建议使用
+     */
+    @Override
+    @Deprecated
+    public Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException {
+        return null;
+    }
+
+    /**
+     * <pre>
+     * 微信支付-申请退款
+     * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
+     * 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund
+     * </pre>
+     *
+     * @param request 请求对象
+     * @return 退款操作结果
+     */
+    @Override
+    public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException {
+        return this.wxPayService.refund(request);
+    }
+
+    /**
+     * <pre>
+     * 微信支付-查询退款
+     * 应用场景:
+     *  提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,
+     *  银行卡支付的退款3个工作日后重新查询退款状态。
+     * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
+     * 接口链接:https://api.mch.weixin.qq.com/pay/refundquery
+     * </pre>
+     * 以下四个参数四选一
+     *
+     * @param transactionId 微信订单号 required = false
+     * @param outTradeNo    商户订单号 required = false
+     * @param outRefundNo   商户退款单号 required = false
+     * @param refundId      微信退款单号 required = false
+     * @return 退款信息
+     */
+    @Override
+    public WxPayRefundQueryResult refundQuery(String transactionId,String outTradeNo,String outRefundNo,String refundId)
+            throws WxPayException {
+        return this.wxPayService.refundQuery(transactionId, outTradeNo, outRefundNo, refundId);
+    }
+
+    /**
+     * 异步通知 huangct
+     * @param xmlData
+     * @return
+     * @throws WxPayException
+     */
+    @Override
+    @Deprecated
+    public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxPayException {
+        return this.wxPayService.getOrderNotifyResult(xmlData);
+    }
+
+    /**
+     * 此方法需要改造,根据实际需要返回com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse对象
+     */
+    @Override
+    public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException {
+        return this.wxPayService.parseOrderNotifyResult(xmlData);
+    }
+
+    /**
+     * 此方法需要改造,根据实际需要返回com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse对象
+     */
+    @Override
+    public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException {
+        return this.wxPayService.parseRefundNotifyResult(xmlData);
+    }
+
+    /**
+     * 发送微信红包给个人用户
+     * <pre>
+     * 文档详见:
+     * 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
+     *  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
+     * 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
+     *  接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
+     * </pre>
+     *
+     * @param request 请求对象
+     */
+    @Override
+    public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxPayException {
+        return this.wxPayService.sendRedpack(request);
+    }
+
+    /**
+     * <pre>
+     *   查询红包记录
+     *   用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
+     *   请求Url	https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
+     *   是否需要证书	是(证书及使用说明详见商户证书)
+     *   请求方式	POST
+     * </pre>
+     *
+     * @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
+     */
+    @Override
+    public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException {
+        return this.wxPayService.queryRedpack(mchBillNo);
+    }
+
+    /**
+     * <pre>
+     * 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
+     * 比如目前的保险行业向客户退保、给付、理赔。
+     * 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
+     * 注意:与商户微信支付收款资金并非同一账户,需要单独充值。
+     * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
+     * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
+     * </pre>
+     *
+     * @param request 请求对象
+     */
+    @Override
+    public WxEntPayResult entPay(WxEntPayRequest request) throws WxPayException {
+        return this.wxPayService.entPay(request);
+    }
+
+    /**
+     * <pre>
+     * 查询企业付款API
+     * 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。
+     * 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
+     * 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
+     * </pre>
+     *
+     * @param partnerTradeNo 商户订单号
+     */
+    @Override
+    public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxPayException {
+        return this.wxPayService.queryEntPay(partnerTradeNo);
+    }
+
+    /**
+     * <pre>
+     * 扫码支付模式一生成二维码的方法
+     * 二维码中的内容为链接,形式为:
+     * weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
+     * 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
+     * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
+     * </pre>
+     *
+     * @param productId  产品Id
+     * @param logoFile   商户logo图片的文件对象,可以为空
+     * @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
+     * @return 生成的二维码的字节数组
+     */
+    @Override
+    public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) {
+        return this.wxPayService.createScanPayQrcodeMode1(productId, logoFile, sideLength);
+    }
+
+    /**
+     * <pre>
+     * 扫码支付模式一生成二维码的方法
+     * 二维码中的内容为链接,形式为:
+     * weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
+     * 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
+     * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
+     * </pre>
+     *
+     * @param productId 产品Id
+     * @return 生成的二维码URL连接
+     */
+    @Override
+    public String createScanPayQrcodeMode1(String productId) {
+        return this.wxPayService.createScanPayQrcodeMode1(productId);
+    }
+
+    /**
+     * <pre>
+     * 扫码支付模式二生成二维码的方法
+     * 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
+     * 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
+     * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
+     * </pre>
+     *
+     * @param codeUrl    微信返回的交易会话的二维码链接
+     * @param logoFile   商户logo图片的文件对象,可以为空
+     * @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
+     * @return 生成的二维码的字节数组
+     */
+    @Override
+    public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) {
+        return this.wxPayService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);
+    }
+
+    /**
+     * <pre>
+     * 交易保障
+     * 应用场景:
+     *  商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
+     *  为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
+     *  微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
+     * 接口地址: https://api.mch.weixin.qq.com/payitil/report
+     * 是否需要证书:不需要
+     * </pre>
+     *
+     * @param request
+     */
+    @Override
+    public void report(WxPayReportRequest request) throws WxPayException {
+        this.wxPayService.report(request);
+    }
+
+    /**
+     * <pre>
+     * 下载对账单
+     * 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
+     * 注意:
+     * 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
+     * 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
+     * 3、对账单中涉及金额的字段单位为“元”。
+     * 4、对账单接口只能下载三个月以内的账单。
+     * 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
+     * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
+     * </pre>
+     *
+     * @param billDate   对账单日期 bill_date	下载对账单的日期,格式:20140603
+     * @param billType   账单类型	bill_type	ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单
+     * @param tarType    压缩账单	tar_type	非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
+     * @param deviceInfo 设备号	device_info	非必传参数,终端设备号
+     * @return 保存到本地的临时文件
+     */
+    @Override
+    public WxPayBillResult downloadBill(String billDate,String billType,String tarType,String deviceInfo) throws WxPayException {
+        return this.wxPayService.downloadBill(billDate, billType, tarType, deviceInfo);
+    }
+
+    /**
+     * <pre>
+     * 提交刷卡支付
+     * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
+     * 应用场景:
+     * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。
+     * 提醒1:提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议30秒);
+     * 提醒2:在调用查询接口返回后,如果交易状况不明晰,请调用【撤销订单API】,此时如果交易失败则关闭订单,该单不能再支付成功;如果交易成功,则将扣款退回到用户账户。当撤销无返回或错误时,请再次调用。注意:请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。
+     * 接口地址:   https://api.mch.weixin.qq.com/pay/micropay
+     * 是否需要证书:不需要。
+     * </pre>
+     */
+    @Override
+    public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException {
+        return this.wxPayService.micropay(request);
+    }
+
+    /**
+     * <pre>
+     * 撤销订单API
+     * 文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
+     * 应用场景:
+     *  支付交易返回失败或支付系统超时,调用该接口撤销交易。如果此订单用户支付失败,微信支付系统会将此订单关闭;如果用户支付成功,微信支付系统会将此订单资金退还给用户。
+     *  注意:7天以内的交易单可调用撤销,其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】,没有明确的支付结果再调用【撤销订单API】。
+     *  调用支付接口后请勿立即调用撤销订单API,建议支付后至少15s后再调用撤销订单接口。
+     *  接口链接 :https://api.mch.weixin.qq.com/secapi/pay/reverse
+     *  是否需要证书:请求需要双向证书。
+     * </pre>
+     */
+    @Override
+    public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException {
+        return this.wxPayService.reverseOrder(request);
+    }
+
+    @Override
+    public String shorturl(WxPayShorturlRequest wxPayShorturlRequest) throws WxPayException {
+        //TODO 待补充完善
+        return null;
+    }
+
+    @Override
+    public String shorturl(String s) throws WxPayException {
+        //TODO 待补充完善
+        return null;
+    }
+
+    @Override
+    public String authcode2Openid(WxPayAuthcode2OpenidRequest wxPayAuthcode2OpenidRequest) throws WxPayException {
+        //TODO 待补充完善
+        return null;
+    }
+
+    @Override
+    public String authcode2Openid(String authCode) throws WxPayException {
+        //TODO 待补充完善
+        return wxPayService.authcode2Openid(authCode);
+    }
+
+    @Override
+    public String getSandboxSignKey() throws WxPayException {
+        return this.wxPayService.getSandboxSignKey();
+    }
+
+    @Override
+    public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request)
+            throws WxPayException {
+        return this.wxPayService.sendCoupon(request);
+    }
+
+    @Override
+    public WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request)
+            throws WxPayException {
+        return this.wxPayService.queryCouponStock(request);
+    }
+
+    @Override
+    public WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request)
+            throws WxPayException {
+        return this.wxPayService.queryCouponInfo(request);
+    }
+
+    /**
+     * 请忽略之
+     */
+    @Override
+    public WxPayApiData getWxApiData() {
+        return null;
+    }
+
+    @Override
+    public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {
+        return this.queryComment(beginDate, endDate, offset, limit);
+    }
+
+    /**
+     * 请忽略之
+     */
+    @Override
+    public WxPayConfig getConfig() {
+        return null;
+    }
+
+    /**
+     * 请忽略之
+     */
+    @Override
+    public void setConfig(WxPayConfig config) {
+
+    }
+}
+

+ 24 - 0
donate-service/src/main/java/com/uas/service/donate/config/WxConfig.java

@@ -0,0 +1,24 @@
+package com.uas.service.donate.config;
+
+/**
+ * Created by 黄诚天 on 2017-10-27.
+ */
+public class WxConfig {
+    //沙盒参数
+    public static String do_main = "http://5087452.nat123.cc";
+
+    //自己个人 wxe73df80d5c7a6ee8   自己公众号 wx59ebbd454c239e2d
+    public static String APPID = "wxbc1f8607137d3b8a";
+
+    //自己个人 6497c36255030cdfd5e0716928abda21   自己公众号 f76b0b47ba1190f75b1590f38d032a7b
+    public static String APPSECRET = "f76b0b47ba1190f75b1590f38d032a7b";
+
+    public static String notify_url = do_main + "/wxpay/notifyUrl";
+
+    public static String redirect_url = do_main + "/wxpay/redirectUrl";
+
+    public static String Token = "huangchengtian";
+
+    public static String encoding_aes_key = "bmSUBuzyzvfUYTw4GMKTHQmnaxj6SNf1JJ3Q1joFnGP";
+    //public static String encoding_aes_key = "34222222222222222f324e324324324324321431243";
+}

+ 11 - 8
donate-service/src/main/java/com/uas/service/donate/controller/AlipayController.java

@@ -16,7 +16,6 @@ import com.alipay.api.response.AlipaySystemOauthTokenResponse;
 import com.alipay.api.response.AlipayTradeAppPayResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
 import com.alipay.api.response.AlipayUserInfoShareResponse;
-import com.uas.platform.core.util.HttpUtil;
 import com.uas.platform.core.util.serializer.FlexJsonUtils;
 import com.uas.service.donate.DruidDBConfiguration;
 import com.uas.service.donate.api.AlipayApi;
@@ -459,16 +458,20 @@ public class AlipayController {
      */
     @ResponseBody
     @RequestMapping("/getUserInfo")
-    public String getUserInfo(HttpServletRequest request) throws Exception {
+    public void getUserInfo(HttpServletRequest request, HttpServletResponse response) throws Exception {
         //return  URLDecoder.decode("alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=2016081600255841&biz_content=%7B%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%2265F1DD5E612%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22App%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%95Java%22%2C%22timeout_express%22%3A%2230m%22%2C%22total_amount%22%3A%220.01%22%7D&charset=UTF-8&format=json&method=alipay.trade.app.pay&notify_url=%E5%95%86%E6%88%B7%E5%A4%96%E7%BD%91%E5%8F%AF%E4%BB%A5%E8%AE%BF%E9%97%AE%E7%9A%84%E5%BC%82%E6%AD%A5%E5%9C%B0%E5%9D%80&sign=C0sJ76k4KTnDVqnWRmnZQI%2FVVl9gX7OQaatNmFmCJ4TS%2Bm0aDBLCT2kAvAvBq%2FNaqcy5UAqEjhczTq0rOPCPwjjoWIOJ6jsRglasCp4THlCi3rCq4vmkou7zMQf1s1fd%2FqMwBgKkAa1PGs6gRcng2s01YMoZuf9fey3d4KGiUae95xtFoW8ngmr62DT8kyrndpUYw2n0B5SV0RufwdQnJdSaqgt26HJ0i%2BPQi4yZkLiy0IxhUcFlTvDpxERPVJO3sqEiGg0MB0r5e4yzStH%2FR047rOwxHOnF9COytaUWvCkBTPoKHJvMx32sFSlBotDQ%2BtzmLCNsSb6ab0B3weJMtQ%3D%3D&sign_type=RSA2&timestamp=2017-11-13+17%3A33%3A14&version=1.0\n", "UTF-8");
 
         String app_id = AlipayConfig.APPID;
-        String scope = "auth_base";
-        String redirect_uri = URLEncoder.encode(AlipayConfig.REDIRECT_URL, AlipayConfig.CHARSET);
-        String sandBoxUrl = "https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm?app_id=" + app_id + "&scope=" + scope + "&redirect_uri=" + redirect_uri;
-        String url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=" + app_id + "&scope=" + scope + "&redirect_uri=" + redirect_uri;
-        HttpUtil.Response response = HttpUtil.sendGetRequest(sandBoxUrl, null);
-        return new String(response.getResponseText().getBytes("gb2312"),"GBK");
+        String scope = "auth_user";
+        String redirect_url = URLEncoder.encode(AlipayConfig.REDIRECT_URL, AlipayConfig.CHARSET);
+        //String sandBoxUrl = "https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm?app_id=" + app_id + "&scope=" + scope + "&redirect_uri=" + redirect_url;
+        String url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=" + app_id + "&scope=" + scope + "&redirect_uri=" + redirect_url;
+
+        com.uas.sso.common.util.HttpUtil.ResponseWrap responseWrap = com.uas.sso.common.util.HttpUtil.doGet(url);
+        response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
+        response.getWriter().write(responseWrap.getContent());//直接将完整的表单html输出到页面
+        response.getWriter().flush();
+        response.getWriter().close();
     }
 
 

+ 470 - 0
donate-service/src/main/java/com/uas/service/donate/controller/WxpayController.java

@@ -0,0 +1,470 @@
+package com.uas.service.donate.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.util.SignUtils;
+import com.uas.platform.core.util.HttpUtil;
+import com.uas.service.donate.api.WxPayApi;
+import com.uas.service.donate.config.WxConfig;
+import com.uas.service.donate.model.ProjectRecode;
+import com.uas.service.donate.model.WechatOrder;
+import com.uas.service.donate.service.ProjectRecodeService;
+import com.uas.service.donate.service.WechatOrderService;
+import com.uas.service.donate.util.QrcodeUtils;
+import com.uas.service.donate.util.StringUtils;
+import com.uas.service.donate.util.WxCheckoutUtil;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URLEncoder;
+import java.util.Date;
+
+/**
+ * Created by 黄诚天 on 2017-10-27.
+ */
+@Controller
+@RequestMapping("/wxpay")
+public class WxpayController {
+
+    @Autowired
+    protected HttpServletRequest request;
+
+    @Autowired
+    protected HttpServletResponse response;
+
+    @Autowired
+    protected WxPayApi wxPayApi;
+
+    @Autowired
+    protected WechatOrderService wechatOrderService;
+
+    @Autowired
+    private ProjectRecodeService projectRecodeService;
+
+    private Logger logger = LoggerFactory.getLogger(WxpayController.class);
+    private static String redirectUrl = "http://5087452.nat123.cc/wxpay/redirectUrl";
+    //private String orderNumber = NumberGenerator.generateId();
+
+    /**
+     * 扫码支付 @RequestParam ProjectRecode projectRecode
+     * @param request
+     * @param response
+     * @throws Exception
+     */
+    @ResponseBody
+    @RequestMapping(value = "/pcPay", method = RequestMethod.POST)
+    public void pcPay(@RequestParam("jsonStr") String jsonStr, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        ProjectRecode projectRecode= null;
+        try {
+            projectRecode = this.createProjectRecode(jsonStr);
+        } catch (Exception e) {
+            response.getWriter().write(e.getMessage());
+            return;
+        }
+
+        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = createWxPayUnifiedOrderRequest(request, projectRecode, WxPayConstants.TradeType.NATIVE);
+        unifiedOrder(wxPayUnifiedOrderRequest);
+    }
+
+    /**
+     * 公众号支付 网页支付JSAPI即公众号支付是用户在微信中打开商户的H5页面
+     * https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
+     * @param request
+     * @param response
+     * @throws Exception
+     */
+    @ResponseBody
+    @RequestMapping(value = "/webPay", method = RequestMethod.POST)
+    public ModelMap appPay(@RequestParam("jsonStr") String jsonStr, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        ModelMap map = new ModelMap();
+
+        ProjectRecode projectRecode= null;
+        try {
+            projectRecode = this.createProjectRecode(jsonStr);
+        } catch (Exception e) {
+            response.getWriter().write(e.getMessage());
+            map.put("error", "参数错误");
+            return map;
+        }
+
+        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = createWxPayUnifiedOrderRequest(request, projectRecode, WxPayConstants.TradeType.JSAPI);
+
+        //配置网页授权url
+        String openId = getOpenId(request);
+        if (StringUtils.isEmpty(wxPayApi.getConfig().getSubAppId())) {
+            wxPayUnifiedOrderRequest.setOpenid(openId);//否是 trade_type=JSAPI,此参数必传,用户在主商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+        } else {
+            wxPayUnifiedOrderRequest.setSubOpenid(openId);//否是 trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+        }
+
+        String prepayId = unifiedOrder(wxPayUnifiedOrderRequest);
+        if (StringUtils.isEmpty(prepayId)) {
+            //TODO 预下单失败处理
+            map.put("error", "支付失败,请重试");
+        } else {
+            //TODO 将prepayId返回给js
+            map.put("appId", wxPayApi.getConfig().getAppId());
+            map.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
+            map.put("nonceStr", wxPayUnifiedOrderRequest.getNonceStr());//String.valueOf(System.currentTimeMillis()
+            map.put("package", "prepay_id=" + prepayId);
+            map.put("signType", "MD5");
+            //预付订单再次签名
+            String packageSign = SignUtils.createSign(map, WxPayConstants.SignType.MD5, wxPayApi.getConfig().getMchKey(), false);
+            map.put("paySign", packageSign);
+        }
+
+        return map;
+    }
+
+    /**
+     * H5支付   商户在微信客户端外的移动端网页
+     * https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4  应让用户去点击按钮触发查单操作
+     * @param request
+     * @param response
+     * @throws Exception
+     */
+    @ResponseBody
+    @RequestMapping(value = "/wapPay", method = RequestMethod.POST)
+    public ModelMap wapPay(@RequestParam("jsonStr") String jsonStr, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        ModelMap map = new ModelMap();
+
+        ProjectRecode projectRecode= null;
+        try {
+            projectRecode = this.createProjectRecode(jsonStr);
+        } catch (Exception e) {
+            response.getWriter().write(e.getMessage());
+            map.put("error", "参数错误");
+            return map;
+        }
+
+        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = createWxPayUnifiedOrderRequest(request, projectRecode, WxPayConstants.TradeType.MWEB);
+        String mwebUrl = unifiedOrder(wxPayUnifiedOrderRequest);
+        if (StringUtils.isEmpty(mwebUrl)) {
+            //TODO 预下单失败处理
+            map.put("error", "支付失败,请重试");
+        } else {
+            map.put("mwebUrl", mwebUrl); //通过mweb_url调起微信支付中间页  重定向mweb_url
+        }
+
+        return map;
+    }
+
+
+    //通过统一下单接口发起请求,获得prepay_id(预支付交易会话标识),这个标示是微信提交支付的关键数据
+    public String unifiedOrder(WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest) throws Exception {
+        WxPayUnifiedOrderResult wxPayUnifiedOrderResult = null;
+        try {
+            wxPayUnifiedOrderResult = wxPayApi.unifiedOrder(wxPayUnifiedOrderRequest);
+
+            if (WxPayConstants.TradeType.MWEB.equals(wxPayUnifiedOrderRequest.getTradeType())) {
+                /*H5支付开发步骤:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4*/
+                String mwebUrl = wxPayUnifiedOrderResult.getMwebUrl() + "&redirect_url=" + URLEncoder.encode(redirectUrl,"UTF-8");
+                return mwebUrl;
+            }
+
+            QrcodeUtils.encode(wxPayUnifiedOrderResult.getCodeURL(),response.getOutputStream());
+            return wxPayUnifiedOrderResult.getPrepayId();
+            //byte[] arr = wxPayApi.createScanPayQrcodeMode2(wxPayUnifiedOrderResult.getCodeURL(),null,null);
+        } catch (WxPayException e) {
+            logger.error("微信支付失败!订单号:{},原因:{}", wxPayUnifiedOrderRequest.getOutTradeNo(), e.getMessage());
+            e.printStackTrace();
+            return null;
+        }
+
+    }
+
+    /**
+     * 查询
+     * @param transactionId
+     * @param outTradeNo
+     */
+    public void queryOrder(String transactionId, String outTradeNo){
+        try {
+            WxPayOrderQueryResult wxPayOrderQueryResult =wxPayApi.queryOrder(transactionId, outTradeNo);
+            wxPayOrderQueryResult.getTradeState();
+        } catch (WxPayException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+
+    /**
+     * 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,
+     *   如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,
+     *   要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
+     * 特别提醒:商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,
+     *   防止数据泄漏导致出现“假通知”,造成资金损失。
+     * @param request
+     * @param response
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping("/notifyUrl")
+    public synchronized String payNotify(HttpServletRequest request, HttpServletResponse response) {
+        ModelMap map = new ModelMap();
+        String returnResult = null;
+        try {
+            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
+            WxPayOrderNotifyResult result = wxPayApi.parseOrderNotifyResult(xmlResult);
+            if ("SUCCESS".equals(result.getReturnCode())) {
+                if ("SUCCESS".equals(result.getResultCode())) {
+                    returnResult = setXml("SUCCESS", "OK");
+                    WechatOrder wechatOrder = wechatOrderService.getByTransactionId(result.getTransactionId());
+                    //微信在数据库中订单存在且状态已处理
+                    if (wechatOrder != null && wechatOrder.getStatus() == 1) {
+                        logger.info("系统已对该笔交易进行处理,交易订单号" + wechatOrder.getOutTradeNo() + "微信交易号" + wechatOrder.getTransactionId());
+                        returnResult = setXml("SUCCESS", "OK");
+                    } else {
+                        // 自己处理订单的业务逻辑
+
+                        //校验返回的订单金额是否与商户侧的订单金额一致
+                        //TODO 先注释这两句
+//                        ProjectRecode projectRecode = projectRecodeService.findOne(Long.parseLong(result.getOutTradeNo()));
+//                        if (!(projectRecode != null && ((int) (projectRecode.getAmount()*100)) == result.getTotalFee().intValue())) {
+                        if (false) {
+                            logger.warn("防止数据泄漏导致出现“假通知”,以免造成资金损失");
+                            map.put("warning", "防止数据泄漏导致出现“假通知”,以免造成资金损失");
+                            returnResult = setXml("FAIL", "商户侧的订单金额与返回的订单金额不一致");
+                        } else {
+                            WxPayOrderQueryResult wxPayOrderQueryResult = wxPayApi.queryOrder(result.getTransactionId(),null);//二选一填
+                            if (wxPayOrderQueryResult != null) {
+                                map.put("tradeState", wxPayOrderQueryResult.getTradeState());
+                                map.put("tradeStateDesc", wxPayOrderQueryResult.getTradeStateDesc());
+                            }
+                            wechatOrder = wechatOrderService.save(WechatOrder.WxPayOrderNotifyResultToConvert(result, (short) 1, wxPayOrderQueryResult));
+                            returnResult = setXml("SUCCESS", "OK");
+                        }
+                    }
+                    //String totalFee = WxPayBaseResult.feeToYuan(result.getTotalFee());
+                } else {
+                    logger.info("微信支付业务处理失败:" + result.getErrCodeDes());
+                    returnResult = setXml("FAIL", "微信支付业务处理失败");
+                }
+            } else {
+                logger.info("微信支付返回错误状态码(通信错误),错误信息:" + result.getReturnMsg());
+                returnResult = setXml("FAIL", "微信支付返回错误状态码(通信错误)");
+            }
+        } catch (WxPayException e) {
+            logger.error("微信回调结果异常,异常原因{}", e.getMessage());
+            map.put("error", e.getMessage());
+            returnResult = setXml("FAIL", "签名失败");
+        } finally {
+            //TODO map
+            return returnResult;
+        }
+    }
+
+    @ResponseBody
+    @RequestMapping("/redirectUrl")
+    public String redirectUrl() {
+    /*由于设置redirect_url后,回跳指定页面的操作可能发生在:1,微信支付中间页调起微信收银台后超过5秒
+    2,用户点击“取消支付“或支付完成后点“完成”按钮。因此无法保证页面回跳时,支付流程已结束,
+    所以商户设置的redirect_url地址不能自动执行查单操作,应让用户去点击按钮触发查单操作。*/
+    //效果图可以参考: https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4  最下面
+
+        return "h5支付回调";
+    }
+
+    /**
+     * 判断是否是微信浏览器发起的请求,如果是返回true,反正返回false
+     * @param req
+     * @return
+     */
+    @ResponseBody
+    @RequestMapping("/isWechat")
+    public boolean isWechatBrowser(HttpServletRequest req){
+        String ua = req.getHeader("user-agent").toLowerCase();
+        if (ua.indexOf("micromessenger") >= 0) {// 是微信浏览器
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * 获取token  公众号支付模式也不需要  先放着
+     * @return
+     * @throws Exception
+     */
+    public String getAccessToken() throws Exception {
+        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WxConfig.APPID + "&secret=" + WxConfig.APPSECRET;
+        HttpUtil.Response response = HttpUtil.sendGetRequest(url,null);
+        if (response.getStatusCode() == 200) {
+            return response.getResponseText();
+        }
+        return null;
+    }
+
+    /**
+     * 获取用户基本信息  静默获取  无需用户同意 只有公众号模式需要
+     * https://mp.weixin.qq.com/advanced/advanced?action=table&token=719542712&lang=zh_CN
+     * 网页授权添加url  需icp备案
+     * @param request
+     * @return
+     */
+    public String getOpenId(HttpServletRequest request){
+        try {
+            //TODO 授权方式  是否需要电话号码  名字等信息
+            //TODO 获取code
+            String code = request.getParameter("code");
+            //String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
+            return wxPayApi.authcode2Openid(code);
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 验证token
+     * @param request
+     * @param response
+     */
+    @ResponseBody
+    @RequestMapping("/checkToken")
+    public void checkToken(HttpServletRequest request, HttpServletResponse response) {
+        boolean isGet = request.getMethod().toLowerCase().equals("get");
+        boolean isPost = request.getMethod().toLowerCase().equals("post");
+        PrintWriter print;
+        if (isGet) {
+            // 微信加密签名
+            String signature = request.getParameter("signature");
+            // 时间戳
+            String timestamp = request.getParameter("timestamp");
+            // 随机数
+            String nonce = request.getParameter("nonce");
+            // 随机字符串
+            String echostr = request.getParameter("echostr");
+            // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
+            if (signature != null && WxCheckoutUtil.checkSignature(signature, timestamp, nonce)) {
+                try {
+                    print = response.getWriter();
+                    print.write(echostr);
+                    print.flush();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        } else if (isPost) {
+            //核心逻辑
+        }
+    }
+//
+
+
+
+//    /**
+//     * 获取验签秘钥API
+//     * https://pay.weixin.qq.com/wiki/doc/api/jsapi_sl.php?chapter=23_1
+//     *  mch_id 商户号
+//     *  partnerKey 商户平台设置的密钥key
+//     * @return {String}
+//     */
+//    @ResponseBody
+//    @RequestMapping("/getsignkey")
+//    public String getsignkey() throws Exception {
+//        Map<String, String> map =new HashMap<String, String>();
+//        String mch_id = "";
+//        String partnerKey = "";//商户平台设置的密钥key
+//        String nonce_str = String.valueOf(System.currentTimeMillis());
+//        map.put("mch_id", mch_id);//商户号
+//        map.put("nonce_str", nonce_str);//随机字符串
+//        map.put("sign", WxSign.createSign(map, partnerKey));
+//
+//        String url = null;
+//        if (isSandBox) {
+//            url = WXPayConstants.SANDBOX_GETSINGKEY_URL;
+//        }else {
+//            //url = WXPayConstants.UGETSINGKEY_URL;
+//        }
+//        HttpUtil.Response result = HttpUtil.sendPostRequest(url, map);
+//
+//        return result.getResponseText();
+//    }
+//
+
+    private WxPayUnifiedOrderRequest createWxPayUnifiedOrderRequest(HttpServletRequest request, ProjectRecode projectRecode, String tradeType) {
+        //Project project = projectRecode.getProject();
+        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
+        wxPayUnifiedOrderRequest.setDeviceInfo("WEB");//否 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB
+        wxPayUnifiedOrderRequest.setNonceStr(String.valueOf(System.currentTimeMillis()));//是 随机字符串,不长于32位。
+        //wxPayUnifiedOrderRequest.setSign("xixihahxixhahaha");//是 签名
+        //wxPayUnifiedOrderRequest.setSignType(null);//否 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
+
+
+        //商品描述交易字段格式根据不同的应用场景按照以下格式:(1)PC网站——传入浏览器打开的网站主页title名-实际商品名称,例如:腾讯充值中心-QQ会员充值;(2) 公众号——传入公众号名称-实际商品名称,例如:腾讯形象店- image-QQ公仔;(3) H5——应用在浏览器网页上的场景,传入浏览器打开的移动网页的主页title名-实际商品名称,例如:腾讯充值中心-QQ会员充值;(4) 线下门店——门店品牌名-城市分店名-实际商品名称,例如: image形象店-深圳腾大- QQ公仔)(5) APP——需传入应用市场上的APP名字-实际商品名称,天天爱消除-游戏充值。
+        if (WxPayConstants.TradeType.MWEB.equals(tradeType)) {
+            //H5——应用在浏览器网页上的场景,传入浏览器打开的移动网页的主页title名-实际商品名称,例如:腾讯充值中心-QQ会员充值;
+            wxPayUnifiedOrderRequest.setBody("一元捐-" + projectRecode.getProjectName());
+        } else if (WxPayConstants.TradeType.JSAPI.equals(tradeType)) {
+            if (StringUtils.isEmpty(wxPayApi.getConfig().getSubAppId())) {
+                wxPayUnifiedOrderRequest.setOpenid(null);//否是 trade_type=JSAPI,此参数必传,用户在主商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+            } else {
+                wxPayUnifiedOrderRequest.setSubOpenid(null);//否是 trade_type=JSAPI,此参数必传,用户在子商户appid下的唯一标识。openid和sub_openid可以选传其中之一,如果选择传sub_openid,则必须传sub_appid。
+            }
+
+            //公众号——传入公众号名称-实际商品名称,例如:腾讯形象店- image-QQ公仔;
+            wxPayUnifiedOrderRequest.setBody("优软科技-" + projectRecode.getProjectName());
+        } else if (WxPayConstants.TradeType.NATIVE.equals(tradeType)) {
+            //PC网站——传入浏览器打开的网站主页title名-实际商品名称,例如:腾讯充值中心-QQ会员充值;
+            wxPayUnifiedOrderRequest.setBody("一元捐-" + projectRecode.getProjectName());
+        }
+
+        //wxPayUnifiedOrderRequest.setDetail("");//否 商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见“单品优惠参数说明”
+
+
+        wxPayUnifiedOrderRequest.setAttach("这是附加数据");//否 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
+
+        wxPayUnifiedOrderRequest.setOutTradeNo(projectRecode.getId().toString());//是 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一。
+
+        //wxPayUnifiedOrderRequest.setFeeType("CNY");//否 符合ISO 4217标准的三位字母代码,默认人民币:CNY
+        wxPayUnifiedOrderRequest.setTotalFee((int)(projectRecode.getAmount() * 100));//是 订单总金额,只能为整数
+
+        //wxPayUnifiedOrderRequest.setSpbillCreateIp(IpUtils.getIpFromRequest(request));//是 APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP
+        wxPayUnifiedOrderRequest.setSpbillCreateIp("218.17.158.219");
+
+        //wxPayUnifiedOrderRequest.setTimeStart(null);//否 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。
+        //wxPayUnifiedOrderRequest.setTimeExpire(null);//否 订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。
+        //wxPayUnifiedOrderRequest.setGoodsTag(null);//否 订单优惠标记,代金券或立减优惠功能的参数
+        //wxPayUnifiedOrderRequest.setNotifyURL();//是 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
+        wxPayUnifiedOrderRequest.setTradeType(tradeType); //是 取值如下:JSAPI,NATIVE,APP
+
+        wxPayUnifiedOrderRequest.setProductId(projectRecode.getProId().toString());//否是 trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。
+
+        //wxPayUnifiedOrderRequest.setLimitPay(null);//否 指定支付方式 如:no_credit--指定不能使用信用卡支付
+        //wxPayUnifiedOrderRequest.setSceneInfo(null);//否 该字段用于上报场景信息,目前支持上报实际门店信息。该字段为JSON对象数据,对象格式为{"store_info":{"id": "门店ID","name": "名称","area_code": "编码","address": "地址" }}
+
+        return wxPayUnifiedOrderRequest;
+    }
+
+    //通过xml 返回给给微信消息
+    public String setXml(String return_code, String return_msg) {
+        return "<xml><return_code><![CDATA[" + return_code + "]]>" +   
+                "</return_code><return_msg><![CDATA[" + return_msg + "]]></return_msg></xml>";  
+    }
+
+    private ProjectRecode createProjectRecode(String jsonStr) throws Exception {
+        ProjectRecode projectRecode= JSONObject.parseObject(jsonStr,ProjectRecode.class);
+        projectRecode.setTime(new Date());
+        ProjectRecode newProjectRecode = projectRecodeService.join(projectRecode);
+        return newProjectRecode;
+    }
+}

+ 19 - 0
donate-service/src/main/java/com/uas/service/donate/dao/WechatOrderDao.java

@@ -0,0 +1,19 @@
+package com.uas.service.donate.dao;
+
+import com.uas.service.donate.model.WechatOrder;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by 黄诚天 on 2017-10-26.
+ */
+@Repository
+public interface WechatOrderDao extends JpaRepository<WechatOrder,Long>,JpaSpecificationExecutor<WechatOrder> {
+    List<WechatOrder> findByTransactionId(@Param(value = "transaction_id") String transactionId);
+
+    List<WechatOrder> findByOutTradeNo(@Param(value = "out_trade_no") String outTradeNo);
+}

+ 338 - 0
donate-service/src/main/java/com/uas/service/donate/model/WechatOrder.java

@@ -0,0 +1,338 @@
+package com.uas.service.donate.model;
+
+import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
+
+import javax.persistence.*;
+
+/**
+ * Created by 黄诚天 on 2017-11-02.
+ * 微信(异步通知)返回订单数据  封装订单信息表
+ */
+@Entity
+@Table(name="wechat$order")
+public class WechatOrder {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private Long id;
+
+    //公众账号ID	 appid
+    @Column(name = "app_id")
+    private String appid;
+
+    //商户号
+    @Column(name = "mch_id")
+    private String mchid;
+
+    //微信支付订单号
+    @Column(name = "transaction_id")
+    private String transactionId;
+
+    //商户系统内部订单号 商户订单号
+    @Column(name = "out_trade_no")
+    private String outTradeNo;
+
+    //用户在商户appid下的唯一标识
+    @Column(name = "openid")
+    private String openid;
+
+    //交易类型
+    @Column(name = "trade_type")
+    private String tradeType;
+
+    //订单金额  单位分
+    @Column(name = "total_fee")
+    private Integer totalFee;
+
+    //随机字符串
+    @Column(name = "nonce_str")
+    private String nonceStr;
+
+    //签名
+    @Column(name = "sign")
+    private String sign;
+
+    //付款银行
+    @Column(name = "bank_type")
+    private String bankType;
+
+
+    @Column(name = "device_info")
+    private String deviceInfo;
+
+    //用户是否关注公众账号,Y-关注,N-未关注,仅在公众账号类型支付有效
+    @Column(name = "is_subscribe")
+    private String isSubscribe;
+
+    //货币种类
+    @Column(name = "fee_type")
+    private String feeType;
+
+    //附加消息
+    @Column(name = "attach")
+    private String attach;
+
+    //支付完成时间
+    @Column(name = "time_end")
+    private String timeEnd;
+
+    @Column(name = "sub_openid")
+    private String subOpenid;
+
+    @Column(name = "sub_is_subscribe")
+    private String subIsSubscribe;
+
+    //现金支付金额订单现金支付金额
+    @Column(name = "cash_fee")
+    private Integer cashFee;
+
+    //现金支付货币类型
+    @Column(name = "cash_fee_type")
+    private String cashFeeType;
+
+    //微信异步通知处理状态 1为已处理
+    @Column(name = "status")
+    private Short status;
+
+    //交易状态 (SUCCESS—支付成功 REFUND—转入退款 NOTPAY—未支付 CLOSED—已关闭 REVOKED—已撤销(刷卡支付) USERPAYING--用户支付中 PAYERROR--支付失败(其他原因,如银行返回失败))
+    @Column(name = "trade_state")
+    private String tradeState;
+
+    //交易状态描述
+    @Column(name = "trade_state_desc")
+    private String tradeStateDesc;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMchid() {
+        return mchid;
+    }
+
+    public void setMchid(String mchid) {
+        this.mchid = mchid;
+    }
+
+    public String getTransactionId() {
+        return transactionId;
+    }
+
+    public void setTransactionId(String transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getTradeType() {
+        return tradeType;
+    }
+
+    public void setTradeType(String tradeType) {
+        this.tradeType = tradeType;
+    }
+
+    public Integer getTotalFee() {
+        return totalFee;
+    }
+
+    public void setTotalFee(Integer totalFee) {
+        this.totalFee = totalFee;
+    }
+
+    public String getNonceStr() {
+        return nonceStr;
+    }
+
+    public void setNonceStr(String nonceStr) {
+        this.nonceStr = nonceStr;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBankType() {
+        return bankType;
+    }
+
+    public void setBankType(String bankType) {
+        this.bankType = bankType;
+    }
+
+    public String getDeviceInfo() {
+        return deviceInfo;
+    }
+
+    public void setDeviceInfo(String deviceInfo) {
+        this.deviceInfo = deviceInfo;
+    }
+
+    public String getIsSubscribe() {
+        return isSubscribe;
+    }
+
+    public void setIsSubscribe(String isSubscribe) {
+        this.isSubscribe = isSubscribe;
+    }
+
+    public String getFeeType() {
+        return feeType;
+    }
+
+    public void setFeeType(String feeType) {
+        this.feeType = feeType;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTimeEnd() {
+        return timeEnd;
+    }
+
+    public void setTimeEnd(String timeEnd) {
+        this.timeEnd = timeEnd;
+    }
+
+    public String getSubOpenid() {
+        return subOpenid;
+    }
+
+    public void setSubOpenid(String subOpenid) {
+        this.subOpenid = subOpenid;
+    }
+
+    public String getSubIsSubscribe() {
+        return subIsSubscribe;
+    }
+
+    public void setSubIsSubscribe(String subIsSubscribe) {
+        this.subIsSubscribe = subIsSubscribe;
+    }
+
+    public Integer getCashFee() {
+        return cashFee;
+    }
+
+    public void setCashFee(Integer cashFee) {
+        this.cashFee = cashFee;
+    }
+
+    public String getCashFeeType() {
+        return cashFeeType;
+    }
+
+    public void setCashFeeType(String cashFeeType) {
+        this.cashFeeType = cashFeeType;
+    }
+
+    public Short getStatus() {
+        return status;
+    }
+
+    public void setStatus(Short status) {
+        this.status = status;
+    }
+
+    public String getTradeState() {
+        return tradeState;
+    }
+
+    public void setTradeState(String tradeState) {
+        this.tradeState = tradeState;
+    }
+
+    public String getTradeStateDesc() {
+        return tradeStateDesc;
+    }
+
+    public void setTradeStateDesc(String tradeStateDesc) {
+        this.tradeStateDesc = tradeStateDesc;
+    }
+
+    public static WechatOrder WxPayOrderNotifyResultToConvert(WxPayOrderNotifyResult wxPayResult, short status, WxPayOrderQueryResult wxPayOrderQueryResult) {
+        WechatOrder wechatOrder = new WechatOrder();
+        wechatOrder.setSubOpenid(wxPayResult.getSubOpenid());
+        wechatOrder.setFeeType(wxPayResult.getFeeType());
+        wechatOrder.setTradeType(wxPayResult.getTradeType());
+        wechatOrder.setAppid(wxPayResult.getAppid());
+        wechatOrder.setAttach(wxPayResult.getAttach());
+        wechatOrder.setBankType(wxPayResult.getBankType());
+        wechatOrder.setCashFee(wxPayResult.getCashFee());
+        wechatOrder.setCashFeeType(wxPayResult.getCashFeeType());
+        wechatOrder.setDeviceInfo(wxPayResult.getDeviceInfo());
+        wechatOrder.setIsSubscribe(wxPayResult.getIsSubscribe());
+        wechatOrder.setMchid(wxPayResult.getMchId());
+        wechatOrder.setNonceStr(wxPayResult.getNonceStr());
+        wechatOrder.setOpenid(wxPayResult.getOpenid());
+        wechatOrder.setOutTradeNo(wxPayResult.getOutTradeNo());
+        wechatOrder.setSign(wxPayResult.getSign());
+        wechatOrder.setSubIsSubscribe(wxPayResult.getSubIsSubscribe());
+        wechatOrder.setTimeEnd(wxPayResult.getTimeEnd());
+        wechatOrder.setTotalFee(wxPayResult.getTotalFee());
+        wechatOrder.setTradeType(wxPayResult.getTradeType());
+        wechatOrder.setTransactionId(wxPayResult.getTransactionId());
+        wechatOrder.setStatus(status);
+
+        wechatOrder.setTradeState(wxPayOrderQueryResult.getTradeState());
+        wechatOrder.setTradeStateDesc(wxPayOrderQueryResult.getTradeStateDesc());
+
+
+        return wechatOrder;
+    }
+
+    public static WechatOrder WxPayUnifiedOrderRequestToConvert(WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest) {
+        WechatOrder wechatOrder = new WechatOrder();
+        wechatOrder.setSubOpenid(wxPayUnifiedOrderRequest.getSubOpenid());
+        wechatOrder.setFeeType(wxPayUnifiedOrderRequest.getFeeType());
+        wechatOrder.setTradeType(wxPayUnifiedOrderRequest.getTradeType());
+        wechatOrder.setAppid(wxPayUnifiedOrderRequest.getAppid());
+        wechatOrder.setAttach(wxPayUnifiedOrderRequest.getAttach());
+        wechatOrder.setDeviceInfo(wxPayUnifiedOrderRequest.getDeviceInfo());
+        wechatOrder.setMchid(wxPayUnifiedOrderRequest.getMchId());
+        wechatOrder.setOpenid(wxPayUnifiedOrderRequest.getOpenid());
+        wechatOrder.setOutTradeNo(wxPayUnifiedOrderRequest.getOutTradeNo());
+        wechatOrder.setSign(wxPayUnifiedOrderRequest.getSign());
+        wechatOrder.setTotalFee(wxPayUnifiedOrderRequest.getTotalFee());
+        wechatOrder.setTradeType(wxPayUnifiedOrderRequest.getTradeType());
+        return wechatOrder;
+    }
+}

+ 14 - 0
donate-service/src/main/java/com/uas/service/donate/service/WechatOrderService.java

@@ -0,0 +1,14 @@
+package com.uas.service.donate.service;
+
+import com.uas.service.donate.model.WechatOrder;
+
+/**
+ * Created by 黄诚天 on 2017-11-02.
+ */
+public interface WechatOrderService {
+    WechatOrder save(WechatOrder wechatOrder);
+
+    WechatOrder getByTransactionId(String transactionId);
+
+    WechatOrder getByOutTradeNo(String outTradeNo);
+}

+ 46 - 0
donate-service/src/main/java/com/uas/service/donate/service/impl/WechatOrderServiceImpl.java

@@ -0,0 +1,46 @@
+package com.uas.service.donate.service.impl;
+
+import com.uas.service.donate.dao.WechatOrderDao;
+import com.uas.service.donate.model.WechatOrder;
+import com.uas.service.donate.service.WechatOrderService;
+import com.uas.service.donate.util.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * Created by 黄诚天 on 2017-11-02.
+ */
+@Service
+public class WechatOrderServiceImpl implements WechatOrderService {
+    @Autowired
+    WechatOrderDao wechatOrderDao;
+
+    @Override
+    public WechatOrder save(WechatOrder wechatOrder) {
+        return wechatOrderDao.save(wechatOrder);
+    }
+
+    @Override
+    public WechatOrder getByTransactionId(String transactionId) {
+        WechatOrder wechatOrder = null;
+        List<WechatOrder> list = wechatOrderDao.findByTransactionId(transactionId);
+        if (!CollectionUtils.isEmpty(list)) {
+            wechatOrder = list.get(0);
+        }
+
+        return wechatOrder;
+    }
+
+    @Override
+    public WechatOrder getByOutTradeNo(String outTradeNo) {
+        WechatOrder wechatOrder = null;
+        List<WechatOrder> list = wechatOrderDao.findByOutTradeNo(outTradeNo);
+        if (!CollectionUtils.isEmpty(list)) {
+            wechatOrder = list.get(0);
+        }
+
+        return wechatOrder;
+    }
+}

+ 136 - 0
donate-service/src/main/java/com/uas/service/donate/sign/WxSign.java

@@ -0,0 +1,136 @@
+package com.uas.service.donate.sign;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Created by 黄诚天 on 2017-10-30.
+ */
+public class WxSign {
+
+    private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
+    private static final char[] CHAR_ARRAY = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
+
+    /**
+     * 生成签名
+     *
+     * @param params
+     *            参数
+     * @param partnerKey
+     *            支付密钥
+     * @return {String}
+     *
+     */
+    public static String createSign(Map<String, String> params, String partnerKey) {
+        // 生成签名前先去除sign
+        params.remove("sign");
+        String stringA = packageSign(params, false);
+        String stringSignTemp = stringA + "&key=" + partnerKey;
+        return md5(stringSignTemp).toUpperCase();
+    }
+
+    public static String md5(String srcStr){
+        return hash("MD5", srcStr);
+    }
+
+    public static String hash(String algorithm, String srcStr) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+            byte[] bytes = md.digest(srcStr.getBytes("utf-8"));
+            return toHex(bytes);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String toHex(byte[] bytes) {
+        StringBuilder ret = new StringBuilder(bytes.length * 2);
+        for (int i=0; i<bytes.length; i++) {
+            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
+            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
+        }
+        return ret.toString();
+    }
+
+    /**
+     * 组装签名的字段
+     *
+     * @param params
+     *            参数
+     * @param urlEncoder
+     *            是否urlEncoder
+     * @return {String}
+     */
+    public static String packageSign(Map<String, String> params, boolean urlEncoder) {
+        // 先将参数以其参数名的字典序升序进行排序
+        TreeMap<String, String> sortedParams = new TreeMap<String, String>(params);
+        // 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (Map.Entry<String, String> param : sortedParams.entrySet()) {
+            String value = param.getValue();
+            if (isBlank(value)) {
+                continue;
+            }
+            if (first) {
+                first = false;
+            } else {
+                sb.append("&");
+            }
+            sb.append(param.getKey()).append("=");
+            if (urlEncoder) {
+                try {
+                    value = urlEncode(value);
+                } catch (UnsupportedEncodingException e) {
+                }
+            }
+            sb.append(value);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 字符串为 null 或者内部字符全部为 ' ' '\t' '\n' '\r' 这四类字符时返回 true
+     */
+    public static boolean isBlank(String str) {
+        if (str == null) {
+            return true;
+        }
+        int len = str.length();
+        if (len == 0) {
+            return true;
+        }
+        for (int i = 0; i < len; i++) {
+            switch (str.charAt(i)) {
+                case ' ':
+                case '\t':
+                case '\n':
+                case '\r':
+                    // case '\b':
+                    // case '\f':
+                    break;
+                default:
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * urlEncode
+     *
+     * @param src
+     *            微信参数
+     * @return String
+     * @throws UnsupportedEncodingException
+     *             编码错误
+     */
+    public static String urlEncode(String src) throws UnsupportedEncodingException {
+        return URLEncoder.encode(src, Charset.forName("UTF-8").name()).replace("+", "%20");
+    }
+}

+ 90 - 0
donate-service/src/main/java/com/uas/service/donate/util/WxCheckoutUtil.java

@@ -0,0 +1,90 @@
+package com.uas.service.donate.util;
+
+import com.uas.service.donate.config.WxConfig;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Created by 黄诚天 on 2017-10-30.
+ *
+ * 微信Access_Token验证类
+ */
+public class WxCheckoutUtil {
+    // 与接口配置信息中的Token要一致
+    private static String token = WxConfig.Token;
+
+    /**
+     * 验证签名
+     *
+     * @param signature
+     * @param timestamp
+     * @param nonce
+     * @return
+     */
+    public static boolean checkSignature(String signature, String timestamp, String nonce) {
+        String[] arr = new String[] { token, timestamp, nonce };
+        // 将token、timestamp、nonce三个参数进行字典序排序
+        // Arrays.sort(arr);
+        sort(arr);
+        StringBuilder content = new StringBuilder();
+        for (int i = 0; i < arr.length; i++) {
+            content.append(arr[i]);
+        }
+        MessageDigest md = null;
+        String tmpStr = null;
+
+        try {
+            md = MessageDigest.getInstance("SHA-1");
+            // 将三个参数字符串拼接成一个字符串进行sha1加密
+            byte[] digest = md.digest(content.toString().getBytes());
+            tmpStr = byteToStr(digest);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        content = null;
+        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
+        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
+    }
+
+    /**
+     * 将字节数组转换为十六进制字符串
+     *
+     * @param byteArray
+     * @return
+     */
+    private static String byteToStr(byte[] byteArray) {
+        String strDigest = "";
+        for (int i = 0; i < byteArray.length; i++) {
+            strDigest += byteToHexStr(byteArray[i]);
+        }
+        return strDigest;
+    }
+
+    /**
+     * 将字节转换为十六进制字符串
+     *
+     * @param mByte
+     * @return
+     */
+    private static String byteToHexStr(byte mByte) {
+        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+        char[] tempArr = new char[2];
+        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
+        tempArr[1] = Digit[mByte & 0X0F];
+        String s = new String(tempArr);
+        return s;
+    }
+    public static void sort(String a[]) {
+        for (int i = 0; i < a.length - 1; i++) {
+            for (int j = i + 1; j < a.length; j++) {
+                if (a[j].compareTo(a[i]) < 0) {
+                    String temp = a[i];
+                    a[i] = a[j];
+                    a[j] = temp;
+                }
+            }
+        }
+    }
+
+}

+ 13 - 0
donate-service/src/main/resources/config/wechat.properties

@@ -0,0 +1,13 @@
+pay.appId=wxbc1f8607137d3b8a
+pay.mchId=1280180301
+pay.mchKey=huangchengtianusoftchina12345678
+#subAppId=
+#subMchId=
+pay.keyPath=D://apiclient_cert.p12
+pay.notifyURL=http://5087452.nat123.cc/wxpay/notifyUrl
+
+mp.appId=wxbc1f8607137d3b8a
+mp.appSecret=
+mp.token=huangchengtian
+mp.aesKey=bmSUBuzyzvfUYTw4GMKTHQmnaxj6SNf1JJ3Q1joFnGP
+

+ 1 - 1
donate-service/src/main/resources/templates/index.ftl

@@ -776,7 +776,7 @@
                     <a href="/project#/detail/${project.id}"><img src="${project.pcImg!''}" alt=""/></a>
                 </div>
                 <div class="project-detail fl">
-                    <p><a href="projectDetailsAndProgress">${project.name!''}</a></p>
+                    <p><a href="/project#/detail/${project.id}">${project.name!''}</a></p>
                     <div><span>项目简介:</span><span>${project.summary!''}</span></div>
                     <div><span>筹款时间:</span><span>${project.startTime!''}至${project.endTime!''}</span></div>
                     <div><span>筹款目标:</span><span>${project.target!''}</span></div>

+ 51 - 34
donate-service/src/main/webapp/resources/js/pay.js

@@ -34,14 +34,16 @@ var pay =function (proId, amount, payWay) {
     if(payWay == "支付宝") {
         aliPay(proId, amount);
     } else if (payWay == "微信支付") {
-        wxPay();
+        wxPay(proId, amount);
     } else if (payWay == "网银支付") {
         unionPay();
     }
 }
 
 
-var wxPay = function () {
+var wxPay = function (proId, amount) {
+    var jsonStr = getJson(proId, amount);
+
     //公众号支付js模板 需引入http://res.wx.qq.com/open/js/jweixin-1.0.0.js
     //对浏览器的UserAgent进行正则匹配,不含有微信独有标识的则为其他浏览器
     //var userAgent = navigator.userAgent;
@@ -51,7 +53,10 @@ var wxPay = function () {
             url : "/wxpay/webPay",
             type : "POST",
             dataType : 'json',
-            //TODO ProjectRecord json数据
+            async: false,
+            data: {
+                jsonStr : jsonStr
+            },
             success : function(data) {
                 WeixinJSBridge.invoke('getBrandWCPayRequest', {
                     "appId" : data.appId, //公众号名称,由商户传入       
@@ -74,54 +79,58 @@ var wxPay = function () {
 
 
                 //这个if判断后面加的  不知道作用
-                if (typeof WeixinJSBridge == "undefined") {
-                    if (document.addEventListener) {
-                        document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
-                    } else if (document.attachEvent) {
-                        document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
-                        document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
-                    }
-                } else {
-                    onBridgeReady();
-                }
+                // if (typeof WeixinJSBridge == "undefined") {
+                //     if (document.addEventListener) {
+                //         document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
+                //     } else if (document.attachEvent) {
+                //         document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
+                //         document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
+                //     }
+                // } else {
+                //     onBridgeReady();
+                // }
             }
         });
     }else{
         //H5支付逻辑
-        //电脑or手机?
+
+        var url = "/wxpay/pcPay";
+        var dataType = "html"
+
+        if (isMobile) {
+            url = "/wxpay/wapPay";
+            dataType = "json"
+        }
 
         $.ajax({
             type : "POST",
-            url : "/wxpay/wapPay",
-            dataType : "json",
-            contentType : 'application/json;charset=UTF-8',
-            //data : JSON.stringify({orderId:orderId}),//TODO ProjectRecord json数据
+            url : url,
+            dataType : dataType,
+            //contentType : 'application/json;charset=UTF-8',
+            data: {
+                jsonStr : jsonStr
+            },
             success : function(res){
-                if("success" == res.errCode){
-                    var mwebUrl = res.data;
-                    window.location.href = mwebUrl;
-                }else{
-                    alert("支付操作异常,请稍后再试!");
+                if (res.error == null) {
+                    if (isMobile) {
+                        var mwebUrl = res.data;
+                        window.location.href = mwebUrl;
+                    } else {
+                        //document.write(res);
+                    }
+                } else {
+                    alert(res.error);
                 }
             },
-            error : function(XMLHttpRequest, textStatus, errorThrown) {
+            error : function() {
                 alert('支付异常,请联系客服!');
-            },
-            complete : function(XMLHttpRequest, textStatus) {
             }
         });
     }
 }
 
 var aliPay = function (proId, amount) {
-    var jsonStr =  "{proId:" + proId + "," +
-        "amount:" + amount + "," +
-        //"uuid:" + uuid + "," +
-        "way:'支付宝'" +
-        "}";
-
-    //location.href="/alipay/pcPay?jsonStr=" + jsonStr;
-
+    var jsonStr = getJson(proId, amount);
     var url = "/alipay/pcPay";
 
     if (isMobile) {
@@ -150,6 +159,14 @@ var unionPay  = function () {
 
 }
 
+var getJson = function (proId, amount) {
+    return jsonStr = "{proId:" + proId + "," +
+        "amount:" + amount + "," +
+        //"uuid:" + uuid + "," +
+        "way:'支付宝'" +
+        "}";
+}
+
 
 
 

+ 17 - 9
donate-service/src/main/webapp/resources/view/project/project_detail.html

@@ -883,11 +883,12 @@
     </div>
 </div>
 <!--捐款弹窗-->
+<!--弹出窗-->
 <div class="pop modal" role='dialog' id='layer'>
     <div class="modal-dialog">
         <div class="modal-content">
             <div class="header modal-header clearfix">
-                <p class="fl">捐款项目:寒门学子 阳光助学</p>
+                <p class="fl">捐款项目:{{project.name}}</p>
                 <div class="close fr" data-dismiss="modal">&times;</div>
             </div>
             <div class="body modal-body">
@@ -895,22 +896,22 @@
                     <span class="fl">捐款金额:</span>
                     <div class="fl">
                         <ul>
-                            <li class="active">1元</li>
-                            <li>50元</li>
-                            <li>100元</li>
-                            <li>200元</li>
+                            <li class="select-money active" ng-click="setMoney(1)">1元</li>
+                            <li class="select-money" ng-click="setMoney(50)">50元</li>
+                            <li class="select-money" ng-click="setMoney(100)">100元</li>
+                            <li class="select-money" ng-click="setMoney(200)">200元</li>
                         </ul>
-                        <div class="write"><input type="text" placeholder="其他金额" class="form-control"/><em>元</em></div>
+                        <div class="write"><input type="text" ng-model="donation" ng-click="setMoney(0)" placeholder="其他金额" class="write-money  form-control"/><em>元</em></div>
                     </div>
                 </div>
                 <div class="choose clearfix">
                     <span class="fl best">我的祝福:</span>
-                    <textarea name="" id="" cols="30" rows="10" class="fl form-control"></textarea>
+                    <textarea ng-model="bless" name="" id="" cols="30" rows="10" class="fl form-control"></textarea>
                     <div class="fl agree clearfix">
-                        <input type="checkbox" class="fl"><span class="fl">同意并接受《<a style="color: #2a5bfb;" href="">优软一元捐用户协议</a>》</span>
+                        <input type="checkbox" class="fl" required><span class="fl">同意并接受《<a href="/userAgreement" target="_blank" style="color: #5078cb;">优软一元捐用户协议</a>》</span>
                     </div>
                 </div>
-                <a href="donationsOver"><button>确认收款</button></a>
+                <a href="donationsOver"><button ng-click="ensureDonate()">确认捐款</button></a>
             </div>
         </div>
     </div>
@@ -923,4 +924,11 @@
         $(this).addClass('active').siblings().removeClass('active');
         $('.bottom').eq(index).addClass('show').siblings().removeClass('show');
     });
+
+    $('.select-money').on('click', function () {
+        $(this).addClass('active').siblings().removeClass('active');
+    });
+    $('.write-money').on('focus', function () {
+        $('.select-money').removeClass('active');
+    });
 </script>