[转载]Winform开发框架之插件化应用框架实现 - 伍华聪 - 博客园

mikel阅读(1481)

[转载]Winform开发框架之插件化应用框架实现 – 伍华聪 – 博客园.

支持插件化应用的开发框架能给程序带来无穷的生命力,也是目前很多系统、程序追求的重要方向之一,插件化的模块,在遵循一定的接口标准的基础上,可以实现快速集成,也就是所谓的热插拔操作,可以无限对已经开发好系统进行扩展,而且不会影响已有的功能,不在需要的模块,通过修改配置移除即可。我 的Winform开发框架一直以来,来源于多年的项目积累以及客户的反馈,已经具备了众多很好的特性以及相关的模块组合,为了更好拥抱变化,提高基于 Winform开发框架基础上开发新系统的效率,以及为框架融入更多好的特性,故此把我的Winform开发框架在原来的基础上进行扩展,实现基于插件化 应用框架特性。

为了引入插件化的应用框架特点,我在上一篇随笔《Winform开发框架之权限管理系统的改进》 已经对我的通用权限管理系统进行了改进,其中增加了菜单管理模块就是为了做插件化做准备的,我们通过权限管理系统配置好菜单的相关信息,然后在应用框架中 动态加载菜单功能即可实现。这个菜单模块,是用来配置基于Web开发框架或者Winform开发框架、WCF开发框架的菜单,通过预先的配置,框架程序的 动态加载解析,就能实现插件模块的热插拔功能了。实际插件化框架的菜单配置界面效果如下所示。

最终在Winform开发框架的程序中,实现基于插件化的应用,如下所示。

先来看看我改造Winform开发框架,最终形成的框架界面效果,然后在逐一进行介绍,整个开发框架的实现过程。

1、框架的项目工程规划

为了减少框架整体的复杂性以及提高重用,对插件化的应用框架的项目工程进行了划分,包括“框架基础界面模块”、“插件应用框架启动模 块”、仓库管理系统模块业务逻辑、仓库管理系统模块窗体界面等几个部分。前面两个部分是插件化框架的核心,可以认为是不需要变化的模块,提供所有插件应用 动态创建以及使用的框架支撑;后面两个是具体的主业务模块,这里以WInform开发框架中的仓库管理系统作为主业务模块,它本身也是插件应用之一,具体 的项目工程结构以及说明如下所示。

项目名称 项目说明
WHC.Framework.BaseUIDx  框架基础界面模块,定义窗体界面基类、通用Excel导入模块、通用高级查询模块等
WHC.Framework.StarterDx  插件应用框架启动模块,集成权限登录、动态菜单创建、插件应用动态加载、基础框架功能等
WHC.WareHouseMis  仓库管理系统模块的业务逻辑
WHC.Framework.WareHouseDx   仓库管理系统模块的窗体界面

从上面的表格说明中,我们可以看到“WHC.Framework.StarterDx”项目工程,是“插件应用框架启动模块”,它基本上只和权限管理系统模块有关联关系,因为权限系统是框架底层支撑的模块,包括用户登录、菜单管理、权限控制等都需要从权限管理系统中获取数据,具体的主要业务功能如下所示。

 

2、框架的菜单动态加载

 本文第一张图片里面,介绍了菜单的定义信息,其中包括了图标的配置,这些图片为了方便管理,以及插件需要动态添加菜单图标,我把它放置在了程序目录的相对路径下面,如下所示,动态创建菜单的时候,从指定的路径去获取图标并加载即可。

动态加载菜单是指在插件化应用框架启动,用户登录后进入主界面后,在主界面中动态创建相应的菜单(菜单在权限管理系统中进行配置管理),如下代码所示。

其中是RibbonPageHelper为了方便动态创建菜单而创建的辅助类,部分代码如下所示。

///
/// 动态创建RibbonPage和其下面的按钮项目辅助类
///

public class RibbonPageHelper
{
private RibbonControl control;
public MainForm mainForm;

public RibbonPageHelper(MainForm mainForm, ref RibbonControl control)
{
this.mainForm = mainForm;
this.control = control;
}

public void AddPages()
{
//约定菜单共有3级,第一级为大的类别,第二级为小模块分组,第三级为具体的菜单
List menuList = WHC.Security.BLL.BLLFactory.Instance.GetTree(Portal.gc.SystemType);
if (menuList.Count == 0) return;

int i = 0;
foreach(MenuNodeInfo firstInfo in menuList)
{
//如果没有菜单的权限,则跳过
if (!Portal.gc.HasFunction(firstInfo.FunctionId)) continue;

//添加页面(一级菜单)
RibbonPage page = new DevExpress.XtraBars.Ribbon.RibbonPage();
page.Text = firstInfo.Name;
page.Name = firstInfo.ID;
this.control.Pages.Insert(i++, page);

if(firstInfo.Children.Count == 0) continue;
foreach(MenuNodeInfo secondInfo in firstInfo.Children)
{
//如果没有菜单的权限,则跳过
if (!Portal.gc.HasFunction(secondInfo.FunctionId)) continue;

//添加RibbonPageGroup(二级菜单)
RibbonPageGroup group = new RibbonPageGroup();
group.Text = secondInfo.Name;
group.Name = secondInfo.ID;
page.Groups.Add(group);

if(secondInfo.Children.Count == 0) continue;
foreach (MenuNodeInfo thirdInfo in secondInfo.Children)
{
//如果没有菜单的权限,则跳过
if (!Portal.gc.HasFunction(thirdInfo.FunctionId)) continue;

//添加功能按钮(三级菜单)
BarButtonItem button = new BarButtonItem();
button.PaintStyle = BarItemPaintStyle.CaptionGlyph;
button.LargeGlyph = LoadIcon(thirdInfo.Icon);
button.Glyph = LoadIcon(thirdInfo.Icon);

button.Name = thirdInfo.ID;
button.Caption = thirdInfo.Name;
..................
group.ItemLinks.Add(button);
}
}
}
}
...............

菜单为了方便管理,约定分为3级菜单,三个层级的菜单示意图如下所示。

启动顶部的选项卡级别为第一级,下面的Ribbon分组为第二级,具体的功能菜单(或者按钮)为第三级,以上就是通过菜单数据动态创建的菜单界面图。

3、框架的用户信息和权限控制

基础框架需要传统的登录进行验证,登录成功后,把用户关联的具有的权限下载到本地,然后由系统逻辑统一判断即可。

插件应用框架系统的登录代码和普通的差别不大,登录后把相关信息存储在框架变量中,如下所示。

private void btLogin_Click(object sender, EventArgs e)
{
.................

try
{
string ip = NetworkUtil.GetLocalIP();
string macAddr = HardwareInfoHelper.GetMacAddress();
string loginName = this.cmbzhanhao.Text.Trim();
string identity = WHC.Security.BLL.BLLFactory.Instance.VerifyUser(loginName, this.tbPass.Text, Portal.gc.SystemType, ip, macAddr);
if (!string.IsNullOrEmpty(identity))
{
UserInfo info = WHC.Security.BLL.BLLFactory.Instance.GetUserByName(loginName);
if (info != null)
{
#region 获取用户的功能列表

List list = WHC.Security.BLL.BLLFactory.Instance.GetFunctionsByUser(info.ID, Portal.gc.SystemType);
if (list != null && list.Count > 0)
{
foreach (FunctionInfo functionInfo in list)
{
if (!Portal.gc.FunctionDict.ContainsKey(functionInfo.ControlID))
{
Portal.gc.FunctionDict.Add(functionInfo.ControlID, functionInfo.ControlID);
}
}
}

#endregion

bLogin = true;
Portal.gc.UserInfo = info;
Portal.gc.LoginUserInfo = ConvertToLoginUser(info);

this.DialogResult = DialogResult.OK;
}
}
else
{
MessageDxUtil.ShowTips("用户帐号密码不正确");
this.tbPass.Text = ""; //设置密码为空
}
}
catch (Exception err)
{
MessageDxUtil.ShowError(err.Message);
}
}

为了使框架记录的权限信息、用户数据、以及系统的一些配置信息能够传递到每个插件应用的窗体中,设计了一个插件应用界面需要实现的接口,放在了BaseUI项目工程中。

namespace WHC.Framework.BaseUI
{
///
/// 父窗体实现的权限控制接口
///

public interface IFunction
{
///
/// 初始化权限控制信息
///

void InitFunction(LoginUserInfo userInfo, Dictionary<string, string> functionDict);

///
/// 是否具有访问指定控制ID的权限
///

///功能控制ID ///
bool HasFunction(string controlId);

///
/// 登陆用户基础信息
///

LoginUserInfo LoginUserInfo { get; set; }

///
/// 登录用户具有的功能字典集合
///

Dictionary<string, string> FunctionDict { get; set; }

///
/// 应用程序基础信息
///

AppInfo AppInfo { get; set; }

}
}

然后在BaseUI的项目中,界面基类BaseForm实现这个接口。

namespace WHC.Framework.BaseUI
{
public partial class BaseForm : DevExpress.XtraEditors.XtraForm, IFunction
{

public BaseForm()
{
InitializeComponent();
}

...................

最后,就是我们如何传递用户信息以及权限信息到窗体本身,传递到窗体作为其本身的变量后,就可以很方便使用这些关键的信息了。

在我们动态加载插件应用的后,我们会创建对应的Form对象,然后转换为IFunction接口,赋予该接口相关的变量属性即可实现用户信息及权限信息的传递,如下代码所示。

Form tableForm = (Form)Activator.CreateInstance(formType);

//如果窗体集成了IFunction接口(第一次创建需要设置)
IFunction function = tableForm as IFunction;
if (function != null)
{
//初始化权限控制信息
function.InitFunction(Portal.gc.LoginUserInfo, Portal.gc.FunctionDict);

//记录程序的相关信息
function.AppInfo = new AppInfo(Portal.gc.AppUnit, Portal.gc.AppName, Portal.gc.AppWholeName, Portal.gc.SystemType);
}

 4、插件应用的动态加载

上面我们说到,只要是实现基于Form的,我们都可以动态创建方式调用显示插件的界面出来,而如果界面实现了IFucntion的权限控制接口,那么我们就能够传递给它响应的数据,实现更加完善的控制功能。

在第一张关于权限系统的菜单管理图片中,我们看到了有个Winform的窗体类型的字段,里面就是用来动态构造插件的配置信息,我们主要是用来构造插件的窗体,并传递给它相关数据即可,下图是菜单管理里面的 “Winform窗体类型” 信息的具体内容。

但我们完成菜单的动态创建后,菜单按钮的响应事件就是触发动态加载插件的事件。

我们添加菜单的时候,对它的响应事件也做了处理,具体代码如下所示。

//添加功能按钮(三级菜单)
BarButtonItem button = new BarButtonItem();
.................
button.Caption = thirdInfo.Name;
button.Tag = thirdInfo.WinformType;
button.ItemClick += (sender, e) =>
{
if (button.Tag != null && !string.IsNullOrEmpty(button.Tag.ToString()))
{
LoadPlugInForm(button.Tag.ToString());
}
else
{
MessageDxUtil.ShowTips(button.Caption);
}
};
group.ItemLinks.Add(button);

单击事件的响应处理就是动态构建插件应用的事件,其中就是根据“Winform窗体类型”的数据进行解析的。

string dllFullPath = Path.Combine(Application.StartupPath, filePath);
Assembly tempAssembly = System.Reflection.Assembly.LoadFrom(dllFullPath);
if (tempAssembly != null)
{
Type objType = tempAssembly.GetType(type);
if (objType != null)
{
LoadMdiForm(this.mainForm, objType, isShowDialog);
}
}

通过动态创建菜单模块,动态加载插件应用,以及权限控制等管理,我们就能隔离框架本身和 插件应用模块之间的耦合性关联,所有后续开发或者别人开发的业务模块,都可以很方便的通过权限管理系统配置数据、自动更新模块更新程序应用的方式,把一个 高效、易于扩展、动态管理的系统应用弄得丰富多彩,有声有色。

基于插件化应用框架的Winform开发框架改造,使得今后开发业务系统,只是基于一定的接口协议,开发插件应用即可,整体性的框架本身可以有专门的人员进行维护,提高团队对业务模块的横向切割和快速开发的效率,更好、统一、高效完成企业化应用框架的搭建和使用。

下面的图形是之前Winform开发框架的相关功能点集合,加上目前框架的“支持插件化框架应用,能快速开发插件、支持动态扩展”的特点,就显得更加丰富完善了。

主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于Winform开发框架、WCF开发框架的研究及应用。
转载请注明出处:
撰写人:伍华聪  http://www.iqidi.com

[转载]C# 图片无损压缩 - Peter Luo - 博客园

mikel阅读(1100)

[转载]C# 图片无损压缩 – Peter Luo – 博客园.

这两天忙于将扫描仪扫描出来的文件缩放图片分辨率和大小,开始尝试修改扫描仪设置的参数,结果发现没有办法修改扫描仪参数,最后尝试将扫描后的图片进行代码处理,下面是写的是关于图片进行无损压缩的代码。

///
/// 无损压缩图片
///

///原图片 ///压缩后保存位置 ///高度 ///宽度 ///压缩质量 1-100 ///
public static bool CompressImage(string sFile, string dFile, int dHeight, int dWidth, int flag)
{

System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile);
ImageFormat tFormat = iSource.RawFormat;
int sW = 0, sH = 0;
//按比例缩放
Size tem_size = new Size(iSource.Width, iSource.Height);

if (tem_size.Width > dHeight ||tem_size.Width > dWidth)
{
if ((tem_size.Width * dHeight) > (tem_size.Height * dWidth))
{
sW = dWidth;
sH = (dWidth * tem_size.Height) / tem_size.Width;
}
else
{
sH = dHeight;
sW = (tem_size.Width * dHeight) / tem_size.Height;
}
}
else
{
sW = tem_size.Width;
sH = tem_size.Height;
}
Bitmap ob = new Bitmap(dWidth, dHeight);
Graphics g = Graphics.FromImage(ob);
g.Clear(Color.WhiteSmoke);
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(iSource, new Rectangle((dWidth - sW) / 2, (dHeight - sH) / 2, sW, sH), 0, 0, iSource.Width, iSource.Height, GraphicsUnit.Pixel);
g.Dispose();
//以下代码为保存图片时,设置压缩质量
EncoderParameters ep = new EncoderParameters();
long[] qy = new long[1];
qy[0] = flag;//设置压缩的比例1-100
EncoderParameter eParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qy);
ep.Param[0] = eParam;
try
{
ImageCodecInfo[] arrayICI = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo jpegICIinfo = null;
for (int x = 0; x < arrayICI.Length; x++)
{
if (arrayICI[x].FormatDescription.Equals("JPEG"))
{
jpegICIinfo = arrayICI[x];
break;
}
}
if (jpegICIinfo != null)
{
ob.Save(dFile, jpegICIinfo, ep);//dFile是压缩后的新路径
}
else
{
ob.Save(dFile, tFormat);
}
return true;
}
catch
{
return false;
}
finally
{
iSource.Dispose();
ob.Dispose();
}

}

[转载]缩放时使用插值模式控制图像质量 - 齐分享 - 博客园

mikel阅读(899)

[转载]缩放时使用插值模式控制图像质量 – 齐分享 – 博客园.

Graphics 对象的插值模式会影响 GDI+ 缩放(拉伸和收缩)图像的方式。 InterpolationMode 枚举定义了几种插值模式,其中一些模式显示在下面的列表中:

 

 

若要拉伸图像,原始图像中的每个像素都必须映射为较大图像中的一组像素。 若要收缩图像,必须将原始图像中成组的像素映射为较小图像中单个的像素。 执行这些映射的算法的效果决定缩放后图像的质量。 生成优质缩放图像的算法往往需要更长的处理时间。 在上面的列表中,NearestNeighbor 是质量最差的模式,HighQualityBicubic 是质量最好的模式。

 

若要设置插值模式,请将 InterpolationMode 枚举的一个成员分配给 Graphics 对象的 InterpolationMode 属性。

 


 

 

示例:

下面的示例绘制一个图像,然后用三种不同的插值模式收缩图像。

下面的插图显示原始图像和三个较小的图像。
具有各种内插设置的图像

Image image = new Bitmap("GrapeBunch.bmp");
int width = image.Width;
int height = image.Height;

// Draw the image with no shrinking or stretching.
e.Graphics.DrawImage(
    image,
    new Rectangle(10, 10, width, height),  // destination rectangle  
    0,
    0,           // upper-left corner of source rectangle
    width,       // width of source rectangle
    height,      // height of source rectangle
    GraphicsUnit.Pixel,
    null);

// Shrink the image using low-quality interpolation. 
e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
e.Graphics.DrawImage(
   image,
    new Rectangle(10, 250, (int)(0.6 * width), (int)(0.6 * height)),
    // destination rectangle 
    0,
    0,           // upper-left corner of source rectangle
    width,       // width of source rectangle
    height,      // height of source rectangle
    GraphicsUnit.Pixel);

// Shrink the image using medium-quality interpolation.
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
e.Graphics.DrawImage(
    image,
    new Rectangle(150, 250, (int)(0.6 * width), (int)(0.6 * height)),
    // destination rectangle 
    0,
    0,           // upper-left corner of source rectangle
    width,       // width of source rectangle
    height,      // height of source rectangle
    GraphicsUnit.Pixel);

// Shrink the image using high-quality interpolation.
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
e.Graphics.DrawImage(
    image,
    new Rectangle(290, 250, (int)(0.6 * width), (int)(0.6 * height)),
    // destination rectangle 
    0,
    0,           // upper-left corner of source rectangle
    width,       // width of source rectangle
    height,      // height of source rectangle
    GraphicsUnit.Pixel);

[转载]IconVault – 创建自定义图标字体的神器推荐 - 梦想天空(山边小溪) - 博客园

mikel阅读(1441)

[转载]IconVault – 创建自定义图标字体的神器推荐 – 梦想天空(山边小溪) – 博客园.

图标字体简单来说就是外观呈现为图标的字体,同时具有矢量图形的特征,在不同的设备上使用图标的时候就不用加载不同尺寸的图片文件,能够减少 HTTP 请求数,提高页面加载速度。

IconVault 这款在线生成工具让你可以轻松创建自定义图标字体,选择图标文件夹,点击生成即可。

 

好强大!我去试试

[转载]C#生成缩略图,加文字或图片水印 - 范涛 - 博客园

mikel阅读(998)

[转载]C#生成缩略图,加文字或图片水印 – 范涛 – 博客园.

最近做东西,客户要求上传商品大图,自动生成缩略图,要求等比缩放,正好能在指定的大小内显示,(即如果高超出的比宽超出的多,就把高缩到指定高度,宽也等比缩放,反之宽也如此)
从网上找了如下代码(出处不明),但发现他的生成缩略图的方式有四种,但都不是我想要的,于是在上面加了case “DB”://等比缩放(不变形,如果高大按高,宽大按宽缩放) 这种方式实现了我想要的功能

/**/
///
/// 生成缩略图
///

///源图路径(物理路径) ///缩略图路径(物理路径) ///缩略图宽度 ///缩略图高度 ///生成缩略图的方式 public static void MakeThumbnail(string originalImagePath, string thumbnailPath, int width, int height, string mode,string type)
{
System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);

int towidth = width;
int toheight = height;

int x = 0;
int y = 0;
int ow = originalImage.Width;
int oh = originalImage.Height;

switch (mode)
{
case "HW"://指定高宽缩放(可能变形)
break;
case "W"://指定宽,高按比例
toheight = originalImage.Height * width / originalImage.Width;
break;
case "H"://指定高,宽按比例
towidth = originalImage.Width * height / originalImage.Height;
break;
case "Cut"://指定高宽裁减(不变形)
if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
{
oh = originalImage.Height;
ow = originalImage.Height * towidth / toheight;
y = 0;
x = (originalImage.Width - ow) / 2;
}
else
{
ow = originalImage.Width;
oh = originalImage.Width * height / towidth;
x = 0;
y = (originalImage.Height - oh) / 2;
}
break;
case "DB"://等比缩放(不变形,如果高大按高,宽大按宽缩放)
if ((double)originalImage.Width / (double)towidth < (double)originalImage.Height / (double)toheight)
{
toheight = height;
towidth = originalImage.Width * height / originalImage.Height;
}
else
{
towidth = width;
toheight = originalImage.Height * width / originalImage.Width;
}
break;
default:
break;
}

//新建一个bmp图片
System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);

//新建一个画板
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);

//设置高质量插值法
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;

//设置高质量,低速度呈现平滑程度
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

//清空画布并以透明背景色填充
g.Clear(System.Drawing.Color.Transparent);

//在指定位置并且按指定大小绘制原图片的指定部分
g.DrawImage(originalImage, new System.Drawing.Rectangle(0, 0, towidth, toheight),
new System.Drawing.Rectangle(x, y, ow, oh),
System.Drawing.GraphicsUnit.Pixel);

try
{
//保存缩略图
if (type=="JPG")
{
bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
if (type=="BMP")
{
bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Bmp);
}
if (type=="GIF")
{
bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Gif);
}
if (type=="PNG")
{
bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch (System.Exception e)
{
throw e;
}
finally
{
originalImage.Dispose();
bitmap.Dispose();
g.Dispose();
}
}

/**/
///
/// 在图片上增加文字水印
///

///原服务器图片路径 ///生成的带文字水印的图片路径 protected void AddShuiYinWord(string Path, string Path_sy)
{
string addText = "测试水印";
System.Drawing.Image image = System.Drawing.Image.FromFile(Path);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image);
g.DrawImage(image, 0, 0, image.Width, image.Height);
System.Drawing.Font f = new System.Drawing.Font("Verdana", 16);
System.Drawing.Brush b = new System.Drawing.SolidBrush(System.Drawing.Color.Blue);

g.DrawString(addText, f, b, 15, 15);
g.Dispose();

image.Save(Path_sy);
image.Dispose();
}

/**/
///
/// 在图片上生成图片水印
///

///原服务器图片路径 ///生成的带图片水印的图片路径 ///水印图片路径 protected void AddShuiYinPic(string Path, string Path_syp, string Path_sypf)
{
System.Drawing.Image image = System.Drawing.Image.FromFile(Path);
System.Drawing.Image copyImage = System.Drawing.Image.FromFile(Path_sypf);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(image);
g.DrawImage(copyImage, new System.Drawing.Rectangle(image.Width - copyImage.Width, image.Height - copyImage.Height, copyImage.Width, copyImage.Height), 0, 0, copyImage.Width, copyImage.Height, System.Drawing.GraphicsUnit.Pixel);
g.Dispose();

image.Save(Path_syp);
image.Dispose();
}

Lumanager设置WordPress站点的固定链接格式解析

mikel阅读(949)

刚将博客搬了家,发现原来的固定链接格式访问不到了
于是去查找关于固定链接解析的问题
发现如下代码,加载到站点的location规则中即可
QQ截图20130708135534
location / {
        index index.html index.php;
         if (-d $request_filename){
           rewrite ^/(.*)([^/])$ $1$2/ permanent;
         }
          if (-f $request_filename/index.php){
            rewrite (.*) $1/index.php;
         }
          if (!-f $request_filename){
            rewrite (.*) /index.php;
         }
}

一定要重启Lumanger操作系统

[转载]浏览器对象模型(BOM) - 断桥残雪々 - 博客园

mikel阅读(953)

[转载]浏览器对象模型(BOM) – 断桥残雪々 – 博客园.

BOM结构

用户浏览网页的时候,浏览器会自动创建一些对象,这些对象存放着浏览器窗口的属性和相关信息,也就是大家熟称的BOM。浏览器对象模型是一个层次化的对象集,我们可以通过window对象访问所有对象集。层级关系如下图所示:

BOM结构

window对象

window对象表示浏览器中打开窗体,提供关于窗口状态的信息。可以使用window对象访问窗口中的文档,事件以及影响窗口的浏览器特性。同时 大家应该知道,在JavaScript中window对象是全局对象,就像我们C#中的static一样(不知道对不对呃),也就是要引用当前窗体根本不 需要特殊的语法,可以把该窗口的属性作为全局变量来使用。例如,我们可以直接写document,而不必写window.document。

window方法及其描述
方法  描述
alert() 弹出一个带有一段消息和确认按钮的窗体
blur() 把键盘焦点从顶层窗口移开
clearInterval() 取消由setInterval()设置的timeout
clearTimeout() 取消有setTimeout()方法设置的timeout
close() 关闭浏览器窗口
confirm() 显示带有一段消息以及确认按钮盒取消按钮的对话框
focus() 把键盘焦点给予一个窗口
moveBy() 可相对窗口的当前坐标移动指定的像素
moveTo() 把窗口的左上角移动到一个指定的坐标
open() 打开一个新的浏览器窗体
prompt() 显示可提示用户输入的对话框
resizeBy() 按照指定的像素调整窗口的大小
resizeTo() 把窗体的大小调整到指定的宽度和高度
scrollBy() 按照指定的像素值来滚动内容
scrollTo() 把内容滚动到指定的坐标
setInterval() 按照指定的周期(毫秒)来调用函数或计算表达式
setTimeout() 在指定的毫秒数后调用函数或表达式
复制代码
1.window.open("www.baidu.com","dqcx","height=200,width=300,top=20,left=20,resizable=yes");  //打开一个新的窗体

2.if(confirm(“确定关闭?”))
  alert("你点击了确定");
 else
  alert("你点击了取消");    //confirm()方法,注意它只接受一个参数,即要显示的文本

3.var name=prompt("姓名:","");    //prompt()方法,提示用户输入某些信息,接受连个参数,一个显示文本,一个默认输入文本

4.window.history.go(-1);    //后退一页
 window.history.go(1);    //前进一页
复制代码

PS:相关的用法很多,这里简单列了几个,可以根据以上表格一一学习研究。

location对象

location对象存储在window对象的location属性中,表示当前页面的URL地址。

location对象的属性
属性 描述
host 设置或返回主机名和当前URL的端口号
hostname 设置或返回当前URL的主机名
href 设置或返回完整的URL
port 设置或返回当前URL的端口号
protocol 设置或返回当前URL的协议
search 设置或返回从问号(?)开始的URL,也就是查询字符串
  1. href属性是既可以读又可以写的字符串
  2. local对象的方法
    • assign()方法:加载新的文档
    • reload()方法:重新加载当前文档(对于此方法由于网络延迟和系统资源等不确定因素,最好放到调用的最后一行)
    • replace()方法:用新的文档替换当前文档

navigator对象

通过这个例子应该蛮容易理解,就不列表格了、、、

navigator对象

screen对象

JavaScript可以获取某些关于用户屏幕的信息

 
属性 描述
availHeight 返回显示屏幕的高度(除window任务栏)
availWidth 返回显示屏幕的宽度(除window任务栏)
deviceXDPI 返回显示屏幕的每英寸水平点数
deviceXDPI 返回显示屏幕的每英寸垂直点数
fontSmoothingEnabled 返回用户是否在显示控制面板中开启了字体平滑
 height 返回显示屏幕的高度
 logicalXDPI 返回显示屏幕每英寸的水平方向的常规点数
 logicalYDPI 返回显示屏幕每英寸的垂直方向的常规点数
 pixelDepth 返回 显示屏幕的颜色分辨率(比特每像素)
 updateInterval 设置或返回屏幕的刷新率
 width 返回显示器屏幕的宽度

每个window对象的screen属性都引用screen对象。该对象存放着有关显示器屏幕相关的信息,我们可以根据这些信息来优化页面的输入等等。

孤独的根号3

以上纯属基础知识,大家自己慢慢实际操作吧,我就点到为止咯!

接下来快要去实习了,从来木有出过远门,独处异乡的我该怎么办?想想,LOL也戒了,剩下博客园陪我,够了、、、成长ing

[转载]学习之路三十二:Visual Studio调试的简单技巧 - TimYang - 博客园

mikel阅读(871)

[转载]学习之路三十二:VS调试的简单技巧 – TimYang – 博客园.

这段时间园子里讲了一些关于VS的快捷键以及一些配置技巧,挺好的,大家一起学习,一起进步。

这段时间重点看了一下关于VS调试技巧方面的书,在此记录一下学习的内容吧,主要还是一些比较浅显的知识。

1. 调试窗口

当调试的时候我们需要清晰的看到变量的值,可以使用调试窗口显示变量的值。

快捷键:ctrl + W,1(先同时按ctrl+W,然后在按1)

好处:可以很清晰的把变量的值显示出来,当我们要查看实例里面某一个属性的值就需要这样做了,

你也可以移动鼠标到实例然后点+展开查看,不过那个看的太累。

2. 附加进程

当程序已经发布了,那么本机又有源代码,那么就可以直接附加进程进行Debug调试了。

好处:当程序出现重大崩溃的时候,可以使用附加进程来调试代码,抓住发生错误的时机。

步骤:点击菜单栏Debug,然后选择Attach To Process,如图:

3. 输出窗口

其实如果在不希望通过断点来获取当前变量值的时候,可以通过在输出窗口打印相应的值,可以不通过调试就可以看到值,如下:

4. 断点的魅力

其实关于断点有很多调试技巧,我记得在第一家公司培训的时候,有一个架构师就讲了关于断点方面的知识,当时很惊讶,觉得不可思议。

经过一段时间的了解,把学习心得记下来:

 4.1 跟踪点

通过设置跟踪点可以让当前变量的值显示在输出窗口上,而不需要我们调试一个一个的查看,例如:

注意:只有在Debug模式下才有效果。

4.2 条件断点(Condition BreakPoint)

顾名思义就是说这个断点只有满足条件时才能触发,这就是条件断点,如图:

4.3 筛选断点(Filter BreakPoint)

这个断点技巧尤其在多线程的系统中很有帮助,可以帮我查看这个线程什么时候执行此段代码等等。

  

  上面三个使用的比较多,还有几个平常没用到也就没做很深入的了解。

  有知道的童鞋可以告诉我,我补上。

5. 调用栈跟踪(Call Stack)

这个技巧可以看到调用方法的层次结构。

这个调试技巧我比较喜欢,因为当一个方法你不知道是被哪个方法调用的话,就可以查看调用栈信息窗口,如下:

6. 线程窗口(Thread)

通过查看线程窗口可以很清楚的看出系统中正在运行的线程。这个对调试死锁问题有一定的帮助。

还可以通过点击线程窗口的向下箭头查看此时此刻线程正在执行哪段代码,如下:

7. 其它

7.1 自动窗口(Autos Window)

可以显示当前变量的值,并且可以编辑当前变量的值,这种调试技巧用的非常多。

7.2 Immediate Window

这个可以直接在窗体内进行编码。

好了,个人能力有限就写这么多了。

[转载]c#中使用ABCpdf处理PDF,so easy - 老赵【苏州】 - 博客园

mikel阅读(914)

[转载]c#中使用ABCpdf处理PDF,so easy – 老赵【苏州】 – 博客园.

这几天项目中需要将页面导成PDF,刚开始使用iTextSharp,觉得在分页处理上比较复杂,后来无意中看到了ABCpdf,使用非常简单,并将一些常用操作记录下来,平时可以瞅瞅,也分享给大家伙们,废话不多说,直接贴代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WebSupergoo.ABCpdf9;
using System.Text;

namespace ABCpdfTest
{
    /// <summary>
    /// 官方网站:http://www.websupergoo.com/
    /// demo用的是当前的最新版本ABCpdf .NET 9.1 X64,支持当前windows的主流操作系统,包括最新的win8,IE10(服务器版本)
    /// ABCpdf有30天的试用期
    /// 引用方式,安装ABCpdf组件,有两个DLL是有用的,需要对ABCpdf.dll添加引用,ABCpdf9-64.dll(引擎组件)放在bin目录下就可以了
    /// 它有其他组件比如(iTextSharp)所不具备的功能,如能直接指定一个URL就可以将页面转换为PDF,这也是它的强大之处
    /// 在选择版本时要注意,区分64位和32位,如果版本放错了,会发生错误,在IIS的部署上一定要注意,这里很可能会出现问题,请参考官方资料
    /// 地址:http://www.websupergoo.com/support.htm 常见问题介绍的比较详细
    /// </summary>
    public partial class Default : System.Web.UI.Page
    {
        string url = "http://www.websupergoo.com/support.htm";

        private void DownloadPDF(string fileName, byte[] buffer)
        {
            Response.Buffer = false;
            Response.AddHeader("Connection", "Keep-Alive");
            Response.ContentType = "application/octet-stream";
            Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
            Response.AddHeader("Content-Length", buffer.Length.ToString());
            Response.BinaryWrite(buffer);
        }

        private string GetFileName()
        {
            return DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss") + ".pdf";
        }

        /// <summary>
        /// 指定URL生成PDF
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Button1_Click(object sender, EventArgs e)
        {
            string fileName = GetFileName();
            Doc doc = new Doc();
            doc.Page = doc.AddPage();//新建一个页面
            doc.Rect.Inset(10, 10);//设置矩形边距
            int id = doc.AddImageUrl(url, true, 800, false);//添加一个URL的页面返回一个页面ID
            
            //以下这段代码很重要,关系到分页,如果不写这段代码,就无法分页
            while (true)
            {
                //这个判断应该是判断id是否是页面对象,如果不是,就跳出循环
                if (!doc.Chainable(id))
                {
                    break;
                }
                doc.Page = doc.AddPage();
                id = doc.AddImageToChain(id);//这里是将这个可链接的对象ID添加到页面并返回一个id
            }

            doc.Flatten();//压缩pdf

            doc.Save(Server.MapPath(fileName));//这里保存pdf到相对路径

            //你也你可以这样做把文件输出
            byte[] buffer = doc.GetData();//得到bytes[]
            DownloadPDF(fileName, buffer);
        }        

        /// <summary>
        /// 自定义页面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Button2_Click(object sender, EventArgs e)
        {
            string fileName = GetFileName();
            Doc doc = new Doc();
            doc.Page = doc.AddPage();//新建一个页面
            doc.Rect.Inset(10, 10);//设置矩形边距,这里Rect是一个重要的对象,你也可以doc.Rect.String来设置属性
            doc.FontSize = 24; //设置默认字体大小
            doc.Color.String = "89,89,254";
            int id = doc.AddText("Hello World!!!");//添加文字
            doc.FrameRect(); //添加边框操作

            doc.Save(Server.MapPath(fileName));

            byte[] buffer = doc.GetData();
            DownloadPDF(fileName, buffer);
        }

        /// <summary>
        /// 支持HTML元素
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Button3_Click(object sender, EventArgs e)
        {
            string fileName = GetFileName();
            Doc doc = new Doc();
            doc.Page = doc.AddPage();
            doc.Rect.Inset(10, 10);
            doc.AddHtml("<h2>How to use the ABCpdf</h2>");
            doc.AddHtml("<hr>");
            doc.AddHtml(@"<p>Use ABCpdf to create Adobe PDF documents on the fly. You won't believe how simple - yet how powerful it truly is. Find out more...
                            If you've been using Version 8 you'll love Version 9. It includes many powerful new features designed to make your life easier. Find out more... or check out our Feature Chart...
                            ABCpdf .NET is a .NET Native product encapsulated in an easy-to-deploy set of DLLs. It also offers a virtualized COM interface designed for backwards compatibility with ABCpdf ASP and Classic ASP/COM.
                            ABCpdf is normally priced from $329. However as a special offer we'll give you a free license key - all you have to do is link back to our web site. For full details check out our link guidelines...</p>");

            //这里是不是很神奇,html都支持,很灵活,赞一个
            doc.Save(Server.MapPath(fileName));

            byte[] buffer = doc.GetData();
            DownloadPDF(fileName, buffer);
        }

        /// <summary>
        /// 自定义页眉页脚
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Button4_Click(object sender, EventArgs e)
        {
            string fileName = GetFileName();
            Doc doc = new Doc();
            doc.Page = doc.AddPage();
            doc.Rect.Inset(20, 40);
            doc.AddHtml("<h2>How to use the ABCpdf</h2>");
            doc.AddHtml("<hr>");

            //自定义页眉
            doc.Rect.String = "24 750 588 778";  //记得这里要定位哦
            doc.HPos = 0; //居中, 0代表居左, 1代表居右
            doc.VPos = 0.5; //居中, 0代表靠上, 1代表靠下
            doc.Color.String = "blue"; //蓝色
            for (int i = 1; i <= doc.PageCount; i++)
            {
                doc.PageNumber = i;
                doc.AddHtml("<b><font>" + "Laozhao learn ABCpdf,Save time for" + DateTime.Now.ToString() + "</font></b>");
                doc.AddLine(24, 750, 588, 750); //画一条分隔线
            }

            //页脚
            doc.Rect.String = "24 12 588 40";
            doc.HPos = 1.0; //Right
            doc.VPos = 0.5; //Middle
            doc.Color.String = "black";
            for (int i = 1; i <= doc.PageCount; i++)
            {
                doc.PageNumber = i;
                doc.AddHtml("<u>Page:</u> " + i.ToString() + " / " + doc.PageCount.ToString());
                doc.AddLine(24, 40, 588, 40);
            }

            doc.Save(Server.MapPath(fileName));

            byte[] buffer = doc.GetData();
            DownloadPDF(fileName, buffer);
        }

        /*
         * Doc还支持AddImageHtml
         * 参数说明;
         * html 需要添加的html  
         * paged 是否分页,true启用分页  
         * width 页面的宽度(浏览器解析html时浏览器的宽度)  
         * disableCache 是否忽略缓存,true不启用缓存,false启用缓存
         */
    }
}

[转载]百万行mysql数据库优化和10G大文件上传方案 - 刀锋诚心 - 博客园

mikel阅读(1107)

[转载]百万行mysql数据库优化和10G大文件上传方案 – 刀锋诚心 – 博客园.

最近这几天正在忙这个优化的方案,一直没时间耍,忙碌了一段时间终于还是拿下了这个项目?项目中不要每次都把程序上的问题,让mySQL数据库来承担,它只是个mySQL而已。

问题1:针对MySQL Community5.5+版本优化业务执行速度,提高整体系统效率

测试服务器硬件环境:Intel Core i5,8gb内存,7200rpm硬盘,Win7专业版

Table名称

读取频率

写入频率

最低连续读取速度

最低连续写入速度

预估数据量

C….

频繁

不频繁

30行/150ms

100行/s

百万行

D…

频繁

不频繁

30行/150ms

100行/s

百万行

De…..

频繁

不频繁

30行/150ms

10行/s

万行

St……

频繁

不频繁

30行/150ms

100行/s

百万行

S……

频繁

频繁

30行/150ms

100行/s

百万行

Pr…

很频繁

不频繁

1000行/s-5000行/s

100行/s

百万行/表

De…….

很频繁

频繁

1000行/s-5000行/s

1000行/s

百万行/表

De……

很频繁

频繁

1000行/s-5000行/s

1000行/s

百万行/表

 

看到这个想到的是拆分表,不外乎就是表的纵向拆分和横向拆分,我在项目中也遇到过类似的问题,当时也是使用mysql数据库当时大概列数有800 多,mysql数据一张表的字段是不能有800多个,最开始测试的是用String 按照JSON的格式存入的数据库,结果发现处理时加入了循环,反而使系统性能变得很慢导出一个Excel也是很吃力的,最后采用分表大概分了9张,解决了 问题,其实现在想想是不是使用对象的序列化,将序列化的对象存入数据库呢,使用在从数据库中取出来反序列化使用,当时分表后满足了需求就没再测试对象的序 列化的方法了。但是这次给的需求不需要纵向拆表,是否需要横向拆表呢?测试一次先,每次的点子都是要测试的e。

有些时候在mysql中还是要善用limit,

除开主键其余没加索引,这样上了百万条的数据查询应该是不存在问题,话不多说优化SQL吧。

但是插入还是存在问题,是否需要分表呢?如果只是上百万还是可以不用分表的,如果分表就要处理好分页查询,删除和增加的操作,我还是喜欢使用 Mysql数据的同步,使用两个mysql数据库,服务器ip分别为ip1和ip2,我们将ip1作为Master数据库,把ip2作为slave服务 器,我们可以采用单项同步的方式,就是Master的数据是主数据,然后slave主动去Master哪儿同步数据回来,太晚了,明天测试通过就可以开始 优化项目了。

在数据库中数据在100w多行时插入数据耗时2.822秒的时间,

问题2:大文件上传居然有这样的要求,

档案大小

Action

最大执行内存占用

内网最低传输速率(802.11g)

50mb

Upload

5mb

1mb/s

500mb

Upload

5mb

1mb/s

5gb

Upload

5mb

1mb/s

10gb

Upload

5mb

1mb/s

50mb

Download

5mb

1mb/s

500mb

Download

5mb

1mb/s

5gb

Download

5mb

1mb/s

10gb

Download

5mb

1mb/s

 

以前遇到过一个视频网站上传要求也是最大4G左右,这次居然要上传最大的有10G,

为提高大文件传输速率,将目标文件分成N块文件,对应启动N个线程通过TCP/IP协议来传 输,传输文件前先检查是否存在该文件的临时文件群,如果存在找出其断点位置进行续传,最后合并文 件。异步分割发送,用目前最主流的FLASH+AJAX技术。ActionScript和HTML5是支持SOCKET通讯的,呵呵。

实现流程:

1 客户端向服务端发送传递文件启动信号(发送文件名字)

2 服务器检查是否包含有该文件所对应的临时文件(eg, 传输file.txt,就检查是否存在temp[i]file.txt,(i为 第N块临时文件)),如果存在就发送所有临时文件的断点位置给客户端

3 客户端更具文件大小将文件分为N块(每块默认大小为500M,可通过参数进行配置)以加快传输速率, 然后根据服务器返回的断点位置(如果有)对每块文件进行移位,移动到断点位置进行续传,如果服务器 上没有临时文件夹,就进行普通的传送文件

4当所有线程工作完成,合并所有临时文件夹。

大文件上传的问题已经实现使用的是serverlight实现的。测试通过了大概是5-6M每秒。