最近维护一个C#开发的H5老系统,是由上届同事留下的系统,我也不知道为啥要用C#开发,Java多香。
代码给我后花了一天时间熟悉了一下这套系统的架构以及下订单的逻辑和支付。
废话不多说,本文只讲支付相关的内容,不涉及业务,以及其他不相关的内容。
我就直接贴代码了,代码都有注释,一步一步看一定看得懂。
前端代码
@using Theia.Swd.H5Pay.Models.Business.School.Result
@model dynamic
@{
ViewBag.Title = "待支付订单";
var data = ViewData["data"] as ResultForGetHtOrder;
}
<div class="shopping">
<div class="shop-group-item">
<strong>合计:<i class="total" id="AllTotal">@data.price</i></strong>
</div>
<button id="butSubmit" class="settlement" onclick="subumitpay()">结算</button>
</div>
</div>
<script>
function subumitpay() {
//按钮置灰
disabledControl();
var orderid = "@data.orderid";//你的订单号
var is_weixin = (function(){return
navigator.userAgent.toLowerCase().indexOf('micromessenger') !== -1})();
if (!is_weixin) {//支付宝支付
window.location.href = "/PaymentData/ReturnToAlipay?
orderId="+orderId;
return;
}//否则就是微信支付
var url = "/PaymentData/SubmitStudentRechargeOrder";
var v = {};
v.orderId = orderId;
jQuery.post(url,
v,
function (r) {
enabledControl();
if (!r.Status) {
mui.alert(r.Message);
return;
}
pay(r.Data,orderId);
});
}
function disabledControl() {
$("#butSubmit").attr("disabled", "disabled");
}
function enabledControl() {
$("#butSubmit").removeAttr("disabled");
}
function pay(data,orderId) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": data.AppId, //公众号名称,由商户传入
"timeStamp": data.TimeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.NonceStr, //随机串
"package": data.Package,
"signType": "MD5", //微信签名方式:
"paySign": data.PaySign //微信签名
},
function (res) {
alert(res.err_msg);
if (res.err_msg === "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//成功后跳转到自定义支付成功的页面
window.location.href = "/Payment/PayInfoResult?orderId="+orderId;
}
});
}
</script>
首先来看微信支付的逻辑
public ActionResult SubmitStudentRechargeOrder()
{
try
{
//订单id
var orderId = WebUtil.GetRequest<string>("orderId");
LogUtil.Info("调用微信支付接口:" + orderId);
var service = new PaymentService();
//根据订单id去数据库里查询订单信息
var orderResult = service.GetStudentRechargeOrderInfo(new
ParamForGetOrderInfo()
{
OrderId = orderId,
UserId = WebUtil.GetUserId()
});
if (orderResult == null || !orderResult.Status)
{
LogUtil.Info("没有找到订单");
return false;
}
//订单信息
var order = orderResult.Data;
LogUtil.Info("创建微信单订单");
//调用微信支付接口
return CreateWechatOrder(order);
}
catch (Exception e)
{
LogUtil.Error("异常:" + e.Message);
return Json(ResponseData<ResultForWeixinMpPayment>.Exception(MessageConstant.GetErrorMessage(e)), JsonRequestBehavior.AllowGet);
}
}
private ActionResult CreateWechatOrder(ResultForGetStudentRechargeOrderInfo order)
{
//微信扫码进来的我把用户的openid放进了session
var opendid = WebUtil.GetOpenId();
//取订单表里的金额乘100 变成分
var totalFee = (int)(Convert.ToDecimal(order.Order.OrderAmount) * 100);
LogUtil.Info("进入微信支付页面-金额" + totalFee);
//取时间戳 必传
var timeStamp = TenPayV3Util.GetTimestamp();
//nonceStr 必传
var nonceStr = TenPayV3Util.GetNoncestr();
var xmlDataInfo = new TenPayV3UnifiedorderRequestData(
ConfigurationManager.AppSettings["WechatAppId"],//微信公众的APPID放在配置文件
ConfigurationManager.AppSettings["WechatMchId"],//商户的MchId放在配置文件
order.Order.OrderTitle,//商品名称
order.OrderId,//订单id
totalFee,//金额
"127.0.0.1",//Request.UserHostAddress,
ConfigurationManager.AppSettings["WechatNotify"],//通知微信的回调地址
TenPayV3Type.JSAPI,
opendid,//用户的openid
ConfigurationManager.AppSettings["WechatKey"],//商户的密钥
nonceStr
);
//进行签名
var unifiedorderResult = TenPayV3.Unifiedorder(xmlDataInfo);
if (unifiedorderResult.return_code.ToUpper() == "FAIL")//签名失败
{
throw new Exception(unifiedorderResult.return_msg);
}
//取package
var package = $"prepay_id={unifiedorderResult.prepay_id}";
//paySign
var paySign = TenPayV3.GetJsPaySign(ConfigurationManager.AppSettings["WechatAppId"], timeStamp, nonceStr, package, ConfigurationManager.AppSettings["WechatKey"]);
//封装成一个data返回给前台
var result = new ResultForWeixinMpPayment
{
AppId = ConfigurationManager.AppSettings["WechatAppId"],
TimeStamp = timeStamp,
NonceStr = nonceStr,
Package = package,
PaySign = paySign
};
return Json(ResponseData<ResultForWeixinMpPayment>.Success(data: result), JsonRequestBehavior.AllowGet);
}
}
用户支付成功后,我们后台传给了微信的一个回调接口。微信自动会执行这个回调接口。
所以我们还需要写一个回调的接口。
using System;
using System.Configuration;
using System.Data.Entity.Migrations;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Xml.Serialization;
using Newtonsoft.Json;
using Senparc.Weixin.MP.TenPayLibV3;
using Theia.Swd.H5Pay.Framework.Data;
using Theia.Swd.H5Pay.Models.Business.Payment.Enum;
using Theia.Swd.H5Pay.Notify.Models;
namespace Theia.Swd.H5Pay.Notify.Controllers
{
public class WechatNotifyController : ApiController
{
[HttpGet, HttpPost]
public HttpResponseMessage WeixinNotify(HttpRequestMessage requestMessage)
{
try
{
var content = requestMessage.Content.ReadAsStringAsync().Result;
if (string.IsNullOrEmpty(content))
{
return ResponseFail();
}
ParamForWeixinNotify model;
using (var rdr = new StringReader(content))
{
var xmlSerializer = new XmlSerializer(typeof(ParamForWeixinNotify));
model = (ParamForWeixinNotify)xmlSerializer.Deserialize(rdr);
}
if (model == null)
{
return ResponseFail();
}
var result = Notify(model);
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(ConvertWeixinNotifyResultToXml(result), Encoding.UTF8, "application/xml")
};
}
catch (Exception ex)
{
//_logger.Info("WeixinNotify()异常", ex);
return ResponseFail();
}
}
public ReturnForWeixinNotify Notify(ParamForWeixinNotify param)
{
LogUtil_1.Info("进入微信Notify");
if (param.return_code == "FAIL")
{
LogUtil_1.Info("--param.return_code == FAIL--");
return ReturnForWeixinNotify.Fail(msg: param.return_msg);
}
if (param.result_code == "FAIL")
{
LogUtil_1.Info("--param.result_code == FAIL--");
return ReturnForWeixinNotify.Fail(msg: param.err_code_des);
}
if (string.IsNullOrEmpty(param.out_trade_no))
{
LogUtil_1.Info("--交易号为空--");
return ReturnForWeixinNotify.Fail(msg: "交易号为空");
}
var r = Query(new ParamForDoQuery()
{
OutTradeNo = param.out_trade_no
});
if (r == null || !r.TradeStatus)
{
LogUtil_1.Info("订单未交易成功");
return ReturnForWeixinNotify.Fail(msg: "订单未交易成功");
}
var message = string.Empty;
if (!CheckToDb(r.OutTradeNo, r.TotalFee, out message))
{
return ReturnForWeixinNotify.Fail(msg: message);
}
return ReturnForWeixinNotify.Success();
}
public bool CheckToDb(string orderId, double price, out string message)
{
try
{
using (var context = new DbContext())
{
var order = context.T_Order.FirstOrDefault(m => m.OrderID == orderId);
if (order == null)
{
LogUtil_1.Info("没有找到订单" + orderId);
}
else
{
LogUtil_1.Info("微信订单支付id" + orderId);
if (order.OrderStatus == (int)OrderStatusEnum.Success)
{
message = "交易成功";
LogUtil_1.Info(message);
return true;
}
if (Math.Abs(order.OrderAmount - Convert.ToDecimal(price)) > 0.00m)
{
message = "金额不正确";
LogUtil_1.Info(message);
return false;
}
order.PaymentType = (int)PaymentTypeEnum.WechatMp;//支付类型
order.OrderStatus = (int)OrderStatusEnum.Success;//支付状态
order.FinishedDate = DateTime.Now;//支付时间
context.T_Order.AddOrUpdate(order);//更新数据库状态
context.SaveChanges();//提交
}
}
message = string.Empty;
LogUtil_1.Info("微信支付成功");
return true;
}
catch (Exception e)
{
message = e.Message;
LogUtil_1.Info("微信支付异常"+message);
return false;
}
}
public ReturnForWeixinQuery Query(ParamForDoQuery paramForDoPayment)
{
//var tenPayV3Info = TenPayV3InfoCollection.Data[ConfigurationManager.AppSettings["TenPayV3_MchId"]];
var nonceStr = TenPayV3Util.GetNoncestr();
var outTradeNo = paramForDoPayment.OutTradeNo;
var datainfo = new TenPayV3OrderQueryRequestData(ConfigurationManager.AppSettings["WechatAppId"], ConfigurationManager.AppSettings["WechatMchId"],
"", nonceStr, outTradeNo, ConfigurationManager.AppSettings["WechatKey"]);
var weixinResult = TenPayV3.OrderQuery(datainfo);
var result = new ReturnForWeixinQuery();
if (weixinResult.return_code == "SUCCESS" && weixinResult.trade_state == "SUCCESS")
{
result.TradeStatus = true;
result.Message = weixinResult.return_msg;
result.OutTradeNo = weixinResult.out_trade_no;
result.TotalFee = Convert.ToDouble(Convert.ToDecimal(weixinResult.total_fee) / 100);
return result;
}
if (weixinResult.return_code == "SUCCESS" && weixinResult.trade_state != "SUCCESS")
{
result.TradeStatus = false;
result.Message = weixinResult.err_code_des;
if (string.IsNullOrEmpty(result.Message))
{
result.Message = weixinResult.return_msg;
}
if (string.IsNullOrEmpty(result.Message))
{
result.Message = weixinResult.trade_state_desc;
}
return result;
}
result.TradeStatus = false;
result.Message = weixinResult.return_msg;
return result;
}
/// <summary>
/// 回应失败
/// </summary>
/// <returns></returns>
private HttpResponseMessage ResponseFail()
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Fail")
};
}
private string ConvertWeixinNotifyResultToXml(ReturnForWeixinNotify param)
{
if (param == null)
{
param = new ReturnForWeixinNotify();
}
StringBuilder sb = new StringBuilder();
sb.Append("<xml>");
sb.AppendFormat("<return_code><![CDATA[{0}]]></return_code>", param.return_code);
sb.AppendFormat("<return_msg><![CDATA[{0}]]></return_msg>", param.return_msg);
sb.Append("</xml>");
return sb.ToString();
}
}
[XmlRoot("xml")]
public class ParamForWeixinNotify
{
[XmlElement("return_code")]
public string return_code { get; set; }
[XmlElement("result_code")]
public string result_code { get; set; }
[XmlElement("return_msg")]
public string return_msg { get; set; }
[XmlElement("err_code")]
public string err_code { get; set; }
[XmlElement("err_code_des")]
public string err_code_des { get; set; }
[XmlElement("appid")]
public string appid { get; set; }
[XmlElement("mch_id")]
public string mch_id { get; set; }
[XmlElement("total_fee")]
public string total_fee { get; set; }
[XmlElement("out_trade_no")]
public string out_trade_no { get; set; }
[XmlElement("attach")]
public string attach { get; set; }
[XmlElement("time_end")]
public string time_end { get; set; }
}
[XmlRoot("xml")]
public class ReturnForWeixinNotify
{
/// <summary>
/// 返回码
/// </summary>
[XmlElement("return_code")]
public string return_code { get; set; }
/// <summary>
/// 返回信息
/// </summary>
[XmlElement("return_msg")]
public string return_msg { get; set; }
public static ReturnForWeixinNotify Fail(string code = "FAIL", string msg = "FAIL")
{
return new ReturnForWeixinNotify
{
return_code = code,
return_msg = msg
};
}
public static ReturnForWeixinNotify Success(string code = "SUCCESS", string msg = "OK")
{
return new ReturnForWeixinNotify
{
return_code = code,
return_msg = msg
};
}
}
public class ParamForDoQuery
{
/// <summary>
/// 外部交易号
/// </summary>
public string OutTradeNo { get; set; }
}
public class ReturnForWeixinQuery
{
/// <summary>
/// 外部交易号
/// </summary>
public string OutTradeNo { get; set; }
/// <summary>
/// 交易状态
/// </summary>
public bool TradeStatus { get; set; }
/// <summary>
/// 返回信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 总金额
/// </summary>
public double TotalFee { get; set; }
}
}
接下来就是支付宝,跟微信一样的逻辑。
public ActionResult ReturnToAlipay()
{
try
{
//订单id
var orderId = WebUtil.GetRequest<string>("orderId");
LogUtil.Info("调用支付宝支付接口"+ orderId);
var service = new PaymentService();
//查询用户信息
var orderResult = service.GetStudentRechargeOrderInfo(new ParamForGetOrderInfo()
{
OrderId = orderId,
UserId = WebUtil.GetUserId()
});
if (orderResult == null || !orderResult.Status)
{
LogUtil.Info("未找到该订单信息");
return Content("未找到该订单信息");
}
var order = orderResult.Data;//订单信息
LogUtil.Info("创建支付宝订单");
return CreateAlipayOrder(order);
}
}
catch (Exception e)
{
LogUtil.Error("异常:"+e.Message);
return Content(ResponseData<ResultForWeixinMpPayment>.Exception(MessageConstant.GetErrorMessage(e)).Message);
}
}
private ActionResult CreateAlipayOrder(ResultForGetStudentRechargeOrderInfo order)
{
order.Order.OrderTitle = "测试付款";
IAopClient client = new DefaultAopClient(
"https://openapi.alipay.com/gateway.do",//通知地址
ConfigurationManager.AppSettings["AlipayAppId"],//支付宝商户appid
ConfigurationManager.AppSettings["AlipayMerchantPrivateKey"],//支付宝密钥
"JSON",
"1.0",
"RSA2",
ConfigurationManager.AppSettings["AlipayAlipayPublicKey"],//支付宝公钥
"utf-8",
false
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.SetReturnUrl(ConfigurationManager.AppSettings["AlipaySuccessUrl"]);//同步通知支付成功的页面
request.SetNotifyUrl(ConfigurationManager.AppSettings["AlipayNotifyUrl"]);//异步请求回调接口
request.BizContent = "{" +
" \"out_trade_no\":\"" + order.OrderId + "\"," +
" \"total_amount\":\"" + order.Order.OrderAmount.ToString("F2") + "\"," +
" \"subject\":\"" + order.Order.OrderTitle + "\"," +
//" \"subject\":\" 测试付款 \"," +
" \"product_code\":\"QUICK_WAP_PAY\"" +
" }";//填充业务参数;
AlipayTradeWapPayResponse response = client.pageExecute(request);
LogUtil.Info("进入支付宝支付页面-"+"订单:"+order.OrderId+"");
return Content($@"
<html>
<head>
<style>
*{{width:0px;height:0px;border:0px;}}
</style>
</head>
<body>
{response.Body}
</body>
</html>
");
}
用户支付宝成功后接下来就是回调的接口。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Aop.Api.Util;
using Lib.Helper;
using Theia.Swd.H5Pay.Entities;
using Theia.Swd.H5Pay.Framework.Data;
using Theia.Swd.H5Pay.Models.Business.Payment.Enum;
using Theia.Swd.H5Pay.Models.Common.Enum;
using Theia.Swd.H5Pay.Notify.Models;
namespace Theia.Swd.H5Pay.Notify.Controllers
{
public class AlipayNotifyController : ApiController
{
protected System.Web.HttpRequest _request = System.Web.HttpContext.Current.Request;
public readonly string ServerUrl = "https://openapi.alipay.com/gateway.do";
public readonly string AppId = ConfigurationManager.AppSettings["AlipayAppId"]; //开发者的应用ID
public readonly string Format = "JSON";
public readonly string Charset = "utf-8";
public readonly string SignType = "RSA2"; //签名格式
public readonly string Version = "1.0";
public readonly string SuccessUrl = ConfigurationManager.AppSettings["AlipaySuccessUrl"];
public readonly string NotifyUrl = ConfigurationManager.AppSettings["AlipayNotifyUrl"];
//商户私钥
static string MerchantPrivateKey = ConfigurationManager.AppSettings["AlipayMerchantPrivateKey"];
//支付宝公钥
static string AlipayPublicKey = ConfigurationManager.AppSettings["AlipayAlipayPublicKey"];
private HttpResponseMessage ResponseMessage(string message)
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(message)
};
}
[HttpGet, HttpPost]
public HttpResponseMessage Notify()
{
LogUtil_1.Info("进入支付宝Notify");
SortedDictionary<string, string> sPara = GetRequestPost();//将post请求过来的参数传化为SortedDictionary
if (sPara.Count <= 0)
{
LogUtil_1.Info("无通知参数");
return ResponseMessage("无通知参数");
}
//AlipayTradeWayPayServer pay = new AlipayTradeWayPayServer();
var verifyerifyResult = Verify(sPara);//验签
if (!verifyerifyResult)
{
LogUtil_1.Info("fail");
return ResponseMessage("fail");
}
try
{
//商户订单号
var out_trade_no = _request.Form["out_trade_no"];
//支付宝交易号
var trade_no = _request.Form["trade_no"];
//支付金额
var total_amount = ConverterHelper.ConvertType<double>(_request.Form["total_amount"]);
//实收金额
//decimal receipt_amount = _request.Form["receipt_amount"].ConvertType(Decimal.Zero);
//交易状态
var trade_status = _request.Form["trade_status"];
//卖家支付宝账号
var seller_id = _request.Form["seller_id"];
//商品描述
var body = _request.Form["body"];
//交易创建时间
var gmt_create = DateTime.Parse(_request.Form["gmt_create"]);
//交易付款时间
var gmt_payment = DateTime.Parse(_request.Form["gmt_payment"]);
var appid = _request.Form["app_id"];
//WriteError("验证参数开始");
if (_request.Form["trade_status"] != "TRADE_SUCCESS")
{
//AlipayWayPayPO model = CreateAlipayWayPay(out_trade_no, trade_no, trade_status, gmt_create, gmt_payment);
//pay.PaySuccess(out_trade_no, model, Server.MapPath("~/" + DateTime.Today.ToString("yyMMdd") + ".txt"));//修改订单
//注意:
//付款完成后,支付宝系统发送该交易状态通知
LogUtil_1.Info("商户验证失败");
return ResponseMessage("商户验证失败");
}
var message = string.Empty;
if (!CheckToDb(out_trade_no, total_amount, seller_id, out message))
{
return ResponseMessage(message);
}
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
//_response.Write("success"); //请不要修改或删除
return ResponseMessage("success");
}
catch (Exception ex)
{
return ResponseMessage(ex.Message);
}
}
public bool CheckToDb(string orderId, double price, string sellerId, out string message)
{
try
{
using (var context = new DbContext())
{
var order = context.T_Order.FirstOrDefault(m => m.OrderID == orderId);
if (order == null)
{
message = "找不到订单";
LogUtil_1.Info(message);
return false;
}
if (order.OrderStatus == (int)OrderStatusEnum.Success)
{
message = "交易成功";
LogUtil_1.Info(message);
return true;
}
if (Math.Abs(order.OrderAmount - Convert.ToDecimal(price)) > 0.00m)
{
message = "金额不正确";
LogUtil_1.Info(message);
return false;
}
using (var trans = context.Database.BeginTransaction())
{
order.PaymentType = (int)PaymentTypeEnum.Alipay;//支付类型
order.OrderStatus = (int)OrderStatusEnum.Success;//支付状态
order.FinishedDate = DateTime.Now;//支付时间
context.T_Order.AddOrUpdate(order);//更新
context.SaveChanges();
trans.Commit();
}
}
}
message = string.Empty;
LogUtil_1.Info("支付宝支付成功");
return true;
}
catch (Exception e)
{
message = e.Message;
LogUtil_1.Info("支付宝支付异常"+message);
return false;
}
}
private SortedDictionary<string, string> GetRequestPost()
{
int i = 0;
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll;
coll = _request.Form;
String[] requestItem = coll.AllKeys;
for (i = 0; i < requestItem.Length; i++)
{
sArray.Add(requestItem[i], _request.Form[requestItem[i]]);
}
return sArray;
}
public Boolean Verify(SortedDictionary<string, string> inputPara)
{
Dictionary<string, string> sPara = new Dictionary<string, string>();
Boolean verifyResult = AlipaySignature.RSACheckV1(inputPara, AlipayPublicKey, Charset, SignType, false);
return verifyResult;
}
}
}