图书商城项目总论
这些年来,我随指南针公司做了一些网站。在这里也感谢指南针用户对鄙人的大力支持,厚爱。汇聚很多程序员多年的智慧,今天我把多年来积累的经验汇聚到一个图书商城项目里面,为大家介绍网站的源代码。关键的环节在于融会贯通,举一反三。
先从注册开始,注册说起来相对来比较简单
一、登录界面
注册界面里面有文本框,有用户名的检测 – 用到“AJAX”这个知识点
填写完信息点击注册后,有个js或是jq的校验
当信息全部填写完,用户点击注册按钮后,把表单里面的数据向服务端提交,在服务端接收数据,插入数据库。
那么,除了把用户信息插入数据库当中之外,我们还要实现用户激活的功能。就是获取用户输入邮箱,根据邮箱发一封邮件。邮件的内容就是激活链接。
把用户信息写入数据库相对简单,问题是怎么去发邮件,怎么发激活链接?这是我们重点讲解的内容。介绍怎么知道用户点没点链接,怎样进行激活。
接下来做的一个功能就是找回密码功能。
二、找回密码演示界面
根据用户的邮箱,把用户名和密码发给用户。这也是我们重点讲解的内容。
这部分用到了之前我们讲解的缓存。
接下来我们做下用户注册之后上传头像的功能,
以前我们上传的时候可能用的是<input type=”File”>但是用户的体验度不是特别的好,为什么呢?<input type=”submit”>一点submit就刷新了。
我们要做个无刷新上传。讲解两种方式,重点介绍flash开源的组件。
三、无刷新上传演示
上传之后,完成截取功能。
四、头像截取功能介绍
讲解flash组件的使用,上传的服务端代码,jq和js实现截取,获取坐标。
然后实现登录功能:
五、登录功能介绍
这里要实现用户名,密码的校验,实现:“记住我”的功能。记住我使用cookie。
这块说完了之后,我们再说下AJAX的登录模式。
六、AJAX登录模式
以及遮罩效果,遮罩我们使用jq来实现。
下一步我们看下:图书列表的展示,我们怎样用美工做好的html网页,怎么样把数据从数据库中拿出来并且进行绑定。
具体实现步骤,从服务端获取相关数据,绑定以及分页的实现。排序的基本实现,还会详细探讨下viewstate。
七、图书列表展示
八、分页效果一
九、另外一种分页的模式
看完另外一种分页的形式后,我们看下url重新问题。
十、url重写
并且深入探讨url重写问题。url重写主要就是为了SEO网站优化的问题。
接下来看下怎么生成静态页:
十一、生成静态页
也就是纯html网页,当用户量比较大的时候,我们最好做成静态页。
然后再看下评论的发布。
十二、评论的发布
这里要实现评论的发布,以及评论内容的加载。重点关注的是时间问题,非具体时间的显示。请仔细看下我们评论区域,不是普通的文本编辑器,是个ubb的文本编辑器。
在这里还要看下xss跨站点脚本攻击的问题和敏感词过滤问题(禁用词,审查词,替换词)。关于审查词,如:发票。这两个字先提交到数据库,管理员进行审核。
接下来的内容自己可以做了,就是评论内容的无刷新分页。
还有就是当滚动条滚动到页面的最下端的时候,才显示评论信息的功能。
这些都讲解完成后,进入购物车功能:
十三、购物车功能
在这里实现商品的增加,商品的递减,商品的删除一系列功能。用jq或js完成。
接下来我们完成结算的功能讲解。
十四、结算功能
进入到订单确认页面里面,输入收货人的地址,选择支付方式,在这里重点讲解怎么实现支付宝。当然在这里我们使用的是模拟的支付宝系统,带大家理解下原理,以及流程。
接下来就到结算功能了,在这里用户要完成下订单操作,向支付宝发送数据的功能。
介绍完这部分内容以后,我们再详细的介绍下编辑器。
十五、编辑器
在这里我们要了解下它的基本使用,再带大家学习词库
十六、词库
要实现敏感词的过滤功能的话,在我们的系统里面必须得有个词库。在这里我们讲解下词库的添加与下载。
接下来我们再讲解下日志记录问题。用到一个开源的框架。
再来介绍下开源的定时框架。就是每隔多长时间去执行什么任务。比如:每天一个约定时间去统计今天的订单数。
这些介绍完以后,我们再来介绍下SEO的问题。
最后的文章里面会给大家介绍下视频处理的问题,就是怎么样做视频的播放的问题。当用户上传任意的格式的视频的时候我们怎么样进行转换。转完以后又怎么播放。
十七、播放有关内容
接下来再说下权限管理的内容:
这块我们单独的进行演示。
十八、权限管理系统
十九、权限管理-用户管理
当admin管理员进入的时候,可以展示出所有的菜单。管理员可以添加新的用户,添加完用户以后可以给这个用户添加角色。
二十、权限管理-角色管理
然后为这个角色指定权限。
二十一、为角色指定权限
以及菜单管理。
二十二、菜单管理
菜单用户可以进行添加。
二十三、添加菜单
然后菜单项也是与权限相关联的。当管理员登陆的时候,菜单全部展开,普通用户登录,只能展示出相应的菜单。所以说,菜单也有权限编号。当用户登录的时候拿到菜单的权限编号和用户的权限编号进行对比,来决定显示哪个菜单。
好,总论讲解完毕,下面进入详细环节。先看下权限管理内容。
权限表分析:在权限管理里面最重要的是三个对象,用户管理对象,角色管理对象,权限管理对象。这里就用到了面向对象的思想。
请看下面的图示:
二十四、权限管理数据库分析
先看下名词解释,用户很好理解。什么叫角色呢?老师,学生都是角色。权限也比较的好理解。
在这里用户为什么没有跟权限直接的进行关联呢?
用户要和角色进行关联,用户属于某个角色。在这里举个例子讲解:杨川川入职了,就是个新员工,公司里面有个打卡系统,经理要开给杨川川在办公系统开个账户。现在公司决定新入职的员工权限提升一次,之前5个权限,现在6个权限。假如说系统在设计的时候是用户和权限直接关联的。本月来的10个新员工,都要调整权限。但是用户要是和角色相关联的话,这时,只要把新员工的权限改下就行了。所有属于新员工的用户权限就都发生变化了。
下面我们就看下权限的数据库怎么进行设计了,最基本的得有用户表,角色表,权限表。
用户表里面有哪几个字段呢?
用户编号,用户名,密码,性别,邮件。
角色表里面有哪几个字段呢?
角色编号,角色名。
权限表里面有哪几个字段呢?
权限编号,权限名。
用户跟角色进行关联,按照我们之前讲解的内容,两个表就有关系了。主外建关系。如果我在用户表里面加个角色编号的话,你们认为合理么?
一个用户属于一个角色,一个角色下可以有多个用户,所以说这两个表的关系就是多对多的关系。既然是多对多的关系,我们怎么表现出这种关系呢?
还得需要一张表,就是用户角色关系表。用户和角色的关系就体现在用户关系角色表里面了。
用户关系角色表里面应该有哪些字段呢?
用户编号,角色编号。
角色表跟权限表是个什么关系呢?
也是个多对多的关系,所以,再建一张表,叫做角色权限关系表。
这张表中有:角色编号,权限编号的字段。
这五张表就是我们的核心表了,还有一张我多增加的表叫做权限类别表。然后权限都放在一个大类下面。
有:类别编号,类别名称字段。
在权限表中,增加个:类别编号的字段。
二十五、数据库当中的六张表
二十六、权限管理模块核心表结构
我们看到还有像菜单表,用户信息表中还有部门这样的字段。刚才的六张表的分析,以思路为主,采用的字段都是最基本的字段。
刚才我们分析了数据表的创建过程,关键是思路,能理解这个过程就可以了.
下一步我们开始设计登录的内容,打开项目,我们先用手写的三层,后面讲到图书商城项目的时候再演示代码生成器.
二十七、web登录(1)
二十八、放验证码的位置
验证码插入位置:
1 using System; 2 using System.Collections; 3 using System.Data; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Services; 7 using System.Web.Services.Protocols; 8 using System.Xml.Linq; 9 using System.Drawing; 10 using System.Drawing.Drawing2D; 11 namespace Web 12 { 13 /// <summary> 14 /// $codebehindclassname$ 的摘要说明 15 /// </summary> 16 [WebService(Namespace = "http://tempuri.org/")] 17 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 18 public class ValidateCode : IHttpHandler,System.Web.SessionState.IRequiresSessionState 19 //3.在一般处理程序中使用session要实现这个接口。 20 { 21 22 public void ProcessRequest(HttpContext context) 23 { 24 context.Response.ContentType = "image/Gif"; 25 CreateStr(CreateCode()); 26 27 } 28 private string CreateCode() 29 { 30 string str = ""; 31 //1.随机生成一个数字 32 Random random = new Random(); 33 str=random.Next(1000,9999).ToString(); 34 //2.把数字放在个session里面。 35 HttpContext.Current.Session["code"] = str; 36 return str; 37 } 38 private void CreateStr(string code) 39 { 40 if (code.Length<= 0) 41 return; 42 string str; 43 Random random=new Random(); 44 using (Bitmap map = new Bitmap(4 * 14, 30)) 45 { 46 using (Graphics g = Graphics.FromImage(map)) 47 { 48 g.Clear(Color.White); 49 g.DrawRectangle(new Pen(Color.Gray), 0, 0, map.Width - 1, map.Height - 1); 50 using (LinearGradientBrush brush = new LinearGradientBrush(new Point(0, 0), new Point(map.Width, map.Height), Color.Red, Color.Green)) 51 { 52 for (int i = 0; i < code.Length; i++) 53 { 54 str = code.Substring(i, 1); 55 g.DrawString(str, new Font("黑体", 14.0f, FontStyle.Bold), brush, new PointF(13.0f * i, random.Next(10))); 56 } 57 //for(int i=0;i<10;i++;) 58 //{ 59 60 //} 61 for (int i = 0; i < 10; i++) 62 { 63 map.SetPixel(random.Next(map.Width), random.Next(map.Height), Color.FromArgb(random.Next(255), random.Next(255), random.Next(255))); 64 } 65 HttpContext.Current.Response.Clear(); 66 System.IO.MemoryStream stream = new System.IO.MemoryStream(); 67 map.Save(stream, System.Drawing.Imaging.ImageFormat.Gif); 68 HttpContext.Current.Response.BinaryWrite(stream.ToArray()); 69 } 70 } 71 } 72 73 } 74 75 public bool IsReusable 76 { 77 get 78 { 79 return false; 80 } 81 } 82 } 83 }
下一步我们怎么把验证码放到登录页面上,我们该怎么放呢?
二十九、将验证码引入-用个img标签
接下来我点验证码的时候需要个切换效果,这个效果怎么实现呢?
我们用js来实现,我在这加了个a标签,在a标签里面写了个onclick
在js的函数里面怎么写呢?获取验证码的id,然后改变src属性,获取随机数加个毫秒数,这样第一步就完成了。
三十、切换验证码的代码
下一步我们就开始点击:登录按钮
现在我们在后台,后台的用户访问少,所以这里可以用服务端控件。
三十一、构建三层的时候需要注意的地方
三十二、DbHelperSQL
动软的代码生成器,把数据库连接字符串都放在appSettings里面了。不要放在这里面,因为ms为我们提供了connectionStrings。
那么我们在什么时候会用到appSettings里的键值对呢?比如分页,每页显示多少条记录,以前都写在程序里面。用户不想一页显示10条的话,我们只能再改程序。
最好的方式是写在配置文件里面,不需要改源代码。我们可以把关于每页显示多少页的项,放在appSettings里面。 ConfigurationManager.AppSettings["key"]获取一下。
三十三、配置文件中需要注意的地方
其实,把经常变动的内容放在配置文件中也不是最佳的选择。如果现在网站正在服务器运行的情况下,正在使用这套程序的用户的会话丢了。最好的解决方式就是做个页面。可以在自己网站的后台做个页面,这个后面马上就讲。
像使用的数据库变化了这样的问题,涉及到抽象工厂。就是面向接口编程。建议看下《大话设计模式》。
三十四、配置页面
三十五、数据访问层我们回顾的内容
三十六、用户校验的DAL层代码
别忘了引用下model
下面写下业务逻辑层
三十七、用户校验的BLL层代码
这里的BLL就是个打酱油的,别忘了引用DAL和Model。
接下来终于回到了web层。
引用bLL和Model,注意:每写完一层,我们都需要重新生成一下。
插入代码位置:
1 using System; 2 using System.Collections; 3 using System.Configuration; 4 using System.Data; 5 using System.Linq; 6 using System.Web; 7 using System.Web.Security; 8 using System.Web.UI; 9 using System.Web.UI.HtmlControls; 10 using System.Web.UI.WebControls; 11 using System.Web.UI.WebControls.WebParts; 12 using System.Xml.Linq; 13 14 namespace Web 15 { 16 public partial class Login : System.Web.UI.Page 17 { 18 protected void Page_Load(object sender, EventArgs e) 19 { 20 } 21 /// <summary> 22 /// 登录 23 /// </summary> 24 /// <param name="sender"></param> 25 /// <param name="e"></param> 26 protected void btnLogin_Click1(object sender, ImageClickEventArgs e) 27 { 28 //1:判断验证码 29 if (Session["code"] != null) 30 { 31 if (Session["code"].ToString()== this.validateCode.Text)//拿到验证码的值。要是验证码中含有字母的话,不考虑大小写.tolower(),验证码的目的主要是防止机器注册。 32 { 33 //2:判读用户名密码 34 string txtName = this.txtUsername.Text;//获取用户名 35 string txtPass = this.txtPassword.Text;//获取密码 36 37 38 //开始校验,写个数据访问层,业务逻辑层 39 BLL.Account_UserManager bll = new BLL.Account_UserManager(); 40 int userID=bll.CheckLogin(txtName, txtPass);//对用户进行校验,返回用户编号 41 if (userID > 0)//登录成功 42 { 43 //对的话,记录下用户的信息 44 Session["User"] = txtName; 45 Session["UserID"] = userID; 46 //跳转 47 Response.Redirect("Manage/Main.htm"); 48 } 49 else 50 { 51 this.lblMsg.Text = "用户名密码错误!"; 52 } 53 54 } 55 else 56 { 57 this.lblMsg.Text = "验证码错误!"; 58 } 59 60 } 61 else 62 { 63 this.lblMsg.Text = "验证码错误!"; 64 } 65 } 66 } 67 }
下面我们重点讨论下:session
session的主要作用就是记录用户登录信息,为什么要放进session,干什么用呢?在后台的页面里面进行校验。
三十八、新建test页
这个网页只有登录的用户才可以看,
三十九、登录测试页面
网站管理员操作的后台页面有很多,在每个页面加这段代码的话,自己累,用户也非常的不爽。我们有什么好的方法处理这个问题么?
可以用过滤器:HttpModule---其中最核心的就是19个事件。
四十、19个事件
看表,得知使用第九个。如何使用这张表:由于每一个动态页面都会走过滤器,我们就可以在过滤器里面进行判断。过滤器有19个事件,我们一查表发现是第9个。
那么,我们怎么去使用第9个事件呢?
可以自己定义个类,来继承HttpModule这个接口,也可以在全局配置文件里面,到底使用哪种方式,随便你.
下面我写好了这段代码,分享源代码贡大家使用:
插入CheckAdminModule.cs位置:
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 namespace Web.Common 14 { 15 //1.自己定义个类继承自IHttpModule 16 public class CheckAdminModule:IHttpModule 17 { 18 #region IHttpModule 成员 19 20 //2.IHttpModule里面有个主要的方法Init ,参数是HttpApplication。这就是我们的请求管道。 21 public void Init(HttpApplication context) 22 //3.获取第9个事件,通过委托调OnRequest这个方法 23 { 24 context.AcquireRequestState+=new EventHandler(OnRequest); 25 26 } 27 //4.看下这个方法怎么做的呢? 28 public void OnRequest(object source, EventArgs e) 29 { 30 HttpApplication application = source as HttpApplication;//得到Application 31 HttpContext context = application.Context;//得到请求上下文. 32 Uri url = context.Request.Url;//得到当前请求的URL 33 34 //5.请求Admin目录下的文件时,需要进行身份验证,只有管理员才能访问. 35 //6.为什么做个判断呢?就是我的后台的管理页面都要放在单独的文件夹里面,放在了admin里面了。如果下一步请求admin文件夹下的文件的话,肯定会带文件夹的名字。就判断一下这个路径里面有没有admin?有的话,就是请求的admin 36 if (url.AbsolutePath.ToLower().StartsWith("/admin")) 37 { 38 //adminlogin.aspx和logout.aspx不需要身份验证 39 //7.如果是的话,再判断一下,这个路径的末尾包不包含:adminlogin.aspx。包含的话,可以访问 40 if (url.AbsolutePath.ToLower().EndsWith("adminlogin.aspx")) 41 { 42 return; 43 } 44 //退出 45 if (url.AbsolutePath.ToLower().EndsWith("loginout.aspx")) 46 { 47 return; 48 } 49 //8.如果是admin下的一个文件但不是登陆退出的话,下一步就校验session,如果session为空的话,直接跳到登陆页面就行了。 50 if (HttpContext.Current.Session["Name"] == null) 51 { 52 HttpContext.Current.Response.Redirect("adminlogin.aspx"); 53 } 54 55 56 } 57 } 58 59 public void Dispose() 60 { 61 throw new NotImplementedException(); 62 } 63 64 #endregion 65 } 66 }
关键是配置项,我们要在Web.config里面配置一下。
四十一、Web.config
上面的内容中我们把登录给大家写了一下,接着我们看下登录成功以后
四十二、跳转一
四十三、跳转二
四十四、然后看看Main.htm里面都是什么
四十五、用frameset的好处
可以使用母版页。母版页就是把公共的元素给独立出来。上面和左面都用母版页来做。那么,我在做后台管理系统的时候为什么没用母版页用的是frameset呢?用母版页一点就刷新,体验性不是特别的好。
四十六、frameset布局
在前台(大众用户看的)页面的布局的时候,一般都用母版页来做,为什么这又不用frameset呢?frameset不利于SEO的优化,搜索引擎都有蜘蛛爬虫,这些蜘蛛不喜欢页面是frameset布局的。frameset放的是不同的页面,蜘蛛所喜欢页面就是一个页面。对于网站的后台(给管理员看的)就无所谓了。
接下来我们再回顾一下frameset的基本用法,
四十七、主页面
不需要用body了,因为body里面放的是网页的主体,只管分割,具体的内容显示交给其它的页面了。rows横向分割,iframe是内嵌框架,*剩下的高度或宽度,rows和cols不能同时使用。在left.html中设定target
四十八、设定left.html中的target属性
在使用frameset的时候,最好给它定死。noresize这个属性就是干这个事儿的。
下面我们看下菜单表的设计:
四十九、菜单设计一frameset
下面我们就看下怎么把菜单给取出来,
五十、干掉这条语句
五十一、给TreeView起个名字
菜单存在数据表里面,下一步要考虑菜单这个数据表它应该怎么设计。通过观察我们发现菜单是个树状结构,数据表要体现出这种主次关系。那么数据表怎么设计呢?通过父id体现这种主次关系。
五十二、数据表设计
那么我们这里不写ParentID行不行呢?做成两个表行不行呢?不行的,子菜单下面可能还有子菜单。所以,以后设计这种树状结构的时候,要增加一个父节点。
五十三、这样设计是不行的
下面我们就看下怎么取数据。
五十四、IsPostBack属性
这个判断是我们在服务端经常用到的判断,下面我们再来说一下IsPostBack的用法。曾经是个面试题呦!
IsPostBack这个属性的值是个bool类型的,那么他在什么情况下为true,什么情况下为false呢?
当是一个get请求时,该属性的值为false。
如果是一个post请求时,该属性的值为true。
什么时候发get请求呢?用户在地址栏里面输入网址,点个超链接。
那么什么时候发post请求呢?
提交表单submit的时候。
那么在这个地方,加这个判断的意义是什么呢?
获取所有的菜单项,查询数据库,当用户第一次访问这个页面的时候,我们把数据从数据库里面取出来。加载到TreeView上,页面上有个submit或其它的提交按钮的话,一点按钮,发出post请求。导致页面挥发、刷新。这时还会再走下Page_Load方法,如果不加if(!IsPostBack)判断,又查询数据库了。加上这层判断就不用查询数据库了,因为IsPostBack属性为true,又加了个非。不成立就不执行下面的代码了。
继续往下走,为什么点击按钮导致页面刷新,为什么不用查数据库但是数据没有丢呢?因为VIEWSTATE。
五十五、viewstate
画图演示这个问题,
五十六、_ _VIEWSTATE出现的场景
那么IsPostBack这个属性,它怎么知道用户发的是get请求还是一个post请求呢?
根据的是请求报文,如果是get请求,请求报文里面只有请求头。如果是post请求还有请求体。
如果发出的是post请求,这时候会把_ _VIEWSTATE发到服务端,服务端一看有隐藏域过来,IsPostBack为true。
五十七、禁用隐藏域
当我们禁用隐藏域以后,_ _VIEWSTATE还有,但是它的value很少了。那么,我们想完完整整的干掉隐藏域的话,应该怎么办呢?
五十八、彻底干掉隐藏域
但是,如果把它去掉了,服务端控件就没办法使用了,这样就回到了纯HTML的时代。
所以说,_ _VIEWSTATE这个东西让人用起来很方便,但是它返回的这坨代码很不爽。浏览器要加载这些东西,让浏览器变得很慢,卡住了一样。一般情况下,我们把隐藏域禁用掉。如果禁用掉的话,每次都要查数据库了。就不能加刚才的if(!IsPostBack)判断了。大家会问,如果我每次查询数据库的话也很慢,其实,在这个地方有外国专家写过博客,连数据库的时间比加载_ _VIEWSTATE的时间要短。一般情况下我们要把_ _VIEWSTATE禁用掉。但是我们现在做的是后台,就无所谓了。要是我们后面做图书列表的话,就没必要用_ _VIEWSTATE了。又不想每次查询数据,就只能启用缓存了。
下面我们就写下GetTreeData()
五十九、数据访问层代码
六十、业务逻辑层代码
六十一、UI层代码
接下来我们考虑下权限问题,我们获取用户的权限编号和菜单的权限编号进行一个对比.
六十二、权限编号的由来
首先应获取下用户所具有的权限编号,
六十三、分析哪两张表关联好写sql语句
分析结果:角色权限关系表dbo.Accounts_RolePermissions
用户角色关系表dbo.Accounts_UserRoles
通过RoleID关联起来,得到权限编号了。
六十四、写好DAL.Account_UserService
六十五、写好BLL.Account_UserManager
然后再回到left.aspx.cs页面
六十六、登录的时候存到Session里面
六十七、权限UI层
最后,我们来看下退出的问题。
六十八、放个退出按钮
六十九、切换到设计模式
七十、退出代码
这块出问题了,我们用的是frameset,跳转的时候只跳出上面这块。
七十一、这样写退出
target的其它选项自己去查,比较简单,不再这里说了。
再加个Loginout.aspx页面。其实退出页做个一般处理程序比较的好。
七十二、新建退出页
七十三、页面报错
七十四、报错的原因
关键就是target属性,今天我们的文章当中就提到了两次。
作者近期文章列表:
C#中级进阶教程(完全免费,献给代码爱好者的最好礼物。注:本作者分享自己精心整理的C#中级进阶教程,无任何商业目的。希望与更多的代码爱好者交流心得,也请高手多多指点!!!) | |
三层及其它内容 | 递归 |
三层(一) | |
三层相关案例(及常见的错误) | |
三层实例(内涵Sql CRUD) | |
手写代码生成器 | |
SQL数据库 ADO.net | 数据库的应用图解一 |
数据库的应用详解二 | |
ADO.NET(内涵效率问题) | |
ADO.NET实例教学一 | |
ADO.NET(内含存储过程讲解) | |
面向过程,面向对象中高级 | 面向过程,面向对象的深入理解一 |
面向过程,面向对象的深入理解二 | |
面向对象的深入理解三 | |
无处不在的XML | |
winform基础 | Winform基础 |
winform中常用的控件 | |
面向过程 | 三种循环的比较 |
C#中的方法(上) | |
我们常见的数组 | |
面向对象 | 思想的转变 |
C#中超级好用的类 | |
C#中析构函数和命名空间的妙用 | |
C#中超级好用的字符串 | |
C#中如何快速处理字符串 | |
值类型和引用类型及其它 | |
ArrayList和HashTable妙用一 | |
ArrayList和HashTable妙用二 | |
文件管理File类 | |
多态 | |
C#中其它一些问题的小节 | |
GDI+ | 这些年我收集的GDI+代码 |
这些年我收集的GDI+代码2 | |
HTML概述以及CSS | 你不能忽视的HTML语言 |
你不能忽视的HTML语言2精编篇 | |
你不能忽视的HTML语言3 | |
CSS基本相关内容--中秋特别奉献 | |
CSS基本相关内容2 | |
JavaScript基础 | JavaScript基础一 |
javascript基础二JavaScript DOM编程 | |
jQuery | jQuery(内涵: jquery选择器) |