[转载]ie6下的iframe,问题多多。 - izumi - 博客园

mikel阅读(1080)

[转载]ie6下的iframe,问题多多。 – izumi – 博客园.

 

ie6下的iframe,问题多多。

 

今天在ie6下显示Velocity页面中的iframe,发现除了iframe的外框以外,src中请求的url完全没有读取成功,结果是个空的iframe。

总结网上一共有以下几种解决办法:

1,

<iframe name=’ifrm_select_jhs_x’ src=”+url+” scrolling=’no’ frameborder=0 width=’256′ height=’174′></iframe>

ifrm_select_jhs_x.location.href = url;

2,

认为src不能写在<iframe的后面

http://be-evil.org/showlog-91.html

http://social.msdn.microsoft.com/forums/zh-TW/236/thread/a01ee23e-08d6-414d-ba22-9922f456af3c/

3,

认为iframe src的URL长度过长

http://yuweijun.blogspot.com/2008/11/when-iframe-src-is-too-long-in-ie6ie7.html

http://support.microsoft.com/kb/208427/zh-cn

 4,

认为iframe src的URL长度过长

http://yuweijun.blogspot.com/2008/11/when-iframe-src-is-too-long-in-ie6ie7.html

http://support.microsoft.com/kb/208427/zh-cn

 5,

猜测是:html书写不规范造成。因为这个结果页面是jsp动态生成的,可能其它代码造成了影响。

最后解决方法:先生成iframe,点击“更多信息”时改变iframe的src,之前是采用每次点击删除之前的iframe,添加新的iframe对象。

6,

今天解决了此问题 以下是核心代码
………..
Container.innerHTML=”<iframe id=sdfgfer567fgh name=sdfgfer567fgh src=”+url+” frameborder=’0′ scrolling=’no’ width=”+divwidth+” height=”+divh+” marginheight=’0′ marginwidth=’0′>”;//创造iframe 并指定ID
var ieset = navigator.userAgent;
if(ieset.indexOf(“MSIE 6.0”) > -1)//浏览器判断 如果是IE6
setTimeout(‘window.parent[\’sdfgfer567fgh\’].location.reload();’,0);//执行这一方法

……

7,

function logindiv() { if(Fid(login_div)) { document.body.removeChild(Fid(login_div)); } var obj_div=document.createElement(div); obj_div.id=login_div; obj_div.style.top =200 obj_div.style.left=100 obj_div.className=login_box; obj_div.innerHTML= <iframe style=’width:400px;height:400px;border:medium none;margin:0px;padding:0px’ name=’Login’ id=’Login’ marginwidth=’0′ marginheight=’0′ scrolling=’no’ frameborder=’0′ src=”> </iframe>; document.body.appendChild(obj_div); obj_div.getElementsByTagName(iframe)[0].src =http://www.qq.com/

}

8,

  为了实现提示框效果,从而使用动态嵌入iframe方案,但是实施过程中IE7下正常,IE6需要刷新才可正常显示,如下:

Js代码
  1. this.open = function(_sUrl)  
  2. {         
  3.     this.show();  
  4.     var openIframe = “<iframe width=’100%’ height=’100%’ name=’iframe_parent’ id=’iframe_parent’ src='” + _sUrl + “‘ frameborder=’0′ scrolling=’no’></iframe>”;  
  5.     myInnerHTML(‘dialogBody’, openIframe);  
  6. }  

该 方法主要将URL通过iframe形式嵌入到document中,但IE7可正常显示,IE显示空白,而且’iframe_parent’ 的src属性为“”,经过漫长的调试,最终通过增加一刷新iframe语句才得以解 决:document.frames(‘iframe_parent’).location.reload();
对于此类BUG的定位实在困难。

[转载]Fiddler真乃前端大杀器!!! - qjoycn - ITeye技术网站

mikel阅读(1018)

[转载]Fiddler真乃前端大杀器!!! – qjoycn – ITeye技术网站.

在老夫还在搞服务器端时候,老夫觉得能读能改js代码就差不多了吧;

当老夫刚刚踏入前端会想js能设置断点该多好呢?

当老夫手拥firebug、google、ie浏览器开发插件(叫不出名字…)时,老夫是多么的高兴啊!!!

但是有些项目就会让你不自主的感觉痛苦,因为改动非常痛苦!!!

比如我对项目做了一点修改,但是我没办法在正式环境测试;换个方式,若是qq首页哪里出了js错误,要马上定位、马上解决该怎么办呢?

前端杀器Fiddler

其实老夫也是最近才开始使用该软件的,其实老夫很多不懂,但是我就用其中一点东西就好了,只一眼便已爱如心扉!!!

先来个截图:

请注意矩形框位置,我就会用这个。。。。

大杀器在线编辑js/html/css

光说不练假把式!下面就让老夫试试这个大杀器~!

打开我们的博客园首页看看,然后观察我们的大杀器变化:

小样东西还不少呢!!!现在让我们来动点手脚了!!!

右键编辑之,出现:

算了,我想了下,还是不用博客园来测试了,用它估计老夫要丢人。。。因为首页可能用了页面片神马的,老夫没找到。。。

于是老夫又进了自己博客文章的页面,来看看有什么东东呢?

日本人,是拉的json数据啦!!!说实话ajax真是讨厌了,老夫又丢脸了,算了继续!!!

最后老夫找到了自己想要的东东,于是乎我随便加点文字,加点js后!!!

做这点变化保存后,刷新页面,非常奇迹的变了,我们用本地的文件替换了线上的请求!!!

这个东西是不得了的,我们根据这个特性完全可以做在线前端测试!!!

对js的操作

 对js的操作,我们换个地方,熟悉点的东西好操作一点,以免再出丑,我们来看大成网的首页:

 

我们将之存到桌面,晚上讲地址赋给fiddler:

 这样一保存,我们在本地的修改就直接同步到线上页面啦!!!!对小的来说,当真神器!!!

于是你可以说你在大成网自豪的弹了个框出来。。。。

结语

其实小的对Fiddler也不太熟,就只会这点点花招,并且还感觉不差呢!!!

它的出现主要有什么好处呢,好处就是我们可以在线测试前端的代码,修复前端的BUG,然后将修改后的文件上传即可;

这也许没什么意义,但当项目到一定规模,发布有一定门槛后,就变得非常有意义了!!!

[转载]jquery收藏本站——添加到浏览器的收藏夹 - 朱羽佳 - 博客园

mikel阅读(1363)

[转载]【jquery】收藏本站——添加到浏览器的收藏夹 – 朱羽佳 – 博客园.

基本上兼容了所有的浏览器,值得收藏。

直接上代码:

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>收藏本站</title>
</head>
<body>
    <a href="javascript:;" title="收藏本站" id="fav">收藏本站</a>
</body>
</html>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
//收藏本站代码
jQuery.fn.addFavorite = function(l, h) {
    return this.click(function() {
        var t = jQuery(this);
        if(jQuery.browser.msie) {
            window.external.addFavorite(h, l);
        } else if (jQuery.browser.mozilla || jQuery.browser.opera) {
            t.attr("rel", "sidebar");
            t.attr("title", l);
            t.attr("href", h);
        } else {
            alert("请使用Ctrl+D将本页加入收藏夹!");
        }
    });
};
$(function(){
    $('#fav').addFavorite('收藏本站',location.href);
});
</script>

ASP.NET MVC 动态路由解析Editable Routes

mikel阅读(978)

.

UPDATE: 2011/02/13: This code is now included in the RouteMagic NuGet package! To use this code, simply run Install-Package RouteMagic within the NuGet Package Manager Console.

In general, once you deploy your ASP.NET MVC application, you can’t change the routes for your application without recompiling the application and redeploying the assembly where your routes are defined.

routesThis is partly by design as routes are generally considered application code, and should have associated unit tests to verify that the routes are correct. A misconfigured route could seriously tank your application.

Having said that, there are many situations in which the ability to change an application’s routes without having to recompile the application comes in very handy. This is the situation I find myself in as I build a blog engine where the folks who will install may want to tweak the routes without having to recompile the blog’s source code.

In this post, I’ll demonstrate an approach that’ll allow you to define your routes in a content file as code (no XML here!) which you deploy with your application as in the screenshot.

Routes File In Soultion

In my implementation, you need to place the routes in a Config folder in your web root. Note that I used Visual Studio’s Properties dialog to mark the file’s Build Action as “Content” so that it’s not compiled into my application.

Properties

What this means is that the code in the Routes.cs file is not compiled with the application. Instead, we will dynamically compile it. First, let’s look at the contents of that file. It shouldn’t be too surprising.

using System.Web.Mvc;
using System.Web.Routing;
using EditableRoutesWeb;

public class Routes : IRouteRegistrar
{
  public void RegisterRoutes(RouteCollection routes)
  {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
      "Default",
      "{controller}/{action}/{id}",
      new { controller = "Home", action = "Index", id = "" }
    );
  }
}

One thing you’ll notice is that this class implements an interface named IRouteRegistrar. This is an interface I created and added to my web application (though it could be defined in another assembly).

The code in Global.asax.cs for this application simply calls an extension method I wrote.

protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();
  RouteTable.Routes.RegisterRoutes("~/Config/Routes.cs");
}

It’s the code in this extension method where the real magic happens.

Before I show the code, there are two concepts at work here that make this work. The first is using the BuildManager to dynamically create an assembly from the Routes.cs file. From that assembly, we can create an instance of the type Routes and cast it to IRouteHandler.

var assembly = BuildManager.GetCompiledAssembly("~/Config/Routes.cs");
var registrar = assembly.CreateInstance("Routes") as IRouteRegistrar;

Once we have an instance of a route registrar, we can call RegisterRoutes on that instance.

The second concept is being able to get notification when the Routes.cs file changes. The clever trick that David told me about is using the ASP.NET Cache object to do that. When you add an item to the cache, you can give it a cache dependency pointing to a file and a method to call when the cache is invalidated.

With those two pieces, we can add a cache dependency pointing to Routes.cs and a callback method which will reload the routes when Routes.cs is changed.

Here’s the full listing for RouteRegistrationExtensions.

public static class RouteRegistrationExtensions
{
  public static void RegisterRoutes(this RouteCollection routes, 
      string virtualPath)
  {
    routes.ReloadRoutes(virtualPath);
    ConfigFileChangeNotifier.Listen(virtualPath, 
      vp => routes.ReloadRoutes(vp));
  }

  static void ReloadRoutes(this RouteCollection routes, string virtualPath)
  {
    var assembly = BuildManager.GetCompiledAssembly(virtualPath);
    var registrar = assembly.CreateInstance("Routes") as IRouteRegistrar;
    using(routes.GetWriteLock())
    {
      routes.Clear();
      registrar.RegisterRoutes(routes);
    }
  }
}

This uses a class called ConfigFileChangeNotifier which is based on some code David wrote for Dynamic Data.

public class ConfigFileChangeNotifier
{
  private ConfigFileChangeNotifier(Action<string> changeCallback)
    : this(HostingEnvironment.VirtualPathProvider, changeCallback)
  { 
  }

  private ConfigFileChangeNotifier(VirtualPathProvider vpp, 
      Action<string> changeCallback) {
    _vpp = vpp;
    _changeCallback = changeCallback;
  }

  VirtualPathProvider _vpp;
  Action<string> _changeCallback;

  // When the file at the given path changes, 
  // we'll call the supplied action.
  public static void Listen(string virtualPath, Action<string> action) {
    var notifier = new ConfigFileChangeNotifier(action);
    notifier.ListenForChanges(virtualPath);
  }

  void ListenForChanges(string virtualPath) {
    // Get a CacheDependency from the BuildProvider, 
    // so that we know anytime something changes
    var virtualPathDependencies = new List<string>();
    virtualPathDependencies.Add(virtualPath);
    CacheDependency cacheDependency = _vpp.GetCacheDependency(
      virtualPath, virtualPathDependencies, DateTime.UtcNow);
      HttpRuntime.Cache.Insert(virtualPath /*key*/,
        virtualPath /*value*/,
        cacheDependency,
        Cache.NoAbsoluteExpiration,
        Cache.NoSlidingExpiration,
        CacheItemPriority.NotRemovable,
        new CacheItemRemovedCallback(OnConfigFileChanged));
  }

  void OnConfigFileChanged(string key, object value, 
    CacheItemRemovedReason reason) {
    // We only care about dependency changes
    if (reason != CacheItemRemovedReason.DependencyChanged)
      return;

    _changeCallback(key);

    // Need to listen for the next change
    ListenForChanges(key);
  }
}

With this in place, you can now change routes within the Routes.cs file in the Config directory after you’ve deployed the application. Note that technically, a recompilation is happening, but it’s happening dynamically at runtime when the file changes and there’s no need to restart your entire App Domain, which is one benefit of this approach over using the code in App_Code.

If you want to try this code out, you can download a sample project here. The sample app is compiled against ASP.NET MVC 2 RC, but the same principles and code can be used with an ASP.NET MVC 1.0 application. In fact, it can also be used in an ASP.NET 4 Web Forms application since we now support page routing.

Note, if you want to see the old version of this code, I’ve archived it here.

[转载]JavasScript 实现Json查询方法 - HeartDawn - 博客园

mikel阅读(1065)

[转载]JS 实现Json查询方法 – HeartDawn – 博客园.

曾经看过一个大牛写的实现Json的一个模板类,今天突然没事就来自己试着写写。

还好,一些东西还记得,思路还算清晰。

在此感谢那位大牛,具体是哪个大牛,我也不知道了。因为担心自己以后会忘记这样的方式,所以在这里记录下来。

也就不直接废话了,直接上代码了,其实很简单,我这部分代码,前一部分是简单的实现如何使用JS写模板,第二个就是具体的实现了JSON查询的一个扩展。

以后查询Json就有了利器了。

View Code 

/*
         * 定义模板函数
        */
        var template = function (queryArr) {

            var count = 0;

            for (var i = 0; i < queryArr.length; i++) {

                var e = queryArr[i];

                if ($express) {
                    count++;
                }
            }

            return count;
        }

        /*
         * 模板创建函数
        */
        var createIntance = function (exp) {
            var fun = template.toString().replace("$express", exp).toString();
            return eval("0," + fun);
        }

        var testTodo = function () {

            var testArr = [
                { name: "张三", age: 20 },
                { name: "李四", age: 25 },
                { name: "王二麻子", age: 28 },
                { name: "小张", age: 30 }
            ];

            var func = createIntance("e.age>=25");

            alert(func(testArr));
        }

        /****************** JS 实现 JSON查询 **********************/
        
        // 定义常用的函数
        var len = function (s) { return s.length; }
        var left = function (s, n) { return s.substr(0, n); }
        var right = function (s, n) { return s.substr(-n); }
        var index = function (s, find) { return s.indexOf(find) + 1; }

        // 扩展原型方法
        var _proto = Object.prototype;

        // 缓存,解决快速查找
        var _cache = {};

        // 扩展运算符
        var _alias = [
            /@/g, "_e.",
            /AND/gi, "&&",
            /OR/gi, "||",
            /<>/g, "!=",
            /NOT/gi, "!",
            /([^=<>])=([^=]|$)/g, '$1==$2'
        ];

        var _rQuote = /""/g;
        var _rQuoteTemp = /!~/g;

        // 编译
        var _complite = function (code) {
            return eval("0," + code);
        }

        // 将扩展符号转换成标准的JS符号
        var _interpret = function (exp) {
            exp = exp.replace(_rQuote,"!~");
            var arr = exp.split('"');
            var i, n = arr.length;
            var k = _alias.length;

            for (var i = 0; i < n; i += 2) {
                var s = arr[i];
                for (var j = 0; j < k; j += 2) {
                    if (index(s, _alias[j]) > -1) {
                        s = s.replace(_alias[j], _alias[j + 1]);
                    }
                }
                arr[i] = s;
            }

            for (var i = 1; i < n; i += 2) {
                arr[i] = arr[i].replace(_rQuoteTemp, '\\"');
            }
            return arr.join('"');
        }

        // 定义模函数
        var _templ = function (_list) {
            var _ret = [];
            var _i = -1;

            for (var _k in _list) {
                var _e = _list[_k];
                if (_e != _proto[_k]) {
                    if ($C) {
                        _ret[++_i] = _e;
                    }
                }
            }
            return _ret;
        } .toString();

        // 扩展查询的方法
        _proto.Query = function (exp) {
            if (!exp) {
                return [];
            }

            var fn = _cache[exp];

            try {
                if (!fn) {
                    var code = _interpret(exp);
                    code = _templ.replace("$C", code);
                    fn = _cache[exp] = _complite(code);
                }
                return fn(this);
            } catch (e) {
                return [];
            }
        }

        var doTest = function () {

            var heros = [
            // 名============攻=====防=======力量====敏捷=====智力====
                {name: '冰室女巫', DP: 38, AP: 1.3, Str: 16, Dex: 16, Int: 21 },
                { name: '沉默术士', DP: 39, AP: 1.1, Str: 17, Dex: 16, Int: 21 },
                { name: '娜迦海妖', DP: 51, AP: 6.0, Str: 21, Dex: 21, Int: 18 },
                { name: '赏金猎人', DP: 39, AP: 4.0, Str: 17, Dex: 21, Int: 16 },
                { name: '剧毒术士', DP: 45, AP: 3.1, Str: 18, Dex: 22, Int: 15 },
                { name: '光之守卫', DP: 38, AP: 1.1, Str: 16, Dex: 15, Int: 22 },
                { name: '炼金术士', DP: 49, AP: 0.6, Str: 25, Dex: 11, Int: 25 }
            //...
            ];

            var match = heros.Query('@Str>20 AND @Dex>20');
            ShowResult(match[0]);
            
            // 查询:“士”结尾的
            // 结果:沉默术士,剧毒术士,炼金术士
            var match = heros.Query('right(@name,1)="士"');
            ShowResult(match[0]);
        }

        function ShowResult(result) {
            alert(result.name + " " + result.DP + " " + result.AP + " " + result.Str + " " + result.Dex + " " + result.Int);
        }

[转载]分享下.NET程序读取二代身份证(附源码 - 每天保持微笑 - 博客园

mikel阅读(1284)

转载分享下.NET程序读取二代身份证(附源码 – 每天保持微笑 – 博客园.

一般来说winform应用程序解决这个问题起来时很容易的,web应用程序就麻烦一点了。

这里我说说我的解决思路:

一、你必要有联机型居民身份证阅读器一个(带驱动光盘),这里我用的是精伦电子公司的iDR200,并有这个阅读器的开发接口说明。

二、新建一个winform控件项目ReadCardControl,添加一个主类ReadCard

1、  声明dll入口

      [DllImport(“Sdtapi.dll”)]

        private static extern int InitComm(int iPort);//初始化

        [DllImport(“Sdtapi.dll”)]

        private static extern int Authenticate();//卡认证

        [DllImport(“Sdtapi.dll”)]

        private static extern int ReadBaseInfos(StringBuilder Name, StringBuilder Gender, StringBuilder Folk, StringBuilder BirthDay, StringBuilder Code, StringBuilder Address, StringBuilder Agency, StringBuilder ExpireStart, StringBuilder ExpireEnd);//读取数据,推荐使用

        [DllImport(“Sdtapi.dll”)]

        private static extern int CloseComm();//关闭端口

       [DllImport(“Sdtapi.dll”)]

        private static extern int ReadBaseMsg(byte[] pMsg, ref int len);//读取数据,这里不用

        [DllImport(“Sdtapi.dll”)]

        private static extern int ReadBaseMsgW(byte[] pMsg, ref int len);//读取数据,这里不用

        [DllImport(“kernel32.dll”)]

        private static extern int Beep(int dwFreq, int dwDuration);//用来大吼一声

2、读卡方法

        private string[] arrys = null;//声明用来保存身份证信息的数组

        public void OnTimer()

        {

            StringBuilder Name = new StringBuilder(31);

           StringBuilder Gender = new StringBuilder(3);

            StringBuilder Folk = new StringBuilder(10);

            StringBuilder BirthDay = new StringBuilder(9);

            StringBuilder Code = new StringBuilder(19);

            StringBuilder Address = new StringBuilder(71);

            StringBuilder Agency = new StringBuilder(31);

            StringBuilder ExpireStart = new StringBuilder(9);

            StringBuilder ExpireEnd = new StringBuilder(9);

            //int len = 0;

            //string[] temp;

            char[] param = { ‘\0’ };

            byte[] pMsg = new byte[256];

            string[] baseinfo = new string[9];

            //打开端口

            int intOpenRet = InitComm(1001);

            if (intOpenRet != 1)

            {

                //SetText(“阅读机具未连接”, lblMsg);

                return;

            }

            //卡认证

            int intReadRet = Authenticate();

            if (intReadRet != 1)

            {

                //SetText(“卡认证失败”, lblMsg);

                CloseComm();

                return;

            }

            //ReadBaseInfos(推荐使用)

            int intReadBaseInfosRet = ReadBaseInfos(Name, Gender, Folk, BirthDay, Code, Address, Agency, ExpireStart, ExpireEnd);

            if (intReadBaseInfosRet != 1)

            {

                //SetText(“读卡失败”, lblMsg);

                CloseComm();

                return;

            }

            Beep(2047, 200);

            arrys = new string[10];

            arrys[0] = Code.ToString().Trim();

            arrys[1] = Name.ToString().Trim();

            arrys[2] = Gender.ToString().Trim();

            arrys[3] = Folk.ToString().Trim();

            arrys[4] = BirthDay.ToString().Trim();

            arrys[5] = Address.ToString().Trim();

            arrys[6] = Agency.ToString().Trim();

            arrys[7] = ExpireStart.ToString().Trim();

            arrys[8] = ExpireEnd.ToString().Trim();

            arrys[9] = System.IO.Directory.GetCurrentDirectory() + “\\photo.bmp”;

            //SetText(“读卡成功”, lblMsg);

            //SetText(“证件号码:” + Code.ToString(), label1);

            //SetText(“姓名:” + Name.ToString(), label2);

            //SetText(“性别:” + Gender.ToString(), label3);

            //SetText(“民族:” + Folk.ToString(), label4);

            //SetText(“出生日期:” + BirthDay.ToString(), label5);

            //SetText(“地址:” + Address.ToString(), label6);

            //SetText(“签发机关:” + Agency.ToString(), label7);

            //SetText(“签发时间:” + ExpireStart.ToString(), label8);

            //SetText(“有效截止时间:” + ExpireEnd.ToString(), label9);

            SetImage(“photo.bmp”, pictureBox1);

            CloseComm();

        }

2、  声明一个客户端调用的方法Test(这里没有直接用数组)

        public string Test()

        {

            string str = “”;

            foreach (string s in arrys)

            {

                str += s + “,”;

            }

            str = str.TrimEnd(‘,’);

            return str;

}

三、将这个控件封装成activex组件

在ReadCard类的头部添加

[Guid(“B9BB196C-5008-4156-840F-9FE37BA81502”)]

若要实现客户端访问服务器端数据,则必须实现IObjectSafe接口

接口声明如下:

   [ComImport, GuidAttribute(“CB5BDC81-93C1-11CF-8F20-00805F2CD064”)]

    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]

    public interface IObjectSafe

    {

        [PreserveSig]

        void GetInterfaceSafeOptions(ref Guid id, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig()]

        void SetInterfaceSafeOptions(ref Guid id, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);

}

四、新建一个web应用程序项目

1、界面:

               <table style=”width:100%;” border=”1″ width=”100%” bordercolordark=”#FFFFFF” cellspacing=”0″ cellpadding=”2″ bordercolor=”#000000″>

            <tr>

                <td style=”width:33.3%; text-align: right;”>证件号码:</td>

                <td style=”width:33.3%” id=”td1″>&nbsp;</td>

                <td style=”width:33.3%; text-align: left;” rowspan=”6″>

                         <object id=”csharpActiveX” name=”csharpActiveX” classid=”clsid:B9BB196C-5008-4156-840F-9FE37BA81502″></object></td>

            </tr>

            <tr>

                <td style=”text-align: right”>姓名:</td>

                <td id=”td2″>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>性别:</td>

                <td id=”td3″>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>民族:</td>

                <td id=”td4″>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>出生日期:</td>

                <td id=”td5″>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>地址:</td>

                <td id=”td6″>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>签发机关:</td>

                <td id=”td7″>&nbsp;</td>

                <td>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>签发时间:</td>

                <td id=”td8″>&nbsp;</td>

                <td>&nbsp;</td>

            </tr>

            <tr>

                <td style=”text-align: right”>有效截止时间:</td>

                <td id=”td9″>&nbsp;</td>

                <td>&nbsp;</td>

            </tr>

        </table>

 

2、JavaScript代码:

      function Demo() {

            try {

                var x = document.getElementById(“csharpActiveX”);

                x.OnTimer();//读取图片

                var v = x.Test();//读取身份证其他信息

                var arrys = v.split(‘,’);

                if (arrys.length > 9) {

                    document.getElementById(“td1”).innerHTML = arrys[0];

                    document.getElementById(“td2”).innerHTML = arrys[1];

                    document.getElementById(“td3”).innerHTML = arrys[2];

                    document.getElementById(“td4”).innerHTML = arrys[3];

                    document.getElementById(“td5”).innerHTML = arrys[4];

                    document.getElementById(“td6”).innerHTML = arrys[5];

                    document.getElementById(“td7”).innerHTML = arrys[6];

                    document.getElementById(“td8”).innerHTML = arrys[7];

                    document.getElementById(“td9”).innerHTML = arrys[8];

                }

            }

            catch (e) {

                //alert(e.message)

            }

        }

        setInterval(Demo, 1000);//设置每隔1秒钟读取一次

大功告成。。。下载源码

截个效果图:

每天进步一点点…

[转载]OSGI:从面向接口编程来理解OSGI - 幸福框架 - 博客园

mikel阅读(1055)

[转载]OSGI:从面向接口编程来理解OSGI – 幸福框架 – 博客园.

接口的种类(API和SPI)

 

从接口的被调用方式和被实现方式看,接口有API和SPI之分,见下图:

 

 

API和SPI在物理组织方式上的建议(可根据情况选择其一)

 

    • 位于独立的Assembly中。
    • 位于调用方的Assembly中。

 

API和SPI的演化方式:

 

    • API可以增加功能,最好保持稳定。
    • SPI可以减少功能,最好保持稳定。

 

API和SPI的交互方式见下图:

 

 

如何实例化接口(避免不了的问题)

 

  • 简单工厂(三种工厂模式都引入了新的抽象,因此最终还是要用简单工厂创建抽象的。适用于根据上下文实例化不同实例的场景)。
  • 服务定位器(适用于实例化边界对象或根对象的场景)。
  • 依赖注入容器(适用于多数场景,推荐用这种方式)。

 

从面向接口编程的角度考虑,为什么采用OSGI?

刚才我们介绍了接口和如何实例化接口,OSGI只是更进一步,允许你动态的管理具体实现Assembly的生命周期。多数应用可能不需要这种动态, 但是如果您发现OSGI对程序的侵入性不大(它唯一的要求就是面向接口编程),而您已经早就习惯了面向接口编程,那么OSGI对于您来说应该不是大问题

[转载]使用StructureMap扩展ASP.NET MVC三层结构框架系列文章总结篇(附源码下载) - 天屹 - 博客园

mikel阅读(976)

[转载]使用StructureMap扩展ASP.NET MVC三层结构框架系列文章总结篇(附源码下载) – 天屹 – 博客园.

本系统提供一个对默认的ASP.NET MVC扩展的三层结构框架,使用了StructureMapEnterprise Library进行依赖注入和异常日志记录处理,面向接口编程在本系统得到了充分的体现。

天屹不推荐直接下载代码,进行Copy and Paste,我们不是Coder而是Developer。希望这个代码可以作为你学习这个框架时的一个参考,而不是拿去就用。系统源码下载:下载地址

下面是对本系统各个模块实现的详细文章:

  1. 扩展ASP.NET MVC三层框架并使用StructureMap实现依赖注入1-Model层的实现
  2. 扩展ASP.NET MVC三层框架并使用StructureMap实现依赖注入2-Repository层的实现
  3. 扩展ASP.NET MVC三层框架并使用StructureMap实现依赖注入3-Service层的实现
  4. 扩展ASP.NET MVC三层框架并使用StructureMap实现依赖注入4-Controller和View的实现
  5. 扩展ASP.NET MVC三层框架并使用StructureMap实现依赖注入5-StructureMap的配置与实现
  6. 扩展ASP.NET MVC三层框架并使用Enterprise Library实现异常与日志记录(6)

本系统基于ASP.NET MVC4,使用了StructureMap实现依赖注入,Enterprise Library实现异常和日志的处理。相应的第三方DLL放在了Commons工程中,数据库使用开源Northwind数据库,Logging和 Northwind数据库备份也放到了Commons工程中。

下面看一下最终我们这个框架的完整结构:

mvc-structuremap-enterprise-library

9个工程功能介绍

  1. TYStudioDemo.Commons工程重要放一些公共的类,和一些工具方法。
  2. TYStudioDemo.DTO工程,主要放我们ViewModel,分离View和Entity Framework,降低代码耦合度。
  3. TYStudioDemo.Interfaces工程,统一管理整个框架的接口,所有的接口都在这一工程。
  4. TYStudioDemo.Membership工程,是我们的权限管理模块,可以参考天屹的MVC4 Simplemembership些列文章。
  5. TYStudioDemo.Models工程,这里没有其他的只有Entity Framework,Models层。
  6. TYStudioDemo.Repositories工程,如名字这里放置所有Repository,数据库持久层,只有这一层去和Model层打交道。
  7. TYStudioDemo.Services工程,业务逻辑层所有的业务逻辑都放在这一工程,通过StructureMap实现对Repository的注入,同时异常处理Service也在这里一层,使用Enterprise Library进行异常的日志记录。
  8. TYStudioDemo.StructureMap工程,这里放置的StructureMap的配置与管理。
  9. TYStudioDemo.WebUI工程,UI层,Controller和View都在这一层。

一些说明:

因为是Demo,所以没有写成一个完整的系统,只对Supplier一个表进行了操作,当然考虑到事务的问题,天屹在SupplierService的Create方法中模拟添加了Product表的内容,对本系统中的事务处理做了注释说明。

如果觉得系统还可以,请大家推荐分享一下,让更多的学习MVC的朋友看到,谢谢。

如果有什么问题,不明白的地方,欢迎来到TYStudio,留下你的问题,我们一起解决他们。原创文章,未经作者允许不可转载。

[转载]ASP.NET的路由系统:路由映射 - Artech - 博客园

mikel阅读(899)

[转载]ASP.NET的路由系统:路由映射 – Artech – 博客园.

总的来说,我们可以通过RouteTable的静态属性Routes得到一个基于应用的 全局路由表,通过上面的介绍我们知道这是一个类型的RouteCollection的集合对象,我们可以通过调用它的MapPageRoute进行路由映 射,即注册URL模板与某个物理文件的匹配关系。路由注册的核心就是在全局路由表中添加一个Route对象,该对象的绝大部分属性都可以通过 MapPageRoute方法的相关参数来指定。接下来我们通过实现演示的方式来说明路由注册的一些细节问题。

目录
一、变量默认值
二、约束
三、对现成文件的路由
四、注册路由忽略地址
五、直接添加路由对象

我 们已前面介绍的关于获取天气预报信息的路由地址,我们在创建的ASP.NET Web应用中创建一个Weather.aspx页面,不过我们并不打算在该页面中呈现任何天气信息,而是将基于该页面的路由信息打印出来。该页面主体部分 的HTML如下所示,我们不仅将基于当前页面的RouteData对象的Route和RouteHandler属性类型输出来,还将存储于Values和 DataTokens字典的变量显示出来。

 1: <body>
 2:     <form id="form1" runat="server">
 3:     <div>
 4:         <table>
 5:             <tr>
 6:                 <td>Route:</td>
 7:                 <td><%=RouteData.Route != null? RouteData.Route.GetType().FullName:"" %></td>
 8:             </tr>
 9:             <tr>
 10:                 <td>RouteHandler:</td>
 11:                 <td><%=RouteData.RouteHandler != null? RouteData.RouteHandler.GetType().FullName:"" %></td>
 12:             </tr>
 13:             <tr>
 14:                 <td>Values:</td>
 15:                 <td>
 16:                     <ul>
 17:                         <%foreach (var variable in RouteData.Values)
 18:                           {%>
 19:                         <li><%=variable.Key%>=<%=variable.Value%></li>
 20:                         <% }%>
 21:                     </ul>
 22:                 </td>
 23:             </tr>
 24:             <tr>
 25:                 <td>DataTokens:</td>
 26:                 <td>
 27:                     <ul>
 28:                         <%foreach (var variable in RouteData.DataTokens)
 29:                           {%>
 30:                         <li><%=variable.Key%>=<%=variable.Value%></li>
 31:                         <% }%>
 32:                     </ul>
 33:                 </td>
 34:             </tr>
 35:         </table>
 36:     </div>
 37:     </form>
 38: </body>

在添加的Global.asax文件中,我们将路由注册操作定义在Application_Start方法中。如下面的代码片断所示,映射到weather.aspx页面的URL模板为{areacode}/{days}。在调用MapPageRoute方法的时候,我们还为定义在URL模板的两个变量定义了默认值以及正则表达式。除此之外,我们还在注册的路由对象上附加了两个变量,表示对变量默认值的说明(defaultCity:BeiJing;defaultDays:2)。

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
 6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
 7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
 8:
 9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
 10:     }
 11: }

一、变量默认值

由于我们为定义在URL模板中表示区号和天数的变量定义了默认值(areacode:010;days:2),如果我们希望返回北京地区未来两天的 天气,可以直接访问应用根地址,也可以只指定具体区号,或者同时指定区号和天数。如下图所示,当我们在浏览器地址栏中输入上述三种不同的URL会得到相同 的输出结果。

从下图所示的路由信息我们可以看到,默认情况下RouteData的Route属性类型正是Route,而RouteHandler属性则一个是PageRouteHandler对象,我们会在本章后续部分对PageRouteHandler进行详细介绍。通过地址解析出来的变量被存储数Values属性中,而在进行路由注册过程为Route对象DataTokens属性定义的变量被转移到了RouteData的同名属性中。[实例源代码下载]

clip_image002

二、约束

我们以电话区号代表对应的城市,为了确保用户在的请求地址中提供有效的区号,我们通过正则表达式(“0\d{2,3}”)对其进行了约束。此外,我们只能提供未来3天以内的天气情况,我们同样通过正则表达式(“[1-3]{1}”)是对请求地址中表示天数的变量进行了约束。如果请求地址中的内容不能符合相关变量段的约束条件,则意味着对应的路由对象与之不匹配。

对于本例来说,由于我们只注册了唯一的路由对象,如果请求地址不能满足我们定义的约束条件,则意味着找不到一个具体目标文件,会返回404错误。如下图所示,由于在请求地址中指定了不合法的区号(01)和天数(4),我们直接在浏览器界面上得到一个HTTP 404错误。

clip_image004

对于约束,除了可以通过字符串的形式为某个变量定义相应的正则表达式之外,我们还可以指定一个实现了IRouteConstraint接 口的类型的对象对整个请求进行约束。如下面的代码片断所示,IRouteConstraint具有唯一的方法Match用于定义约束的逻辑,该方法的5个 参数分别表示:HTTP上下文、当前路由对象、约束的名称(存储约束对象的RouteValueDictionary的Key)、解析被匹配URL得到的 变量集合以及表示路由的方向。

 1: public interface IRouteConstraint
 2: {
 3:     bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
 4: }
 5: public enum RouteDirection
 6: {
 7:     IncomingRequest,
 8:     UrlGeneration
 9: }

所谓路由的方向表示是针对请求匹配(入栈)还是针对URL的生成(出栈),分别通过如上所示的枚举类型RouteDirection的两个枚举值表示。具体来说,当调用路由对象的GetRouteData和GetVirtualPathData方法时,枚举值IncomingRequest和UrlGeneration分别被采用。

ASP.NET路由系统的应用编程接口中定义了如下一个实现了IRouteConstraint接口的HttpMethodConstraint类 型。顾名思义,HttpMethodConstraint提供针对HTTP方法(GET、POST、PUT、DELTE等)的约束。我们可以通过 HttpMethodConstraint为路由对象设置一个允许的HTTP方法列表,只有方法名称在这个指定的列表中的HTTP请求才允许被路由。这个 被允许被路由的HTTP方法列表对于HttpMethodConstraint的只读属性AllowedMethods,并在构造函数中初始化。

 1: public class HttpMethodConstraint : IRouteConstraint
 2: {
 3:     public HttpMethodConstraint(params string[] allowedMethods);
 4:     bool IRouteConstraint.Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
 5:     public ICollection<string> AllowedMethods {  get;  }
 6: }

同样是针对我们演示的例子,我们在进行路由注册的时候通过如下的代表应用了一个类型为HttpMethodConstraint的约束,并将允许的HTTP方法设置为POST,意味着被注册的Route对象仅限于路由POST请求。

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 } };
 6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" }, { "httpMethod", new HttpMethodConstraint("POST") } };
 7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
 8:
 9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
 10:     }
 11: }

现在我们采用与注册的URL模板相匹配的地址(/010/2)来访问Weather.aspx页面,依然会得到如下图所示的404错误。[实例源代码下载]

clip_image006

三、对现有文件的路由

在成功注册路由的情况下,如果我们按照传统的方式访问一个物理文件(比如.asxp、.css或者.js等),在请求地址满足某个路由的URL模板 模式的情况下,ASP.NET是否还是正常实施路由呢?我们不妨通过我们的实例还测试一下。为了让针对某个物理文件的访问地址也满足注册路由对象的URL 模板模式,我们需要按照如下的方式将上面定义的关于正则表达式约束删除。

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
 6:         //var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
 7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
 8:
 9:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, null, dataTokens);
 10:     }
 11: }

当我们通过传统的方式来访问存放于根目录下的weather.aspx页面时会得到如下图所示的结果。从界面上的输出结果我们不难看出,虽然请求地 址完全满足我们注册路由对象的URL模板模式,但是ASP.NET并没有对请求地址实施路由。原因很简单,如果中间发生了路由,基于页面的 RouteData的各项属性都不可能为空。[实例源代码下载]

clip_image008

那么是否意味着如果请求地址对应着一个现存的物理文件,ASP.NET就会自动忽略路由呢?实则不然,或者说不对现有文件实施路由仅仅默认采用的行 为。是否对现有文件实施路由取决于代表全局路由表的RouteCollection对象的RouteExistingFiles属性,该属性默认情况下为 False,我们可以将此属性设置为True使ASP.NET路由系统忽略现有物理文件的存在,总是按照注册的路由表进行路由。为了演示这种情况下,我们 对Global.asax文件作了如下的改动,在进行路由注册之前将RouteTable的Routes属性代表的RouteCollection对象的 RouteExistingFiles属性设置为True。

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         RouteTable.Routes.RouteExistingFiles = true;
 6:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 } };
 7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
 8:
 9:          RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, null, dataTokens);
 10:     }
 11: }

依旧是针对weather.aspx页面的访问,我们却得到不一样的结果。从下图中我们可以看到,针对页面的相对地址weather.aspx不再指向具体的Web页面,在这里就是一个表示获取的天气信息对应的目标城市(areacode=weather.aspx)。[实例源代码下载]

clip_image010

四、注册路由忽略地址

如果将代表全局路由表的RouteTable的静态属性Routes的RouteExistingFiles属性设置为True,意味着 ASP.NET针对所有抵达的请求都一视同仁,都按照注册的路由表进行注册,但这会代码一些问题。不知道读者有没有发现上图所示的页面具有不一样的格式 (标签部分没有加粗,也没有居右上对齐),这是因为这是采用了JQuery的方式来控制的,为此我们必须按照如下的方式来饮用JQuery相关的脚本文 件。

 1: <script src="/jquery-1.4.1.min.js" type="text/javascript"></script>

但是由于我们将全局路由表的RouteExistingFiles属性设置为True,意味着针对上面这个.js脚本文件的访问也会被路由。根据我 们注册的路由规则,针对这个文件的访问会自动被导向weather.aspx这个页面。如下图所示,我们直接在浏览器的地址栏中属性.js文件的地址,呈 现出来还是我们熟悉的界面(areacode=JQuery-1.4.1.min.js)。[实例源代码下载]

clip_image012

这是一个不得不解决的问题,因为它是我们无法正常地在页面中引用向JavaScript和css文件。我们可以通过调用 RouteCollection的Igore方法来注册一些需要让路由系统忽略的URL模板。从前面给出的关于RouteCollection的定义我们 可以看到它具有两个Igore重载,除了指定需要忽略的URL模板之外,我们还可以对相关的变量定义约束正则表达式。为了让ASP.NET路由系统忽略掉 针对.js文件请求,我们可以按照如下的方式在Global.asax中调用RouteTable的Routes属性的Ignore方法。[实例源代码下载]

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         RouteTable.Routes.RouteExistingFiles = true;
 6:         RouteTable.Routes.Ignore("{filename}.js/{*pathInfo}");
 7:         //其他操作
 8:     }
 9: }

五、直接添加路由对象

当我们调用RouteCollection对象的MapPageRoute方法进行路由注册的本质就在路由字典中添加Route对象,所以我们完全 调用Add方法添加一个手工创建的Route对象,如下所示的两种路由注册方式是完全等效的。如果我们需要添加一个继承自RouteBase的自定义路由 对象,我们不得不采用手工添加的方式。

 1: public class Global : System.Web.HttpApplication
 2: {
 3:     protected void Application_Start(object sender, EventArgs e)
 4:     {
 5:         var defaults = new RouteValueDictionary { { "areacode", "010" }, { "days", 2 }};
 6:         var constaints = new RouteValueDictionary { { "areacode", @"0\d{2,3}" }, { "days", @"[1-3]{1}" } };
 7:         var dataTokens = new RouteValueDictionary { { "defaultCity", "BeiJing" }, { "defaultDays", 2 } };
 8:
 9:         //路由注册方式1
 10:         RouteTable.Routes.MapPageRoute("default", "{areacode}/{days}", "~/weather.aspx", false, defaults, constaints, dataTokens);
 11:
 12:         //路由注册方式2
 13:         Route route = new Route("{areacode}/{days}", defaults, constaints, dataTokens, new PageRouteHandler("~/weather.aspx", false));
 14:         RouteTable.Routes.Add("default", route);
 15:     }
 16: }

 

ASP.NET的路由系统:URL与物理文件的分离
ASP.NET的路由系统:路由映射
ASP.NET的路由系统:根据路由规则生成URL

[转载]快速开发平台的比较 - chenjie100 - 博客园

mikel阅读(1053)

[转载]快速开发平台的比较 – chenjie100 – 博客园.

WebBuilder

WebBuilder是一款开源的跨平台、数据库和浏览器的可视化Web应用开发平台。WebBuilder使用了多项最新的技术,使Web应用的开发更快捷和简单。
作为一款高效的Web开发工具,WebBuilder的特色是:
.基于浏览器的集成开发环境
.丰富的组件库
.开发应用简单快速
.高效率和高稳定性
.跨平台、数据库和浏览器
.服务器端的脚本支持
.智能的数据库访问机制
IDE
使用WebBuilder可开发ERP、OA、CRM、HR、MIS以及电信、银行、政府、企业等各行业的企业级应用系统,帮助信息化管理系统的快速构建。完善的基础架构,具有大型应用系统必须的完整功能,使应用系统的开发仅需致力于业务的开发。
您可以到 http://www.putdb.com 在线使用或下载到本地使用。

Nexaweb

最近接触到一种新的基于Web2.0应用开发的技术,叫做Nexaweb(http://www.nexaweb.com),我们可以把他理解为一 个简易的开发平台或框架。Nexaweb的特点就是开发者在一个基于Eclipse的插件集提供的界面上,使用拖拽的方式来构造页面,而最终生成的代码将 是一个基于XML的文件,取名为XAL。事实上,接触过JasperReport+iReport的人,应该不会对这种技术感到陌生。其示例内容如下:

 

JBoss Seam

JBoss Seam,算得上是Java开源框架里面最优秀的快速开发框架之一。
Seam框架非常出色,尤其是他的组件机制设计的很有匠 心,真不愧是Gavin King精心打造的框架了,虽然看起来还是有些缺陷,但是做企业应用项目的话,Seam是一个很棒的选择,作为程序员来说,要比用 Spring/Hibernate/Struts省心的多,更能够把精力放在业务逻辑的编写上面,开发效率也很不错,可能是Java开源框架里面最优秀的 快速开发框架之一了。

Dorado

dorado展现中间件是一款 商用AJAX平台软件,由BSTEK研发。作为Web表现层的运行平台与开发平台,dorado能够提升用户体验、开发规范性与开发效率,并增强项目的可 管理度。其特色包括支持OPOB设计模式,提供一套由BRICH引擎统一驱动的Widget Lib,内置AJAX通讯引擎,广泛支持第三方后台业务逻辑框架,提供Web控制台进行参数配置与性能监控,提供TestFrame进行浏览器端性能测 试,多种性能优化措施以支持高并发压力下的核心应用系统,提供dorado studio与eclipse plug-in方便高效地进行可视化开发。http://www.bstek.com/

Jdon Framework

Jdon Framework(简称JF)是一套适合开发中小型J2EE应用系统的快速开发框架、也是一套Ioc/Aop框架、更是一套符合当前国际水平的、面向组件开发的、国人拥有自主产权的中间件产品。中国第一个开源框架,国内先进的组件、构件工具。
Jdon框架是快速性和灵活性相结合的产物,体现了软件开发既快又好的特点,对于小项目,使用Jdon框架可以开发出高质量可扩展的好的系统;对于大项目,使用Jdon框架可以更快地开发出系统。

Python Web 开发框架

python语言,功能强大,开发效率高,平台移植性好,可扩展性好,很适合小型的团队作战,他的语法采用缩进形式编写,比较简单,容易上手,并且目前Web 开发框架很多,可以直接运用。