[Flash]Flash3D编程探秘一

mikel阅读(860)

作者:Yang Zhou
感谢:Crystal

介绍

对学习Flash中的3D编程感兴趣?那么你来对地方了。在这篇文章中,我将陆续的介绍在Flash中使用Actionsript进行3D编程一些实例。 这是一篇初级到中级难度的学习资料,如果你具有一些基本的几何知识,那对你来说不会太难。虽然例子中运用了非常简单的程序构架和实现方法,但是我还是期望 你已经有大量的Actionscirpt和Flash经验,这样你在使用以及理解Actionscript语言的时候不会有太大的障碍。如果你在阅读中发 现很多地方不清楚,或者这些对你来说是比较新的东西,那么我建议你参考我写过的另外几篇3D的基础知识的文章。

文章中含有大量的代码和一些算法的实现,在这里你可以完全拷贝我写的代码去使用,但是请务必注明出处。

 

点此下载本节源文件

 

Flash 和 3D空间

第一件事情我想你知道的是,在Flash里,并不存在真正的3D。我们所做的是运用Flash里的2D绘制方法去模拟3D绘制。或者我应该 说,Flash并不支持3D绘制,Flash并不知道3D是什么也不知道如何去处理3D对象。但是好消息是所有的3D处理和3D计算都是建立在数学计算的 基础上的,加上 Flash知道如何的处理数学计算。太好了,我们有了这些工具便可以创造出我们自己的动画了。这并不是说Flash里的3D编程要简单,如果你打算深入去 探索的话你会发现恰恰相反。不管怎样,在这篇文章中我会用最大的努力把数学部分变得简单。

在Flash里,有两种3D处理方式,一种是提前处理好3D模型,另外一种是在程序运行时通过数学计算处理3D图形。运用第一种方法,我们可以提前 处理好一系列的图形,然后通过对祯或者是时间进行动画播放,以达到3D效果。相对来说,第一种方法对美工的要求比较高。后一种方法我们通过大量的数学计算 对物体进行操作,这也是在这篇文章里所关心的。

 

3D程序

如今你在互联网上搜索3D Flash你会找到很多的工具和程序,利用这些程序你可以绘制一些3D图形并导出你需要的格式,甚至完全使用在你的项目里。基本上你可以不必操心如何绘制 3D图形。但是这些程序都是提前做好的模版,不能够作太多的编辑。于是我们发现我们自己也有大脑,我们自己也可以制作简单的缩放动画,还可以制作复杂的 3D绘制引擎。

毕竟我们是从最基础的2D绘制开始制作3D对象。这并不像我们在使用显卡语言或者OpenGL时的绘制,一切3D的物体我们都要自己动脑动手加上数 学运算进行绘制,这就增加了一些数学上的挑战。不过我认为,这对你来说应该不是问题,用Flash作3D图形一样会给你带来你意想不到的乐趣。那么开始 吧!

 

3D空间坐标系

从技术角度而言,Flash中并不存在3D,也就是说z轴并不存在,所以所谓的z轴是由你来制造的,也就是远景物体的大小。那么也就是说,对于一个 3D虚拟空间,z轴存在于当你看进显示器,x轴和y轴分别为横向和纵向。可是我们用什么方法来表达3D空间呢?我们需要两种手法来处理3D显示,缩放和层 叠。

 

 2D与3D坐标系

 

 

对于z轴的解释

在现实中,当一个物体离你远去,那么对你的眼睛来说,你所看到的是物体越来越小。当然并不只有物体的大小在改变,物体离你的距离也在增大。那么我们可以假定,在3D空间里,离得人眼越远的物体,它的大小就越小,那么它在x和y轴上的移动就越缓慢。很简单对吧?很好。

 

原点

Flash 中3D空间是围绕坐标系原点的,原点的坐标我们用Point(x, y, z), (0, 0, 0) 来表示。在Flash 2D中,原点存在于程序的左上角Point(0, 0),那么对于3D来说,原点也自然存在于程序的左上角,也许你会发现,如果原点在左上角的话,那么你所在的位置肯定是成一定角度来看程序中3D空间中的 物体的。当然我们可以把3D空间的原点向右再向下移动,那么我们在围绕原点绘制物体的时候会发现方便很多。

 

缩放物体

离人眼越近,那么物体就越大,反之物体就越小。物体缩放的比率以及移动速率与物体z的大小成反比。现在我用一个实例给你说明如何制造3D动画效果, 在这个例子中,我手工绘制了几个小球,作为我们关心的物体,让它们沿着z轴在舞台上来回移动,以制造3D效果。虽然很基本,不过别担心,把这些简单的东西 掌握好是深入探索的基础。

小球与3D空间(无层次)

 

动画制作步骤

1. 第一步,用Flash画出一个你喜欢的物体,任何物体都可以。在这个例子中我画了一个蓝色的小球。当然你可以导入你喜欢的图片,只不过不要忘记在 Library你创建的物体上点击右键,选择Linkage,然后在Export For Actionscript上打勾。

2. 下一步,详细解说一下代码。当然一开始我们要设置一些变量,原点和焦距(摄像机)。Focal length(焦距)确定了摄像机(在本例子中为人眼的)的凸透镜的焦距,值越大,那么物体的扭曲就会越小。我们把它设为300,这是一个在本例子中适中的数值。

var origin = new Object();
origin.x 
= stage.stageWidth/2;
origin.y 
= stage.stageHeight/280;

 

var focal_length = 400;

 

3. 创建一个舞台,并且把它的x和y设置为原点,这样我们在参照物体的时候就会非常简单易读了。

var scene = new Sprite();
this.addChild(scene);
scene.x 
= origin.x;
scene.y 
= origin.y;

 

4. 然后我们要在舞台上添加一些我们绘制好的小球。在这个例子中我们绘制3个,分别在左中右。把它们的x_3d, y_3d, z_3d,也就是他们的3D空间的x,y,z的值设为相应的数值,我把它们排为一排。给他们添加一个direction属性,1代表向屏幕方向移动,-1 代表向我们的方向移动。然后设置他们的移动速度,并且把它们添加到舞台上。这时你如果编译的话,你会看到有3个球在舞台上,那么下一步我们让它们运动起 来。

for (var i = 0; i < 3; i++)
{
    var sphere 
= new Sphere();
    sphere.x_3d 
= 190+i*160;
    sphere.y_3d 
= 80;
    sphere.z_3d 
= i*100;
    sphere.direction 
= 1;
    sphere.speed 
= 6;
    scene.addChild(sphere);
}

 

5. 下面这个函数,在每一次执行,都会把小球移动到相应的位置,并且对小球进行缩放。当小球的z大于600时,我们让它向相反的方向移动。当小球的z_3d值 变化后,我们计算小球当前的大小和位置,把小球移动到相应的位置然后对其进行缩放,这样在一连串的函数执行后,我们就会得到动画效果。

function run(e:Event)
{
    
for (var i = 0; i < scene.numChildren; i++)
    {
        scene.getChildAt(i).z_3d 
+= scene.getChildAt(i).speed*scene.getChildAt(i).direction;
        
if (scene.getChildAt(i).z_3d > 600)
        {
            scene.getChildAt(i).z_3d 
= 600;
            scene.getChildAt(i).direction 
= 1;
        }
        
else if (scene.getChildAt(i).z_3d < 0)
        {
            scene.getChildAt(i).z_3d 
= 0;
            scene.getChildAt(i).direction 
= 1;
        }
        
        var scale 
= focal_length/(focal_length+scene.getChildAt(i).z_3d);
        scene.getChildAt(i).x 
= scene.getChildAt(i).x_3d*scale;
        scene.getChildAt(i).y 
= scene.getChildAt(i).y_3d*scale;
        scene.getChildAt(i).scaleX 
= scene.getChildAt(i).scaleY = scale;
    }
}

 

6. 最后,在舞台上添加一个函数循环响应时间。让第5步我们写的函数循环执行。发布看一下,现在小球在3D舞台上移动了。

Hooray!你的第一个Flash3D程序完成了。总结一下,其实我们并没有使用任何高深的技巧,只不过是利用了变化物体的x和y以及小球的缩放来制造3D效果。

 

层叠

在Flash中表现3D空间,仅有缩放是不够的,我们还需要层叠。基本概念是,离人眼较近的物体会在离人眼较远的物体之上显示。
在上一节的例子里面,我们缩放小球,以达到3D效果。可是你会发现,3个小球之间的x距离都很大。你也许会想如果3个小球离得很近的话,会出现什么现象 呢?尝试把上面例子中小球之间的x距离变小,你会发现,不管小球离我们多远,右边的小球始终在最上面。即使中间的小球应该盖过右边小球的时候,右边的小球 还会在上面。这是因为在把小球添加到舞台上的时候,我们已经给了小球层次,也就是说最后添加的小球(右边的小球)就在最上面。

小球3D空间(无层次)间距太小啦!

我们应该设计一种方法实现小球的层次感,当小球离我们远的时候,那么它的层次就比较靠后,以此类推。换句话说,我们利用小球的z值给小球们分开层次,这也是我们即将要做的。在这个例子中,我们用7个小球的运动来说明是如何实现层次的。

小球3D空间(有层次)好多了!

 

动画制作步骤

1. 和上次的例子一样,重复6个步骤。不同的是我们初始化7个小球,并且把它们的x距离缩短。

for (var i = 0; i < 7; i++)
{
    var sphere 
= new Sphere();
    sphere.x_3d 
= 150+i*40;
    sphere.y_3d 
= 80;
    sphere.z_3d 
= Math.random()*(0600)+600;
    sphere.direction 
= 1;
    sphere.speed 
= Math.random()*(512)+12;    
    scene.addChild(sphere);
}

 

2. 利用Bubble Sort算法,在每一次对小球x,y和大小设置后,对所有的小球在舞台上的层次进行操作。这里使用的理论是最小的z值的小球,它所在层次就应该在最上面。

function swap_depth(container:Sprite)
{
    
for (var i = 0; i < container.numChildren  1; i++)
    {
        
for (var j = container.numChildren  1; j > 0; j)
        {
            
if (Object(container.getChildAt(j1)).z_3d < Object(container.getChildAt(j)).z_3d)
            {
                container.swapChildren(container.getChildAt(j
1), container.getChildAt(j));
            }
        }
    }
}

 

3. 然后在循环函数里的最后加上

swap_depth(scene);

 

本文章旨在讨论如何在Flash中实现3D动画,对于一些算法,比如这一节中使用到的冒泡排序算法,我就不再多说了。当然你可以选择使用插入排序 (可能运算起来比较快40%?!)。你可以完全拷贝我写的代码去使用,但是请务必注明出处。如果是排序的话,google或者百度一下,我相信你会找到更 详细的说明文字来解释冒泡排序。

OK,你已经学会了如果使用缩放和一些简单的设置产生3D效果的动画。在后面的几篇中,我们会逐渐深入探讨更有趣的内容。加油!

 

点此下载本节源文件


作者:Yang Zhou
出处:http://yangzhou1030.cnblogs.com
感谢:Yunqing
本文版权归作者和博客园共有,转载未经作者同意必须保留此段声明。请在文章页面明显位置给出原文连接,作者保留追究法律责任的权利。

[Flash]Flash3D编程探秘二

mikel阅读(792)

作者:Yang Zhou
感谢:Crystal

介绍

对 学习Flash中的3D编程感兴趣?那么你来对地方了。在这篇文章中,我将陆续的介绍在Flash中使用Actionsript进行3D编程一些实例。这 是一篇初级到中级难度的学习资料,如果你具有一些基本的几何知识,那对你来说不会太难。虽然例子中运用了非常简单的程序构架和实现方法,但是我还是期望你 已经有大量的Actionscirpt和Flash经验,这样你在使用以及理解Actionscript语言的时候不会有太大的障碍。如果你在阅读中发现 很多地方不清楚,或者这些对你来说是比较新的东西,那么我建议你参考我写过的另外几篇3D的基础知识的文章。

文章中含有大量的代码和一些算法的实现,在这里你可以完全拷贝我写的代码去使用,但是请务必注明出处。

 

点此下载本节源文件

 

静态长方体

那么我们接着上一节所学习的内容,来制作一个静态的长方体,并且让它在屏幕上来回的运动。这个例子和上一节的例子非常的相似,同样主要关心3D空 间。不同的是,上一节我们利用了一个事先画好的小球,这一节我们改变方式,在程序执行时,我们计算出长方体的每个顶点的位置然后使用Flash的图形 API绘制出一个长方体,这样在一系列的绘制后,我们所看到的就是长方体移动的动画!

移动的静态长方体

 

动画制作步骤

1. 在这一个例子中,我们需要发挥一下我们的空间想象力去定位长方体的顶点。至于场景上的网格,我想大家可以先把它放在场景的底部,等动画完成后再把它向上移动到合适的位置。

2. 开始和以前一样,定义原点以及焦距。另外我们也要初始几个常量。长方体围绕y轴公转,R是长方体公转的半径。

var PI = 3.1415926535897932384626433832795;

var R = 100;

var origin = new Object();
origin.x 
= stage.stageWidth/2;
origin.y 
= stage.stageHeight/2;
origin.z 
= 0;

var focal_length = 300;
var angular_Velocity = PI/160;
var _angle_xz = 0;

 

3. 接下来定义一个3D空间的点,我们绘制的长方体就围绕这个点进行旋转。

var spin_center = new Object();
spin_center.x 
= 0;
spin_center.y 
= 0;
spin_center.z 
= 100;

 

4. 创建一个场景舞台,用来盛放我们绘制的长方体。创建一个长方体的空Sprite并且把它添加到舞台上。

var scene = new Sprite();
scene.x 
= origin.x;
scene.y 
= origin.y
this.addChild(scene);
var box:Sprite 
= new Sprite();
scene.addChild(box);

 

5. 下面我们需要一个函数来创建3D空间的点。

function vertex(x, y, z):Object
{
    var point3d 
= new Object();
    point3d.x 
= x;
    point3d.y 
= y;
    point3d.z 
= z;
    
return point3d;
}

 

6. 你肯定猜到下一步我们要做的,那就是把一个3D空间的点转换成Flash能够理解的2D空间的点。转换的原理和第一节是一样的,这里就不解释了。

function convert(point3d, focal_length):Object
{
    var point2d 
= new Object();
    var scale_ratio 
= focal_length/(focal_length+point3d.z);
    point2d.x 
= point3d.x * scale_ratio;
    point2d.y 
= point3d.y * scale_ratio;
    
return point2d;
}

 

7. 下一步也就是我们主要关心的循环函数。首先我想你明确这个函数要做的工作,那就是计算出长方体每个顶点的3D坐标,然后把他们转化成2D坐标,最后用 Flash的绘制API建立图形。每一次函数执行,我们把长方体围绕y轴旋转的角度增加。(当然这里你可以长方体的运动改为以时间为依据的运动)然后根据 这个角度,我们便可以计算出长方体中心点(对角线的交点)cente.x,center.y,center.z。很好,下面我们就可以确定这个长方体的每 个点的坐标了。在这里我使用了一个边长为80正方体,你可以更改参数调试出你喜欢的长方体。

 

俯瞰长方体的移动

 

 

那么紧接着,使用我们之前写的函数,把长方体的6个3D顶点转换成2D点。然后用Flash的绘制函数绘制出来长方体。需要注意的是,我们在这里是对空间中的点进行操作而不是对一个Sprite进行操作。

function move(e:Event):void
{
    var screen_points 
= new Array();
    
    _angle_xz 
+= angular_Velocity;
    
if (_angle_xz > 360)
    {
        _angle_xz 
-= 360;
    }
    var center 
= new Object();
    center.x 
= R*Math.cos(_angle_xz) + spin_center.x;
    center.y 
= 0 + spin_center.y;
    center.z 
= R*Math.sin(_angle_xz) + spin_center.z;
    
    var points 
= [
            vertex(center.x
4040, center.z40),    
            vertex(center.x
+4040, center.z40),        
            vertex(center.x
+4040, center.z+40),
            vertex(center.x
4040, center.z+40),
                    
            vertex(center.x
4040, center.z40),
            vertex(center.x
+4040, center.z40),
            vertex(center.x
+4040, center.z+40),
            vertex(center.x
4040, center.z+40)
             ];
    
for (var i = 0; i < points.length; i++)
    {
        screen_points[i] 
= convert(points[i], focal_length);
    }
    
    with (box.graphics)
    {
        clear();
        lineStyle(.
50x0000001);
        moveTo(screen_points[
0].x, screen_points[0].y);    
        lineTo(screen_points[
1].x, screen_points[1].y);
        lineTo(screen_points[
2].x, screen_points[2].y);
        lineTo(screen_points[
3].x, screen_points[3].y);
        lineTo(screen_points[
0].x, screen_points[0].y);
        
        moveTo(screen_points[
4].x, screen_points[4].y);    
         lineTo(screen_points[
5].x, screen_points[5].y);
        lineTo(screen_points[
6].x, screen_points[6].y);
        lineTo(screen_points[
7].x, screen_points[7].y);
        lineTo(screen_points[
4].x, screen_points[4].y);
        
        moveTo(screen_points[
0].x, screen_points[0].y);    
        lineTo(screen_points[
4].x, screen_points[4].y);
        moveTo(screen_points[
1].x, screen_points[1].y);
        lineTo(screen_points[
5].x, screen_points[5].y);
        moveTo(screen_points[
2].x, screen_points[2].y);
        lineTo(screen_points[
6].x, screen_points[6].y);
        moveTo(screen_points[
3].x, screen_points[3].y);
        lineTo(screen_points[
7].x, screen_points[7].y);
    }
}

 

8. 最后在场景上添加一个循环执行事件。

this.addEventListener(Event.ENTER_FRAME, move);

 

我希望你能够明确我们制作这个动画的思路:建立场景,创建3D物体,把顶点转换成为2D点,使用Flash绘制。So far so good? Great! 后面我们开始介绍摄像机以及相关的要素,希望你能跟上。

建议:

在你的脑海中建立一个长方体应该不是很困难。我的方法是首先勾勒出正面,然后后面,上面,下面,左面和右面。如果你觉得用脑海想象比较困难的话,可以试着用笔和纸画出一个长方体,然后标出坐标。

建议:

在Flash里,2D空间的原点在左上角(0,0)。在这上面的两节的例子中,我们在程序一开始就把3D空间的原点向右再向下移动了,那么在屏幕上的映射 面也就到了屏幕的中间。我是刻意这样写的,好处在于如果你是新接触3D空间这个课题的话,那么想象物体在原点附近对你来说要容易一些。当然你可以尝试不移 动原点,取而代之移动物体,看看和原程序有什么不同。

作者:Yang Zhou
出处:http://yangzhou1030.cnblogs.com
感谢:Yunqing
本文版权归作者和博客园共有,转载未经作者同意必须保留此段声明。请在文章页面明显位置给出原文连接,作者保留追究法律责任的权利。

[Flash]Sandy 3D

mikel阅读(959)

Sandy

Sandy is an intuitive and user-friendly 3D open-source library developed in Actionscript 2 and now Actionscript 3 for the Flash environment.

This project is updated very often, and the latest release is the 3.0.2 official release. The latest version is available on the website : flashsandy.org

Some technical demos (get all of them there: http://www.flashsandy.org/demos/ )

walker.jpg

flightsim.jpg

You can download the latest version here : http://www.flashsandy.org/download

New 3.0 release features

Here a list of main features:

  • Simple and more powerful API
  • Frustum culling and Frustum clipping
  • compatible with majority of tween libraries (Tweener, etc. )
  • real scene graph representation, with a fully integration of the camera as an element of this scene tree.
  • flexible skinning of objects. Each material has some attributes that allow it display more information (edges, outine, light)
  • Parsers able to load more that 1 single object. (ASE, 3DS-basic-, COLLADA formats)
  • possibility to choose the depth sorting between Object and Polygon level.
  • built-in bubbling event system
  • Sprite2D and Sprite3D (understand oriented sprite) integration.

Characteristics

This 3D engine features many exclusive characteristics such as :

  • Flash player 7 compatibility.
  • Both MTASC and Macromedia compilers compliant.
  • Several 3D primitives, allowing fast and parameterized object creation
  • Advanced object management allowing some fantastic possibilities during your creations (scaling, rotation, translation, etc.)
  • API based on Java3D, the reference open-source Java 3D API
  • Advanced camera management (multiple cameras, rotation, motion on linear or bezier-curve path, movements, etc.)
  • Complex object loading thanks to the .ASE and .WRL files parser (files generated by several 3D object modeling packages such as 3D Studio Max)
  • Skin system to easily change your objects appearance. Several skins are available allowing to create transparent faces, bitmap texture and video texture as webcam video stream.
  • Managment of Flash8 filters bringing some very nice visual effects

Why this project ?

The idea comes from the lack of possibilities to run 3D in Flash. This project goals are to supply the more reliable and flexible API to users, plus reach the highest performance level possible.

Author

Thomas Pfeiffer started this project in Oct 2005 and since, a small but complete team has been created: Development team

Some people have kindly contributed to the project, and you can see the list here: contributors

Why this name ?

Sandy is intended to be a community project, with a simple API, documented and updated as much as possible. Sandy is a pun which represents 3D. I’ve been inspired by the Chinese language because ‘3’ is pronounced ‘san’ and the letter ‘D’ ‘di’. Combining those two words I got sandy.

[FCKEditor]使用FCKeditor_2.6.3版本有关上传图片问题解决

mikel阅读(917)

使FCKeditor_2.6.3版本有关上传图片问题解决

问题:提示This connector is disabled

解决:
在fckeditor\editor\filemanager\connectors\aspx目录下面有一个 config.ascx 用户控件。打开它,我们可以看到有一个:private bool CheckAuthentication()的方法。
private bool CheckAuthentication()
 {
  // WARNING : DO NOT simply return "true". By doing so, you are allowing
  // "anyone" to upload and list the files in your server. You must implement
  // some kind of session validation here. Even something very simple as…
  //
  //  return ( Session[ "IsAuthorized" ] != null && (bool)Session[ "IsAuthorized" ] == true );
  //
  // … where Session[ "IsAuthorized" ] is set to "true" as soon as the
  // user logs in your system.
 
  return false;
  }
默认是返回false的,返回true就可以了。不要轻易的返回true,要不然任何人都可以上传文件到你的服务器。可以在这里验证session的值来判断用户是否可以上传文件。
 

问题:FCKEditor 图片上传一直显示进度条的问题


解决:

很多博主介绍配置FCKeditor的目录时都是这样写的,我不知道是不是大家互相复制的关系

<appSettings>
    <add key="FCKeditor:BasePath" value="~/FCKeditor/"/>
    <!–FCKeditor基本文件目录–>
    <add key="FCKeditor:UserFilesPath" value="/UserFiles/"/>
    <!–文件上传目录–>
  </appSettings>

大家看一下上面两个配置有什么区别没有,"~/FCKeditor/"比"/UserFiles/"前面多了符号“~”。

在“/UserFiles/”前面加上“~”符号就可以了。

这个错误还会导致下面的问题:在单击浏览服务器按钮是提示:未能映射路径“/Files/image/”,具体提示如下:

==========================================================================================

—————————
Microsoft Internet Explorer
—————————
The server didn't send back a proper XML response. Please contact your system administrator.

XML request error: Internal Server Error (500)

Requested URL:
http://localhost:7958/FCKeditorTest/FCKeditor/editor/filemanager/connectors/aspx/connector.aspx?Command=GetFoldersAndFiles&Type=Image&CurrentFolder=%2F&uuid=1224920141937

Response text:
<html>

    <head>

        <title>未能映射路径“/UserFiles/image/”。</title>

        <style>

         body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;}

         p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}

         b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}

         H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }

         H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }

         pre {font-family:"Lucida Console";font-size: .9em}

         .marker {font-weight: bold; color: black;text-decoration: none;}

         .version {color: gray;}

         .error {margin-bottom: 10px;}

         .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }

        </style>

    </head>

 

    <body bgcolor="white">

 

            <span><H1>“/FCKeditorTest”应用程序中的服务器错误。<hr width=100% size=1 color=silver></H1>

 

            <h2> <i>未能映射路径“/UserFiles/image/”。</i> </h2></span>

 

            <font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">

 

            <b> 说明: </b>执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

 

            <br><br>

 

            <b> 异常详细信息: </b>System.InvalidOperationException: 未能映射路径“/UserFiles/image/”。<br><br>

 

            <b>源错误:</b> <br><br>

 

            <table width=100% bgcolor="#ffffcc">

               <tr>

                  <td>

                      <code>

 

执行当前 Web 请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息。</code>

 

                  </td>

               </tr>

            </table>

 

            <br>

 

            <b>堆栈跟踪:</b> <br><br>

 

            <table width=100% bgcolor="#ffffcc">

               <tr>

                  <td>

                      <code><pre>

 

[InvalidOperationException: 未能映射路径“/UserFiles/image/”。]

   System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull) +615

   System.Web.VirtualPath.MapPathInternal() +29

   System.Web.HttpRequest.MapPath(VirtualPath virtualPath, VirtualPath baseVirtualDir, Boolean allowCrossAppMapping) +125

   System.Web.HttpServerUtility.MapPath(String path) +58

   FredCK.FCKeditorV2.FileBrowser.TypeConfig.GetFilesDirectory() +63

   FredCK.FCKeditorV2.FileBrowser.FileWorkerBase.ServerMapFolder(String resourceType, String folderPath, Boolean isQuickUpload) +37

   FredCK.FCKeditorV2.FileBrowser.Connector.GetFolders(XmlNode connectorNode, String resourceType, String currentFolder) +21

   FredCK.FCKeditorV2.FileBrowser.Connector.OnLoad(EventArgs e) +708

   System.Web.UI.Control.LoadRecursive() +49

   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3743

</pre></code>

 

                  </td>

               </tr>

            </table>

 

            <br>

 

            <hr width=100% size=1 color=silver>

 

            <b>版本信息:</b>&nbsp;Microsoft .NET Framework 版本:2.0.50727.42; ASP.NET 版本:2.0.50727.42

 

            </font>

 

    </body>

</html>

<!–

[InvalidOperationException]: 未能映射路径“/UserFiles/image/”。

   在 System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull)

   在 System.Web.VirtualPath.MapPathInternal()

   在 System.Web.HttpRequest.MapPath(VirtualPath virtualPath, VirtualPath baseVirtualDir, Boolean allowCrossAppMapping)

   在 System.Web.HttpServerUtility.MapPath(String path)

   在 FredCK.FCKeditorV2.FileBrowser.TypeConfig.GetFilesDirectory()

   在 FredCK.FCKeditorV2.FileBrowser.FileWorkerBase.ServerMapFolder(String resourceType, String folderPath, Boolean isQuickUpload)

   在 FredCK.FCKeditorV2.FileBrowser.Connector.GetFolders(XmlNode connectorNode, String resourceType, String currentFolder)

   在 FredCK.FCKeditorV2.FileBrowser.Connector.OnLoad(EventArgs e)

   在 System.Web.UI.Control.LoadRecursive()

   在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

[HttpUnhandledException]: 引发类型为“System.Web.HttpUnhandledException”的异常。

   在 System.Web.UI.Page.HandleError(Exception e)

   在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

   在 System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

   在 System.Web.UI.Page.ProcessRequest()

   在 System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)

   在 System.Web.UI.Page.ProcessRequest(HttpContext context)

   在 ASP.fckeditor_editor_filemanager_connectors_aspx_connector_aspx.ProcessRequest(HttpContext context)

   在 System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()

   在 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

–>
—————————
确定  
—————————

============================================================================================================

以上问题都是根据测试推断出的,我并不知道源码是怎么处理的,希望高手能给予指点。

相关链接:

FCKeditor_2.6.3的安装使用方法

[C#]WebService序列化

mikel阅读(1200)

 1 /// <summary>
 2     /// 序列化DataTable
 3     /// </summary>
 4     /// <param name="pDt">包含数据的DataTable</param>
 5     /// <returns>序列化的DataTable</returns>
 6     private static string SerializeDataTableXml(DataTable pDt) {
 7         // 序列化DataTable
 8         StringBuilder sb = new StringBuilder();
 9         XmlWriter writer = XmlWriter.Create(sb);
10         XmlSerializer serializer = new XmlSerializer(typeof(DataTable));
11         serializer.Serialize(writer, pDt);
12         writer.Close();
13 
14         return sb.ToString();
15     }
16 

 1 /// <summary>
 2         /// 反序列化DataTable
 3         /// </summary>
 4         /// <param name="pXml">序列化的DataTable</param>
 5         /// <returns>DataTable</returns>
 6         public static DataTable DeserializeDataTable(string pXml) {
 7 
 8             StringReader strReader = new StringReader(pXml);
 9             XmlReader xmlReader = XmlReader.Create(strReader);
10             XmlSerializer serializer = new XmlSerializer(typeof(DataTable));
11 
12             DataTable dt = serializer.Deserialize(xmlReader) as DataTable;
13 
14             return dt;
15         }
16

[Flex]用FlexMonkey测试Flex

mikel阅读(970)

在这篇新闻中,InfoQ.com与FlexMonkey项目创建者、来自Gorilla Logic的Stu Stern一起讨论了FlexMonkey。FlexMonkey是一个用来测试Flex应用的开源工具,它采用记录/回放模式。

Stern首先对FlexMonkey进行了概要性描述:

FlexMonkey是一个开源的Flex应用和库,可以记录和回放用户界面的交互并生成可重复使用的测试用例,你可以在持续集成框架(如Cruise Control)中运行这些测试用例。

接下来InfoQ问询了FlexMonkey与其他Flex测试工具有何区别:

我们注意到FlexMonkey是唯一一个完全基于Flex的记录/回放工具。它无需浏览器插件(当然除了Flash player以外),也用不着特殊的脚本语言。记录下来的UI场景可以作为ActionScript的源代码,它们既可读又可编辑。甚至不需要使用记录工 具就可以轻松创建测试,因为利用FlexMonkey API,我们没必要直接在ActionScript中指定大多数的UI操作。

如果你了解Flex,那么你对FlexMonkey的使用就几乎没有任何问题,能运行Flex的地方就能运行FlexMonkey(也就是说几乎任何平台都可以)。

接下来,Stern谈到了许可协议:

FlexMonkey本身基于Apache 2许可,这意味着你可以修改其源代码,并将其作为其它开源或商业产品的一部分。很显然,Gorilla Logic认为将FlexMonkey放出价值更大,而并不是将其作为一个产品来卖!

但我们应该注意到FlexMonkey依赖于Adobe的Flex Automation API,它位于FlexBuilder专业版中。FlexBuilder标准版包含了Automation API的试用版,这限制了应用每次加载时所允许的重放次数。你可以通过FlexBuilder标准版来试用FlexMonkey,如果觉得满意再升级到专 业版。我们希望Adobe将Automation API加到大多数已开源的Flex平台中,但现在你不得不使用FlexBuilder专业版。专业版还可以进行性能与内存分析,因此如果你正在进行要求严 格的企业级开发,那么无论如何也要升级到专业版。

InfoQ谈到了测试异步功能所面临的挑战:

FlexMonkey所生成的每个UI事件都是异步的,而且FlexMonkey都会在生成每个后续事件前暂停(默认暂停500毫秒)。如果你有一个运行时间很长的数据库查询(比如由按钮点击所触发),那么在按钮事件产生后你可以增加延迟时间。

像FlexUnit这样的测试运行框架也需要针对异步操作进行特殊的处理。FlexMonkey API本身就是异步的,因此你需要通过某种手段告诉运行器测试何时完成。当FlexMonkey在一个测试用例中处理完所有的事件时它会产生一个 READY_FOR_VALIDATION事件。如果使用FlexUnit,你需要在调用下一个测试用例前使用FlexUnit的addAsync方法来 告诉FlexUnit等待这个事件完成。

我还要补充一下,尽管FlexUnit是当前唯一一个直接集成到FlexMonkey中的 xUnit框架,但你仍然可以将其他针对Flex的xUnit框架与FlexMonkey搭配使用。我再强调一次,FlexMonkey测试其实就是 ActionScript。此外,你可以直接将其他任何xUnit框架集成到FlexMonkey中并生成代码,就像我们对FlexUnit所做的一样 (请放心大胆地去做吧)。

InfoQ紧接着问道,FlexMonkey是如何使用Flex Automation框架的:

当你运行一个使用了Automation API的应用时,每个UI事件(如按钮或者鼠标点击)都会生成一个“automation事件”来描述相应的UI事件。这种包含在automation事 件中的信息可以反馈到Automation API中并产生一个假的按钮点击,而Flex对其的响应就好像它是原生的UI事件一样。正如我之前所提到的,通过使用FlexMonkey API,你可以创建一个此前并没有被Automation API记录下来的事件。我们可以使用FlexMonkey记录并回放几乎任何Flex UI事件,包括相关的“exotic”操作,比如某个DataGrid里的itemEditor是一个ComboBox,那么我们就可以从中选择一个条 目。

最后,InfoQ问Stern,读者还需了解什么:

尽管我们的开源项目还是个新兵,但FlexMonkey却相当稳定。它有丰富的文档。大多数人能在不到一小时内就成功运行起来。

你可以运行http://keystone.gorillalogic.com/~sstern/MonkeyContacts.html上的这个示例应用来快速了解FlexMonkey。如果你运行这个示例,你会看到记录并回放UI场景是多么的简单,你还能看到生成的ActionScript是什么样子的。

该项目本身位于http://flexmonkey.googlecode.com。我们希望看过这篇新闻的每个人都能加入我们这个快速发展的社区!

查看英文原文:Flex Testing with FlexMonkey

[C#]C#反射程序集

mikel阅读(1101)

近来刚好在看一些关于反射的东西,之前一直没用过,真是惭愧,后来看了些资料后,觉得好像也不怎么难,就一句话:
   Assembly.Load(Assembly.GetExecutingAssembly().FullName).CreateInstance(Namespace + "." + ClassName);就搞掂了,

       但是很多貌似简单(或许真的是很简单吧)的问题就搞了我很久,就是关于那个程序集的问题,一开始的时候,

       只是知道Assembly.Load("程序集名")这个,只是知道用Assembly.GetExecutingAssembly().FullName这可以拿到了,

      看似一切都是那么的简单,但是当我在调试时,却发现我反射不出那个类,找了些资料才知道,原来是程序集出了问题了.

      正确点来说,是我用错了程序集,对于很多新人来说,或是刚接触的反射的来说,可能并不怎么了解那些程序集是怎么一回事.

      我做了测试后得出:
       1.类
              所有的类是在同一个程序集中,所有的类都在App_Code的文件夹下(默认),在App_Code里,不管你分几个文件夹存放那些类,不管
              类中有多少个namespace,都只有一个程序集.
       2.用户控件
             每一个UserControl属于不同的程序集,不管你是否放在同一个文件夹里.
       3.页面
             每一个不同的页面都属于同一个程序集.不管程序代码的命名空间是否一致.在运行时,所有页面的命令空间会默认显示
             为"ASP",而你加的命名空间,则和页面的名字加起来统称为基类名了.

       关于反射Assembly.Load("程序集").CreateInstance("命名空间.类"),而不管在哪一层写这段代码其中的("程序集")
读取的实际是web层bin文件夹下的dll,也就是说你反射的类的程序集dll在web层的bin下必须有,当我们的程序运行或发布时,.Net工具会自动
的添加当前项目的类的dll,页面的dll,还有用户控件的dll.
       注意CreateInstance()一定是命名空间.类名,否则创建的实例为空
              Assembly.Load("程序集名")
              Assembly.LoadFrom("程序集实际路径")
  希望我这些总结可以给那些刚入门的朋友一点帮助,本人才疏学浅,要是有什么不对的地方,还忘朋友倍们指出.

在此赋上我的测试代码.Reflect程序集测试例子  ,大家下载后,用VS中打开后,可以直接浏览default,和default2这两个页面,并做些对比,相信这时你会明白很多.

[C#]应用系统架构设计

mikel阅读(864)

应用系统架构设计

应用系统架构设计  Simonw@2005.4.24 如有转载请注明出处。
 

我 们在做着表面上看似是对于各种不同应用的开发,其实背后所对应的架构设计都是相对稳定的。在一个好的架构下编程,不仅对于开发人员是一件赏心悦目的事情, 更重要的是软件能够表现出一个健康的姿态;而架构设计的不合理,不仅让开发人员受苦受难,软件本身的生命周期更是受到严重威胁。这里我将针对在微软 dotNet平台上做应用开发系统的一般架构流程设计做一个粗浅的讨论。

 

总体设计图 

 

表示层

表示层由UI(User Interface)和UI控制逻辑组成。

l         UI(User Interface)

UI是客户端的用户界面,负责从用户方接收命令,请求,数据,传递给业务层处理,然后将结果呈现出来。根据客户端的不同我们大体将应用程序分为BS(Browser-Server) 浏览器结构,CS(Client-Server)桌面客户端结构。

BS 的优点是无需操心客户端,只需要部署维护好服务器即可。CS的优点在于强大的界面交互表达能力。RIA(Rich Internet Application)是为了融合这两种结构优点的一种技术,它依赖在客户端一次性安装一个通用解释器之后即获得强大的界面交互表达能力和无需部署具体 客户端的方便性。具体的实现技术很多,例如微软的SmartClient, Avalon; Macromedia的Flex;以JS为基础的Bindows;Ajax等等很多。

 

l         UI控制逻辑

UI 控制逻辑负责处理UI和业务层之间的数据交互,UI之间状态流程的控制,同时负责简单的数据验证和格式化等功能。具体的说在dotNet事件驱动的编程模 型下,UI控制逻辑被自然的实现在了事件函数中,例如PageLoad事件函数,ButtonClick事件函数。在这些事件函数中,主要任务就是做UI 控件与业务实体的数据交换与业务调用,但面对大量的数据交换工作量与维护量就成了最大的问题。而在复杂应用的系统中,状态与流程的管理是必须要考虑的因 素,它们同样是业务逻辑的一部分,如果不加以封装的直接写在事件函数中将导致业务依赖表示层。下面分别讨论这两个问题。

 

1.         1.UI与业务实体之间的数据交互

此 阶段负责数据交换的业务实体称为DTO(Data Transfer Object),处理输入时我们从UI控件的获得数据填入DTO再向下传播,处理输出时用户发出请求业务层会将数据以DTO的形式返出再赋给UI控件展 现。因此需要一种方式来自动解决这样的来回赋值问题。遗憾的是dotNet下的不少控件虽然支持数据绑定但仍然没有一个现成完整的解决办法。我们可以自己 设计一个Adapter按照某种映射关系来自动处理这样的绑定,这样的映射关系最好是UI控件与DTO属性的事先命名约定,以此种方式的约定作为映射关系 无需增加任何配置文件和配置工作即可实现。

 

2.         2.状态与流程的管理

既然是业务逻辑的一部分就不应该耦合再表示层当中。MVC(Model-View-Controller) 模式提供了实现这一目标的方法。Controller是整个方案的核心,它是一个流程管理器,来自UI所有的命令与数据经过Controller分发给业 务层或其他UI,这样我们可以把流程,权限等逻辑单独封装,例如配置文件中,达到最大化的业务重用。dotNet下MVC的方案并不像Java下有那么多 选择,目前有以下几种选择:

微软的UIPAB,它可以处理bs,cs下的流程跳转,可以使得相同的业务系统有webform和winform不同的展现方式。

开源的Mavrick.Net,它只适用于ASP.NET应用程序,它对流程,国际化,页面包装,xslt页面转换提供了很好的支持。

开源的Lattis,同样只适用于ASP.NET应用程序。

 

业务层

业务层封装了实际业务逻辑,包含数据验证,事物处理,权限处理等业务相关操作,是整个应用系统的核心。因此设计一个能够真实反映实际需要的业务层是非常必要的,我们将实际业务具体分为业务数据与业务操作两部分。

 

l         业务数据

业务数据又是业务逻辑的核心,最终业务数据将以一种固定的格式表现于内存中,在系统的各个层次间传输,充当DTO角色。表达业务数据的方式一般分为两种Table Model和Domain Model。

Table Model是将数据库中的表直接映射成为业务数据对象,这样的优点是适合于机器操作,ADO.NET直接提供了这种操作的便利,但对于复杂业务关系的表达 就很不直观。只适合于业务需求与数据表对应关系很直接的需要快速开发的情况。通常我们选用Dataset或者强类型Dataset(Strong Typed Dataset),强类型Dataset支持编译时的类型检查,效率上要略高于普通Dataset。Dataset有很多方便的特性:无需自己编写维护 类,支持序列化,数据副本保存,支持数据集合,对控件绑定支持效果好,微软提供了相应的生成工具以及持久方案。但缺点也是明显,复杂数据表现不直观,做为 DTO在各个层次间传输,尤其是分布式环境,庞大的体积,相对缓慢的实例化对于性能造成很大压力。

Domain Model则是根据实际业务按照现实方式用OO思想建模,这样很适合业务复杂的系统。通常采用自定义数据实体(Custom Data Entity)方式表达。自定义数据实体,有着良好的性能,编译时的类型检查,数据表现方式非常直观符合实际业务的操作方式等优点,但需要自己定义维护 类,在分布式环境下需要自己编写序列化方法。

综合各种因素考虑,虽然业务简单对应直接的系统我们以Table Model建模开发效率很高但难免保证系统日后不会变的复杂,因此出于复用性,扩展性,性能等方面选用Domain Model建模为佳。

 

l         业务操作

业务操作负责对业务数据进行各种业务相关的处理,例如验证,流向,整合,事物,权限等,但它不负责有关对数据源的操作。它与业务数据的关系设计有2种方式。

分 离业务数据与业务操作,将业务数据单独封装到只有数据get,set的数据类中,这个数据类只充当DTO。将业务操作封装到独立的service类中与业 务数据一起充当业务层。这样当系统不复杂的时候显的简单直观,而随着系统日益复杂,service类会变的杂乱,而将本身耦合紧密的数据与操作分离对于复 用也是不利的因素。具体可参考Martin Fowler 的贫血的Domain Model一文,但我并不倾向于业务层直接访问数据源。

整 合业务数据与业务操作,将业务数据与相关的业务操作封装在一起称为业务实体,业务实体作为统一的业务层为表示层提供服务,同时也负责作为DTO在各个层次 间传输,我倾向于这样完整的Domain Model设计方式,每个业务实体都可以做为一个单独组件形式存在,对于组件化复用有着莫大的好处。

 

l         业务模块间的依赖

各 个业务模块之间的依赖,有时候会是难以解决的问题,尤其是一些可以重复利用的业务组件,例如权限管理,邮件发送等等。管理好这些各种不同的业务组件是我们 的目标,IoC容器为我们提供了最完美的方案,通过它将不同的模块注入到系统中我们可以在不知道这个组件存在的情况下调用它。但目前只有不成熟的Spring.Net一个选择,我们只有一声叹息,因此也就不多讨论了。

 

业务数据访问层

业 务数据访问层是一个针对具体应用系统的专属层,它为业务层提供与数据源交互的最小操作方式,仅仅是业务层需要的数据访问接口,业务层完全依赖业务数据访问 层所提供的服务。这些服务负责从业务层接收数据或返回业务实体,它屏蔽了实际业务数据与机器存储方式的差别。当然,数据层选用抽象的解决方案同样可以达到 这个效果,但业务数据访问层最大的特点就是针对具体业务做抽象,而抽象的数据层访问方案是针对通用做抽象。往往业务中针对具体的设计生命力会变的更强,这 样我们可以最大限度的保持了上层代码的复用性,当需要更换存储策略如果数据层访问差别太大,通过更换数据层无法解决问题的时候我们最多只需要更换业务数据 访问层,而无需改变业务层。

 

业务数据访问层由DAO(Data Access Object)层和系统服务层两部分组成。DAO层为每个业务实体提供最基本的数据访问服务,系统服务层为系统全局提供与业务关系不大的通用数据访问服务,这两层处于系统中的同一个层次位置。

 

业务层与业务数据访问层关系图

 

 

数据层

数据层的宗旨就是为数据源提供一个可供外界访问的接口,我们应该选用一种能够提供数据源无关的抽象数据访问接口并通过在其下挂接各种不同的DataProviador来访问数据源的数据层组件,这样做便于移植到不同的数据源上。目前有以下3种数据层方案:

 

1.        1. 封装ADO.Net

这 些数据访问组件都是基于ADO.Net的浅封装,它的优点在于封装层次低所以速度最快,我们可以手动组织SQL语句用来适应复杂的操作以及个性的优化等。 缺点是无法直接处理自定义数据实体方式的业务实体对象,需要将业务实体中的数据属性以参数形式传入传出。这样的方式虽然最为保险,但随着系统规模增大,开 发效率,质量,,后期的维护,二次开发都变成尤为突出的问题,对开发人员的要求会变的越来越高。另外对于事物操作封装不是很好,无法提供声明性事物,经常 会在业务层出现访问数据层的需要。这样的组件目前应用的很广泛,例如微软在EnterpriseLibrary中提供的DAAB(Data Access Application Block),还有以前的DAAB3.1。EnterpriseLibrary是个成熟的产品,包括了数据访问,异常,日志,缓存,加密,配置,安全等组件做为通用服务非常适合。

 

2.        2. or-Mapping组件

ORM 是最好的数据持久解决方案,它的优点在于能够以面向对象的方式操纵数据,因此可以直接处理自定义数据实体的业务对象,我们根本不用操心SQL语句以及底层 存储方式,这样极大的简化的代码提高了开发效率,对于日后维护扩展都带来极大的便利。缺点在于屏蔽了底层使得我们无法针对具体数据源做优化,而且对于复杂 关联的SQL操作有些力不从心,同时性能也差一些但辅助以缓存情况会好很多,而在dotNet下最大的问题就是没有一个成熟便宜的ORM产品供我们使用, 全部都是beta版本和商业版本。这些版本或多或少都存在一些问题,以至于真正应用中需要经过仔细考察。例如 NHibernate,Gentle.Net,XPO,Grove.Net等等非常多。

 

3.        3. DataMapper(SqlMapper)

SqlMapper为以上两种方式提供了一个折中的选择,它可以以面向对象的方式直接处理自定义数据实体的业务对象,同时可以根据与数据源与业务实体的映射关系执行手写的sql语句,这样完全使得我们可以针对具体数据源做优化,对于复杂操作同样可以胜任。目前只有iBatis.Net一个产品,它是一个java移至的开源项目,已经比较成熟,可以在无需编译的情况下随意替换DAO。

 

 

至 此,整个架构方案的讨论已经完成,我们可以看出dotNet下可供选择的解决方案是那么的有限,反看Java世界,有那么多成熟可供利用的组件框架,流口 水中…不过dotNet也正在走向成熟,我们需要时间等待。这个架构设计的思路只代表了我个人的理解,而且也并不是说所有的开发都是这么一套方案,在 具体环境中需要做具体的调整。希望能起到一个抛砖引玉的作用。我的邮箱是i-simon AT msn.com,由于我经验尚浅,有不正确或不足的地方欢迎指正讨论,另外本文将根据技术的最新进展持续更新。
应用系统架构设计-补全版:http://simonw.cnblogs.com/archive/2005/10/27/263145.html

[SQL]临时表和表变量

mikel阅读(1177)

我们经常使用临时表和表变量,那现在我们就对临时表和表变量进行一下讨论.

临时表
局部临时表
全局临时表
表变量

                              
临时表
临 时表存储在TempDB数据库中,所有的使用此SQL Server 实例的用户都共享这个TempDB,因为我们应该确保用来存储TempDB数据库的 硬盘有足够的空间,以使之能够自己的增长.最好能够存储在一个拥有独立硬盘控制器上.因为这样不存在和其它的硬盘I/O进行争用.
 
我 们很多程序员认为临时表非常危险,因为临时表有可能被多个连接所共享.其实在SQL Server中存在两种临时表:局部临时表和全局临时表,局部临时表 (Local temp table)以#前缀来标识,并且只能被创建它的连接所使用.全局临时表(Global temp table)以##前缀来进 行标识,并且可以和其它连接所共享.
 
局部临时表
局部临时表不能够被其它连接所共享的原因其实是在SQL Server 2000中自动为局部临时表的表名后面加上了一个唯一字符来标识.如: 
     Create TABLE [#DimCustomer_test]
     (
        [CustomerKey] [int]
        ,   [FirstName] [nvarchar](50)  
    ,[MiddleName] [nvarchar](50)  
    ,[LastName] [nvarchar](50) 
        )

现在我们来查看一下TempDB中 sysobjects表,我们会发现我们新创建的临时表#DimCustomer_test已经被加上了后缀:
 
  USE TempDB
  GO
  Select name FROM sysobjects Where name LIKE ’%DimCustomer%’

 
the Result is:
name
#DimCustomer_test___________________________________________________________________________________________________000000000005
全局临时表
下面我们来看一下全局临时表:
     Create TABLE [##DimCustomer_test]
     (
        [CustomerKey] [int]
        ,      [FirstName] [nvarchar](50)  
    ,[MiddleName] [nvarchar](50)  
    ,[LastName] [nvarchar](50) 
        )

现在我们来查看一下TempDB中 sysobjects表,我们会发现我们新创建的临时表##DimCustomer_test没有被加上了后缀:
 
  USE TempDB
  GO
  Select name FROM sysobjects Where name LIKE ’%DimCustomer%’

 
The Result are:
#DimCustomer_test___________________________________________________________________________________________________000000000005
##DimCustomer_test
 
–Drop test temp tables
                              Drop TABLE [##DimCustomer_test]
                              Drop TABLE [#DimCustomer_test]

 
可以看到我们刚才创建的全局临时表名字并没有被加上标识.
 
表变量
表变量和临时表针对我们使用人员来说并没有什么不同,但是在存储方面来说,他们是不同的,表变量存储在内存中.所以在性能上和临时表相比会更好些!
 
另一个不同的地方是在表连接中使用表变量时,要为此表变量指定别名.如:
 
  USE AdventureWorksDW
  GO
  DECLARE @DimCustomer_test TABLE 
  (
     [CustomerKey] [int]
     ,      [FirstName] [nvarchar](50)  
 ,[MiddleName] [nvarchar](50)  
 ,[LastName] [nvarchar](50) 
     )
  —insert data to @DimCustomer_test
  Insert @DimCustomer_test 
  (
     [CustomerKey]  
     ,      [FirstName]  
 ,[MiddleName]  
 ,[LastName] 
     )
  Select  
     [CustomerKey]  
     ,      [FirstName]  
 ,[MiddleName]  
 ,[LastName] 
  FROM DimCustomer
  Select [@DimCustomer_test].CustomerKey,SUM(FactInternetSales.OrderQuantity)
 FROM @DimCustomer_test  INNER JOIN FactInternetSales   ON
 @DimCustomer_test.CustomerKey = FactInternetSales.CustomerKey
 Group BY CustomerKey

 
Result:
 
Server: Msg 137, Level 15, State 2, Line 32
Must declare the variable ’@DimCustomer_test’.
 
 
如果我们对上面的查询进行更改,对查询使用别名(并且找开IO):
—–in the follow script,we used the table alias.
 DECLARE @DimCustomer_test TABLE 
 (
    [CustomerKey] [int]
    ,      [FirstName] [nvarchar](50)  
,[MiddleName] [nvarchar](50)  
,[LastName] [nvarchar](50) 
    )
 Insert @DimCustomer_test 
 (
    [CustomerKey]  
    ,      [FirstName]  
,[MiddleName]  
,[LastName] 
    )
 Select  
    [CustomerKey]  
    ,      [FirstName]  
,[MiddleName]  
,[LastName] 
 FROM DimCustomer
 Select t.CustomerKey,f.OrderQuantity
 FROM @DimCustomer_test t INNER JOIN FactInternetSales  f ON
 t.CustomerKey = f.CustomerKey
 where t.CustomerKey=13513

 
表变量在批处理结束时自动被系统删除,所以你不必要像使用临时表表一样显示的对它进行删除.