# 操作流程
- 注册微信公众号、微信支付商户号,并做好基础配置(不解释配置详情,无非是获取 appid,商户号等)
- 微信支付接口代码
- 微信支付回调接口代码
- 微信h5支付页面唤起字符密码界面完成支付
1. 写代码之前准备工作
(1):利用开源代码 weixin-java-tools来开发效率很高,免去了很多繁琐的代码开发量;
链接 https://github.com/wechat-group/weixin-java-tools
搭建maven工程,引入:
<!-- 微信支付 开始-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>2.8.0</version>
<classifier>sources</classifier>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.8.0</version>
<classifier>sources</classifier>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
<version>2.8.0</version>
<classifier>sources</classifier>
</dependency>
<!-- 微信支付 结束 -->
(2):微信支付开发接口需要 用到用户openId参数,至于微信授权获取用户openId可查看http://blog.hce-space.top/blog/6; (3):获得微信支付所需的配置文件,
这里我配置的有参数的都是必须要填写的,其他的可以不写,这里WX_WEB_URL这个是你网站的网址在回调的时候需要用到,我把这个地址配置到了配置文件里了。
#微信对接配置
weixin:
id:
appId: **************
secret: ***********
mchId: ************
mchKey: *************
redirect-url: http://www.dadsa.com/
refund-notify-url: http://www.api.dadsa.com/pay/notify/refund
pay-notify-url: http://www.api.dadsa.com/pay/notify/pay
auth-file: MP_verify_TxToYqnU86bNRnVu.txt
expires-time:
key-path: classpath:/weixin/apiclient_cert.p12
(4):这个是我们从微信平台上获取的配置文件,还有两个重要的授权地址是我们要在微信平台上配置的。
-
在微信公众平台——》权限接口——》网页授权获取用户基本信息
网址: https://mp.weixin.qq.com 微信公众号登录入口
必须填入外网域名并且要下载提示里的.txt文件,放到你网站的跟目录下,可以通过网站直接访问的路径
推荐一个内网穿透工具,调试微信开发非常方便https://natapp.cn/#download
微信支付的路径配置,这就是支付授权目录,注意这里是目录,不是仅仅是域名,后面要加你要掉起支付的html页面的最后一个路径要加/。如果不加掉用起不来支付界面。
2. 撸代码,Java搞起来
2.1:先把微信配置文件写入一个java类:
@Data
@ConfigurationProperties(prefix = "weixin")
public class WxPayProperties {
/**
* 设置微信公众号或者小程序等的appid
*/
private String appId;
/**
* 微信支付商户号
*/
private String mchId;
/**
* 微信支付商户密钥
*/
private String mchKey;
/**
* 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
*/
private String subAppId;
/**
* 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
*/
private String subMchId;
/**
* apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
*/
private String keyPath;
private String secret;
private String id;
private String aesKey;
private Long expiresTime;
private String redirectUrl;
private String refundNotifyUrl;
private String payNotifyUrl;
private String authFile;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
ToStringStyle.MULTI_LINE_STYLE);
}
}
2.2 配置微信支付bean,这一步使用Binary Wang的jar包后配置十分简单:
@Configuration
public class WxConfig {
private final WxPayProperties wxPayProperties;
private final CustomWxMpInRedisConfigStorage storage;
@Autowired
public WxConfig(WxPayProperties wxPayProperties, CustomWxMpInRedisConfigStorage storage) {
this.wxPayProperties = wxPayProperties;
this.storage = storage;
}
@Bean
public WxMpService wxMpService() {
WxMpService service = new WxMpServiceImpl();
storage.setAppId(wxPayProperties.getAppId());
storage.setSecret(wxPayProperties.getSecret());
storage.setOauth2redirectUri(wxPayProperties.getRedirectUrl());
storage.setExpiresTime(wxPayProperties.getExpiresTime());
service.setWxMpConfigStorage(storage);
return service;
}
@Bean
public WxPayConfig wxPayConfig() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(wxPayProperties.getAppId());
payConfig.setMchId(wxPayProperties.getMchId());
payConfig.setMchKey(wxPayProperties.getMchKey());
payConfig.setNotifyUrl(wxPayProperties.getRedirectUrl());
payConfig.setKeyPath(wxPayProperties.getKeyPath());
payConfig.setTradeType("JSAPI");
payConfig.setSignType("MD5");
return payConfig;
}
@Bean
public WxPayService wxPayService(WxPayConfig payConfig) {
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
2.3 微信支付控制器,这是我之前写的系统:
/**
* 微信对接控制器,微信支付
*/
@Controller
@RequestMapping("/pay")
public class WxPayController extends BaseController {
private final Logger logger = LoggerFactory.getLogger("WxPayController");
@Autowired
private WxMpService service;
@Autowired
private WxPayProperties wxPayProperties;
@Autowired
private WXService ourWxService;
/**
* 统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
* request请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
*
* @param orderNumber 这里是我自己系统的订单号,可以根据这个查出来需要的费用等等
*/
@PostMapping("/unifiedOrder/{orderNumber}")
@MapTo(WxPayDto.class)
public WxPayMpOrderResult unifiedOrder(@PathVariable String orderNumber, Principal principal, HttpServletRequest req) {
String wxOpenid = getUser(principal).getWxOpenid();
return ourWxService.unifiedOrder(orderNumber, wxOpenid, principal, req);
}
/**
* 付款微信回调
*
* @param body 微信返回参数
* @return
*/
@RequestMapping("notify/pay")
public Object payNotify(@RequestBody String body) {
return ourWxService.payNotify(body);
}
/**
* <pre>
* 微信支付-申请退款
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
* 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund
* </pre>
* <p>
* request 请求对象
*
* @return 退款操作结果
*/
@PostMapping("/refund/{orderType}/{id}")
public WxPayRefundResult refund(@PathVariable OrderType orderType, @PathVariable String id) throws WxPayException {
OrderInfo order = orderService.getByType((short) orderType.origin(), id);
//组装退款对象
WxPayRefundRequest request = new WxPayRefundRequest();
request.setOutTradeNo(order.getNumber());
request.setOutRefundNo(order.getNumber());
request.setTotalFee((int) (order.getPrice() * 100));
request.setRefundFee((int) (order.getPrice() * 100));
request.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());
return this.wxService.refund(request);
}
/**
* 退款结果通知
*
* @param request
* @throws WxPayException
*/
@RequestMapping("/notify/refund")
public Object reFundNotify(HttpServletRequest request) {
return ourWxService.reFundNotify(request);
}
}
Service:
@Override
public WxPayMpOrderResult unifiedOrder(String orderNumber, String wxOpenid, Principal principal, HttpServletRequest req) {
OrderInfo order = orderService.getOrder(orderNumber);
String lable = "测试付款";
//组装前端所需付款参数
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
String ip = req.getRemoteAddr();
request.setOutTradeNo(orderNumber);
//微信支付都以分为单位,此处*100
request.setTotalFee((int) (order.getPrice() * 100));
request.setBody(order.getType().label() + "-" + lable);
request.setTradeType(TRADETYPE);
request.setNotifyUrl(wxPayProperties.getPayNotifyUrl());
request.setSpbillCreateIp(ip);
request.setOpenid(wxOpenid);
try {
return wxService.createOrder(request);
} catch (WxPayException e) {
e.printStackTrace();
}
}
@Override
public Object payNotify(String body) {
WxPayOrderNotifyResult result = null;
try {
result = wxPayService.parseOrderNotifyResult(body);
if (SUCCESS_CODE.equals(result.getReturnCode())) {
//返回微信接收成功,否则微信会一直调用此接口
WxPayNotifyResponse response = new WxPayNotifyResponse();
response.setReturnCode("SUCCESS");
response.setReturnMsg("Ok");
return response;
}
return null;
} catch (WxPayException e) {
e.printStackTrace();
}
return null;
}
@Override
public Object reFundNotify(HttpServletRequest request) {
logger.error("接收到退款通知");
String body = readRequestStr(request);
WxPayRefundNotifyResult wxPayRefundNotifyResult = null;
try {
wxPayRefundNotifyResult = wxPayService.parseRefundNotifyResult(body);
} catch (WxPayException e) {
e.printStackTrace();
}
WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
if (SUCCESS_CODE.equals(wxPayRefundNotifyResult.getReturnCode())) {
//返回微信接收成功,否则微信会一直调用此接口
WxPayNotifyResponse response = new WxPayNotifyResponse();
response.setReturnCode("SUCCESS");
response.setReturnMsg("Ok");
return response;
}
return null;
}
2.3 前端代码:
<head>
<script type="text/javascript" src="http://g.alicdn.com/sj/lib/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script src="../js/common.js"></script>
<script type="text/javascript">
function toPay(){
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}
function onBridgeReady(){
$.ajax({
type: "POST",
url: DEF_GLOBAL_DOMAIN+"/pay/unifiedOrder/124534",
success: function(data){
console.log(data);
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId" : data.data.appId,
"timeStamp": data.data.timeStamp,
"nonceStr" : data.data.nonceStr,
"package" : data.data.package,
"signType" : data.data.signType,
"paySign" : data.data.paySign
},function(res){
$("#msgId").html(res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
$("#resId").html("支付成功");
// location.href="weixinPayResult.html";//支付成功跳转到指定页面
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
$("#resId").html("支付取消");
}else{
$("#resId").html("支付失败");
}
});
}
});
}
</script>
</head>
<body>
<div class="content">
<div class="form-area">
<div class="inp">
支付0.01元
</div>
<button class="em-submit-st2" οnclick="toPay()" >
确定支付
</button>
</div>
结果:
<p/>
<div id="resId"></div>
参数:
<p/>
<div id="invokeId"></div>
<br/><p/>
返回:
<p/>
<div id="msgId"></div>
</div>
</body>
</html>
到这里整个微信支付就完成了,跑不通一般是哪里配置有问题,多查一下自己代码里的配置项。
微信用的各种签名、sign,这个工具已经给我们解决了,只要各个地方的配置没有问题,其实就很简单了。
###### 整个执行流程 是 :
微信点击支付按钮——》发送ajax到支付请求控制器——》返回支付参数——》用支付参数,调用微信内嵌的掉起支付js方法,发起支付——》支付结果同步返回结果——》支付结果异步发送到后台回调控制器做结果处理