微信支付已经做烂了,没啥好讲的。记录一下。
首先微信支付流程相信大家大致都了解,不知道的自己去微信开发文档上看,很简单,我这边不多说直接上代码。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@GetMapping(value = "pay")
public String wechatPayOrder(@RequestParam("orderId") String orderId, HttpServletRequest request, Model model){
log.info("活动订单: {} 开始微信支付", orderId);
// 调用serviceH5支付
//将属性转化为xml格式,然后传给微信服务器,得到支付的URL
String url = weChatPayService.wechatPayH5("标题", null, orderId(订单号), String.valueOf(1)(价格,单位是分 1对应0.01 ), request);
if(StringUtils.isEmpty(url)){
log.error("活动订单: {} 微信支付失败, 获取到的支付url为空", "");
return "/pay/error";//Result.error("no",null);
}
try {
//将返回的url加上我们自己本地服务器上的返回路径redirect_url
url = url + "&redirect_url="+ URLEncoder.encode(weChatConfig.redirect_url, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
model.addAttribute("pay",url);
return "pay/wxbuy";// Result.success(url);
}
/**
* 微信支付完成后,微信回调的页面
* @return
*/
@GetMapping("/backll")
public String backll(){
System.out.println("-------------微信回调---------------:");
return "pay/back"; //Result.success("no");
}
/**
* 查询订单,用于微信回调接口时查询订单是否完成。用户主动触发
* @param orderId
* @return
*/
@GetMapping("/checkList")
public String CheckList(@RequestParam("orderId")String orderId){
weChatPayService.CheckList(orderId);
return "pay/back";
}
参数类,值就自己去自己配置文件中设置
@Component
public class WeChatConfig {
@Value("${wxpay.appid}")
public String appid;
@Value("${wxpay.appsecret}")
public String appsecret;
@Value("${wxpay.mer_id}")
public String merId;
@Value("${wxpay.key}")
public String key;
// 支付回调
@Value("${wxpay.callback}")
public String callback;
// 文档介绍: 正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,则可以在MWEB_URL后拼接上redirect_url参数,来指定回调页面。
@Value("${wxpay.redirect_url}")
public String redirect_url;
}
实现方法
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
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 javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
@Service
public class WeChatPayServiceImpl implements WeChatPayService {
@Autowired
private WeChatConfig weChatConfig;
private static final Logger logger = LoggerFactory.getLogger("WeChatPayServiceImpl");
/**
* 微信H5支付
* @param remark 订单备注
* @param attach 携带的附加数据. 可以不用
* @param out_trade_no 订单号
* @param money 金额
* @param request
* @return url
*/
@Override
public String wechatPayH5(String remark, String attach, String out_trade_no, String money, HttpServletRequest request) {
String requestIp = CommonUtils.getIpAddr(request);
//返回参数
SortedMap<String,String> params = new TreeMap<>();
params.put("appid", weChatConfig.appid);
params.put("mch_id", weChatConfig.merId);
params.put("nonce_str", CommonUtils.generateUUID()); // 随机字符串, 请求参数需要
params.put("body", remark); // 支付备注
params.put("out_trade_no", out_trade_no); // 订单号
params.put("total_fee", "1"); // 支付金额
params.put("spbill_create_ip",requestIp); // 设置创建订单的ip地址,不太明白是什么ip.有人用当前服务器的ip,我这里直接使用用户请求的ip,没有发现有什么影响.
params.put("notify_url",weChatConfig.callback); // 支付回调,也就是支付成功后,我们业务员上需要做的操作
params.put("trade_type", "MWEB"); // 交易类型,这里为H5
String sign = WXPayUtil.createSign(params, weChatConfig.key);
params.put("sign",sign);
String payXml;
try {
// 微信支付要求调用统一下单接口的必须是一个xml
payXml = WXPayUtil.mapToXml(params);
logger.info("payXml: "+payXml);
// 调用微信的统一下单接口
String orderStr = HttpUtils.doPost("https://api.mch.weixin.qq.com/pay/unifiedorder",payXml,4000);
if(StringUtils.isEmpty(orderStr)){
logger.error("微信支付失败.原因: 调用微信统一下单接口失败");
return null;
}
logger.info("orderStr: "+orderStr);
// 调用成功, 返回的结果也是一个xml, 需要将返回的XML转化为一个map, 方便操作.
Map<String, String> unifiedOrderMap = WXPayUtil.xmlToMap(orderStr);
if(unifiedOrderMap != null) {
// 得到支付的url
return unifiedOrderMap.get("mweb_url");
}
} catch (Exception e) {
logger.error("微信支付失败.原因: map参数转xml失败({})", e.getMessage());
e.printStackTrace();
}
return null;
}
public String CheckList(String orderId){
//查询订单接口
SortedMap<String,String> params = new TreeMap<>();
params.put("appid", weChatConfig.appid);
params.put("mch_id", weChatConfig.merId);
params.put("nonce_str", CommonUtils.generateUUID()); // 随机字符串, 请求参数需要
params.put("out_trade_no", orderId); // 订单号
String sign = WXPayUtil.createSign(params, weChatConfig.key);
params.put("sign",sign);
String payXml;
try {
// 微信支付要求调用统一下单接口的必须是一个xml
payXml = WXPayUtil.mapToXml(params);
// logger.info("payXml: " + payXml);
// 调用微信的统一下单接口
String orderStr = HttpUtils.doPost("https://api.mch.weixin.qq.com/pay/orderquery", payXml, 4000);
System.out.println(orderStr);
Map<String, String> map = WXPayUtil.xmlToMap(orderStr);
System.out.println("状态码: "+map.get("err_code")+" ---订单状态----:"+map.get("err_code_des")+"-----:"+map.get("result_code"));
}catch (Exception e){
}
return "";
}
java方面大致就是这样。但是微信返回的那个支付url是无法直接用浏览器打开的,所以我们得返回给html,让html去请求。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="hidden" id="url2" th:value="${pay}" name="token">
<button th:onclick="first2([[${pay}]])"> 点击</button>
</body>
<script type="text/javascript" th:inline="javascript">
function first2(ss) {
window.location.href = ss;
}
</script>
</html>
请求后就是这样,支付成功。
注意2点:一,请求时的域名地址必须和微信商城中设置的域名一样,回调的地址也是一样,不然会出现下列错误。
2.为了防止用户假支付,我们应该确认订单是否完成了。因为用户在取消支付或者停留页面过长,系统都会回调我们自己的接口。所以我们需要在里面设置一个查询订单状态的接口。用来判断订单是否完成。微信方面是希望我们设置一个页面让客户自己点击去触发这次操作。
还有一些就参数问题啊,配置问题啥的就不说了自己去微信开发平台看,里面都有详细说明。地址:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_4
整个支付流程就这样。具体有什么问题可以提出来。毕竟我也不保证能都没问题。如果没问题,麻烦点个赞 哈哈。
补充下,博友需要自己下载下微信的sdk。微信平台上有下载。当然也可以用maven自己去引进。
项目地址:https://download.csdn.net/download/qq_42729674/20156744?spm=1001.2014.3001.5501