DiscuzNT使用Silverlight进行多文件上传(下)

2016-08-20 10:49:23来源:http://daizhj.blog.51cto.com/285189/147173作者:daizhenjun人点击



如果当前用户通过验证,就可以通过SL上传附件了,因为用户上传的附件要进行实时统计,以即时更新已上传附件的总和大小,来防止用户上传过量的附件),所以我在打开文件对话框事件中加入了到已上传附件大小的统计以便进行控件:
///<summary>///选择文件对话框事件///</summary>///<paramname="sender"></param>///<paramname="e"></param>privatevoidSelectFilesButton_Click(objectsender,RoutedEventArgse){if(AttachmentList.Count>=_maxAttachments){ShowMessageBox("/r/n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");return;}OpenFileDialogofd=newOpenFileDialog();ofd.Multiselect=true;try{if(!string.IsNullOrEmpty(_fileFilter))ofd.Filter=_fileFilter;}catch(ArgumentExceptionex){ShowMessageBox("错误的文件过滤配置:"+ex.Message);}if(ofd.ShowDialog()==true){if(filecount==0)filecount=AttachmentList.Count;foreach(FileInfofileinofd.Files){if((filecount+1)>_maxAttachments){ShowMessageBox("/r/n您上传的文件数已达到系统规定的上限:"+_maxAttachments+".");return;}filecount++;stringfileName=file.Name;UserFileuserFile=newUserFile();userFile.FileName=file.Name;userFile.FileStream=file.OpenRead();userFile.ViewStream=file.OpenRead();//总上传值在规定范围内时if(_todayAttachSize<(_todayUploadSize+_wantUploadSize+userFile.FileStream.Length)){ShowMessageBox("/r/n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)+"MB,而今天还可以上传:"+Math.Round((decimal)(_todayAttachSize-_todayUploadSize)/1024/1024,2)+"MB.");break;}//当单个文件大小大于最大上传附件尺寸时if(userFile.FileStream.Length>_maxFileSize){ShowMessageBox("/r/n当前附件大小:"+Math.Round((decimal)userFile.FileStream.Length/1024/1024,2)+"MB,而单个附件允许最大尺寸为:"+Math.Round((decimal)_maxFileSize/1024/1024,2)+"MB./r/n");break;}//向文件列表中添加文件信息_files.Add(userFile);_wantUploadSize+=userFile.FileStream.Length;}}}
这样就从选择附件方面杜绝了上述情况的发生。
之后,当用户选择了上传的附件,并加载到上传列表后点击上传按钮时,SL会将当前要上传的文件进行切块(4 * 4096 byte),并分块上传,代码如下:

///<summary>///上传文件///</summary>privatevoidUploadAdvanced(){byte[]buffer=newbyte[4*4096];intbytesRead=_file.FileStream.Read(buffer,0,buffer.Length);//文件是否上传完毕?if(bytesRead!=0){_dataSent+=bytesRead;if(_dataSent==_dataLength)_lastChunk=true;//是否是最后一块数据,这样WCF会在服务端根据该信息来决定是否对临时文件重命名//上传当前数据块_client.StoreFileAdvancedAsync(_file.FileName,buffer,bytesRead,_initParams,_firstChunk,_lastChunk,Utils.GetCredentialInfo());//在第一条消息之后一直为false_firstChunk=false;//通知上传进度修改OnProgressChanged();}else{//当上传完毕后_file.FileStream.Dispose();_file.FileStream.Close();_client.ChannelFactory.Close();}}

注意上面的StoreFileAdvancedAsync方法就是要请求的服务端代码,下面即是其服务端代码:

///<summary>///上传附件///</summary>///<paramname="fileName">文件名称</param>///<paramname="data">上传的字节数据</param>///<paramname="dataLength">数据长度</param>///<paramname="parameters">上传参数</param>///<paramname="firstChunk">是否第一块数据</param>///<paramname="lastChunk">是否最后一块数据</param>[WebMethod]publicAttachmentInfoStoreFileAdvanced(stringfileName,byte[]data,intdataLength,stringparameters,boolfirstChunk,boollastChunk,CredentialInfocreinfo){if(AuthenticateUser(creinfo)){UploadSetInfouploadSetInfo=GetAttachmentUploadSet(creinfo);stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();if(uploadSetInfo.CanPostAttach&&uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)>=0&&uploadSetInfo.AttachSize>dataLength&&Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage)){stringuploadFolder=GetUploadFolder(fileName,creinfo.ForumID.ToString());stringtempFileName=fileName+_tempExtension;if(firstChunk){//删除临时文件if(File.Exists(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName))File.Delete(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName);//删除目录文件if(File.Exists(uploadFolder+"/"+fileName))File.Delete(uploadFolder+"/"+fileName);}FileStreamfs=File.Open(@HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName,FileMode.Append);fs.Write(data,0,dataLength);fs.Close();if(lastChunk){File.Move(HostingEnvironment.ApplicationPhysicalPath+"/upload/temp/"+tempFileName,uploadFolder+"/"+fileName);returnDiscuz.Forum.Attachments.GetAttachmentInfo(AddAttachment(fileName,creinfo));}}}returnnull;}

上面代码会将客户端发送过来的分块数据进行组装到临时文件中,当该文件的所有分块数据传输完毕,就会将该临时文件移动到指定的附件文件夹中,同时删除
相应临时数据。大家注意到了,在该方法开始部分还调用了AuthenticateUser方法(之前说明),这主要就是对安全性的考虑,必定HTTP是
一种无状态协议呀。
上面的代码中这一行判断:
if(uploadSetInfo.CanPostAttach&&uploadSetInfo.AttachExtensionsNoSize.IndexOf(fileextname)>=0&&uploadSetInfo.AttachSize>dataLength&&Utils.StrIsNullOrEmpty(uploadSetInfo.ErrMessage))

即是对当前用户上传信息(包括已上传附件大小,数量等)进行检验,以免出现上传数据超过系统限制的情况。
在该方法的最后一行,会调用AddAttachment(fileName,
creinfo)来进行相应附件信息的初始化绑定,因为论坛中每个主题包括回帖都可以有附件,只不过对附件的扩展名和大小会有限制,所以这里通过该方法进行封装,下面是其核心代码:

///<summary>///添加附件///</summary>///<paramname="fileName">文件名称</param>///<paramname="creinfo">认证信息</param>///<returns>返回当前插入的附件id</returns>privateintAddAttachment(stringfileName,CredentialInfocreinfo){stringUploadDir=GetUploadFolder(fileName,creinfo.ForumID.ToString());AttachmentInfoattachmentinfo=newAttachmentInfo();stringfileextname=Utils.CutString(fileName,fileName.LastIndexOf(".")+1).ToLower();stringnewfilename=(Environment.TickCount&int.MaxValue).ToString()+newRandom().Next(1000,9999)+"."+fileextname;try{//如果是bmpjpgpng图片类型if((fileextname=="bmp"||fileextname=="jpg"||fileextname=="jpeg"||fileextname=="png")){if(Discuz.Common.Utils.FileExists(UploadDir+fileName)){System.Drawing.Imageimg=System.Drawing.Image.FromFile(UploadDir+fileName);if(config.Attachimgmaxwidth>0&&img.Width>config.Attachimgmaxwidth)attachmentinfo.Sys_noupload="图片宽度为"+img.Width.ToString()+",系统允许的最大宽度为"+config.Attachimgmaxwidth.ToString();if(config.Attachimgmaxheight>0&&img.Height>config.Attachimgmaxheight)attachmentinfo.Sys_noupload="图片高度为"+img.Width.ToString()+",系统允许的最大高度为"+config.Attachimgmaxheight.ToString();if(config.Watermarkstatus==0)attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;else{if(config.Watermarktype==1&&File.Exists(Utils.GetMapPath(BaseConfigs.GetForumPath+"watermark/"+config.Watermarkpic)))Discuz.Forum.ForumUtils.AddImageSignPic(img,UploadDir+newfilename,Utils.GetMapPath(BaseConfigs.GetForumPath+"watermark/"+config.Watermarkpic),config.Watermarkstatus,config.Attachimgquality,config.Watermarktransparency);else{stringwatermarkText;watermarkText=config.Watermarktext.Replace("{1}",config.Forumtitle);watermarkText=watermarkText.Replace("{2}","http://"+DNTRequest.GetCurrentFullHost()+"/");watermarkText=watermarkText.Replace("{3}",Utils.GetDate());watermarkText=watermarkText.Replace("{4}",Utils.GetTime());Discuz.Forum.ForumUtils.AddImageSignText(img,UploadDir+newfilename,watermarkText,config.Watermarkstatus,config.Attachimgquality,config.Watermarkfontname,config.Watermarkfontsize);}System.IO.File.Delete(UploadDir+fileName);//获得加水印后的文件长度attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;}}}else{System.IO.File.Move(UploadDir+fileName,UploadDir+newfilename);attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;}}catch{}if(Discuz.Common.Utils.FileExists(UploadDir+fileName)){attachmentinfo.Filesize=newFileInfo(UploadDir+fileName).Length;attachmentinfo.Filename=GetDirInfo(fileName,creinfo.ForumID.ToString())+fileName;}if(Discuz.Common.Utils.FileExists(UploadDir+newfilename)){attachmentinfo.Filesize=newFileInfo(UploadDir+newfilename).Length;attachmentinfo.Filename=GetDirInfo(newfilename,creinfo.ForumID.ToString())+newfilename;}attachmentinfo.Uid=creinfo.UserID;attachmentinfo.Description=fileextname;attachmentinfo.Filetype=GetContentType(fileextname);attachmentinfo.Attachment=fileName;attachmentinfo.Downloads=0;attachmentinfo.Postdatetime=DateTime.Now.ToString();attachmentinfo.Sys_index=0;returnDiscuz.Data.DatabaseProvider.GetInstance().CreateAttachment(attachmentinfo);}

通过上面的方法就实现了将附件与相应的主题进行绑定功能同时为相应的图片附件加上水印。
到这里,主要的代码就介绍的差不多了。 当用户完成上传之后,点击“返回”按钮时,会触发下面事件:

///<summary>///返回按钮事件///</summary>///<paramname="sender"></param>///<paramname="e"></param>privatevoidFinishUpload_Click(objectsender,RoutedEventArgse){GetAttachmentList();}[ScriptableMember]publicvoidGetAttachmentList(){StringBuildersb_attachments=newStringBuilder();sb_attachments.Append("[");foreach(AttachmentInfoattachmentInfoinAttachmentList){sb_attachments.Append(string.Format("{{'aid':{0},'attachment':'{1}','description':'{2}','filename':'{3}','filesize':{4},'filetype':'{5}','Uid':{6}}},",attachmentInfo.Aid,attachmentInfo.Attachment,attachmentInfo.Description.Trim(),attachmentInfo.Filename.Trim(),attachmentInfo.Filesize,attachmentInfo.Filetype,attachmentInfo.Uid));}if(sb_attachments.ToString().EndsWith(","))sb_attachments.Remove(sb_attachments.Length-1,1);sb_attachments.Append("]");//调用js端注册事件javaScriptableObject.OnUploadAttchmentList(JsonCharFilter(sb_attachments.ToString()));}


GetAttachmentList方法会调用页面的JS事件并将“已上传”的数据发给WEB页面,而相应的页面事件绑定代码如下(文件位于Discuz.Web/templates/default_postattachments.htm):
functiononLoad(plugin,userContext,sender){//只读属性,标识Silverlight插件是否已经加载。if(sender.getHost().IsLoaded){$("MultiUploadFile").content.JavaScriptObject.UploadAttchmentList=getAttachmentList;}}//获取silverlight插件已经上传的附件列表functiongetAttachmentList(sender,args){varattachment=args.AttchmentList;if(isUndefined(attachment)||attachment=='[]'){BOX_remove('silverlightControlHost');return;}varattachmentList=eval("("+attachment+")");BOX_remove('silverlightControlHost');addAttachUploaded(attachmentList);}

这样一个SL多文件上传插件就算基本完成了。当然我还写了“缩略图”功能,因为代码很简单就不多说了。

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台