最近接触了一些比较新奇的东西,记录一下
先贴出微信官方的API地址,感受一下微信的魅力。。。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6
了解完微信下载账单的一些注意事项之后,咱们正式开始
下面是具体实现:
先贴出主方法,其他工具类会有具体说明:
public static void main(String[] args) throws Exception {
// downloadBill();
}
public static void downloadBill() throws Exception {
//这里的MyConfig工具类是自己封装的一些配置,为了方便自己使用,大家可以跳过这一步
MyConfig myConfig = new MyConfig();
SortedMap<Object,Object> parameters =new TreeMap<Object,Object>();
//这里面的value值,大家自己根据自己的微信商户参数配置一下
parameters.put("appid", myConfig.getAppID());//appid
parameters.put("mch_id", myConfig.getMchID());//商户号
parameters.put("nonce_str", CreateNoncestr());//随机字符串
parameters.put("bill_date", "20180125");//对账单日期
parameters.put("bill_type", "ALL");//对账单类型
//这里调用方法生成微信需要的签名(这里是一个坑点,当时在做微信退款的时候因为签名不符合规范被卡一天时间)
String sign = createSign("utf-8", parameters);//签名
parameters.put("sign", sign);
//这里的getRequestXml方法是转xml的工具方法,下面我会贴出来
String reuqestXml = getRequestXml(parameters);
/**
* 这里的CommonUtil是一个https通用工具类,我也会在下面贴出来
* download_bill_url是微信官方提供的对账单下载地址
* download_bill_url = “https://api.mch.weixin.qq.com/pay/downloadbill“
*/
String result=CommonUtil.httpsRequest(myConfig.download_bill_url, "POST", reuqestXml);
//微信对账单生成时间是次日的9点之后,所以查询日期为当天时,错误信息提示日期无效
if(result.startsWith("<xml>")){
System.out.println(result);
System.out.println("无订单");
}else {
String tradeMsg = result.substring(result.indexOf("`"));
String tradeInfo = tradeMsg.substring(0, tradeMsg.indexOf("总")).replace("`", "");// 去掉汇总数据,并且去掉'`'
String tradeInfo = tradeMsg.substring(0,tradeMsg.indexOf("总"));
String tradeTotalMsg =tradeMsg.substring(tradeMsg.indexOf("总"));
String tradeTotalInfo =tradeTotalMsg.substring(tradeTotalMsg.indexOf("`"));
System.out.println("result----->"+result);
System.out.println("tradeMsg----->"+tradeMsg);
System.out.println("tradeInfo----->"+tradeInfo);
System.out.println("tradeTotalMsg----->"+tradeTotalMsg);
System.out.println("tradeTotalInfo----->"+tradeTotalInfo);
//最后一栏是费率,里面以%结尾,以此作为切割目标,方便操作存数据库
String[] tradeArray = tradeInfo.split("%");
List<Map<String, Object>> resultList = new ArrayList<>();
for(int i = 0;i < tradeArray.length;i++) {
String[] tradeDetailArray = tradeArray[i].split(",");
Map<String, Object> map = new HashMap<>();
/**
* 这里我取了几个对我来说用处较大的几个字段
* 详细字段的话,大家可以参考一下这里,或自己看控制台打印结果
* https://www.cnblogs.com/mgqy/articles/7657483.html
*/
map.put("readeTime", tradeDetailArray[0]);//交易时间
map.put("appid", tradeDetailArray[1]);//公众号ID
map.put("mchId", tradeDetailArray[2]);//商户号
map.put("transactionId", tradeDetailArray[5]);//微信订单号
map.put("outTradeNo", tradeDetailArray[6]);//商户订单号
map.put("openid", tradeDetailArray[7]);//用户标识(openid)
map.put("tradeState", tradeDetailArray[9]);// 交易状态
map.put("tradeBank", tradeDetailArray[10]);// 付款银行
map.put("totalFee", tradeDetailArray[12]);//总金额
map.put("refundFee", tradeDetailArray[16]);//退款金额
map.put("tradeName", tradeDetailArray[20]);// 商品名称
map.put("poundage", tradeDetailArray[22]);//手续费
resultList.add(map);
}
System.out.println("resultList--->"+resultList);
}
}
下面是一些用到的工具类和方法:
1、随机字符串生成方法
/**
* 随机字符串
* @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;
}
2、编写签名方法
/**
* 编写签名
* @param charSet
* @param parameters
* @return
* @throws Exception
*/
public static String createSign(String charSet,SortedMap<Object,Object> parameters) throws Exception{
MyConfig myconfig = new MyConfig();
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=" + myconfig.getKey());
// String sign = MD5Util.MD5Encode(sb.toString(), charSet).toUpperCase();
String sign = MD5Util.MD5Encode(sb.toString(), charSet).toUpperCase();
// String sign = MD5.MD5Encode(sb.toString(), charSet).toUpperCase();
return sign;
}
3、转xml格式方法
/**
* 转为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();
}
4、https通用工具类
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import org.apache.log4j.Logger;
import net.sf.json.JSONObject;
/**
* https通用工具类
*/
public class CommonUtil {
private static Logger log = Logger.getLogger(CommonUtil.class);
public static JSONObject httpsRequestToJsonObject(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
String buffer = httpsRequest(requestUrl, requestMethod, outputStr);
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (Exception e) {
log.error("https请求异常:"+e.getMessage());
}
return jsonObject;
}
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;
}
}
到此,微信下载对账单功能就实现了
代码写的不好之处,请大家多多包涵并提出宝贵意见 937017870@qq.com