LinQ动态排序
首先修复程序中的一个BUG这个BUG在GridPager类中,把sord修改为sort这个名称填写错误,会导致后台一直无法获取datagrid的排序字段
本来是没有这一讲的,为了使20行的代码精简成2行,我查阅了一些资料,借鉴了一些大神的建议,首先感谢第八讲中,11楼@nyth和15楼@红颜醉丶帝的建议投递,每一次的的排序要都一个判断这的确很麻烦,我们利用反射来解决这个问题。
先看原来的代码
//排序
if (pager.order == "desc")
{
switch (pager.order)
{
case "CreateTime":
queryData = queryData.OrderByDescending(c => c.CreateTime);
break;
case "Name":
queryData = queryData.OrderByDescending(c => c.Name);
break;
default:
queryData = queryData.OrderByDescending(c => c.CreateTime);
break;
}
}
else
{ switch (pager.order)
{
case "CreateTime":
queryData = queryData.OrderBy(c => c.CreateTime);
break;
case "Name":
queryData = queryData.OrderBy(c => c.Name);
break;
default:
queryData = queryData.OrderBy(c => c.CreateTime);
break;
}
}
以上每一次排序都要进行判断,利用反射可以解决这个问题,我把他封装起来了。(需要对反射有一些理解)
在App.Common中新建LinqHelper类代码如下(下面有3个方法,我都对方法进行了注释,看下就明白)
我们对Sorting的代码分析如下:
ParameterExpression param = Expression.Parameter(typeof(T), sortExpression);
我们们传入的类型中找出我们需要进行排序的字段。
PropertyInfo pi = typeof(T).GetProperty(sortExpression);
取出要排序字段的相关属性
Type[] types = new Type[2];
types[0] = typeof(T); 获得要进行排序的数据集的类型。
types[1] = pi.PropertyType; 取出我们把什么类型的字段进行排序(即传入参数的值类型)
Expression expr = Expression.Call(typeof(Queryable), sortingDir, types, source.Expression, Expression.Lambda(Expression.Property(param, sortExpression), param));
生成排序表达式
IQueryable<T> query = source.AsQueryable().Provider.CreateQuery<T>(expr);
执行排序
现在我们修改一下SysSample的BLL层
将以上的代码修改为
queryData = LinqHelper.DataSorting(queryData,pager.sort,pager.order);
我们的代码顿时精简成了一行,赞一个吧。
出处:http://ymnets.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
YY一下微信线下支付的场景
在上一篇文章里面提到了 《跨行清算的实现原理》,这次来分析一下线下支付的场景和流程。
今天看到一篇文章:http://www.huxiu.com/article/23248/1.html?f=chouti 银泰和支付宝线下合作,推广支付宝当面付款的功能
其实仔细分析一下,觉得当面付这个功能说实在的,对消费者来说,并没有太大的优势,主要表现在以下几点:
1 当面付的资金要么从支付宝余额支付,要么从关联的快捷银行卡支付。对于大多数用户来说,直接使用信用卡支付即可,为什么要经过支付宝钱包绕一圈,人为增加了一道手续。
2 线下支付最重要的是支付效率,从个人经验来看,银行卡的支付效率是除现金之外,目前线下支付场景中最快的。耍一下,签个字即可。对于银泰这种大卖场,支付效率最为重要,否则排队的人不耐烦不想买了,最终损失的银行。从当面付的流程来看,先淘出手机,解锁,选择支付宝钱包,在解锁,选择到制定的页面,对准声波发生器,如果一切顺利的话,自然还好,如果不顺利的话,急死你。整个过程要保证柜台网络畅通。我自己体验过,必须网络信号好,手机别套套子,外部环境安静的情况下,支付成功率比较高。
不过支付宝当面付对于卖场来说,是有一些优势的,主要是费率,银联卡的费率比较高,如果支付宝当面付的费率很低的话,商户可以节约很大一部分成本。但是核心问题不是卖家而是买家是否愿意使用。从支付宝的定位来看,主要是解决支付的问题,那么线下购物是否可以采用类似网上购物的模式,构成一个闭环。自己分析了一下,觉得还是可行的。
线下支付购物的场景
1 每当你去大商场买东西的时候,开始的时候发现一个商品,比如裤子比较合身,但是你想看看后面还有更好的,如果没有发现更适合的,你只能重新来到这家店在来买这一件裤子。那能不能和线上购物一样,先保存订单,等全部看完之后,在确定是否需要
2 在大商场举办打折活动的时候,购买的人非常多,你必须要一点点在柜台前面排队,等待支付。这个过程是同步,必须等待前一个人支付完成之后,后面在支付。而且整个过程你必须排队,一离开就只能重新再排了,如果这个时候你肚子难受,不就郁闷死。
从上面的线下购物两个场景来看,其实和线上购物比较类似的,在网络上购物,首先是选择商品,然后下单,进入购物车,在对购物车的订单进行确认,进入了收银台,然后支付,在等待收货即可。简化一下线上购物流程:挑选商品——>下单——>在购物车确认订单——>进入收银台——>支付订单——>等待收货。
类比线上购物,线下是否也可以做成和线上一样了,其实仔细分析一下,两者有着很大的共同点,拿微信举例(淘宝也是可以的,鉴于微信最近比较火,选择微信做例子而已,只要是移动客户端都可以),下面是一个简单的订单支付流程:
线下购物流程
下单流程:通过二维码作为中介,订单推送到微信的购物车,微信先把订单保存到本地,你就可以先把订单保存下来,至于卖不卖,可以等到后面在做决定
确认订单:等用户确认了哪些商品确实需要,那么就可以进行订单确认。在这个时候,订单才推送到财付通(可以是腾讯的一个内部系统),财付通在通知卖场的信息管理管理系统
进入收银台:用户确定订单之后,到收银台进行支付,选择微信支付,支付成功之后通知卖场,卖场修改订单状态,确认订单已经付款。
在整个订单支付的过程,完全不需要依赖卖场的柜面,而且是异步进行的,不用排队。你可以一边吃饭,一边完成整个订单的支付过程。
这里面要解决一个问题:如何知道订单是属于哪个卖场的和属于卖场的那个具体店铺的?
解决方案1:
在二维码上做文章,生成一个二维码,这里面包含了卖场,店铺,价格等信息,那这就是线下商铺进入卖场,必须登陆卖场的管理系统,自己生成二维码,然后自己在贴到自己的店铺上,让用户扫。
解决方案2:
卖场在微信上开一个公共账号,用户关注公共账号,并输入一个商品ID,公共账号返回商品二维码,系统自动扫描进入购物车。这个ID是卖场的管理系统为商品生成的一个ID。
显然第二种对于卖场来说是比较合理的,对用户来说也是方便的,卖场获取了用户的信息,用户操作也比较方便,但是必须依赖卖场。
线下收货流程
线下购物和线上购物在收货环节也不同,主要体现在,线下可以直接取货。这就需要支付凭证,更重要的是要有发票。支付凭证其实还好处理,微信本身就保存有,主要是发票。这个必须由卖场或者商铺来出具。我在苏宁买电器的时候,貌似是苏宁出具发票,具体的厂家出具保修服务。那么获取发票的流程,其实必须到柜台索要,这个是整个过程中唯一需要到柜台排队的环节。
这里其实卖场可以优化的环节为:柜台发票和支付分离开的话,对于使用微信支付,直接到获取发票的柜台排队,对于刷卡或者现金支付的,到传统的柜台排队。这个效率也是比较明显。其实可以再想象一下,如果未来有电子发票或者自主打印机发票。那么整个购物环节其实完全和线下实体的柜面脱离。对于用户来说,效率非常高。我在苏宁实体店买过东西,跑上跑下的,那个过程对于一个懒人来说实在是觉得麻烦。
其实从整个线下的购物过程来看,其实和线上非常类似,但是淘宝系的优势在线下无法体验。对于传统卖场来说,线下支付并不重要,重要的还是购物者的体验以及营销的渠道。接入淘宝对他们来说并没有太大的优势,因为我都来到你卖场这里了,干嘛还要去网上买,上网主要是为了比价。但是微信和淘宝不同的是在于他的渠道价值,这个是线下商户最为看重的,关注过公共平台账号的微信用户体验会非常深,如果你喜欢和星巴克,你去关注星巴克,那么星巴克有什么新品和促销信息,你自然很在意,而星巴克也希望把这些信息通知到消费者,这对于消费者和商户来说是双赢的。比如我就关注了招商微信的公共账户,一个是作为信息提醒,另外一个是像知道最近那些商户刷卡有积分赚等等。为什么是微信,因为他是手机端使用最为频繁的应用,据说已经占领了中国广大的农村。
GodIsCoder
采集博客园文章,用瀑布流+无限滚动展示(附源码)
一 前言
前段时间一直在了解关于Http相关的知识,然后园子里时不时有园友发关于采集网页信息的文章,然后自己也想试试如何做网页的数据采集,便开始在网找查找相关资料,
方法有很多种,如 用开源的框架忘了叫什么名了,或者用.net Framework自带的HttpwebRequest对象与HttpwebResponse对象,当然也还有其它对象也可以做到如 WebClient 等,而我选择用HttpwebRequest 与HttpWebResponse来处理。
经过几个晚上的不断折腾终于把这东西折腾出来了,我的定位就只是用来练手所以不免会有BUG,这个小工具有两个BUG 一个在无限滚动这里,都以经按插件的参数配置了,可它就是不听使唤,老是会自动触发加载事件,不得以我来个限定最多只加载10页的数据。如果有熟悉这个插件的朋友,下载源码后帮忙修改下,我拿它真没折了.......先谢过了~~
第二个BUG在构造Http请求时有时正常,有时却出现请求超时 比如我在家里测试时,都可以正常运行,而同样的代码放到公司时却出现请求超时,这个问题真心不知道是什么原因引起的,
这是我写的第二个小工具
第一个在这里 文件夹管理工具(MVC+zTree+layer)(附源码)
本项目地址在这里 采集博客园文章工具
文章还涉及到正则表达示,我总结了一篇相关的文章
在这里 读懂正则表达式就这么简单
二 工具介绍与思路介绍
2.1工具截图
效果大至就是这样了,样式什么的就没细调了,大伙将就下吧,能看就行了,主要这段时间比较忙,所以匆匆收尾了,还望见谅
2.2 工具所用到插件
masonry:
是 一款非常强大的jQuery动态网格布局插件,可以帮助开发人员快速开发类似剪贴画的界面效果。和CSS中float的效果不太一样的地方在 于,float先水平排列,然后再垂直排列,使用Masonry则垂直排列元素,然后将下一个元素放置到网格中的下一个开发区域。这种效果可以最小化处理 不同高度的元素在垂直方向的间隙
infinitescroll
是一个无限循环滚动的插件,做自动分页加载是很好用的,再配合masonry 瀑布流就可以达到 类似于QQ空间自动加载的效果,
三 开发思路
3.1 分析请求
先用Fiddler 抓取博客园的请求信息大至如下,因为只需要获取文章的信息,不需要做其它操作,所以Cookies部分就可以不考虑,
只要把请求头的相关信息Copy就行了然后添加到HttpWebRequest对象中
3.2 构造请求 并获取响应信息
通过HttpWebRequest创建一个请求,然后添加请求头信息,最后获取请求的响应信息到HttpWebResponse对象中,并读取出相应数据。
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://www.cnblogs.com/");
request.Accept = "text/plain, */*; q=0.01";
request.Method = "GET";
request.Headers.Add("Accept-Language", "zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
request.ContentLength = 0;
request.ContentType = "keep-alive";
request.Host = "www.cnblogs.com";
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:25.0) Gecko/20100101 Firefox/25.0"; HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responStream,Encoding.UTF8);
string content = reader.ReadToEnd();
3.3 通过正则取文章基本信息
个人觉得最难的部分就在用正则匹配出指定数据,因为没有接触过正则,而且正则又不太容易理解,所以学习正则花了一部分时间,并把正则相关的知识总结成了一篇文章
读懂正则表达式就这么简单 感谢大家的支持。,这里只列取一部分,具体的项目中都有详细的代码
//取推荐
regex =new Regex(
"<div class=\"digg\">.*<span.*>(?<digNum>.*)" + @"</span>" +
".*<div class=\"post_item_body\">", RegexOptions.Singleline);
article.DiggNum = regex.Match(item.Value).Groups["digNum"].Value; //取文章标题 需要去除转义字符
regex = new Regex("<h3>(?<a>.*)</h3>", RegexOptions.Singleline);
string a = regex.Match(item.Value).Groups["a"].Value;
regex = new Regex("<a\\s.*href=\"(?<href>.*?)\".*>(?<summary>.*)</a>", RegexOptions.Singleline);
article.AritcleUrl = regex.Match(a).Groups["href"].Value;
article.AritcleTitle = regex.Match(a).Groups["summary"].Value; //取作者图片 先取html img标签再取Src
regex = new Regex("<a.*>(?<img><img[^>].*>)</a>", RegexOptions.Singleline);
string img = regex.Match(item.Value).Groups["img"].Value;
regex = new Regex(@"<img.*src=(?<path>.*)\s+.*/>", RegexOptions.Singleline);
article.AuthorImg = regex.Match(img).Groups["path"].Value.TrimEnd('"').TrimStart('"');
3.4 把数据返回给插件Masonry
具体的参数配置官网都有详细的解释,这里就不详细说了,
$('.container').masonry({
itemSelector: '.item',
columnWidth: 230,//一列的宽度 Integer
isAnimated: true,//使用jquery的布局变化 Boolean
animationOptions: { Object :{ queue: false, duration: 500 } //jquery animate属性 渐变效果
},
gutterWidth: 10,//列的间隙 Integer
isFitWidth: true,// 适应宽度 Boolean
isResizableL: true,// 是否可调整大小 Boolean
isRTL: false,//使用从右到左的布局 Boolean
});
3.5 通过infinitescroll自动加载数据
通过触发这个插件infinitescroll的事件,来达到自动加载的效果,这里要注意的是自动加需要一个div 与a 标签,div是分页的容器初始化后会隐藏,而a标签的href属性则
是你要自动加载数据的地址,后面的参数 id=2 默认是从第二页开始,会自动累加。刚开始自己在网上找资料时,没人把这两个元素写出来,让我纠结了好久,我说不给地址
怎么去哪自动加载去啊,找了好久终于让我发现了.....
<div id="page-nav">
<a href="/GetArticle/GetArticles/?id=2"></a>
</div>
template 的函数返回值就是自动加载后返回的数据可以在DataType属性设定返回的数据格式,注意插件的最后一个回调函数 function (newElements) 要把新的数据添加进瀑布流的布局里就是在这里处理的, 这里的 newElements 其实就是template的返回值,也就是自动加载后重新拼装的数据。
$('.container').infinitescroll({
navSelector: '#page-nav',
nextSelector: '#page-nav a', //下一页选择器
itemSelector: ".item", //下一页中需要被加载进当前页的块
extraScrollPx: 150,//滚动条距离底部多少像素的时候开始加载,默认150
animate: true,
maxPage:10,//最大页数
dataType: 'json',
loading: {
//加载效果
finishedMsg: 'No more pages to load',
},
template: function (data) {
//data表示服务端返回的json格式数据,这里需要把data转换成瀑布流块的html格式,然后返回给回到函数
var article = '';
for (var i in data) {
article += "<li class='item'>" +
"<a href=" + data[i].AritcleUrl + " target='_blank'><h3> " + data[i].AritcleTitle + "</h3></a>" +
"<p>推荐<b> " + data[i].DiggNum + "</b> <a href=" + data[i].AuthorUrl + "><img src=" + data[i].AuthorImg + " alt='' /> </a></p>" +
"<p style='text-indent: 2em'>" + data[i].AritcleSummary + "</p>" +
"<p><a href=" + data[i].AuthorUrl + ">" + data[i].Author + "</a>" + data[i].PublishTime + "</p>" +
"<p>" + data[i].CommentNum +" "+data[i].ReadNum + "</p></li>";
}
return article;
},
},
function (newElements) {
//回调函数,用Masonry布局
// 当加载时隐藏所有新项目
var $newElems = $(newElements).css({ opacity: 0 });
// 现在可以显示所有的元素
$newElems.animate({ opacity: 1 });
$('.container').masonry('appended', $newElems, true); }
);
通过上面5步就可以把数据正常的加载出来,具体的细节部分喜欢的朋友可以下载源码看看。
四 总结
每次接触新的知识我都尽量会把所学的做一个工具出来,以加强自己的印象。我很享受从构思直到开发完成的这一个过程,在这个过程中收获的东西也很多。
不仅了解了Http相关的知识,还学习了正则与瀑布流和无限滚动,我会继续以这种方式一直走下去....
如果您觉得本文有给您带来一点收获,不妨点个推荐,为我的付出支持一下,谢谢~
如果希望在技术的道路上能有更多的朋友,那就关注下我吧,让我们一起在技术的路上奔跑