美文网首页嘟嘟程序猿微信相关Java
JAVA后端实现微信支付(微信扫码及微信App支付)开发(模式二

JAVA后端实现微信支付(微信扫码及微信App支付)开发(模式二

作者: Java开发者记录站 | 来源:发表于2019-07-08 10:57 被阅读97次

    一,准备工作

    事前申请一个商家版的微信公众号(目前微信支付只有商家版公众号可开通),然后开通微信支付功能,并做相应的配置。

    image

    申请开通微信公众号和开通微信支付需要等待审核,一般都5个工作日左右。开通成功后,需要获取配置信息:wx.pay.appid=********

    wx.pay.mchid=******

    wx.pay.key=**************

    wx.pay.secret=*********

    其中appid和secret可以在公众平台找着,mchid和key则在商户平台找到,特别是key(即API_KEY)要在商户平台设置好。本项目中这些配置通过properties文件放在***-payment-service工程的resource根路径下。

    在编码之前,还需要登录微信商户平台配置支付回调URL,此配置作为支付成功后回调接口的域名。如果配置的URL为:http://www.abc.com/, 你的支付回调路径则可设置为:http://www.abc.com/api/payment/wxNotify

    二,编写代码

    本项目我是用SpringBoot的微服务开发的,项目结构如下:

    image

    我们先看看Service接口

    image

    再看看Service的实现类:

    
    @Service(value = "paymentService")
    
    public class PaymentServiceImpl implements PaymentService {
    
    private static Logger LOGGER = LoggerFactory.getLogger(PaymentServiceImpl.class);
    
    @Value("${project.service.env}")
    
    private String PROJECT_ENV;
    
    @Value("${hcc.pay.domain}")
    
    private String payDomain;
    
    @Autowired
    
    private PaymentRecordMapper paymentRecordMapper;
    
    @Autowired
    
    private PaymentNotifyMapper paymentNotifyMapper;
    
    @Override
    
    @Transactional(readOnly=false,rollbackFor={Exception.class})
    
    public Map<String,String> wxAppPayment(String orderId, double money) throws Exception {
    
    LOGGER.info("【微信App支付】 统一下单开始, 订单编号="+orderId);
    
    SortedMap<String, String> resultMap = new TreeMap<String, String>();
    
    //生成支付金额
    
    double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV, money);
    
    //添加或更新支付记录
    
    int flag = this.addOrUpdatePaymentRecord(orderId, payAmount, PayConstant.PAY_METHOD_WX,PayConstant.PAY_TRADE_TYPE_APP, false, null);
    
    if(flag < 0){
    
    resultMap.put("returnCode", "FAIL");
    
    resultMap.put("returnMsg", "此订单已支付!");
    
    LOGGER.info("【微信App支付】 此订单已支付!");
    
    }else if(flag == 0){
    
    resultMap.put("returnCode", "FAIL");
    
    resultMap.put("returnMsg", "支付记录生成或更新失败!");
    
    LOGGER.info("【微信App支付】 支付记录生成或更新失败!");
    
    }else{
    
    //统一下单
    
            Map<String,String> resMap = this.wxUnifieldOrder(orderId, PayConfig.TRADE_TYPE_APP, payAmount);
    
            if(PayConstant.SUCCESS.equals(resMap.get("return_code")) && PayConstant.OK.equals(resMap.get("return_msg"))){
    
    //封装参数返回
    
        resultMap.put("appid", PayConfig.WX_APP_ID);//前面配置中的appid
    
        resultMap.put("partnerid", PayConfig.WX_MCH_ID);//前面配置中的mchid
    
        resultMap.put("prepayid", resMap.get("prepay_id"));
    
        resultMap.put("package", "Sign=WXPay");
    
        resultMap.put("noncestr", PayUtil.makeUUID(32));
    
        resultMap.put("timestamp", PayUtil.getCurrentTimeStamp());
    
        resultMap.put("sign", PayUtil.createSign(resultMap,PayConfig.WX_KEY));
    
        resultMap.put("returnCode", "SUCCESS");
    
        resultMap.put("returnMsg", "OK");
    
        LOGGER.info("【微信App支付】统一下单成功,返回参数:"+resultMap);
    
            }else{
    
            resultMap.put("returnCode", resMap.get("return_code"));
    
        resultMap.put("returnMsg", resMap.get("return_msg"));
    
        LOGGER.info("【微信App支付】统一下单失败,失败原因:"+resMap.get("return_msg"));
    
            }
    
    }
    
    return resultMap;
    
    }
    
        @Override
    
    public Map<String, String> wxQrPayment(String orderId, double money) throws Exception {
    
    LOGGER.info("【微信扫码支付】 开始下单, 订单编号="+orderId+",支付金额="+money);
    
    double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV,money);
    
    Map<String,String> retMap = new HashMap<String, String>();
    
    //添加或更新支付记录
    
    int flag = this.addOrUpdatePaymentRecord(orderId, payAmount, PayConstant.PAY_METHOD_WX,PayConstant.PAY_TRADE_TYPE_QR,false, null);
    
    if(flag < 0){
    
    retMap.put("returnCode", "FAIL");
    
    retMap.put("returnMsg", "此订单已支付!");
    
    LOGGER.info("【微信扫码支付】  此订单已支付!");
    
    }else if(flag == 0){
    
    retMap.put("returnCode", "FAIL");
    
    retMap.put("returnMsg", "支付记录生成或更新失败!");
    
    LOGGER.info("【微信扫码支付】 支付记录生成或更新失败!");
    
    }else{
    
    //微信统一下单
    
    Map<String,String> map = this.wxUnifieldOrder(orderId,PayConfig.TRADE_TYPE_NATIVE,payAmount);
    
    //下单后返回状态
    
            if(PayConstant.SUCCESS.equals(map.get("return_code")) && PayConstant.OK.equals(map.get("return_msg"))) {
    
            retMap.put("returnCode", map.get("return_code"));
    
                retMap.put("returnMsg", PayConstant.OK);
    
                retMap.put("codeUrl",map.get("code_url"));
    
                retMap.put("payAmount",String.valueOf(payAmount));
    
                retMap.put("orderName", BaseConstants.PLATFORM_COMPANY_NAME);
    
                retMap.put("payMethod", "微信扫码支付");
    
                retMap.put("queryUrl", this.getNotifyUrl(PayConstant.PAY_TYPE_WX));
    
                LOGGER.info("【微信扫码支付】统一下单成功!");
    
            }else{
    
            retMap.put("returnCode", map.get("return_code"));
    
            retMap.put("returnMsg", map.get("return_msg"));
    
            LOGGER.info("【微信扫码支付】统一下单失败,失败原因:"+map.get("return_msg"));
    
            }
    
            retMap.put("orderNo",orderId);
    
    }
    
            return retMap;
    
    }
    
    @Override
    
    @Transactional(readOnly=false,rollbackFor={Exception.class})
    
    public int wxNotify(Map<String,Object> map) throws Exception{
    
    Integer flag = 0;
    
            //支付订单编号
    
            String orderNo = (String)map.get("out_trade_no");
    
            //检验是否需要回调
    
            if(this.isNotifyAgain(orderNo)){
    
            //此处写更新支付信息和订单状态逻辑
    
            }
    
            return flag;
    
    }
    
        /**
    
    * <p>微信支付统一下单</p>
    
    *
    
    * @param orderId 订单编号
    
    * @param tradeType 支付类型
    
    * @return
    
    * @throws Exception
    
    */
    
    private Map<String,String> wxUnifieldOrder(String orderId,String tradeType, double payAmount) throws Exception{
    
        //封装参数
    
            SortedMap<String,String> paramMap = new TreeMap<String,String>();
    
            paramMap.put("appid", PayConfig.WX_APP_ID);
    
            paramMap.put("mch_id", PayConfig.WX_MCH_ID);
    
            paramMap.put("nonce_str", PayUtil.makeUUID(32));
    
            paramMap.put("body", BaseConstants.PLATFORM_COMPANY_NAME);
    
            paramMap.put("out_trade_no", orderId);
    
            paramMap.put("total_fee", PayUtil.moneyToIntegerStr(payAmount));
    
            paramMap.put("spbill_create_ip", PayUtil.getLocalIp());
    
            paramMap.put("notify_url", this.getNotifyUrl(PayConstant.PAY_TYPE_WX));//此处为要配置的回调地址
    
            paramMap.put("trade_type", tradeType);
    
            paramMap.put("sign", PayUtil.createSign(paramMap,PayConfig.WX_KEY));
    
            //转换为xml
    
            String xmlData = PayUtil.mapToXml(paramMap);
    
            //请求微信后台
    
            String resXml = HttpUtils.postData(PayConfig.WX_PAY_UNIFIED_ORDER, xmlData);
    
            LOGGER.info("【微信支付】 统一下单响应:\n"+resXml);
    
            return PayUtil.xmlStrToMap(resXml);
    
        }
    
        @Override
    
    public int addOrUpdatePaymentRecord(String orderNo, double payAmount, int payType, String tradeType, boolean isPayment, String tradeNo) throws Exception{
    
            PaymentRecord record = null;
    
            if(null == (record = paymentRecordMapper.findPaymentRecordByorderNo(orderNo)))
    
            {
    
                record = new PaymentRecord();
    
                //封装对应参数,并添加一条支付信息,状态为“待支付”
    
                return paymentRecordMapper.insert(record);
    
            }else{
    
                record.set...();
    
                //此处是对已改变的参数进行更新
    
                record.setUpdateTime(new Date());
    
                return paymentRecordMapper.updateByPrimaryKey(record);
    
            }
    
    }
    
        /**
    
    * <p>检查是否需要再次回调更新订单</p>
    
    *
    
    * @param orderNo
    
    * @return
    
    */
    
    private boolean isNotifyAgain(String orderNo){
    
    //根据订单编号,查询对应支付信息,如果此条支付状态为已支付,返回TRUE,否则返回false
    
    //这样做的目的是防止多次调回调接口平凡刷新支付信息
    
    }
    
        /**
    
    * <p>根据不同环境获取回调Api地址</p>
    
    *
    
    * @return
    
    */
    
        private String getNotifyUrl(){
    
    //服务域名
    
    String serverDomain = PayConfig.PRO_SERVER_DOMAIN;
    
    if(BaseConstants.PLATFORM_ENV_DEV.equals(PROJECT_ENV)){
    
    serverDomain = PayConfig.TEST_SERVER_DOMAIN;
    
    }
    
    return serverDomain + PayConstant.WX_PAY_CALLBACK_URL;
    
    }
    
    }
    
    

    再看看这里的PayUtil工具类:

    
    public class PayUtil {
    
    static Logger log = LogManager.getLogger(PayUtil.class.getName());
    
    /**
    
    * 获取当前机器的ip
    
    *
    
    * @return String
    
    */
    
    public static String getLocalIp(){
    
    InetAddress ia=null;
    
    String localip = null;
    
            try {
    
                ia=ia.getLocalHost();
    
                localip=ia.getHostAddress();
    
            } catch (Exception e) {
    
                e.printStackTrace();
    
            }
    
    return localip;
    
    }
    
    /**
    
    * Map转换为 Xml
    
    *
    
    * @param data
    
    * @return Xml
    
    * @throws Exception
    
    */
    
    public static String mapToXml(SortedMap<String, String> map) throws Exception {
    
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    
            //防止XXE攻击
    
            documentBuilderFactory.setXIncludeAware(false);
    
            documentBuilderFactory.setExpandEntityReferences(false);
    
            DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
    
            org.w3c.dom.Document document = documentBuilder.newDocument();
    
            org.w3c.dom.Element root = document.createElement("xml");
    
            document.appendChild(root);
    
            for (String key: map.keySet()) {
    
                String value = map.get(key);
    
                if (value == null) {
    
                    value = "";
    
                }
    
                value = value.trim();
    
                org.w3c.dom.Element filed = document.createElement(key);
    
                filed.appendChild(document.createTextNode(value));
    
                root.appendChild(filed);
    
            }
    
            TransformerFactory tf = TransformerFactory.newInstance();
    
            Transformer transformer = tf.newTransformer();
    
            DOMSource source = new DOMSource(document);
    
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
    
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    
            StringWriter writer = new StringWriter();
    
            StreamResult result = new StreamResult(writer);
    
            transformer.transform(source, result);
    
            String output = writer.getBuffer().toString();
    
            try {
    
                writer.close();
    
            }
    
            catch (Exception ex) {
    
            }
    
            return output;
    
        }
    
    /**
    
    * 创建签名Sign
    
    *
    
    * @param key
    
    * @param parameters
    
    * @return
    
    */
    
    public static String createSign(SortedMap<String,String> parameters,String key){ 
    
            StringBuffer sb = new StringBuffer(); 
    
            Set es = parameters.entrySet();
    
            Iterator<?> it = es.iterator(); 
    
            while(it.hasNext()) { 
    
                Map.Entry entry = (Map.Entry)it.next(); 
    
                String k = (String)entry.getKey(); 
    
                if(entry.getValue() != null || !"".equals(entry.getValue())) {
    
                String v = String.valueOf(entry.getValue());
    
                if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
    
                sb.append(k + "=" + v + "&");
    
                }
    
                } 
    
            } 
    
            sb.append("key=" + key); 
    
            String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); 
    
            return sign; 
    
        }
    
    /**
    
    * XML转换为Map
    
    *
    
    * @param strXML
    
    * @return Map
    
    * @throws Exception
    
    */
    
    public static Map<String, Object> getMapFromXML(String strXML) throws Exception {
    
            try {
    
                Map<String, Object> data = new HashMap<String, Object>();
    
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    
                //防止XXE攻击
    
                documentBuilderFactory.setXIncludeAware(false);
    
                documentBuilderFactory.setExpandEntityReferences(false);
    
                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;
    
            }
    
    }
    
    /**
    
    * 生成随机数
    
    *
    
    * @return
    
    */
    
    public static String makeUUID(int len) {
    
    return UUID.randomUUID().toString().replaceAll("-", "").substring(0, len);
    
    }
    
    /**
    
        * 获取当前的Timestamp
    
        *
    
        * @return
    
        */
    
        public static String getCurrentTimeStamp() {
    
            return Long.toString(System.currentTimeMillis()/1000);
    
        }
    
        /**
    
        * 获取当前的时间
    
        * @return
    
        */
    
        public static long getCurrentTimestampMs() {
    
            return System.currentTimeMillis();
    
        }
    
        /**
    
    * 获取当前工程url
    
    *
    
    * @param request
    
    * @return
    
    */
    
    public static String getCurrentUrl(HttpServletRequest request){
    
    return request.getScheme() +"://" + request.getServerName()  + ":" +request.getServerPort() +request.getContextPath();
    
    }
    
    /**
    
    * Xml字符串转换为Map
    
    *
    
    * @param xmlStr
    
    * @return
    
    */
    
    public static Map<String,String> xmlStrToMap(String xmlStr){
    
            Map<String,String> map = new HashMap<String,String>();
    
            Document doc;
    
            try {
    
                doc = DocumentHelper.parseText(xmlStr);
    
                Element root = doc.getRootElement();
    
                List children = root.elements();
    
                if(children != null && children.size() > 0) {
    
                    for(int i = 0; i < children.size(); i++) {
    
                        Element child = (Element)children.get(i);
    
                        map.put(child.getName(), child.getTextTrim());
    
                    }
    
                }
    
            } catch (DocumentException e) {
    
                e.printStackTrace();
    
            }
    
            return map;
    
        }
    
    public static String getSceneInfo(String wapUrl,String name){
    
    Map<String,Map<String,String>> map = new HashMap<String, Map<String,String>>();
    
    if(!StringUtils.isEmpty(wapUrl) && !StringUtils.isEmpty(name)){
    
    /*{"h5_info": {"type":"Wap","wap_url": "https://pay.qq.com","wap_name": "腾讯充值"}}*/
    
    Map<String,String> childmap = new TreeMap<String, String>();
    
    childmap.put("type", "Wap");
    
    childmap.put("wap_url",wapUrl);
    
    childmap.put("wap_name", name);
    
    map.put("h5_info", childmap);
    
    return JSON.toJSONString(map);
    
    }
    
    return null;
    
    }
    
        /**
    
        * 转换金额型到整型
    
        * @param money
    
        * @return
    
        */
    
        public static String moneyToIntegerStr(Double money){
    
            BigDecimal decimal = new BigDecimal(money);
    
            int amount = decimal.multiply(new BigDecimal(100))
    
                .setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
    
            return String.valueOf(amount);
    
        }
    
        /**
    
        * 除去数组中的空值和签名参数
    
        * @param sArray 签名参数组
    
        * @return 去掉空值与签名参数后的新签名参数组
    
        */
    
        public static Map<String, String> paraFilter(Map<String, String> sArray) {
    
            Map<String, String> result = new HashMap<String, String>();
    
            if (sArray == null || sArray.size() <= 0) {
    
                return result;
    
            }
    
            for (String key : sArray.keySet()) {
    
                String value = sArray.get(key);
    
                if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
    
                    || key.equalsIgnoreCase("sign_type")) {
    
                    continue;
    
                }
    
                result.put(key, value);
    
            }
    
            return result;
    
        }
    
        /**
    
        * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
    
        * @param params 需要排序并参与字符拼接的参数组
    
        * @return 拼接后字符串
    
        */
    
        public static String createLinkString(Map<String, String> params) {
    
            List<String> keys = new ArrayList<String>(params.keySet());
    
            Collections.sort(keys);
    
            String prestr = "";
    
            for (int i = 0; i < keys.size(); i++) {
    
                String key = keys.get(i);
    
                String value = params.get(key);
    
                if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
    
                    prestr = prestr + key + "=" + value;
    
                } else {
    
                    prestr = prestr + key + "=" + value + "&";
    
                }
    
            }
    
            return prestr;
    
        }
    
        /**
    
        * 根据不同环境生成支付金额
    
        * 生产环境支付金额为实际要支付钱数,测试环境做了处理便于测试人员测试
    
        *
    
        * @param env
    
        * @param money
    
        * @param payType
    
        * @return
    
        */
    
        public static double getPayAmountByEnv(String env,Double money){
    
        double pay_money = 0.01;
    
        //测试环境
    
        if(BaseConstants.PLATFORM_ENV_DEV.equals(env)){
    
    if(money>10000){
    
    pay_money = 0.03;
    
    }else if(money>1000){
    
    pay_money = 0.02;
    
    }else{
    
    pay_money = 0.01;
    
    }
    
    return pay_money;
    
        }else{
    
        //生成环境
    
        return money;
    
        }
    
        }
    
    }
    
    

    支付配置类PayConfig:

    
    public class PayConfig {
    
    //微信支付类型
    
    //NATIVE--原生支付
    
    //JSAPI--公众号支付
    
    //MWEB--H5支付
    
    //APP -- app支付
    
    public static final String TRADE_TYPE_NATIVE = "NATIVE";
    
    public static final String TRADE_TYPE_JSAPI = "JSAPI";
    
    public static final String TRADE_TYPE_MWEB = "MWEB";
    
    public static final String TRADE_TYPE_APP = "APP";
    
    //服务器域名
    
    public static String PRO_SERVER_DOMAIN;
    
    public static String TEST_SERVER_DOMAIN;
    
    //微信公众号参数
    
    public static String WX_APP_ID;
    
    public static String WX_MCH_ID;
    
    public static String WX_KEY;
    
    public static String WX_APP_SECRET;
    
    //微信支付API
    
    public static final String WX_PAY_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    
    //参数
    
    static{
    
    Properties properties = new Properties();
    
    try {
    
    properties.load(PayConstant.class.getClassLoader().getResourceAsStream("payment_config.properties"));
    
    PRO_SERVER_DOMAIN = (String) properties.get("pro.server.domain");
    
    TEST_SERVER_DOMAIN = (String) properties.get("test.server.domain");
    
    //wx pay
    
    WX_APP_ID = (String) properties.get("wx.pay.appid");
    
    WX_MCH_ID = (String) properties.get("wx.pay.mchid");
    
                WX_KEY = (String) properties.get("wx.pay.key");
    
                WX_APP_SECRET = (String) properties.get("wx.pay.secret");
    
    } catch (Exception e) {
    
    e.printStackTrace();
    
    }
    
    }
    
    }
    
    

    到这里为止,业务实现基本已经写完了,现在我们去看看接口层吧!

    
    @RestController
    
    @RequestMapping(value = "/app/payment/")
    
    public class PaymentController {
    
    private static Logger logger = LoggerFactory.getLogger(PaymentController.class);
    
    @Value("${project.service.env}")
    
    private String PROJECT_ENV;
    
    @Value("${error.page}")
    
    private String error_page;
    
    @Value("${hcc.app.domain}")
    
    private String orderDomain;
    
    @Autowired
    
    private PaymentService paymentService;
    
    @Autowired
    
    private RedisCacheService cacheService;
    
    /**
    
    * App支付接口
    
    * 微信和支付宝统一下单入口
    
    *
    
    * @param request
    
    * @return
    
    * @throws Exception
    
    */
    
    @ResponseBody
    
        @RequestMapping(value="appPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
    
    public JSONObject toPay(HttpServletRequest request) throws Exception {
    
    String requestStr = RequestStr.getRequestStr(request);
    
    if (StringUtils.isEmpty(requestStr)) {
    
    throw new ParamException();
    
    }
    
    JSONObject jsonObj = JSONObject.parseObject(requestStr);
    
    if(StringUtils.isEmpty(jsonObj.getString("payType")) || StringUtils.isEmpty(jsonObj.getString("orderNo"))){
    
      throw new ParamException();
    
    }
    
      //验证订单是否存在
    
      String orderId = jsonObj.getString("orderNo");
    
      OrderInfo orderInfo = getPayOrder(orderId);
    
      if(orderInfo == null){
    
      return AjaxUtil.renderFailMsg("订单不存在!");
    
      }else if(orderInfo.getPayPrice() == null || orderInfo.getPayPrice() < 0.01){
    
      return AjaxUtil.renderFailMsg("订单有误,请确认!");
    
      }else if(orderInfo.getpStatus() != OrderConstant.PORDER_STATUS_YTJ){
    
      String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
    
      return AjaxUtil.renderFailMsg(msg);
    
      }else{
    
      //微信支付
    
      if(PayConstant.PAY_TYPE_WX.equals(jsonObj.getString("payType"))){
    
      Map<String, String> resMap = paymentService.wxAppPayment(orderInfo.getOrderNo(),orderInfo.getPayPrice());
    
      //判断微信统一下单是否成功
    
      if("SUCCESS".equals(resMap.get("returnCode")) && "OK".equals(resMap.get("returnMsg"))){
    
      //统一下单成功
    
      resMap.remove("returnCode");
    
      resMap.remove("returnMsg");
    
      logger.info("【App支付服务】微信支付下单成功!");
    
      return AjaxUtil.renderSuccessMsg(resMap);
    
      }else{
    
      return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
    
      }
    
      }else if(PayConstant.PAY_TYPE_ALI.equals(jsonObj.getString("payType"))){
    
      //支付宝支付
    
    }else{
    
      return AjaxUtil.renderParamFailMsg("请选择支付方式!");
    
    }
    
      }
    
    }
    
    /**
    
    * 扫码支付接口
    
    * 微信和支付宝统一下单入口
    
    *
    
    * @param request
    
    * @return
    
    * @throws Exception
    
    */
    
    @ResponseBody
    
        @RequestMapping(value="qrPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
    
    public JSONObject qrPay(HttpServletRequest request) throws Exception {
    
    String requestStr = RequestStr.getRequestStr(request);
    
    if (StringUtils.isEmpty(requestStr)) {
    
    throw new ParamException();
    
    }
    
    JSONObject jsonObj = JSONObject.parseObject(requestStr);
    
    if(StringUtils.isEmpty(jsonObj.getString("payType")) || StringUtils.isEmpty(jsonObj.getString("orderNo"))){
    
      throw new ParamException();
    
    }
    
      //验证订单是否存在
    
        String orderId = jsonObj.getString("orderNo");
    
        OrderInfo orderInfo = getPayOrder(orderId);
    
        if(orderInfo == null){
    
      return AjaxUtil.renderFailMsg("订单不存在!");
    
      }else if(orderInfo.getPayPrice() == null || orderInfo.getPayPrice() < 0.01){
    
      return AjaxUtil.renderFailMsg("订单有误,请确认!");
    
      }else if(orderInfo.getpStatus() != OrderConstant.PORDER_STATUS_YTJ){
    
      String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
    
      return AjaxUtil.renderFailMsg(msg);
    
      }else{
    
      if(PayConstant.PAY_TYPE_WX.equals(jsonObj.getString("payType"))){
    
      //微信支付扫码支付
    
      Map<String, String> resMap = paymentService.wxQrPayment(orderInfo.getOrderNo(), orderInfo.getPayPrice());
    
      //判断微信统一下单是否成功
    
      if(PayConstant.SUCCESS.equals(resMap.get("returnCode")) && PayConstant.OK.equals(resMap.get("returnMsg"))){
    
      resMap.remove("returnCode");
    
      resMap.remove("returnMsg");
    
      logger.info("【Web扫码支付服务】微信支付下单成功!");
    
      return AjaxUtil.renderSuccessMsg(resMap);
    
      }else{
    
      return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
    
      }
    
      }else if(PayConstant.PAY_TYPE_ALI.equals(jsonObj.getString("payType"))){
    
      //支付宝扫码支付
    
    }else{
    
      return AjaxUtil.renderParamFailMsg("请选择支付方式!");
    
    }
    
      }
    
    }
    
    /**
    
    * <p>获取二维码</p>
    
    *
    
    * @param request
    
    * @param response
    
    * @throws Exception
    
    */
    
    @ResponseBody
    
        @RequestMapping(value="qrCodeImg", method=RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
    
    public void getQrCodeImg(HttpServletRequest request,HttpServletResponse response) throws Exception{
    
    //获取参数
    
    String codeUrl = request.getParameter("codeUrl");
    
    if(!StringUtils.isEmpty(codeUrl)){
    
      CodeUtil.generateQrCodeImg(codeUrl,response.getOutputStream());
    
    }else{
    
      throw new ParamException();
    
    }
    
    }
    
        /**
    
    * 微信支付完成回调Api
    
    *
    
    * @param request
    
    * @param response
    
    * @throws Exception
    
    */
    
        @RequestMapping(value="wxNotify")
    
    public void wxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception {
    
    InputStream inputStream =  request.getInputStream();
    
    //获取请求输入流
    
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    
            byte[] buffer = new byte[1024];
    
            int len = 0;
    
            while ((len=inputStream.read(buffer))!=-1){
    
                outputStream.write(buffer,0,len);
    
            }
    
            outputStream.close();
    
            inputStream.close();
    
            Map<String,Object> map = BeanToMap.getMapFromXML(new String(outputStream.toByteArray(),"utf-8"));
    
            logger.info("【微信支付回调】 回调数据: \n"+map);
    
            String resXml = "";
    
            String returnCode = (String) map.get("return_code");
    
            if ("SUCCESS".equalsIgnoreCase(returnCode)) {
    
                String returnmsg = (String) map.get("result_code");
    
                if("SUCCESS".equals(returnmsg)){
    
                //更新数据
    
                int result = paymentService.wxNotify(map);
    
                if(result > 0){
    
                //支付成功
    
                    resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
    
                            + "<return_msg><![CDATA[OK]]></return_msg>"+"</xml>";
    
                }
    
                }else{
    
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
    
                            + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
    
                    logger.info("支付失败:"+resXml);
    
                }
    
            }else{
    
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
    
                        + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
    
                logger.info("【订单支付失败】");
    
            }
    
            logger.info("【微信支付回调响应】 响应内容:\n"+resXml);
    
            //做出响应
    
            response.getWriter().print(resXml);
    
    }
    
    /**
    
    * <p>查询订单支付是否完成</p>
    
    *
    
    * @param request
    
    * @param response
    
    * @return
    
    * @throws Exception
    
    */
    
    @ResponseBody
    
        @RequestMapping(value="queryPayStatus")
    
    public JSONObject queryPayStatus(HttpServletRequest request,HttpServletResponse response) throws Exception {
    
    String requestStr = RequestStr.getRequestStr(request);
    
    if (StringUtils.isEmpty(requestStr)) {
    
    throw new ParamException();
    
    }
    
    JSONObject jsonObj = JSONObject.parseObject(requestStr);
    
    if(StringUtils.isEmpty(jsonObj.getString("orderNo"))){
    
      throw new ParamException();
    
    }
    
    PaymentRecord record = paymentService.queryPaymentStatusById(jsonObj.getString("orderNo"));
    
    if(record != null && record.getStatus){
    
      //此处可根据自己想要返回的数据封装返回,“已支付”可用封装的Map返回
    
      return AjaxUtil.renderSuccessMsg(“已支付”);
    
    }else{
    
      return AjaxUtil.renderFailMsg("未支付!");
    
    }
    
    }
    
    /**
    
    * <p>通过Http请求订单服务获取订单信息</p>
    
    *
    
    * @param orderNo
    
    * @return
    
    * @throws Exception
    
    */
    
    private OrderInfo getPayOrder(String orderNo) throws Exception{
    
    //更新订单状态
    
    String reqUrl = orderDomain + "order/findOrderByPrimary";
    
    SortedMap<String, String> params = new TreeMap<String, String>();
    
    params.put("orderId", orderNo);
    
    JSONObject json = JSONObject.parseObject(HttpUtils.sendPostWithSign(reqUrl, params));
    
    if("0000".equals(json.get("responseCode"))){
    
    OrderInfo orderInfo = JSONObject.parseObject(json.getString("data"),OrderInfo.class);
    
    if(orderInfo != null){
    
    return orderInfo;
    
    }
    
    }
    
    return null;
    
    }
    
    }
    
    

    到此为止,所有的编码工作已完成。

    三,测试(用扫码支付)

    选择要购买的商品,然后下单,再去发起支付。

    image

    单击“去支付”按钮,跳转到二维码支付页面:

    image

    扫码支付完成后,显示二维码的页面会跳转到支付成功页面(带微信支付成功logo),并有3s的倒计时,然后跳转到“订单详情”页。

    image

    **本人有完整的电商支付微服务代码(微信支付和支付宝支付),如果需要,请关注本人微信公众号留言,或通过公众号加我私人微信联系,希望能和大家一起学习进步! **

    image

    相关文章

      网友评论

        本文标题:JAVA后端实现微信支付(微信扫码及微信App支付)开发(模式二

        本文链接:https://www.haomeiwen.com/subject/cmznhctx.html