微信小程序支付、对账java后端代码

之前写的一个开发注意事项总结:
微信百度支付开发

百度流程代码梳理:
百度小程序代码
今天梳理一下微信小程序支付这块儿的代码。
controller层的代码主要是为了和前端进行交互,传一些参数,跟自己的业务需求相关,就不梳理了。主要说一下service层以及一些utils。

/**
     * 微信端操作,调用微信统一支付订单API,并将信息封装
     *
     * @param openId
     * @param fee
     * @param IP
     */
    @Override
    public Map<String, String> WXPaymentService((一些params,根据自己的业务来)) {
       //相关参数校验逻辑
       *******
        //构建订单相关信息
        WXOrderInfoVO wxOrderInfoVO = buildOrderInfo(openId, fee, IP);
        //转换成要求格式
        String paramString = WXPayUtil.mapToXml(ObjectToMapUtil.objectToMap(wxOrderInfoVO));
        //调用统一支付接口
        String result = WXPayUtil.httpRequest(payURL, RewardConstants.POST, paramString);
        //返回参数解析
        SortedMap<String, String> returnParams = WXPayUtil.parseXml(result);
        //校验,二次签名
        Map<String, String> returnInfo = WXPayUtil.reSign(returnParams, wxOrderInfoVO);
        //生成预付订单成功才存入数据库
        调用DAO层,操作数据库,为了之后对账
        return returnInfo;
    }

    /**
     * 生成微信统一支付订单相关信息,对照微信文档,一个个属性赋值
     *中间用到了一些我自己定义的常量约束
     * @param openId
     * @param fee
     * @param IP
     * @return
     */
    private WXOrderInfoVO buildOrderInfo(String openId, Integer fee, String IP) {
        WXOrderInfoVO wxOrderInfoVO = new WXOrderInfoVO();
        wxOrderInfoVO.setAppid(appid);
        wxOrderInfoVO.setMch_id(mch_id);
        wxOrderInfoVO.setOpenid(openId);
        wxOrderInfoVO.setTotal_fee(fee);
        //生成唯一的随机商户订单号,微信文档有算法介绍
        wxOrderInfoVO.setOut_trade_no(GenerateTradeNumberUtil.getTradeNumber(RewardConstants.WXTRADELENGTH));
        //生成随机字符串,微信文档有生成算法推荐
        wxOrderInfoVO.setNonce_str(RandomStringUtil.getRandomStringByLength(RewardConstants.WXNONCELENGTH));
        wxOrderInfoVO.setBody(RewardConstants.DESCRIPTION);
        wxOrderInfoVO.setSpbill_create_ip(IP);
        wxOrderInfoVO.setNotify_url(RewardConstants.NOTIFYURL);
        wxOrderInfoVO.setTrade_type(RewardConstants.TRADETYPE);
        //根据要传递的参数生成签名字符串
        String sign = WXPayUtil.sign(wxOrderInfoVO);
        wxOrderInfoVO.setSign(sign);
        return wxOrderInfoVO;
    }

用到的微信订单包装类:

/**
 * 订单信息,调用微信支付统一下单API用,直接可以转成String类型的xml,所以变量命名不符合小驼峰
 * 和微信要求的参数名称保持了一致
 */
@Data
public class WXOrderInfoVO {
    String appid;
    String mch_id;
    String device_info;
    String nonce_str;
    String sign;
    String sign_type;
    String body;
    String detail;
    String attach;
    String out_trade_no;
    String fee_type;
    Integer total_fee;
    String spbill_create_ip;
    String time_start;
    String time_expire;
    String goods_tag;
    String notify_url;
    String trade_type;
    String product_id;
    String limit_pay;
    String openid;
    String receipt;
    JSONObject scene_info;
}

用到的工具类:因为生成签名时要根据参数的名称排字典序,所以我没有用hashmap而是直接用了treemap,这样put的时候就自动按字典顺序进行排序了。

/**
 * 支付操作工具类
 *
 * @author zishuzhao
 */
@Slf4j
public class WXPayUtil {
    private static final String SIGN = "sign";
    private static final String SIGNTYPE = "sign_type";

    private static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }

    /**
     * 将返回的XML字符串转换为Map
     */
    public static SortedMap<String, String> parseXml(String strxml) {
        if (null == strxml || "".equals(strxml)) {
            log.error("wx return null");
            return Maps.newTreeMap();
        }
        try {
            SortedMap<String, String> m = new TreeMap<>();
            InputStream in = String2Inputstream(strxml);
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List list = root.getChildren();
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String k = e.getName();
                String v = "";
                List children = e.getChildren();
                if (children.isEmpty()) {
                    v = e.getTextNormalize();
                } else {
                    v = getChildrenText(children);
                }

                m.put(k, v);
            }
            //关闭流
            in.close();
            return m;
        } catch (Exception e) {
            log.error("parse returnInfo error.");
            throw new ServiceException(SystemCode.PARSE_FAIL);
        }
    }

    /**
     * 获取子节点的xml
     */
    private static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    /**
     * map转换成xml格式
     */
    public static String mapToXml(SortedMap<String, String> map) {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        //防止XXE攻击
        documentBuilderFactory.setXIncludeAware(false);
        documentBuilderFactory.setExpandEntityReferences(false);
        DocumentBuilder documentBuilder = null;
        try {
            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.equals("")) {
                    continue;
                }
                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();
            //去掉第一行的约束字段
            int index = output.indexOf("<xml>");
            writer.close();
            return output.substring(index);
        } catch (Exception e) {
            log.error("map to xml error.");
            throw new ServiceException(SystemCode.GENERATEPARAM_FAIL);
        }

    }

    /**
     * 拼接参数字符串,在参数最后拼接上商户的密钥
     */
    public static String createLinkString(SortedMap<String, String> params) {
        List<String> keys = new ArrayList<>(params.keySet());
        StringBuilder prestr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (value == null || value.equals("")) {
                continue;
            }
            if (i == keys.size() - 1) {
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("&");
            }
        }
        prestr.append("&").append("key=").append(RewardConstants.WXSECRETKEY);
        return prestr.toString();
    }

    /**
     * 通过订单信息生成sign签名
     */
    public static String sign(WXOrderInfoVO wxOrderInfoVO) {
        SortedMap<String, String> params = buildMap(wxOrderInfoVO);
        String src = createLinkString(params);
        String sign = DigestUtils.md5Hex(src).toUpperCase();
        return sign;
    }

    /**
     * 参数字符串已拼接好,生成签名
     */
    public static String sign(String src) {
        return DigestUtils.md5Hex(src).toUpperCase();
    }


    /**
     * 将订单信息转换为参数map
     */
    private static SortedMap<String, String> buildMap(WXOrderInfoVO wxOrderInfoVO) {
        try {
            return ObjectToMapUtil.objectToMap(wxOrderInfoVO);
        } catch (Exception e) {
            log.error("class to map error.");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 调用微信统一支付接口
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方法类型
     * @param outputStr     请求参数信息
     */
    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {

        log.info("begin call wx download api");
        // 创建SSLContext
        StringBuffer buffer = null;
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(requestMethod);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.connect();
            //往服务器端写内容
            if (null != outputStr) {
                OutputStream os = conn.getOutputStream();
                os.write(outputStr.getBytes("utf-8"));
                os.close();
            }
            // 读取服务器端返回的内容
            InputStream is = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            buffer = new StringBuffer();
            String line = null;
            while ((line = br.readLine()) != null) {
                buffer.append(line);
                buffer.append("\n");
            }
            br.close();
            log.info("receive data done");
        } catch (Exception e) {
            log.error("call api error.");
            throw new ServiceException(SystemCode.CALLAPI_FAIL);
        }
        return buffer.toString();
    }

    /**
     * 微信返回的参数解析,sign,然后返回给前端
     */
    public static Map<String, String> reSign(SortedMap<String, String> params, WXOrderInfoVO wxOrderInfoVO) {
        log.info("enter resign");
        Map<String, String> payMap = new HashMap<>();
        String returnCode = params.get("return_code");
        String resultCode = params.get("result_code");
        String returnMessage = params.get("return_msg");
        String errCode = params.get("err_code");
        String errCodeDes = params.get("err_code_des");

        log.info("begin resign");
        //都为SUCCESS才会有下列信息
        if (returnCode.equals(RewardConstants.SUCCESS) && resultCode.equals(RewardConstants.SUCCESS)) {
            if (!checkParam(params, wxOrderInfoVO)) {
                log.error("check return params error.");
                throw new ServiceException(SystemCode.CHECK_FAIL);
            }
            payMap.put("nonceStr", wxOrderInfoVO.getNonce_str());
            payMap.put("package", "prepay_id=" + params.get("prepay_id"));
            Long timeStamp = System.currentTimeMillis() / 1000;
            payMap.put("timeStamp", String.valueOf(timeStamp));
            //拼接签名需要的参数
            String stringSignTemp = "appId=" + wxOrderInfoVO.getAppid() + "&nonceStr=" + wxOrderInfoVO.getNonce_str()
                    + "&package=prepay_id=" + params.get("prepay_id") + "&signType=MD5&timeStamp=" + timeStamp
                    + "&key=" + RewardConstants.WXSECRETKEY;

            //再次签名,这个签名用于小程序端调用wx.requesetPayment方法
            String paySign = WXPayUtil.sign(stringSignTemp);
            payMap.put("paySign", paySign);
            payMap.put("appid", wxOrderInfoVO.getAppid());
            return payMap;
        }
        if (returnCode.equals(RewardConstants.SUCCESS) && resultCode.equals(RewardConstants.FAIL)) {
            log.error("WeChat report error,pay fail.");
            throw new ServiceException(SystemCode.RETURN_FAIL, errCodeDes);
        }
        if (returnCode.equals(RewardConstants.FAIL)) {
            log.error("WeChat report error,pay fail.");
            throw new ServiceException(SystemCode.RETURN_FAIL, returnMessage);
        }
        log.error("resign error");
        return null;
    }

    /**
     * 二次签名前对微信接口返回的信息进行校验
     */
    private static boolean checkParam(SortedMap<String, String> params, WXOrderInfoVO wxOrderInfoVO) {
        if (params.get("appid").isEmpty() || !params.get("appid").equals(wxOrderInfoVO.getAppid())) {
            return false;
        }
        if (params.get("mch_id").isEmpty() || !params.get("mch_id").equals(wxOrderInfoVO.getMch_id())) {
            return false;
        }
        if (params.get("nonce_str").isEmpty()) {
            return false;
        }
        //应该根据返回的信息重新生成sign,再和这个sign进行比较
        if (params.get("sign").isEmpty() || !checkSign(params)) {
            return false;
        }
        if (params.get("prepay_id").isEmpty()) {
            return false;
        }
        if (!params.get("trade_type").equals(RewardConstants.TRADETYPE)) {
            return false;
        }
        return true;
    }

    /**
     * 对微信返回的信息重新生成签名,并和微信返回信息中的签名进行比对
     */
    private static boolean checkSign(SortedMap<String, String> params) {
        String remoteSign = params.get("sign");
        params.remove("sign");
        String localSign = sign(createLinkString(params));
        if (!remoteSign.equals(localSign)) {
            return false;
        }
        params.put("sign", remoteSign);
        return true;
    }

    /**
     * 去除返回信息参数中的空值和签名
     */
    public static SortedMap<String, String> paraFilter(Map<String, String> sArray) {
        SortedMap<String, String> result = new TreeMap<>();
        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(SIGNTYPE)) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }
}

这里边还用到了一个工具类,就是把自己的包装类转换成map,这里我也直接转为了treemap,具体代码如下:

/**
 * 类转为SortedMap
 *
 * @author zishuzhao
 */
@Slf4j
public class ObjectToMapUtil {
    /**
     * 将指定对象属性名称和属性值转化为Map键值对
     *
     * @param obj
     * @return
     */
    public static SortedMap<String, String> objectToMap(Object obj) {
        if (obj == null) {
            log.error("obj empty.");
            throw new ServiceException(SystemCode.PARAM_MISS);
        }
        Class clazz = obj.getClass();
        SortedMap<String, String> map = new TreeMap();
        getClass(clazz, map, obj);
        SortedMap<String, String> newMap = convertSortedMap(map);
        return newMap;
    }

    /**
     *
     */
    private static void getClass(Class clazz, SortedMap map, Object obj) {
        if (clazz.getSimpleName().equals("Object")) {
            return;
        }

        Field[] fields = clazz.getDeclaredFields();
        if (fields == null || fields.length <= 0) {
            throw new ServiceException(SystemCode.PARAM_MISS);
        }
        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            String name = fields[i].getName();
            Object value = null;
            try {
                value = fields[i].get(obj);
            } catch (IllegalAccessException e) {
                log.error("field get value error");
                e.printStackTrace();
            }
            map.put(name, value);

        }
        Class superClzz = clazz.getSuperclass();
        getClass(superClzz, map, obj);
    }

    /**
     * @param map
     * @return
     * @throws Exception
     */
    private static SortedMap convertSortedMap(SortedMap map) {

        SortedMap newMap = new TreeMap();
        Set keys = map.keySet();
        Iterator it = keys.iterator();
        while (it.hasNext()) {
            Object key = it.next();
            convertToString(map.get(key), newMap, key);
        }

        return newMap;
    }

    /**
     * @param value
     * @param newMap
     * @param key
     */
    private static void convertToString(Object value, SortedMap newMap, Object key) {
        if (value != null) {
            Class clazz = value.getClass();
            if (isBaseType(clazz)) {
                newMap.put(key, value.toString());
            }
        }
    }

    /**
     * @param clazz
     * @return
     */
    private static boolean isBaseType(Class clazz) {
        if (clazz == String.class) {
            return true;
        }
        if (clazz == Integer.class) {
            return true;
        }
        return false;
    }
}

中间用的到常量约束,随机字符串生成工具类(雪花算法等)我就不贴出来了,都是很简单的一些代码,根据个人和业务要求进行选择。
至此,整个支付功能就打通了,剩下的就是前段调起支付界面,然后后端接受微信的回调信息。
**TIPS:**因为可能会有高并发的情况,但是不能同时有多个相同的订单,所以自己根据业务需求解决高并发。
这是我controller层回调函数接口:

/**
     * 回调接口,处理微信返回的支付消息
     */
    @PostMapping("/wxpayback")
    public void WXNotify(HttpServletRequest request, HttpServletResponse response) {
        log.info("wx payback enter");
        String resultXML = wxPayCallbackService.payCallback(request, response);
        try {
            BufferedOutputStream out = new BufferedOutputStream(
                    response.getOutputStream());
            out.write(resultXML.getBytes());
            out.flush();
            out.close();
            log.info("response wx callback api");
        } catch (IOException e) {
            log.error("stream close error.");
            e.printStackTrace();
        }
    }

处理回调的service层代码:

    public String payCallback(HttpServletRequest request, HttpServletResponse response) {
        String resultXML = "";
        //微信返回的数据流,xml形式的String
        String notityXml = parseData(request);
        if (notityXml == null) {
            log.error("callback parse error.");
            resultXML = WXCallbackUtil.callbackError();
        } else {
            SortedMap<String, String> map = WXPayUtil.parseXml(notityXml);
            //只有返回成功时,才有参数,才会进行参数校验
            String returnCode = map.get("return_code");
            if (returnCode == null) {
                log.error("wx return format error.");
                resultXML = WXCallbackUtil.callbackError();
            } else {
                if (returnCode.equals(RewardConstants.SUCCESS)) {
                    String sign = WXPayUtil.sign(WXPayUtil.createLinkString(WXPayUtil.paraFilter(map)));
                    Integer originalFee = weChatOrderInfoMapper.searchFee(map.get("out_trade_no"));
                    //对通知消息的签名校验,并对金额参数和原始参数进行校验
                    int checkResult = WXCallbackUtil.checkCallbackParam(map, sign, originalFee);
                    //校验通过,对消息的处理
                    if (checkResult == RewardConstants.CHECKSUCCESS) {
                        updateOrder(map, buildCallbackInfo(map.get("out_trade_no"), notityXml));
                        resultXML = WXCallbackUtil.callbackSuccess();
                    }
                    //签名错误,返回对应信息
                    if (checkResult == RewardConstants.SIGNERROR) {
                        resultXML = WXCallbackUtil.signError();
                    }
                    //参数错误,金额对不上或者订单查不到
                    if (checkResult == RewardConstants.PARAMERROR) {
                        resultXML = WXCallbackUtil.paramError();
                    }
                }
                log.info("receive wx callback request");
            }
        }
        return resultXML;
    }

    /**
     * 解析返回的数据流信息
     */
    private String parseData(HttpServletRequest request) {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            br.close();
            return sb.toString();
        } catch (IOException e) {
            log.error("stream parse error.");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构造返回信息表包装类
     */
    private PayCallbackInfo buildCallbackInfo(String localOrderNO, String text) {
        PayCallbackInfo payCallbackInfo = new PayCallbackInfo();
        payCallbackInfo.setLocalOrderNo(localOrderNO);
        payCallbackInfo.setCallback(text);
        return payCallbackInfo;
    }

    /**
     * 业务处理,DAO层代码
     */
    private void updateOrder(SortedMap<String, String> param, PayCallbackInfo payCallbackInfo) {
       自己的业务逻辑代码
    }

    /**
     * 创建支付成功消息
     */
    private UserMessageFO buildSuccessInfo(String userId) {
        UserMessageFO userMessageFO = new UserMessageFO();
        userMessageFO.setUserId(userId);
        userMessageFO.setAppId(AppIdEnum.APPLET_WX.getCode());
        userMessageFO.setTitle("您的打赏支付已成功");
        userMessageFO.setContent("您提交的打赏支付已经成功");
        return userMessageFO;
    }

    /**
     * 创建支付失败消息
     */
    private UserMessageFO buildFailInfo(String userId) {
        UserMessageFO userMessageFO = new UserMessageFO();
        userMessageFO.setUserId(userId);
        userMessageFO.setAppId(AppIdEnum.APPLET_WX.getCode());
        userMessageFO.setTitle("您的打赏支付失败");
        userMessageFO.setContent("您提交的打赏支付未成功");
        return userMessageFO;
    }

其中WXCallbackUtil工具类是校验参数,和生成对应状态返回字符串信息的相关函数,没什么难度,就不在这里贴出来了。
**TIPS:**需要注意的是,处理消息要注意幂等性,解决幂等性的问题有很多种方法,自己根据业务需要选择一种方法。
接下来是对账的函数,因为微信时每天上午九点出前一天的账单,所以为了保险起见,我设置的是每天上午十一点去下载前一天的账单。
只有一个service层就够了。

/**
     * 每天的上午十一点下载前一天的账单,进行对账
     */
    @Scheduled(cron = "0 0 11 * * ?")
    public void downloadBill() {
        log.info("build request parameters");
        String requestParam = buildRequestParam();
        //调用微信下载API,发送下载请求,接受返回数据
        log.info("begin request wx api");
        String resultParam = WXPayUtil.httpRequest(downloadURL, "POST", requestParam);
        //对账时间
        String date = getBillDate();
        //对返回数据进行解析
        log.info("begin parse return data");
        if (!resultParam.contains(RewardConstants.FAIL)) {
			//自己查账的业务逻辑
            }
        }
    }

    /**
     * 生成下载对账单的请求参数
     */
    private String buildRequestParam() {
        SortedMap<String, String> param = new TreeMap<>();
        Date lastDate = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String date = dateFormat.format(lastDate);
        param.put("appid", appId);
        param.put("mch_id", mchId);
        param.put("nonce_str", RandomStringUtil.getRandomStringByLength(RewardConstants.WXNONCELENGTH));
        param.put("bill_date", date);
        param.put("bill_type", RewardConstants.SUCCESSBILL);
        String temp = WXPayUtil.createLinkString(param);
        String sign = WXPayUtil.sign(temp);
        param.put("sign", sign);
        //请求参数Map转换成为xml类型的字符串
        String requestParam = WXPayUtil.mapToXml(param);
        return requestParam;
    }

    /**
     * 取微信返回账单中上一天的订单总金额和订单数量
     */
    private List<Integer> WXCount(String resultBill) {
        List<Integer> result = new ArrayList<>();
        String[] str = resultBill.split("\n");
        int count = str.length;
        String[] info = str[count - 1].replace("`", "").split(",");
        if (info.length == str[count - 2].split(",").length) {
            //订单总数
            result.add(Integer.valueOf(info[0]));
            //订单总金额,金额单位为元,要换算为分
            log.info(info[1]);
            double totalFee = Double.valueOf(info[1]);
            result.add((int) (totalFee * 100));
        } else {
            log.error("bill message error.");
        }
        return result;
    }

    /**
     * 对返回的账单中的每个订单数据进行解析,都是字符串类型,不涉及类型转换,可以不进行非空判断
     */
    private List<WXBillInfoVO> parseBill(String resultBill) {
        List<WXBillInfoVO> wxBillInfoVOList = new ArrayList<>();
        String[] str = resultBill.split("\n");
        int count = str.length;
        //第一行是表头信息,所以不读取,后两行是总金额信息,所以也不读取
        for (int i = 1; i < count - 2; i++) {
            String[] info = str[i].replace("`", " ").split(",");
            WXBillInfoVO wxBillInfoVO = new WXBillInfoVO();
            if (info.length != str[0].split(",").length) {
                log.error("bill message error.");
                continue;
            }
            wxBillInfoVO.setTransDate(info[0]);
            wxBillInfoVO.setAppId(info[1]);
            wxBillInfoVO.setMchId(info[2]);
            wxBillInfoVO.setChildBusinessNo(info[3]);
            wxBillInfoVO.setEquipmentNo(info[4]);
            wxBillInfoVO.setTransactionId(info[5]);
            wxBillInfoVO.setOutTradeNo(info[6]);
            wxBillInfoVO.setOpenId(info[7]);
            wxBillInfoVO.setTransType(info[8]);
            wxBillInfoVO.setTransStatus(info[9]);
            wxBillInfoVO.setBankType(info[10]);
            wxBillInfoVO.setFeeType(info[11]);
            wxBillInfoVO.setTotalFee(info[12]);
            wxBillInfoVO.setCouponFee(info[13]);
            wxBillInfoVO.setGoodsName(info[14]);
            wxBillInfoVO.setAttach(info[15]);
            wxBillInfoVO.setServiceCharge(info[16]);
            wxBillInfoVO.setRate(info[17]);
            wxBillInfoVO.setOrderFee(info[18]);
            wxBillInfoVO.setRateRemark(info[19]);
            wxBillInfoVOList.add(wxBillInfoVO);
        }
        return wxBillInfoVOList;
    }

    /**
     * 获取账单时间
     */
    private String getBillDate(){
        Date lastDate = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        return dateFormat.format(lastDate);
    }

我只写出了主要的流程代码,业务逻辑以及DAO层的操作自己每个人的业务不同,因此写的内容也不同,所以不具有参考性,这些逻辑代码已经经过业务验证没有问题,但是在展示中我删除了一些跟业务有关的代码,所以直接粘贴是没法运行的,各位自己补充。另外此次代码实现功能不包括退款,查询订单等功能,后续业务有需求,我会再继续开发,也会继续贴出来和大家分享。
TIPS:本次业务代码中HTTP请求处理的不够好,有能力的同学可以修改为其他包装工具,欢迎交流。

转载需要经过同意!!!!!!!!不得擅自转载!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值