本文转自:
最近这几天很忙,一边忙着准备一堆课程设计(8门专业课.....伤不起...时间都是靠挤),一边还要党校培训....呃......顺便做了一下购物车,订单和支付宝简单的流程.
上次,曾经说到一个URL管理的问题,比如我们很多页面为了性能考虑生成静态页面,我们经常
性刚开始的时候用动态页面+ajax的方式加载,页面静态化的时候,如果是新闻内容页,我们可以
把静态页面的URL地址保存在数据库中,但是,单个页面,比如,首页,会员空间的各个页面,就不
适合放在数据库中,这时候更适合写一个通用模块类似MVC中的"控制器"来控制页面的静态化
和URL重写,这就省去了一个一个很繁琐的过程.
打个比方,我们可以写一个通用模块调用:
这种方式类似asp.net 中MVC的控制器,
函数大致的代码思路:
1: ///
2: /// 获得路径(暂时只做静态页面管理)(/*在这里可以扩展出URL重写*/)
3: ///
4: /// 页面的URL(不包括扩展名)
5: /// 页面参数
6: ///
7: public static string GetURL(string PageUrl,string QueryString)
8: {
9: //页面路径
10: string PagePath = "";
11:
12: //如果当前的参数不为空,则加上?
13: if (QueryString != "")
14: QueryString = "?" + QueryString;
15: //如果是静态页面(从配置文件中读取静态页面状态(是否))
16: if (ReadURLConfig(PageUrl) == true)
17: {
18: PagePath=PageUrl + ".htm" + QueryString;
19: }
20: //如果是动态页面
21: else
22: PagePath = PageUrl + ".aspx" + QueryString;
23: //把相对路径转化为绝对路径
24: return System.Web.VirtualPathUtility.ToAbsolute(PagePath); ;
25: }
26: ///
27: /// 从配置文件中读取是否生成静态页面
28: ///
29: /// 页面的名称
30: ///
31: public static bool ReadURLConfig(string PageName)
32: {
33: //读取配置文件
34: string path = HttpContext.Current.Server.MapPath(@"~/Admin/ConfigManage/URLConfig.xml");
35: //XmlHelper.Read(path, "/Node/Element[@Attribute='Name']", "Attribute")
36: //是否生成HTML
37: string IsHtml="false";
38: IsHtml=XMlHelper.Read(path, "/PageSettings/Page[@PageName='"+PageName+"']", "IsHtml");
39: if (IsHtml.ToLower() == "true")
40: {
41: return true;
42: }
43: else return false;
44:
45: }
配置文件属性:(URL重写部分,还没有实现)
我们可以在后台设置那些页面要生成HTML和URL重写规则的定制.......
不过貌似还有好多没实现,正在思考中............
进入主题:
这次,主要是购物车的实现,购物车的实现,我是在数据库建立了一个购物车的临时表,本来打算用Cookies做,不过,先用数据库做,比较稳妥,Cookies涉及安全性处理需要做很多处理.呃....这个以后可能会深入实现.
首先是,当用户点击
呃.....就ajax加入购物车,然后弹出层,显示
主要是ajax,先加入购物车(加入购物车之前,要检查购物车是否存在此商品,如果存在,本来应该
把购物车中商品的数量+1,我这里是直接提示用户已加入购物车,这是个小BUG),然后回调计
算购物车中的宝贝数量和总金额.
代码不太重要,这里就不粘贴了.
主要是思路要清晰一些.接下来就是购物车结算.
这个用了一个框架(改改颜色就上了,不过感觉加载了好多js,呃,....不过总比asp.net服务端控
件实现要好得多).
这个也就是增删改查设计,不过值得一提的就是,我们尽量把大量的前台js代码单独放在一个文
件中,这样客户端的缓存起来第二次访问起来就只需要更少的请求.
前台代码非常简洁:
1: <%@ Page Language="C#" MasterPageFile="~/Member.master" AutoEventWireup="true" CodeFile="ShopingCart.aspx.cs"
2: Inherits="Member_ShopingCart" Title="购物车" %>
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: type="text/css" />
14:
15:
16:
17:
18: .New_Button, .Edit_Button, .Delete_Button, .Update_Button, .Cancel_Button
19: {
20: font-size:11px;color:#1B3F91;font-family:Verdana;
21: margin-right:5px;
22: }
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41: 商品总价(不含运费):
42:
43: 元
44:
45:
46:
47:
48:
49: url="Data/GetMemberInfo.ashx?method=SearchShoppingCart" idfield="Id">
50:
51:
52:
53:
54:
55: 产品Id
56:
57: 图片
58:
59: 产品名称
60:
61: 供应商
62:
63: 商品售价
64:
65:
66: 购买数量
67:操作
68:
69:
70:
71:
72:
73:
74: <%-- --%> 批量删除
75:
76:
77:
78: 商品总价(不含运费):
79:
80:
81: 元
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99: mini.parse();
100:
101: var grid = mini.get("datagrid1");
102: grid.load({
103: key: "",
104: pageIndex: 0,
105: pageSize: 10,
106: sortField: "Id",
107: sortOrder: "asc"
108: })
109: //初始化
110: $(function(){
111: GetCartInfo();
112: });
113:
114:
115:
116:
关键性js文件:
1: //购物车汇总信息
2: function GetCartInfo(){
3: $.ajax({
4: url:"/Member/Data/GetMemberInfo.ashx?method=GetCartInfo",
5: type:"post",
6: success:function(text){
7: var DataJson=$.parseJSON(text);
8: if(DataJson.Status!='False')//执行成功!
9: {
10: //显示当前购物车总数量和总价
11: $("#lbCountNum").text(DataJson.Data[0].CartSum);
12: $("#lbCountNum1").text(DataJson.Data[0].CartSum);
13: //$("#CartMsg").html('目前购物车中已有'+DataJson.Data[0].CartCount+'件宝贝,合计:'+DataJson.Data[0].CartSum+'元');
14: }
15: else
16: alert("加载购物车汇总信息出错!");
17: }
18: });
19: }
20: //操作重绘
21: function onActionRenderer(e) {
22: var grid = e.sender;
23: var record = e.record;
24: var uid = record._uid;
25: var rowIndex = e.rowIndex;
26:
27: var s = ''
28: + ' 编辑'
29: + ' 删除';
30:
31: if (grid.isEditingRow(record)) {
32: s = '更新'
33: + '取消'
34: }
35: return s;
36: }
37:
38:
39: //产品名称超链接重绘
40: function onRenderProductName(e){
41: var record = e.record;
42: var uid = record._uid;
43: var rowIndex = e.rowIndex;
44: var row = grid.getRowByUID(uid);
45: var href=''+ row.ProductName+'';
46: return href;
47: }
48: //产品超链接重绘
49: function onRenderProduct(e){
50: var record = e.record;
51: var uid = record._uid;
52: var rowIndex = e.rowIndex;
53: var row = grid.getRowByUID(uid);
54: var href=''+ row.ProductId+'';
55: return href;
56:
57: }
58: //图片重绘
59: function onReaderPic(e){
60: var record = e.record;
61: var uid = record._uid;
62: var rowIndex = e.rowIndex;
63: var row = grid.getRowByUID(uid);
64: var src= '';
65: var href=''+ src+'';
66: return href;
67:
68: }
69: //卖家网址重绘
70: function RendererSupperlierName(e) {
71: var record = e.record;
72: var uid = record._uid;
73: var rowIndex = e.rowIndex;
74: var row = grid.getRowByUID(uid);
75: var SupperlierName=row.SupperlierName;
76: var SupperlierId=row.SupperlierId;
77: var BelongType=row.BelongType;
78: var BelongWebSize;
79: if(BelongType==0)
80: {
81: BelongWebSize="/Master/MasterInfo.aspx?MasterId="+SupperlierId;
82: }
83: else
84: BelongWebSize="/Company/CompanyInfo.aspx?CompanyId="+SupperlierId;
85: var s = ''+SupperlierName+'';
86:
87: return s;
88: }
89: function editRow(row_uid) {
90: var row = grid.getRowByUID(row_uid);
91: if (row) {
92: grid.cancelEdit();
93: grid.beginEditRow(row);
94: }
95: }
96: function cancelRow(row_uid) {
97: grid.reload();
98: }
99: function delRow(row_uid) {
100: var row = grid.getRowByUID(row_uid);
101: if (row) {
102: if (confirm("确定删除此记录?")) {
103: grid.loading("删除中,请稍后......");
104: $.ajax({
105: url: "Data/GetMemberInfo.ashx?method=RemoveShoppingCart&Id=" + row.Id,
106: success: function (text) {
107: grid.reload();
108: GetCartInfo();
109: },
110: error: function () {
111: }
112: });
113: }
114: }
115: }
116:
117: function updateRow(row_uid) {
118: var row = grid.getRowByUID(row_uid);
119:
120: var rowData = grid.getEditRowData(row);
121: if(parseInt(row.Num-row.Soldnum)
122: {
123: alert("当前库存不足!");
124: rowData.Quantity=parseInt(row.Num-row.Soldnum);
125: return;
126: }
127: grid.loading("保存中,请稍后......");
128: var json = mini.encode([{Id: row.Id,Quantity:rowData.Quantity,ProductId:row.ProductId}]);
129: $.ajax({
130: url: "Data/GetMemberInfo.ashx?method=SaveShoppingCart",
131: data: {ShoppingCart:json},
132: success: function (text) {
133: grid.reload();
134: GetCartInfo();
135: },
136: error: function (jqXHR, textStatus, errorThrown) {
137: alert(jqXHR.responseText);
138: }
139: });
140:
141: }
142: //批量删除
143: function remove(e) {
144: var rows = grid.getSelecteds();
145: if (rows.length > 0) {
146: if (confirm("确定删除选中商品?")) {
147: var ids = [];
148: for (var i = 0, l = rows.length; i < l; i++) {
149: var r = rows[i];
150: ids.push(r.Id);
151: }
152: var id = ids.join(',');
153: grid.loading("操作中,请稍后......");
154: $.ajax({
155: url: "Data/GetMemberInfo.ashx?method=RemoveShoppingCart&Id=" + id,
156: success: function (text) {
157: grid.reload();
158: GetCartInfo();
159: },
160: error: function () {
161: }
162: });
163: }
164: } else {
165: alert("请选中一条记录");
166: }
167: }
168: //操作重绘
169: function onSumRenderer(e) {
170: var grid = e.sender;
171: var record = e.record;
172: var uid = record._uid;
173: var rowIndex = e.rowIndex;
174: var row = grid.getRowByUID(uid);
175: return row.Price*row.Quantity;
176: }
不过注意的是,涉及到电子商务,客户端的数据都是不可靠的,所以我们的数据都是从数据库重
新读取.
后台c#处理代码:
1: ///
2: /// 购物车检索
3: ///
4: ///
5: public void SearchShoppingCart(HttpContext context)
6: {
7: //用户id
8: string UserId = SessionHelper.GetSession("UserId").ToString();
9: // string key = context.Request["key"];
10: //分页
11: int pageIndex = Convert.ToInt32(context.Request["pageIndex"]);
12: int pageSize = Convert.ToInt32(context.Request["pageSize"]);
13: //字段排序
14: String sortField = context.Request["sortField"];
15: String sortOrder = context.Request["sortOrder"];
16: string strCondition = "";
17: VCartProductInfoBLL bll = new VCartProductInfoBLL();
18: if (Tools.IsNullOrEmpty(sortField))
19: sortField = "Id";
20: //查询条件
21: strCondition = " MemberId=" + UserId;
22: //分页数据读取
23: IEnumerablelist = bll.ListByPagination(sortField, pageSize, pageIndex + 1, sortOrder == "asc" ? "1" : "0", strCondition);
24:
25: //获取总页数
26: int totalPage = bll.GetCount(strCondition);
27: //JSON 序列化
28: string json = Common.FormatToJson.MiniUiListToJson((IList )list, totalPage, "");
29: context.Response.Write(json);
30: }
31: ///
32: /// 保存到购物车
33: ///
34: ///
35: public void SaveShoppingCart(HttpContext context)
36: {
37: //数据读取
38: String Cart = context.Request["ShoppingCart"];
39: string info = Cart.TrimStart('[');
40: info = info.TrimEnd(']');
41: JObject o = JObject.Parse(info);
42: Int64 Id = (Int64)o.SelectToken("Id");
43: int Quantity = (int)o.SelectToken("Quantity");
44: Int64 ProductId = (Int64)o.SelectToken("ProductId");
45: //库存判断(从数据库读取库存检验)
46: product CartInfo = new productBLL().Get(ProductId);
47: if (Quantity > (int)(CartInfo.Num.Value - CartInfo.Soldnum.Value))
48: {
49: context.Response.Write(Tools.WriteJsonForReturn(false, "库存数量不足!"));
50: return;
51: }
52: //更新购物车
53: ShoppingCart Shop=new ShoppingCart ();
54: Shop.Id=Id;
55: Shop.Quantity=Quantity;
56: bool Status=false;
57: Status=new ShoppingCartBLL().UpdateShoppingCart(Shop);
58: string Msg="";
59: if (Status)
60: {
61: Msg = "";
62: }
63: else
64: Msg = "库存不足!";
65: context.Response.Write(Tools.WriteJsonForReturn(Status, Msg));
66:
67: }
68:
69: ///
70: /// 获取购物车信息
71: ///
72: ///
73: public void GetCartInfo(HttpContext context)
74: {
75: string UserId = (string)context.Session["UserId"];
76:
77: context.Response.Write(new ShoppingCartBLL().GetCartInfo(UserId));
78: }
79: ///
80: /// 删除购物车内容
81: ///
82: ///
83: public void RemoveShoppingCart(HttpContext context)
84: {
85: String idStr = context.Request["Id"];
86: if (String.IsNullOrEmpty(idStr)) return;
87: //检验客户端字符串
88: if (Common.Tools.IsValidInput(ref idStr, true))
89: {
90: new ShoppingCartBLL().DeleteMoreID(idStr);
91: }
92: }
接下来就是订单结算,
呃...订单很丑...没做处理.....
其实,这里面大部分信息都是以前做会员信息管理的数据加载,只需要调用会员管理的js,根本业务逻辑都不用写....
相对来说难写一点的就是提交订单的处理,
首先我们要提交订单,我的数据库,设计了订单表和订单商品表,订单号是根据日期生成的,订单号的生成就是类似流水号生成,
这个很重要,因为大多数情况下,订单是日期生成,而且要保证唯一性,以前曾经总看到(数据库的id不设计成自增,然后varchar类型,程序生成id号),
这种设计方式就是严重没考虑并发处理的情况,如果同时n个人订单号根本就不能保证唯一性...
到网上搜索流水号生成,就能看到如何解决这个问题,其实就是建一张表,写存储过程的方式计算id,要保证id的唯一性.
我的这个是从博客园一个高手的日志上切下来的..
获取订单号的存储过程
1: USE [czcraft]
2: GO
3: /****** 对象: StoredProcedure [dbo].[dpPMT_SGetMaintainSeq] 脚本日期: 05/19/2012 00:18:39 ******/
4: SET ANSI_NULLS ON
5: GO
6: SET QUOTED_IDENTIFIER ON
7: GO
8:
9: CREATE PROC [dbo].[dpPMT_SGetMaintainSeq]
10: (
11: @MaintainCate VARCHAR(2)
12: )
13: AS
14: --***********************累加编号*************************************************
15: declare @MaintainNo VARCHAR(12) IF NOT EXISTS(SELECT * FROM NumSeq WHERE Cate=@MaintainCate AND DATEDIFF(DAY,CrTime,GETDATE())=0) BEGIN
16: INSERT INTO NumSeq(Cate,DateNo,Seq,CrTime) values(@MaintainCate,RIGHT(CONVERT(VARCHAR(4),YEAR(GETDATE())),2)+ REPLICATE('0',2-LEN(MONTH(GETDATE())))+CONVERT(VARCHAR(2),MONTH(GETDATE())),0,getdate()) END
17: ELSE
18: BEGIN
19: UPDATE NumSeq SET Seq=Seq+1 WHERE Cate=@MaintainCate AND DateNo=RIGHT(CONVERT(VARCHAR(4),YEAR(GETDATE())),2)+ REPLICATE('0',2-LEN(MONTH(GETDATE())))+CONVERT(VARCHAR(2),MONTH(GETDATE())) END
20: --************************组合编号***************************************************************
21: SELECT @MaintainNo=Cate+DateNo+REPLICATE('0',6-LEN(Seq))+CONVERT(VARCHAR(6),Seq) FROM NumSeq WHERE Cate=@MaintainCate AND DateNo=RIGHT(CONVERT(VARCHAR(4),YEAR(GETDATE())),2)+ REPLICATE('0',2-LEN(MONTH(GETDATE())))+CONVERT(VARCHAR(2),MONTH(GETDATE())) SELECT @MaintainNo
调用函数
这样,我们每次插入数据的时候,只要调用这个存储过程就能保证每次生成的订单号都不一样,
接下来就是订单处理了:
我们需要处理哪些呢?
首先是提交用户的收货信息,再次检验库存状态,然后插入订单信息表和订单产品表,并且将商品表的产品数量更新,并且给用户发送订单邮件(我copy的卓越网邮件的HTML布局,哈哈),
这里粘贴主要模块代码:
提交订单:
1: ///
2: /// 订单提交
3: ///
4: ///
5: public void SubmitOrderData(HttpContext context)
6: {
7: string UserId = (string)context.Session["UserId"];
8: if(Tools.IsNullOrEmpty(UserId))
9: {
10: return;
11: }
12: string Name = context.Request["Name"];
13: string Email = context.Request["Email"];
14: string Province = context.Request["Province"];
15: string City = context.Request["City"];
16: string Country = context.Request["Country"];
17: string Address = context.Request["Address"];
18: string ZipCode = context.Request["ZipCode"];
19: string MobilePhone = context.Request["MobilePhone"];
20: string TelPhone = context.Request["TelPhone"];
21: //订单信息保存
22: orders order = new orders();
23: order.ConsigneeName = Name;
24: order.ConsigneeRealName = Name;
25: order.ConsigneeEmail = Email;
26: order.ConsigneeProvince = Province;
27: order.ConsigneeZip = ZipCode;
28: order.UserId =Convert.ToInt32(UserId);
29: order.ConsigneeAddress = City + Country + Address;
30: order.OrderDate = DateTime.Now;
31: order.ConsigneePhone = MobilePhone;
32: order.ConsigneeTel = TelPhone;
33: order.OrderId = ordersBLL.GetOrderId();
34: ordersBLL bll = new ordersBLL();
35: string ReturnProductName = "";
36: //下单
37: bool Status = bll.SaveOrder(ref order, out ReturnProductName);
38: //去除最后的,
39: ReturnProductName = ReturnProductName.Remove(ReturnProductName.Length - 1, 1);
40: string Data = "";
41: //支付跳转URL
42: string TurnURL = "";
43: if (Status)
44: {
45: Data = "恭喜您!下单成功!";
46: //支付平台的跳转URL生成
47: PayInfo info=new PayInfo ();
48: info.SaleEmail="tianzhuanghu@qq.com";
49: info.OrderId=order.OrderId;
50: info.ProductName = ReturnProductName;
51:
52: info.Remark=order.ConsigneeName+"在"+order.ShopDate.Value.ToShortDateString()+"购买商品,共计:"+order.TotalPrice.Value.ToString ();
53: info.TotalFre = order.FactPrice.Value.ToString ();
54: Pay pay = new Pay();
55: TurnURL=pay.BuildURL(info);
56: }
57: else
58: Data = "对不起!下单失败!";
59: //返回的json数据
60: string ReturnJson = "{\"Status\":\"" + Status + "\",\"Data\":\"" + Data + "\",\"URL\":\""+TurnURL+"\"}"; ;
61: context.Response.Write(ReturnJson);
62:
63: }
1: #region 保存订单
2: ///
3: /// 保存订单
4: ///
5: /// 订单
6: /// 返回产品名称列表
7: ///
8: public bool SaveOrder(ref orders order,out string ReturnProductNames)
9: {
10: ReturnProductNames = "";
11: //查询条件(购物车视图中查询)
12: string Condition = " MemberId=" + order.UserId;
13: //(需要读取购物车,然后,插入订单商品表和订单表)
14: //订单产品信息列表
15: ListlistOrder = new List ();
16: IEnumerableCartProducts = new VCartProductInfoDAL().ListAll(Condition);
17: order.TotalPrice = 0.0;
18: order.FactPrice = 0.0;
19: foreach (VCartProductInfo CartProduct in CartProducts)
20: {
21: orderproduct OrderProduct = new orderproduct();
22: OrderProduct.AddTime = DateTime.Now;
23: OrderProduct.OrderId = order.OrderId;
24: OrderProduct.ProId = CartProduct.ProductId.Value.ToString();
25: OrderProduct.ProImg = CartProduct.Picturepath;
26: OrderProduct.ProName = CartProduct.ProductName;
27: ReturnProductNames += OrderProduct.ProName + ",";
28: OrderProduct.ProNum = CartProduct.Quantity;
29: OrderProduct.ProPrice = CartProduct.Price;
30: OrderProduct.ProOtherPara = "";
31: OrderProduct.Remark = "";
32: OrderProduct.Specification = "";
33: //加入到产品订单信息列表中
34: listOrder.Add(OrderProduct);
35: //总价计算
36: order.TotalPrice += OrderProduct.ProPrice.Value * OrderProduct.ProNum.Value;
37: //实际总价
38: order.FactPrice += OrderProduct.ProPrice.Value * OrderProduct.ProNum.Value;
39: }
40: //支付状态为等待付款
41: order.PaymentStatus = orders.ePaymentStatus.WaitPay.GetHashCode().ToString();
42: //订单状态为未支付
43: order.OrderStatus = orders.eOrderStatus.NotPay.GetHashCode().ToString();
44:
45: //订单状态
46: order.IsOrderNormal = 0;
47: order.Remark = "";
48: order.ShopDate = DateTime.Now;
49: order.OrderDate = DateTime.Now;
50: //返回订单执行状态
51: bool Status = new ordersDAL().AddOrders(order, listOrder);
52: if (Status)
53: {
54: //给客户发邮件
55: SMTP smtp = new SMTP(order.ConsigneeEmail);
56: smtp.SendMail("潮州工艺平台", SendToCustomContentHtml(order, listOrder));
57:
58: }
59: return Status;
60:
61: }
发送邮件:
1: #region 生成给客户发的HTML内容(亚马逊布局)
2: ///
3: /// 生成给客户发的HTML内容(亚马逊)
4: ///
5: ///
6: ///
7: ///
8: public string SendToCustomContentHtml(orders order, IEnumerableProductsList)
9: {
10: //获取当前http上下文
11: System.Web.HttpContext context = System.Web.HttpContext.Current;
12: //主页
13: string Default = context.Request.Url.Scheme + "://" + context.Request.Url.Authority + System.Web.VirtualPathUtility.ToAbsolute("~/Default.aspx");
14: //会员订单网址
15: string webpath = context.Request.Url.Scheme + "://" + context.Request.Url.Authority + System.Web.VirtualPathUtility.ToAbsolute("~/Member/MemberOrders.aspx");
16: //文件流读取
17: StringBuilder sb=new StringBuilder ();
18: sb.Append(File.ReadAllText (context.Server.MapPath("~/Other/SendToCustomContent.html"),Encoding.UTF8));
19: sb.Replace("$ConsigneeRealName", order.ConsigneeRealName);
20: sb.Replace("$ConsigneeEmail", order.ConsigneeEmail);
21: sb.Replace("$ConsigneeRealName", order.ConsigneeRealName);
22: sb.Replace("$ConsigneeAddress", order.ConsigneeAddress);
23: sb.Replace("$ConsigneeProvince", order.ConsigneeProvince);
24: sb.Replace("$ConsigneeZip", order.ConsigneeZip);
25: sb.Replace("$TotalPrice", order.TotalPrice.Value.ToString ());
26: sb.Replace("$webpath", webpath);
27: sb.Replace("$OrderId", order.OrderId);
28: sb.Replace("$TotalPrice", order.TotalPrice.Value.ToString ());
29: sb.Replace("$Carriage", order.Carriage.ToString ());//
30: sb.Replace("$TotalPrice", order.TotalPrice.Value.ToString ());
31: sb.Replace("$FactPrice", order.FactPrice.Value.ToString ());
32: sb.Replace("$DateTime", DateTime.Now.AddDays(3).ToShortDateString());
33:
34: //商品内容生成
35: int num = 0;
36: StringBuilder TempData = new StringBuilder();
37: foreach (orderproduct Product in ProductsList)
38: {
39: string temp3 = @"
40: " + (++num) + @"" + Product.ProName + @"
41: ¥ " + Product.ProPrice + @"现在有货 卖家: 潮州工艺品集团 ";
42: TempData.Append(temp3);
43:
44:
45: }
46: //商品主体信息替换
47: sb.Replace("$Body", TempData.ToString ());
48: //sb.Replace("$Carriage", order.Carriage);
49:
50:
51:
52: return sb.ToString();
53:
54: }
DAL中保存订单处理:
1: #region 下单
2: ///
3: /// 下单
4: ///
5: /// 订单信息
6: /// 订单产品信息
7: ///
8: public bool AddOrders(orders order, IEnumerableOrderProductsList)
9: {
10: //执行事务状态
11: bool Status = false;
12: StringBuilder sb = new StringBuilder();
13: SqlHelper.Open();
14: //开始事务
15: SqlHelper.BeginTrans();
16: foreach (orderproduct product in OrderProductsList)
17: {
18: //插入订单产品表信息
19: sb.AppendFormat("insert into orderproduct(OrderId,ProId,ProClass,ProName,ProImg,ProPrice,ProNum,AddTime,ProOtherPara,Specification,Remark) output inserted.Id values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}');", product.OrderId, product.ProId, product.ProClass, product.ProName, product.ProImg, product.ProPrice, product.ProNum, product.AddTime, product.ProOtherPara, product.Specification, product.Remark);
20: //产品数量修改
21: sb.AppendFormat("update product set Num=Num-{0},Soldnum=Soldnum+{0} where Id={1};", product.ProNum, product.ProId);
22: //删除购物车中的产品
23: sb.AppendFormat("delete from ShoppingCart where ProductId={0} and MemberId={1};", product.ProId, order.UserId);
24:
25: }
26: //订单信息添加
27: sb.AppendFormat("insert into orders(OrderId,UserId,ShopDate,OrderDate,ConsigneeRealName,ConsigneeName,ConsigneePhone,ConsigneeProvince,ConsigneeAddress,ConsigneeZip,ConsigneeTel,ConsigneeEmail,TotalPrice,FactPrice,Remark,OrderStatus,PaymentStatus,IsOrderNormal) values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}','{11}','{12}','{13}','{14}','{15}','{16}','{17}');", order.OrderId, order.UserId, order.ShopDate, order.OrderDate, order.ConsigneeRealName, order.ConsigneeName, order.ConsigneePhone, order.ConsigneeProvince, order.ConsigneeAddress, order.ConsigneeZip, order.ConsigneeTel, order.ConsigneeEmail, order.TotalPrice, order.FactPrice, order.Remark, order.OrderStatus, order.PaymentStatus, order.IsOrderNormal);
28: Status = SqlHelper.ExecuteNonQuery(sb.ToString());
29: if (Status)
30: {
31: SqlHelper.CommitTrans();
32: return true;
33: }
34: else
35: {
36: SqlHelper.RollbackTrans();
37: return false;
38: }
39:
40:
41: }
在这里,为了更节省性能,我用StringBuilder拼接字符串,也没有用参数化查询的方式.(注意这里采用事务处理)
然后就是支付平台的实现,其实支付平台说简单点是非常容易的,只需要按照支付的接口提供http请求参数,数字签名,等信息,交易成功然后按照请求读取参数检验数字签名是否正确.
这部分内容,我是准备集成多种支付平台设计,今天只展示支付宝部分.
在设计这部分,我们需要去查看支付宝接口模拟,一般申请支付宝都会提供一个接口测试程序,等等,
我们在做之前,为了考虑多种支付平台的配置,首先定义一些配置信息,
我是把支付宝接口配置成一个网站,然后,通过网关调用,进行模拟
1: using System;
2: using System.Data;
3: using System.Configuration;
4: using System.Linq;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.HtmlControls;
9: using System.Web.UI.WebControls;
10: using System.Web.UI.WebControls.WebParts;
11: using System.Xml.Linq;
12:
13: ///
14: ///PayInfo 的摘要说明
15: ///
16: public class PayInfo
17: {
18: public PayInfo()
19: {
20: //
21: //TODO: 在此处添加构造函数逻辑
22: //
23: }
24: ///
25: /// 商户
26: ///
27: public string SaleManId { get; set; }
28: ///
29: /// 回调地址
30: ///
31: public string CallBackUrl { get; set; }
32: ///
33: /// 产品名称
34: ///
35: public string ProductName { get; set; }
36:
37: ///
38: /// 订单号
39: ///
40: public string OrderId { get; set; }
41: ///
42: /// 总金额
43: ///
44: public string TotalFre { get; set; }
45: ///
46: /// 卖家邮箱
47: ///
48: public string SaleEmail { get; set; }
49: ///
50: /// 数字签名
51: ///
52: public string Sign { get; set; }
53: ///
54: /// 备注信息
55: ///
56: public string Remark { get; set; }
57:
58: }
59: ///
60: /// 支付回调信息
61: ///
62: public class PayCallBackInfo
63: {
64: ///
65: /// 支付类型
66: ///
67: public Pay.PayType PayType { get; set; }
68: ///
69: /// 订单号
70: ///
71: public string OrderId { get; set; }
72: ///
73: /// 支付机构
74: ///
75: public string PayMode { get; set; }
76: ///
77: /// 支付金额
78: ///
79: public string PayFre { get; set; }
80: ///
81: /// 金额币种
82: ///
83: public string MoneyType { get; set; }
84: ///
85: /// 备注1
86: ///
87: public string Remark1 { get; set; }
88: ///
89: /// 备注2
90: ///
91: public string Remark2 { get; set; }
92: ///
93: /// 数字签名
94: ///
95: public string Sign { get; set; }
96: ///
97: /// 状态码
98: ///
99: public Pay.ReturnCode ReturnCode { get; set; }
100: ///
101: /// 回发的消息
102: ///
103: public string Msg { get; set; }
104: }
105: ///
106: /// 支付配置信息
107: ///
108: public class PayConfig
109: {
110: ///
111: /// 支付类型
112: ///
113: public Pay.PayType PayType { get; set; }
114: ///
115: /// 商户帐号
116: ///
117: public string v_mid { get; set; }
118: ///
119: /// 商户密码
120: ///
121: public string v_pwd { get; set; }
122: ///
123: /// 网关地址
124: ///
125: public string PayUrl { get; set; }
126: }
1: using System;
2: using System.Data;
3: using System.Configuration;
4: using System.Linq;
5: using System.Web;
6: using System.Web.Security;
7: using System.Web.UI;
8: using System.Web.UI.HtmlControls;
9: using System.Web.UI.WebControls;
10: using System.Web.UI.WebControls.WebParts;
11: using System.Xml.Linq;
12: using Common;
13: using czcraft.BLL;
14:
15: ///
16: ///Pay 的摘要说明
17: ///
18: public class Pay
19: {
20: //支付平台的配置信息
21: public readonly PayConfig config;
22: public Pay()
23: {
24: //获取支付平台的配置信息
25: config = GetPayConfig();
26: //
27: //TODO: 在此处添加构造函数逻辑
28: //
29: }
30: ///
31: /// 支付类型
32: ///
33: public enum PayType
34: {
35: ///
36: /// 支付宝
37: ///
38: Alipay = 0,
39: ///
40: /// 网银在线
41: ///
42: ChinaBank = 1
43: }
44: ///
45: /// 回调状态码(支付宝才有)
46: ///
47: public enum ReturnCode
48: {
49: ///
50: /// 支付成功!
51: ///
52: ok = 0,
53: ///
54: /// 支付失败!
55: ///
56: error = 1
57: }
58:
59: #region 构造支付的URL
60: ///
61: /// 构造支付的URL(从配置文件中读取出支付平台配置信息然后构造支付的网关信息(支付平台由配置文件决定)(初步只提供网银在线和支付宝两种模式中的一种)
62: ///
63: /// 支付信息(支付宝支付需要输入总金额,产品名称,订单号,卖家邮箱)
64: ///
65: public string BuildURL(PayInfo Info)
66: {
67: //获取支付平台的配置信息
68: //PayConfig config = GetPayConfig();
69: //支付的地址
70: string PayUrl = "";
71: switch (config.PayType)
72: {
73: //支付宝支付
74: case PayType.Alipay:
75: PayUrl = BuildAlipayURL(Info, config);
76: break;
77: //网银在线支付
78: case PayType.ChinaBank:
79: PayUrl = BuildChinaBackUrl(Info, config);
80: break;
81: default:
82: PayUrl= "#";
83: break;
84: }
85: return PayUrl;
86: }
87: #endregion
88:
89: #region 支付完成回调处理
90: ///
91: /// 支付完成回调处理
92: ///
93: /// 回调信息
94: ///
95: public PayCallBackInfo CallBackPayInfo()
96: {
97: string Msg = "";
98: PayCallBackInfo CallBackInfo = new PayCallBackInfo();
99: switch (config.PayType)
100: {
101: //支付宝支付
102: case PayType.Alipay:
103: CallBackInfo = CallBackAlipayInfo();
104: break;
105: //网银在线支付
106: case PayType.ChinaBank:
107: CallBackInfo = CallBackChinaBankInfo();
108: break;
109: default:
110: CallBackInfo = null;
111: break;
112: }
113: return CallBackInfo;
114: }
115: #region 支付宝支付完成回调处理
116: ///
117: /// 支付宝支付完成回调处理
118: ///
119: /// 回调信息
120: ///
121: private PayCallBackInfo CallBackAlipayInfo()
122: {
123: //回调信息
124: string Msg = "";
125: System.Web.HttpContext context = System.Web.HttpContext.Current;
126: //订单号
127: string OrderId = context.Request["out_trade_no"];
128: //回调状态码
129: string ReturnCode = context.Request["returncode"];
130: //总金额
131: string TotalFre = context.Request["total_fee"];
132: //数字签名
133: string Sign = context.Request["sign"];
134: //数字签名(本地计算的)
135: string Md5Sign = CommonHelper.GetMD5(OrderId + ReturnCode + TotalFre + config.v_pwd);
136: //回调信息
137: PayCallBackInfo CallBackInfo = new PayCallBackInfo();
138: if (Md5Sign.Equals(Sign))
139: {
140: //支付成功!
141: if (ReturnCode.Equals(Pay.ReturnCode.ok.ToString()))
142: {
143: Msg = "支付成功!";
144: CallBackInfo.Msg = Msg;
145: CallBackInfo.OrderId = OrderId;
146: CallBackInfo.PayFre = TotalFre;
147: CallBackInfo.ReturnCode = Pay.ReturnCode.ok;
148: }
149: else
150: {
151: Msg = "支付失败!";
152:
153: CallBackInfo.Msg = Msg;
154: CallBackInfo.ReturnCode = Pay.ReturnCode.error;
155: }
156:
157: }
158: else
159: {
160: Msg = "数据被篡改!";
161: CallBackInfo.Msg = Msg;
162: CallBackInfo.ReturnCode = Pay.ReturnCode.error;
163: }
164: return CallBackInfo;
165: }
166: #endregion
167: #region 网银在线支付完成回调处理
168: ///
169: /// 网银在线支付完成回调处理(未实现)
170: ///
171: /// 回调信息
172: ///
173: private PayCallBackInfo CallBackChinaBankInfo()
174: {
175: //回调信息
176: string Msg = "";
177: PayCallBackInfo CallBackInfo = new PayCallBackInfo();
178: return CallBackInfo;
179: }
180: #endregion
181: #endregion
182: #region 支付宝平台的网关URL
183: ///
184: /// 支付宝平台的网关URL
185: ///
186: /// 支付信息
187: /// 系统支付配置
188: ///
189: private string BuildAlipayURL(PayInfo info, PayConfig config)
190: {
191: System.Web.HttpContext context = System.Web.HttpContext.Current;
192: //为按顺序连接 总金额、 商户编号、订单号、商品名称、商户密钥的MD5值。
193: //支付宝数字签名
194: string SignMd5 = CommonHelper.GetMD5(info.TotalFre + config.v_mid + info.OrderId + info.ProductName + config.v_pwd);
195: //回调网址
196: string webpath = context.Server.UrlEncode(context.Request.Url.Scheme + "://" + context.Request.Url.Authority + System.Web.VirtualPathUtility.ToAbsolute("~/Member/Data/DealAlipayCallBack.ashx"));
197: //商品名称
198: string ProductName = System.Web.HttpContext.Current.Server.UrlEncode(info.ProductName);
199: //备注
200: string Remark = System.Web.HttpContext.Current.Server.UrlEncode(info.Remark);
201: //支付的URL地址
202: string PayURL = config.PayUrl + "?partner=" + config.v_mid + "&return_url=" + webpath + "&subject=" + ProductName + "&body=" + Remark + "&out_trade_no=" + info.OrderId + "&total_fee=" + info.TotalFre + "&seller_email=" + info.SaleEmail + "&sign=" + SignMd5;
203: return PayURL;
204:
205: }
206: #endregion
207:
208: #region 网银在线平台的网关URL
209: ///
210: /// 网银在线平台的网关URL(等待实现)
211: ///
212: /// 支付信息
213: /// 系统支付配置
214: ///
215: private string BuildChinaBackUrl(PayInfo info, PayConfig config)
216: {
217: return "";
218:
219: }
220: #endregion
221:
222: #region 获取系统配置信息(支付相关)
223: ///
224: /// 获取系统配置信息(支付相关)
225: ///
226: ///
227: public PayConfig GetPayConfig()
228: {
229: PayConfig info = new PayConfig();
230: //读取配置文件信息
231: string path = System.Web.HttpContext.Current.Server.MapPath(@"~/Admin/ConfigManage/config.xml");
232: //系统配置中的支付类型
233: string ConfigPayType = XMlHelper.Read(path, "/Root/Pay", "PayType");
234: //商户帐号
235: string v_mid = XMlHelper.Read(path, "/Root/Pay/" + ConfigPayType, "v_mid");
236: //商户密码
237: string v_pwd = XMlHelper.Read(path, "/Root/Pay/" + ConfigPayType, "v_pwd");
238: //支付网关
239: string PayUrl = XMlHelper.Read(path, "/Root/Pay/" + ConfigPayType + "/PayUrl", "");
240:
241:
242: info.PayType = ConfigPayType == PayType.Alipay.ToString() ? PayType.Alipay : PayType.ChinaBank;
243: info.v_mid = v_mid;
244: info.v_pwd = v_pwd;
245: info.PayUrl = PayUrl;
246:
247: return info;
248:
249: }
250: #endregion
251:
252: }
然后支付回调处理:
1: <%@ WebHandler Language="C#" Class="DealAlipayCallBack" %>
2:
3: using System;
4: using System.Web;
5: //处理关于支付宝回调
6: public class DealAlipayCallBack : IHttpHandler {
7:
8: public void ProcessRequest (HttpContext context) {
9: //支付回调
10: Pay pay = new Pay();
11: PayCallBackInfo CallBackInfo = pay.CallBackPayInfo();
12: if (CallBackInfo.ReturnCode == Pay.ReturnCode.ok)
13: {
14: CallBackInfo.Msg = "恭喜您,支付成功!我们会尽快发货!如果您收货就可以继续确认收货!";
15: }
16: else
17: CallBackInfo.Msg = "对不起,支付失败!!失败信息 :" + CallBackInfo.Msg + "请联系支付宝有关人员!";
18: //回调信息
19: string Msg = System.Web.HttpContext.Current.Server.UrlEncode(CallBackInfo.Msg);
20: Common.JScript.JavaScriptLocationHref("../PayCallBack.aspx?ReturnCode=" + CallBackInfo.ReturnCode.ToString() + "&Msg=" + Msg + "&OrderId=" + CallBackInfo.OrderId + "&PayFre=" + CallBackInfo.PayFre);
21: }
22:
23: public bool IsReusable {
24: get {
25: return false;
26: }
27: }
28:
29: }
回调前台页面:
1: <%@ Page Language="C#" MasterPageFile="~/Member.master" AutoEventWireup="true" CodeFile="PayCallBack.aspx.cs"
2: Inherits="Member_PayCallBack" Title="支付回调" %>
3:
4:
5:
6:
7:
8:
9:
10:
11: .MoneyFont
12: {
13: font-family:Verdana, Geneva, sans-serif;
14: font-size:18px;
15: font-weight:bold;
16: color:#F60;
17: }
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38: 支付宝首页|
39: href="https://b.alipay.com/home.htm">商家服务|
40: 帮助中心
41:
42: 支付宝纯担保交易付款快速通道
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62: ¥:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73: style="text-align: center" />
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87: //获得回调过来的信息
88: $(function(){
89: var ReturnCode=$.query.get("ReturnCode");
90: var Msg=$.query.get("Msg");
91: var OrderId=$.query.get("OrderId");
92: var PayFre=$.query.get("PayFre");
93: if(ReturnCode=="ok")
94: $("#Msg").text("恭喜您,支付成功!我们会尽快发货!如果您收货就可以继续确认收货!");
95: else
96: $("#Msg").text("对不起,支付失败!!失败信息 :"+Msg+"请联系支付宝有关人员!");
97: $("#OrderId").text(OrderId);
98: $("#PayFre").text(PayFre);
99: });
100:
101:
102:
103:
程序截图:
效果图就是这样子