首页 > 学院 > 开发设计 > 正文

微信APP支付——支付流程说明及示例

2019-11-09 17:14:48
字体:
来源:转载
供稿:网友

微信APP支付——支付流程说明及示例

官方示例图

微信支付官方文档地址:https://pay.weixin.QQ.com/wiki/doc/api/app/app.php?chapter=8_3 官方流程图:

商户系统和微信支付系统主要交互说明:步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。步骤3:统一下单接口返回正常的PRepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay步骤4:商户APP调起微信支付。api参见本章节【app端开发步骤说明】步骤5:商户后台接收支付通知。api参见【支付结果通知API】步骤6:商户后台查询支付结果。,api参见【查询订单API】

个人实际应用后的理解及实现

生成订单(与支付宝不太一样,订单的生成是在微信支付系统中生成,而不是本地系统)。app调用接口。异步接收返回通知,并根据结果处理自己的业务逻辑。

生成订单

组装统一下单接口参数(一个xml字符串)。调用支付接口,发送接口参数,创建预付单。如果成功,则会返回一个有效的prepay_id,这是app调用微信支付的一个关键参数。将结果返回给APP端,APP端发起调用一些细节要注意,微信的单位是“分”,支付宝的单位是“元”,所以共用订单的话要统一单位。如果出现“body不是UTF8编码”,则是在使用URL发起请求时,统一接口编码。 关键代码(UTF-8部分):// 获取URLConnection对象对应的输出流out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"UTF-8"));// 发送请求参数out.print(param);

app调用接口

参考官方集成文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5

异步接收返回通知,并根据结果处理自己的业务逻辑。

微信异步通知的返回地址是在生成订单时发送的参数里包含的(notify_url)。接收到异步消息。返回结果是一个xml字符串 。将返回的xml解析到map集合中。验证返回的数据(订单是否存在,订单状态是否已经为成功,金额是否正常等)验证通过,处理自己的业务逻辑(修改订单状态等)。由于是跟金钱挂钩的,日志要写得完善,我本地即写库也写日志,所以代码比较乱,不用的删除即可。

注意问题

各个阶段生成的前面是不一样的,参见TenpayUtil类。下单和返回都需要是一个参数有序的(ASCII正序)xml。预留位置,后续更新

代码

处理类VipWXPayController

import java.io.IOException;import java.io.PrintWriter;import java.math.BigDecimal;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.SortedMap;import java.util.TreeMap;import javax.annotation.Resource;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import net.sf.json.JSONObject;import org.apache.commons.lang.StringUtils;import org.apache.log4j.Logger;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;/** * 【会员管理】 微信支付 * @author pzr * */@SuppressWarnings({"unchecked"})@Controller@RequestMapping("/vipWXPay")public class VipWXPayController { @Resource private VipOrderMapper vipOrderMapper; @Resource private VipPriceMapper vipPriceMapper; @Resource private UserMapper userMapper; @Resource private VipWxpayAsynNotifyMapper vipWxpayAsynNotifyMapper; @Resource private VipPayNotifyMapper vipPayNotifyMapper; @Resource private VipPayService vipPayService; // 支付信息处理日志 /** * 支付日志 */ Logger payLogger = Logger.getLogger("pay-log"); /** * 微信支付的回调 * @return */ @RequestMapping(value = "/wxPay.do",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody public void wxPay(HttpServletRequest request,HttpServletResponse response){ payLogger.info("【=================================微信回调通知开始======================================】"); payLogger.info("【微信回调通知】正在接收微信回调报文......"); String resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; try { ServletInputStream in = request.getInputStream(); int size = request.getContentLength(); byte[] bdata = new byte[size]; in.read(bdata); String xmlstring = new String(bdata,TenpayUtil.getCharacterEncoding(request, response)); if(!StringUtils.isEmpty(xmlstring)){ payLogger.info("【微信回调通知】微信回调报文接收成功"); Map<String,String> paramMap = XmlUtil.parseXmlToMap(xmlstring); //打印返回结果// for(Map.Entry<String,String> entry : paramMap.entrySet()){// System.out.println(entry.getKey()+":"+entry.getValue());// } String result_code = paramMap.get("result_code").toString(); if("SUCCESS".equals(result_code.toUpperCase())){ //通过订单id和订单编号获取指定的订单信息 //存储反馈信息,不要 注释掉就可以了 VipWxpayAsynNotify vwan = saveSourceNotify(paramMap); VipOrder vo = new VipOrder(); vo.setId(paramMap.get("attach")); vo.setOrderNum(paramMap.get("out_trade_no")); payLogger.info("本地订单号【"+vo.getOrderNum()+"】【微信回调通知】支付成功"); vo = vipOrderMapper.findByIdOrderNum(vo); payLogger.info("本地订单号【"+vo.getOrderNum()+"】【微信回调通知】验证请求真实性......"); boolean flag = checkTrue(vwan,vo);//验证是否是微信返回的信息,防止“假请求” if(flag){ //存储到后台 支付通知表里 savePayNotify(vwan, vo); payLogger.info("用户【"+vo.getUserName()+"】本地订单号【"+vo.getOrderNum()+"】【微信回调通知】验证通过,业务处理中......"); vipPayService.vipHandle(vo); payLogger.info("用户【"+vo.getUserName()+"】本地订单号【"+vo.getOrderNum()+"】【微信回调通知】业务处理完成"); }else{ payLogger.info("本地订单号【"+vo.getOrderNum()+"】【微信回调通知】验证未通过"); } }else{ payLogger.info("【微信回调通知】支付失败,报错信息【"+paramMap.get("return_msg").toString()+"】"); } resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; }else{ payLogger.info("【微信回调通知】支付失败,回调报文为空"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } } catch (Exception e) { payLogger.info("【微信回调通知】内部异常"); e.printStackTrace(); }finally{ try { sendToCFT(resXml,response); } catch (IOException e) { e.printStackTrace(); } } payLogger.info("【=================================微信回调通知结束======================================】"); } /** * 保存支付通知 * @param vwan * @param vo */ private void savePayNotify(VipWxpayAsynNotify vwan, VipOrder vo) { VipPayNotify vipPayNotify = new VipPayNotify(); vipPayNotify.setGoodsId(vo.getGoodsId()); vipPayNotify.setGoodsName(vo.getGoodsName()); vipPayNotify.setOrderCreatetime(vo.getCreatetime()); vipPayNotify.setOrderNum(vo.getOrderNum());//订单编号 vipPayNotify.setPayAmount(fenToYuan(vwan.getTotal_fee()));//总金额,单位是元,微信需要转换 vipPayNotify.setPayState(vipPayService.getPayState(vwan.getReturn_code(),VipOrder.PAYMODE_WX));//返回状态 vipPayNotify.setBusinessId(Integer.parseInt(vwan.getId())); vipPayNotify.setPayType(VipOrder.PAYMODE_WX); vipPayNotify.setUserId(vo.getUserId()); vipPayNotify.setUserName(vo.getUserName()); vipPayNotifyMapper.add(vipPayNotify); } /** * 存储微信的原始回调信息 * @param paramMap * @return */ private VipWxpayAsynNotify saveSourceNotify(Map<String, String> paramMap) { //存储到原始表 VipWxpayAsynNotify saveObj = new VipWxpayAsynNotify(); saveObj.setAppid(paramMap.get("appid")); saveObj.setAttach(paramMap.get("attach")); saveObj.setBank_type(paramMap.get("bank_type")); saveObj.setCash_fee(paramMap.get("cash_fee")); saveObj.setCash_fee_type(paramMap.get("cash_fee_type")); saveObj.setCoupon_count(paramMap.get("coupon_count")); saveObj.setCoupon_fee(paramMap.get("coupon_fee")); saveObj.setDevice_info(paramMap.get("device_info")); saveObj.setErr_code(paramMap.get("err_code")); saveObj.setErr_code_des(paramMap.get("err_code_des")); saveObj.setFee_type(paramMap.get("fee_type")); saveObj.setIs_subscribe(paramMap.get("is_subscribe")); saveObj.setMch_id(paramMap.get("mch_id")); saveObj.setNonce_str(paramMap.get("nonce_str")); saveObj.setOpenid(paramMap.get("openid")); saveObj.setOut_trade_no(paramMap.get("out_trade_no")); saveObj.setReturn_code(paramMap.get("return_code")); saveObj.setReturn_msg(paramMap.get("return_msg")); saveObj.setSign(paramMap.get("sign")); saveObj.setTime_end(paramMap.get("time_end")); saveObj.setTotal_fee(paramMap.get("total_fee")); saveObj.setTrade_type(paramMap.get("trade_type")); saveObj.setTransaction_id(paramMap.get("transaction_id")); vipWxpayAsynNotifyMapper.add(saveObj); return saveObj; } /** * 验证数据真实性 * @param vaan * @return */ private boolean checkTrue(VipWxpayAsynNotify vwan,VipOrder vo) { //一、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号 //如果不存在则说明反馈的订单号和订单id对不上 if(vo == null){ payLogger.info("【微信回调通知】【订单验证失败】未获取本地订单"); return false; } payLogger.info("【微信回调通知】【订单验证成功】获取本地订单"); //验证订单是否已经完成,避免重复执行会员购买业务 if(vo.getPayState().equals(VipOrder.PAYSTATE_SUCCESS) || vo.getPayState().equals(VipOrder.PAYSTATE_FINISHED)){ payLogger.info("【微信回调通知】【订单验证失败】订单已完成支付,订单状态为【"+vo.getPayState()+"】"); return false; } payLogger.info("【微信回调通知】【订单验证成功】订单状态正常,订单状态为【"+vo.getPayState()+"】"); //二、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额) if(!YuanTofen(vo).equals(vwan.getTotal_fee())){ payLogger.info("【微信回调通知】【订单验证失败】订单金额异常,本地订单金额【"+YuanTofen(vo)+"】,回调订单金额【"+vwan.getTotal_fee()+"】"); return false; } payLogger.info("【微信回调通知】【订单验证成功】订单金额正常,订单金额为【"+vwan.getTotal_fee()+"】"); return true; } /** * 生成预支付单 * 商户系统先调用该接口在微信支付服务后台生成预支付交易单 * 返回正确的预支付交易回话标识后再在APP里面调起支付 * @param vipPriceId 套餐id * @param username 用户名称 * @param request * @param response * @return */ @RequestMapping(value = "/createOrder.do") @ResponseBody public JSONObject createOrder(@RequestParam("id") String vipPriceId, @RequestParam("username") String username, HttpServletRequest request, HttpServletResponse response ) { payLogger.info("【=================================微信订单创建开始======================================】"); payLogger.info("用户【" + username + "】开始创建微信订单......"); User user = userMapper.findByName(username);//通过用户名获取用户 VipPrice vipPrice = vipPriceMapper.findById(vipPriceId);//通过套餐id获取套餐 VipOrder vo = vipPayService.addVipOrder(user, vipPrice,VipOrder.PAYMODE_WX);//创建订单 JSONObject jsonCode = wXHandle(request, response, vo);//微信的订单处理 payLogger.info("用户【" + username + "】创建微信订单成功,本地订单号【"+vo.getOrderNum()+"】"); payLogger.info("【=================================微信订单创建结束======================================】"); return jsonCode; } /** * 创建订单,微信操作 * @param request * @param response * @param vo * @return */ private JSONObject wXHandle(HttpServletRequest request, HttpServletResponse response, VipOrder vo) { JSONObject jsonCode = new JSONObject(); payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】参数开始生成......"); String orderInfo = getOrderReqData(response, request, vo); payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】参数生成成功"); String orderJsonStr = ""; try { payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】开始调用......"); orderJsonStr = HttpRequest.sendPost(ConstantUtil.PAY_ORDER_URL, orderInfo); Map<String, String> mapOrder = XmlUtil.doXMLParse(orderJsonStr); if (mapOrder.get("return_code").toString().equals("SUCCESS")) { payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】调用成功,生成预付单"); //时间戳 String timestamp = OrderReqDataUtil.getTimeStamp(); jsonCode.put("appid",mapOrder.get("appid").toString()); jsonCode.put("partnerid", ConstantUtil.MCH_ID); jsonCode.put("prepay_id", mapOrder.get("prepay_id").toString()); jsonCode.put("packageValue", ConstantUtil.PACKAGE); jsonCode.put("timeStamp", timestamp); jsonCode.put("nonceStr", mapOrder.get("nonce_str")); jsonCode.put("sign",getAppSign(mapOrder,timestamp)); } else { jsonCode.put("msg", "errorCode"); payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】调用失败,报错信息【"+mapOrder.get("return_msg").toString()+"】"); } } catch (Exception e) { jsonCode.put("msg", "errorCode"); payLogger.info("用户【" + vo.getUserName() + "】【微信操作】【统一下单API】内部异常"); e.printStackTrace(); } return jsonCode; } /** * 获取APP调用微信支付的签名 * @param mapOrder * @param timestamp * @return */ private String getAppSign(Map<String, String> mapOrder, String timestamp) { SortedMap<String, String> appParam = new TreeMap<String, String>(); appParam.put("appid", mapOrder.get("appid").toString()); appParam.put("noncestr", mapOrder.get("nonce_str")); appParam.put("package", "Sign=WXPay"); appParam.put("partnerid", ConstantUtil.MCH_ID); appParam.put("prepayid", mapOrder.get("prepay_id").toString()); appParam.put("timestamp", timestamp); return TenpayUtil.genAppSignMap(appParam); } /** * 统一下单 * 获取请求参数组装 * * @param strUrl * @return String */ private String getOrderReqData(HttpServletResponse response,HttpServletRequest request,VipOrder vo) { //使用有序集合 SortedMap<String, String> dataObj = new TreeMap<String, String>(); dataObj.put("appid", ConstantUtil.APP_ID);// 获取appid参数 dataObj.put("mch_id", ConstantUtil.MCH_ID);// 微信支付分配的商户号 dataObj.put("device_info", ConstantUtil.DEVICE_INFO);//终端设备号(门店号或收银设备ID),默认请传"WEB" dataObj.put("nonce_str", OrderReqDataUtil.getNonceStr());// 获取随机字符串 dataObj.put("body", vo.getGoodsName());// 商品或支付单简要描述 dataObj.put("detail", getDetail(vo));// 商品详情 //主要传送订单id dataObj.put("attach", vo.getId());// 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 dataObj.put("out_trade_no", vo.getOrderNum());// 户系统内部的订单号,32个字符内、可包含字母 dataObj.put("fee_type", ConstantUtil.FEE_TYPE);//货币类型 默认人民币:CNY dataObj.put("total_fee", YuanTofen(vo));//订单总金额 订单金额; dataObj.put("spbill_create_ip", OrderReqDataUtil.getIpAddr(request));// APP和网页支付提交用户端ip // dataObj.put("time_start", // OrderReqDataUtil.getDateTime("yyyyMMddHHmmss"));//订单生成时间 // dataObj.put("time_expire", // OrderReqDataUtil.getDateTime("yyyyMMddHHmmss"));//订单失效时间,必须大于5分钟 dataObj.put("notify_url", ConstantUtil.NOTIFY_URL);// 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。 dataObj.put("trade_type", ConstantUtil.TRADE_TYPE);//支付类型 取值如下:JSAPI,NATIVE,APP dataObj.put("sign", TenpayUtil.genServerSign(dataObj));// 获取签名 //打印// for(Map.Entry<String, String> entry : dataObj.entrySet()){// System.out.println(entry.getKey()+":"+entry.getValue());// } // 生成xml参数字符串 String resObj = XmlUtil.getRequestXml(dataObj); return resObj; } /** * 获取详情json字符串 * @param vo */ private String getDetail(VipOrder vo) { WXDetail wxDetail = new WXDetail(); List<WXGoodsInfo> goodsInfoList = new ArrayList<WXGoodsInfo>(); WXGoodsInfo wxGoodsInfo = new WXGoodsInfo(); wxGoodsInfo.setBody(vo.getGoodsName()); wxGoodsInfo.setGoods_id(vo.getOrderNum()); wxGoodsInfo.setGoods_name(vo.getGoodsName()); wxGoodsInfo.setPrice(YuanTofen(vo));//总价格 wxGoodsInfo.setQuantity("1");//商品数量 goodsInfoList.add(wxGoodsInfo); wxDetail.setGoods_detail(goodsInfoList); //转为json格式 JSONObject detailObject = JSONObject.fromObject(wxDetail); return detailObject.toString(); } /** * 获取微信价格 * 原始价格为单位为元,微信单位为分,所以需要转换 * @param vo * @return */ private String YuanTofen(VipOrder vo) { BigDecimal sourcePrice = new BigDecimal(vo.getCurrentPrice());//原始价格 单位元 BigDecimal b2 = new BigDecimal("100");//将元换算为分的单位 100 String tfee=Double.toString(sourcePrice.multiply(b2).doubleValue()); // 订单金额 String total_fee = tfee.substring(0, tfee.indexOf(".")); return total_fee; } /** * 将分转换为元 如:1 分= 0.01元 * @param price * @return */ private String fenToYuan(String price){ BigDecimal sourcePrice = new BigDecimal(price);//原始价格 单位元 BigDecimal b2 = new BigDecimal("100");//将元换算为分的单位 100 String tfee=Double.toString(sourcePrice.divide(b2).doubleValue()); // 订单金额 return tfee; } /** * 给微信返回信息,通知接收情况 * @param msg * @param response * @throws IOException */ private void sendToCFT(String msg,HttpServletResponse response) throws IOException { String strHtml = msg; PrintWriter out = response.getWriter(); out.println(strHtml); out.flush(); out.close(); } }

基础参数类 ConstantUtil

/** * 微信支付配置 * @author pzr * */public class ConstantUtil { /** * 商户id */ public static String MCH_ID = "11111"; // 商户号 // 商户号 /** * 应用id,appId */ public static String APP_ID = "11111"; // 微信开发平台应用id /** * APP_SECRET */ public static String APP_SECRET = "111111"; // 应用对应的凭证 /** * 秘钥 */ public static String APP_KEY = "111111"; // 商户号对应的密钥 /** * 扩展字段 */ public static String PACKAGE = "Sign=WXPay"; // 扩展字段 暂填写固定值Sign=WXPay /** * 设备号 */ public static String DEVICE_INFO = "WEB";// 设备号 终端设备号(门店号或收银设备ID),默认请传"WEB" /** * 通知回调接口路径 */ public static String NOTIFY_URL = "http://11111"; /** * 钞票类型 人民币 */ public static String FEE_TYPE = "CNY"; /** * 交易类型 */ public static String TRADE_TYPE = "APP";//交易类型 /** * 固定的,统一下单后调用的生成预付单接口 */ public static String PAY_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";}

工具类 OrderReqDataUtil

import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;import javax.servlet.http.HttpServletRequest;public class OrderReqDataUtil { public static void main(String args[]){ System.out.println(getRandomStringByLength(32)); } /** * 生成指定长度的随机字符串 * @param length * @return */ public static String getRandomStringByLength(int length) { String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } /** * 生成随机字符串 * * @return */ public static String getNonceStr() { Random random = new Random(); return md5Util.MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8"); } public static String getTimeStamp() { return String.valueOf(System.currentTimeMillis() / 1000); } public static String getDateTime(String format) { String temp_str = ""; Date dt = new Date(); // 最后的aa表示“上午”或“下午” HH表示24小时制 如果换成hh表示12小时制 SimpleDateFormat sdf = new SimpleDateFormat(format); temp_str = sdf.format(dt); return temp_str; } public static String getIpAddr(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; }}

工具类 TenpayUtil

import java.text.SimpleDateFormat;import java.util.Date;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.SortedMap;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * 微信支付工具 * @author pzr * */public class TenpayUtil { private static Object Server; private static String QRfromGoogle; /** * 把对象转换成字符串 * * @param obj * @return String 转换成字符串,若对象为null,则返回空字符串. */ public static String toString(Object obj) { if (obj == null) return ""; return obj.toString(); } /** * 把对象转换为int数值. * * @param obj * 包含数字的对象. * @return int 转换后的数值,对不能转换的对象返回0。 */ public static int toInt(Object obj) { int a = 0; try { if (obj != null) a = Integer.parseInt(obj.toString()); } catch (Exception e) { } return a; } /** * 获取当前时间 yyyyMMddHHmmss * * @return String */ public static String getCurrTime() { Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String s = outFormat.format(now); return s; } /** * 获取当前日期 yyyyMMdd * * @param date * @return String */ public static String formatDate(Date date) { SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); String strDate = formatter.format(date); return strDate; } /** * 取出一个指定长度大小的随机正整数. * * @param length * int 设定所取出随机数的长度。length小于11 * @return int 返回生成的随机数。 */ public static int buildRandom(int length) { int num = 1; double random = Math.random(); if (random < 0.1) { random = random + 0.1; } for (int i = 0; i < length; i++) { num = num * 10; } return (int) ((random * num)); } /** * 获取编码字符集 * * @param request * @param response * @return String */ public static String getCharacterEncoding(HttpServletRequest request, HttpServletResponse response) { if (null == request || null == response) { return "gbk"; } String enc = request.getCharacterEncoding(); if (null == enc || "".equals(enc)) { enc = response.getCharacterEncoding(); } if (null == enc || "".equals(enc)) { enc = "gbk"; } return enc; } /** * Url编码 * @param content * @return */ public static String URLencode(String content) { String URLencode; URLencode = replace(Server.equals(content), "+", "%20"); return URLencode; } private static String replace(boolean equals, String string, String string2) { return null; } /** * 获取unix时间,从1970-01-01 00:00:00开始的秒数 * * @param date * @return long */ public static long getUnixTime(Date date) { if (null == date) { return 0; } return date.getTime() / 1000; } public static String QRfromGoogle(String chl) { int widhtHeight = 300; String EC_level = "L"; int margin = 0; String QRfromGoogle; chl = URLencode(chl); QRfromGoogle = "http://chart.apis.google.com/chart?chs=" + widhtHeight + "x" + widhtHeight + "&cht=qr&chld=" + EC_level + "|" + margin + "&chl=" + chl; return QRfromGoogle; } /** * 时间转换成字符串 * * @param date * 时间 * @param formatType * 格式化类型 * @return String */ public static String date2String(Date date, String formatType) { SimpleDateFormat sdf = new SimpleDateFormat(formatType); return sdf.format(date); } /** * 生成【调用统一下单API】阶段的签名 * 按参数名称a-z排序, * 遇到空值的参数不参加签名。 * MD5加密并转换为大写 */ public static String genServerSign(SortedMap<String, String> packageParams) { StringBuffer sb = new StringBuffer(); Set es = packageParams.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 (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) { sb.append(k + "=" + v + "&"); } } sb.append("key=" + ConstantUtil.APP_KEY); System.out.println("md5 sb:" + sb); //MD5加密并全部转换为大写 String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); return sign; } /** * 生成【APP客户端调用微信支付】阶段签名 * @param params * @return */ public static String genAppSignMap(SortedMap<String, String> appParams) { StringBuilder sb = new StringBuilder(); for(Map.Entry<String, String> entry : appParams.entrySet()){ sb.append(entry.getKey()); sb.append('='); sb.append(entry.getValue()); sb.append('&'); } sb.append("key="); sb.append(ConstantUtil.APP_KEY);//秘钥 String appSign = MD5Util.MD5Encode(sb.toString(),"utf-8"); return appSign; } /** * 生成【APP客户端调用微信支付】阶段签名 * @param params * @return */ public static String genAppSign(List<Param> params) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < params.size(); i++) { sb.append(params.get(i).getKey()); sb.append('='); sb.append(params.get(i).getValue()); sb.append('&'); } sb.append("key="); sb.append(ConstantUtil.APP_KEY);//秘钥 String appSign = MD5Util.MD5Encode(sb.toString(),"utf-8"); return appSign; }}

商品集合对象 WXDetail 只是为了组装成需要的json格式可以直接用jsonArray

import java.util.List;public class WXDetail { /** * 微信商品详情集合对象 */ private List<WXGoodsInfo> goods_detail; public List<WXGoodsInfo> getGoods_detail() { return goods_detail; } public void setGoods_detail(List<WXGoodsInfo> goods_detail) { this.goods_detail = goods_detail; }}

商品详情对象 WXGoodsInfo

/** * 微信商品订单详情 * @author pzr * */public class WXGoodsInfo { /** * 【必填】商品编号 */ private String goods_id; /** * 【可选】微信支付定义的统一商品编号 */ private String wxpay_goods_id; /** * 【必填】商品名称 */ private String goods_name; /** * 【必填】商品数量 */ private String quantity; /** * 【必填】商品单价 单位分 */ private String price; /** * 【可选】商品类目id */ private String goods_category; /** * 【可选】商品描述信息 长度1000 */ private String body; public String getGoods_id() { return goods_id; } public void setGoods_id(String goods_id) { this.goods_id = goods_id; } public String getWxpay_goods_id() { return wxpay_goods_id; } public void setWxpay_goods_id(String wxpay_goods_id) { this.wxpay_goods_id = wxpay_goods_id; } public String getGoods_name() { return goods_name; } public void setGoods_name(String goods_name) { this.goods_name = goods_name; } public String getQuantity() { return quantity; } public void setQuantity(String quantity) { this.quantity = quantity; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } public String getGoods_category() { return goods_category; } public void setGoods_category(String goods_category) { this.goods_category = goods_category; } public String getBody() { return body; } public void setBody(String body) { this.body = body; }}

工具类 XmlUtil

import java.io.IOException;import java.io.InputStream;import java.io.StringReader;import java.io.UnsupportedEncodingException;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import java.util.SortedMap;import org.jdom2.Document;import org.jdom2.Element;import org.jdom2.JDOMException;import org.jdom2.input.SAXBuilder;import org.xml.sax.InputSource;public class XmlUtil { /** * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * * @param strxml * @return * @throws JDOMException * @throws IOException */ public static Map<String, String> doXMLParse(String strxml) throws JDOMException, IOException { if (null == strxml || "".equals(strxml)) { return null; } Map<String, String> m = new HashMap<String, String>(); InputStream in = HttpClientUtil.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; } /** * 获取子结点的xml * * @param children * @return String */ public 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(); } /** * 获取xml编码字符集 * * @param strxml * @return * @throws IOException * @throws JDOMException */ public static String getXMLEncoding(String strxml) throws JDOMException, IOException { InputStream in = HttpClientUtil.String2Inputstream(strxml); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(in); in.close(); return (String) doc.getProperty("encoding"); } /** * @author wjj * @date 2016-06-01下午2:32:05 * @Description:将请求参数转换为xml格式的string * @param parameters 请求参数 * @return */ public static String getRequestXml(SortedMap<String,String> 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>"); String result =sb.toString();// try {// result = new String(result.getBytes("UTF-8"), "ISO-8859-1");// } catch (UnsupportedEncodingException e) {// e.printStackTrace();// } return result; } /** * XML转为Map * @param xml * @return */ public static Map parseXmlToMap(String xml) { Map retMap = new HashMap(); try { StringReader read = new StringReader(xml); // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入 InputSource source = new InputSource(read); // 创建一个新的SAXBuilder SAXBuilder sb = new SAXBuilder(); // 通过输入源构造一个Document Document doc = sb.build(source); Element root = (Element) doc.getRootElement();// 指向根节点 List<Element> es = root.getChildren(); if (es != null && es.size() != 0) { for (Element element : es) { retMap.put(element.getName(), element.getValue()); } } } catch (Exception e) { e.printStackTrace(); } return retMap; } }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表