App微信支付流程

微信app支付流程

**1.申请微信商家**
申请商家---获取如下
app appID ,
appPartnerKey【app密钥】
 商户号(mch_id)
 设置交易类型
 /**
 * 交易类型以及同意下单链接与微信回调接口连接
 */
public static  String tradeTypeJSAPI = "JSAPI";

public static  String tradeTypeAPP = "APP";

public static  String signType = "MD5";

/**
 * 微信统一下单接口链接 
 */
public static  String wxOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";

/**
 * 微信支付成功回调
 */
public static  String wxPayCallback= "-------------------------------";
{特注:app微信支付回调只支持域名80默认端口,不支持携带其他端口号}

2.创建Service层

/**
 * 统一下单
 * @throws Exception 
 * */
Map<String, Object> unifiedOrder(Map<String, Object> map, HttpServletRequest request) throws Exception;

3.实现类

//加粗的代码为静态类的代码–可挪至静态类直接调用
@Override
public Map<String, Object> unifiedOrder(Map<String, Object> paramMap, HttpServletRequest request) throws Exception {
//需求参数map,订单参数都在map中
//先判断openid是否是空
String openId = null;
if(null != paramMap.get(“openId”) && null != paramMap.get(“openId”) && paramMap.get(“openId”).toString().length()>0){
openId = paramMap.get(“openId”).toString();
}
//获取到参数中的金额
int totalFee = (int)(Double.parseDouble(paramMap.get(“totalFee”).toString())100);
String noncestr = WxPayUtil.getNonceStr();
{
/
* 获得随机字符串
/
注: 调用的静态类的方法获取字符串
public static String getNonceStr(){
return UUID.randomUUID().toString().replaceAll("-", “”).substring(0, 32);
}

}
//获取时间截
String timestamp = WxPayUtil.getTimeStamp();
{
/**
* 北京时间时间戳
*/
public static String getTimeStamp() {
return String.valueOf(System.currentTimeMillis() / 1000);
}

}
//获取APPiD
logger.info(“支付前获取到配置WxConfig.appId=”+WxConfig.appId);
//创建Map
Map<String, Object> signParams = new HashMap<String, Object>();
//判断是否有openId,如果有则是公众号,没有则直接进入app类型如果只是单纯app支付,此处可省略简写
if(null != paramMap.get(“openId”) && null != paramMap.get(“openId”) && paramMap.get(“openId”).toString().length()>0){
signParams.put(“appid”, WxConfig.appId);//app_id
signParams.put(“mch_id”, WxConfig.partner);//微信商户账号
signParams.put(“trade_type”, WxConfig.tradeTypeJSAPI);//付款类型为JSAPI
signParams.put(“openid”, openId);//openId
}else{
signParams.put(“appid”, WxConfig.appAppId);//app_id
signParams.put(“mch_id”, WxConfig.appPartner);//微信商户账号
signParams.put(“trade_type”, WxConfig.tradeTypeAPP);//付款类型为APP
}
//添加随机字符串
signParams.put(“nonce_str”, noncestr);//32位不重复的编号
//添加商品注明
signParams.put(“body”,“我爱秦岭支付”);//商品参数信息
signParams.put(“attach”, “attachParams”);//支付通知中原样返回,可作为自定义参数使用
//添加订单编号
signParams.put(“out_trade_no”, paramMap.get(“out_trade_no”));//订单编号
//添加支付金额
signParams.put(“total_fee”, String.valueOf(totalFee));//支付金额 单位为分
signParams.put(“spbill_create_ip”, WxPayUtil.getRealIp(request));//请求的实际ip地址
{
/**
* 获取真实IP
*/
public static String getRealIp(HttpServletRequest request) {
if (request == null) {
return “0.0.0.0”;
}
String realIp = request.getHeader(“X-Real-IP”);
if (realIp != null && realIp.length() > 0) {
return realIp;
}
realIp = request.getHeader(“X-Forwarded-For”);
if (realIp != null && realIp.length() > 0) {
return realIp;
}
return request.getRemoteAddr();
}

}
//添加回调地址
signParams.put(“notify_url”, WxConfig.wxPayCallback);//回调页面
String signXML = null;//定义空字符串
//判断是否是app支付还是公众号,如只是app可省略
if(null != paramMap.get(“openId”) && null != paramMap.get(“openId”) && paramMap.get(“openId”).toString().length()>0){
signXML = WxPayUtil.createSignXml(signParams, WxConfig.partnerKey);//生成Xml格式的签名字符串
}else{
signXML = WxPayUtil.createSignXml(signParams, WxConfig.appPartnerKey);//生成Xml格式的签名字符串
}
String result = HttpClientUtil.httpsRequest(WxConfig.wxOrderUrl, “POST”, signXML);//以post请求的方式调用统一下单接口

//返回的result成功结果取出prepay_id
Map<String, Object> map = XMLUtil.xmlToMap(result);
String prepay_id = null;
String return_code = null;
if (map.containsKey(“return_code”)) {
return_code = map.get(“return_code”).toString();
if (return_code.equalsIgnoreCase(“FAIL”)) {
return map;
}else if (return_code.equalsIgnoreCase(“SUCCESS”)) {
boolean signValid = false;
if(null != paramMap.get(“openId”) && null != paramMap.get(“openId”) && paramMap.get(“openId”).toString().length()>0){
signValid = WxPayUtil.signValid(map, WxConfig.partnerKey);
}else{
signValid = WxPayUtil.signValid(map, WxConfig.appPartnerKey);
{
/

* 判断签名是否正确
* @param map
* @param key API密钥
* @return 签名是否正确
* @throws Exception
*/
public static boolean signValid(Map<String, Object> map, String key) throws Exception {
if (!map.containsKey(“sign”) ) {
return false;
}
String sign = map.get(“sign”).toString();
return createSign(map, key).equals(sign);
}

}
}
if (!signValid) {
throw new Exception();
}else {
//获取到prepay_id
prepay_id = map.get(“prepay_id”).toString();
}
}
}

//支付需要的参数 判断是否有openid没有直接进入app支付
Map<String, Object> payParams = new HashMap<>();
Map<String, Object> signAgainParams = new HashMap<String, Object>();
if(null != paramMap.get(“openId”) && null != paramMap.get(“openId”) && paramMap.get(“openId”).toString().length()>0){
signAgainParams.put(“appId”, WxConfig.appId);
signAgainParams.put(“package”, “prepay_id=”+prepay_id);
signAgainParams.put(“timeStamp”, timestamp);
signAgainParams.put(“nonceStr”, noncestr);
signAgainParams.put(“signType”, WxConfig.signType);
//再次进行签名
payParams = XMLUtil.xmlToMap(WxPayUtil.createSignXml(signAgainParams,WxConfig.partnerKey));
{

/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, Object> xmlToMap(String strXML) throws Exception {
try {
Map<String, Object> data = new HashMap<String, Object>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes(“UTF-8”));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}

try {
stream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return data;
} catch (Exception ex) {
throw ex;
}
}

{//BaseHttpSSLSocketFactory类
public class BaseHttpSSLSocketFactory extends SSLSocketFactory {
private SSLContext getSSLContext() {
return createEasySSLContext();
}
**

@Override
public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2,
int arg3) throws IOException {
return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
arg2, arg3);
}

@Override
public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3)
throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
arg2, arg3);
}

@Override
public Socket createSocket(InetAddress arg0, int arg1) throws IOException {
return getSSLContext().getSocketFactory().createSocket(arg0, arg1);
}

@Override
public Socket createSocket(String arg0, int arg1) throws IOException,
UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(arg0, arg1);
}

@Override
public String[] getSupportedCipherSuites() {
// TODO Auto-generated method stub
return null;
}
@Override
public String[] getDefaultCipherSuites() {
// TODO Auto-generated method stub
return null;
}

@Override
public Socket createSocket(Socket arg0, String arg1, int arg2, boolean arg3)
throws IOException {
return getSSLContext().getSocketFactory().createSocket(arg0, arg1,
arg2, arg3);
}

private SSLContext createEasySSLContext() {
try {
SSLContext context = SSLContext.getInstance(“SSL”);
context.init(null,
new TrustManager[] { MyX509TrustManager.manger }, null);
return context;
} catch (Exception e) {
///LogUtil.writeErrorLog(e.getMessage(), e);
return null;
}
}

public static class MyX509TrustManager implements X509TrustManager {

static MyX509TrustManager manger = new MyX509TrustManager();

public MyX509TrustManager() {
}

public X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(X509Certificate[] chain, String authType) {
}

public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
}

/**
* 解决由于服务器证书问题导致HTTPS无法访问的情况 PS:HTTPS hostname wrong: should be
*/
public static class TrustAnyHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
// 直接返回true
return true;
}
}
}

}

/**
* 生成带有 sign 的 XML 格式字符串
* @param data Map类型数据
* @param key API密钥
* @return 含有sign字段的XML
*/
public static String createSignXml(Map<String, Object> map, String key) throws Exception {
String sign = createSign(map, key);
map.put(“sign”, sign);
return XMLUtil.mapToXml(map);
}

}**
}else{
//添加支付参数,并在次签名
signAgainParams.put(“appid”, WxConfig.appAppId);//appId
signAgainParams.put(“partnerid”, WxConfig.appPartner);//app商户号
signAgainParams.put(“prepayid”, prepay_id);//获取到的prepay_id
signAgainParams.put(“package”, “Sign=WXPay”);
signAgainParams.put(“timestamp”, timestamp);//时间截
signAgainParams.put(“noncestr”, noncestr);//随机字符串
Map<String, Object> signAgainResult = XMLUtil.xmlToMap(WxPayUtil.createSignXml(signAgainParams,WxConfig.appPartnerKey));
{
/**
* 生成带有 sign 的 XML 格式字符串
* @param data Map类型数据
* @param key API密钥
* @return 含有sign字段的XML
/
public static String createSignXml(Map<String, Object> map, String key) throws Exception {
String sign = createSign(map, key);
map.put(“sign”, sign);
return XMLUtil.mapToXml(map);

}
/
*
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, Object> xmlToMap(String strXML) throws Exception {
try {
Map<String, Object> data = new HashMap<String, Object>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes(“UTF-8”));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
return data;
} catch (Exception ex) {
throw ex;
}
}

}

//将转换的map文件整合返回出去
payParams.put(“appId”, WxConfig.appAppId);
payParams.put(“partnerId”, signAgainResult.get(“partnerid”));
payParams.put(“prepayId”, signAgainResult.get(“prepayid”));
payParams.put(“package”, signAgainResult.get(“package”));
payParams.put(“timeStamp”, signAgainResult.get(“timestamp”));
payParams.put(“nonceStr”, signAgainResult.get(“noncestr”));
payParams.put(“sign”, signAgainResult.get(“sign”));
}
return payParams;
}

4.控制器层

/**
* 调用统一下单接口,生成prepay_id(预支付订单Id)后,再按扫码、JSAPI、APP等不同场景生成交易串调起支付
/
@ApiOperation(value = “统一下单”, notes = “返回配置信息”)
@ApiImplicitParams({
@ApiImplicitParam(paramType = “query”, name = “out_trade_no”, dataType = “String”, required = true, value = “订单号”, defaultValue = “”),
})
@ApiResponses({
@ApiResponse(code = 400, message = “请求参数没填好”),
@ApiResponse(code = 404, message = “请求路径没有或页面跳转路径不对”)
})
@RequestMapping(value = “/unifiedOrder”, method = RequestMethod.GET)
@ResponseBody
public ResponseEntity unifiedOrder(@RequestParam(“out_trade_no”) String out_trade_no, HttpServletRequest request, HttpServletResponse response) throws Exception {
// response.addHeader(“Access-Control-Allow-Origin”, "
");
//设置跨域访问
response.setHeader(“Access-Control-Allow-Origin”, “");
response.setHeader(“Access-Control-Allow-Methods”, “POST, GET, OPTIONS, DELETE”);
response.setHeader(“Access-Control-Max-Age”, “3600”);
response.addHeader(“Access-Control-Allow-Headers”, "
”);

JsonResult r = new JsonResult();
try {
// 根据初始创建的订单号获取订单详情
QlOrderPay order = orderService.getQlOrderByOutTradeNo(out_trade_no);

if (order == null) {
SortedMap<String, Object> finalpackage = new TreeMap<>();
finalpackage.put(“error”, “out_trade_no not found”);
r.setStatus(“error”);
r.setResult(finalpackage);
return ResponseEntity.ok®;
}
//将订单里的值装入Map
Map<String, Object> paramsMap = new HashMap<String, Object>();
paramsMap.put(“totalFee”,order.getPrice());//预支付金额
paramsMap.put(“userId”, order.getUserId());//token
paramsMap.put(“price”, order.getRealPrice());//预支付金额
paramsMap.put(“amount”, order.getPrice());//真实付款金额
paramsMap.put(“actUserId”, order.getUserId());//token
paramsMap.put(“serviceType”, “app”);
paramsMap.put(“out_trade_no”,order.getOutTradeNo());//订单号
if (null == paramsMap
|| null == paramsMap.get(“totalFee”)
|| 0 == paramsMap.get(“totalFee”).toString().length()
|| 0 == Double.valueOf(paramsMap.get(“totalFee”).toString())) {
throw new Exception("");
}
//获取Map返回的xml参数调用微信支付接口
Map<String, Object> payParams = wxPayService.unifiedOrder(paramsMap, request);
System.out.println(“unifiedOrder返回数据:” + payParams);
r.setStatus(“ok”);
r.setResult(payParams);
}catch (Exception e){
r.setErrMsg(e.getClass().getName() + “:” + e.getMessage());
r.setStatus(“error”);
e.printStackTrace();
}
将微信支付接口返回出去
return ResponseEntity.ok®;
}

5.微信支付回调接口

 /**
 * 支付回调地址
 * @param request
 * @return
 * @throws IOException
 */
@RequestMapping(value = "/json/money/wxpay/succ",
        produces = MediaType.APPLICATION_JSON_VALUE)
public String wxpaySucc(HttpServletRequest request) throws IOException {
    System.out.println("微信支付回调");
    InputStream inStream = request.getInputStream();//获取输入流读取xml
    ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = inStream.read(buffer)) != -1) {
        outSteam.write(buffer, 0, len);
    }
    //将xml文件转换为字符串
    String resultxml = new String(outSteam.toByteArray(), "utf-8");
    System.out.println("返回的xml"+resultxml);
    Map<String, String> params = null;
    try {
    	//将xml文件转换成map
        params = PayCommonUtil.doXMLParse(resultxml);
        System.out.println("返回的map"+params);
    } catch (JDOMException e) {
        e.printStackTrace();
    }
    outSteam.close();
    inStream.close();
    //判断是否支付
    {

/**
* 验证回调签名
* @param map
* @return
*/
public static boolean isTenpaySign(Map<String, String> map) {
String charset = “utf-8”;
String signFromAPIResponse = map.get(“sign”);
if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
System.out.println(“44444API返回的数据签名数据不存在,有可能被第三方篡改!!!”);
return false;
}
System.out.println(“44444服务器回包里面的签名是:” + signFromAPIResponse);
//过滤空 设置 TreeMap
SortedMap<String,String> packageParams = new TreeMap<>();
for (String parameter : map.keySet()) {
String parameterValue = map.get(parameter);
String v = “”;
System.out.println(“4444parameterValue的值是”+parameterValue);
if (null != parameterValue) {
v = parameterValue.trim();
}
packageParams.put(parameter, v);
}
StringBuilder sb = new StringBuilder();
Set es = packageParams.entrySet();
for (Object e : es) {
Map.Entry entry = (Map.Entry) e;
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if (!“sign”.equals(k) && null != v && !"".equals(v)) {
sb.append(k).append("=").append(v).append("&");
}

}
sb.append(“key=”).append(API_KEY);
//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返 回的签名进行比较
//算出签名
String tobesign = sb.toString();
System.out.println(“4444tobesign:”+tobesign);
String resultSign = MD5Util.MD5Encode(tobesign, “utf-8”).toUpperCase();
String tenpaySign = packageParams.get(“sign”).toUpperCase();
System.out.println(“4444tenpaySign:”+tenpaySign);
System.out.println(“4444resultSign:”+resultSign);
return tenpaySign.equals(resultSign);
}
}
if (!PayCommonUtil.isTenpaySign(params)) {
System.out.println(“支付失败了*”);
// 支付失败
return “fail”;
} else {
System.out.println("=付款成功");
String out_trade_no = params.get(“out_trade_no”)//获取订单号;
System.out.println(“out_trade_no ====” + out_trade_no);
String total_fee = params.get(“total_fee”);//获取付款金额
double v = Double.valueOf(total_fee) / 100;
System.out.println(“total_money ====” + v);
try {
Boolean res = orderService.updateQlOrderStatus(out_trade_no, v);
//为订单标的真实付款金额赋值
System.out.println(“修改是否正常:”+res);
if (!res) {
throw new JSONException(“error HTTP 500”);
}
其他用法调用者自行补充
}catch (Exception e){
e.printStackTrace();
}
return “success”;
}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值