微信app支付(android端+java后台)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信app支付(android端+java后台)相关的知识,希望对你有一定的参考价值。

本文讲解使用微信支付接口完成在android开发的原生态app中完成微信支付功能, 文章具体讲解了前端android如何集成微信支付功能以及后台如何组装前端需要支付信息, 话不多话, 具体看文章内容吧
00:00 / 07:03正常

本实例项目运行条件:

开发环境: 【Android Studio】

  1. 到微信开放平台注册帐号并且创建移动应用

    https://open.weixin.qq.com/cgi-bin/frame?t=home/app_tmpl&lang=zh_CN
    技术分享图片

Column 1 Column 2 Column 3
Text Text Text
  1. 获得移动应用的权限【微信支付】

    这个权限要求比较高,需要公司资质 并且 每年需要支付300元 才能开通 (这里不作讲解, 具体到官网上申请)
    技术分享图片

    1. 配置应用签名, 这个签名通过 android打包文件jks生成或者keystore生成 【如何生成jks文件】

    签名文件生成方法:

    3.1 keytool -list -v -keystore jks文件(或者keystore文件)

    3.2 获取指纹证书md5值, 将md5中的冒号去掉, 大写换成小写 (详情)

    总结: 微信开放平台Android应用签名的本质便是我们签名文件jks(或者keystore)的MD5值
    技术分享图片

    1. 配置支付密钥, 【如何配置密钥】 【微信配置密钥官网】
      技术分享图片
      1. 应用程序开发完成后,debug模式是无法完成支付的,应用程序必须由相应的jks签名之后生成的apk包安装在手机上才能进行分支付(微信会校验应用签名)
  2. 支付流程讲解

2.1 android程序启动后如下第一张图, 点击【确认支付】

2.1.1 android端向后台请求获得预支付信息

2.1.2 后台根据微信官网平台上的 配置信息 加上 订单信息 生成预支付信息

2.1.3 android端根据预支付信息 拉起微信支付页面进行支付(见下面第二张图)
技术分享图片技术分享图片

  1. 代码详解(Android端)

3.1 在android studio中引入 微信需要使用的jar包
技术分享图片
3.2 在android工程对应的包名下面新建 包以及类, wxapi/WXPayEntryActivity
技术分享图片
在AndroidManifest.xml中引用 WXPayEntryActivityandroid:icon="@drawable/desk"
br/>android:allowBackup="true"
android:icon="@drawable/desk"
android:label="@string/app_name"
br/>android:theme="@style/AppTheme">
android:screenOrientation="portrait"
android:label="@string/app_name">
activity
android:name=".activity.MainActivity"
android:screenOrientation="portrait"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity
    android:name=".wxapi.WXPayEntryActivity"
    android:screenOrientation="portrait"
    android:exported="true"
    android:launchMode="singleTop"/>

</application>
WXPayEntryActivity 代码详情(支付完成后,onResp会被调用,BaseResp.ErrCode.ERR_OK 表明支付成功)
public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {

private static final String TAG = "WXPayEntryActivity";

private IWXAPI api;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Constant.wxApi.handleIntent(getIntent(), this);
}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    api.handleIntent(intent, this);
}

@Override
public void onReq(BaseReq req) {
}

/**
 * 得到支付结果回调
 */
@Override
public void onResp(BaseResp resp)
{
    Log.i(TAG, "onPayFinish, errCode = " + resp.errCode);

    String strPayResult = "";
    switch (resp.errCode) {
        case BaseResp.ErrCode.ERR_OK:
            Toast.makeText(this, "付款成功!", Toast.LENGTH_SHORT).show();
            break;
        case BaseResp.ErrCode.ERR_USER_CANCEL:
            //分享取消
            //Toast.makeText(this, "付款取消!", Toast.LENGTH_SHORT).show();
            //Constant.WEIXIN_PAY_STATUS = "PAY_CANCEL";
            break;
        case BaseResp.ErrCode.ERR_AUTH_DENIED:
            //分享拒绝
            //Toast.makeText(this, "付款拒绝!", Toast.LENGTH_SHORT).show();
            //Constant.WEIXIN_PAY_STATUS = "PAY_DENY";
            break;
    }

    //向之前页面返回支付结果信息
    /*Intent intent = new Intent();
    intent.putExtra("payResult", strPayResult);
    setResult(100, intent);*/
    finish();
}

}
3.3 支付按钮的点击事件

通过http协议向后台请求相应的预支付信息, 根据这些信息组装相应的信息来调用微信接口, 拉起微信支付界面
    @OnClick(R.id.pay)

public void pay(){
String orderNum = OrderInfo.generateOutTradeNo();
payService
.wpay(orderNum, totalPrice, address.getText().toString() + "-外卖订单")
.subscribe(new Action1<WeiXinPrePay>() {
br/>@Override
public void call(WeiXinPrePay payInfo) {
if (Constant.wxApi != null) {
PayReq req = new PayReq();
req.appId = payInfo.getAppId();// 微信开放平台审核通过的应用APPID
req.partnerId = payInfo.getMchId();// 微信支付分配的商户号
req.prepayId = payInfo.getPrepayId();// 预支付订单号,app服务器调用“统一下单”接口获取
req.nonceStr = payInfo.getNonceStr();// 随机字符串,不长于32位,服务器小哥会给咱生成
req.timeStamp = payInfo.getTimeStamp();//
时间戳,app服务器小哥给出
req.packageValue = "WXPay";// 固定值Sign=WXPay,可以直接写死,服务器返回的也是这个固定值
req.sign = payInfo.getPaySign();// 签名,服务器小哥给出,他会根据: om/wiki/doc/api/app/app.php?chapter=4_3指导得到这个
Constant.wxApi.sendReq(req);
}
}
}, new Action1<Throwable>() {br/>@Override
public void call(Throwable throwable) {
showToast(throwable.getMessage());
}
});
}
4 微信支付Java后台

4.1 后台代码结构图
技术分享图片
4.2 微信配置信息 Config.properties
技术分享图片
4.3 方法wxpay用于生成预支付订单信息

方法notifyWeiXinPay用于微信支付成功后的回调, 注意: 在手机端使用微信支付成功后,微信服务器会根据提供的回调地址进行回调, parameterMap.put("notify_url", wxnotify); (见下面代码) 

在局域网是无法进行回调的,必须将你的服务端放在公网上进行测试, 回调函数会被多次调用,如果第一次成功后,你可以将业务数据状态标志为已处理, 对于相同订单的其它回调就不需要再次处理了br/>@Controller
@RequestMapping("/pay")
public class PayController {

String timeMillis = String.valueOf(System.currentTimeMillis() / 1000);
String randomString = PayCommonUtil.getRandomString(32);
//支付成功后的回调函数
public static String wxnotify = "http://gepanjiang.hk1.tunnelfrp.cc/WxPay/pay/notifyWeiXinPay.htm";

public PayController() {
    System.out.println("MainController构造函数");
}

/**
 * @param totalAmount    支付金额
 * @param description    描述
 * @param request
 * @return
 */
@RequestMapping(value = "/wxpay.htm", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody    
public Result wxpay(HttpServletRequest request) {
    Result result = new Result();
    Long userId = new Long(1);//baseController.getUserId();

    BigDecimal totalAmount = new BigDecimal(request.getParameter("totalPrice"));
    String trade_no = "";
    String description="";
    try {
        trade_no = new String(request.getParameter("orderNum").getBytes("ISO-8859-1"),"UTF-8");
        description = request.getParameter("description");
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    String openId = "";

    Map<String, String> map = weixinPrePay(trade_no,totalAmount,description,openId,request);  
    SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
    finalpackage.put("appId", ConfigManager.getInstance().getConfigItem("WXAppID")/*PayCommonUtil.APPID*/); 
    finalpackage.put("mchId", ConfigManager.getInstance().getConfigItem("MCH_ID"));
    Long time = (System.currentTimeMillis() / 1000);  
    finalpackage.put("timeStamp", time.toString());
    finalpackage.put("nonceStr", map.get("nonce_str"));
    finalpackage.put("prepayId", map.get("prepay_id"));
    finalpackage.put("package", "Sign=WXPay");
    finalpackage.put("signType", "MD5");
    String sign = PayCommonUtil.createSign("UTF-8", finalpackage);  
    finalpackage.put("paySign", sign);//官方文档上是sign,当前示例代码是paySign 可能以前的

    WeiXinPrePay prePay = new WeiXinPrePay();
    prePay.setAppId(ConfigManager.getInstance().getConfigItem("WXAppID"));
    prePay.setMchId(ConfigManager.getInstance().getConfigItem("MCH_ID"));
    prePay.setTimeStamp(time.toString());
    prePay.setNonceStr(map.get("nonce_str"));
    prePay.setPrepayId(map.get("prepay_id"));
    prePay.setSignType("MD5");
    prePay.setPaySign("paySign");
    result.setData(prePay);
    result.setStateCode(GeneralConstant.SUCCESS);
    result.setDesc("微信支付加载成功");

    return result;
} 

/**
 * 统一下单 
 * 应用场景:商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付。
 * @param trade_no
 * @param totalAmount
 * @param description
 * @param openid
 * @param sym
 * @param request
 * @return
 */
@SuppressWarnings("unchecked")
public Map<String, String> weixinPrePay(String trade_no,BigDecimal totalAmount,  
        String description, String openid, HttpServletRequest request) { 
    SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();  
    parameterMap.put("appid", ConfigManager.getInstance().getConfigItem("WXAppID"));  //应用appid 
    parameterMap.put("mch_id", ConfigManager.getInstance().getConfigItem("MCH_ID")/*PayCommonUtil.MCH_ID*/);  //商户号
    //parameterMap.put("device_info", "WEB");
    parameterMap.put("nonce_str", randomString);  
    parameterMap.put("body", description);
    parameterMap.put("out_trade_no", trade_no);
    parameterMap.put("fee_type", "CNY");  
    System.out.println("jiner");  
    BigDecimal total = totalAmount.multiply(new BigDecimal(100));  //接口中参数支付金额单位为【分】,参数值不能带小数,所以乘以100
    java.text.DecimalFormat df=new java.text.DecimalFormat("0");  
    parameterMap.put("total_fee", df.format(total));  
    System.out.println("jiner2");  
    parameterMap.put("spbill_create_ip", PayCommonUtil.getRemoteHost(request));  
    parameterMap.put("notify_url", wxnotify);
    parameterMap.put("trade_type", "APP");//"JSAPI"
    //trade_type为JSAPI是 openid为必填项
    //parameterMap.put("openid", openid);
    System.out.println("");  
    String sign = PayCommonUtil.createSign("UTF-8", parameterMap); 
    System.out.println("jiner2");  
    parameterMap.put("sign", sign);  
    String requestXML = PayCommonUtil.getRequestXml(parameterMap);  
    System.out.println(requestXML);  
    String result = PayCommonUtil.httpsRequest(  
            "https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",  
            requestXML);  
    System.out.println(result);  
    Map<String, String> map = null;  
    try {  
        map = PayCommonUtil.doXMLParse(result);  
    } catch (JDOMException e) {  
        // TODO Auto-generated catch block  
        e.printStackTrace();  
    } catch (IOException e) {  
        // TODO Auto-generated catch block  
        e.printStackTrace();  
    }  
    return map;        
}

/**
 * 此函数会被执行多次,如果支付状态已经修改为已支付,则下次再调的时候判断是否已经支付,如果已经支付了,则什么也执行
 * @param request
 * @param response
 * @return
 * @throws IOException
 * @throws JDOMException
 */
@RequestMapping(value = "notifyWeiXinPay.htm", produces = MediaType.APPLICATION_JSON_VALUE)

// @RequestDescription("支付回调地址")br/>@ResponseBody
public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {
System.out.println("微信支付回调");
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String resultxml = new String(outSteam.toByteArray(), "utf-8");
Map<String, String> params = PayCommonUtil.doXMLParse(resultxml);
outSteam.close();
inStream.close();

    Map<String,String> return_data = new HashMap<String,String>();  
    if (!PayCommonUtil.isTenpaySign(params)) {
        // 支付失败
        return_data.put("return_code", "FAIL");  
        return_data.put("return_msg", "return_code不正确");
        return StringUtil.GetMapToXML(return_data);
    } else {
        System.out.println("===============付款成功==============");
        // ------------------------------
        // 处理业务开始
        // ------------------------------
        // 此处处理订单状态,结合自己的订单数据完成订单状态的更新
        // ------------------------------

        String total_fee = params.get("total_fee");
        double v = Double.valueOf(total_fee) / 100;
        String out_trade_no = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
        Date accountTime = DateUtil.stringtoDate(params.get("time_end"), "yyyyMMddHHmmss");
        String ordertime = DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
        String totalAmount = String.valueOf(v);
        String appId = params.get("appid");
        String tradeNo = params.get("transaction_id");

        return_data.put("return_code", "SUCCESS");  
        return_data.put("return_msg", "OK");  
        return StringUtil.GetMapToXML(return_data);
    }
}

}








以上是关于微信app支付(android端+java后台)的主要内容,如果未能解决你的问题,请参考以下文章

APP支付微信支付,Java后台开发

微信APP支付-Java后台实现

APP微信支付Java后台的实现(springmvc)

android 集成支付宝app支付(原生态)-包括android前端与java后台

android 集成支付宝app支付(原生态)-包括android前端与java后台

android 集成支付宝app支付(原生态)-包括android前端与java后台