步骤:

  1.预订单

  2.接受微信返回的url

  3.将url转为二维码显示到页面上

  4.扫码支付

  5.接收微信的异步通知,在这步修改订单的状态

  6.收到异步通知的同时给微信返回指定数据,告知对方已成功处理异步通知

难点:

  1.根据传递的参数生成签名

  2.将数据转为xml格式发送给微信预订单接口

常见错误:

  1.签名错误(推荐用微信的验签工具检验)

  2.xml格式错误(很有可能是发送数据的方式出现了问题)

具体实现:

  1.预订单

public String getImageUrl(String body,String out_trade_no,String product_id,String total_fee) throws Exception{
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("appid", data.getAppid()); //appid:每个公众号都有一个appid
paramMap.put("body", body); //商品描述
paramMap.put("mch_id", data.getMch_id()); //商户号:开通微信支付后分配
paramMap.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32)); // 随机字符串
paramMap.put("notify_url", data.getNotify_url()); //支付成功后,回调地址
paramMap.put("out_trade_no", out_trade_no); //商户订单号
paramMap.put("product_id", product_id); // 商户根据自己业务传递的参数 当trade_type=NATIVE时必填
paramMap.put("spbill_create_ip", this.localIp()); //本机的Ip
paramMap.put("total_fee", total_fee); //金额必须为整数 单位为分
paramMap.put("trade_type", data.getTrade_type()); //交易类型
paramMap.put("sign", WxzfUtil.getSign(paramMap, WXPayAction.KEY));//根据微信签名规则,生成签名。随机参数可以在商户后台管理系统中进行设置。 String xmlData = XmlUtils.map2xmlBody(paramMap,"xml");//把参数转换成XML数据格式
String codeUrl = getCodeUrl(xmlData); //获取二维码链接
return codeUrl;
}
public static String getSign(Map map, String key) throws Exception {
String signTemp = "appid=" + map.get("appid") + "&body="
+ map.get("body") + "&mch_id=" + map.get("mch_id")
+ "&nonce_str=" + map.get("nonce_str") + "&notify_url="
+ map.get("notify_url") + "&out_trade_no="
+ map.get("out_trade_no") + "&product_id="
+ map.get("product_id") + "&spbill_create_ip="
+ map.get("spbill_create_ip") + "&total_fee="
+ map.get("total_fee") + "&trade_type=" + map.get("trade_type")
+ "&key=" + key;
String sign = MD5.MD5Encode(signTemp).toUpperCase();//MD5微信接口中提供,直接调用即可
return sign;
}
public static String map2xmlBody(Map<String, Object> vo, String rootElement) {
org.dom4j.Document doc = DocumentHelper.createDocument();
Element body = DocumentHelper.createElement(rootElement);
doc.add(body);
__buildMap2xmlBody(body, vo);
return doc.asXML();
} @SuppressWarnings("unchecked")
private static void __buildMap2xmlBody(Element body, Map<String, Object> vo) {
if (vo != null) {
Iterator<String> it = vo.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
if (StringUtil.isNotEmpty(key)) {
Object obj = vo.get(key);
Element element = DocumentHelper.createElement(key);
if (obj != null) {
if (obj instanceof java.lang.String) {
element.setText((String) obj);
} else {
if (obj instanceof java.lang.Character || obj instanceof java.lang.Boolean || obj instanceof java.lang.Number
|| obj instanceof java.math.BigInteger || obj instanceof java.math.BigDecimal) {
org.dom4j.Attribute attr = DocumentHelper.createAttribute(element, "type", obj.getClass().getCanonicalName());
element.add(attr);
element.setText(String.valueOf(obj));
} else if (obj instanceof java.util.Map) {
org.dom4j.Attribute attr = DocumentHelper.createAttribute(element, "type", java.util.Map.class.getCanonicalName());
element.add(attr);
__buildMap2xmlBody(element, (Map<String, Object>) obj);
} else {
}
}
}
body.add(element);
}
}
}
}
/**
* 获取一定长度的随机字符串
* @param length 指定字符串长度
* @return 一定长度的字符串
*/
public static String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
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();
}
//获取本机ip地址
@SuppressWarnings("rawtypes")
private String localIp(){
String ip = null;
Enumeration allNetInterfaces;
try {
allNetInterfaces = NetworkInterface.getNetworkInterfaces();
while (allNetInterfaces.hasMoreElements()) {
NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
List<InterfaceAddress> InterfaceAddress = netInterface.getInterfaceAddresses();
for (InterfaceAddress add : InterfaceAddress) {
InetAddress Ip = add.getAddress();
if (Ip != null && Ip instanceof Inet4Address) {
ip = Ip.getHostAddress();
}
}
}
} catch (SocketException e) {
log.warn("获取本机Ip失败:异常信息:"+e.getMessage());
}
return ip;
}

  2.接受微信返回的url

/**
* 获取二维码链接
* @param xmlData
* @return
*/
private String getCodeUrl(String xmlData) {
String resXml = null;
try {
resXml = WxzfUtil.sendPost(WXPayAction.WX_CREATE_ORDER_URL, xmlData);
} catch (UnrecoverableKeyException e1) {
log.error(e1.getMessage());
} catch (KeyManagementException e1) {
log.error(e1.getMessage());
} catch (KeyStoreException e1) {
log.error(e1.getMessage());
} catch (NoSuchAlgorithmException e1) {
log.error(e1.getMessage());
} catch (IOException e1) {
log.error(e1.getMessage());
} String code_url = "";
Map<String, String> map;
try {
map = WxzfUtil.parseXml(resXml);
Object returnCode = map.get("return_code");
if("SUCCESS".equals(returnCode)) {
Object resultCode = map.get("result_code");
if("SUCCESS".equals(resultCode)) {
code_url = map.get("code_url").toString();
}
}
} catch (Exception e) {
log.error(e.getMessage());
return "";
}
return code_url;
}
//将xml数据发送给微信
@SuppressWarnings({ "resource" })
public static String sendPost(String url, String postDataXML)
throws IOException, KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, KeyManagementException { String result = null; HttpPost httpPost = new HttpPost(url);
HttpClient client = new DefaultHttpClient(); // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别 StringEntity postEntity = new StringEntity(postDataXML, "UTF-8"); httpPost.addHeader("Content-Type", "text/xml"); httpPost.setEntity(postEntity); try { HttpResponse response = client.execute(httpPost); HttpEntity entity = response.getEntity(); result = EntityUtils.toString(entity, "UTF-8"); } catch (ConnectionPoolTimeoutException e) { // LOG.debug("http get throw ConnectionPoolTimeoutException(wait time out)"); } catch (ConnectTimeoutException e) { // LOG.debug("http get throw ConnectTimeoutException"); } catch (SocketTimeoutException e) { // LOG.debug("http get throw SocketTimeoutException"); } catch (Exception e) { e.printStackTrace(); // LOG.debug("http get throw Exception" ); } finally {
httpPost.abort();
} System.out.println(result); return result; }

  3.将url转为二维码显示到页面上

public String payWeChat(String ids,String content,HttpServletResponse response,HttpServletRequest request, ModelMap model){
WebErrors errors = WebErrors.create(request);
try {
OmShopOrder order = orderService.findById(Long.parseLong(ids));
content = this.getImageUrl(order.getSoProductname(), order.getSoId().toString(), order.getSoId().toString(), (int)(order.getSoTotal()*10*10)+"");
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
Hashtable hints = new Hashtable();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400,hints);
response.setContentType("image/jpeg");
MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
log.warn("订单已支付,请勿重新支付");
}
return null;
}

  4.扫码支付

  5.接收微信的异步通知,在这步修改订单的状态

if ("SUCCESS".equals(returnMap.get("return_code"))&&"SUCCESS".equals(returnMap.get("result_code"))) {
//处理你的业务逻辑代码(修改订单支付状态)
}

  6.收到异步通知的同时给微信返回指定数据,告知对方已成功处理异步通知

response.setContentType("text/plain;charset=UTF-8");
PrintWriter writer;
try {
writer = response.getWriter();
writer.write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}

[支付]微信NATIVE扫码支付JAVA实现的更多相关文章

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

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

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

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

  3. 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_6-3.微信网站扫码支付介绍

    笔记 3.微信网站扫码支付介绍     简介:讲解微信网页扫码支付         1.扫码支付文档:https://pay.weixin.qq.com/wiki/doc/api/native.php ...

  4. Win10环境前后端分离项目基于Vue.js+Django+Python3实现微信(wechat)扫码支付流程(2021年最新攻略)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_182 之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内 ...

  5. 170327、Java微信支付中的扫码支付

    微信支付现在已经变得越来越流行了,随之也出现了很多以可以快速接入微信支付为噱头的产品,不过方便之余也使得我们做东西慢慢依赖第三方,丧失了独立思考的能力,这次打算分享下我之前开发过的微信支付. 一 H5 ...

  6. 微信支付(PC扫码支付和H5公众号支付)

    最近在做微信支付,微信支付比较坑,官方居然只有.NET.C#.PHP的demo居然没有java的demo.然后微信支付是不提供测试账号的需要直接用正式的公众号.首先来介绍下微信扫码支付吧,微信扫码有两 ...

  7. Java微信公众平台开发之扫码支付模式一

    官方文档点击查看准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败)借鉴了很多大神的文章,在此先谢过了大体过程:先扫码(还没有确定实际要支付的金额),这个码是商品的二维码,再生 ...

  8. 微信扫码支付功能详细教程————Java

    前言  首先声明 我并非原创 原创是 http://blog.csdn.net/wangqiuyun/article/details/51241064 我只是在前辈的基础 加以解释说明 还有自己的一些 ...

  9. Java之微信支付(扫码支付模式二)案例实战

    摘要:最近的一个项目中涉及到了支付业务,其中用到了微信支付和支付宝支付,在做的过程中也遇到些问题,所以现在总结梳理一下,分享给有需要的人,也为自己以后回顾留个思路. 一:微信支付接入准备工作: 首先, ...

随机推荐

  1. hdu 4961 Boring Sum (思维 哈希 扫描)

    题目链接 题意:给你一个数组,让你生成两个新的数组,A要求每个数如果能在它的前面找个最近的一个是它倍数的数,那就变成那个数,否则是自己,C是往后找,输出交叉相乘的和 分析: 这个题这种做法是O(n*s ...

  2. LA 2218 (半平面交) Triathlon

    题意: 有n个选手,铁人三项有连续的三段,对于每段场地选手i分别以vi, ui 和 wi匀速通过. 对于每个选手,问能否通过调整每种赛道的长度使得他成为冠军(不能并列). 分析: 粗一看,这不像一道计 ...

  3. HDU 5313 Bipartite Graph (二分图着色,dp)

    题意: Soda有一个n个点m条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的. 思路: 先将二分图着色,将每个连通分 ...

  4. GreenDao官方文档翻译(上)

    笔记摘要: 上一篇博客简单介绍了SQLite和GreenDao的比较,后来说要详细介绍下GreenDao的使用,这里就贴出本人自己根据官网的文档进行翻译的文章,这里将所有的文档分成上下两部分翻译,只为 ...

  5. linux 命令——文件管理 ls

    一.介绍 ls命令是linux下最常用的命令之一,ls跟dos下的dir命令是一样的都是用来列出目录下的文件和子目录.ls全称list,即列表. 缺省下ls用来打印出当前目录的清单,如果ls指定其他目 ...

  6. [selenium webdriver Java]元素定位——findElement/findElements

    策略 语法 语法 描述 By id driver.findElement(By.id()) driver.findElements(By.id()) 通过id属性定位元素 By name driver ...

  7. Authentication with SignalR and OAuth Bearer Token

    Authentication with SignalR and OAuth Bearer Token Authenticating connections to SignalR is not as e ...

  8. C++的笔记学习第一篇,认识C++

    在一个类中包含两种成员: 数据和函数,分别称为C++数据成员和成员函数. 关于类: 类是C++新增加的重要数据类型,有了类,就就可以实现面向对象程序设计方法中的封装.信息隐蔽.继承.派生.多态等功能. ...

  9. cocos2d-x知识巩固-基础篇(2)

    上一篇博客介绍了整个cocos2dx引擎需要掌握的各个模块,每一个模块实际上往深了研究都有难点,后面我会详细地去分析它的用法.今天我们从第一个模块说起,即渲染模块.首先,为了理解,我们做个类比,说明该 ...

  10. 数据库(class0507)

    局部变量_先声明再赋值 声明局部变量 DECLARE @变量名 数据类型 DECLARE @name varchar(20) DECLARE @id int 赋值 SET @变量名 =值 --set用 ...