本文直接从代码调用微信扫码支付讲起。账号配置,参数生成等请参考官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_1

微信扫码支付。简单来说,就是你把微信支付需要的信息,生成到二维码图片中。通过微信扫一扫,发起支付。我们需要做的就是二件事:

一是:按照微信扫码支付规则生成二维码信息.

二是:微信没有提供生成二维码图片的接口。需要我们自己把二维码信息生成到二维码图片中。

1.模式选择:

微信扫码支付,有两种模式,文档中有介绍。第二种模式,微信接口会返回二维码信息给我们。而第一种模式则需要我们自己去生成二维码信息。会有些麻烦。尤其 是参数大小写,还有签名的问题,容易出错。总的来说第二种模式比第一种模式简单。所有我采用的是第二种模式,比较通用。京东与携程亦用的是第二种模式。

2.调用统一下单接口获取带有二维码信息的url:(模式二)

模式二的微信扫码支付,需要先调用微信的统一下单接口,生成预交易单。(参数传递与接收都是XML 数据格式。)

正确调用后,会返回含有交易标示ID,和二维码链接的URL。

3.实现扫码支付(模式二)

  private static String APPID = "";  

  private static String MCHID= "";
  private static String KEY= "";
  private static String APPSECRET= "";
  private static String body= "";
  private static String notify_url= "";    //回调地址。测试回调必须保证外网能访问到此地址
   /**
  * 统一下单接口
* 微信二维码支付
* @param params
* @return
*/
public String weixin_pay(String out_trade_no,String product_id) {
JSONObject retJson = new JSONObject();
try { String currTime = PayCommonUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayCommonUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;      //生成随机字符串 JSONObject requestObj = JSONObject.fromObject(params); // 正式上线的时候价格根据订单id查询
String order_price = "1"; // 价格 注意:价格的单位是分 SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
packageParams.put("appid", APPID);
packageParams.put("mch_id", MCHID);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", order_price);
packageParams.put("spbill_create_ip", "用户端ip");
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", "NATIVE");
packageParams.put("product_id", product_id);
Calendar nowTime = Calendar.getInstance();
packageParams.put("time_start", DateFormatUtil.formatDate(
nowTime.getTime(), "yyyyMMddHHmmss"));
nowTime.add(Calendar.MINUTE, requestObj.getInt("expire_time"));
packageParams.put("time_expire", DateFormatUtil.formatDate(
nowTime.getTime(), "yyyyMMddHHmmss")); String sign = PayCommonUtil.createSign("UTF-8", packageParams,
KEY);
packageParams.put("sign", sign);        //加密 String requestXML = PayCommonUtil.getRequestXml(packageParams);
logger.info("支付请求:" + requestXML);
long startTime=System.currentTimeMillis();
String resXml = HttpRequest.postData(
"https://api.mch.weixin.qq.com/pay/unifiedorder",
requestXML);
long endTime=System.currentTimeMillis(); Integer execute_time = (int) ((endTime-startTime)/1000);
logger.info("支付结果:" + resXml);
Map map = XMLUtil.doXMLParse(resXml); JSONObject reportParams = new JSONObject();
reportParams.put("url", "https://api.mch.weixin.qq.com/pay/unifiedorder");
reportParams.put("execute_time", execute_time);
reportParams.put("return_code", map.get("return_code").toString());
reportParams.put("return_msg", map.get("return_msg").toString());
reportParams.put("result_code", map.get("result_code").toString());
if (map.get("err_code") != null) {
reportParams.put("err_code", map.get("err_code").toString());
reportParams.put("err_code_des", map.get("err_code_des").toString());
}
reportParams.put("out_trade_no", out_trade_no);
//交易保障
report(reportParams.toString());
if (map.get("return_code").toString().equals("SUCCESS") && map.get("result_code").toString().equals("SUCCESS")) {
String urlCode = (String) map.get("code_url");          //微信二维码短链接
retJson.put("code", 0);
retJson.put("message", "下单成功.");
retJson.put("data", urlCode);
} else {
retJson.put("code", 1);
retJson.put("message", map.get("err_code_des").toString());
retJson.put("data", "");
}
return retJson.toString();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

4.支付工具类

public class PayCommonUtil {

    public static Logger log = LoggerFactory.getLogger(PayCommonUtil.class);

    /**
* 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @return boolean
*/
public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
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(!"sign".equals(k) && null != v && !"".equals(v)) {
sb.append(k + "=" + v + "&");
}
} sb.append("key=" + API_KEY); //算出摘要
String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
String tenpaySign = ((String)packageParams.get("sign")).toLowerCase(); //System.out.println(tenpaySign + " " + mysign);
return tenpaySign.equals(mysign);
} /**
* @author
* @date 2016-4-22
* @Description:sign签名
* @param characterEncoding
* 编码格式
* @param parameters
* 请求参数
* @return
*/
public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {
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 = "";
try {
v = (String) entry.getValue();
} catch (Exception e) {
// TODO: handle exception
v = entry.getValue() + "";
} if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + API_KEY);
String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
} /**
* @author
* @date 2016-4-22
* @Description:将请求参数转换为xml格式的string
* @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 = "";
try {
v = (String) entry.getValue();
} catch (Exception e) {
// TODO: handle exception
v = 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();
} /**
* 取出一个指定长度大小的随机正整数.
*
* @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));
} /**
* 获取当前时间 yyyyMMddHHmmss
*
* @return String
*/
public static String getCurrTime() {
Date now = new Date();
SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
String s = outFormat.format(now);
return s;
} public static JSONObject httpsRequestToJsonObject(String requestUrl,
String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
StringBuffer buffer = httpsRequest(requestUrl, requestMethod,
outputStr);
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:" + ce.getMessage());
} catch (Exception e) {
log.error("https请求异常:" + e.getMessage());
}
return jsonObject;
} private static StringBuffer httpsRequest(String requestUrl,
String requestMethod, String output)
throws NoSuchAlgorithmException, NoSuchProviderException,
KeyManagementException, MalformedURLException, IOException,
ProtocolException, UnsupportedEncodingException {
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = connection.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;
connection.disconnect();
return buffer;
}
}

java实现微信支付之扫码支付的更多相关文章

  1. 微信支付之扫码支付、公众号支付、H5支付、小程序支付相关业务流程分析总结

    前言 很久以来,一直想写一篇微信支付有关的总结文档:一方面是总结自己的一些心得,另一方面也可以帮助别人,但是因种种原因未能完全理解透彻微信支付的几大支付方式,今天有幸做一些总结上的文章,也趁此机会,将 ...

  2. 微信原生支付 Native扫码支付( V3.3.7 版本)

    原文:微信原生支付 Native扫码支付( V3.3.7 版本) [尊重别人的劳动成果,转载请注明出处:一缕晨光工作室,www.wispdawn.com] 前言 辛苦研究三天,遇到各种困难,最终还是克 ...

  3. asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1

    2018-08-13更新生成二维码的方法 在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付.H5支付.公众号支付.App支付等,本人使用的是asp.net mvc c ...

  4. 记录:c#实现微信,支付宝扫码支付(一)

    因为公司系统业务需要,这几天了解了一下微信和支付宝扫码支付的接口,并用c#实现了微信和支付宝扫码支付的功能. 微信支付分为6种支付模式:1.付款码支付,2.native支付,3.jsapi支付,4.a ...

  5. 支付宝支付之扫码支付(电脑网站支付)、H5支付(手机网站支付)相关业务流程分析总结

    前言 在上一篇文章<微信支付之扫码支付.公众号支付.H5支付.小程序支付相关业务流程分析总结>中,分析和总结了微信支付相关支付类型的业务流程,这里作为与微信支付平起平坐不相伯仲的支付宝支付 ...

  6. php实现支付宝在线支付和扫码支付demo

    ### php实现支付宝在线支付和扫码支付demo 背景:在做一个公众号时增加了h5端,需要接入支付,非微信环境,选择了支付宝,以下简单记录下实现过程,并做了简单的封装,拿来即可使用,注意:本项目只是 ...

  7. 微信公众号 扫码支付 模式二 demo

    扫码支付 本文附有代码,在下方,如果不熟悉场景的可以看看下面的场景介绍 场景介绍 官网介绍地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?ch ...

  8. 微信支付Native扫码支付模式二之CodeIgniter集成篇

    CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/ ...

  9. 微信支付之扫码支付开发:我遇到的坑及解决办法(附:Ecshop 微信支付插件)

    前段时间帮一个朋友的基于ecshop开发的商城加入微信扫描支付功能,本以为是很简单的事儿——下载官方sdk或开发帮助文档,按着里面的做就ok了,谁知折腾了两三天的时间才算搞定,中间也带着疑问在网上找了 ...

随机推荐

  1. Jetty入门(1-2)eclipse集成jetty插件并发布运行应用

    一.eclipse集成jetty插件 1.从市场安装jetty插件 2.使用jetty插件发布应用和配置运行环境 debug配置默认共用上述run配置 3.使用jetty插件启动运行和停止运行选中的应 ...

  2. 阿里云API网关(1)服务网关的产品概述

    网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 网关控制台: https ...

  3. python 面向对象进阶之内置方法

    一 isinstance(obj,cls)和issubclass(sub,super) 1.1,isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(obj ...

  4. H5 仿ios select滚动选择器。框架。

    官网上描述的很详细,并且开源,轻量. 有兴趣的可以去尝试官网上的demo写的也很好,并且每个参数也解释的很详细. http://zhoushengfe.com/iosselect/website/in ...

  5. CSS 选择器简介

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 选择器权重 如果以4位数表示选择符权重,那么: 元素选择器的权重是1: id 选择器的权重为100: cl ...

  6. vue2.0 带头冲锋(打包时,小心萝卜坑)

    距离上一期,时间间距可能有点长.谁让本人处于兴奋状态,生活已经不能自理. 哈哈哈,嗯,正经一下, 在已有的经验里总结一下那些容易抓狂的坑! 起因:npm run build 打包 本地运行,你以为可以 ...

  7. SpringMVC 使用MultipartFile实现文件上传(转)

    http://blog.csdn.net/kouwoo/article/details/40507565 一.配置文件:SpringMVC 用的是 的MultipartFile来进行文件上传 所以我们 ...

  8. angularjs1.x版本,父子组件之间的双向绑定

    今天遇到了一个angularjs的坑, ng-repeat和ng-if会改变他所包含的html中绑定变量的作用域. angularjs自定义指令,可以定义四种变量,通过 =,@,&双向绑定,单 ...

  9. SSO-单点统一登录系统的设计与实现

    本文主要基于web类应用展开讨论,提供的是一种通用机制和方法,所以不论何种技术栈都可进行相应的具体实现. 实现目标 可以在相同或跨域环境下完成各应用的统一登录/注销 方案原理 本质上是采用了web应用 ...

  10. [LeetCode] Find Anagram Mappings 寻找异构映射

    Given two lists A and B, and B is an anagram of A. B is an anagram of A means B is made by randomizi ...