ASP.NET Forums 2.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
(
@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/";
uploadFilesPath = attributeCollection["uploadFilesPath"].Value;
public string UploadFilesPath { get { return uploadFilesPath; } }
4、修改Components项目下的PostAttachment类
增加如下引用:
using System.IO;
using JSG.PhotoPropertiesLibrary;
using JSG.PhotoPropertiesLibrary;
增加如下变量:
string exif;
string diskFileName;
string checkGuid;
string diskFileName;
string checkGuid;
增加如下方法:
/// <summary>
/// 获取文件的Exif信息
/// </summary>
/// <param name="postedFile"></param>
/// <returns></returns>
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 += "<BR>暴光时间:" + 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;
}
/// 获取文件的Exif信息
/// </summary>
/// <param name="postedFile"></param>
/// <returns></returns>
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 += "<BR>暴光时间:" + 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();
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个属性,代码如下:
/// <summary>
/// 磁盘文件名(文件保存在硬盘上的物理文件名)
/// 37AE8655-05F8-4ed9-A771-35B41F0222DE.ext
/// </summary>
public string DiskFileName
{
get
{
return diskFileName;
}
set
{
diskFileName = value;
}
}
/// <summary>
/// 照片Exif信息
/// </summary>
public string Exif
{
get
{
return exif;
}
set
{
exif = value;
}
}
/// <summary>
/// 用于判断是否要以attachment形式让用户下载附件
/// </summary>
public string CheckGuid
{
get
{
return checkGuid;
}
set
{
checkGuid = value;
}
}
/// 磁盘文件名(文件保存在硬盘上的物理文件名)
/// 37AE8655-05F8-4ed9-A771-35B41F0222DE.ext
/// </summary>
public string DiskFileName
{
get
{
return diskFileName;
}
set
{
diskFileName = value;
}
}
/// <summary>
/// 照片Exif信息
/// </summary>
public string Exif
{
get
{
return exif;
}
set
{
exif = value;
}
}
/// <summary>
/// 用于判断是否要以attachment形式让用户下载附件
/// </summary>
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;
//类似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;
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();
// 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 += "<span class=exif>" + attachment.Exif + "</span>";
}
}
}
//此处可扩充直接显示附件为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 += "<span class=exif>" + attachment.Exif + "</span>";
}
}
}
/// <summary>
/// 如果附件为图片类型,那么调用该方法,生成显示图片的HTML代码
/// </summary>
/// <param name="ImageFilePath">要显示的图片路径</param>
/// <returns></returns>
public string DisplayImage(string ImageFilePath)
{
return "<a href='" + ImageFilePath + "' target='_blank'><img src="" + ImageFilePath + "" border=0></a>";
}
/// 如果附件为图片类型,那么调用该方法,生成显示图片的HTML代码
/// </summary>
/// <param name="ImageFilePath">要显示的图片路径</param>
/// <returns></returns>
public string DisplayImage(string ImageFilePath)
{
return "<a href='" + ImageFilePath + "' target='_blank'><img src="" + ImageFilePath + "" border=0></a>";
}
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();
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; } }
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
{
/// <summary>
/// update_20040807 的摘要说明。
/// </summary>
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 窗体设计器生成的代码
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 += "<BR>暴光时间:" + 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;
}
}
}
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
{
/// <summary>
/// update_20040807 的摘要说明。
/// </summary>
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 窗体设计器生成的代码
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 += "<BR>暴光时间:" + 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字段,因为我们不再需要他了。
完工!