springMVC后端接入支付宝,微信

近期项目要求打通支付宝支付和微信支付,所以趟了一趟接入支付的浑水:

支付宝接入流程

è¿éåå¾çæè¿°

微信支付流程

è¿éåå¾çæè¿°

分析完之后就对照官方的文档开始行动了

一:支付宝支付

  1. 打开支付宝
  2. 选择商家平台
  3. 选择手机网站支付如下操作

https://b.alipay.com/signing/productDetail.htm?productId=I1011000290000001001

选择手机网站支付,填写资料

填写后等待审核通过

然后进入开放平台->开发者中心->网页&移动应用,

然后创建应用

然后点击进入查看详情

然后添加手机网站支付功能

然后点击应用信息访问进行开发配置

在配置上图的回调地址和密钥,接下来就是开发了

这里有官方的demo

https://docs.open.alipay.com/270/106291/  

二 、微信支付

接下来介绍微信支付,微信支付没有官方的demo

比较蛋疼,踩过很多的坑

支付宝支付相对接入比较容易,微信支付需要分微信内打开和微信外打开,微信内走公众号支付,微信外走H5支付,刚开始接入的时候发现H5链接在微信内打开支付不了才知道微信内强制走的是公众号支付,这一点不知道可能让你的功能在提测的时候不通过,或者延期

先到微信公众平台

申请开通公众号支付和H5支付

然后配置

 

添加公众号授权,然后就是接入开发了

微信或者支付宝下单/支付回调

PayController.java

 

package com.lebo.pay.controller;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.lebo.pay.controller.BaseController;
import com.lebo.pay.entity.OpenIdClass;
import com.lebo.pay.entity.Order;
import com.lebo.pay.entity.WechatUnifiedOrder;
import com.lebo.pay.service.AlipayTradeService;
import com.lebo.pay.service.WechatTradeService;
import com.lebo.pay.service.impl.OrderService;
import com.lebo.util.PageData;
import com.lebo.util.RedisUtil;
import com.lebo.util.ResultUtil;
import com.lebo.util.StatusEnum;
import com.lebo.util.StringUtil;
import com.lebo.util.UIDUtil;
import com.lebo.util.XmlUtil;

/**
 * 
 * @ClassName:  PayController   
 * @author chenrui
 * @QQ:	914221084
 * @date:   2018年6月12日 下午8:46:18   
 */
@Controller
@RequestMapping("/pay")
public class PayController extends BaseController{
	private static Logger logger = Logger.getLogger(PayController.class);
	 
	@Autowired
	private AlipayTradeService alipayTradeService; 
	 
	@Autowired
	private WechatTradeService wechatTradeService; 
	
	@Autowired
	private OrderService orderService; 
	
	/*
	 * 微信或者支付宝支付下单
	 */
	@RequestMapping(value="/unifiedOrder")
	@ResponseBody
	public Object unifiedOrder(Order order,Model model){
		ResultUtil reUtil = new ResultUtil(StatusEnum.SUCCESS.getCode(), StatusEnum.SUCCESS.getMessage());
		String outTradeNo = order.getOutTradeNo();
		if(StringUtils.isBlank(outTradeNo)){
			reUtil.setCodeAndMessage(StatusEnum.ORDERNO_IS_CANNOT_NULL.getCode(), StatusEnum.ORDERNO_IS_CANNOT_NULL.getMessage());
			return reUtil;
		}
		if("P".equals(RedisUtil.getStr(outTradeNo+"status"))){
			reUtil.setCodeAndMessage(StatusEnum.ORDER_HAVE_PAY.getCode(), StatusEnum.ORDER_HAVE_PAY.getMessage());
			return reUtil;
		}
		
		order.setStatus("w");
		if("w".equals(RedisUtil.getStr(outTradeNo+"status"))){
			String orderStr = (String) RedisUtil.getStr("order"+outTradeNo);
			if(StringUtils.isNoneBlank(orderStr)){
				TreeMap<String,String> prepareH5Pay = (TreeMap<String, String>) JSON.parseObject(orderStr, TreeMap.class);
				reUtil.setData(prepareH5Pay);
				return reUtil;
			}
		}
		if(StringUtils.isNotBlank(order.getIp())){
			if(StringUtil.isInnerIp(order.getIp())){
				reUtil.setCodeAndMessage(StatusEnum.IP_IS_WRONG.getCode(), StatusEnum.IP_IS_WRONG.getMessage());
			}
		}
		
		if(RedisUtil.tryLock(outTradeNo,15)){
			try {
				if(StringUtils.isBlank(order.getPayType())){
					order.setPayType("weChat");
				}
				order.setPayId(UIDUtil.getUUID());
				orderService.insertOrder(order);
				RedisUtil.putObj("order"+outTradeNo,JSON.toJSONString(order),(int) TimeUnit.DAYS.toSeconds(10));
			} catch (Exception e1) {
				reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
				logger.error("支付失败:params"+JSON.toJSONString(order)+","+e1.getMessage());
				return reUtil;
			}
			if("weChat".equals(order.getPayType())){
				WechatUnifiedOrder wechatOrder = new WechatUnifiedOrder();
				String isWxbrowser = (String) getRequest().getParameter("isWxbrowser");
				if("true".equals(isWxbrowser)){
					String code = (String) getRequest().getParameter("code");
					logger.info("支付失败:code="+code+"isWxbrowser="+isWxbrowser);
					wechatOrder.setTrade_type("JSAPI");
					try {
						OpenIdClass openData  = wechatTradeService.getOpenId(code);
						if(openData==null){
							reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
							return reUtil;
						}
						wechatOrder.setOpenid(openData.getOpenid());
					} catch (Exception e) {
						reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
						logger.error("获取openid失败:params"+JSON.toJSONString(order)+","+e.getMessage());
						return reUtil;
					}
				}
				wechatOrder.setBody(order.getBody());
				wechatOrder.setDetail(order.getDetail());
				wechatOrder.setGoods_tag(order.getGoodsTag());
				wechatOrder.setOut_trade_no(outTradeNo);
				wechatOrder.setFee_type("CNY");
				wechatOrder.setTotal_fee((int)(order.getTotalAmount()*100));
				if(StringUtils.isBlank(order.getIp())){
					wechatOrder.setSpbill_create_ip("119.139.197.202");
				}else{
					wechatOrder.setSpbill_create_ip(order.getIp());
				}
				wechatOrder.setTime_start(System.currentTimeMillis()+"");
				wechatOrder.setLimit_pay("cera");
				wechatOrder.setTime_expire(order.getTimeExpire());
				//TODO  生成预付单   
				try {
					TreeMap<String,String> data = wechatTradeService.unifiedOrderRequest(wechatOrder);
					if(data!=null) {
						reUtil.setData(data);
					}else {
						reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
					}
					
				} catch (Exception e) {
					reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_EXCEPTION.getCode(), StatusEnum.PREPARORDER_EXCEPTION.getMessage());
					logger.error("支付失败:params"+JSON.toJSONString(order)+","+e.getMessage());
				}
			}else{
				try {
			        Map<String,String> paraMap = new HashMap<String,String>();
			        paraMap.put("out_trade_no",outTradeNo);
			        paraMap.put("total_amount",String.valueOf(order.getTotalAmount()));
			        paraMap.put("subject",order.getBody());
			        paraMap.put("body",order.getDetail());
			        paraMap.put("product_code","QUICK_WAP_PAY");
			        String resultStr = alipayTradeService.TradeWapPayRequest(paraMap);
			        if(resultStr!=null) {
						reUtil.setData(resultStr);
					}else {
						reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
					}
				} catch (Exception e) {
					reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_EXCEPTION.getCode(), StatusEnum.PREPARORDER_EXCEPTION.getMessage());
					logger.error("支付失败:params"+JSON.toJSONString(order)+","+e.getMessage());
				}
			}	
		}else{
			reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_IS_PRODUCTING.getCode(), StatusEnum.PREPARORDER_IS_PRODUCTING.getMessage());
		}
		
		logger.info("接口結果:json:"+JSON.toJSONString(reUtil));
		return  reUtil;
	}
	
	
	
	/*
	 * 微信支付成功回调
	 */
	@RequestMapping(value="/wechatNotify")
	@ResponseBody
	public Object wechatNotify(HttpServletRequest request){
		PageData pd = new PageData(request);
		Map<String,String> return_data = new HashMap<String,String>();
		
		try {
			logger.info("access to wechatNotify");
			if(wechatTradeService.verifyNotify(request)) {
				return_data.put("return_code", "SUCCESS");  
                return_data.put("return_msg", "OK");  
			}else {
				return_data.put("return_code", "FAIL");  
                return_data.put("return_msg", "return_code不正确");  
			}

		} catch (Exception e) {
			return_data.put("return_code", "FAIL");  
            return_data.put("return_msg", "支付回调异常");  
			logger.error("支付失败:params"+JSON.toJSONString(pd)+","+e.getMessage());
		}
		
		return  XmlUtil.GetMapToXML(return_data);
	}
	
	
	/*
	 * 支付宝支付成功回调
	 */
	
	
	@RequestMapping(value="/alipayNotify")
	@ResponseBody
	public Object alipayNotify(HttpServletRequest request){
		PageData pd = new PageData(request);
		logger.info("access to alipayNotify");
		String result = "success";
		try {
			if(alipayTradeService.verifyNotify(request)) {
				logger.info("支付成功:params"+JSON.toJSONString(pd));
			}else {
				result = "fail";
				logger.error("支付失败:params"+JSON.toJSONString(pd)+",支付回调失败");
			}

		} catch (Exception e) {
			result = "fail";
			logger.error("支付失败:params"+JSON.toJSONString(pd)+","+e.getMessage());
		}
		
		return  result;
	}
	
	
	/*
	 * 获取公众号相关的用户信息
	 */
	@RequestMapping(value="/getOpenid")
	@ResponseBody
	public Object getOpenid(HttpServletRequest request){
		PageData pd = new PageData(request);
		ResultUtil reUtil = new ResultUtil(StatusEnum.SUCCESS.getCode(), StatusEnum.SUCCESS.getMessage());
		Map<String, Object> data = new HashMap<String, Object>();
		logger.info("access to getOpenid");
		
		String url = request.getRequestURI();
		logger.info("request url : " + url);


		Enumeration<String> em = request.getParameterNames();
		while (em.hasMoreElements()) {
			String nameParam = em.nextElement();
			String valueParam = request.getParameter(nameParam);
			data.put(nameParam, valueParam);
			logger.info(nameParam + " = " + valueParam);

		}
		String result = "success";
		try {
			if(StringUtils.isBlank(pd.getString("code"))){
				reUtil.setCodeAndMessage(StatusEnum.VALIDATION_FAIL.getCode(), StatusEnum.VALIDATION_FAIL.getMessage());
				return reUtil;
			}
			OpenIdClass openData  = wechatTradeService.getOpenId(pd.getString("code"));
			if(openData!=null) {
				data.put("openid", openData.getOpenid());
				data.put("access_token", openData.getAccess_token());
				data.put("refresh_token", openData.getRefresh_token());
				data.put("scope", openData.getScope());
				data.put("unionid", openData.getUnionid());
				reUtil.setData(data);
			}else {
				reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_FAIL.getCode(), StatusEnum.PREPARORDER_FAIL.getMessage());
			}
			
		} catch (Exception e) {
			reUtil.setCodeAndMessage(StatusEnum.PREPARORDER_EXCEPTION.getCode(), StatusEnum.PREPARORDER_EXCEPTION.getMessage());
			logger.error("获取openId失败:params"+JSON.toJSONString(pd)+","+e.getMessage());
		}
		
		return  result;
	}
	
	/*
	 * 获取订单状态
	 */
	@RequestMapping(value="/getOrderStatus")
	@ResponseBody
	public Object getOrderStatus(HttpServletRequest request){
		PageData pd = new PageData(request);
		ResultUtil reUtil = new ResultUtil(StatusEnum.SUCCESS.getCode(), StatusEnum.SUCCESS.getMessage());
		Map<String, Object> data = new HashMap<String, Object>();
		
		String outTradeNo = pd.getString("outTradeNo");
		if(StringUtils.isBlank(pd.getString("outTradeNo"))){
			reUtil.setCodeAndMessage(StatusEnum.VALIDATION_FAIL.getCode(), StatusEnum.VALIDATION_FAIL.getMessage());
			return reUtil;
		}
		
		data.put("status", RedisUtil.getStr(outTradeNo+"status"));
		reUtil.setData(data);
		
		return  reUtil;
	}
	
}

微信支付service

WechatTradeServiceImpl .java

package com.lebo.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.lebo.pay.config.WechatConfig;
import com.lebo.pay.entity.AccessToken;
import com.lebo.pay.entity.OpenIdClass;
import com.lebo.pay.entity.Order;
import com.lebo.pay.entity.WechatPayNotify;
import com.lebo.pay.entity.WechatRefund;
import com.lebo.pay.entity.WechatRefundQuery;
import com.lebo.pay.entity.WechatUnifiedOrder;
import com.lebo.pay.entity.WxTicket;
import com.lebo.pay.service.WechatTradeService;
import com.lebo.util.HttpUtil;
import com.lebo.util.RedisUtil;
import com.lebo.util.SignUtil;
import com.lebo.util.WebUtils;
import com.lebo.util.XmlUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;


/**
 * 微信交易
 * @author chenrui
 * @date 2018/06/11
 */
@Service
public class WechatTradeServiceImpl implements WechatTradeService{

    private static Logger logger = LoggerFactory.getLogger(WechatTradeServiceImpl.class);
   
	
	@Autowired
	private OrderService orderService; 
    /**
     * 微信统一下单
     * @param unifiedOrder 要下单的内容
     * @return 返回H5下单请求需要内容
     */
    public TreeMap<String,String> unifiedOrderRequest(WechatUnifiedOrder unifiedOrder){
        WechatUnifiedOrder.Response response =  WechatConfig.getInstance().unifiedOrder(unifiedOrder);
        if (response.getResult_code().equals(WechatConfig.SUCCESS_REQUEST)){
            TreeMap<String,String> prepareH5Pay = new TreeMap<String, String>();
            prepareH5Pay.put("appId", WechatConfig.APP_ID);
            prepareH5Pay.put("nonceStr", WechatConfig.getInstance().nonce_str(16));
            if("JSAPI".equals(unifiedOrder.getTrade_type())){
            	prepareH5Pay.put("package", "prepay_id="+response.getPrepay_id());
            }else{
            	prepareH5Pay.put("partnerId", WechatConfig.MCH_ID);
            	prepareH5Pay.put("package", "Sign=WXPay");
            	prepareH5Pay.put("prepayId",response.getPrepay_id());
            }
            prepareH5Pay.put("signType", "MD5");
            prepareH5Pay.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
            prepareH5Pay.put("sign", WechatConfig.getInstance().sign(prepareH5Pay));
            prepareH5Pay.put("mweburl",response.getMweb_url());
            
            RedisUtil.putObj("order"+unifiedOrder.getOut_trade_no(), JSON.toJSONString(prepareH5Pay), 120);
            RedisUtil.putObj(unifiedOrder.getOut_trade_no()+"status", "w", 120);
            return prepareH5Pay;
        }
        return null;
    }

    /**
     * 微信退款请求
     * @param refund 退款请求参数
     * @return 返回参数(同步接口,直接返回),只有return_code和result_code都成功则退款成功
     */
    public WechatRefund.Response refundRequest(WechatRefund refund){
        WechatRefund.Response response = WechatConfig.getInstance().refund(refund);
        return response;
    }
    /**
     * 微信退款查询请求
     * @param refund 退款请求参数
     * @return 返回参数(同步接口,直接返回),只有return_code和result_code都成功则查询成功
     */
    public WechatRefundQuery.Response refundQueryRequest(WechatRefundQuery refund){
        WechatRefundQuery.Response response = WechatConfig.getInstance().refundQuery(refund);
        return response;
    }

    /**
     * 微信回调验签
     * @param request  回调请求
     * @return true成功
     */
    @SuppressWarnings("unchecked")
	public boolean verifyNotify(HttpServletRequest request){
        try {
            InputStream inputStream = request.getInputStream();
            WechatPayNotify notice = XmlUtil.xmlToBean(inputStream, WechatPayNotify.class);
            //更新预付单状态
            if (notice == null) return false;
            logger.debug("微信回调参数:"+ JSON.toJSONString(notice));
            String sign = WechatConfig.getInstance().sign(SignUtil.bean2TreeMap(notice));
            boolean ischeck = sign.equals(notice.getSign());
            if(ischeck){
            	RedisUtil.putObj(notice.getOut_trade_no()+"status", "P",(int) TimeUnit.DAYS.toSeconds(10));
	            Order order = new Order();
	            order.setOutTradeNo(notice.getOut_trade_no());
	            order.setStatus("p");
	            try {
					orderService.updateOrder(order);
					order = (Order) RedisUtil.getObj("order"+notice.getOut_trade_no());
					if(order==null){
						order =orderService.getOrder(notice.getOut_trade_no());
					}
					Map<String,Object>  parameterMap = new HashMap<String,Object>();
					parameterMap.put("outTradeNo", notice.getOut_trade_no());
					parameterMap.put("userId",order.getUserId());
					parameterMap.put("payType","weChat");
					String result = WebUtils.post(order.getNotifyUrl(), parameterMap);
					Map<String,String> resultMap = (Map<String, String>) JSON.parseObject(result, Map.class);
					logger.info(order.getNotifyUrl()+"接口結果:json:"+JSON.toJSONString(result));
					if("00".equals(resultMap.get("code"))){
						ischeck = true;
					}else{
						ischeck = false;
					}
				} catch (Exception e) {
					 logger.error("订单更新失败:"+ JSON.toJSONString(notice));
					 ischeck = false;
				}
	            logger.debug("微信验签结果:"+ischeck);
            }
            return ischeck;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    
 // 获取access_token的接口地址(GET) 限200(次/天)  
    public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";  
    public final static String ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card";  
    public final static String auth_url = "https://api.weixin.qq.com/card/invoice/getauthurl?access_token=ACCESS_TOKEN";  

    /** 
     * 获取access_token 
     *  
     * @param appid 凭证 
     * @param appsecret 密钥 
     * @return 
     */  
    public static AccessToken getAccessToken() {  
        AccessToken accessToken = null;  
      
        String requestUrl = ticket_url.replace("ACCESS_TOKEN", WechatConfig.APP_ID).replace("APPSECRET", WechatConfig.APP_SECRET);  
        String jsonStr = WebUtils.get(requestUrl, null) ;
        // 如果请求成功  
        if (null != jsonStr) {  
            try {  
            	JSONObject jsonObject = JSONObject.parseObject(jsonStr);
                accessToken = new AccessToken();  
                accessToken.setToken(jsonObject.getString("access_token"));  
                accessToken.setExpiresIn(jsonObject.getIntValue("expires_in"));  
            } catch (JSONException e) {  
                accessToken = null;  
                // 获取token失败  
                logger.error("获取token失败 errcode:{} errmsg:{}",jsonStr);  
            }  
        }  
        return accessToken;  
    }  

    
    public static WxTicket getTickect(AccessToken  accessToken) {  
    	WxTicket wxTicket = null;  
      
    	if(accessToken==null){
    		logger.error("获取wxTicket失败 ");  
    		return wxTicket;
    	}
        String requestUrl = ticket_url.replace("ACCESS_TOKEN", accessToken.getToken());  
        String jsonStr = WebUtils.get(requestUrl, null) ;
        // 如果请求成功  
        if (null != jsonStr) {  
            try {  
            	JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            	wxTicket = new WxTicket();  
            	wxTicket.setTicket(jsonObject.getString("ticket")); 
            	wxTicket.setExpiresIn(jsonObject.getIntValue("expires_in"));  
            } catch (JSONException e) {  
            	wxTicket = null;  
                // 获取token失败  
                logger.error("获取token失败 errcode:{} errmsg:{}",jsonStr);  
            }  
        }  
        return wxTicket;  
    }  
    
    
    public String  getAuth(Order order) {  
    	String auth = null;  
    	AccessToken accessToken = getAccessToken();  
    	
    	WxTicket wxTicket = getTickect(accessToken) ;
    	
    	if(wxTicket==null){
    		logger.error("获取wxTicket失败 ");  
    		return auth;
    	}
        String requestUrl = auth_url.replace("ACCESS_TOKEN", accessToken.getToken());  
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("s_pappid", "");//开票平台在微信的标识号,商户需要找开票平台提供
        params.put("order_id", order.getOutTradeNo());//订单id,在商户内单笔开票请求的唯一识别号,
        params.put("money", (int)(order.getTotalAmount()*100));//订单金额,以分为单位
        params.put("timestamp", String.valueOf(System.currentTimeMillis() /1000));//时间戳
        params.put("source", "wap");//开票来源,app:app开票,web:微信h5开票,wxa:小程序开发票,wap:普通网页开票
        params.put("redirect_url", "");//授权成功后跳转页面。本字段只有在source为H5的时候需要填写,引导用户在微信中进行下一步流程。app开票因为从外部app拉起微信授权页,授权完成后自动回到原来的app,故无需填写。
        params.put("ticket", wxTicket.getTicket());//从上一环节中获取
        params.put("type", "1");//授权类型,0:开票授权,1:填写字段开票授权,2:领票授权
        String jsonStr = WebUtils.post(requestUrl, params);
        // 如果请求成功  
        if (null != jsonStr) {  
            try {  
            	JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            	auth = jsonObject.getString("auth_url");
            } catch (JSONException e) {  
            	wxTicket = null;  
                // 获取token失败  
                logger.error("获取auth失败 errcode:{} errmsg:{}",jsonStr);  
            }  
        }  
        return auth;  
    }  
    
    @Override
    public OpenIdClass getOpenId(String code) throws Exception {
    	logger.info("************************getOpenId*********************");
    	logger.info("+++++++++++" + code + "++++++++++");
		if (code != null) {

			// 狗日的微信又是必须要https请求,千万不要搞错了
			String url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
					+ "appid="+WechatConfig.APP_ID
					+ "&secret="+WechatConfig.OFFICAL_ACCOUNT_SECRET + "&code="
					+ code + "&grant_type=authorization_code";
			logger.info("url="+url);
			String returnData = HttpUtil.loadJSON(url);
			logger.info("returnData="+returnData + "################");
			OpenIdClass  openIdClass  = JSON.parseObject(returnData,OpenIdClass.class);  

			if (openIdClass.getOpenid() != null) {
				return openIdClass;
			}
		}
		return null;
	}
   
}

支付宝支付service

AlipayTradeServiceImpl.java

package com.lebo.pay.service.impl;


import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.lebo.pay.config.AliPayConfig;
import com.lebo.pay.entity.Order;
import com.lebo.pay.service.AlipayTradeService;
import com.lebo.util.RedisUtil;
import com.lebo.util.SignUtil;
import com.lebo.util.WebUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

/**
 * 支付宝交易类
 * @author chenrui
 * @date 2018/06/11
 */
@Service
public class AlipayTradeServiceImpl  implements  AlipayTradeService{

    private Logger logger = LoggerFactory.getLogger(AlipayTradeServiceImpl.class);

	
	@Autowired
	private OrderService orderService; 
    /**
     * web支付下单并支付(web支付在安卓中是可以直接唤醒支付宝APP的)
     * url https://doc.open.alipay.com/doc2/detail.htm?treeId=203&articleId=105463&docType=1#s1
     * @return web支付的表单
     */
    public String TradeWapPayRequest(Map<String, String> sParaTemp){
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
        alipayRequest.setReturnUrl(AliPayConfig.RETURN_URL);
        alipayRequest.setNotifyUrl(AliPayConfig.PAY_NOTIFY);
        // 待请求参数数组
        sParaTemp.put("seller_id",AliPayConfig.SELLER_ID);
        alipayRequest.setBizContent(JSON.toJSONString(sParaTemp));
        String form = "";
        try {
            form = AliPayConfig.getInstance().pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            logger.error("支付宝构造表单失败",e);
        }
        logger.debug("支付宝支付表单构造:"+form);
        return form;
    }

    /**
     * 申请退款
     * @param sParaTemp 退款参数
     * @return true成功,回调中处理
     * 备注:https://doc.open.alipay.com/docs/api.htm?spm=a219a.7629065.0.0.3RjsEZ&apiId=759&docType=4
     */
    public boolean tradeRefundRequest(Map<String, ?> sParaTemp) throws AlipayApiException {
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setReturnUrl(AliPayConfig.RETURN_URL);
        request.setNotifyUrl(AliPayConfig.REFUND_NOTIFY);
        // 待请求参数数组
        request.setBizContent(JSON.toJSONString(sParaTemp));
        AlipayTradeRefundResponse response = AliPayConfig.getInstance().execute(request);
        logger.debug("支付宝退货结果:"+response.isSuccess());
        return response.isSuccess();
    }

    /**
     * 支付宝回调验签
     * @param request 回调请求
     * @return true成功
     * 备注:验签成功后,按照支付结果异步通知中的描述(二次验签接口,貌似称为历史接口了)
     */
    public boolean verifyNotify(HttpServletRequest request) throws AlipayApiException {
        Map<String,String> paranMap = SignUtil.request2Map(request);
        logger.debug("支付宝回调参数:"+paranMap.toString());
        boolean isVerify = false;
        if (AliPayConfig.SUCCESS_REQUEST.equals(paranMap.get("trade_status")) || AliPayConfig.TRADE_CLOSED.equals(paranMap.get("trade_status"))) {
            isVerify = AlipaySignature.rsaCheckV1(paranMap, AliPayConfig.ALIPAY_PUBLIC_KEY, AliPayConfig.CHARSET,AliPayConfig.SIGN_TYPE); //调用SDK验证签名
        	if(isVerify){
	            String orderNo = paranMap.get("out_trade_no");
	            RedisUtil.putObj(orderNo+"status", "P",(int) TimeUnit.DAYS.toSeconds(10));
	            Order order = new Order();
	            order.setOutTradeNo(orderNo);
	            order.setStatus("p");
	            try {
					orderService.updateOrder(order);
					order = (Order) RedisUtil.getObj("order"+orderNo);
					if(order==null){
						order =orderService.getOrder(orderNo);
					}
					Map<String,Object>  parameterMap = new HashMap<String,Object>();
					parameterMap.put("outTradeNo", orderNo);
					parameterMap.put("userId",order.getUserId());
					parameterMap.put("payType","alipay");
					String result = WebUtils.post(order.getNotifyUrl(), parameterMap);
					logger.info(order.getNotifyUrl()+"接口結果:json:"+JSON.toJSONString(result));
					Map<String,String> resultMap = (Map<String, String>) JSON.parseObject(result, Map.class);
					if("00".equals(resultMap.get("code"))){
						isVerify =true;
					}else{
						isVerify =false;
					}
					
	            }catch(Exception e){
	            	logger.error("verifyNotify error:"+e.getMessage());
	            	isVerify =false;
	            }
        	}
        }
        logger.debug("支付宝验签结果"+isVerify);
        return isVerify;
    }
}

支付宝下单后生产预付单,接口会生成form数据,通过js自动提交(<form> ...submit</form>)

微信支付分为H5支付和公众号支付

H5支付在微信内是不能支付支付成功的,微信会强制在微信内用微信公众号支付,这样就少不了走公众号支付那一套,这里严重吐槽一下,

进入前页面后要判断是在微信内还是为微信外,微信内就要用

http://open.weixin.qq.com/connect/oauth2/authorize拿取授权码,因为公众号支付需要openId,而openId需要通过授权code获得,拿到授权code就可以调用jssdk支付了,在微信外走H5支付为调用接口生成预付单后微信会生成一个字段mweburl,这个是一个url,通过这个地址就可以唤起微信支付了,但是要传入refer如果你直接点击能想办法传过去也是可以的,我这里采用的方法是在页面内绑定点击事件,它传过去的时候就会解析到refer了,不传的话会报商家配置参数有误,

然后贴上html代码,供大家参考

wxpayDemo2.html(微信支付(融合H5支付、公众号支付))

<!DOCTYPE html>
<html>
	<head>
	<title>微信手机网站支付接口页面demo</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
    *{
        margin:0;
        padding:0;
    }
    ul,ol{
        list-style:none;
    }
    body{
        font-family: "Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
    }
    .hidden{
        display:none;
    }
    .new-btn-login-sp{
        padding: 1px;
        display: inline-block;
        width: 75%;
    }
    .new-btn-login {
        background-color: #02aaf1;
        color: #FFFFFF;
        font-weight: bold;
        border: none;
        width: 100%;
        height: 30px;
        border-radius: 5px;
        font-size: 16px;
    }
    #main{
        width:100%;
        margin:0 auto;
        font-size:14px;
    }
    .red-star{
        color:#f00;
        width:10px;
        display:inline-block;
    }
    .null-star{
        color:#fff;
    }
    .content{
        margin-top:5px;
    }
    .content dt{
        width:100px;
        display:inline-block;
        float: left;
        margin-left: 20px;
        color: #666;
        font-size: 13px;
        margin-top: 8px;
    }
    .content dd{
        margin-left:120px;
        margin-bottom:5px;
    }
    .content dd input {
        width: 85%;
        height: 28px;
        border: 0;
        -webkit-border-radius: 0;
        -webkit-appearance: none;
    }
    #foot{
        margin-top:10px;
        position: absolute;
        bottom: 15px;
        width: 100%;
    }
    .foot-ul{
        width: 100%;
    }
    .foot-ul li {
        width: 100%;
        text-align:center;
        color: #666;
    }
    .note-help {
        color: #999999;
        font-size: 12px;
        line-height: 130%;
        margin-top: 5px;
        width: 100%;
        display: block;
    }
    #btn-dd{
        margin: 20px;
        text-align: center;
    }
    .foot-ul{
        width: 100%;
    }
    .one_line{
        display: block;
        height: 1px;
        border: 0;
        border-top: 1px solid #eeeeee;
        width: 100%;
        margin-left: 20px;
    }
    .am-header {
        display: -webkit-box;
        display: -ms-flexbox;
        display: box;
        width: 100%;
        position: relative;
        padding: 7px 0;
        -webkit-box-sizing: border-box;
        -ms-box-sizing: border-box;
        box-sizing: border-box;
        background: #1D222D;
        height: 50px;
        text-align: center;
        -webkit-box-pack: center;
        -ms-flex-pack: center;
        box-pack: center;
        -webkit-box-align: center;
        -ms-flex-align: center;
        box-align: center;
    }
    .am-header h1 {
        -webkit-box-flex: 1;
        -ms-flex: 1;
        box-flex: 1;
        line-height: 18px;
        text-align: center;
        font-size: 18px;
        font-weight: 300;
        color: #fff;
    }
</style>
</head>
<script src="./js/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="./js/qrcode.min.js" type="text/javascript"></script>

<div style="display: none;margin-top: 20px;">
	<a id="getBrandWCPayRequest" href="#" style="font-size:40px;">H5非微信app支付</a>移动端,非微信app使用<br>
</div>

<div id="qrcode" style="display: none;margin-top: 20px;"><a id="getBrandWCPayRequest" href="#" style="font-size:40px;">H5非微信app支付</a>移动端,非微信app使用<br>
</div>
<script>

    var appId = "";
    var timeStamp = "";
    var nonceStr = "";
    var pg = "";
    var signType = "";
    var paySign = "";
	var openid = "";
	var code  = "";
	
	function getQueryString(name) { 
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 
        var r = window.location.search.substr(1).match(reg); 
        if (r != null) return unescape(r[2]); 
        return null; 
    } 
	
	
    function getOpenId(){
    	var isWxbrowser = isWeiXin();
    	if(isWxbrowser){
    		code = getQueryString("code")
    		
    		if(code==null||code==undefined||code==""){
        		//获取openid
        	    window.location.href="http://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxx&redirect_uri=http://xxx/payDemo/wxpayDemo2.html&response_type=code&scope=snsapi_base&state=wxpay#wechat_redirect";
        	}
    	}
    	
    	
    	
    }
    
	$(function(){
	    getOpenId();
	})
	
    function createWxH5Pay(){
    	var isWxbrowser = isWeiXin();
    	var data = "body="+$("#body1").val()+"&detail="+$("#detail").val()+"&outTradeNo="+$("#outTradeNo").val()+"&totalAmount="+$("#totalAmount").val()+"&payType="+$("#payType").val()+"&isWxbrowser="+isWxbrowser+"&code="+code;
    	var outTradeNo = $("#outTradeNo").val();
    	if(outTradeNo==null||outTradeNo==undefined||outTradeNo==""){
    		//处理
    		alert("商户订单号不能为空");
    		return;
    	}
    	
    	var body1 = $("#body1").val();
    	if(body1==null||body1==undefined||body1==""){
    		//处理
    		alert("订单名称不能为空");
    		return;
    	}
    	
    	var totalAmount = $("#totalAmount").val();
    	if(totalAmount==null||totalAmount==undefined||totalAmount==""){
    		//处理
    		alert("付款金额不能为空");
    		return;
    	}
    	
    	var detail = $("#detail").val();
    	if(detail==null||detail==undefined||detail==""){
    		//处理
    		alert("商品描述不能为空");
    		return;
    	}
    	$.ajax({
            url: '/payDemo/pay/unifiedOrder.do',
            type: 'post',
            cache:false,
            async:false,
			data:  data,
            dataType: 'JSON',
            timeout: 5000,
            success: function(data){
                console.log("data="+data.prepayid);
                if(data!=null){
                	if(data.code!="00")alert(data.code+data.message);
					appId = data.data.appId;
					timeStamp = data.data.timeStamp;
					nonceStr = data.data.nonceStr;
					pg =  data.data.package;
					signType = "MD5";
					paySign = data.data.sign;
					if(!isWeiXin()){
					    $("#getBrandWCPayRequest").attr("href",data.data.mweburl);
						document.getElementById("getBrandWCPayRequest").click();
					}else{
						pay();
					}
					
                }
            }
        });
    }

	
	 function isWeiXin(){
        var ua = window.navigator.userAgent.toLowerCase();
        if(ua.match(/MicroMessenger/i) == 'micromessenger'){
            return true;
        }else{
            return false;
        }
    }
	
	    //开始支付
    function onBridgeReady(){
        console.log("-------------------------------->>>>:")
        WeixinJSBridge.invoke(
            'getBrandWCPayRequest', {
                "appId" : appId,     //公众号名称,由商户传入
                "timeStamp": timeStamp+"",         //时间戳,自1970年以来的秒数
                "nonceStr" : nonceStr, //随机串
                "package" : pg,
                "signType" : signType,         //微信签名方式:
                "paySign" : paySign    //微信签名
            },

            function(res){
                if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                    alert("支付成功");  // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
                }else if (res.err_msg == "get_brand_wcpay_request:cancel")  {
                    alert("支付过程中用户取消");
                }else{
                    //支付失败
                   // alert("appId="+appId+",timestamp="+timeStamp+",nonceStr="+nonceStr+",package="+pg+",signType="+signType+",paySign="+paySign);

                    alert(res.err_msg)
                }
            }
        );
    }

    //唤起微信支付
    function pay(){
    	    	
        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();
        }

    }

 
</script>

<body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4>
<header class="am-header">
        <h1>微信手机网站支付接口快速通道</h1>
</header>
<div id="main">
            <div id="body" style="clear:left">
                <dl class="content">
                    <dt>商户订单号(*):</dt>
                    <dd>
                        <input id="outTradeNo" name="outTradeNo" />
                    </dd>
                    <hr class="one_line">
                    <dt>订单名称(*):</dt>
                    <dd>
                        <input id="body1" name="body1" />
                    </dd>
                    <hr class="one_line">
                    <dt>付款金额(*):</dt>
                    <dd>
                        <input id="totalAmount" name="totalAmount" />
                    </dd>
                    <hr class="one_line"/>
                    <dt>商品描述(*):</dt>
                    <dd>
                        <input id="detail" name="detail" />
                    </dd>
                    <dt></dt>
                     <dd>
                        <input type="hidden"  id="payType" name="payType" value="weChat" />
                    </dd>
                    <hr class="one_line">
                    <dt></dt>
                    <dd id="btn-dd">
                        <span class="new-btn-login-sp">
                            <button class="new-btn-login"  onclick='createWxH5Pay(this);'  style="text-align:center;">确 认</button>
                        </span>
                        <span class="note-help">如果您点击“确认”按钮,即表示您同意该次的执行操作。</span>
                    </dd>
                </dl>
            </div>
        <div id="foot">
			<ul class="foot-ul">
				<li>
					深圳市xxxxx公司版权所有  2015-2018 
				</li>
			</ul>
		</div>
	</div>
</body>

</html>

alipayDemo.html(支付宝支付)

<!DOCTYPE html>
<html>
	<head>
	<title>支付宝手机网站支付接口</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
    *{
        margin:0;
        padding:0;
    }
    ul,ol{
        list-style:none;
    }
    body{
        font-family: "Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
    }
    .hidden{
        display:none;
    }
    .new-btn-login-sp{
        padding: 1px;
        display: inline-block;
        width: 75%;
    }
    .new-btn-login {
        background-color: #02aaf1;
        color: #FFFFFF;
        font-weight: bold;
        border: none;
        width: 100%;
        height: 30px;
        border-radius: 5px;
        font-size: 16px;
    }
    #main{
        width:100%;
        margin:0 auto;
        font-size:14px;
    }
    .red-star{
        color:#f00;
        width:10px;
        display:inline-block;
    }
    .null-star{
        color:#fff;
    }
    .content{
        margin-top:5px;
    }
    .content dt{
        width:100px;
        display:inline-block;
        float: left;
        margin-left: 20px;
        color: #666;
        font-size: 13px;
        margin-top: 8px;
    }
    .content dd{
        margin-left:120px;
        margin-bottom:5px;
    }
    .content dd input {
        width: 85%;
        height: 28px;
        border: 0;
        -webkit-border-radius: 0;
        -webkit-appearance: none;
    }
    #foot{
        margin-top:10px;
        position: absolute;
        bottom: 15px;
        width: 100%;
    }
    .foot-ul{
        width: 100%;
    }
    .foot-ul li {
        width: 100%;
        text-align:center;
        color: #666;
    }
    .note-help {
        color: #999999;
        font-size: 12px;
        line-height: 130%;
        margin-top: 5px;
        width: 100%;
        display: block;
    }
    #btn-dd{
        margin: 20px;
        text-align: center;
    }
    .foot-ul{
        width: 100%;
    }
    .one_line{
        display: block;
        height: 1px;
        border: 0;
        border-top: 1px solid #eeeeee;
        width: 100%;
        margin-left: 20px;
    }
    .am-header {
        display: -webkit-box;
        display: -ms-flexbox;
        display: box;
        width: 100%;
        position: relative;
        padding: 7px 0;
        -webkit-box-sizing: border-box;
        -ms-box-sizing: border-box;
        box-sizing: border-box;
        background: #1D222D;
        height: 50px;
        text-align: center;
        -webkit-box-pack: center;
        -ms-flex-pack: center;
        box-pack: center;
        -webkit-box-align: center;
        -ms-flex-align: center;
        box-align: center;
    }
    .am-header h1 {
        -webkit-box-flex: 1;
        -ms-flex: 1;
        box-flex: 1;
        line-height: 18px;
        text-align: center;
        font-size: 18px;
        font-weight: 300;
        color: #fff;
    }
</style>
</head>
<script src="./js/jquery-1.9.1.min.js" type="text/javascript"></script>

<script>

function createAliH5Pay(){
	var data = "body="+$("#body1").val()+"&detail="+$("#detail").val()+"&outTradeNo="+$("#outTradeNo").val()+"&totalAmount="+$("#totalAmount").val()+"&payType="+$("#payType").val();
	var outTradeNo = $("#outTradeNo").val();
	if(outTradeNo==null||outTradeNo==undefined||outTradeNo==""){
		//处理
		alert("商户订单号不能为空");
		return;
	}
	
	var body1 = $("#body1").val();
	if(body1==null||body1==undefined||body1==""){
		//处理
		alert("订单名称不能为空");
		return;
	}
	
	var totalAmount = $("#totalAmount").val();
	if(totalAmount==null||totalAmount==undefined||totalAmount==""){
		//处理
		alert("付款金额不能为空");
		return;
	}
	
	var detail = $("#detail").val();
	if(detail==null||detail==undefined||detail==""){
		//处理
		alert("商品描述不能为空");
		return;
	}
	$.ajax({
        url: '/payDemo/pay/unifiedOrder.do',
        type: 'post',
        cache:false,
        async:false,
		data:  data,
        dataType: 'JSON',
        timeout: 5000,
        success: function(data){
            console.log("data="+data.data);
            if(data!=null){
            	if(data.code!="00")alert("["+data.code+"]"+data.message);
            	$("body").html(data.data);
            }
        }
    });
}


</script>

<body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4>
<header class="am-header">
        <h1>支付宝手机网站支付接口快速通道(接口名:alipay.trade.wap.pay)</h1>
</header>
<div id="main">
            <div id="body" style="clear:left">
                <dl class="content">
                    <dt>商户订单号(*):</dt>
                    <dd>
                        <input id="outTradeNo" name="outTradeNo" />
                    </dd>
                    <hr class="one_line">
                    <dt>订单名称(*):</dt>
                    <dd>
                        <input id="body1" name="body" />
                    </dd>
                    <hr class="one_line">
                    <dt>付款金额(*):</dt>
                    <dd>
                        <input id="totalAmount" name="totalAmount" />
                    </dd>
                    <hr class="one_line"/>
                    <dt>商品描述(*):</dt>
                    <dd>
                        <input id="detail" name="detail" />
                    </dd>
                    
                     <dt></dt>
                     <dd>
                        <input type="hidden" id="payType" name="payType" value="aliPay" />
                    </dd>
                    
                    <hr class="one_line">
                    <dt></dt>
                    <dd id="btn-dd">
                        <span class="new-btn-login-sp">
                            <button class="new-btn-login" type="button" onclick='createAliH5Pay(this);' style="text-align:center;">确 认</button>
                        </span>
                        <span class="note-help">如果您点击“确认”按钮,即表示您同意该次的执行操作。</span>
                    </dd>
                </dl>
            </div>
        <div id="foot">
			<ul class="foot-ul">
				<li>
					深圳市xxxxx公司版权所有 2015-2018 
				</li>
			</ul>
		</div>
	</div>
</body>

</html>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值