步骤:

  • 导入maven依赖
    <!--微信支付-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
  • 微信支付参数配置
import com.github.wxpay.sdk.WXPayConfig;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream; /**
* 微信支付配置(单例)
*/
public class WXConfigUtil implements WXPayConfig { private byte[] certData;
private static WXConfigUtil INSTANCE; public static final String APP_ID = "*****";//应用AppID
public static final String KEY = "******";//商户密钥
public static final String MCH_ID = "******";//商户号 public WXConfigUtil() throws Exception {
String certPath = WXConfigUtil.class.getClassLoader().getResource("").getPath();//从微信商户平台下载的安全证书存放的路径
File file = new File(certPath+ "apiclient_cert.p12");
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
} //双重检查加锁
public static WXConfigUtil getInstance() throws Exception {
if (INSTANCE == null) {
synchronized (WXConfigUtil.class) {
if (INSTANCE == null) {
INSTANCE = new WXConfigUtil();
}
}
}
return INSTANCE;
} @Override
public String getAppID() {
return APP_ID;
} //parnerid,商户号
@Override
public String getMchID() {
return MCH_ID;
} @Override
public String getKey() {
return KEY;
} @Override
public InputStream getCertStream() {
ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
return certBis;
} @Override
public int getHttpConnectTimeoutMs() {
return 8000;
} @Override
public int getHttpReadTimeoutMs() {
return 10000;
}
}
  • 业务层统一下单以及异步通知后的XML数据处理
import com.aone.app.common.wx.WXConfigUtil;
import com.aone.app.common.wx.WxCfg;
import com.aone.app.service.PayService;
import com.aone.app.service.WXAppPayService;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import java.util.HashMap;
import java.util.Map; @Service
public class WXAppPayServiceImpl implements WXAppPayService { private static final Logger logger = LoggerFactory.getLogger("WXAppPayServiceImpl");
@Autowired
private WxCfg wxCfg;
/**
* 调用官方SDK 获取预支付订单等参数
* @param type
* @param out_trade_no
* @param money
* @return
* @throws Exception
*/
@Override
public Map<String, String> dounifiedOrder(String type,String out_trade_no,String money) throws Exception {
Map<String, String> returnMap = new HashMap<>(); //支付参数
WXConfigUtil config = new WXConfigUtil();
WXPay wxpay = new WXPay(config);
//请求参数封装
Map<String, String> data = new HashMap<>();
data.put("appid", config.getAppID());
data.put("mch_id", config.getMchID());
data.put("nonce_str", WXPayUtil.generateNonceStr());
data.put("body", "订单支付");
data.put("out_trade_no", out_trade_no);
data.put("total_fee", "1");
data.put("spbill_create_ip", wxCfg.getIp()); //自己的服务器IP地址
data.put("notify_url", wxCfg.getAppNotifyUrl());//异步通知地址(请注意必须是外网)
data.put("trade_type", wxCfg.getAppType());//交易类型
data.put("attach", type);//附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
String s = WXPayUtil.generateSignature(data, config.getKey()); //签名
data.put("sign", s);//签名 try {
//使用官方API请求预付订单
Map<String, String> response = wxpay.unifiedOrder(data);
System.out.println(response);
String returnCode = response.get("return_code"); //获取返回码
//若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
if (returnCode.equals("SUCCESS")) {
//主要返回以下5个参数(必须按照顺序,否则APP报错:-1)
String resultCode = response.get("result_code");
returnMap.put("appid", response.get("appid"));
returnMap.put("noncestr", response.get("nonce_str"));
if ("SUCCESS".equals(resultCode)) {//resultCode 为SUCCESS,才会返回prepay_id和trade_type
returnMap.put("package","Sign=WXPay");
returnMap.put("partnerid", response.get("mch_id"));
returnMap.put("prepayid", response.get("prepay_id"));
returnMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));//单位为秒 String sign = WXPayUtil.generateSignature(returnMap, config.getKey());// 二次签名
returnMap.put("sign",sign); //签名
returnMap.put("trade_type", response.get("trade_type"));//获取预支付交易回话标志
return returnMap;
} else {
//此时返回没有预付订单的数据
return returnMap;
}
} else {
return returnMap;
}
} catch (Exception e) {
System.out.println(e);
//系统等其他错误的时候
}
return returnMap;
} /**
*
* @param notifyData 异步通知后的XML数据
* @return
*/
@Override
public String payBack(String notifyData) {
WXConfigUtil config = null;
try {
config = new WXConfigUtil();
} catch (Exception e) {
e.printStackTrace();
}
WXPay wxpay = new WXPay(config);
String xmlBack = "";
Map<String, String> notifyMap = null;
try {
notifyMap = WXPayUtil.xmlToMap(notifyData); // 调用官方SDK转换成map类型数据
if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {//验证签名是否有效,有效则进一步处理 String return_code = notifyMap.get("return_code");//状态
String out_trade_no = notifyMap.get("out_trade_no");//商户订单号
if (return_code.equals("SUCCESS")) {
if (out_trade_no != null) {
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户的订单状态从退款改成支付成功
// 注意特殊情况:微信服务端同样的通知可能会多次发送给商户系统,所以数据持久化之前需要检查是否已经处理过了,处理了直接返回成功标志
//业务数据持久化
System.err.println("支付成功"+"\n");
String attach = notifyMap.get("attach");//附加数据,用于区分是那张表订单
System.out.print("附加数据类型为:{}"+attach+"\n");
if(StringUtils.isEmpty(attach)){
logger.info("附加数据类型为:{}", attach);
}else{
//@TODO 预支付下单后回调的逻辑 }
logger.info("微信手机支付回调成功订单号:{}", out_trade_no);
xmlBack = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
} else {
logger.info("微信手机支付回调失败订单号:{}", out_trade_no);
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
}
return xmlBack;
} else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
//失败的数据要不要存储?
logger.error("手机支付回调通知签名错误");
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
return xmlBack;
}
} catch (Exception e) {
logger.error("手机支付回调通知失败", e);
xmlBack = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
}
return xmlBack;
}
}
  • WXCfg中配置的是微信支付的回调地址以及交易类型
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; /**
* 微信参数配置中心
*/
@Component
public class WxCfg { @Value("${wx.appType}")
private String appType;//App支付交易类型
@Value("${wx.appNotifyUrl}")
private String appNotifyUrl;//App回调地址
@Value("${wx.h5Type}")
private String h5Type;//H5支付交易类型
@Value("${wx.h5NotifyUrl}")
private String h5NotifyUrl;//H5回调地址
@Value("${wx.ip}")
private String ip;//服务器ip
@Value("${wx.redirect_url}")
private String redirect_url;//跳转地址 public String getAppNotifyUrl() {
return appNotifyUrl;
} public void setAppNotifyUrl(String appNotifyUrl) {
this.appNotifyUrl = appNotifyUrl;
} public String getH5NotifyUrl() {
return h5NotifyUrl;
} public void setH5NotifyUrl(String h5NotifyUrl) {
this.h5NotifyUrl = h5NotifyUrl;
} public String getAppType() {
return appType;
} public void setAppType(String appType) {
this.appType = appType;
} public String getH5Type() {
return h5Type;
} public void setH5Type(String h5Type) {
this.h5Type = h5Type;
} public String getIp() {
return ip;
} public void setIp(String ip) {
this.ip = ip;
} public String getRedirect_url() {
return redirect_url;
} public void setRedirect_url(String redirect_url) {
this.redirect_url = redirect_url;
}
}
  • 控制层下单接口以及回调接口
import com.aone.app.service.WXAppPayService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map; @RestController
@RequestMapping("pay")
@Api("App支付")
public class PayAppController { @Autowired
private WXAppPayService wxAppPayService; /**
*
* App支付统一下单
* @param out_trade_no 订单号
* @param total_fee 支付金额
* @param type 0:预约订单1:专家保证金2:即时咨询订单
* @return
* @throws Exception
*/
@PostMapping("order")
public Map<String, String> order(@RequestParam(value = "type") String type,@RequestParam(value = "out_trade_no") String out_trade_no,@RequestParam(value = "total_fee") String total_fee)throws Exception{
return wxAppPayService.dounifiedOrder(type,out_trade_no,total_fee);
} /**
* 微信支付异步结果通知
*/
@RequestMapping(value = "wxPayNotify", method = {RequestMethod.GET, RequestMethod.POST})
public String wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
System.out.print("微信回调开始"+"\n");
String resXml = "";
try {
InputStream inputStream = request.getInputStream();
//将InputStream转换成xmlString
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
resXml = sb.toString();
String result = wxAppPayService.payBack(resXml);
System.out.print("微信回调结束"+"\n");
return result;
} catch (Exception e) {
System.out.println("微信手机支付失败:" + e.getMessage());
String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
return result;
}
} }
  • 下单封装的Map中封装参数服务器IP写死可能会报错,提供获取服务器IP工具类
import javax.servlet.http.HttpServletRequest;

/**
* 获取服务器IP工具类
*/
public class IpAddr { 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;
} }

主要用于安卓APP微信支付,IOS微信支付可能是需要交钱,太贵了,所以IOS的微信支付提供外链接使用H5进行支付。

微信APP支付(基于Java实现微信APP支付)的更多相关文章

  1. 微信H5支付(基于Java实现微信H5支付)

    微信的H5支付区别与APP支付,主要在于预下单(返回的参数不一样),其它大体相同(基本没什么区别,区别在于有些人加密喜欢用MD5有些人喜欢用官方提供的加密方式加密,我用的是官方的),贴一下H5支付预下 ...

  2. 支付宝APP支付(基于Java实现支付宝APP支付)

    贴一下支付核心代码,以供后续参考: 业务层 import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; ...

  3. 带领技术小白入门——基于java的微信公众号开发(包括服务器配置、java web项目搭建、tomcat手动发布web项目、微信开发所需的url和token验证)

    微信公众号对于每个人来说都不陌生,但是许多人都不清楚是怎么开发的.身为技术小白的我,在闲暇之余研究了一下基于java的微信公众号开发.下面就是我的实现步骤,写的略显粗糙,希望大家多多提议! 一.申请服 ...

  4. wemall app中基于Java获取和保存图片的代码

    wemall-mobile是基于WeMall的android app商城,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可定制修改.分享其中关于 保存正在下载的图片URL集合和图片三种获 ...

  5. 支付宝手机网站支付(基于Java实现支付宝手机网站支付)

    支付宝支付核心需要的参数是(APPID,PRIVATE_KEY,ALIPAY_PUBLIC_KEY) APPID:创建应用后就有的APPID. PRIVATE_KEY:应用私钥 ALIPAY_PUBL ...

  6. 微信开发 -- 搭建基于ngrok的微信本地调试环境

    第一步,安装ngrok客户端 (1)首先先到官网下载个客户端 http://natapp.cn/,选择适合的客户端类型,本人选择的是windows版 (2)下载后,解压,可以看到如下目录: 第二步,开 ...

  7. app微信支付-java服务端接口 支付-查询-退款

    个人不怎么看得懂微信的文档,看了很多前辈的写法,终于调通了,在这里做一下记录. 首先来定义各种处理类(微信支付不需要特殊jar包,很多处理需要自己封装,当然也可以自己写完打个jar包) 参数要用jdo ...

  8. java中微信统一下单采坑(app微信支付)

    app支付前java后台统一下单文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1 微信支付接口签名校验工具:https ...

  9. 微信支付之扫码、APP、小程序支付接入详解

    做电商平台的小伙伴都知道,支付服务是必不可少的一部分,今天我们开始就说说支付服务的接入及实现.目前在国内,几乎90%中小公司的支付系统都离不开微信支付和支付宝支付.那么大家要思考了,为什么微信支付和支 ...

随机推荐

  1. Django中authenticate和login模块

    Django 提供内置的视图(view)函数用于处理登录和退出,Django提供两个函数来执行django.contrib.auth中的动作 : authenticate()和login(). 认证给 ...

  2. 实现Modbus TCP多网段客户端应用

    对于Modbus TCP来说与Modbus RTU和Modbus ASCII有比较大的区别,因为它是运行于以太网链路之上,是运行于TCP/IP协议之上的一种应用层协议.在协议栈的前两个版本中,Modb ...

  3. MVC ViewBag和ViewData的使用

    ViewBag public ActionResult About() { ViewBag.Message = "Your application description page.&quo ...

  4. 【JS新手教程】replace替换一个字符串中所有的某单词

    JS中的replace方法可以替换一个字符串中的单词.语句的格式是: 需要改的字符串.replace(字符串或正则表达式,替换成的字符串) 如果第一个参数用字符串,默认是找到该字符串中的第一个匹配的字 ...

  5. python logging模块日志输出

    import logging logger = logging.getLogger(__name__) logger.setLevel(level = logging.INFO) handler = ...

  6. ROW_NUMBER()函数使用详解

    原文地址:https://blog.csdn.net/qq_30908543/article/details/74108348 注:mysql貌似不适用,本人测试未成功,mysql实现方式可参考:ht ...

  7. 推荐Pi(π)币,相当于比特币手机挖矿版

    我为什么推荐这个? 说实话,之所以发出来还是因为如果用我的邀请码注册,双方的挖矿速度都会增加些,我的邀请码:leneing,有问题可以咨询我. Pi币简介 1.在这里强烈推荐Pi币,相当于比特币手机挖 ...

  8. ztree节点名称排序

    // result 为后台返回的集合,在渲染tree前的数据 result = result.sort(function (a, b) { // 判断前面一个是字母,后面一个不是字母,那么不换位置,返 ...

  9. 探索安卓热修复框架AndFix的奥秘

    虽然阿里的AndFix框架已经出来很长时间了,但是还不了解它的同学依然挺多,接下来就跟着我一起来到AndFix的世界里一起看看,如何达到不用重新安装app就可以修复bug. 1.什么是AndFix? ...

  10. D1. Docker: win7 环境下安装 Docker

    [下载与安装] win7.win8 等需要利用 docker toolbox 来安装,国内可以使用阿里云的镜像来下载,下载地址:http://mirrors.aliyun.com/docker-too ...