对接微信扫码支付(模式2),前端使用velocity技术
(1)调用微信支付接口(view层) 此部分业务逻辑部分可以省略
1 @RequestMapping("/wxpay.htm") 2 public ModelAndView wxpay(HttpServletRequest request,HttpServletResponse response, String id, String type, 3 String payment_id) 4 { 5 ModelAndView mv = new JModelAndView("wxpay.html", 6 configService.getSysConfig(), 7 this.userConfigService.getUserConfig(), 1, request, 8 response); 9 /*处理业务逻辑开始,如获取当前订单单号,充值单号,积分兑换单号,获取当前价格 10 此处为自定义部分 11 */ 12 OrderForm of = null; 13 Predeposit obj = null; 14 GoldRecord gold = null; 15 IntegralGoodsOrder ig_order = null; 16 String redirect =null; 17 String msg ="返回订单列表"; 18 if (type.equals("goods") || type.equals("group")) { 19 of = this.orderFormService.getObjById(CommUtil.null2Long(id)); 20 } 21 if (type.equals("cash")) { 22 obj = this.predepositService.getObjById(CommUtil.null2Long(id)); 23 } 24 if (type.equals("gold")) { 25 gold = this.goldRecordService.getObjById(CommUtil.null2Long(id)); 26 } 27 if (type.equals("integral")) { 28 ig_order = this.integralGoodsOrderService.getObjById(CommUtil 29 .null2Long(id)); 30 } 31 // 获取提交的商品价格 32 String order_price = ""; 33 if (type.equals("goods") ) { 34 double order_total_price = 0d; 35 //order_price = CommUtil.null2String(of.getTotalPrice()); 36 if (of != null ) { 37 if(of.getLiuCheng()==0){ ////普通实物订单 TotalPrice已经包含运费 38 order_total_price = CommUtil.null2Double(of 39 .getTotalPrice()); 40 if (!CommUtil.null2String(of.getChild_order_detail()) 41 .equals("")) { 42 List<Map> maps = this.orderFormTools 43 .queryGoodsInfo(of.getChild_order_detail()); 44 for (Map map : maps) { 45 OrderForm child_order = this.orderFormService 46 .getObjById(CommUtil.null2Long(map 47 .get("order_id"))); 48 if(child_order.getOrder_status()==10){ //这里判断如果是主订单的话,就会和次订单一块结算,但是如果次订单结算了,就不在添加使用。 49 order_total_price = order_total_price 50 + CommUtil.null2Double(child_order 51 .getTotalPrice()); 52 } 53 } 54 } 55 redirect = "/buyer/order.htm"; 56 }else if(of.getLiuCheng()==1){ ///预售订单这里只支付定金 57 if(of.getOrder_status() == 10){ 58 order_total_price = CommUtil.null2Double(of.getDingJin_price()); 59 mv.addObject("level", "1"); 60 }else if(of.getOrder_status() == 18){ 61 order_total_price = CommUtil.add(CommUtil.null2Double(of.getWeiKuan_price()), of.getShip_price()); 62 mv.addObject("level", "2"); 63 } 64 redirect = "/buyer/yuShouOrder.htm"; 65 } 66 } 67 68 order_price = CommUtil.null2String(order_total_price) ; 69 } 70 //微信扫码后暂不支持自动跳转,根据订单不同,在支付二维码下提示返回不同的列表 71 if (type.equals("group")) { 72 //Map queryGroupInfo = this.orderFormTools.queryGroupInfo(of.getGroup_info()); 73 redirect = "/buyer/group.htm"; 74 order_price = CommUtil.null2String(of.getTotalPrice()); 75 } 76 if (type.equals("cash")) { 77 redirect = "/buyer/predeposit_list.htm"; 78 msg = "返回充值列表"; 79 order_price = CommUtil.null2String(obj.getPd_amount()); 80 } 81 if (type.equals("gold")) { 82 redirect = "/seller/gold_record_list.htm"; 83 msg = "返回金币日志"; 84 order_price = CommUtil.null2String(gold.getGold_money()); 85 } 86 if (type.equals("integral")) { 87 redirect = "/buyer/integral_order_list.htm"; 88 order_price = CommUtil.null2String(ig_order.getIgo_trans_fee()); 89 } 90 mv.addObject("redirect", redirect); 91 mv.addObject("msg", msg); 92 // 获取提交的商品名称 93 String product_name = ""; 94 if (type.equals("goods") || type.equals("group")) { 95 product_name = of.getOrder_id(); 96 } 97 if (type.equals("cash")) { 98 product_name = obj.getPd_sn(); 99 } 100 if (type.equals("gold")) { 101 product_name = gold.getGold_sn(); 102 } 103 if (type.equals("integral")) { 104 product_name = ig_order.getIgo_order_sn(); 105 } 106 //自定義的參數 107 String attach = ""; 108 if (type.equals("goods") || type.equals("group")) { 109 attach = type + "," + of.getId().toString(); 110 } 111 if (type.equals("cash")) { 112 attach = type + "," + obj.getId().toString(); 113 } 114 if (type.equals("gold")) { 115 attach = type + "," + gold.getId().toString(); 116 } 117 if (type.equals("integral")) { 118 attach = type + "," + ig_order.getId().toString(); 119 } 120 String desc = "商品:" + product_name; 121 // 获取提交的订单号 122 String out_trade_no = ""; 123 if (type.equals("goods") || type.equals("group")) { 124 out_trade_no = of.getOrder_id(); 125 } 126 if (type.endsWith("cash")) { 127 out_trade_no = obj.getPd_sn(); 128 } 129 if (type.endsWith("gold")) { 130 out_trade_no = gold.getGold_sn(); 131 } 132 if (type.equals("integral")) { 133 out_trade_no = ig_order.getIgo_order_sn(); 134 } 135 /* OrderForm order = this.orderFormService.getObjById(CommUtil 136 .null2Long(orderid));*/ 137 138 //double order_total_price = 0d; 139 140 mv.addObject("order_total_price", order_price); 141 /* 142 处理业务逻辑结束 ---------- 143 144 145 **/ 146 //获取预支付信息 147 Map<String,Object> token = null; 148 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath(); 149 String notify= basePath + "/wxBuyerNotify.htm?attach="+attach; //微信支付回调地址,付款成功后调用该地址 150 Money para = new Money(); //将订单编号和订单金额封装到实体中(Money) 151 para.setId(product_name); 152 // para.setCash(new BigDecimal(order_total_price)); 153 para.setCash(new BigDecimal(0.01)); //测试使用,不获取实际订单金额 154 mv.addObject("type", type); 155 mv.addObject("id", id); 156 try 157 { 158 token = wxPayService.getPrepayKey(para,notify); //调用微信API,生成页面二维码信息 159 String barCode = (String)token.get("codeUrl"); 160 mv.addObject("barCode", barCode); 161 } 162 catch(Exception e) 163 { 164 mv = new JModelAndView("error.html", configService.getSysConfig(), 165 this.userConfigService.getUserConfig(), 1, request, 166 response); 167 mv.addObject("op_title", "参数错误,付款失败"); 168 mv.addObject("url", CommUtil.getURL(request) + "/index.htm"); 169 } 170 171 172 return mv; 173 }
(2)view层用到的 实体,接口和工具类
<1>实体类:Money
1 public class Money implements Serializable { 2 /** 3 * 主键编号 4 */ 5 private String id; 6 7 /** 8 * 用户编号 9 */ 10 private String userId; 11 12 /** 13 * 支付金额 14 */ 15 private BigDecimal cash; 16 17 /** 18 * 手机号码 19 */ 20 private String phone; 21 22 /** 23 * 支付方式:1支付宝,2微信,3银联,4余额 24 */ 25 private String type;
<2>微信支付接口:IWxPayService
1 public interface IWxPayService { 2 3 /** 4 * 获取微信支付链接 5 * @param record 6 * @param path 7 * @param ds 8 * @return 9 * @throws Exception 10 */ 11 Map<String,Object> getPrepayKey(Money record,String path)throws Exception; 12 13 /** 14 * 微信支付成功回调 15 * @param request 16 * @return 17 */ 18 int updateWxPay(HttpServletRequest request); 19 20 /** 21 * 形成支付订单信息 22 * @param para 23 * @return 24 */ 25 PayOrder insertOrder(Money para); 26 27 /** 28 * 用户余额支付 29 * @param order 30 * @param user 31 * @return 32 */ 33 int updateStorePay(PayOrder order, User user); 34 35 /** 36 * 形成支付宝支付信息 37 * @param id 38 * @param string 39 * @param user_id 40 * @param basePath 41 * @return 42 */ 43 String createAlipay(Long id, String cash, long user_id, String basePath); 44 45 /** 46 * 支付宝支付回调 47 * @param orderid 48 * @param fee 49 * @param storeId 50 * @return 51 */ 52 int updateAliPay(String orderid, String fee, String storeId); 53 54 /** 55 * 形成银联支付信息 56 * @param para 57 * @return 58 */ 59 String packPay(Money para,PayOrder order); 60 61 /** 62 * 银联支付回调 63 * @param request 64 * @return 65 */ 66 int unionNotfy(HttpServletRequest request); 67 }
<3>实现类:WxPayServiceImpl
1 @Service 2 @Transactional 3 public class WxPayServiceImpl implements IWxPayService 4 { 5 /** 6 * 获取packageValue 7 * @param response 8 * @param request 9 * @param orderCode String 用户编号 10 * @param ds boolean 是否打赏 11 * @return 12 */ 13 @Override 14 public Map<String,Object> getPrepayKey(Money record,String path) 15 throws Exception 16 { 17 Pay pay = new Pay(); //此处为微信支付返回的参数,封装为实体(Pay) 18 String orderCode = record.getId(); 19 if(StringUtils.isBlank(orderCode)) 20 { 21 return null; 22 } 23 orderCode = orderCode.trim(); 24 25 BigDecimal money = record.getCash(); 26 if(money == null) 27 { 28 return null; 29 } 30 packRecharge(orderCode,pay,money,path); 31 packSign(pay);//形成签名 32 return packToMap(pay,true); 33 } 34 private void packRecharge(String ucode,Pay pay,BigDecimal money,String notify) 35 { 36 37 float cash = money.floatValue(); 38 int total = (int)(cash * 100); 39 String orderCode = ucode.trim(); 40 String prekey = doInBackground(orderCode.trim(),total,pay,notify); 41 pay.setPrepayid(prekey); 42 } 43 /** 44 * 形成调起支付的签名 45 * @param pay Pay 46 */ 47 private void packSign(Pay pay) 48 { 49 //将数据封装到map中 50 if(pay == null) 51 { 52 return; 53 } 54 Map<String,Object> map = packToMap(pay,false); 55 if(map != null) 56 { 57 String sign = WXPayDataUtils.genPackageSign(map); 58 pay.setSign(sign); 59 } 60 } 61 /** 62 * 请求微信后台获取预支付单号 63 * @param ucode String 64 * @param total int 65 * @return 66 */ 67 private String doInBackground(String ucode,int total,Pay pay,String notify) { 68 69 String entity = WXPayDataUtils.genProductArgs(ucode,total,pay,notify); 70 Map<String,String> map =WXPayDataUtils.sendPost(WXPayDataUtils.WX_VERIFY_URL, entity); 71 pay.setCodeUrl(map.get("code_url")); 72 String id = map.get("prepay_id"); 73 return id; 74 } 75 76 private Map<String,Object> packToMap(Pay pay,boolean flag) 77 { 78 if(pay == null) 79 { 80 return null; 81 } 82 Map<String,Object> param = new HashMap<String,Object>(); 83 if(pay.getAppid() != null) 84 { 85 param.put("appid", pay.getAppid().trim()); 86 } 87 if(pay.getPartnerid() != null) 88 { 89 param.put("partnerid", pay.getPartnerid().trim()); 90 } 91 if(pay.getPrepayid() != null) 92 { 93 param.put("prepayid", pay.getPrepayid().trim()); 94 } 95 if(pay.getPack() != null) 96 { 97 param.put("package", pay.getPack().trim()); 98 } 99 if(pay.getNoncestr() != null) 100 { 101 param.put("noncestr", pay.getNoncestr().trim()); 102 } 103 if(pay.getTimestamp() != null) 104 { 105 param.put("timestamp", pay.getTimestamp().trim()); 106 } 107 if(pay.getSign() != null && flag) 108 { 109 param.put("sign", pay.getSign()); 110 } 111 if(pay.getAppkey() != null && flag) 112 { 113 param.put("appkey", pay.getAppkey()); 114 } 115 if(pay.getCodeUrl() !=null && flag) 116 { 117 param.put("codeUrl",pay.getCodeUrl()); 118 } 119 return param; 120 } 121 }
<4>实体:Pay
public class Pay { private String appid; private String appkey; private String noncestr; private String pack; private String partnerid; private String prepayid; private String timestamp; private String sign; private String codeUrl; . . . }
<5>微信支付工具类:WXPayDataUtils
1 package com.sanmi.wx.util; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.util.Calendar; 7 import java.util.HashMap; 8 import java.util.Iterator; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.Random; 12 import java.util.Set; 13 import java.util.SortedMap; 14 import java.util.TreeMap; 15 import java.util.TreeSet; 16 17 import org.apache.commons.lang3.StringUtils; 18 import org.apache.commons.logging.Log; 19 import org.apache.commons.logging.LogFactory; 20 import org.apache.http.HttpResponse; 21 import org.apache.http.client.methods.HttpPost; 22 import org.apache.http.client.params.ClientPNames; 23 import org.apache.http.entity.StringEntity; 24 import org.apache.http.impl.client.DefaultHttpClient; 25 import org.apache.http.util.EntityUtils; 26 import org.jdom.Document; 27 import org.jdom.Element; 28 import org.jdom.JDOMException; 29 import org.jdom.input.SAXBuilder; 30 31 import com.sanmi.wx.client.HttpClientConnectionManager; 32 import com.sdsanmi.core.domain.Pay; 33 34 35 /** 36 * 微信支付数据 37 * @author Admin 38 * 39 */ 40 public class WXPayDataUtils { 41 private static final Log logger = LogFactory.getLog(WXPayDataUtils.class); 42 43 public static final String APPID = "***********";//微信分配的公众账号ID 44 public static final String MCH_ID = "********";//微信支付分配的商户号 45 public static final String API_KEY="as4d4s41a4s4789a5w4********";//商户号对应的密钥 46 public static final String APP_SECRET = "c1634fe990550b96********";//应用对应的凭证 47 public static final String BODY = "东地美商城";//商品或支付单简要描述 48 public static final String NOTIFY_URL = "http://121.40.35.3/test";//接收微信支付异步通知回调地址 49 public static final String TRADE_TYPE = "NATIVE";//交易类型 50 public static final String WX_VERIFY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信统一下单请求url 51 public static final String WX_CLOSE_ORDER = "https://api.mch.weixin.qq.com/pay/closeorder";//关闭订单接口 52 public static final String WX_ORDER_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";//查询订单接口 53 54 public static DefaultHttpClient httpclient; 55 56 static 57 { 58 httpclient = new DefaultHttpClient(); 59 httpclient = (DefaultHttpClient)HttpClientConnectionManager.getSSLInstance(httpclient); 60 } 61 62 /** 63 * 拼接要传递的参数 64 * @param order 65 * @return 66 */ 67 public static String genProductArgs(String order,int cash,Pay pay,String notify) { 68 69 SortedMap<String, Object> map = new TreeMap<String, Object>(); 70 String appid = APPID;//微信分配的公众账号ID 71 String mch_id= MCH_ID;//微信支付分配的商户号 72 String nonce_str = getRandomString(18);//随机字符串 73 String body = BODY; 74 75 String out_trade_no = order;//商户订单号 76 String total_fee = String.valueOf(cash);//订单总金额,单位为分 77 String spbill_create_ip = "127.0.0.1";//APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP,暂时为本机地址 78 String notify_url = notify;//接收微信支付异步通知回调地址,不支持参数 79 String trade_type = TRADE_TYPE;//交易类型 80 81 map.put("appid", appid); 82 map.put("mch_id", mch_id); 83 map.put("nonce_str", nonce_str); 84 map.put("body", body); 85 map.put("out_trade_no", out_trade_no); 86 map.put("total_fee", total_fee); 87 map.put("spbill_create_ip", spbill_create_ip); 88 map.put("notify_url", notify_url); 89 map.put("trade_type", trade_type); 90 91 String sign = genPackageSign(map); 92 map.put("sign", sign);//签名 93 pay.setSign(sign); 94 pay.setAppid(appid); 95 pay.setAppkey(API_KEY); 96 pay.setPartnerid(mch_id); 97 pay.setPack("Sign=WXPay"); 98 pay.setNoncestr(nonce_str); 99 pay.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000)); 100 String xmlstring = "<xml>" + "<appid>" + appid + "</appid>" 101 + "<mch_id>" + mch_id + "</mch_id>" 102 + "<nonce_str>" + nonce_str + "</nonce_str>" 103 + "<sign>" + sign + "</sign>" 104 + "<body><![CDATA[" + body + "]]></body>" 105 + "<out_trade_no>" + out_trade_no + "</out_trade_no>" 106 + "<total_fee>" + total_fee + "</total_fee>" 107 + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" 108 + "<notify_url>" + notify_url + "</notify_url>" 109 + "<trade_type>" + trade_type + "</trade_type>" 110 + "</xml>"; 111 return xmlstring; 112 113 } 114 115 /** 116 * 生成签名 117 * @param params 118 * @return 119 */ 120 public static String genPackageSign(Map<String,Object> params) { 121 StringBuilder sb = new StringBuilder(); 122 123 TreeSet<String> sort = new TreeSet<String>(params.keySet()); 124 for (String key : sort) { 125 String value = (String) params.get(key); 126 sb.append(key); 127 sb.append("="); 128 sb.append(value); 129 sb.append("&"); 130 } 131 sb.append("key="); 132 sb.append(API_KEY);//API密钥 133 String packageSign = MD5.MD5Encode((sb.toString())); 134 packageSign = packageSign.toUpperCase(); 135 return packageSign; 136 } 137 /** 138 * 生成随机字符串 139 * @param length 140 * @return 141 */ 142 public static String getRandomString(int length) { //length表示生成字符串的长度 143 String base = "abcdefghijklmnopqrstuvwxyz0123456789"; 144 Random random = new Random(); 145 StringBuffer sb = new StringBuffer(); 146 for (int i = 0; i < length; i++) { 147 int number = random.nextInt(base.length()); 148 sb.append(base.charAt(number)); 149 } 150 return sb.toString(); 151 } 152 /** 153 * 实现Java访问url 154 * @param url param 155 * @return 156 * @throws JDOMException 157 * @throws IOException 158 */ 159 public static Map<String,String> sendPost(String url, String param) { 160 DefaultHttpClient client = new DefaultHttpClient(); 161 client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); 162 HttpPost httpost= HttpClientConnectionManager.getPostMethod(url); 163 Map<String,String> map = null; 164 try { 165 httpost.setEntity(new StringEntity(param, "UTF-8")); 166 HttpResponse response = httpclient.execute(httpost); 167 String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); 168 // System.out.println("=====" + jsonStr); 169 if(jsonStr.indexOf("FAIL")!=-1){ 170 return map; 171 } 172 map = doXMLParse(jsonStr); 173 //prepay_id = (String) map.get("prepay_id"); 174 } catch (Exception e) { 175 logger.error("request weixin prepay_id error!", e); 176 e.printStackTrace(); 177 } 178 return map; 179 } 180 /** 181 * 关闭订单支付 182 * @param url 183 * @param param 184 * @return 185 */ 186 public static boolean sendClosePost(String url,String param) 187 { 188 boolean flag = true; 189 DefaultHttpClient client = new DefaultHttpClient(); 190 client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); 191 HttpPost httpost= HttpClientConnectionManager.getPostMethod(url); 192 try 193 { 194 httpost.setEntity(new StringEntity(param,"UTF-8")); 195 HttpResponse response = httpclient.execute(httpost); 196 String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); 197 if(jsonStr.indexOf("FAIL")!=-1){ 198 return false; 199 } 200 201 } 202 catch(Exception e) 203 { 204 flag = false; 205 } 206 return flag; 207 } 208 209 /** 210 * 形成支付网址 211 * @param phone 212 * @return 213 */ 214 public static String createPayUrl(String order) 215 { 216 if(StringUtils.isBlank(order)) 217 { 218 return null; 219 } 220 StringBuffer sb = new StringBuffer(); 221 //weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX 222 Map<String,Object> param = new HashMap<String,Object>(); 223 param.put("appid",APPID); 224 param.put("mch_id", MCH_ID); 225 param.put("time_stamp", String.valueOf(Calendar.getInstance().getTimeInMillis())); 226 param.put("nonce_str", getNewId()); 227 param.put("product_id", order); 228 String sign = genPackageSign(param); 229 param.put("sign",sign); 230 sb.append("weixin://wxpay/bizpayurl?"); 231 sb.append(genUrlParam(param)); 232 return sb.toString(); 233 } 234 235 /** 236 * 形成随机字符串 237 * @return 238 */ 239 private static String getNewId() 240 { 241 return java.util.UUID.randomUUID().toString().toLowerCase().replaceAll("-",""); 242 } 243 244 private static String genUrlParam(Map<String,Object> param) 245 { 246 StringBuffer sb = new StringBuffer(); 247 TreeSet<String> sort = new TreeSet<String>(param.keySet()); 248 for (String key : sort) { 249 String value = (String) param.get(key); 250 sb.append(key); 251 sb.append("="); 252 sb.append(value); 253 sb.append("&"); 254 } 255 String params = sb.toString(); 256 while(params.endsWith("&")) 257 { 258 params = params.substring(0,params.length() - 1); 259 } 260 return params; 261 } 262 /** 263 * 查询订单是否存在 264 * @param url 265 * @param param 266 * @return 267 */ 268 public static boolean sendQueryPost(String url,String param) 269 { 270 boolean flag = true; 271 DefaultHttpClient client = new DefaultHttpClient(); 272 client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); 273 HttpPost httpost= HttpClientConnectionManager.getPostMethod(url); 274 try 275 { 276 httpost.setEntity(new StringEntity(param,"UTF-8")); 277 HttpResponse response = httpclient.execute(httpost); 278 String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); 279 System.out.println(jsonStr); 280 if(jsonStr.indexOf("FAIL")!=-1){ 281 return false; 282 } 283 284 } 285 catch(Exception e) 286 { 287 flag = false; 288 } 289 return flag; 290 } 291 /** 292 * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 293 * @param strxml 294 * @return 295 * @throws JDOMException 296 * @throws IOException 297 */ 298 public static Map<String, String> doXMLParse(String strxml) throws Exception { 299 if(null == strxml || "".equals(strxml)) { 300 return null; 301 } 302 303 Map<String, String> m = new HashMap<String, String>(); 304 InputStream in = String2Inputstream(strxml); 305 SAXBuilder builder = new SAXBuilder(); 306 Document doc = builder.build(in); 307 Element root = doc.getRootElement(); 308 List<?> list = root.getChildren(); 309 Iterator<?> it = list.iterator(); 310 while(it.hasNext()) { 311 Element e = (Element) it.next(); 312 String k = e.getName(); 313 String v = ""; 314 List<?> children = e.getChildren(); 315 if(children.isEmpty()) { 316 v = e.getTextNormalize(); 317 } else { 318 v = getChildrenText(children); 319 } 320 321 m.put(k, v); 322 } 323 324 //关闭流 325 in.close(); 326 327 return m; 328 } 329 /** 330 * 获取子结点的xml 331 * @param children 332 * @return String 333 */ 334 public static String getChildrenText(List<?> children) { 335 StringBuffer sb = new StringBuffer(); 336 if(!children.isEmpty()) { 337 Iterator<?> it = children.iterator(); 338 while(it.hasNext()) { 339 Element e = (Element) it.next(); 340 String name = e.getName(); 341 String value = e.getTextNormalize(); 342 List<?> list = e.getChildren(); 343 sb.append("<" + name + ">"); 344 if(!list.isEmpty()) { 345 sb.append(getChildrenText(list)); 346 } 347 sb.append(value); 348 sb.append("</" + name + ">"); 349 } 350 } 351 352 return sb.toString(); 353 } 354 public static InputStream String2Inputstream(String str) { 355 return new ByteArrayInputStream(str.getBytes()); 356 } 357 358 /** 359 * 支付成功微信回调 360 * @param children 361 * @return String 362 * @throws Exception 363 */ 364 public static Map<String,String> doReqToMap(InputStream inputStream) throws Exception { 365 // 解析结果存储在HashMap 366 Map<String, String> map = new HashMap<String, String>(); 367 SAXBuilder builder = new SAXBuilder(); 368 Document doc = builder.build(inputStream); 369 Element root = doc.getRootElement(); 370 List<?> list = root.getChildren(); 371 Iterator<?> it = list.iterator(); 372 while(it.hasNext()) { 373 Element e = (Element) it.next(); 374 String k = e.getName(); 375 String v = ""; 376 List<?> children = e.getChildren(); 377 if(children.isEmpty()) { 378 v = e.getTextNormalize(); 379 } else { 380 v = getChildrenText(children); 381 } 382 383 map.put(k, v); 384 } 385 386 //关闭流 387 inputStream.close(); 388 389 return map; 390 } 391 392 /** 393 * 处理返回数据 394 * @param children 395 * @return String 396 */ 397 public static Map<String,Object> responseData(String prepayId) { 398 SortedMap<String, Object> map = new TreeMap<String, Object>(); 399 map.put("appid", APPID);//微信分配的公众账号ID 400 map.put("partnerid", MCH_ID);//微信支付分配的商户号 401 map.put("prepayid", prepayId);//支付交易会话ID 402 map.put("package", "Sign=WXPay");//扩展字段 固定值Sign=WXPay 403 map.put("noncestr", getRandomString(18));//随机字符串 404 map.put("timestamp", String.valueOf(System.currentTimeMillis()/1000));//10位时间戳 405 406 String sign = genPackageSign(map); 407 map.put("sign", sign);//签名 408 409 return map; 410 } 411 412 /** 413 * 关闭上次订单 414 * @param order 415 */ 416 public static void closePrePay(String order) { 417 //查询订单是否存在 418 if(checkExists(order)) 419 { 420 String closeStr = closeParam(createCloseParam(order)); 421 sendClosePost(WXPayDataUtils.WX_CLOSE_ORDER, closeStr); 422 } 423 424 } 425 426 /** 427 * 查询订单是否存在 428 * @param order 429 * @return boolean true存在;false不存在 430 */ 431 private static boolean checkExists(String order) 432 { 433 boolean flag = false; 434 String closeStr = closeParam(createCloseParam(order)); 435 flag = sendQueryPost(WXPayDataUtils.WX_ORDER_QUERY, closeStr); 436 return flag; 437 } 438 /** 439 * 行程请求参数 440 * @param order 441 * @return 442 */ 443 private static Map<String,Object> createCloseParam(String order) 444 { 445 SortedMap<String, Object> map = new TreeMap<String, Object>(); 446 map.put("appid", APPID);//微信分配的公众账号ID 447 map.put("mch_id", MCH_ID);//微信支付分配的商户号 448 map.put("out_trade_no", order);//商家订单编号 449 map.put("nonce_str", getRandomString(18));//随机字符串 450 String sign = genPackageSign(map); 451 map.put("sign", sign);//签名 452 return map; 453 } 454 455 /** 456 * 转为字符串 457 * @param param 458 * @return 459 */ 460 461 private static String closeParam(Map<String,Object> param) 462 { 463 StringBuffer sb = new StringBuffer(); 464 sb.append("<xml>"); 465 Set<String> key = param.keySet(); 466 for(String k : key) 467 { 468 sb.append("<" +k.toString().trim()+">" + param.get(k.trim()) + "</" + k.toString().trim() + ">"); 469 } 470 sb.append("</xml>"); 471 return sb.toString(); 472 } 473 }
<6>将返回值生成二维码,前端wxpay.html页面,使用qrcode生成
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>微信支付 - $!{config.poweredby}</title> <meta name="keywords" content="$!config.keywords" /> <meta name="description" content="$!config.description" /> <meta name="generator" content="$!{config.meta_generator}" /> <meta name="author" content="$!{config.meta_author}" /> <meta name="copyright" content="$!{config.copyRight}" /> <!-- <link href="$!webPath/resources/style/system/front/default/css/public.css" type="text/css" rel="stylesheet" /> --> <link href="$!webPath/resources/style/system/front/default/css/goods.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="$!webPath/resources/js/yjs/jquery.js"></script> <script type="text/javascript" src="$!webPath/resources/js/jquery.qrcode.min.js"></script> <link href="$!webPath/resources/style/system/front/default/webcss/zhuye/css.css" type="text/css" rel="stylesheet" /> <script type="text/javascript"> function utf16to8(str) { var out, i, len, c; out = ""; len = str.length; for (i = 0; i < len; i++) { c = str.charCodeAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { out += str.charAt(i); } else if (c > 0x07FF) { out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } else { out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)); } } return out; } jQuery(function(){ jQuery(‘#output‘).qrcode({ render : "canvas",//也可以替换为table width : 200, height : 200, text : utf16to8("$!barCode")}); }) </script> </head> <body> <div class="main" style="overflow:hidden;"> <div class="payfor_box"> <h3>微信支付</h3> <h5 style="color:#F00;">付款金额:¥$!order_total_price</h5> <span class="payfor_textarea" id="output" style="color:#F00"> </span> <img src="$!webPath/resources/style/channel/images/wxpay.png" /> <h4>支付成功 <a href="$!webPath/index.htm">返回首页逛逛</a></h4> <h4>支付失败 <a href="$!webPath$!redirect">$!msg</a></h4> </div> </div> </body> </html>
(3)前两步完成后,支付链接对应的二维码就可以自动生成,我们还需要对支付结果进行处理,微信回调方法:wxBuyerNotify
1 /** 2 * 微信支付回调 3 * @param response 4 * @param request 5 */ 6 @RequestMapping("/wxBuyerNotify.htm") 7 public void wxBuyerNotify(HttpServletResponse response,HttpServletRequest request) 8 { 9 //TODO 待完成 10 String result ="<xml> <return_code><![CDATA[%s]]></return_code> <return_msg><![CDATA[%s]]></return_msg></xml>"; 11 12 StringBuffer xml = new StringBuffer(); 13 String temp = null; 14 try 15 { 16 BufferedReader read = request.getReader(); 17 while((temp = read.readLine()) != null) 18 { 19 xml.append(temp); 20 } 21 read.close(); 22 23 } 24 catch(Exception e){} 25 Map<String,String> param = ParseXml.parse(xml.toString()); 26 //验证是否微信回调 27 if(checkSign(param)) 28 { 29 //获取自定义返回值,此处定义的自定义返回值的格式为:付款类型,订单编号 30 String attach = param.get("attach"); 31 32 String type = "" ; 33 String order_id="" ; 34 if (attach != null) { 35 String a[] = attach.split(","); 36 if (a[0] != null) { 37 type = a[0].trim(); 38 } 39 if (a[1] != null) { 40 order_id = a[1].trim(); 41 } 42 } 43 if(!StringUtils.isBlank(order_id) && !StringUtils.isBlank(type) ) 44 { 45 //签名,返回值,状态码判断之后,开始处理逻辑 46 OrderForm order = null; 47 Predeposit obj = null; 48 GoldRecord gold = null; 49 IntegralGoodsOrder ig_order = null; 50 if (type.equals("integral")) { 51 ig_order = this.integralGoodsOrderService.getObjById(CommUtil 52 .null2Long(order_id)); 53 } 54 if (type.equals("cash")) { 55 obj = this.predepositService.getObjById(CommUtil 56 .null2Long(order_id)); 57 } 58 if (type.equals("gold")) { 59 gold = this.goldRecordService.getObjById(CommUtil 60 .null2Long(order_id)); 61 } 62 if (type.equals("goods") || type.equals("group")) { 63 order = this.orderFormService.getObjById(CommUtil 64 .null2Long(order_id)); 65 } 66 67 if (type.equals("cash")) { 68 obj.setPd_status(1); 69 obj.setPd_pay_status(2); 70 this.predepositService.update(obj); 71 User user = this.userService.getObjById(obj 72 .getPd_user().getId()); 73 user.setAvailableBalance(BigDecimal.valueOf(CommUtil 74 .add(user.getAvailableBalance(), 75 obj.getPd_amount()))); 76 this.userService.update(user); 77 } 78 if (type.equals("goods") || type.equals("group")) { 79 if(order.getLiuCheng()==1){ 80 if(order.getOrder_status()==10){ 81 order.setOrder_status(18);////预售支付定金成功标志 82 }else if(order.getOrder_status()==18){ 83 order.setOrder_status(20);////支付尾款成功,就是已付款 84 } 85 } 86 if(order.getLiuCheng()==0){ 87 order.setOrder_status(20);////普通商品 ,20为已付款待发货 88 order.setPayTime(new Date()); 89 } 90 91 this.orderFormService.update(order); 92 if (order.getOrder_main() == 1 93 && !CommUtil.null2String( 94 order.getChild_order_detail()).equals( 95 "")) {// 同步完成子订单付款状态调整 96 List<Map> maps = this.orderFormTools 97 .queryGoodsInfo(order 98 .getChild_order_detail()); 99 for (Map child_map : maps) { 100 OrderForm child_order = this.orderFormService 101 .getObjById(CommUtil 102 .null2Long(child_map 103 .get("order_id"))); 104 child_order.setOrder_status(20); 105 this.orderFormService.update(child_order); 106 // 向加盟商家发送付款成功短信提示,自营商品无需发送短信提示 107 // 付款成功,发送短信提示 108 } 109 } 110 // 如果是团购订单,则需呀执行团购订单相关流程及发送团购码 111 if (order.getOrder_cat() == 2) { 112 Calendar ca = Calendar.getInstance(); 113 ca.add(ca.DATE, this.configService.getSysConfig() 114 .getAuto_order_return()); 115 SimpleDateFormat bartDateFormat = new SimpleDateFormat( 116 "yyyy-MM-dd HH:mm:ss"); 117 String latertime = bartDateFormat.format(ca.getTime()); 118 order.setReturn_shipTime(CommUtil.formatDate(latertime)); 119 Map map = this.orderFormTools.queryGroupInfo(order 120 .getGroup_info()); 121 int count = CommUtil.null2Int(map.get("goods_count") 122 .toString()); 123 String goods_id = map.get("goods_id").toString(); 124 GroupLifeGoods goods = this.groupLifeGoodsService 125 .getObjById(CommUtil.null2Long(goods_id)); 126 /* goods.setGroup_count(goods.getGroup_count() 127 - CommUtil.null2Int(count)); 128 this.groupLifeGoodsService.update(goods);*/ 129 int i = 0; 130 List<String> code_list = new ArrayList();// 存放团购消费码 131 /*User user = this.userService.getObjById(SecurityUserHolder 132 .getCurrentUser().getId());*/ 133 User user = this.userService.getObjById(CommUtil.null2Long(order.getUser_id())); 134 Map params = new HashMap(); 135 params.put("mark", "wxpay"); 136 List<Payment> payments = this.paymentService.query( 137 "select obj from Payment obj where obj.mark=:mark", params, 138 -1, -1); 139 String codes = ""; 140 System.out.println("微信支付团购消费码开始生成"); 141 while (i < count) { 142 GroupInfo info = new GroupInfo(); 143 info.setAddTime(new Date()); 144 info.setLifeGoods(goods); 145 info.setPayment(payments.get(0)); 146 info.setUser_id(CommUtil.null2Long(order.getUser_id())); 147 info.setUser_name(CommUtil.null2String(order.getUser_name())); 148 info.setOrder_id(order.getId()); 149 info.setGroup_sn(CommUtil.null2Long(order.getUser_id()) 150 + CommUtil.formatTime("yyyyMMddHHmmss" + i, 151 new Date())); 152 Calendar ca2 = Calendar.getInstance(); 153 ca2.add(ca2.DATE, this.configService.getSysConfig() 154 .getGrouplife_order_return()); 155 SimpleDateFormat bartDateFormat2 = new SimpleDateFormat( 156 "yyyy-MM-dd HH:mm:ss"); 157 String latertime2 = bartDateFormat2.format(ca2 158 .getTime()); 159 info.setRefund_Time(CommUtil.formatDate(latertime2)); 160 this.groupInfoService.save(info); 161 codes = codes + info.getGroup_sn() + " "; 162 code_list.add(info.getGroup_sn()); 163 i++; 164 } 165 if (order.getOrder_form() == 0) { 166 Store store = this.storeService.getObjById(CommUtil 167 .null2Long(order.getStore_id())); 168 if (store.getAgent_id() != null) { 169 User agent = this.userService.getObjById(store.getAgent_id()); 170 agent.setAvailableBalance(BigDecimal.valueOf(CommUtil.add(agent.getAvailableBalance(), order.getAgent_commission_amount()))); 171 this.userService.update(agent); 172 } 173 PayoffLog plog = new PayoffLog(); 174 plog.setPl_sn("pl" 175 + CommUtil.formatTime("yyyyMMddHHmmss", 176 new Date()) 177 + store.getUser().getId()); 178 plog.setPl_info("团购码生成成功"); 179 plog.setAddTime(new Date()); 180 plog.setSeller(store.getUser()); 181 plog.setO_id(CommUtil.null2String(order.getId())); 182 plog.setOrder_id(order.getOrder_id().toString()); 183 plog.setCommission_amount( 184 order.getCommission_amount());// 该订单总佣金费用 185 plog.setAgent_commission_amount( 186 order.getAgent_commission_amount());// 该订单代理佣金费用 187 // 将订单中group_info({})转换为List<Map>([{}]) 188 List<Map> Map_list = new ArrayList<Map>(); 189 Map group_map = this.orderFormTools 190 .queryGroupInfo(order.getGroup_info()); 191 Map_list.add(group_map); 192 plog.setGoods_info(Json.toJson(Map_list, 193 JsonFormat.compact())); 194 plog.setOrder_total_price(order.getTotalPrice());// 该订单总商品金额 195 plog.setTotal_amount(BigDecimal.valueOf(CommUtil.subtract(order.getTotalPrice(), order.getCommission_amount())));// 该订单应结算金额:结算金额=订单总商品金额-总佣金费用 196 this.payoffLogService.save(plog); 197 System.out.println("微信支付团购消费码生成成功"); 198 store.setStore_sale_amount(BigDecimal 199 .valueOf(CommUtil.add( 200 order.getTotalPrice(), 201 store.getStore_sale_amount())));// 店铺本次结算总销售金额 202 // 团购消费码,没有佣金,店铺总佣金不变,有佣金 203 store.setStore_commission_amount(BigDecimal 204 .valueOf(CommUtil.add( 205 order.getCommission_amount(), 206 store.getStore_commission_amount()))); 207 store.setStore_payoff_amount(BigDecimal 208 .valueOf(CommUtil.add( 209 order.getTotalPrice(), 210 store.getStore_payoff_amount())));// 店铺本次结算总佣金 211 this.storeService.update(store); 212 } 213 // 增加系统总销售金额 214 SysConfig sc = this.configService.getSysConfig(); 215 sc.setPayoff_all_sale(BigDecimal.valueOf(CommUtil.add( 216 order.getTotalPrice(), sc.getPayoff_all_sale()))); 217 sc.setPayoff_all_commission(BigDecimal.valueOf(CommUtil.add( 218 order.getCommission_amount(), sc.getPayoff_all_commission()))); 219 this.configService.update(sc); 220 // 更新lucene索引 221 /*String goods_lucene_path = ""; 222 if (goods.getArea_id() != 0) { 223 goods_lucene_path = System.getProperty("user.dir") 224 + File.separator + "luence" 225 + File.separator + "lifegoods" 226 + goods.getArea_id(); 227 } else { 228 goods_lucene_path = System.getProperty("user.dir") 229 + File.separator + "luence" 230 + File.separator + "lifegoods"; 231 } 232 File file = new File(goods_lucene_path); 233 if (!file.exists()) { 234 CommUtil.createFolder(goods_lucene_path); 235 } 236 LuceneUtil lucene = LuceneUtil.instance(); 237 lucene.setIndex_path(goods_lucene_path); 238 lucene.update(CommUtil.null2String(goods.getId()), 239 luceneVoTools.updateLifeGoodsIndex(goods));*/ 240 String msg_content = "恭喜您成功购买团购" 241 + map.get("goods_name") + ",团购消费码分别为:" + codes 242 + "您可以到用户中心-我的生活购中查看消费码的使用情况"; 243 // 发送系统站内信给买家 244 Message tobuyer_msg = new Message(); 245 tobuyer_msg.setAddTime(new Date()); 246 tobuyer_msg.setStatus(0); 247 tobuyer_msg.setType(0); 248 tobuyer_msg.setContent(msg_content); 249 tobuyer_msg.setFromUser(this.userService 250 .getObjByProperty("userName", "admin")); 251 tobuyer_msg.setToUser(user); 252 this.messageService.save(tobuyer_msg); 253 // 付款成功,发送短信团购消费码 254 } 255 // this.update_goods_inventory(order,null);// 更新商品库存 256 if (order.getOrder_cat() != 2) { 257 258 List<Goods> goods_list = this.orderFormTools 259 .queryOfGoods(CommUtil.null2String(order 260 .getId())); 261 for (Goods goods : goods_list) { 262 // 造成搜索数据重复的原因 263 String goods_lucene_path = null; 264 if (goods.getGoods_type() == 0) { // 如果商品是自营商品 265 goods_lucene_path = System 266 .getProperty("user.dir") 267 + File.separator 268 + "luence" 269 + File.separator + "goods"; 270 } else { // 如果商品是店铺商品 271 if (goods.getGoods_store().getArea() != null) { // 店铺入驻到地区 272 goods_lucene_path = System 273 .getProperty("user.dir") 274 + File.separator 275 + "luence" 276 + File.separator 277 + "goods" 278 + goods.getGoods_store().getArea() 279 .getId(); 280 } else { 281 goods_lucene_path = System // 店铺入住到中国大区 282 .getProperty("user.dir") 283 + File.separator + "luence" 284 + File.separator + "goods_store"; 285 } 286 287 } 288 File file = new File(goods_lucene_path); 289 if (!file.exists()) { 290 CommUtil.createFolder(goods_lucene_path); 291 } 292 LuceneUtil lucene = LuceneUtil.instance(); 293 lucene.setIndex_path(goods_lucene_path); 294 lucene.update(CommUtil.null2String(goods.getId()), 295 luceneVoTools.updateGoodsIndex(goods)); 296 } 297 } 298 OrderFormLog ofl = new OrderFormLog(); 299 ofl.setAddTime(new Date()); 300 ofl.setLog_info("微信支付"); 301 ofl.setLog_user(SecurityUserHolder.getCurrentUser()); 302 ofl.setOf(order); 303 this.orderFormLogService.save(ofl); 304 } 305 306 if (type.equals("gold")) { 307 gold.setGold_status(1); 308 gold.setGold_pay_status(2); 309 this.goldRecordService.update(gold); 310 User user = this.userService.getObjById(gold 311 .getGold_user().getId()); 312 user.setGold(user.getGold() + gold.getGold_count()); 313 this.userService.update(user); 314 GoldLog log = new GoldLog(); 315 log.setAddTime(new Date()); 316 log.setGl_payment(gold.getGold_payment()); 317 log.setGl_content("微信支付"); 318 log.setGl_money(gold.getGold_money()); 319 log.setGl_count(gold.getGold_count()); 320 log.setGl_type(0); 321 log.setGl_user(gold.getGold_user()); 322 log.setGr(gold); 323 this.goldLogService.save(log); 324 } 325 if (type.equals("integral")) { 326 ig_order.setIgo_status(20); 327 ig_order.setIgo_pay_time(new Date()); 328 ig_order.setIgo_payment("wxpay"); 329 this.integralGoodsOrderService.update(ig_order); 330 for (IntegralGoodsCart igc : ig_order.getIgo_gcs()) { 331 IntegralGoods goods = igc.getGoods(); 332 goods.setIg_goods_count(goods.getIg_goods_count() 333 - igc.getCount()); 334 goods.setIg_exchange_count(goods 335 .getIg_exchange_count() + igc.getCount()); 336 this.integralGoodsService.update(goods); 337 } 338 } 339 //处理业务逻辑结束 340 result = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" 341 + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; 342 } 343 }else{ 344 result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" 345 + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; 346 } 347 //處理業務完畢,輸出結果 348 try 349 { 350 response.getOutputStream().write(result.getBytes()); 351 } 352 catch(Exception ioe) 353 { 354 ioe.printStackTrace(); 355 } 356 357 }
<-----------------------------结束------------------------------------------>
小结:支付环节步骤很复杂,但是根据官方API按步骤对接,可以有条理的进行对接
官方接口地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5,微信工具类请下载最新版