一、查看接口
项目中要进行对微信支付的账单进行对账,网上查一了一下,基本上所有的模式都是直接调用返回字符串的模式。微信官方接口如下微信对账官方接口
我们可以看到,其中有一个tar_type字段,网上大部分的对账单下载都是字符串格式进行处理,也就是说tar_type是不用传的,那么我就想,如果字符串数据过大,可能会造成数据的丢失,那么远不如下载文件来的方便。
我这里使用的是 XXL-JOB 进行定时下载处理文件。话不多说,上代码。
二、定时下载
首先定时机制将在后面介绍,这里就直接截图处理了
下面进行下载微信的对账文件,我们也看到了,其格式要求为GZIP的,之前我也直接存过ZIP,但是代码解压不出来,windows上直接手动解压可以,再手动压缩用代码解压也可以。就是下载后直接解压告诉我们不是ZIP文件,所以这里必须要保存它的原来的 .gzip 格式。
下面是文件的下载:
/**
* 文件格式的微信对账单
*
* @param mchnt
* @throws Exception
*/
public void downWxpayBill(PaygatewayMchnt mchnt) throws Exception {
// 拿微信的参数
String wxPayKey ="微信支付时的商户秘钥KEY";
String wxMchntId = "微信支付时候的商户号";
String wxAppaId = "微信支付时候的商户APPID";
// 实例化当天的日期
Date today = new Date();
// 用当天的日期减去24小时得到昨天的日期
Date yesterdayDate = new Date(today.getTime() - 86400000L);
// 将昨天日期解析成字符串
String billDate = new SimpleDateFormat("yyyyMMdd").format(yesterdayDate);
MyConfig config = new MyConfig(wxPayKey, wxMchntId, wxAppaId);
// 微信公共参数封装
WXPay wxpay = new WXPay(config);
// 读取公共参数并创建处理对象
Map<String, String> paramMap = new HashMap<String, String>();
// 对账单日期 格式:20140603
paramMap.put("bill_date", billDate);
// 随机字符串
paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
paramMap.put("bill_type", "ALL");// 账单类型 ALL SUCCESS REFUND RECHARGE_REFUND
paramMap.put("tar_type", "GZIP");//文件格式
String sign = WXPayUtil.generateSignature(paramMap, wxPayKey);
paramMap.put("sign", sign);// 签名
//微信SDK的下载对账单
/****************START*********************/
Map<String, String> respMap = wxpay.downloadBill(paramMap);
String wxbillPath = propertiesDIY.getFile_path_wxpay();
//判断有没有文件
if (("SUCCESS").equals(respMap.get("return_code")) && ("ok").equals(respMap.get("return_msg"))) {
logger.debug("success for wxpay bill");
//这时候打印的返回内容是乱码,我们不用理会
String requestXml = WXPayUtil.mapToXml(paramMap);
String filePath = wxbillPath + File.separator + mchnt.getMchntId() + "-" + billDate + ".gzip";
//准备下载
HttpClientUtil.downWxpayBill(WXPayConstants.DOWNLLOAD_BIILLURL, filePath, requestXml);
logger.debug("download success:[" + mchnt.getInstId() + mchnt.getMchntId() + "-" + billDate + ".gzip]");
} else if (("No Bill Exist").equals(respMap.get("return_msg"))) {
logger.debug("no wxpay bill:[" + mchnt.getInstId() + "-" + mchnt.getMchntId() + "-" + billDate + "]");
} else {
logger.error("call wxpay for bills fail:[" + mchnt.getInstId() + "-" + mchnt.getMchntId() + "-" + billDate + "]");
}
/****************END********************/
//把文件全都移走到
List<String> files = FileUtil
.getFile(new File(wxbillPath + File.separator + propertiesDIY.getFile_path_recvtmp()));
if (files.size() != 0) {
for (String filename : files) {
FileUtil.MoveFile(wxbillPath + File.separator + propertiesDIY.getFile_path_recvtmp(), wxbillPath + File.separator + propertiesDIY.getFile_path_recv(), filename);
}
}
}
上面的START–END可以不需要的,我这里是判断了一下有没有对账单来判断要不要下载,实际上请求判断+下载是两次请求过程了。
下面给出downWxpayBill工具类,其中
WXPayConstants.DOWNLLOAD_BIILLURL=https://api.mch.weixin.qq.com/pay/downloadbill
微信对账单地址
/**
* 微信对账
*
* @param Url
* @param savePath
* @param requestXml
*/
public static void downWxpayBill(String Url, String savePath, String requestXml) {
// 设置访问地址
URL url = null;
HttpURLConnection httpURLConnection = null;
InputStream inputStream = null;
FileOutputStream fos = null;
try {
url = new URL(Url);
// http的连接类 得到网络访问对象
httpURLConnection = (HttpURLConnection) url.openConnection();
// 设置请求参数(访问方式,超时时间,输入,输出流,请求头信息),以流的形式进行连接
// 设定请求的方法,默认是GET
httpURLConnection.setRequestMethod("POST");
// 超时时间
httpURLConnection.setConnectTimeout(5000);
// 设置是否向HttpURLConnection输出
httpURLConnection.setDoOutput(true);
// 设置是否从httpUrlConnection读入
httpURLConnection.setDoInput(true);
// 设置使用编码格式参数的名-值对
httpURLConnection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
httpURLConnection.setRequestProperty("Charsert", "UTF-8");
// 简历连接
httpURLConnection.connect();
if (requestXml != null && requestXml != "") {
// 写入参数到请求中
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(httpURLConnection.getOutputStream(), "UTF-8"));
// 传递参数
writer.write(requestXml.toString());
writer.flush();
writer.close();
}
// 获取响应code 200成功
int code = httpURLConnection.getResponseCode();
if (code == 200) {
inputStream = httpURLConnection.getInputStream();
// 判断字节大小
if (inputStream.available() != 0) {
File file = new File(savePath);
if (!file.getParentFile().exists()) {
boolean result = file.getParentFile().mkdirs();
if (!result) {
logger.error("creat file fail");
}
}
byte[] temp = new byte[2048];
int b;
fos = new FileOutputStream(file);
while ((b = inputStream.read(temp)) != -1) {
fos.write(temp, 0, b);
fos.flush();
}
}
}
// 关闭 http连接,释放资源
httpURLConnection.disconnect();
} catch (IOException e) {
logger.error("ERR:", e);
} finally {
//最终都执行关流
try {
if (inputStream != null)
inputStream.close();
if (fos != null)
fos.close();
if (httpURLConnection != null)
httpURLConnection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
三、解压下载文件
这时候我们执行下载后,会下载下图的文件,看起来想txt的是因为可以用txt打开
我们用UE或者txt打开都是乱码,最主要的是,windows没有自带gzip文件的解压格式,用的其他软件也没有。这为我们的工作带来的困难。因为我不知道下载的是不是我们需要的。
下面就直接进行解压操作看一下,文件里的内容是不是我们想要的。
GZIPInputStream ginm = null;
BufferedReader reader = null;
FileOutputStream fos = null;
int lineCount = 0;
try {
//zipFilePath为压缩包在的全路径
ginm = new GZIPInputStream(new FileInputStream(zipFilePath));
reader = new BufferedReader(new InputStreamReader(ginm, "UTF-8"));
String lineCon;
//filePath为要解压的全称,包括文件名,我这里是方便后面操作也可以改为txt格式
fos = new FileOutputStream(filePath + File.separator + gzipName.substring(0, 29));
while ((lineCon = reader.readLine()) != null) {
//这里加一个\n是因为读取的文件都是一行,我们给他区别行,方便读取
fos.write((lineCon + "\n").getBytes());
lineCount++;
}
ginm.close();
reader.close();
fos.close();
} catch (Exception e) {
logger.error("UnGzip fail", e);
} finally {
if (null != reader) {
reader.close();
}
if (null != fos) {
fos.close();
}
if (null != ginm) {
ginm.close();
}
}
解压过程是拿到全路径文件地址(包括文件名),解压也是全路径
成功
就此完毕,下面就是读取文件,千篇一律了,不做详细介绍了,告辞!