微信下载对账单

微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
了解一些注意事项后,具体实现

import com.weein.quickpass.core.config.WeChatConfig;
import com.weein.wcommon.utils.DateUtils;

import java.util.*;

/**
 * @Des下载微信对账单
 * @Author hzt
 */
public class DownloadBillUtils {

    public static void main(String[] args) throws Exception {
        String list = downloadBill();
        System.out.println(list);
    }

    public static String downloadBill() throws Exception {
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        //这里面的value值,大家自己根据自己的微信商户参数配置一下
        parameters.put("appid", WeChatConfig.APPID);//appid
        parameters.put("mch_id", WeChatConfig.MCH_ID);//商户号
        //parameters.put("device_info", "");//微信支付分配的终端设备号,填写此字段,只下载该设备号 的对账单
        parameters.put("nonce_str", CreateNoncestr());//随机字符串
        //下载对账单的日期,格式:20140603,当前日期前一天。
        //parameters.put("bill_date", "20190329");
        String billDate = DateUtils.format(DateUtils.addDay(new Date(), -1), DateUtils.FORMAT_DATE_02);
        parameters.put("bill_date", billDate);
        //bill_type:ALL返回当日所有订单信息,默认值SUCCESS返回当日成功支付的订单。REFUND,返回当日退款订单
        parameters.put("bill_type", "ALL");//对账单类型
        //这里调用方法生成微信需要的签名(这里是一个坑点,当时在做微信退款的时候因为签名不符合规范被卡一天时间)
        String sign = createSign("utf-8", parameters);//签名
        parameters.put("sign", sign);

        //getRequestXml():是转xml的工具方法
        String requestXml = getRequestXml(parameters);
        //从微信下载对账单
        String result = HttpUtil.httpsRequest(WeChatConfig.DOWNLOAD_BILL_URL, "POST", requestXml);
        return result;

    }


    /**
     * 随机字符串
     *
     * @return
     */
    public static String CreateNoncestr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String res = "";
        for (int i = 0; i < 16; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        return res;
    }

    /**
     * 编写签名
     *
     * @param charSet
     * @param parameters
     * @return
     * @throws Exception
     */
    public static String createSign(String charSet, SortedMap<Object, Object> parameters) throws Exception {
        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();
            Object v = entry.getValue();
            if (null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + WeChatConfig.KEY);
        String sign = MD5Util.MD5Encode(sb.toString(), charSet).toUpperCase();
        return sign;
    }

    /**
     * 转为xml格式
     *
     * @param parameters
     * @return
     */
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }
}

Do

public class WeChatBillDO implements Serializable {
    private Integer id;

    /**
     * 交易时间
     */
    private String tradeTime;

    /**
     * 公众账号ID
     */
    private String appId;

    /**
     * 商户号
     */
    private String mchId;

    /**
     * 子商户号
     */
    private String mchAppId;

    /**
     * 设备号
     */
    private String deviceInfo;

    /**
     * 微信订单号
     */
    private String transactionId;

    /**
     * 商户订单号
     */
    private String outTradeNo;

    /**
     * 用户标识
     */
    private String openId;

    /**
     * 交易类型
     */
    private String tradeType;

    /**
     * 交易状态
     */
    private String tradeStatus;

    /**
     * 付款银行
     */
    private String payBank;

    /**
     * 货币种类
     */
    private String moneyType;

    /**
     * 应结订单金额
     */
    private String orderPay;

    /**
     * 代金劵金额
     */
    private String voucherAmount;

    /**
     * 微信退款单号
     */
    private String refundNumber;

    /**
     * 商户退款单号
     */
    private String outRefundNo;

    /**
     * 退款金额
     */
    private String refundAmount;

    /**
     * 充值劵退款金额
     */
    private String refundAmountVoucher;

    /**
     * 退款类型
     */
    private String refundsType;

    /**
     * 退款状态
     */
    private String refundsStatus;

    /**
     * 商品名称
     */
    private String commodityName;

    /**
     * 商户数据包
     */
    private String dataPacket;

    /**
     * 手续费
     */
    private String serviceCharge;

    /**
     * 费率
     */
    private String rate;

    /**
     * 订单金额
     */
    private String orderAmount;

    /**
     * 申请退款金额
     */
    private String applicationRefundAmount;

    /**
     * 费率备注
     */
    private String rateNotes;

HttpUtil

import org.apache.log4j.Logger;

import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;


public class HttpUtil {
    private static Logger log = Logger.getLogger(HttpUtil.class);

    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr){
        try {
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时:{}");
        } catch (Exception e) {
            System.out.println("https请求异常:{}");
        }
        return null;
    }
}

MD5Util

import java.security.MessageDigest;

/**
 * 
 * @Title: MD5Util.java
 * @Description: MD5加密 工具类
 * 
 * @author liufei
 * @date 2019年3月18日
 */
public class MD5Util {
    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++)
            resultSb.append(byteToHexString(b[i]));

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n += 256;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes()));
            else
                resultString = byteArrayToHexString(md.digest(resultString
                        .getBytes(charsetname)));
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

定时下载微信对账单

 /**
     * 生成下载微信对账单并存入数据库任务
     */
    @Scheduled(cron = "30 * * * * ?")
    public void downloadWeChatBill() {
        weChatBillService.saveWeChatBill();
    }

将对账单存入数据库实现

public interface IWeChatBillService {
    int saveWeChatBill();
}
public class WeChatBillServiceImpl implements IWeChatBillService {
    private final static Logger log = LoggerFactory.getLogger(WeChatBillServiceImpl.class);
    @Resource
    IWeChatBillMapper weChatBillMapper;

    @Override
    public int saveWeChatBill() {
        String result = null;
        try {
            result = DownloadBillUtils.downloadBill();
            if (result.startsWith("<xml>")) {//查询日期为当天时,错误信息提示日期无效
                log.info(result);
                log.info("无订单");
                return 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        int x = 0;
        int i = result.indexOf("`");
        int j = result.indexOf("总");

        String substring = result.substring(i, j - 2);
        String[] temp = substring.split(",``");

        for (int k = 0; k < temp.length; k++) {
            String[] payment = temp[k].replace("`", "").split(",");
            WeChatBillDO bean = new WeChatBillDO();
            bean.setTradeTime(payment[0]);
            bean.setAppId(payment[1]);
            bean.setMchId(payment[2]);
            bean.setMchAppId(payment[3]);
            bean.setDeviceInfo(payment[4]);
            bean.setTransactionId(payment[5]);
            bean.setOutTradeNo(payment[6]);
            bean.setOpenId(payment[7]);
            bean.setTradeType(payment[8]);
            bean.setTradeStatus(payment[9]);
            bean.setPayBank(payment[10]);
            bean.setMoneyType(payment[11]);
            bean.setOrderPay(payment[12]);
            bean.setVoucherAmount(payment[13]);
            bean.setRefundNumber(payment[14]);
            bean.setOutRefundNo(payment[15]);
            bean.setRefundAmount(payment[16]);
            bean.setRefundAmountVoucher(payment[17]);
            bean.setRefundsType(payment[18]);
            bean.setRefundsStatus(payment[19]);
            bean.setCommodityName(payment[20]);
            bean.setDataPacket(payment[21]);
            bean.setServiceCharge(payment[22]);
            bean.setRate(payment[23]);
            bean.setOrderAmount(payment[24]);
            bean.setApplicationRefundAmount(payment[25]);

            x = weChatBillMapper.insertSelective(bean);
        }
        return x;
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,565评论 6 525
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,696评论 3 406
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,935评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,327评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,338评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,760评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,085评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,091评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,656评论 1 327
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,657评论 3 348
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,767评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,360评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,088评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,493评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,654评论 1 278
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,374评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,841评论 2 367

推荐阅读更多精彩内容