DinnerNow.Net中的AJAX应用体味(3)
2009-03-10 01:30 AnyKoro 阅读(358) 评论(0) 收藏 举报现在再让我们言归正传,再来看看Search.aspx文件的所有代码,由于此代码很长,我仍然采取直接利用注释说明的方法进行讲解。
<%@ Page Language="C#" MasterPageFile="Main.master" AutoEventWireup="true" Inherits="Search"2
Title="DinnerNow.net" CodeBehind="Search.aspx.cs" %>3
<%@ Register Src="LoginControl.ascx" TagName="LoginControl" TagPrefix="uc2" %>4
<%@ Register Src="SearchBar.ascx" TagName="SearchBar" TagPrefix="uc1" %>5
<asp:Content ID="Content1" ContentPlaceHolderID="LoginPlaceHolder" runat="Server">6
<uc2:LoginControl ID="LoginControl1" runat="server"></uc2:LoginControl>7
</asp:Content>8
<asp:Content ID="SearchBarContent" ContentPlaceHolderID="SearchBarPlaceHolder" runat="Server">9
<uc1:SearchBar ID="SearchBar1" runat="server"></uc1:SearchBar>10
</asp:Content>11
<asp:Content ID="Content3" ContentPlaceHolderID="MainContentPlaceHolder" runat="Server">12
<!—对于这个已经是第二次看到了,为调用WCF服务做准备--> 13
<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">14
<Services>15
<asp:ServiceReference Path="~/Services/ShoppingCartService.svc" />16
</Services>17
</asp:ScriptManagerProxy>18

19

20
<script type="text/javascript">21
//这个函数是用来处理回传信息的,这个是asp.net ajax框架里面的pageload(),在页面加载的时候自动运行22
function pageLoad()23
{24
try25
{26
var PARAMETERS = {};27
//这是一种在JavaScript语言中定义函数的方法,函数名就是PARMETERS.load,在下面有调用,这里不运行28
PARAMETERS.load = function() {29
PARAMETERS.map = {};30
//下面的程序提取了请求的url地址,并且利用JavaScript中的replace方法,按照正则表达式进行操作。31
//对于这个命令,我也没有搞得十分明白,期待大牛能不吝赐教,我只是在FireBug中进行调试得到了他的运行规律,32
//这个程序中会一连运行四次,就好像加了个循环,运行的对象分别是PostalCode,MenuType等等,就是设置的那四个搜索33
//对应的s、k、q、v数值分别为,以PostalCode为例,s=”PostalCode=98101&”,k=”PostalCode”,q=”=98101”,v=”98101”,以此类推34
//其他的,只是将这里的PostalCode换成如MenuType等等35
window.location.search.substring(1).replace(/([^&=]+)([=]([^&]*))?(&|$)/g,function(s,k,q,v){36
if (undefined === PARAMETERS.map[k]) {37
PARAMETERS.map[k] = [];38
}39
PARAMETERS.map[k].push(decodeURIComponent(v));40
});41
for (var k in PARAMETERS.map) {42
var a = PARAMETERS.map[k];43
PARAMETERS.map[k] = ((1 == a.length) ? a[0] : a);44
}45
};46
//刚刚定义的函数的调用47
PARAMETERS.load();48
//下面这个命令就是前面在searchbar.ascx里面写的JavaScript函数 49
set_Content(PARAMETERS.map.DeadLine, PARAMETERS.map.MenuType, PARAMETERS.map.PostalCode, PARAMETERS.map.RestaurantCategory); 50
//这里直接调用了WCF服务,获得下面生成搜索结果的页面,就是选择饭店的页面。51
var service = new DinnerNow.Services.IMenuSearchService();52
service.FindRestaurant(PARAMETERS.map.PostalCode, PARAMETERS.map.MenuType, PARAMETERS.map.RestaurantCategory, PARAMETERS.map.DeadLine, onRestaurantSeachSuccess, onRestaurantSeachFailed, null);53
}54
catch(ex)55
{56
alert(ex);57
alert("对象无法被序列化");58
}59
}60
//这个很简单就是用来标示需要显示的div61
var _divs = ["SearchResultsDivision","MenuDivision"];62
function DisplayDiv(divName)63
{64
//根据赋予的divName来进行决定谁显示,谁不显示,为了保证程序的健壮性所以采用了,每次都循环扫描的方法,上面的_divs代表一共有几个受影响65
for (var i=0; i <_divs.length; i++)66
{67
document.getElementById(_divs[i]).style.display = 68
(_divs[i]==divName) ? "block": "none";69
}70
}71
//前面findrestaurant的ajax应用的成功回调函数72
function onRestaurantSeachSuccess(searchResult)73
{74
//这里就是准备利用前面获得的结果利用Javascript写出页面显示。75
//下面是获得用于存放饭店结果列表的位置76
var restaurantContainer = document.getElementById("restaurantList");77
restaurantContainer.innerHTML = "";78
//这里是根据后端传过来的数据格式用JavaScript写出一个resultslist79
for (var i=0; i<searchResult.length; i++)80
{81
var restaurantHtml= "<a href=""javascript:restaurantSelection_Click('"82
+ searchResult[i].RestaurantId + "', '"83
+ searchResult[i].LogoImageLocation +"', '"84
+ searchResult[i].Name +"');""><img src="""85
+ searchResult[i].LogoImageLocation + """ alt="""86
+ searchResult[i].Name + """ width=""154"" height=""90"" class=""thingreenline"" /></a>";87
var restaurantElement=document.createElement("span");88
restaurantElement.innerHTML = restaurantHtml;89
//每次循环都会新增一个span。即是我们看到的饭店的logo,但同时restaurantSelection_Click函数已经在上面的代码中动态的赋予了参数。90
restaurantContainer.appendChild(restaurantElement);91
}92
//显示出搜索结果93
DisplayDiv("SearchResultsDivision");94
}95
//搜索失败时候调用的回调函数96
function onRestaurantSeachFailed(result)97
{98
alert(result._message);99
alert("搜索失败");100
}101
//发现这个函数有点眼熟吗?没有错这个函数的使用是通过前面在onRestaurantSeachSuccess动态生成结果列表时,动态生成的,具体的函数的定义是在这里102
function restaurantSelection_Click(identifier, logo, name)103
{104
/********** RestaurantSelected ***********/105
document.getElementById("restaurantImage").src = logo;106
document.getElementById("restaurantName").innerHTML = name;107
//这里的restaurantDescription是有问题的,所有的饭店都是相同的描述,这个感觉应该是DinnerNow中的一个小的疏漏但是并不影响我们研究108
document.getElementById("restaurantDescription").innerHTML = "Since 1923, the offering fas, friendly and courteous service. We use only the best ingredients and maintain a skilled staff to answer your questions. We have built our reputation on our commitment to providing quality service, which has earned us many valuable customers.";109
//获取对应饭店的菜单110
document.getElementById("restaurantMenuFeed").href = "service/syndication.svc/rss/restaurants/"+ name;111
112
var restaurant = document.getElementById("restaurantID");//这是一个span,里面存放当前选中的restaurantidentifier113
restaurant.innerHTML = identifier; //存放restaurantidentifier114
/********** RestaurantSelected ***********/115
//这里进行了wcf调用116
var service = new DinnerNow.Services.IMenuSearchService();117
//这个return_MenuType()是在searchbar.ascx中写的JavaScript函数118
var menuType = return_MenuType();119
var selectedMenuType = document.getElementById("selectedMenuItemCategory");//也是一个hidden控件,放着当前选的菜单项的分类,如当前选的是breakfast等等120
selectedMenuType.value = menuType;121
//又一次调用wcf了,这里不得不说,微软用wcf,完全替代了webservice,我感觉这个能增加应用的安全性。122
//获得各项具体的食物123
service.GetMenuItemsForMenu(identifier,menuType,restaurantSelection_onSuccess,restaurantSelection_onFailed,null);124
//获得所包涵的食品类型125
service.GetMenuTypes(getMenuTypes_onSuccess, getMenuTypes_onFailed, null);126
}127
//这里是利用前面service.GetMenuItemsForMenu所获得的结果,在这里利用JavaScript写出一个列表用来显示这些食物128
function restaurantSelection_onSuccess(result)129
{130
var menuItemContainer = document.getElementById("menuList");131
menuItemContainer.innerHTML = "";132
133
/******** MenuItems **********/ 134
for (var i=0; i<result.length; i++)135
{136
var menuItem = result[i];137
//给每个菜做了一个table,然后通过建立一个span加载,注意这里的图片显示是用img来做到的,menuitem的图片都存在该项目的images文件夹中138
//第二行写了个href,表示点击image在新窗口打开,查看大图,这些都是通过css实现的,JavaScript和c#代码做到的仅仅是提供了图片139
var menuItemHtml = "<table width='100%' border='0' align='center' cellpadding='8' cellspacing='0' class='thinblueline'><tr><td width='150' align='center' valign='top'><div class='hoverarea'><div><a href="""140
+ menuItem.ImageLocation + """ target='_blank'> <img id=""MenuItemImage"" src="""141
+ menuItem.ImageLocation + """ alt="""142
+ menuItem.Name +"""/><img id=""Img1"" src="""143
+ menuItem.ImageLocation+ """ alt="""144
+ menuItem.Name+""" class=""hoverimage_preview""/></a></div></div></td><td valign='top'><strong>Item # "145
+ i + "</strong><br/><strong>"146
+ menuItem.Name+"</strong><br/>"147
+ menuItem.Description+"<br/><br/><div align='left'><strong>Estimated Delivery Time: "148
+ menuItem.PreparationTime+" minutes</strong></div></td><td width='80' align='right' valign='top'><strong>$"149
+ menuItem.Price+"</strong><br/><br/><a class=""noUnderline"" href=""javascript:AddItemToShoppingCart('"150
+ menuItem.Description + "', '"151
+ menuItem.ImageLocation + "', '"152
+ menuItem.MenuId + "', '"153
+ menuItem.MenuItemId + "', '"154
+ menuItem.Name + "', '"155
+ menuItem.PreparationTime + "', '"156
+ menuItem.Price + "');""><img src=""images/selectbutton.gif"" border=""0"" /></a></td></tr></table>";157
//上面的代码又动态写入了一些在后面会定义到的函数158
var menuItemElement=document.createElement("span");159
menuItemElement.innerHTML = menuItemHtml;160
161
menuItemContainer.appendChild(menuItemElement);162
}163
/******** MenuItems **********/164
//当一旦生成了菜谱后,购物车的抬头就被生成了,这里的生成也就是显示,通过下面一句165
DisplayDivContent4("shoppingCart");166
DisplayDiv("MenuDivision");167
}168
function restaurantSelection_onFailed(result)169
{170
alert("选择失败");171
}172
//获得MenuType后,这里我感觉就是用JavaScript写了一个类似tab控件的效果。173
function getMenuTypes_onSuccess(result)174
{175
var menuTypeContainer = document.getElementById("menuTypeListTab");176
menuTypeContainer.innerHTML="";177
var savedMenuType = document.getElementById("selectedMenuItemCategory");178
var currentMenuType = savedMenuType.value 179
180
for (var i=0; i<result.length;i++)181
{182
var menuType = result[i];183
//配置不同的css样式以达到显示出已被选中或者未被选中的目的184
var classStyle = "tabUnselected";185
if (menuType.MenuTypeName == currentMenuType)186
{187
classStyle = "tabSelected";188
}189
//利用字符串拼接来构造出一个由span组成的tab190
var menuTypeHtml = "<a class='" + classStyle + "' href=javascript:ChangeMenuType('" + menuType.MenuTypeName + "');>"191
+ "<span>" + menuType.MenuTypeName + "</span></a>";192
//创建一个span,把刚才的字符串写到其中,构造出tab 193
//这里又动态添加了ChangeMenuType,其定义在后面194
var menuItemTypeElement=document.createElement("span");195
menuItemTypeElement.innerHTML = menuTypeHtml;196
//并且给他部署它应该在的位置 197
menuTypeContainer.appendChild(menuItemTypeElement); 198
}199
}200
function getMenuTypes_onFailed(result)201
{202
var menuTypeList = $get("menuType");203
menuTypeList.innerHTML="Failed Search";204
}205
//这里顾名思义就是比如你从breakfast切换到lunch所执行的206
function ChangeMenuType(menuType)207
{208
//wcf调用209
var service = new DinnerNow.Services.IMenuSearchService();210
var identifier = document.getElementById("restaurantID").innerHTML;211
var selectedMenuType = document.getElementById("selectedMenuItemCategory");212
selectedMenuType.value = menuType;//改变标记,始终让他代表当前选中的餐类型213
//其实就是重新显示对应tab下所属的食物214
service.GetMenuItemsForMenu(identifier,menuType,restaurantSelection_onSuccess,restaurantSelection_onFailed,null);215
service.GetMenuTypes(getMenuTypes_onSuccess, getMenuTypes_onFailed, null);216
}217
//这个就是返回前面的饭店选择218
function returnToRestaurantList_Click()219
{220
DisplayDivContent4("");221
DisplayDiv("SearchResultsDivision");222
}223
224
var menuSort =-1;//这个是排序方法的标记,就是按照饭店名称进行排序,在后面wcf服务中作为参数。225
//这里定义了添加菜到购物车的行为,这些函数都是在动态生成的数据显示中写的226
function AddItemToShoppingCart(description,imageLocation,menuId,menuItemId,name,preparationTime,price)227
{228
var menuItem = new DinnerNow.Business.Data.RestaurantMenuItem();229

230
menuItem.Description = description;231
menuItem.ImageLocation = imageLocation;232
menuItem.MenuId = menuId;233
menuItem.MenuItemId = menuItemId;234
menuItem.Name = name;235
menuItem.PreparationTime = preparationTime;236
menuItem.Price = price;237
//以上是根据wcf规定的的datacontract定义并且赋值了变量238
var restaurant = new DinnerNow.Business.Data.RestaurantHeader();239
240
restaurant.RestaurantId = document.getElementById("restaurantID").innerHTML;241
restaurant.Name = document.getElementById("restaurantName").innerHTML;242
restaurant.LogoImageLocation = document.getElementById("restaurantImage").src;243
//以上是根据wcf规定的的datacontract定义并且赋值了变量244
//上面所做的为的就是调用下面的WCF服务245
DinnerNow.ShoppingCartService.AddItem(menuItem,restaurant,menuSort,addItemToShoppingCart_onSuccess,addItemToShoppingCart_onFailed,null);246
}247
248
function addItemToShoppingCart_onSuccess(result)249
{250
251
_refreshShoppingCart(result);252
}253
254
function addItemToShoppingCart_onFailed(result)255
{256
alert("该菜目无法加入您的菜单");257
}258
259
260
function DeleteItemFromShoppingCart(itemIdentifier)261
{262
DinnerNow.ShoppingCartService.RemoveItem(itemIdentifier,menuSort,deleteItemFromShoppingCart_onSuccess,deleteItemFromShoppingCart_onFailed,null);263
}264
265
function deleteItemFromShoppingCart_onSuccess(result)266
{267
_refreshShoppingCart(result);268
}269
270
function deleteItemFromShoppingCart_onFailed(result)271
{272
alert("菜单无法被删除");273
}274
275
function refreshShoppingCart()276
{277
//根据判断选择的值是多少来,赋予menusort的值,再决定排序278
menuSort = parseInt(document.getElementById ("menuSortOptionList").value);279
//调用wcf服务,刷新购物车280
DinnerNow.ShoppingCartService.RefreshItems(menuSort,refreshShoppingCart_onSuccess,refreshShoppingCart_onFailed,null);281
}282
283
function refreshShoppingCart_onSuccess(result)284
{285
_refreshShoppingCart(result);286
}287
288
function refreshShoppingCart_onFailed(result)289
{290
alert("无法刷新菜单");291
}292
//这个是刷新购物车成功时候的操作293
function _refreshShoppingCart(result)294
{295
296
var shoppingCartContainer = document.getElementById("shoppingCartList");297
shoppingCartContainer.innerHTML = "";298
299
var restaurantId = "";300
var firsth = true;301
302
var html = "";303

304
/******** Shopping Cart Items **********/305
for (var i=0; i<result.length; i++)306
{307
var shoppingCartItem = result[i];308
var subtotal = (shoppingCartItem.Price * shoppingCartItem.Quantity);309

310
var restaurantItemHtml="";311
var endPrevRestaurantItemHtml ="";312
//饭店名称抬头生成313
if (restaurantId != shoppingCartItem.RestaurantIdentifier && menuSort != 1)314
{315
if (!firsth)316
endPrevRestaurantItemHtml = "</table></td></tr>";317
318
firsth = false; 319
restaurantId = shoppingCartItem.RestaurantIdentifier;320
restaurantItemHtml = "<table width='100%' border='0' align='center' cellpadding='4' cellspacing='4' bgcolor='#5686B4' class='thinblueline'><tr><td align='left' bgcolor='#31465B' class='boldWhite'>"321
+ shoppingCartItem.RestaurantName + "</td></tr><tr><td>";322
}323
//饭店所属的购物车中菜单的实体生成324
var shoppingCartHtml = "<table width='100%' border='0' cellspacing='2' cellpadding='2' bgcolor='#5686B4'><tr><td align='left'><a class='noUnderline' href=""javascript:DeleteItemFromShoppingCart('"325
+ shoppingCartItem.MenuItemIdentifier + "');""><img src='images/delete.gif' alt='移除' width='17' height='16'/></a></td><td align='left' width='60%'>"326
+ shoppingCartItem.MenuItemName + "</td><td align='left'><input type='text' id='"327
+ shoppingCartItem.MenuItemIdentifier + "_itemViewQuantityBox' size='2' class='checkOutFormsField' onchange=""updateShoppingCartQuantity('"328
+ shoppingCartItem.MenuItemIdentifier + "');"" value ='"329
+ shoppingCartItem.Quantity + "'></input></td><td align='left' nowrap='nowrap' class='bodyTextWhite'> $"330
+ subtotal + "</td></tr>";331
332
html += endPrevRestaurantItemHtml+restaurantItemHtml+shoppingCartHtml+"</table><br/>";333
}334
/******** Shopping Cart Items **********/335
//生成对应的购物车框336
if (html != "")337
html+="</td></tr></table>";338
339
var shoppingCartElement=document.createElement("span"); 340
shoppingCartElement.innerHTML = html;341
342
shoppingCartContainer.appendChild(shoppingCartElement);343
//重新计算总价344
DinnerNow.ShoppingCartService.Totals(getTotals_onSuccess, getTotals_onFailed,null);345
}346
//当ajax应用成功时候显示总价和预计送达时间的功能347
function getTotals_onSuccess(result)348
{349
var shoppingCartTotalContainer = document.getElementById("shoppingCartTotals");350
shoppingCartTotalContainer.innerHTML = "";351
352
var checkout ="";353
if (result[0] != "$0.00")354
checkout = "Checkout.aspx";355
//这里又再次利用前面多次出现的方法,“画”出了购物车的样子356
var shoppingCartTotalHtml = "<table width='100%' border='0' cellspacing='2' cellpadding='4'><tr><td width='22%' align='right' class='boldWhite'>Total:</td><td id='Td1' width='78%' class='boldWhite'>"357
+ result[0] + "</td></tr><tr><td align='right' class='boldWhite'>ETA:</td><td class='bodyTextWhite'>"358
+ result[1] + "</td></tr><tr><td> </td><td align='right'><a id='itemListCheckoutButton' href='"359
+ checkout + "'><img src='images/Checkoutbutton.gif' border='0'/></a></td></tr></table>";360

361
var shoppingCartTotal=document.createElement("span");362
shoppingCartTotal.innerHTML = shoppingCartTotalHtml;363
364
shoppingCartTotalContainer.appendChild(shoppingCartTotal);365
}366
367
function getTotals_onFailed(result)368
{369
alert("无法获得总价");370
}371
//这个函数是在动态生成的代码中用到的372
function updateShoppingCartQuantity(menuItemId)373
{374
375
var newQuantity = parseInt(document.getElementById(menuItemId+"_itemViewQuantityBox").value);376
DinnerNow.ShoppingCartService.UpdateQuantity(menuItemId, newQuantity, menuSort, updateShoppingCartQuantity_onSuccess, updateShoppingCartQuantity_onFailed,null);377
}378
379
function updateShoppingCartQuantity_onSuccess(result)380
{381
_refreshShoppingCart(result);382
}383
384
function updateShoppingCartQuantity_onFailed(result)385
{386
alert("无法改变所选菜目的数量");387
}388
//这个ExecuteTrigger函数是在模板页中调用的是外部文件,函数具体是这样的389
//function ExecuteTrigger(triggerId)390
//{391
// var trigger = document.getElementById(triggerId);392
// if (trigger != null)393
// {394
// trigger.click();395
// } 396
//}397
function SelectCurrentMenu()398
{399
// Raise a click event for a hidden link on this form, so we cause a post-back400
ExecuteTrigger("currentMenuTrigger.ClientID");401
}402
403
function SelectPreviousMenus()404
{405
// Raise a click event for a hidden link on this form, so we cause a post-back406
ExecuteTrigger("previousOrdersTrigger.ClientID");407
}408
409
410
</script>411

412
<div id="SearchResultsDivision">413
<!--style="display:none;">-->414
<input id="selectedRestaurantIdentifier" type="hidden" runat="server" value="" />415
<span id="restaurantID" style="display: none"></span>416
<br />417
<span class="boldDarkBlue">418
<asp:Label runat="server" ID="searchResultsLabel" />419
</span>420
<br />421
<br />422
<!-- Restaurant list goes here-->423
<div id="restaurantList">424
</div>425
</div>426
<div id="MenuDivision" style="display: none;">427
<input id="selectedMenuItemCategory" type="hidden" value="" />428
<input id="selectedMenuItem" type="hidden" runat="server" value="" />429
<br />430
<div id="restaurantSelected">431
<div class="restaurantNavHeader">432
<div class="restaurantNavHeaderLeft">433
<span class="boldBlue">Your Selected Restaurant Menu</span>434
</div>435
<div class="restaurantNavHeaderRight">436
<input name="backToList" type="button" class="formbuttonBlue" value="Back To Restaurant List"437
onclick="returnToRestaurantList_Click();" />438
</div>439
</div>440
<br />441
<div class="restaurantDescription">442
<div class="restaurantDescriptionLeft">443
<span>444
<img id="restaurantImage" src="" width="154" height="90" alt="Restaurant Logo" /></span>445
</div>446
<div class="restaurantDescriptionRight">447
<span id="restaurantName" class="boldGreen"></span>448
<br />449
<span id="restaurantDescription"></span>450
<br />451
<br />452
<a id='restaurantMenuFeed' href="">453
<img src='images/rss.gif' alt='RSS' align='middle' border='0' /></a> Receive454
updates to the menu455
</div>456
</div>457
</div>458
<br />459
<!-- Menu Type (lunch, breakfast etc) go here -->460
<div id="menuTypeListTab" class="tabUnselected">461
</div>462
<!-- Menu items list goes here-->463
<div id="menuList">464
</div>465
</div>466
</asp:Content>467
<asp:Content ID="Content4" ContentPlaceHolderID="RightMenuPlaceHolder" runat="Server">468

469
<script type="text/javascript">470
var _divsCt4 = ["shoppingCart"];471
function DisplayDivContent4(divName)472
{473
for (var i=0; i <_divsCt4.length; i++)//这里的length=1,就是数据的大小,但是应该可以有很多个,对于不同的饭店。。有点不明白474
{475
document.getElementById(_divsCt4[i]).style.display = 476
(_divsCt4[i]==divName) ? "block": "none";477
}478
}479
</script>480

481
<input type="hidden" id="selectedOrder" value="" runat="server" />482
<div id="shoppingCart" class="cartDetailsBox">483
<!--visible="false"-->484
<div>485
<span>Your Menu Today</span> <span>486
<select id="menuSortOptionList" onchange="refreshShoppingCart();" visible="true">487
<option value="-1">Sort Menu By ------></option>488
<option value="0">Restaurant</option>489
<option value="1">Name</option>490
</select></span>491
<!-- Shopping Cart list goes here-->492
<div id="shoppingCartList">493
</div>494
<!-- Shopping Cart totals goes here-->495
<div id="shoppingCartTotals">496
</div>497
<div>498
</div>499
</div>500
</div>501
</asp:Content>502

这里的Html语言麻烦点的就是你要对其中的位置要了然于胸,否则,看着代码,看着看着就糊涂。完全分析下来还是很多的。但是从原理上来说却不难,说穿了,无非就是WCF调用,然后再利用JavaScript动态的写下页面元素。不过,真的自己写起来,估计也不会是容易的事情,另外对应的cs文件觉得说的价值不大。
好了,就这些了,这篇主要是写关于dinnernow中的AJAX应用的。希望对大家有用,另外其中有错误的还望大家海涵并指正。
作者:AnyKoro
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号