生成商品静态页的类和方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
using System.Threading;
/// <summary>
/// 用于生成商品详细页的类
/// </summary>
public class ProductHtmlCreate
{
/// <summary>
/// 存储商品静态文件的文件夹路径,在Application_Start事件中被设置为磁盘的绝对路径
/// </summary>
public static string ProductFolder = "~/Pro/";
/// <summary>
/// 根据商品ID,生成静态文件
/// </summary>
/// <param name="pid">商品ID</param>
/// <param name="productUrl">商品页面绝对Url地址</param>
/// <param name="useProTypeFolder">是否根据商品类型来存放静态页面的文件夹,如果为true,则根据商品类型来存放静态页面的文件夹,否则统一使用ProductHtmlCreate.ProductFolder指定的文件夹</param>
public static void CreateHtml(ProductHtmlSaveConfig config, string productUrl, bool useProTypeFolder)
{
//获取HTML
string html = MySpider.GetResponseText(string.Format(productUrl + "?pid={0}", config.ProductID), null);
//存储静态HTML文件的文件夹路径
string folderPath = ProductFolder;
if (useProTypeFolder)
{
folderPath = GetFolderByProType(config.TypeID);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
}
//静态文件本地路径
string filePath = folderPath + config.ProductID + ".html";
var model = AppCache.Product.GetProduct(int.Parse(config.ProductID));
if (model != null)
{
//如果已经存在静态文件,则删除其静态文件
if (!string.IsNullOrEmpty(model.HtmlPath))
{
string oldFilePath = HttpRuntime.AppDomainAppPath + model.HtmlPath.Substring(1).Replace('/', '\\');
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
}
}
}
//将静态文件的路径更新至数据库
AppCache.Product.SetHtmlPath(int.Parse(config.ProductID), "/" + filePath.ToLower().Substring(HttpRuntime.AppDomainAppPath.Length).Replace('\\', '/'));
//将所有href替换为正确的相对路径
html = RegexCollection.RegHref.Replace(html, (mat) =>
{
return "href=" + mat.Groups[1].Value + GetHref(productUrl, mat.Groups[2].Value) + mat.Groups[1].Value;
});
//将所有src替换为正确的相对路径
html = RegexCollection.RegSrc.Replace(html, (mat) =>
{
return "src=" + mat.Groups[1].Value + GetHref(productUrl, mat.Groups[2].Value) + mat.Groups[1].Value;
});
//生成静态文件
using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
writer.Write(html);
}
}
/// <summary>
/// 从一个商品类型集合里,批量生成商品详细页的静态页
/// </summary>
/// <param name="arr">商品信息配置集合</param>
/// <param name="productUrl">商品页绝对url</param>
/// <param name="isAsyn">是否使用异步</param>
/// <param name="act">异步结束后调用的委托</param>
/// <param name="useProTypeFolder">是否根据商品类型选择存储文件夹</param>
public static void CreateHtmlList(IEnumerable<ProductHtmlSaveConfig> arr, string productUrl, bool isAsyn, Action<int, int> act, bool useProTypeFolder)
{
if (isAsyn)
{
Action asynAct = () =>
{
int successCount = 0;
foreach (var item in arr)
{
try
{
CreateHtml(item, productUrl, useProTypeFolder);
//没成功生成一个html文件,则successCount自增
successCount++;
}
catch (Exception ex)
{
}
}
if (act != null)
{
act(arr.Count(), successCount);
}
};
asynAct.BeginInvoke(new AsyncCallback(
isr => ((Action)isr.AsyncState).EndInvoke(isr)
), asynAct);
}
else
{
foreach (var item in arr)
{
CreateHtml(item, productUrl, useProTypeFolder);
}
}
}
/// <summary>
/// 根据页面url地址,和资源url地址,生成一个引用资源的绝对url地址
/// </summary>
/// <param name="currentUrl">页面url地址</param>
/// <param name="href">资源url地址</param>
/// <returns></returns>
public static string GetHref(string currentUrl, string href)
{
href = href.Trim().ToLower();
//如果实在href里面调用JS,则返回当前JS调用
if (href.StartsWith("javascript"))
{
return href;
}
string scheme = "";
if (href.Length > 5)
{
scheme = href.Substring(0, 6).ToLower();
}
//如果是http开头,则直接返回
if (scheme.StartsWith("http:") || href.StartsWith("https:"))
{
return href;
}
Uri uri = new Uri(currentUrl);
//获取,域名加端口号,类似http://a.com:789
string start = uri.Scheme + "://" + uri.Authority;
//如果href使用绝对路径,直接返回绝对路径
if (href.StartsWith("/"))
{
return href;
}//如果href使用类似 ../之类的相对路径
else if (href.StartsWith("../"))
{
int count = 0;
int index = 0;
while ('.' == href[index] && '.' == href[index + 1] && '/' == href[index + 2])
{
count++;
index += 3;
}
for (int i = 0; i < uri.Segments.Length - 1 - count; i++)
{
start += uri.Segments[i];
}
start += href.Substring(index);
//返回资源的绝对路径
return new Uri(start).AbsolutePath;
}//如果href和当前路径在同一目录
else
{
//如果currentUrl是类似于http://aa.com或者http://aa.com/aa/之类的路径,则应该将uri.Segments中的最后一个字符串也算进去
for (int i = 0; i < (uri.Segments[uri.Segments.Length - 1].EndsWith("/") ? uri.Segments.Length : uri.Segments.Length - 1); i++)
{
start += uri.Segments[i];
}
start += href;
//返回资源的绝对路径
return new Uri(start).AbsolutePath;
}
}
/// <summary>
/// 根据商品类型ID,获取商品静态页面保存的完整目录
/// </summary>
/// <param name="typeId"></param>
/// <returns></returns>
public static string GetFolderByProType(string typeId)
{
//如果没用商品类别,则返回存储商品静态页的顶级目录
if (typeId == "0")
{
return ProductFolder;
}
var list = MyCache.GetCache<Dictionary<string, ProType>>(CacheConfigList.AllProType.Name, CacheConfigList.AllProType.Func, CacheConfigList.AllProType.TimeSpan);
StringBuilder sb = new StringBuilder(50);
sb.Append(ProductFolder);
int index = sb.Length;
//递归商品类型
while (list.ContainsKey(typeId))
{
sb.Insert(index, list[typeId].ImgFolderName);
index += list[typeId].ImgFolderName.Length;
sb.Insert(index, '\\');
typeId = list[typeId].FatherID.ToString();
}
return sb.ToString();
}
}
/// <summary>
/// 保存商品静态页需要使用的参数
/// </summary>
public class ProductHtmlSaveConfig
{
public string ProductID { get; set; }
public string TypeID { get; set; }
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Web;
using System.Threading;
/// <summary>
/// 用于生成商品详细页的类
/// </summary>
public class ProductHtmlCreate
{
/// <summary>
/// 存储商品静态文件的文件夹路径,在Application_Start事件中被设置为磁盘的绝对路径
/// </summary>
public static string ProductFolder = "~/Pro/";
/// <summary>
/// 根据商品ID,生成静态文件
/// </summary>
/// <param name="pid">商品ID</param>
/// <param name="productUrl">商品页面绝对Url地址</param>
/// <param name="useProTypeFolder">是否根据商品类型来存放静态页面的文件夹,如果为true,则根据商品类型来存放静态页面的文件夹,否则统一使用ProductHtmlCreate.ProductFolder指定的文件夹</param>
public static void CreateHtml(ProductHtmlSaveConfig config, string productUrl, bool useProTypeFolder)
{
//获取HTML
string html = MySpider.GetResponseText(string.Format(productUrl + "?pid={0}", config.ProductID), null);
//存储静态HTML文件的文件夹路径
string folderPath = ProductFolder;
if (useProTypeFolder)
{
folderPath = GetFolderByProType(config.TypeID);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
}
//静态文件本地路径
string filePath = folderPath + config.ProductID + ".html";
var model = AppCache.Product.GetProduct(int.Parse(config.ProductID));
if (model != null)
{
//如果已经存在静态文件,则删除其静态文件
if (!string.IsNullOrEmpty(model.HtmlPath))
{
string oldFilePath = HttpRuntime.AppDomainAppPath + model.HtmlPath.Substring(1).Replace('/', '\\');
if (File.Exists(oldFilePath))
{
File.Delete(oldFilePath);
}
}
}
//将静态文件的路径更新至数据库
AppCache.Product.SetHtmlPath(int.Parse(config.ProductID), "/" + filePath.ToLower().Substring(HttpRuntime.AppDomainAppPath.Length).Replace('\\', '/'));
//将所有href替换为正确的相对路径
html = RegexCollection.RegHref.Replace(html, (mat) =>
{
return "href=" + mat.Groups[1].Value + GetHref(productUrl, mat.Groups[2].Value) + mat.Groups[1].Value;
});
//将所有src替换为正确的相对路径
html = RegexCollection.RegSrc.Replace(html, (mat) =>
{
return "src=" + mat.Groups[1].Value + GetHref(productUrl, mat.Groups[2].Value) + mat.Groups[1].Value;
});
//生成静态文件
using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8))
{
writer.Write(html);
}
}
/// <summary>
/// 从一个商品类型集合里,批量生成商品详细页的静态页
/// </summary>
/// <param name="arr">商品信息配置集合</param>
/// <param name="productUrl">商品页绝对url</param>
/// <param name="isAsyn">是否使用异步</param>
/// <param name="act">异步结束后调用的委托</param>
/// <param name="useProTypeFolder">是否根据商品类型选择存储文件夹</param>
public static void CreateHtmlList(IEnumerable<ProductHtmlSaveConfig> arr, string productUrl, bool isAsyn, Action<int, int> act, bool useProTypeFolder)
{
if (isAsyn)
{
Action asynAct = () =>
{
int successCount = 0;
foreach (var item in arr)
{
try
{
CreateHtml(item, productUrl, useProTypeFolder);
//没成功生成一个html文件,则successCount自增
successCount++;
}
catch (Exception ex)
{
}
}
if (act != null)
{
act(arr.Count(), successCount);
}
};
asynAct.BeginInvoke(new AsyncCallback(
isr => ((Action)isr.AsyncState).EndInvoke(isr)
), asynAct);
}
else
{
foreach (var item in arr)
{
CreateHtml(item, productUrl, useProTypeFolder);
}
}
}
/// <summary>
/// 根据页面url地址,和资源url地址,生成一个引用资源的绝对url地址
/// </summary>
/// <param name="currentUrl">页面url地址</param>
/// <param name="href">资源url地址</param>
/// <returns></returns>
public static string GetHref(string currentUrl, string href)
{
href = href.Trim().ToLower();
//如果实在href里面调用JS,则返回当前JS调用
if (href.StartsWith("javascript"))
{
return href;
}
string scheme = "";
if (href.Length > 5)
{
scheme = href.Substring(0, 6).ToLower();
}
//如果是http开头,则直接返回
if (scheme.StartsWith("http:") || href.StartsWith("https:"))
{
return href;
}
Uri uri = new Uri(currentUrl);
//获取,域名加端口号,类似http://a.com:789
string start = uri.Scheme + "://" + uri.Authority;
//如果href使用绝对路径,直接返回绝对路径
if (href.StartsWith("/"))
{
return href;
}//如果href使用类似 ../之类的相对路径
else if (href.StartsWith("../"))
{
int count = 0;
int index = 0;
while ('.' == href[index] && '.' == href[index + 1] && '/' == href[index + 2])
{
count++;
index += 3;
}
for (int i = 0; i < uri.Segments.Length - 1 - count; i++)
{
start += uri.Segments[i];
}
start += href.Substring(index);
//返回资源的绝对路径
return new Uri(start).AbsolutePath;
}//如果href和当前路径在同一目录
else
{
//如果currentUrl是类似于http://aa.com或者http://aa.com/aa/之类的路径,则应该将uri.Segments中的最后一个字符串也算进去
for (int i = 0; i < (uri.Segments[uri.Segments.Length - 1].EndsWith("/") ? uri.Segments.Length : uri.Segments.Length - 1); i++)
{
start += uri.Segments[i];
}
start += href;
//返回资源的绝对路径
return new Uri(start).AbsolutePath;
}
}
/// <summary>
/// 根据商品类型ID,获取商品静态页面保存的完整目录
/// </summary>
/// <param name="typeId"></param>
/// <returns></returns>
public static string GetFolderByProType(string typeId)
{
//如果没用商品类别,则返回存储商品静态页的顶级目录
if (typeId == "0")
{
return ProductFolder;
}
var list = MyCache.GetCache<Dictionary<string, ProType>>(CacheConfigList.AllProType.Name, CacheConfigList.AllProType.Func, CacheConfigList.AllProType.TimeSpan);
StringBuilder sb = new StringBuilder(50);
sb.Append(ProductFolder);
int index = sb.Length;
//递归商品类型
while (list.ContainsKey(typeId))
{
sb.Insert(index, list[typeId].ImgFolderName);
index += list[typeId].ImgFolderName.Length;
sb.Insert(index, '\\');
typeId = list[typeId].FatherID.ToString();
}
return sb.ToString();
}
}
/// <summary>
/// 保存商品静态页需要使用的参数
/// </summary>
public class ProductHtmlSaveConfig
{
public string ProductID { get; set; }
public string TypeID { get; set; }
}