在本章的最后,我们来讲解图片的浏览和编辑模块,你可能很奇怪,与其他教程不同,我将表面上看起来应该首先讲解的部分放在了最后。这里我的理由有二:第一是,在这种系统中,图片的浏览和编辑实际上是建立在用户模块和上传模块之后的,也就是说,你只有注册用户和上传图片后,才能比较方便的进行这些操作。第二则是,通过前面的章节,你应当对显示数据和编辑数据有所了解,因此相对于前面几节,这一节不是本章重点,我会讲解的比较简略。
系统首页我们调用了热门和最新图片列表,其效果如图8.15所示。
图8.15
这部分代码比较简单,我们来看default.asp文件中显示热门图片部分的代码:
<ul class="photo-list">
<%
'取出浏览量前5的图片
sql = "SELECT TOP 5 Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName FROM [Photo] " & _
" LEFT JOIN [ShareUser] ON Photo.UserID = ShareUser.UserID" & _
" WHERE PhotoPermission = '公开'" & _
" Order By PhotoClick DESC,PhotoID DESC"
'打开记录集
oRs.Open sql,oConn,1,1
'遍历记录集并显示图片
For i = 1 To oRs.RecordCount
'调用ShowPhotoThumb显示图片的缩略图
ShowPhotoThumb oRs("PhotoID"),oRs("PhotoName"),oRs("PhotoSourceUrl"),oRs("UserNickName"),oRs("PhotoAddTime")
oRs.MoveNext
Next
oRs.Close
%>
</ul>
程序使用了一个看起来很长的SQL语句用于打开记录集,没有关系,我们对其进行一些分析:
首先,选取的字段是:
Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName
除非必要,我们不应当使用SELECT * 来选取数据表中的所有字段,选取必要的字段有利于节省服务器的内存资源。
而后,我们使用了JOIN链接,在取出图片时同时取出上传图片的用户的相应信息。
同时,我们指定了选取条件是PhotoPermission为“公开”,即用户上传时指定可以公开的图片。
最后,记录集的排列方式为按照点击数从大到小排列。
请你注意,这里我们的Order By子句同时指定了两个排列条件,这时因为在使用TOP N的选取限制语句时,如果排列条件中有相等值,则会出现结果数目超出N的现象。例如,如果在点击量前15个图片中,有两个图片的点击量是相同的,则实际上记录集会取出16个记录,但是在我们的语句中,同时指定了按PhotoID排列,则由于PhotoID不会重复,因此不会出现这种现象。
选取最新图片部分的代码与此类似,这里不再详述。
[NextPage]
图片列表浏览是通过页面list.asp文件来实现的,在这个文件中,将可以以随机、指定相册、指定用户ID、指定TAG标签四种方式进行浏览。
总体来看,list.asp要完成的任务非常简单,就是打开记录集,从Photo表中选取记录,并且分页显示。但是本页面的特点在于,它可以以四种方式进行浏览,而这四种方式浏览的不同,则主要在于打开记录集时所使用的SQL语句的不同,因此我们在这里设计了一个“GetTypeAndMakeSQL”过程,此过程通过获取用户指定的相应参数,来生成相应的SQL语句。
GetTypeAndMakeSQL过程代码如下:
Sub GetTypeAndMakeSQL(ByRef strOpType, ByRef strOpName, ByRef strSQL)
Dim sRequestString
'获得操作类型和名称
sRequestString = UCase(Trim(Request.ServerVariables("QUERY_STRING") & ""))
If sRequestString = "" Then
strOpType = "RADOM"
strOpName = "随机展示"
ElseIf InStr(sRequestString,"ALBUMID") > 0 Then
strOpType = "ALBUMID"
strOpName = "相册展示"
ElseIf InStr(sRequestString,"USERID") > 0 Then
strOpType = "USERID"
strOpName = "用户展示"
ElseIf InStr(sRequestString,"TAG") > 0 Then
strOpType = "TAG"
strOpName = "标签展示"
Else
strOpType = "RADOM"
strOpName = "随机展示"
End If
'根据类型生成SQL语句
Select Case UCase(strOpType)
Case "RADOM"
strSQL = "SELECT TOP 50 Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName FROM [Photo] " & _
" LEFT JOIN [ShareUser] ON Photo.UserID = ShareUser.UserID" & _
" Order By Rnd(PhotoID)"
Case "ALBUMID"
strSQL = "SELECT Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName FROM [Photo] " & _
" LEFT JOIN [ShareUser] ON Photo.UserID = ShareUser.UserID" & _
" WHERE AlbumID=" & CLng(Request.QueryString("AlbumID")) & _
" Order By PhotoID DESC"
Case "USERID"
strSQL = "SELECT Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName FROM [Photo] " & _
" LEFT JOIN [ShareUser] ON Photo.UserID = ShareUser.UserID" & _
" WHERE Photo.UserID=" & CLng(Request.QueryString("UserID")) & _
" Order By PhotoID DESC"
Case "TAG"
strSQL = "SELECT Photo.PhotoID,Photo.PhotoName,Photo.PhotoSourceUrl,Photo.PhotoAddTime,ShareUser.UserNickName FROM [Photo] " & _
" LEFT JOIN [ShareUser] ON Photo.UserID = ShareUser.UserID" & _
" WHERE PhotoTags LIKE '%," & Request.QueryString("Tag") & ",%'" &_
" Order By PhotoID DESC"
End Select
End Sub
此过程整体分为两个部分,第一部分是判断当前用户要浏览的类型,第二部分是根据类型和用户的QueryString参数来生成SQL语句。
在第一部分中,我们依次用Instr语句来判断整体的QueryStirng串中是否包含相应的指定类型的字符串。
而在第二部分,我们使用Select…Case语句来根据strOpType变量的值,进入不同的分支生成SQL语句。
那么,我们的各个变量既然生成了,又怎么传递到过程外部呢。
在这里我们使用了VBScript过程参数的前缀ByRef,即以饮用方式传递变量,此时你在过程内部对变量的操作,将实现在调用过程外部的脚本环境中。
了解了本页面的重点过程,其他部分就比较简单了:
页面头部首先调用过程,生成SQL语句等变量:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%>
<%Option Explicit%>
<!--#include file="conn.html" -->
<!--#include file="include/function.html" -->
<!--#include file="include/def/list.html" -->
<!--#include file="include/def/album.html" -->
<%
Dim sOpType,sOpName
Dim oRs,sql,i
Dim lPageCount,lRecordCount,lCurPage,lPerPage
'调用GetTypeAndMakeSQL过程生成SQL语句
GetTypeAndMakeSQL sOpType,sOpName,sql
'建立记录集对象的实例oRs
Set oRs = Server.CreateObject("ADODB.RecordSet")
%>
而后程序进行分页显示操作:
<ul class="photo-list">
<%
'打开记录集
oRs.Open sql,oConn,1,1
If oRs.EOF AND oRs.BOF Then '如果记录集为空
Response.Write("还没有记录!")
Else
'处理分页
If sOpType <> "RADOM" Then '当不是随机方式时,进行分页处理
lPerPage = 30 '每页30个
lRecordCount = oRs.RecordCount '获得总记录数
oRs.PageSize = lPerPage '设定每页记录数目
lPageCount = oRs.PageCount '获得总页数
'获得并处理当前请求页数
lCurPage = Trim(Request.QueryString("p"))
If lCurPage = "" Then lCurPage = 1
If IsNumeric(lCurPage) = False Then lCurPage = 1
If CLng(lCurPage) < 1 Or CLng(lCurPage) > lPageCount Then lCurPage = 1
oRs.AbsolutePage = lCurPage '设定当前是第几页
End If
i = 0 '初始化计数变量
Do While Not oRs.Eof '当记录集不为空时
'如果不是随机方式显示,则需要注意当前显示个数小于每页要显示的记录数
If sOpType <> "RADOM" Then
If i > lPerPage Then Exit Do '如果计数变量大于每页记录集,则退出循环
End If
'调用ShowPhotoThumb过程显示图片
ShowPhotoThumb oRs("PhotoID"),oRs("PhotoName"),oRs("PhotoSourceUrl"),oRs("UserNickName"),oRs("PhotoAddTime")
oRs.MoveNext '下移指针
i = i + 1 '计数变量加1
Loop
End If
oRs.Close
%>
</ul>
<%
If sOpType <> "RADOM" Then '如果不是随机方式,则显示分页导航
%>
<p style="clear:both; margin:0 5px; padding:2px; text-align:center">分页:
<%showPageNav lCurPage,lPageCount,sOpType & "=" & Request.QueryString(sOpType)%>
</p>
<%
End If
%>
[NextPage]
在图片列表页中点击图片的链接,将进入view.asp文件中,同时通过QueryString传递图片的编号,显示图片详情。如图8.16所示。
图8.16
此文件表面上的处理过程是这样的:ASP获取相应图片的信息→保存在变量中→HTML调用相应变量。但是实际上,我们使用prototype+ script.aculo.us来实现了一个“InPlaceEditor”功能,此功能是出现在Web 2.0类网站上方便用户对信息进行即时编辑的一个效果,你可以翻阅前面的JavaScript框架部分进行复习。
如图8.16所示的界面,在应用了InPlaceEditor效果后,当你点击图片名称时,会发现此部分变为了一个文本框,你可以进行编辑,而后点击“确定”,进行数据库的更新,如图8.17所示。
图8.17
实现这部分,我们可以通过JavaScript脚本来对相应的元素应用InPlaceEditor效果。
先来看实际的代码,页面头部获取图片信息的代码:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="936"%>
<%Option Explicit%>
<!--#include file="conn.html" -->
<!--#include file="include/function.html" -->
<!--#include file="include/def/album.html" -->
<%
'……省略定义变量部分
'获取图片编号
lPhotoID = Trim(Request.QueryString("PhotoID"))
'建立并打开记录集,取出图片信息
Set oRs = Server.CreateObject("ADODB.RecordSet")
sql = "SELECT Photo.*,Album.AlbumName,Album.AlbumCover FROM [Photo] LEFT JOIN [Album] ON Photo.AlbumID = Album.AlbumID " & "WHERE PhotoID = " & lPhotoID
oRs.Open sql,oConn,3,3
If oRs.EOF AND oRs.BOF Then '如果记录集为空
CloseDb() '关闭相应对象,回收资源
ShowError "图片不存在或者已经被删除!" '提示错误信息
Response.End()
End If
'如果图片被设为因此,且当前浏览用户不是图片主人
If oRs("PhotoPermission")="隐私" AND (IsCurUser(oRs("UserID"))=False) Then
CloseDb()
ShowError "图片被作者设为隐私,不允许被查看!"
Response.End()
End If
'获取图片详情
sPhotoName = oRs("PhotoName")
sPhotoContent = oRs("PhotoContent")
sPhotoUrl = oRs("PhotoSourceUrl")
lUserID = oRs("UserID")
sPhotoPermission = oRs("PhotoPermission")
sPhotoTags = oRs("PhotoTags")
lAlbumID = oRs("AlbumID")
sAlbumName = oRs("AlbumName")
sAlbumCover = oRs("AlbumCover")
lPhotoRateStars = oRs("PhotoVoteScore") / oRs("PhotoVoteTotal") '总分除以打分人数
oRs("PhotoClick") = oRs("PhotoClick") + 1 '浏览量加1
'去掉加入数据库时标签两侧加入的格式化作用的,号
sPhotoTags = Left(sPhotoTags,Len(sPhotoTags)-1)
sPhotoTags = Right(sPhotoTags,Len(sPhotoTags)-1)
'更新和关闭记录集
oRs.Update
oRs.Close
Set oRs = Nothing
%>
这里与一般的读取记录集中某条记录的各字段值的过程是类似的,但是有两点不同:
第一点是,首先对图片的权限进行了判断,如果图片的浏览权限被设为隐私,那么就要通过函数IsCurUser来检测图片主人是不是当前登录的用户,如果是,则可以显示,否则提示“图片被作者设为隐私,不允许被查看!”的错误信息。
第二点是,我们将字段PhotoClick的值加一,并更新记录集,以实现图片点击数的计数操作。
而后面实现InPlaceEditor的JavaScript代码如下:
<%If IsCurUser(lUserID) Then%>
<script type="text/javascript">
//建立图片名称的InPlaceEditor
new Ajax.InPlaceEditor($('PhotoName'), 'op.asp?PhotoID=<%=lPhotoID%>&type=PhotoName', {
submitOnBlur: false,
okButton: true,
cancelLink: true,
okText: '确认修改',
cancelText: '取消',
savingText: '正在保存...',
clickToEditText: '点击这里修改名称',
ajaxOptions: {method: 'get'}
});
//建立图片介绍的InPlaceEditor
new Ajax.InPlaceEditor($('PhotoContent'), 'op.asp?PhotoID=<%=lPhotoID%>&type=PhotoContent', {
submitOnBlur: false,
okButton: true,
cancelLink: true,
okText: '确认修改',
cancelText: '取消',
savingText: '正在保存...',
clickToEditText: '点击这里修改简介',
rows: 5,
cols: 25,
ajaxOptions: {method: 'get'}
});
//建立图片Tag的InPlaceEditor
new Ajax.InPlaceEditor($('PhotoTags'), 'op.asp?PhotoID=<%=lPhotoID%>&type=PhotoTags', {
submitOnBlur: false,
okButton: true,
cancelLink: true,
okText: '确认修改',
cancelText: '取消',
savingText: '正在保存...',
clickToEditText: '点击这里修改Tags',
ajaxOptions: {method: 'get'}
});
//建立图片公开/隐私的InPlaceEditor
//注意这里是InPlaceCollectionEditor
new Ajax.InPlaceCollectionEditor(
'PhotoPermission', 'op.asp?PhotoID=<%=lPhotoID%>&type=PhotoPermission', {
collection: ['公开','隐私'],
okText: '确认修改',
cancelText: '取消',
savingText: '正在保存...',
clickToEditText: '点击这里修改隐私许可',
ajaxOptions: {method: 'get'}
});
</script>
<%End If%>
你可以看到,仅当前登录的用户是图片的主人时,才会输出下面的JavaScript代码。在JavaScript代码中我们将所有的图片编辑的处理过程都交由op.asp文件进行处理,在处理时通过PhotoID的QueryString变量传递图片编号,通过type的QueryString变量传递要处理的类型,即,要编辑图片的哪个信息。
Op.asp文件的处理,请看下一节图片编辑部分中多介绍。
[NextPage]
在上一节中,我们讲到InPlaceEditor的ajax处理页面是op.asp页,本节对这个页面进行分析讲解,当然,这个页面是不存在显示界面的,它只由view.asp文件中实现ajax的JavaScript调用分析。
首先来看此文件代码:
<%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<%Option Explicit%>
<!--#include file="conn.html" -->
<!--#include file="include/function.html" -->
<%
'……省略变量定义
'获取图片编号和操作类型
lPhotoID = Trim(Request.QueryString("PhotoID"))
sOpType = UCase(Trim(Request.QueryString("type")))
'建立和打开记录集,并取出图片记录
Set oRs = Server.CreateObject("ADODB.RecordSet")
sql = "SELECT * FROM [Photo] WHERE PhotoID = " & Clng(lPhotoID)
oRs.Open sql,oConn,1,3
If oRs.EOF AND oRs.BOF Then '如果记录集为空,则提示图片不存在
oRs.Close
Set oRs = Nothing
oConn.Close
Set oConn = Nothing
ShowError "这张图片不存在!"
Response.End()
End If
'下面开始各操作的处理部分
'不需要是图片主人的操作:
'评分
Select Case sOpType
Case "RATESTAR"
Dim lScore,lPhotoVoteScore,lPhotoVoteTotal
lScore = CLng(Request.QueryString("value"))
If lScore <=5 And lScore >=1 Then
lPhotoVoteScore = oRs("PhotoVoteScore") + lScore
lPhotoVoteTotal = oRs("PhotoVoteTotal") + 1
oRs("PhotoVoteScore") = lPhotoVoteScore
oRs("PhotoVoteTotal") = lPhotoVoteTotal
oRs.Update
oRs.Close
Set oRs = Nothing
oConn.Close
Set oConn = Nothing
Response.Write lPhotoVoteScore / lPhotoVoteTotal
Response.End
End If
End Select
'图片主人才可以进行的操作:
'修改名称
'修改简介
'修改隐私
'********
'修改标签
'删除
If IsCurUser(oRs("UserID")) Then '判断,如果当前用户是图片主人
Select Case sOpType
'修改名称
'修改简介
'修改隐私
Case "PHOTONAME","PHOTOCONTENT","PHOTOPERMISSION"
oRs(sOpType) = Trim(Request.QueryString("value"))
oRs.Update
'修改标签
Case "PHOTOTAGS"
Dim sOldTags,sNewTags
'从数据库获得旧标签
sOldTags = oRs("PhotoTags")
'从用户输入获得新标签
sNewTags = Trim(Request.QueryString("value"))
'将新标签更新到数据库
oRs(sOpType) = sNewTags
oRs.Update
'删除标签表中的旧标签
DelTags(sOldTags)
'新增标签表中的新标签
SaveTags(sNewTags)
'删除
Case "DELETE"
'删除文件
Dim oFSO
Set oFSO = Server.CreateObject("Scripting.FileSystemObject")
oFSO.DeleteFile Server.MapPath(oRs("PhotoSourceUrl"))
Set oFSO = Nothing
'删除图片的标签
DelTags(oRs("PhotoTags"))
'删除该图片记录
oRs.Delete()
'关闭和清空记录集和数据连接
oRs.Close
Set oRs = Nothing
oConn.Close
Set oConn = Nothing
ShowSuccess "这张图片已经删除成功!"
End Select
Else '如果当前用户不是图片主人
'关闭和清空记录集和数据库链接并提示错误信息
oRs.Close
Set oRs = Nothing
oConn.Close
Set oConn = Nothing
ShowError "您不是这张图片的主人!"
End If
CloseDb()
Response.Write(Trim(Request.QueryString("value")))
'保存标签的过程
Sub SaveTags(ByVal strTags)
If strTags = "" Then Exit Sub
Dim aTags,sTagElement
Dim oRsTag,sqlTag
'获得和处理标签
strTags = Replace(strTags,",",",")
strTags = Replace(strTags," ",",")
strTags = Replace(strTags,"|",",")
aTags = Split(strTags,",")
'建立和打开记录集
Set oRsTag = Server.CreateObject("ADODB.RecordSet")
'对每一个标签,遍历
For Each sTagElement In aTags
'打开记录集以判断是否存在标签
sqlTag = "SELECT * FROM [Tag] WHERE TagName = '" & sTagElement & "'"
oRsTag.Open sqlTag,oConn,1,3
If oRsTag.EOF AND oRsTag.BOF Then '不存在则创建标签
oRsTag.AddNew()
oRsTag("TagName") = sTagElement
oRsTag("TagCount") = 1
Else '存在则为其使用次数加1
oRsTag("TagCount") = oRsTag("TagCount") + 1
End If
更新和关闭记录集
oRsTag.Update
oRsTag.Close
Next
Set oRsTag = Nothing
End Sub
'删除标签过程
Sub DelTags(ByVal strTags)
If strTags = "" Then Exit Sub
Dim aTags,sTagElement
Dim oRsTag,sqlTag
'获得和处理标签
strTags = Replace(strTags,",",",")
strTags = Replace(strTags," ",",")
strTags = Replace(strTags,"|",",")
aTags = Split(strTags,",")
'打开记录集以判断是否存在标签
Set oRsTag = Server.CreateObject("ADODB.RecordSet")
For Each sTagElement In aTags
sqlTag = "SELECT * FROM [Tag] WHERE TagName = '" & sTagElement & "'"
oRsTag.Open sqlTag,oConn,1,3
If Not(oRsTag.EOF AND oRsTag.BOF) Then '如果记录集不为空,则存在标签
If oRsTag("TagCount") = 1 Then '如果标签使用次数为1,则删除它
oRsTag.Delete()
Else '否则将其使用次数减1
oRsTag("TagCount") = oRsTag("TagCount") - 1
End If
oRsTag.Update
End If
oRsTag.Close
Next
Set oRsTag = Nothing
End Sub
%>
在这个文件中,首先获取通过QueryString传递来的图片编号和编辑类型,而后打开记录集,取出相应图片的记录。
根据编辑相应信息所需权限的不同,在进行具体处理部分共有两个分支,他们之间是并行的,首先是不需要确认当前登录用户是图片的主人的操作,主要是对图片的评分操作,而后则是仅有图片主人能够进行的操作,这部分的Select…Case语句分支处理,主要有三类,第一类是对图片基本信息的编辑,第二类是修改标签,第三类是删除图片。
之所以这样分类,理由如下:对图片基本信息的编辑,仅需简单设定记录集中相应的字段即可,而对图片标签的修改,则需要进行复杂的标签
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛