HiForums(Asp.Net Forums)开发指南(二):将论坛附件以文件形式保存,并读取照片的Exif信息
来源:
原创
发表时间:
2006-07-17 09:12:35
查看:
917
评论:
0
今天我们要说的是“如何将论坛附件直接以文件形式保存,并读取照片文件的Exif信息;”
废话少说,直接进入主题:
准备工作:下载PhotoProperties类库,用于读取Exif信息,在Components中引用该类库
1、修改web.config配置文件,在forums/forums下增加一个配置项
uploadFilesPath="/Upload/"
值可以自行修改,用来保存用户上传的文件;
2、修改数据库
forums_PostAttachments表增加如下字段
DiskFileName nvarchar(256), 保存附件在硬盘上的文件名
Exif nvarchar(200), 用于保存照片附件的Exif信息
CheckGuid nvarchar(50) 用于保存检测的Guid
注意:我们修改的最终方案是会删除原有的Content字段的
修改存储过程:
create procedure forums_PostAttachment_Add
(
@PostID int,
@UserID int,
@ForumID int,
@Filename nvarchar(256),
@DiskFileName nvarchar(256),
@ContentType nvarchar(50),
@ContentSize int,
@Exif nvarchar(500),
@CheckGuid nvarchar(50)
)
AS
BEGIN

IF EXISTS (SELECT PostID FROM forums_PostAttachments WHERE PostID = @PostID)
RETURN

INSERT INTO
forums_PostAttachments
(
PostID,
ForumID,
UserID,
[FileName],
DiskFileName,
ContentType,
ContentSize,
Exif,
CheckGuid
)
VALUES
(
@PostID,
@ForumID,
@UserID,
@Filename,
@DiskFileName,
@ContentType,
@ContentSize,
@Exif,
@CheckGuid
)

END


GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
3、修改系统配置管理类Components项目下的Configuration/ForumConfiguration.cs文件:
1)在头部增加一变量
string uploadFilesPath="/Upload/"; 2)在LoadValuesFromConfigurationXml方法里增加以下代码,读取配置文件中的值:
uploadFilesPath = attributeCollection["uploadFilesPath"].Value; 3)给ForumConfiguration类增加UploadFilesPath属性:

public string UploadFilesPath { get { return uploadFilesPath; } }

配置文件部分完成。
4、修改Components项目下的PostAttachment类
增加如下引用:
using System.IO;
using JSG.PhotoPropertiesLibrary;
增加如下变量:
string exif;
string diskFileName;
string checkGuid;
增加如下方法:

/**////
/// 获取文件的Exif信息
///
///
///
private string GetExif(string ContentType,string FullFileName)

{
string imgFilePath = FullFileName;
string exif="";
try

{
PhotoProperties pp = new PhotoProperties();

pp.Initialize();
pp.Analyze(imgFilePath);
if(ContentType.ToLower() == "image/pjpeg")

{
//Exif Version
exif += "Exif版本:" + pp.GetTagDatum(36864).PrettyPrintValue;

//制造商
exif += " 制造商:" + pp.GetTagDatum(271).PrettyPrintValue;

//型号
exif += " 型号:" + pp.GetTagDatum(272).PrettyPrintValue;

//拍摄时间
exif += " 拍摄时间:" + pp.GetTagDatum(36868).PrettyPrintValue;

//暴光时间:
exif += "
暴光时间:" + pp.GetTagDatum(33434).PrettyPrintValue + "秒";

//光圈
exif += " 光圈:" + pp.GetTagDatum(33437).PrettyPrintValue;

//ISO
exif += " ISO:" + pp.GetTagDatum(34855).PrettyPrintValue;

//分辨率
exif += " 分辨率:" + pp.GetTagDatum(282).PrettyPrintValue + "/" + pp.GetTagDatum(283).PrettyPrintValue;
}
}

catch
{}

return exif;
} 在构造函数的最下面增加:
string uploadPath = HttpContext.Current.Server.MapPath("~" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath);
uploadPath += "\" + Users.GetUser().UserID.ToString() + "\";
if(!System.IO.Directory.Exists(uploadPath))

{
System.IO.Directory.CreateDirectory(uploadPath);
}
//HttpContext.Current.User.Identity
diskFileName = System.Guid.NewGuid().ToString() + System.IO.Path.GetExtension(postedFile.FileName);
uploadPath += diskFileName;
postedFile.SaveAs(uploadPath);
exif = GetExif(contentType,uploadPath);
checkGuid = System.Guid.NewGuid().ToString();
最后增加3个属性,代码如下:

/**////
/// 磁盘文件名(文件保存在硬盘上的物理文件名)
/// 37AE8655-05F8-4ed9-A771-35B41F0222DE.ext
///
public string DiskFileName

{
get

{
return diskFileName;
}
set

{
diskFileName = value;
}
}


/**////
/// 照片Exif信息
///
public string Exif

{
get

{
return exif;
}
set

{
exif = value;
}
}


/**////
/// 用于判断是否要以attachment形式让用户下载附件
///
public string CheckGuid

{
get

{
return checkGuid;
}
set

{
checkGuid = value;
}
}
5、下面要修改的是负责系统数据库操作的SqlDataProvider项目,用于完成对新增加字段的数据库操作,修改如下:
找到public override void AddPostAttachment(Post post, PostAttachment attachment)方法:
//增加DiskFileName字段,用于附件在硬盘上的保存文件名,
//类似1990ffb3-3992-4438-b7e2-2bca963d969f.jpg
//该文件名不暴露给最终用户
myCommand.Parameters.Add("@DiskFileName", SqlDbType.NVarChar, 256).Value = attachment.DiskFileName;
//注释掉对Content的操作
//myCommand.Parameters.Add("@Content", SqlDbType.Image).Value = attachment.Content;

//增加照片Exif信息与用于验证的CheckGuid字段
myCommand.Parameters.Add("@Exif",SqlDbType.NVarChar,500).Value = attachment.Exif;
myCommand.Parameters.Add("@CheckGuid",SqlDbType.NVarChar,500).Value = attachment.CheckGuid; 注意:这里需要注释掉对Content字段的操作,因为虽然数据字段还在,但上面修改的存储过程中,我们已经删除了对Content字段的操作;
6、修改Components项目下的ForumsDataProvider类中的PopulatePostAttachmentFromIReader方法,完成从数据库到对象的转换,修改如下:
//删除Content字段,附件内容不再保存到数据库,而是直接以文件形式保存到硬盘
// attachment.Content = (byte[]) reader["Content"];

//增加DiskFileName字段,用于附件在硬盘上的保存文件名,
//类似1990ffb3-3992-4438-b7e2-2bca963d969f.jpg
//该文件名不暴露给最终用户
attachment.DiskFileName = (string) reader["DiskFileName"].ToString();

//增加照片Exif信息与用于验证的CheckGuid字段
if(reader["Exif"] != DBNull.Value)


{
attachment.Exif = (string) reader["Exif"];
}
attachment.CheckGuid = (string) reader["CheckGuid"].ToString();
7、到此数据的操作部分已经都完成了,下面要做的就是修改显示部分,系统最终显示帖子内容是通过Controls下的TextPost类完成的,我们要修改的代码当然也在这里了。
找到InitializeSkin方法中的body.Text = post.FormattedBody;,在他下面增加如下代码:
//判断附件的mime类型是否为图片,如果为图片,那么直接调用DisplayImage方法生成显示图片的HTML代码
//此处可扩充直接显示附件为Flash等其他类型的文件
string Attachment=post.AttachmentFilename;
if (Attachment!="" && Attachment!=null)

{
AspNetForums.Components.PostAttachment attachment = Posts.GetAttachment(post.PostID);
string contentType = attachment.ContentType;
if (contentType=="image/pjpeg"
|| contentType=="image/gif"
|| contentType=="image/bmp"
|| contentType=="image/x-png" )

{
body.Text += DisplayImage(Globals.GetSiteUrls().PostAttachment(post.PostID) + "&guid=" + attachment.CheckGuid);
//显示Exif信息
if(attachment.Exif.Length>0)
{
body.Text += "" + attachment.Exif + "";
}
}
} DisplayImage方法很简单,代码如下,自己可以修改该代码,给图片增加边框等
8、修改附件下载部分,Controls项目下的DownloadPostAttachment类,代码如下:
System.Web.HttpContext.Current.Response.Clear();
System.Web.HttpContext.Current.Response.ContentType = attachment.ContentType;

//判断用户从QueryString提交的Guid值是否和数据库的CheckGuid是否相同
//如果相同,那么不以attachment的形式输出,直接显示文件(通常提供该Guid值的情况都是为图片附件)
//如果不同,那么以attachment形式输出,直接由用户下载
if(forumContext.CheckGuid != attachment.CheckGuid)

{
System.Web.HttpContext.Current.Response.AppendHeader("content-disposition", "attachment; filename="" + System.Web.HttpUtility.UrlEncode(attachment.FileName,System.Text.Encoding.UTF8) + """);
}

//System.Web.HttpContext.Current.Response.OutputStream.Write(attachment.Content, 0, attachment.Length);
string diskFileName = System.Web.HttpContext.Current.Server.MapPath("~/" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath + "/" + attachment.UserID.ToString() + "/" + attachment.DiskFileName);
System.Web.HttpContext.Current.Response.WriteFile(diskFileName);
System.Web.HttpContext.Current.Response.End();
9、最后要修改的是ForumContext类,要对该类增加一个属性,用于读取通过QueryString传递的Guid值,找到Components项目下的ForumContext类,
首先增加一变量:
string checkGuid = ""; 在构造函数的最下面增加:
checkGuid = context.Request.QueryString["guid"]; 在最下面增加属性:
//CheckGuid 判断是否合法的显示文件请求

public string CheckGuid
{ get
{ return checkGuid; } }
至此,我们的修改工作已经全部完成,下面要做的就是对原有的数据库进行升级,将Content字段中的数据保存到硬盘,下面的代码比较简单了,直接贴出代码 
在web项目下增加一个页面,后台的操作代码如下,代码比较简单,都是直接操作数据库的。不要忘记增加对PhotoProperties的引用,
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using System.IO;
using JSG.PhotoPropertiesLibrary;

namespace AspNetForums.Update


{

/**////
/// update_20040807 的摘要说明。
///
public class update_20040807 : System.Web.UI.Page

{
protected System.Web.UI.WebControls.Button Button1;
private void Page_Load(object sender, System.EventArgs e)

{
// 在此处放置用户代码以初始化页面
}


Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)

{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}

/**////
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()

{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);

}
#endregion

private void Button1_Click(object sender, System.EventArgs e)

{
string ConnectionString = "database=forums;server=dbserver;User ID=sa;Password=;";

SqlConnection myConn = new SqlConnection(ConnectionString);
myConn.Open();

string select="select * from forums_PostAttachments";
SqlCommand myComm = new SqlCommand(select,myConn);

SqlDataReader dr = myComm.ExecuteReader();
string DiskFileName,CheckGuid,Exif;
string UpdateString="Update forums_PostAttachments SET DiskFileName=’{0}’,Exif=’{1}’,CheckGuid=’{2}’ where PostID={3}";
string UserID;
byte[] fileContent;
FileStream fs=null;







SqlConnection myConn2 = new SqlConnection(ConnectionString);
myConn2.Open();



while(dr.Read())

{
UserID=dr["UserID"].ToString();
fileContent = (byte[])dr["Content"];
DiskFileName = Server.MapPath("~/" + AspNetForums.Configuration.ForumConfiguration.GetConfig().UploadFilesPath + "/" + UserID + "/" + System.Guid.NewGuid().ToString()) + System.IO.Path.GetExtension(dr["FileName"].ToString());
CheckGuid = System.Guid.NewGuid().ToString();

fs=new FileStream(DiskFileName ,FileMode.Create,FileAccess.Write, FileShare.ReadWrite);
fs.Write(fileContent,0,fileContent.Length);
fs.Close();
Exif = GetExif(DiskFileName);

SqlCommand myComm2 = new SqlCommand(string.Format(UpdateString,System.IO.Path.GetFileName(DiskFileName),Exif,CheckGuid,dr["PostID"].ToString()),myConn2);
myComm2.ExecuteNonQuery();
}
dr.Close();
}


private string GetExif(string diskFileName)

{
string imgFilePath = diskFileName;
PhotoProperties pp = new PhotoProperties();

string exif="";
try

{
pp.Initialize();
pp.Analyze(imgFilePath);
//Exif Version
exif += "Exif版本:" + pp.GetTagDatum(36864).PrettyPrintValue;

//制造商
exif += " 制造商:" + pp.GetTagDatum(271).PrettyPrintValue;

//型号
exif += " 型号:" + pp.GetTagDatum(272).PrettyPrintValue;

//拍摄时间
exif += " 拍摄时间:" + pp.GetTagDatum(36868).PrettyPrintValue;


//暴光时间:
exif += "
暴光时间:" + pp.GetTagDatum(33434).PrettyPrintValue + "秒";

//光圈
exif += " 光圈:" + pp.GetTagDatum(33437).PrettyPrintValue;

//ISO
exif += " ISO:" + pp.GetTagDatum(34855).PrettyPrintValue;

//分辨率
exif += " 分辨率:" + pp.GetTagDatum(282).PrettyPrintValue + "/" + pp.GetTagDatum(283).PrettyPrintValue;
}

catch
{}

return exif;
}
}
}

别忘了最后一步工作,删除forums_PostAttachments表中的Content字段,因为我们不再需要他了。
完工! 