图书商城项目-三

知识点:简单的邮件发送找回密码,缓存帮助类,商品列表展示以及分页展示,URL重写,Seo优化

图书商城项目-三

知识点:简单的邮件发送找回密码,缓存帮助类,商品列表展示以及分页展示,URL重写,Seo优化

邮件找回密码

KzZpG.jpg

构建的内容中我们应该带一个具有验证码一样功能的参数来做到防止用户的骚操作

一般的邮件发送

1
2
3
4
5
6
7
8
MailMessage mail = new MailMessage();//声明mailMessage,在system.net.mail命名空间下
mail.From = new MailAddress("694176993@qq.com","测试");//发送者
mail.To.Add(new MailAddress("694176993@qq.com"));//收件人
mail.Subject = "代码发送邮件测试";//标题
mail.Body = "dotnet发送邮件测试";//发送内容
SmtpClient client = new SmtpClient("smtp.qq.com");//smtp服务器,邮件传输协议
client.Credentials = new NetworkCredential("694176993","Chendi735~!~");
client.Send(mail);//发送

缓存的使用

我们可以构建一个简单的缓存帮助类,用于增删查改,

(正如之前所提的,缓存可以在如下地方用到:不需要实时更新但是又极其消耗数据库的数据,需要实时更新,但是更新频率不高的数据,在某个时刻访问量极大而且更新也很频繁的数据但是这个另当别论,要是没有设置过期时间那么缓存将一直存在?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Web;
using System.Web.Caching;

namespace Common
{
public class CacheHelper
{
/// <summary>
/// 获取缓存
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static object Get(string key)
{
Cache cache = HttpRuntime.Cache;
return cache[key];
}

/// <summary>
/// 设置缓存
/// </summary>
/// <param name="key"></param>
/// <param name="obj"></param>
public static void Set(string key,Object obj)
{
Cache cache = HttpRuntime.Cache;
cache[key]=obj;
}

public static void Set(string key,Object obj, DateTime time)
{
Cache cache = HttpRuntime.Cache;
cache.Insert(key,obj,null,time,TimeSpan.Zero);
}

public static void Delete(string key)
{
Cache cache = HttpRuntime.Cache;
cache.Remove(key);
}
}
}

这样一来我们在没有缓存的时候调用数据库查询,但是以后我们就调用业务层来从缓存里面取我们所需要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//业务层
public string GetValue(string key)
{
if (Common.CacheHelper.Get("Setting_"+key)==null)
{
//查询
string value= dal.GetModel(key).Value;//动软生成查询方法
CacheHelper.Set("Setting_" + key,value);
return value;
}
else
{
return Common.CacheHelper.Get("Setting_" + key).ToString();
}
}

商品列表展示

通常而言的物品展示,都是循环某段模板,然后做好分页,那么最简单的我们就可以用到之前的reaper控件

前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
//循环内容
<table>
<tbody>
<tr>
<td rowspan="2"><a href="<%#Eval("Id","/BookDetail_{0}.aspx") %>">
<img
id="ctl00_cphContent_dl_Books_ctl01_imgBook"
style="cursor: hand" height="121"
alt="<%#Eval("Title") %>" hspace="4"
src="<%#Eval("ISBN","/Images/BookCovers/{0}.jpg") %>" width="95"></a>
</td>
<td style="font-size: small; color: red" width="650"><a
class="booktitle" id="link_prd_name"
href="<%#Eval("Id","/BookDetail_{0}.aspx") %>" target="_blank"
name="link_prd_name"><%#Eval("Title") %></a>
</td>
</tr>
<tr>
<td align="left"><span
style="font-size: 12px; line-height: 20px"><%#Eval("Author") %></span><br>
<br>
<span
style="font-size: 12px; line-height: 20px"><%# this.CurringStr(Eval("ContentDescription").ToString(),150)%></span>
</td>
</tr>
<tr>
<td align="right" colspan="2"><span
style="font-weight: bold; font-size: 13px; line-height: 20px">&yen;
<%#Eval("UnitPrice","{0:0.00}") %></span> </td>
</tr>
</tbody>
</table>
</ItemTemplate>
<SeparatorTemplate>
<hr/>
</SeparatorTemplate>
</asp:Repeater>

后端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public partial class BookList : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindBookList();
}
}

private void BindBookList()
{
BLL.BookManager bookManager = new BookManager();//业务层相关表的对象
this.Repeater1.DataSource = bookManager.GetModelList("");//调用业务层获取数据
Repeater1.DataBind();//绑定
}
//字符切割
public string CurringStr(string str,int length)
{
return str.Length>length?str.Substring(0,length)+"...":str;
}
}

有两个需要注意的地方,因为用到了空间所以会产生一坨的viewstate,需要在webform的开头第一个标签后面加上 EnableEventValidation=”false” ,另外就是 SeparatorTemplate 这个是reaper的分割标签 ,注意别写在table里面

实现分页(每页划分10商品)

数据层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
   /// <summary>
/// 获取图书列表的总数
/// </summary>
/// <returns></returns>
public int GetRecordCount()
{
string sql = "select count(*) from Books";
return Convert.ToInt32(DbHelperSQL.GetSingle(sql));
}
/// <summary>
/// 获取数据列表
/// </summary>
/// <param name="start">开始的index</param>
/// <param name="end">结束index</param>
/// <returns></returns>
public DataSet GetPageList(int start,int end)
{
string sql =
"select * from(select *,row_number()over(order by id) as num from Books) as t where t.num>=@start and t.num<=@end";
SqlParameter[] parameters = new SqlParameter[]
{
new SqlParameter("@start",start),
new SqlParameter("@end",end),
};
return DbHelperSQL.Query(sql,parameters);
}

逻辑层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/// <summary>
/// 获取图书的总页数
/// </summary>
/// <param name="pagesize"></param>
/// <returns></returns>
public int GetPageCount(int pagesize)
{
int recordCount = dal.GetRecordCount();
return Convert.ToInt32(Math.Ceiling((double) recordCount / pagesize));
}
/// <summary>
/// 获取指定范围的分页数据
/// </summary>
/// <param name="pageIndex">第几页</param>
/// <param name="pagesize">每页的个数</param>
/// <returns></returns>
public List<Book> GetPageList(int pageIndex,int pagesize)
{
int start = (pageIndex - 1) * pagesize + 1;
int end = pageIndex * pagesize;
DataSet ds = dal.GetPageList(start, end);
return DataTableToList(ds.Tables[0]);//动软生产的业务层的dataset转list方法
}

web调用,就改写上面的商品展示列,采用分页的办法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public int pageindex;//
public int pageSize = 10;//这里是偷懒最好用属性赋值
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindBookList();
}
}

private void BindBookList()
{
BLL.BookManager bookManager = new BookManager();
//this.Repeater1.DataSource = bookManager.GetModelList("");
//Repeater1.DataBind();
if (!int.TryParse(Request["pageIndex"], out pageindex))
{
pageindex = 1;
}
pageindex = pageindex < 1 ? 1 : pageindex;
pageindex = pageindex > bookManager.GetPageCount(pageSize) ? bookManager.GetPageCount(pageSize) : pageindex;
Repeater1.DataSource = bookManager.GetPageList(pageindex,pageSize);
Repeater1.DataBind();
}

在可以需要一个简单的分页helper类(每页10个数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public static string GetPagaBar(int pageIndex, int pageCount)
{
if (pageCount == 1)
{
return string.Empty;
}
int start = pageIndex - 5;//计算起始位置.要求页面上显示10个数字页码.
if (start < 1)
{
start = 1;
}
int end = start + 9;//计算终止位置.
if (end > pageCount)
{
end = pageCount;
//重新计算一下Start值.
start = end - 9 < 1 ? 1 : end - 9;
}
StringBuilder sb = new StringBuilder();
if (pageIndex > 1)
{
sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>上一页</a>", pageIndex - 1);
}
for (int i = start; i <= end; i++)
{
if (i == pageIndex)
{
sb.Append(i);
}
else
{
sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>{0}</a>",i);
}
}
if (pageIndex < pageCount)
{
sb.AppendFormat("<a href='?pageIndex={0}' class='myPageBar'>下一页</a>", pageIndex + 1);
}

return sb.ToString();
}

前端调用,在Repeater控件后面调用

1
2
3
<div class="page_nav">
<%= Common.PageBarHelper.GetPagaBar(this.pageindex, this.pageSize)%>//记得别漏了=
</div>

URL重写

为什么要进行重写,这是为了seo优化,比如说蜘蛛爬虫他不会趴带参数的地址,因此我们的URL必能参数,由于请求管道中的第八个事件就进行生成请求的对象,那么只能在请求管道的第八个事件前进行改写,最简单的就是建立一个全局应用类(Gobal.asax),里面有请求管道的第一个事件。也可以像之前那样自己定义一个类来实现相关接口然后改写

1
2
3
4
5
6
7
8
9
10
//请求管道的第一个事件
protected void Application_BeginRequest(object sender, EventArgs e)
{
string str = Request.AppRelativeCurrentExecutionFilePath;//获取虚拟路径,格式~/。。。
Match match=Regex.Match(str, @"~/BookDetail_(\d+).aspx");//正则匹配
if (match.Success)
{
Context.RewritePath("BookDetail.aspx?id="+match.Groups[1].Value);
}
}

所以注意一点seo不会执行js,所以用a标签直接请求地址就好

YnuGX.jpg


图书商城项目-三
http://www.kju147.com/2018/02/26/图书商城项目-三/
作者
个人学习
发布于
2018年2月26日
许可协议