嘟嘟程序猿微信相关Java

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

2019-07-08  本文已影响97人  Java开发者记录站

一,准备工作

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

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
上一篇下一篇

猜你喜欢

热点阅读