精华内容
下载资源
问答
  • 并利用具体的例子来全面介绍每个特性,不仅讨论了各个特性是什么,还说明了它是如何工作的,如何使用这个特性来开发软件,以及有关的常见陷阱。  本书面向所有oracle 数据库应用开发人员dba。 作译者 作者  ...
  • 玻璃温室大棚外观现代、新颖,结构稳定,视觉流畅,...玻璃温室以玻璃为主要透光覆盖材料的温室,通常分为单层玻璃温室双层玻璃温室双层中空玻璃覆盖较单层玻璃覆盖的防集露性强,保温效果好,更适用于北方的自.

    玻璃温室大棚外观现代、新颖,结构稳定,视觉流畅,透光率极强,可高达90%以上,抗风雪能力强。温室采光面积大,室内光照均匀:内部宽敞明亮操作空间大温室利用率高外型美观,有很强的观赏性,温室有很强的排水能力,可大面积连栋。玻璃温室具有较好的透光率,其透光率90%:使用寿命长,展示效果佳,透光率稳定。不会随着时间的推移使得透光率下降抗老化性好防结露性好。

    为什么现代农业种植中连栋玻璃温室大棚发挥的优势更明显

     

    玻璃温室是以玻璃为主要透光覆盖材料的温室,通常分为单层玻璃温室和双层玻璃温室双层中空玻璃覆盖较单层玻璃覆盖的防集露性强,保温效果好,更适用于北方的自然条件。力求满足植物或生物最大光照的需求情况下,达到最佳保温效果,采用现代先进技术对温室细节进行技术密封处理,充分利用自然条件促进生物或作物的各项指标生长,中空玻璃温室采用浮法玻璃高透光率,规格常用5mm+9mm+5mm,4mm+9mm+4mm两种规格应用范围:在栽培设施中,玻璃温室作为使用寿命最长的一种形式,适合于多种地区和各种气候条件下使用通常用于中高档花卉蔬菜水果种植、科研温室、生态餐厅酒店、花卉市场、观光展示、种苗繁育、特种养殖等玻璃温室大多为尖顶的结构形式,主要有文洛型和大尖顶型,也有多边体形、拱形、金字塔形,并可组合建成综合温室群。主体结构采用装配式热镀锌钢骨架,配合温室专用铝合金型材及抗老化密封橡胶件。

    为什么现代农业种植中连栋玻璃温室大棚发挥的优势更明显

     

    玻璃温室配套系统:可根据使用要求配套外遮阳系统,内遮荫系统,保温系统,自然通风系统,风机湿帘强制降温系统,微雾降温系统,灌溉系统(灌溉系统可分为滴灌系统、喷灌系统、移动喷灌机系统等),C02补充系统,补光系统,施肥系统,加温系统,环流风机系统,苗床系统,物联网及自动控制系统,顶喷淋系统等。

    为什么现代农业种植中连栋玻璃温室大棚发挥的优势更明显

    玻璃温室常规产品参数:

     

    玻璃温室常用栋宽:9.6m:10.8m:12m:6.4m:7.2m:8m

    玻璃温室常用开间:4m;8m;5m

    玻璃温室水槽高度:4m;4.5m;(2.5m-10m)

    玻璃温室风载:0.5KN/m雪载:0.3KN/m可以根据实际使用情况另外设计槽高3m-4.5m左右,一般情况不建议建设高檐高温室,对于空间温室的处理及光照处理有一定的弊病。

    为什么现代农业种植中连栋玻璃温室大棚发挥的优势更明显

     

    玻璃温室顶部建议采用阳光板或5mm钢化玻璃。

    展开全文
  • 因为我们的数据结构考试的范围就限定在内部排序上,所以我没有什么办法,只好对自己埋头苦干就行内部排序的编程了。有些内部排序的例子很好理解,我们可以通过一些图示来很好地了解到这些排序的过程,但是这些程序...
  • 游戏中人体皮肤实时渲染第一弹

    千次阅读 2017-07-27 10:38:21
    要渲染皮肤,首先要知道皮肤的整体构成及属于一种什么样的材质,根据现代医学分析,皮肤大致的整体结构分为表皮层,真皮层皮下组织,并且轻微半透明的,所以我们知道了,皮肤一种多层半透明材质。 然后我们...

    第一弹主要介绍原理部分,第二弹  是可以在游戏中运用的。 

    要渲染皮肤,首先要知道皮肤的整体构成及属于一种什么样的材质,根据现代医学分析,皮肤大致的整体结构分为表皮层,真皮层和皮下组织,并且是轻微半透明的,所以我们知道了,皮肤是一种多层半透明材质。

    然后我们分析光射射到皮肤上的变化。

    一小部分光在接触到皮肤的时候会直接发生镜面反射,这部分光大约占据入射光光能的百分之六,这主要以为菲涅尔互动和最上层含油的皮肤。下图展示了光在皮肤表面反射示意图。

    另一部分光穿过皮肤表层会发生来回的反射,一部分被皮肤吸收,一部分再穿过表层皮肤在某个位置穿出。下图展示了光在皮肤次表面散射的示意图。


    皮肤渲染总流程

    1.位皮肤实现一个基于物理的镜面反射模型

    我们使用BRDF进行渲染。通常BRDF的高光反射项用以下形式来表示。


    其中F代表菲涅反射项,G代表阴影遮蔽函数,D代表微面元的法线分布函数,具体BRDF的详细细节可参考:https://boblchen.github.io/images/brdf/brdf.pdf

    其中F的实现如下:

    其中halfDir代表半角向量,ViewDir代表顶点点到摄像机的方向,F0是入射时的反射值,对于皮肤我们用0.28.

    float fresnelReflectance(float3 halfDir, float3 viewDir, float F0)
    {
    	float base = 1.0 - dot(viewDir, halfDir);
    	float exponential = pow(base, 5.0);
    	return exponential + F0 * (1.0 - exponential);
    }

    我们这里对BRDF进行分解以高效的计算,我们这里预计算Beckmann法线分布函数的单个纹理并使用上述的fresnel近似得到足够高效的镜面反射计算式。

    			float PHBeckmann(float nDotH, float m)
    			{
    				float alpha = acos(nDotH);
    				float tanAlpha = tan(alpha);
    				float value = exp(-(tanAlpha * tanAlpha) / (m * m)) / (m * m * pow(nDotH, 4.0));
    				return value;
    			}
    
    			float4 frag(v2f i) : COLOR
    			{
    				float value = 0.5 * pow(PHBeckmann(i.tex.x, i.tex.y), 0.1);//使用纹理uv坐标作为ndoth和m
    				return float4(value, value, value, 1.0);
    			}

    使用上述代码生成的2D纹理得到镜面模型

    float brdf_KS(float3 normal, float3 lightDir, float3 viewDir, float roughness, float specPower, sampler2D beckmannTex)
    {
    	float result = 0.0;
    	float nDotL = dot(normal, lightDir);
    	if (nDotL > 0.0)
    	{
    		float3 h = viewDir + lightDir;
    		float3 halfDir = normalize(h);
    		float nDotH = dot(normal, halfDir);
    		float PH = pow(2.0 * tex2D(beckmannTex, float2(nDotH, roughness)).r, 10.0);
    		const float F0 = 0.028; // Reflectance at normal incidence
    		float F = fresnelReflectance(halfDir, viewDir, F0);
    		float frSpec = max(PH * F / dot(h, h), 0.0);
    		result = frSpec * nDotL * specPower;
    	}
    	return result;
    }


    2.次表面散射模型

    本文提供的人体皮肤的渲染方法是用高斯函数求个近似半透明材质表面光的漫反射剖面(漫反射剖面表达的是每种颜色在材质剖面的传播及散射的数学分析,函数的参数是距离光源中心的距离及角度,我们使用一条一维曲线来表达,每种颜色有各自的漫反射剖面,如下图),这个高斯函数使用两次一维卷积来实现,通过对辐照度问的的滤波与线性组合最终生成用于实时渲染的人体皮肤纹理。


        对漫反射剖面近似有两种理论,分别是偶极子近似和多极子近似,这两种理论分表描述了光在进入人体皮肤后的传播和反射情况,后者补充了光在穿过在像耳朵这种薄的部位的情况,实际上多极子的方法实际上就是多个偶极子共同作用。注:这两种理论读者无需悉知,因为咱们用不到,有兴趣的读者可以自己研究下。

    由于偶极子和多极子近似多层半透明材质漫反射剖面的方法不适于实时渲染,我们这里引入高斯函数求和来对偶极子和多极子进行近似。从而提高算法效率。

    使用高斯函数求和主要有三个优点。第一,因为二维高斯函数可以分离成x方向和y方向的两个一维卷积来实现。第二,一个较宽的高斯函数的卷积可以在之前较窄的高斯函数卷积的结果上进行计算。这样计算精度可以得到很好的提高。第三,任意两个高斯函数的二维径向卷积结果为另一个高斯函数。

    四个高斯函数可以很好的满足单一薄层的剖面,增加高斯函数的个数可以相应的增加精确度。

    针对皮肤三层模型,我们使用以下高斯参数来近似漫反射剖面



    介绍完使用高斯函数求和来近似漫反射剖面后,我们开始整个渲染流程,如下图



    具体来说有三步:

    (1)计算辐照度纹理。在顶点着色器将模型UV坐标作为屏幕位置输出,同时输出模型每个顶点的世界坐标位置,在像素着色器中对每个像素进行漫反射光照计算(如有阴影则考虑在内),得到辐照度纹理。

    (2)对得到的辐照度纹理进行6次卷积操作,卷积核由漫反射剖面来确定,并生成6张卷积后的图像,由于本技术在弯曲表面的时候会有一些问题,所以需要进行UV矫正,需要计算拉伸纹理,来加入到每次高斯模糊中,下面详述。

    (3)将(2)得到的多张图像根据高斯权重线性组合得到最终的次表面散射结果,加上镜面反射的结果,就是最终结果。


    再计算辐照度文理的时候,要考虑到光能守恒,我们只需要考虑穿入皮肤表层以下的光量,所以要就算高光反射出去的光量,可以根据以下方案来计算高光反射的光量并存入纹理中。

     			float4 frag(v2f i) : COLOR
     			{
     				float cosTheta = i.tex.x; // N dot L or N dot V
     				float m = i.tex.y; // Roughness
     				float sum = 0.0;
     				float3 N = float3(0.0, 0.0, 1.0);
     				float3 V = float3(0.0, sqrt(1.0 - cosTheta * cosTheta), cosTheta);
     				for (int j = 0; j < NUM_TERMS; ++j)
     				{
     					float phip = (float(j) / float(NUM_TERMS - 1)) * (2.0 * PI);
     					float localSum = 0.0;
     					float cosp = cos(phip);
     					float sinp = sin(phip);
     					for (int k = 0; k < NUM_TERMS; ++k)
     					{
     						float thetap = (float(k) / float(NUM_TERMS - 1)) * (PI / 2.0);
     						float sint = sin(thetap);
     						float cost = cos(thetap);
     						float3 L = float3(sinp * sint, cosp * sint, cost);
     						localSum += brdf_KS(N, L, V, m, 1.0, _BeckmannTex) * sint;
     					}
     					sum += localSum * (PI / 2.0) / float(NUM_TERMS);
     				}
    
     				float value = sum * (2.0 * PI)/ float(NUM_TERMS);
     				return float4(value, value, value, 1.0);
     			}

    然后再计算辐照度纹理,由于考虑到光在耳朵等薄的部位会发生透射,所以我们要计算渲染点处的皮肤厚度,并存入辐照度纹理a通道中,计算厚度在之前的文中有介绍,下面是辐照度的计算。

    float3 diffuse = max(0.0, nDotL) * _LightColor0.rgb;
    float reflectedEnergy = _SpecPower * tex2D(_AttenuationTex, float2(nDotL, _Roughness)).r;
    float3 lighting = (1 - reflectedEnergy) * diffuse;

    得到辐照度纹理后,我们进行六次矫正的高斯模糊,矫正纹理的计算如下:

    float3 deriv_u = ddx(i.posWorld);
    float3 deriv_v = ddy(i.posWorld);
    float stretch_u = (1.0 / length(deriv_u)) * _StretchScale;
    float stretch_v = (1.0 / length(deriv_v)) * _StretchScale;
    return float4(stretch_u, stretch_v, 0.0, 1.0);

    然后进行高斯模糊的U方向的代码如下,V方向同理:

    	float stretch = tex2D(_StretchTex, i.tex).r;
    	float scale = (1.0 / _TextureSize) * stretch * _GaussianWidth / _BlurStepScale;
    
    	float curve[7] = {0.006, 0.061, 0.242, 0.383, 0.242, 0.061, 0.006};
    	float2 coords = i.tex - float2(scale * 3.0, 0.0);
    	float4 sum = 0.0;
    	for (int j = 0; j < 7; ++j)
    	{
    		float4 tap = tex2D(_MainTex, coords);
    		sum += curve[j] * tap;
    		coords += float2(scale, 0.0);
    	}
    
    	return sum;


    6次高斯模糊之后我们得到6张模糊后的纹理,然后在最终shader中进行线性组合,

    				float4 tap1 = tex2D(_IrradianceTex, i.tex);
    				float4 tap2 = tex2D(_Blur2Tex, i.tex);
    				float4 tap3 = tex2D(_Blur3Tex, i.tex);
    				float4 tap4 = tex2D(_Blur4Tex, i.tex);
    				float4 tap5 = tex2D(_Blur5Tex, i.tex);
    				float4 tap6 = tex2D(_Blur6Tex, i.tex);
    				float3 totalWeight = _Blur1WV.xyz + _Blur2WV.xyz + _Blur3WV.xyz + _Blur4WV.xyz + _Blur5WV.xyz + _Blur6WV.xyz;
    				float3 diffuse = float3(0.0, 0.0, 0.0);
    				diffuse += _Blur1WV.xyz * tap1.rgb;
    				diffuse += _Blur2WV.xyz * tap2.rgb;
    				diffuse += _Blur3WV.xyz * tap3.rgb;
    				diffuse += _Blur4WV.xyz * tap4.rgb;
    				diffuse += _Blur5WV.xyz * tap5.rgb;
    				diffuse += _Blur6WV.xyz * tap6.rgb;
    				diffuse /= totalWeight;

    组合之后的结果加上在薄的部位的透射光(之前玉石渲染里有介绍),得到散射的结果。


    然后再计算出高光部分结果,相加就是最终效果。

    当然,还有接缝问题的处理,预先散射变形,后置散射变形等。

    接缝可以根据,6次拉伸纹理的a通道去计算边界,然后和关闭散射使用传统漫反射的结果做一个lerp。

    预先散射变形,后置散射变形是在计算辐照度的时候引入纹理颜色还是在最后引入纹理颜色。

    解决办法可以在计算辐照度的时候乘上pow(albedo,_Mix),在最后散射记过再乘上pow(albedo,1-_Mix)。来解决。


    最终的渲染结果如下:




    参考:

    https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch14.html







    展开全文
  • 数据采集分析系统

    2021-01-06 16:33:44
    数据埋点分析系统都做了些什么?采集了哪些数据?这些数据我们将如何运用分析?最终又将如何展示呢? 首先我们看下系统结构。整个系统由以下 4 个部分组成,期望能提供一套完整的用户行为分析的解决方案: 埋点...

    1.系统概览

    数据埋点分析系统都做了些什么?采集了哪些数据?这些数据我们将如何运用和分析?最终又将如何展示呢?

    首先我们看下系统结构。整个系统由以下 4 个部分组成,期望能提供一套完整的用户行为分析的解决方案:

    1. 埋点采集 JSSDK:收集用户行为数据,并进行上报;
    2. 数据处理服务:接收上报数据并存储;筛取所需数据,进行数据处理并透出;
    3. 数据可视化平台:汇总展示详细数据,支持自定义,打通业务;
    4. Chrome插件工具:在页面上直观展示坑位数据,提供场景更友好的数据可视化服务;

    其基本协作流程是,用户进入平台任意一个已埋点的 Web 页面,进行的一系列(进入、点击、滚屏等)操作,都会由 JSSDK 进行分类并将数据上报至服务端进行存储,再由站点 / 插件发起查询,服务端将处理后的数据返回,再通过数据可视化平台进行透出展示。

    2.数据采集

    数据采集一般分为以下三种:

    1. 无埋点(全埋点):零埋点成本,抓取用户行为全量数据,任何操作行为都会被上传。数据量大,“噪音”多;
    2. 可视化埋点:在页面中操作,选择埋点位置/模块,非开发人员也可以进行埋点;
    3. 侵入式埋点:埋点时需要将数据采集代码写入业务代码中,埋点成本较高,但准确度也更高;

    由于对数据的准确度要求较高,同时希望前期只投入较少的开发资源就可以进行快速试错,并为了满足重点的用户行为数据的采集需求,因此,我们优先采用代码侵入式埋点方案**。**

    同时针对其接入成本较高的劣势,我们也将埋点在搭建系统及组件中采用了自动化的植入方式,这点将不再此详述。为降低接入成本并且更加灵活的捕获数据,我们采用了 DOM 节点挂载特殊属性后自动发送和手动自定义发送两种方式结合,以满足不同场景的需要。

    //自动发送埋点方式,举例:
    <button data-utm-click="${did}" data-utm-data="${业务数据}">
    //手动发送埋点方式,举例:
    const utmCnt = g_UTM.batchSend('触发类型(click/browse)等',[{
        utmCD:['区块信息','位置信息'],
        bdata:{key:'其他业务数据'}
      },{
        utmCD:['001','008'],
        bdata:{key:'value'}
      }
    ]);
    

    基于用户行为分析这个大目标,我们所采集数据紧紧围绕着两个主题,即:Event(事件/行为)和 User(用户)。

    围绕“事件“我们采集了:事件的类型、发生时间、页面位置等信息,组成事件唯一标识。

    围绕”用户“我们采集了:用户 IP、操作系统、浏览器信息、屏幕分辨率等,并生成用户唯一标识植入 Cookie 中。

    {
      bdata: {}, //业务数据
      createTime: "1571038815128", // 创建时间
      evt: "browse", // 事件类型
      ipAddr: 122.226.174.195, //ip地址
      logType: 2, // 触发类型
      lver: 1.1.0, //版本
      mx: 0, // 页面位置坐标x
      my: 0, // 页面位置坐标y
      os: "Windows/7", // 操作系统
      pre: "https://www.zcygov.cn/", // 来源地址
      scr: "1920x1360", // 屏幕分辨率
      url: "https://www.zcygov.cn/", // 页面地址
      userId: "001", // 用户标识
      utmCnt: "a0004.2ef5001f.0001.0001.d814bf60ee5511e99397b37fe9083257", // 触发位置
      utmUrl: "a0004.2ef5001f.0001.0001", // 来源位置
      uuid: "d7fd8de0-ee55-11e9-9397-b37fe9083257", // 浏览器唯一标识
    }
    

    上述一些收集的字段,会在下面案例中使用到。

    点击发送请求.gif

    3.数据展示

    目前前台站点已经提供了比较丰富的数据展示功能,比如:PV(浏览次数)/UV(浏览人数) 排序或趋势、漏斗分析、路径分析、热图分析、用户画像、自定义看板等等,还有各种业务相关的数据统计及报表导出功能。总体菜单如下:

    数据展示.png

    • PV/UV 排序或趋势(PV:PageView,页面浏览次数,用户每打开一次记录一次,多次打开同一页面将累计多次;UV:UserView,浏览页面人数;下文中将直接用PV/UV;)
      • 全站的PV/UV单日趋势图:分时段查看访问量的高峰和低谷;
      • PV/UV排序:查看Top页面的PV/UV
      • 按页面、时间区间查询PV/UV
    • 漏斗分析:按流程排序每个阶段的人数,计算出转化率;
    • 路径分析:查询各个页面的来源和去向;
    • 热图分析
      • 点击热图:按钮及链接点击的热图;
      • 滚屏热图(即将上线):用户页面滚屏触达率;
    • 用户画像(即将上线):针对重点用户的回访次数、浏览路径、用户身份、所在地、操作系统、浏览器等详细信息查询;
    • 自定义看板:可选择首页看板的展示项;

    image.png

    4.赋能业务

    采集和分析哪些数据才是对业务有价值的,我们参考了许多业界成熟的用户行为分析解决方案,包括:

    1. GrowingIO
    2. 神策数据
    3. 数极客

    这些产品在用户行为分析侧的功能可以说是做到了大而全。根据我们的实际需求可以筛选出以下一些重点功能模块:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N3xYZ3mp-1609921993398)(C:\Users\lekaiyu\AppData\Roaming\Typora\typora-user-images\1609913502139.png)]

    上面大部分一支持的功能都可以在【数据展示】模块中查看,表单分析及用户行为序列目前已在我们版本的规划中。表单分析是分析一个用户从进入一个表单填写页面到表单提交的过程中各个行为的分析,每个表单项的填写率、重填率、填写时长、放弃率等都是重要的分析指标,会直接影响到整体的转化率。也能帮助开发人员及时发现和定位表单页面中的交互问题,从而提升用户体验,和重要链路中的转化率。

    例如:常见的注册表单的转化,即 10 个用户进入注册页面但最后只有 7 个用户成功注册,这个功能可以有效发掘剩余 3 个注册失败的用户流失的点,找到他们是在填写哪个表单项前离开页面或是找到重填率最高的表单项进行优化。用户行为序列是从单一用户的角度去查看在我们站点上的行为轨迹,从而去分析重点用户的行为喜好。

    基于公司当前的业务发展,除了上述基础功能模块外,系统中还会对应考虑一些定制化的业务能力模块。依据目前系统的能力类型,可分为用户行为分析、链路转化分析、用户体验分析等:

    5.搜索流程埋点案例

    那么在一个页面或者一个流程中我们可以采集到哪些有价值的数据呢?下面我们就以一个简单的流程为例来说明。

    这里流程可以分为三步,首先,用户进入政采云电子卖场首页,并在搜索框中输入想要搜索的关键词,其次,点击搜索按钮后进入搜索结果页,最后,在结果页中找到了目标商品并点击进去了商品详情页查看。这是在一个电商平台中用户操作行为中较为常见的一种流程,也是一个关键流程。

    我们在上述的三个页面中会采集的数据有以下三种:

    1. 页面进入/离开自动埋点
    2. 按钮点击埋点
    3. 链接点击埋点

    gbjaorgWvUkrL8zz__thumbnail.png

    如上图所示,通过 Chrome 插件工具,可以在页面上直观的展示链接和按钮的点击次数(数据已脱敏)。

    利用上面说到的三项埋点,我们在单个页面中可以得到用户行为相关的四种数据。

    1. PV:通过计算日志中所有进入页面日志条数的总和我们可以得到 pv
    2. UV:以唯一 uuid 将 pv 进行过滤后可以得到 uv ;
    3. 按钮点击数:直接通过统计按钮点击事件上报的日志条数可以得到按钮的点击量;
    4. 链接点击数:与按钮点击有所不同,按钮点击是通过单独发送的点击事件上报来进行统计,而链接点击往往导致的是一次页面跳转,此处即为从电子卖场首页离开进入了搜索结果页,此时我们所统计的就是搜索结果页的页面进入事件中的 utmUrl(即来源按钮的唯一识别码)值,判断出该次搜索结果页的进入是来源于首页常见搜索关键词的点击,从而统计出该位置的的链接点击量。

    bVoH1OuCEtA66wys__thumbnail.png

    再对这些数据进行加工,我们进一步可以得到:停留时长、转化率、热力图;

    • 热力图:用于反映图中点的密集程度,在此处我们利用点击的坐标(点击的 x,y 坐标位置,再根据屏幕分辨率做一致性的换算)组合成点击热图,如下图所示(数据已脱敏)。

    3Lq2AEjithQwS1JR__thumbnail.png

    • 漏斗分析:由一个元事件/虚拟事件加一个或者多个筛选条件组成,表示一个转化流程中的一个关键性的步骤;在我们平台上创建一个漏斗主要由以下几步:

      漏斗分析.png

    如下图所示,在这个漏斗中定义了三个事件。

    1.png

    将这三个事件串联起来,可以得到完整的漏斗分析图(数据已脱敏)。

    2.png

    6.前端埋点方案选型和前端上报方案设计

    1)监控数据

    首先我们需要明确一个产品或者网页,普遍需要监控和上报数据,监控分为三个阶段:用户进入网页首页 用户在网页内部交互和交互中报错

    preview

    2)埋点方案

    在实际项目中考虑到上报数据灵活制定,以及减少数据传输和服务器压力,在所需埋点处不多的情况下,常用的方式是代码埋点

    以用户进入首页为例,我们在首页渲染完成后会发送事件类型和类型相关的数据给server端 告知首页的监控信息。

    preview

    3)上报周期和上报数据类型

    如果埋点的事件不是很多,上报可以时时进行,比如监控用户的交互事件,可以在用户触发事件后,立刻上报用户所触发的事件类型。如果埋点的事件较多,或者说网页内部交互频繁,可以通过本地存储的方式先缓存上报信息,然后定期上报。

    接着来确定需要埋点上报的数据,上报的信息包括用户个人信息以及用户行为,主要数据可以分为:

    • who: appid(系统或者应用的id),userAgent(用户的系统、网络等信息)
    • when: timestamp(上报的时间戳)
    • from where: currentUrl(用户当前url),fromUrl(从哪一个页面跳转到当前页面),type(上报的事件类型),element(触发上报事件的元素)
    • what: 上报的自定义扩展数据data:{},扩展数据中可以按需求定制,比如包含uid等信息

    上报数据的对象为:

    {   
        ----------------上报接口本身提供--------------------
        currentUrl,  
        fromUrl,
        timestamp,
        userAgent:{
           os,
           netWord,
        }
        ----------------业务代码配置和自定义上报数据------------
        type,
        appid,
        element,
        data:{
            uid,
            uname
        }
    }
    
    

    4)埋点和上报举例

    我们以上报首屏加载事件为例,DOM提供了document的DOMContentLoaded事件来监听dom挂载,提供了window的load事件来监听页面所有资源加载渲染完毕。

    <script type="text/javascript">
      var start=Date.now();
      document.addEventListener('DOMContentLoaded', function() {
         fetch('some api',{
             type:'dom complete',
             data:{
               domCompletedTime:Date.now()-start
             }
         })
      });
      window.addEventListener('load', function() {
         fetch('some api',{
             type:'load complete',
             data:{
               LoadCompletedTime:Date.now()-start
             }
         })
      });
    </script>
    
    

    5)前端埋点系统的前后端通信加密

    在上报数据的前后端通信中,需要和server端协商加密机制,利用 OpenSSL库来实现的加密,OpenSSL已经是一个广泛被采用的加密算法。前端可以采用node的crypto模块。

    首先来看hash算法,crypto.createHash() 来创建一个Hash实例,可利用的hash算法如下:

    • md5
    • sha1
    • sha256
    • sha512
    • ripemd160

    以sha256算法加密为例:

    const str="123445";//需要加密的字段
    const hash=crypto.createHash('sha256');//指定加密算法
    hash.update(str); //通过算法加密相应的字段
    const result=hash.digest('hex');//转化成十六进制
    

    7.前端如何实现全局 PV 统计,以 Vue 应用为例

    方案一

    通过在入口文件 index.js 全局定义 Router.beforeEach

    import App from './app'
    import Router from './router'
    
    Router.beforeEach((to, from, next) => {
        App.logEvent({
            type: 'visit',
            name: to.name,
            time: new Date().valueOf(),
            params: {
                from: {
                    name: from.name,
                    path: from.path,
                    query: from.query
                },
                to: {
                    name: to.name,
                    path: to.path,
                    query: to.query
                }
            }
        })
        next()
    })
    

    停留时长可通过 (跳转页 time - 当前页 time) 获知,但关闭应用时如何统计?监听应用关闭 onbeforeunload + onunload

    其中 App.logEvent 为自定义 Vue 插件 App 中的 method,用于向服务器发起 埋点上报请求

    import Request from './utils/request'
    
    const App = {
        // ...
        logEvent (opts) {
            Request({
                url: '/log/event',
                method: 'POST',
                data: {
                    type: opts.type,
                    name: opts.name,
                    time: opts.time,
                    params: opts.params || {}
                }
            })
        }
    }
    App.install = (Vue, options) => {
        Vue.prototype.$app = {
            // ...
            logEvent: App.logEvent
        }
    }
    
    export default App
    
    方案二

    通过在入口文件 index.js 全局注册混入 beforeRouteEnterbeforeRouteLeave 对象:

    import Vue from 'vue'
    
    Vue.mixin({
        beforeRouteEnter (to, from, next) {
            next(vm => {
                vm.$app.logEvent({
                    type: 'visit',
                    name: to.name,
                    time: new Date().valueOf(),
                    params: {
                        from: {
                            name: from.name,
                            path: from.path,
                            query: from.query
                        },
                        to: {
                            name: to.name,
                            path: to.path,
                            query: to.query
                        }
                    }
                })
            })
        },
        beforeRouteLeave (to, from, next) {
            this.$app.logEvent({
                type: 'visit',
                name: to.name,
                time: new Date().valueOf(),
                params: {
                    from: {
                        name: from.name,
                        path: from.path,
                        query: from.query
                    },
                    to: {
                        name: to.name,
                        path: to.path,
                        query: to.query
                    }
                }
            })
            next()
        }
    })
    

    关闭应用时 beforeRouteLeave 是否触发?

    上述方案存在明显缺陷:

    • 官方曰慎用全局混入对象!!!
    • 对于页面同名钩子函数 beforeRouteEnterbeforeRouteLeave,如何 merge?如何 next
    • 含子路由的页面将调用 2beforeRouteEnterbeforeRouteLeave,PV 无形翻倍…

    我猜此刻有打全局混入 createddestroyed 并通过 this.$route 获知访问对象主意的人了,试试看?

    8.前端如何实现功能点击量统计?

    方案一

    将埋点上报混入业务接口请求,无接口请求的点击采用自定义上报:

    img

    其中 param keys 指代需上报的业务请求参数 key list(并非全部参数均需随埋点上报)。

    上述方案大大节约请求数,但存在明显缺陷:

    • 将埋点上报混入业务接口,上报 crash 不仅丢失统计数据,还将影响主功能。
    • 统计与业务 高耦合,两者尽量不混于同一服务。
    方案二

    将所有点击事件视为同一类,走统一上报接口:

    logEvent (opts) {
        Request({
            url: '/log/event',
            method: 'POST',
            data: {
                type: opts.type,
                name: opts.name,
                time: opts.time,
                params: opts.params || {}
            }
        })
    }
    

    上述方案也存在明显缺陷:

    • 请求量翻倍:但统计与业务服务拆分后,请求并非同一组服务器承担。
    • 待上报的点击事件函数均需调用 logEvent:封装一枚附带埋点上报的 组件,以 Vue 为例。
    <template>
        <div class="vc-trace" @click="triggerClick">
            <slot></slot>
        </div>
    </template>
    
    <script>
    import Request from './utils/request'
    
    export default {
        name: 'Trace',
        props: {
            type: {
                type: String,
                default: ''
            },
            name: {
                type: String,
                default: ''
            },
            from: {
                type: String,
                default: ''
            },
            params: {
                type: Object,
                default: () => ({})
            }
        },
        methods: {
            triggerClick () {
                Request({
                    url: 'XXX/log/event',
                    method: 'POST',
                    data: {
                        type: this.type,
                        name: this.name,
                        from: this.from,
                        time: new Date().valueOf(),
                        params: this.params
                    }
                })
            }
        }
    }
    </script>
    

    方案本无优劣,适合才更重要,需综合考虑 产品设计产品使用度服务利用率 等等。例使用度较低应用可将统计与业务混于同一服务以节约成本,使用度较高应用可采取 本地缓存批量上报 以降低服务压力,但批量上报是否加大统计 误差

    9.实现整体流程

    img

    网站数据统计分析工具是网站站长和运营人员经常使用的一种工具,比较常用的有谷歌分析百度统计腾讯分析等等。所有这些统计分析工具的第一步都是网站访问数据的收集。目前主流的数据收集方式基本都是基于javascript的。本文将简要分析这种数据收集的原理,并一步一步实际搭建一个实际的数据收集系统。

    注:从上图中可以看出,一个统计分析平台架构的挑战来自以下 5 个:

    ​ (1)日志采集、(2)元数据管理、(3)业务数据建模、(4)任务调度、(5)OLAP引擎

    数据收集原理分析

    简单来说,网站统计分析工具需要收集到用户浏览目标网站的行为(如打开某网页、点击某按钮、将商品加入购物车等)及行为附加数据(如某下单行为产生的订单金额等)。早期的网站统计往往只收集一种用户行为:页面的打开。而后用户在页面中的行为均无法收集。这种收集策略能满足基本的流量分析、来源分析、内容分析及访客属性等常用分析视角,但是,随着ajax技术的广泛使用及电子商务网站对于电子商务目标的统计分析的需求越来越强烈,这种传统的收集策略已经显得力不能及。
    后来,Google在其产品谷歌分析中创新性的引入了可定制的数据收集脚本,用户通过谷歌分析定义好的可扩展接口,只需编写少量的javascript代码就可以实现自定义事件和自定义指标的跟踪和分析。目前百度统计、搜狗分析等产品均照搬了谷歌分析的模式。
    其实说起来两种数据收集模式的基本原理和流程是一致的,只是后一种通过javascript收集到了更多的信息。下面看一下现在各种网站统计工具的数据收集基本原理。

    1.1 流程概览

    首先通过一幅图总体看一下数据收集的基本流程。
    img

    图1. 网站统计数据收集基本流程

    首先,用户的行为会触发浏览器对被统计页面的一个http请求,这里姑且先认为行为就是打开网页。当网页被打开,页面中的埋点javascript片段会被执行,用过相关工具的朋友应该知道,一般网站统计工具都会要求用户在网页中加入一小段javascript代码,这个代码片段一般会动态创建一个script标签,并将src指向一个单独的js文件,此时这个单独的js文件(图1中绿色节点)会被浏览器请求到并执行,这个js往往就是真正的数据收集脚本。数据收集完成后,js会请求一个后端的数据收集脚本(图1中的backend),这个脚本一般是一个伪装成图片的动态脚本程序,可能由php、python或其它服务端语言编写,js会将收集到的数据通过http参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在http响应中给客户端种植一些用于追踪的cookie。
    上面是一个数据收集的大概流程,下面以谷歌分析为例,对每一个阶段进行一个相对详细的分析。

    1.2埋点脚本执行阶段

    若要使用谷歌分析(以下简称GA),需要在页面中插入一段它提供的javascript片段,这个片段往往被称为埋点代码。下面是我的博客中所放置的谷歌分析埋点代码截图:

    img

    图2. 谷歌分析埋点代码

    其中_gaq是GA的的全局数组,用于放置各种配置,其中每一条配置的格式为:

    _gaq.push(['Action', 'param1', 'param2', ...]);
    

    Action指定配置动作,后面是相关的参数列表。GA给的默认埋点代码会给出两条预置配置,_setAccount用于设置网站标识ID,这个标识ID是在注册GA时分配的。_trackPageview告诉GA跟踪一次页面访问。更多配置请参考:https://developers.google.com/analytics/devguides/collection/gajs/ 。实际上,这个_gaq是被当做一个FIFO队列来用的,配置代码不必出现在埋点代码之前,具体请参考上述链接的说明。

    就本文来说,_gaq的机制不是重点,重点是后面匿名函数的代码,这才是埋点代码真正要做的。这段代码的主要目的就是引入一个外部的js文件(ga.js),方式是通过document.createElement方法创建一个script并根据协议(http或https)将src指向对应的ga.js,最后将这个element插入页面的dom树上。

    注意ga.async = true的意思是异步调用外部js文件,即不阻塞浏览器的解析,待外部js下载完成后异步执行。这个属性是HTML5新引入的。

    1.3 数据收集脚本执行阶段

    数据收集脚本(ga.js)被请求后会被执行,这个脚本一般要做如下几件事:
    (1)通过浏览器内置javascript对象收集信息,如页面title(通过document.title)、referrer(上一跳url,通过document.referrer)、用户显示器分辨率(通过windows.screen)、cookie信息(通过document.cookie)等等一些信息。
    (2)解析_gaq收集配置信息。这里面可能会包括用户自定义的事件跟踪、业务数据(如电子商务网站的商品编号等)等。
    (3)将上面两步收集的数据按预定义格式解析并拼接。
    (4)请求一个后端脚本,将信息放在http request参数中携带给后端脚本。
    这里唯一的问题是步骤4,javascript请求后端脚本常用的方法是ajax,但是ajax是不能跨域请求的。这里ga.js在被统计网站的域内执行,而后端脚本在另外的域(GA的后端统计脚本是http://www.google-analytics.com/__utm.gif),ajax行不通。一种通用的方法是js脚本创建一个Image对象,将Image对象的src属性指向后端脚本并携带参数,此时即实现了跨域请求后端。这也是后端脚本为什么通常伪装成gif文件的原因。通过http抓包可以看到ga.js对__utm.gif的请求:

    img

    图3. 后端脚本请求的http包

    可以看到ga.js在请求__utm.gif时带了很多信息,例如utmsr=1280×1024是屏幕分辨率,utmac=UA-35712773-1是_gaq中解析出的我的GA标识ID等等。
    值得注意的是,__utm.gif未必只会在埋点代码执行时被请求,如果用_trackEvent配置了事件跟踪,则在事件发生时也会请求这个脚本。
    由于ga.js经过了压缩和混淆,可读性很差,我们就不分析了,具体后面实现阶段我会实现一个功能类似的脚本。

    1.4 后端脚本执行阶段

    GA的__utm.gif是一个伪装成gif的脚本。这种后端脚本一般要完成以下几件事情:
    (1)解析http请求参数的到信息。
    (2)从服务器(WebServer)中获取一些客户端无法获取的信息,如访客ip等。
    (3)将信息按格式写入log。
    (4)生成一副1×1的空gif图片作为响应内容并将响应头的Content-type设为image/gif。
    (5)在响应头中通过Set-cookie设置一些需要的cookie信息。
    之所以要设置cookie是因为如果要跟踪唯一访客,通常做法是如果在请求时发现客户端没有指定的跟踪cookie,则根据规则生成一个全局唯一的cookie并种植给用户,否则Set-cookie中放置获取到的跟踪cookie以保持同一用户cookie不变(见图4)。

    img

    图4. 通过cookie跟踪唯一用户的原理

    类似的脚本。

    1.4 后端脚本执行阶段

    GA的__utm.gif是一个伪装成gif的脚本。这种后端脚本一般要完成以下几件事情:
    (1)解析http请求参数的到信息。
    (2)从服务器(WebServer)中获取一些客户端无法获取的信息,如访客ip等。
    (3)将信息按格式写入log。
    (4)生成一副1×1的空gif图片作为响应内容并将响应头的Content-type设为image/gif。
    (5)在响应头中通过Set-cookie设置一些需要的cookie信息。
    之所以要设置cookie是因为如果要跟踪唯一访客,通常做法是如果在请求时发现客户端没有指定的跟踪cookie,则根据规则生成一个全局唯一的cookie并种植给用户,否则Set-cookie中放置获取到的跟踪cookie以保持同一用户cookie不变(见图4)。

    img

    图4. 通过cookie跟踪唯一用户的原理

    这种做法虽然不是完美的(例如用户清掉cookie或更换浏览器会被认为是两个用户),但是是目前被广泛使用的手段。注意,如果没有跨站跟踪同一用户的需求,可以通过js将cookie种植在被统计站点的域下(GA是这么做的),如果要全网统一定位,则通过后端脚本种植在服务端域下(我们待会的实现会这么做)。

    展开全文
  • 在众多规模的公司里,对于复杂的业务,业务线里会有多个产品经理,前端工程师,首席工程师等成员,需求的变更人力资源的不透明企业开发过程中的顽疾。 ,人们力量资源的占用更加透明,所以开发了这个系统。 本...
  • businessbook-backend-源码

    2021-04-16 14:55:30
    ‍:laptop: 这个应用程式关于什么的: 在荷兰居住时,我一直在寻找可以满足我需求的企业。 我想出了这个应用程序,以使搜索过程更容易。 该应用程序用户可以注册搜索企业,与该企业进行约会以及注册自己的企业...
  • 初识MySQL

    2021-04-15 00:01:25
    1、初识MySQL ...如果能再把离散数学、数字电路、体系结构、数据结构/算法、编译原理学通透,再加上丰富的实践经验与领域特定知识,就能算是一个优秀的工程师了。 1.1、为什么学习数据库 1、岗位技能需求

    1、初识MySQL

    JavaEE: 企业级开发 Web

    前端 :页面、展示、数据

    后台:连接点(连接数据库JDBC、连接前端(控制、控制视图跳转、给前端传递数据))

    数据库: 存数据(txt、Excel、word)

    只会写代码的是码农;学好数据库,基本能混口饭吃;在此基础上再学好操作系统和计算机网络,就能当一个不错的程序员。如果能再把离散数学、数字电路、体系结构、数据结构/算法、编译原理学通透,再加上丰富的实践经验与领域特定知识,就能算是一个优秀的工程师了。

    1.1、为什么学习数据库

    1、岗位技能需求

    2、现在的世界,得数据者得天下

    3、存储数据的方法

    4、程序,网站中,大量数据如何长久保存?

    5、数据库是几乎软件体系中最核心的一个存在。

    1.2、什么是数据库

    数据库 ( DataBase , 简称DB ) (行列的表)

    概念 : 长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据 “仓库”,SQL语句

    作用 : 保存存储数据,并能安全管理数据(如:增删改查等),减少冗余…

    数据库总览 :

    • 关系型数据库 ( SQL ) 行 、列

      • MySQL , Oracle , SQL Server , SQLite , DB2 , …
      • 关系型数据库通过外键关联来建立表与表之间的关系 (表与表之间、行和列之间的关系进行数据存储) 学员信息表 考勤表
    • 非关系型数据库 ( NOSQL not only sql ) 键值对 动态的关系

      • Redis , MongoDB , …
      • 非关系型数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定

    1.3、什么是DBMS

    数据库管理系统 ( DataBase Management System )

    数据库管理软件 , 科学组织和存储数据 , 高效地获取和维护数据

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传image-20210410001812958.png

    为什么要说这个呢?

    数据库存储数据 相当于一个容器, DBMS是一个工具,通过它我们可以实现一些功能。

    因为我们要学习的MySQL应该算是一个数据库管理系统.

    1.4、MySQL简介

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n0V2aJ8K-1618416061480)(E:\StudyNotes\TyporaNotes\Java\pic\MySQL\image-20210410002635959.png)]

    概念 : 是现在流行开源的,免费关系型数据库。最流行的关系型数据库之一

    历史 : 由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。

    特点 :

    • 免费 , 开源数据库

    • 小巧 , 功能齐全

    • 使用便捷

    • 可运行于Windows或Linux操作系统

    • 可适用于中小型甚至大型网站应用

      官网 : https://www.mysql.com/

    1.5、安装MySQL (5.7稳定)

    这里建议使用压缩版,安装快,方便.不复杂.

    1、软件下载

    mysql5.7 64位下载地址:

    https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip

    电脑是64位的就下载使用64位版本的!

    2、步骤

    下载后得到zip压缩包.

    解压到自己想要安装到的目录,

    添加环境变量:我的电脑->属性->高级->环境变量

    3、选择PATH,在其后面添加: 你的mysql 安装文件下面的bin文件夹

    4、编辑 my.ini 文件 ,注意替换路径位置

    [mysqld] 
    basedir=D:\Program Files\mysql-5.7\ 
    datadir=D:\Program Files\mysql-5.7\data\ 
    port=3306 
    skip-grant-tables
    

    5、启动管理员模式下的CMD,并将路径切换至mysql下的bin目录,然后输入mysqld –install (安装mysql)

    6、再输入mysqld --initialize-insecure --user=mysql初始化数据文件

    7、然后再次启动mysql 然后用命令 mysql –u root –p 进入mysql管理界面(密码可为空) mysql 是因为有mysql.exe u指user p 指password

    8、进入界面后更改root密码 ;号要加上

    update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
    

    9、刷新权限

    flush privileges;
    

    10、修改 my.ini文件删除最后一句skip-grant-tables

    11、重启mysql即可正常使用

    net stop mysql 
    net start mysql
    

    12、连接上测试出现以下结果就安装好了

    PS C:\WINDOWS\system32> mysql -uroot -p
    Enter password:
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 2
    Server version: 10.1.32-MariaDB mariadb.org binary distribution
    
    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    

    一步步去做 , 理论上是没有任何问题的 .

    如果您以前装过,现在需要重装,一定要将环境清理干净 .

    好了,到这里大家都装好了,因为刚接触,所以我们先不学习命令.

    这里给大家推荐一个工具 : SQLyog . (xampp自带mysql)

    即便有了可视化工具,可是基本的DOS命名大家还是要记住!

    1.6、SQLyog

    可手动操作,管理MySQL数据库的软件工具

    特点 : 简洁 , 易用 , 图形化

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传image-20210410011053060.png

    ]

    使用SQLyog管理工具自己完成以下操作 :

    • 连接本地MySQL数据库

    • 新建MySchool数据库

      • 数据库名称MySchool

      • 新建数据库表(grade)

    • 字段

      • GradeID : int(11) , Primary Key (pk)

      • GradeName : varchar(50)

    在历史记录中可以看到相对应的数据库操作的语句 .

    1.7、连接数据库

    打开MySQL命令窗口

    • 在DOS命令行窗口进入 安装目录**\mysql\bin**

    • 可设置环境变量,设置了环境变量,可以在任意目录打开!

    连接数据库语句 : mysql -h 服务器主机地址 -u 用户名 -p 用户密码

    注意 : -p后面不能加空格,否则会被当做密码的内容,导致登录失败 !

    几个基本的数据库操作命令 :

    update user set password=password('123456')where user='root';      在mysql表中的user表中修改密码 
    flush privileges; 刷新数据库
    
    show databases; 显示所有数据库 
    use dbname; 打开某个数据库 
    show tables; 显示数据库mysql中所有的表 
    
    describe user; 显示表mysql数据库中user表的列信息 create database name; 创建数据库 
    use databasename; 选择数据库 
    exit; 退出Mysql 
    ? 命令关键词 : 寻求帮助 
    -- 表示单行注释(SQL本身的注释)
    /**/ sql的多行注释
    # 注释
    
    展开全文
  • 第1章至第4章基础篇,包括数据库建模、oracle体系结构、网络结构、备份恢复使用oem,这些对于刚刚从事dba或者试图转做dba的朋友都必备知识。第5章至第9章中级篇,专门讨论性能调整,包括性能优化原理、...
  • Oracle Database 11g DBA手册--详细书签版

    热门讨论 2013-02-05 13:16:22
     Bob Bryla Oracle9i10g的认证专家,在数据库设计、数据库应用程序开发、培训Oracle数据库管理等方面拥有20多年的经验,威斯康星州Dodgeville的Lands’ End 公司的首席Internet数据库设计师Oracle DBA。...
  • 设计模式 GOF 23

    热门讨论 2012-08-02 10:41:53
    在系统开发阶段强调这种机制的优势在于,它能使所生成的系统体系结构更加精巧、简洁易于理解,其程度远远超过了未使用模式的体系结构。 模式在构造复杂系统时的重要性早已在其他领域中被认可。特别地,...
  • 二十三种设计模式【PDF版】

    热门讨论 2011-05-30 14:13:49
    如果你还不了解设计模式是什么的话? 那就先看设计模式引言 ! 学习 GoF 设计模式的重要性 建筑软件中模式之异同 A. 创建模式 设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证...
  • 大学物理-卢德馨序言

    2010-03-19 20:25:56
    文,原义自然,而中文的含义“物”(物质的结构、性质)“理”(物 质的运动、变化规律).中文含义与现代观点颇为吻合.现代观点认为物理学 主要研究:物质运动,或物质世界及其各部分之间的相互作用,或物 ...
  • 可是png到底是什么,它的压缩原理是什么? 很好,接下来我将会给大家一一阐述。 什么是PNG <p>PNG的全称叫便携式网络图型(Portable Network Graphics)是目前最流行的网络传输展示...
  • 在系统开发阶段强调这种机制的优势在于,它能使所生成的系统体系结构更加精巧、简洁易于理解,其程度远远超过了未使用模式的体系结构。  模式在构造复杂系统时的重要性早已在其他领域中被认可。特别地,...
  • ASP.NET 2.0技术内幕

    2008-07-13 17:13:50
    1.1 究竟什么是ASP.NET 2 1.1.1 Web窗体中的编程 4 1.1.2 通过HTTP的事件驱动编程 4 1.1.3 HTTP协议 6 1.1.4 ASP.NET页面的结构 8 1.2 ASP.NET组件模型 11 1.2.1 组件交互...
  • 看到网上有个方案说:主项目负责加载组件,由于主项目组件之间隔离的,那么主项目如何调用组件ApplicationLike的生命周期方法呢,目前采用的基于编译期字节码插入的方式,扫描所有的ApplicationLike类(其有一...
  • 他当过开发人员,也做过DBA,目前 Oracle ACE总监OakTable成员。最近几年,他专注于研究Oracle内部原理以及解决性能问题。他的博客主页 kerryosborne.oracle-guy.com。  ROBYN SANDS 思科公司的软件...
  • 他当过开发人员,也做过DBA,目前 Oracle ACE总监OakTable成员。最近几年,他专注于研究Oracle内部原理以及解决性能问题。他的博客主页 kerryosborne.oracle-guy.com。  ROBYN SANDS 思科公司的软件...
  • 6.3.1对象变量的实质是什么220 6.3.2对象下面的秘密222 6.3.3重述对象关键字226 6.3.4 Class_Terminate事件228 第7章事件、多态性与继承性232 7.1事件232 7.1.1事件代码复用性232 7.1.2事件的语法233 7.1.3第一个...
  • 6.3.1对象变量的实质是什么220 6.3.2对象下面的秘密222 6.3.3重述对象关键字226 6.3.4 Class_Terminate事件228 第7章事件、多态性与继承性232 7.1事件232 7.1.1事件代码复用性232 7.1.2事件的语法233 7.1.3第一个...

空空如也

空空如也

1 2 3
收藏数 49
精华内容 19
关键字:

展和透是什么结构