5分钟快速开发之代码生成器asp.net mvc4

开发 前端
我们还是会想要快速开发,比如我选择了一些设定之后,就可以直接生成我想要的代码包括html及js,拷贝到项目中就可以直接运行,运行后就看到我想要的页面,基本功能都有。当然这里所说的快速开发是建立在我对页面功能的提炼模板之上的。

一、前言

作为一个码农这么多年,一直在想怎么提高我们的编码效率,关于如何提高编码效率,我自己的几点体会

1、清晰的项目结构,要编写代码的地方集中

2、实现相同功能的代码量少并且清晰易懂

3、重复或有规律的代码应该自动生成

在这里我就讨论下代码生成的问题。

二、关于代码生成器

刚毕业时我也非常迷信代码生成器,喜欢在网上找一些代码生成器及相关的源码,喜欢在和网友讨论哪款生成器***用,但实际上很少真正用这些东西来开发项目,原因很简单:

1、生成出来的代码不是我们要的代码

2、生成后的代码再修修改改,其实还没有我的ctrl+c和ctrl+v速度快。

3、生成的基本上是实体类及sql拼接代码,现在直接用linq或一些好用的orm多方便,谁还用SQLHelper加sql文拼接?

4、b/s项目中没有一个生成器能很好的能生成UI层代码及前端交互的js代码,即使能生成也是简单的页面。

所以,我劝大家不要迷信代码生成器了。它的确可以提高我们的效率,但是并不是网上你找一个生成器就行的。代码生成器它只是一个模板引擎而已,最重要的不是代码生成器本身,而是对一类功能或一类页面的代码规范,对自己代码的提炼,提炼出一个通用的模板。

比如我们常见的查询页面,录入页面等,我们只要提炼一个标准的查询页面的代码,包括前台html,前台js,后台控制器,后台数据服务。然后把它写成模板,再利用模板引擎就可以生成我们需要的代码了。

代码生成器本身就是模板引擎,所以我觉得***的代码生成器不是网上流传的那些可以生成三层架构代码的软件,而是微软的razor引擎,非常简洁易懂,而且做过asp.net mvc项目的朋友应该也很熟悉。我个人觉得这是用来做代码生成***的引擎。

三、页面模板

我们还是会想要快速开发,比如我选择了一些设定之后,就可以直接生成我想要的代码包括html及js,拷贝到项目中就可以直接运行,运行后就看到我想要的页面,基本功能都有。当然这里所说的快速开发是建立在我对页面功能的提炼模板之上的。实际上我提炼了三种模板:

1、查询页面

这个模板可以解决大部分的查询报表业务功能
 

2、编辑页面

这个编辑模板可以解决基本上所有的录入功能,因为包括了主表,及多个从表(1:N或1:1)录入,而且可以一次性在同一事务中保存。并且定义了很多触发前后事件用于写一些业务处理,并且做到差异更新。
 

3、查询编辑页面,可以查询也可以直接在grid中编辑,这个页面用于做一些简单单据或一些基础数据页面。

四、代码生成原理

把以上页面代码做成razor模板,razor模板 + 设定选项 ==razor引擎==> 页面代码

怎么利用razor引擎,其实有以下几种方法:

1、直接利用mvc的view输出功能,以下为关键代码

  1. var stringWriter = new StringWriter();  
  2. var viewContext = new ViewContext(controllerContext, view, viewData, TempData, stringWriter);  
  3. view.Render(viewContext, stringWriter);  
  4. var result = stringWriter.ToString(); 

用这种方法的优点在于不需要引入第三方类库,直接调用mvc视图的Render方法生成,而且效率很高,缺点是controllerContext及view对象的构建获取非常复杂。这种方法适用于有洁辟的码农们,我属于这一种。

2、利用第三方类库RazorEngine输出,以下为关键代码

  1. var template = "Hello @Model.Name! Welcome to Razor!";  
  2. var viewData = new { Name = "World" });  
  3. var result = Razor.Parse(template, viewData); 

这代码很清爽,一目了然,只不过要引入RazorEngine类库,而且效率不如前者。

五、代码生成用户界面

我们模板准备好了,引擎准备好了,那么还需要一个数据输入viewData,我们做用户界面的目的也就是为了更好的定义这个viewData。

这个用户界面我们还是要把三种页面的定义分开:

1、查询页面生成

***步,选择代码类别search(查询页面),选择数据库,选择业务主表,再勾选字段即可实现查询条件部的设置,并且实现了拖拉排序功能。大家可以对照查询模板看。

 

image

第二步,选择grid中要显示的列,并且设置属性,格式化等 

image

第三步,设置一些全局设定,主要根据这些参数确定命名空间,生成文件名等信息 

image

点击生成按钮,按设定生成代码,生成后弹出文件夹,已分别生成MVC三层代码 

image

mms_receive.cs 

image

Index.cshtml 

image

ReceiveController.cs 

image

把这个代码直接拷贝到项目中直接运行,测试条件过滤都没有问题,grid会自适应高度,grid远程排序,选择分页翻页都没有问题,所有的功能都可用, 

只有lookup控件弹出是空值,因为只把控制设置为了lookup但没有为它设置更详细的选项。autocomplete也是同样 

即代码生成器已经生成了一个大的结构及UI,一些小细节还是要手动修改下,代码生成的UI界面如果把每个控件的选项也做进去会相当的复杂,也没有必要再细化了。 

image

2、编辑页面生成 

***步,选择主表编辑区的字段及控件类型,控件类型中的高级还未实现,这个编辑的UI也可以参照编辑的模板看 

image

第二步,添加tab页签,选择页签类型(grid,form,empty) grid是指跟主表N:1关系,form是指跟主表1:1关系,empty是空页签,生成后自己可以添加内容 

这里我随便添加三个tab页签tab1 tab2 tab3 

tab1用来放人员变动grid(跟主表关系N:1)

image 

 

tab2就选择form(跟主表关系1:1,也可以是主表本身)

image

tab3也随便添些东西 

image

第三步,其它设置 

image

点击生成按钮,生成后自动打开文件夹 

image

把这些代码拷贝到项目中直接运行 

image

tab2 

image

tab3,修改主表数据,tab1,tab2,tab3点保存,能保存成功, 

image

审核按钮也可用,审核后单据不可修改 

image

这个编辑功能基本上可以囊括很多的录入页面了,可以算是比较通用了

3、查询编辑页面(查询编辑在同一个页面内)页面生成

***步,选择查询条件并设置控件类型

image

第二步,设置grid中的数据列,及编辑器 

image

第三步,其它设置 

image

点击生成按钮,生成后自动打开文件夹  

image

把代码直接拷贝到项目中运行,结果如下,经测试除了控件还需要进一步设置,所有按钮功能正常使用 

image

#p#

六、代码生成页面的源码

Index.cshtml

  1. @{  
  2.     ViewBag.Title = "代码生成";  
  3.     Layout = "~/Views/Shared/_Layout.cshtml";  
  4. }  
  5.  
  6. @section head{  
  7.     <link href="~/Content/js/jquery-plugins/smartwizard/smart_wizard.css" rel="stylesheet" /> 
  8.     <style type="text/css"> 
  9.         div#navigation{float: left;width: 180px;}  
  10.         div#wrapper{float: right;width: 100%;margin-left: -185px;}  
  11.         div#wizard{margin-left: 185px;}  
  12.         ul.anchor{margin:0 0 10px 0 !important;}  
  13.         ul li{margin-left:-16px;}  
  14.         .grid .z-txt{margin:0 -3px;width:90%;}   
  15.         .grid input{width:90%;}  
  16.         .grid input[type=checkbox]{cursor:default;}  
  17.         .grid select{width:80%;padding:0 !important;height:22px;}  
  18.         .grid select + a{margin:5px;}  
  19.         .tDnD_whileDrag{background-color: #FBEC88 !important;}  
  20.     </style> 
  21. }  
  22.  
  23. @section scripts{  
  24.     <script src="~/Content/js/jquery-plugins/smartwizard/jquery.smartWizard.js"></script> 
  25.     <script src="~/Content/js/jquery-extend/jquery.tablednd.js"></script> 
  26.     @Scripts.Render("~/Resource/Sys/Generator.js")  
  27.     <script type="text/javascript"> 
  28.         $(function () {  
  29.             ko.applyBindings(new viewModel());  
  30.         });  
  31.     </script> 
  32. }  
  33.  
  34. <div id="container"> 
  35.     <div id="navigation"> 
  36.         <div class="panel-header" style="width: 168px; border-width: 0; background: #FAFAFA;"> 
  37.             代码类别   
  38.             <input type="text" class="z-txt" data-bind="easyuiCombobox:codetype" /> 
  39.             <div style="margin:1px;"></div> 
  40.             数据库名   
  41.             <input type="text" class="z-txt" data-bind="easyuiCombobox:database" /> 
  42.  
  43.             <div style="margin:5px;"></div> 
  44.              <div  data-bind="autoheight:60"  style="width: 172px; border-width: 0;margin:0;padding:0; background: #FAFAFA; overflow:auto;"> 
  45.                 <ul data-bind="easyuiTree:tabletree"></ul> 
  46.             </div> 
  47.         </div> 
  48.     </div> 
  49.     <div id="wrapper"> 
  50.         <div id="wizard" class="swMain" style="width:100%"></div> 
  51.     </div> 
  52. </div> 
  53.  
  54. <script id="template-searchEdit" type="text/html"> 
  55.     <ul> 
  56.         <li><a href="#step-1"> 
  57.             <label class="stepNumber">1</label> 
  58.             <span class="stepDesc">设置条件部<br /> 
  59.                 <small>定义查询条件</small> 
  60.             </span> 
  61.         </a></li> 
  62.         <li><a href="#step-2"> 
  63.             <label class="stepNumber">2</label> 
  64.             <span class="stepDesc">设置数据列<br /> 
  65.                 <small>定义查询显示的数据字段</small> 
  66.             </span> 
  67.         </a></li> 
  68.         <li><a href="#step-3"> 
  69.             <label class="stepNumber">3</label> 
  70.             <span class="stepDesc">其它设置<br /> 
  71.                 <small>修改其它代码生成设置</small> 
  72.             </span> 
  73.         </a></li> 
  74.     </ul> 
  75.  
  76.     <div id="step-1" class="step"> 
  77.         <h2 class="StepTitle">***步 请勾选要查询的字段</h2> 
  78.         <div>    
  79.             <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> 
  80.                     <ul data-bind="easyuiTree:searchEdit.columntree"></ul> 
  81.             </div>    
  82.             <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> 
  83.                 <table class="grid"> 
  84.                     <thead> 
  85.                         <tr> 
  86.                             <th style="width:50px">字段</th> 
  87.                             <th style="width:120px">显示名称</th> 
  88.                             <th style="width:120px">控件类型</th> 
  89.                             @*<th >参数</th>*@  
  90.                             <th style="width:80px">查询逻辑</th> 
  91.                         </tr> 
  92.                     </thead> 
  93.                     <tbody data-bind="foreach:form.conditions"> 
  94.                         <tr data-bind="attr:{id:$index}"> 
  95.                             <td data-bind="text:field" style="text-align:left"></td> 
  96.                             <td><input type="text" class="z-txt" data-bind="value:title"/></td> 
  97.                             <td><select class="z-txt"  data-bind="options:$root.data.input,value:type"></select></td> 
  98.                             @*<td><input type="text" class="z-txt" data-bind="value:options"/></td>*@  
  99.                             <td><select class="z-txt"  data-bind="options:$root.data.compare,value:cp"></select></td> 
  100.                         </tr> 
  101.  
  102.                     </tbody> 
  103.                 </table> 
  104.             </div>    
  105.         </div> 
  106.     </div> 
  107.     <div id="step-2" class="step"> 
  108.         <h2 class="StepTitle">第二步 请勾选要显示的数据字段</h2> 
  109.         <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> 
  110.             <ul data-bind="easyuiTree:searchEdit.columntree2"></ul> 
  111.         </div>    
  112.         <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> 
  113.             <table class="grid"> 
  114.                 <thead> 
  115.                     <tr> 
  116.                         <th style="width:50px">字段</th> 
  117.                         <th style="width:100px">题头</th> 
  118.                         <th style="width:30px">隐藏</th> 
  119.                         <th style="width:30px">排序</th> 
  120.                         <th style="width:50px">对齐</th> 
  121.                         <th style="width:40px">宽度</th> 
  122.                         <th style="width:50px">格式化</th> 
  123.                         <th style="width:50px">编辑器</th> 
  124.                     </tr> 
  125.                 </thead> 
  126.                 <tbody data-bind="foreach:form.columns"> 
  127.                     <tr data-bind="attr:{id:$index}"> 
  128.                         <td data-bind="text:field" style="text-align:left"></td> 
  129.                         <td><input type="text" class="z-txt" data-bind="value:title" /></td> 
  130.                         <td><input type="checkbox" data-bind="checked:hidden"/></td> 
  131.                         <td><input type="checkbox" data-bind="checked:sortable"/></td> 
  132.                         <td><select class="z-txt"  data-bind="options:$root.data.align,value:align" ></select></td> 
  133.                         <td><input type="text" class="z-txt" data-bind="value:width" /></td> 
  134.                         <td><select class="z-txt"  data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> 
  135.                         <td><select class="z-txt"  data-bind="options:$root.data.editor,optionsText:'text',optionsValue:'value',value:editor" ></select></td> 
  136.                     </tr> 
  137.                 </tbody> 
  138.             </table> 
  139.         </div>    
  140.     </div> 
  141.  
  142.      <div id="step-3" class="step"> 
  143.         <h2 class="StepTitle">第三步 其它设置</h2> 
  144.  
  145.         <div class="container_12"> 
  146.             <div class="grid_1 lbl">业务区域</div> 
  147.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> 
  148.  
  149.             <div class="clear"></div> 
  150.  
  151.             <div class="grid_1 lbl">控制器名称</div> 
  152.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> 
  153.  
  154.             <div class="clear"></div> 
  155.  
  156.             <div class="grid_1 lbl">生成路径</div> 
  157.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> 
  158.         </div> 
  159.     </div> 
  160. </script> 
  161.  
  162. <script id="template-search" type="text/html"> 
  163.     <ul> 
  164.         <li><a href="#step-1"> 
  165.             <label class="stepNumber">1</label> 
  166.             <span class="stepDesc">设置条件部<br /> 
  167.                 <small>定义查询条件</small> 
  168.             </span> 
  169.         </a></li> 
  170.         <li><a href="#step-2"> 
  171.             <label class="stepNumber">2</label> 
  172.             <span class="stepDesc">设置数据列<br /> 
  173.                 <small>定义查询显示的数据字段</small> 
  174.             </span> 
  175.         </a></li> 
  176.         <li><a href="#step-3"> 
  177.             <label class="stepNumber">3</label> 
  178.             <span class="stepDesc">其它设置<br /> 
  179.                 <small>修改其它代码生成设置</small> 
  180.             </span> 
  181.         </a></li> 
  182.     </ul> 
  183.  
  184.     <div id="step-1" class="step"> 
  185.         <h2 class="StepTitle">***步 请勾选要查询的字段</h2> 
  186.         <div>    
  187.             <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> 
  188.                     <ul data-bind="easyuiTree:searchEdit.columntree"></ul> 
  189.             </div>    
  190.             <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> 
  191.                 <table class="grid"> 
  192.                     <thead> 
  193.                         <tr> 
  194.                             <th style="width:50px">字段</th> 
  195.                             <th style="width:120px">显示名称</th> 
  196.                             <th style="width:120px">控件类型</th> 
  197.                             @*<th >参数</th>*@  
  198.                             <th style="width:80px">查询逻辑</th> 
  199.                         </tr> 
  200.                     </thead> 
  201.                     <tbody data-bind="foreach:form.conditions"> 
  202.                         <tr data-bind="attr:{id:$index}"> 
  203.                             <td data-bind="text:field" style="text-align:left"></td> 
  204.                             <td><input type="text" class="z-txt" data-bind="value:title"/></td> 
  205.                             <td><select class="z-txt"  data-bind="options:$root.data.input,value:type"></select></td> 
  206.                             @*<td><input type="text" class="z-txt" data-bind="value:options"/></td>*@  
  207.                             <td><select class="z-txt"  data-bind="options:$root.data.compare,value:cp"></select></td> 
  208.                         </tr> 
  209.  
  210.                     </tbody> 
  211.                 </table> 
  212.             </div>    
  213.         </div> 
  214.     </div> 
  215.     <div id="step-2" class="step"> 
  216.         <h2 class="StepTitle">第二步 请勾选要显示的数据字段</h2> 
  217.         <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> 
  218.             <ul data-bind="easyuiTree:searchEdit.columntree2"></ul> 
  219.         </div>    
  220.         <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> 
  221.             <table class="grid"> 
  222.                 <thead> 
  223.                     <tr> 
  224.                         <th style="width:50px">字段</th> 
  225.                         <th style="width:100px">题头</th> 
  226.                         <th style="width:30px">隐藏</th> 
  227.                         <th style="width:30px">排序</th> 
  228.                         <th style="width:50px">对齐</th> 
  229.                         <th style="width:40px">宽度</th> 
  230.                         <th style="width:50px">格式化</th> 
  231.                     </tr> 
  232.                 </thead> 
  233.                 <tbody data-bind="foreach:form.columns"> 
  234.                     <tr data-bind="attr:{id:$index}"> 
  235.                         <td data-bind="text:field" style="text-align:left"></td> 
  236.                         <td><input type="text" class="z-txt" data-bind="value:title" /></td> 
  237.                         <td><input type="checkbox" data-bind="checked:hidden"/></td> 
  238.                         <td><input type="checkbox" data-bind="checked:sortable"/></td> 
  239.                         <td><select class="z-txt"  data-bind="options:$root.data.align,value:align" ></select></td> 
  240.                         <td><input type="text" class="z-txt" data-bind="value:width" /></td> 
  241.                         <td><select class="z-txt"  data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> 
  242.                     </tr> 
  243.                 </tbody> 
  244.             </table> 
  245.         </div>    
  246.     </div> 
  247.  
  248.      <div id="step-3" class="step"> 
  249.         <h2 class="StepTitle">第三步 其它设置</h2> 
  250.  
  251.         <div class="container_12"> 
  252.             <div class="grid_1 lbl">业务区域</div> 
  253.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> 
  254.  
  255.             <div class="clear"></div> 
  256.  
  257.             <div class="grid_1 lbl">控制器名称</div> 
  258.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> 
  259.  
  260.             <div class="clear"></div> 
  261.  
  262.             <div class="grid_1 lbl">生成路径</div> 
  263.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> 
  264.         </div> 
  265.     </div> 
  266. </script> 
  267.  
  268. <script id="template-edit" type="text/html"> 
  269.     <ul> 
  270.         <li><a href="#step-1"> 
  271.             <label class="stepNumber">1</label> 
  272.             <span class="stepDesc">设置主表编辑区<br /> 
  273.                 <small>定义主表编辑字段</small> 
  274.             </span> 
  275.         </a></li> 
  276.         <li><a href="#step-2"> 
  277.             <label class="stepNumber">2</label> 
  278.             <span class="stepDesc">设置明细数据页签<br /> 
  279.                 <small>定义明细表及页签</small> 
  280.             </span> 
  281.         </a></li> 
  282.         <li><a href="#step-3"> 
  283.             <label class="stepNumber">3</label> 
  284.             <span class="stepDesc">其它设置<br /> 
  285.                 <small>修改其它代码生成设置</small> 
  286.             </span> 
  287.         </a></li> 
  288.     </ul> 
  289.  
  290.     <div id="step-1" class="step"> 
  291.         <h2 class="StepTitle">***步 请勾选要编辑的字段</h2> 
  292.         <div>    
  293.             <div style="width:200px;float:left;overflow:auto;" data-bind="autoheight:172"> 
  294.                     <ul data-bind="easyuiTree:searchEdit.columntree"></ul> 
  295.             </div>    
  296.             <div style="float:left;overflow:auto" data-bind="autoheight:172,autowidth:405"> 
  297.                 <table class="grid"> 
  298.                     <thead> 
  299.                         <tr> 
  300.                             <th style="width:20%">字段</th> 
  301.                             <th style="width:40%">标签名称</th> 
  302.                             <th style="width:30%">控件类型</th> 
  303.                             <th style="width:10%">只读</th> 
  304.                         </tr> 
  305.                     </thead> 
  306.                     <tbody data-bind="foreach:form.conditions"> 
  307.                         <tr data-bind="attr:{id:$index}"> 
  308.                             <td data-bind="text:field" style="text-align:left"></td> 
  309.                             <td><input type="text" class="z-txt" data-bind="value:title"/></td> 
  310.                             <td><select class="z-txt"  data-bind="options:$root.data.input,value:type" style="width:60%"></select><a href="#">高级</a></td> 
  311.                             <td><input type="checkbox" data-bind="checked:readonly"/></td> 
  312.                         </tr> 
  313.                     </tbody> 
  314.                 </table> 
  315.             </div>    
  316.         </div> 
  317.     </div> 
  318.     <div id="step-2" class="step"> 
  319.         <h2 class="StepTitle">第二步 请设置页面中的tab页签</h2> 
  320.            
  321.         <div style="float:left;overflow:auto;width:150px;" data-bind="autoheight:172"> 
  322.             <a href="#" class="buttonNext" style="float:left;margin:5px 3px 5px 0" data-bind="click:edit.addTab">添加Tab页签</a> 
  323.             <table class="grid"> 
  324.                 <thead> 
  325.                     <tr> 
  326.                         <th style="width:30%">#</th> 
  327.                         <th style="width:70%">名称</th> 
  328.                     </tr> 
  329.                 </thead> 
  330.                 <tbody data-bind="foreach:form.tabs"> 
  331.                     <tr data-bind="attr:{id:$index}"> 
  332.                         <td><a href="#" data-bind="click:$parent.edit.removeTab">删除</a></td> 
  333.                         <td><input type="text" class="z-txt" data-bind="value:title,click:$parent.edit.clickTab" style="width:90%"/></td> 
  334.                     </tr> 
  335.                 </tbody> 
  336.             </table> 
  337.         </div>    
  338.  
  339.          <div id="edit-tab-setting" style="float:left;overflow:auto;" data-bind="autoheight:172,autowidth:355,visible:edit.selectedTitle()!=null"> 
  340.    
  341.         </div>   
  342.     </div> 
  343.  
  344.      <div id="step-3" class="step"> 
  345.         <h2 class="StepTitle">第三步 其它设置</h2> 
  346.  
  347.         <div class="container_12"> 
  348.             <div class="grid_1 lbl">业务区域</div> 
  349.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.area"/></div> 
  350.  
  351.             <div class="clear"></div> 
  352.  
  353.             <div class="grid_1 lbl">控制器名称</div> 
  354.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.controller"/></div> 
  355.  
  356.             <div class="clear"></div> 
  357.  
  358.             <div class="grid_1 lbl">生成路径</div> 
  359.             <div class="grid_2 val"><input type="text" class="z-txt" data-bind="value:form.path"/></div> 
  360.         </div> 
  361.     </div> 
  362. </script> 
  363.  
  364. <script type="text/html" id="template-edit-tab-setting"> 
  365.      <div style="padding:8px;clear:both"> 
  366.         <span>页签类型 </span> 
  367.         <select class="z-txt" style="padding:0;height:22px;" data-bind="value:edit.selectedTab.type"> 
  368.             <option value="empty">empty</option> 
  369.             <option value="grid">grid</option> 
  370.             <option value="form">form</option> 
  371.         </select>   
  372.  
  373.         <span data-bind="visible:edit.selectedTab.type()!='empty'"> 数据表 </span> 
  374.         <select class="z-txt" style="padding:0;height:22px;" data-bind="options:data.table,optionsText:'text',optionsValue:'id',value:edit.selectedTab.subtable,visible:edit.selectedTab.type()!='empty'"></select> 
  375.  
  376.         <span data-bind="visible:edit.selectedTab.type()!='empty'">与主表的关联</span> 
  377.         <select class="z-txt" style="padding:0;height:22px;" data-bind="options:data.tablekey,value:edit.selectedTab.relationship,visible:edit.selectedTab.type()!='empty'"></select> 
  378.     </div> 
  379.  
  380.     <div style="width:180px;float:left;overflow:auto;margin-right:-18px;" data-bind="autoheight:212,visible:edit.selectedTab.type()!='empty'"> 
  381.         <ul data-bind="easyuiTree:edit.columntree2"></ul> 
  382.     </div>   
  383.       
  384.     <div style="float:right;overflow:auto;" data-bind="autoheight:210,autowidth:535,visible:edit.selectedTab.type()!='empty'"> 
  385.         <table class="grid"> 
  386.             <thead> 
  387.                 <tr> 
  388.                     <th style="width:50px">字段</th> 
  389.                     <th style="width:100px">题头</th> 
  390.                     <th style="width:30px" data-bind="visible:edit.selectedTab.type()=='grid'">隐藏</th> 
  391.                     <th style="width:30px" data-bind="visible:edit.selectedTab.type()=='grid'">排序</th> 
  392.                     <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">对齐</th> 
  393.                     <th style="width:40px" data-bind="visible:edit.selectedTab.type()=='grid'">宽度</th> 
  394.                     <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">格式化</th> 
  395.                     <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='grid'">编辑器</th> 
  396.                     <th style="width:50px" data-bind="visible:edit.selectedTab.type()=='form'">控件类型</th> 
  397.                     <th style="width:10px" data-bind="visible:edit.selectedTab.type()=='form'">只读</th> 
  398.                 </tr> 
  399.             </thead> 
  400.             <tbody data-bind="foreach:edit.selectedTab.columns"> 
  401.                 <tr data-bind="attr:{id:$index}"> 
  402.                     <td data-bind="text:field" style="text-align:left"></td> 
  403.                     <td><input type="text" class="z-txt" data-bind="value:title" /></td> 
  404.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="checkbox" data-bind="checked:hidden"/></td> 
  405.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="checkbox" data-bind="checked:sortable"/></td> 
  406.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt"  data-bind="options:$root.data.align,value:align" ></select></td> 
  407.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><input type="text" class="z-txt" data-bind="value:width" /></td> 
  408.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt"  data-bind="options:$root.data.formatter,optionsText:'text',optionsValue:'value',value:formatter" ></select></td> 
  409.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='grid'"><select class="z-txt"  data-bind="options:$root.data.editor,optionsText:'text',optionsValue:'value',value:editor" ></select></td> 
  410.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='form'"><select class="z-txt"  data-bind="options:$root.data.input,value:type"></select></td> 
  411.                     <td data-bind="visible:$parent.edit.selectedTab.type()=='form'"><input type="checkbox" data-bind="checked:readonly"/></td> 
  412.                 </tr> 
  413.             </tbody> 
  414.         </table> 
  415.     </div> 
  416. </script> 

Generator.js

  1. /**  
  2. * 模块名:mms viewModel  
  3. * 程序名: Generator.js  
  4. * Copyright(c) 2013 liuhuisheng [ liuhuisheng.xm@gmail.com ]   
  5. **/  
  6.  
  7. var viewModel = function () {  
  8.     var self = this;  
  9.  
  10.     this.form = {  
  11.         type: '',  
  12.         database:ko.observable(),  
  13.         table: ko.observable(),  
  14.         controller: ko.observable(),  
  15.         area:ko.observable(),  
  16.         conditions: ko.observableArray(),  
  17.         columns: ko.observableArray(),  
  18.         tabs: ko.observableArray(),  
  19.         path: ko.observable("~/Generator/")  
  20.     };  
  21.    
  22.     this.resetForm = function () {  
  23.         self.form.conditions([]);  
  24.         self.form.columns([]);  
  25.         self.form.tabs([]);  
  26.     };  
  27.  
  28.     this.data = {  
  29.         codetype: [{ text: 'search', value: 'search' }, { text: 'edit', value: 'edit' }, { text: 'searchEdit', value: 'searchEdit' }],  
  30.         database: ko.observableArray(),   
  31.         table: ko.observableArray(),  
  32.         column:ko.observableArray(),  
  33.         tablekey: ko.observableArray(),  
  34.         input: ['text', 'autocomplete', 'combobox', 'lookup','datebox','daterange'],  
  35.         compare: ['equal', 'like', 'startwith', 'endwith', 'greater', 'less', 'daterange'],  
  36.         align:['left','center','right'],  
  37.         formatter: [{text:'',value:''},{ text: '日期', value: 'com.formatDate' }, { text: '时间', value: 'com.formatTime' }, { text: '金额', value: 'com.formatMoney' }, { text: '是否', value: 'com.formatCheckbox' }],  
  38.         editor: [{text:'',value:''},{ text: '文本', value: 'text'}, { text: '整数', value: "{type: 'numberbox',options:{min: 0}}" }, { text: '两位小数', value: "{type: 'numberbox',options:{min: 0, precision: 2}}" }, { text: '下拉框', value: "{type:'combobox',options:{}}" }, { text: '弹出框', value: "{type:'lookup',options:{}}" }, { text: '日期', value: 'datebox' }]  
  39.     };  
  40.  
  41.     this.initDatabase = function () {  
  42.         com.ajax({  
  43.             type: 'GET',  
  44.             async:false,  
  45.             url: '/api/sys/generator/GetConnectionStrings',  
  46.             success: function (d) {  
  47.                 self.data.database(d);  
  48.             }  
  49.         });  
  50.     };  
  51.  
  52.     this.initDatabase();  
  53.  
  54.     this.getTableUrl = function () {  
  55.         return '/api/sys/generator/GetTables?database=' + self.form.database();  
  56.     };  
  57.     this.getColumnUrl = function (table) {  
  58.         return '/api/sys/generator/GetColumns?database=' + self.form.database() + "&table=" + table;  
  59.     }  
  60.  
  61.     this.codetype = {  
  62.         showblank: true,  
  63.         width: 110,  
  64.         data: self.data.codetype,  
  65.         onSelect: function (node) {  
  66.             self.form.type = node.value;  
  67.             self.initWizard();  
  68.         }  
  69.     };  
  70.  
  71.     this.database = {  
  72.         showblank: true,  
  73.         width: 110,  
  74.         data: self.data.database,  
  75.         onSelect: function (node) {  
  76.             self.form.database(node.value)  
  77.             self.form.area((node.value.split('.')[1] || node.value).replace(/(^|\s+)\w/g, function (s) { return s.toUpperCase(); }));  
  78.         }  
  79.     };  
  80.  
  81.     this.tabletree = {  
  82.         method: 'GET',  
  83.         url: ko.computed(self.getTableUrl),  
  84.         loadFilter: function (d) {  
  85.             var data = utils.filterProperties(d.rows || d, ['TableName as id', 'TableName as text']);  
  86.             self.data.table(data);  
  87.             return data;  
  88.         },  
  89.         onSelect: function (node) {  
  90.             self.form.table(node.id);  
  91.             self.edit.init();  
  92.             self.resetWizard();  
  93.             self.form.controller((node.id.split('_')[1] || node.id).replace(/(^|\s+)\w/g, function (s) { return s.toUpperCase(); }));  
  94.         }  
  95.     };  
  96.  
  97.     this.generator = function () {  
  98.         com.ajax({  
  99.             type:'POST',  
  100.             url: '/api/sys/generator',  
  101.             data: ko.toJSON(self.form),  
  102.             success: function (d) {  
  103.                 com.message('success', "代码已生成!");  
  104.             }  
  105.         });  
  106.     };  
  107.  
  108.     this.searchEdit = {};  
  109.     this.searchEdit.columntree = {  
  110.         method: 'GET',  
  111.         url: ko.computed(function () {  
  112.             return self.getColumnUrl(self.form.table());  
  113.         }),  
  114.         checkbox: true,  
  115.         loadFilter: function (d) {  
  116.             return utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']);  
  117.         },  
  118.         onSelect: function (node) {  
  119.             var handle = node.checked ? 'uncheck' : 'check';  
  120.             $(this).tree(handle, node.target);  
  121.         },  
  122.         onCheck: function (node, checked) {  
  123.             if (checked)  
  124.                 self.form.conditions.push({ field: node.id, title: node.id, type: 'text', options: '', cp: 'equal',readonly:false });  
  125.             else  
  126.                 self.form.conditions.remove(function (item) { return item.field == node.id });  
  127.         },  
  128.         onLoadSuccess: self.resetForm  
  129.     };  
  130.  
  131.     this.searchEdit.columntree2 = {  
  132.         method: 'GET',  
  133.         url: ko.computed(function () {  
  134.             return self.getColumnUrl(self.form.table());  
  135.         }),  
  136.         checkbox: true,  
  137.         loadFilter: function (d) {  
  138.             return utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']);  
  139.         },  
  140.         onSelect: function (node) {  
  141.             var handle = node.checked ? 'uncheck' : 'check';  
  142.             $(this).tree(handle, node.target);  
  143.         },  
  144.         onCheck: function (node, checked) {  
  145.             var arr = self.form.columns;  
  146.               
  147.             if (checked) {  
  148.                 var item = $.grep(arr(), function (row) {return row.field == node.id;})[0];  
  149.                 item || arr.push({ field: node.id, title: node.id, hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text' });  
  150.             } else  
  151.                 arr.remove(function (item) { return item.field == node.id });  
  152.         }  
  153.     };  
  154.  
  155.     this.edit = {};  
  156.     this.edit.selectedTab = {  
  157.         title: ko.observable(),  
  158.         type: ko.observable(),  
  159.         subtable: ko.observable(),  
  160.         relationship: ko.observable(),  
  161.         columns: ko.observableArray(),  
  162.         primaryKeys:ko.observableArray()  
  163.     };  
  164.        
  165.     this.edit.columntree2 = {  
  166.         method: 'GET',  
  167.         url:ko.observable(),  
  168.         checkbox: true,  
  169.         loadFilter: function (d) {  
  170.             self.data.column(d);  
  171.             var list = utils.filterProperties(d.rows || d, ['ColumnName as id', 'ColumnName as text']);  
  172.             self.edit.setDefaultForm();  
  173.             self.edit.resetTableKey();  
  174.             var checkedList = [];  
  175.             for (var i in self.edit.selectedTab.columns())  
  176.                 checkedList.push(self.edit.selectedTab.columns()[i].field);  
  177.             for (var i in list)  
  178.                 if ($.inArray(list[i].id, checkedList) > -1) list[i].checked = true;  
  179.               
  180.             return list  
  181.         },  
  182.         onSelect: function (node) {  
  183.             var handle = node.checked ? 'uncheck' : 'check';  
  184.             $(this).tree(handle, node.target);  
  185.         },  
  186.         onCheck: function (node, checked) {  
  187.             var arr = self.edit.selectedTab.columns;  
  188.  
  189.             if (checked) {  
  190.                 var item = $.grep(arr(), function (row) { return row.field == node.id; })[0];  
  191.                 item || arr.push({ field: node.id, title: node.id, hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text', type: '', readonly: true });  
  192.             } else  
  193.                 arr.remove(function (item) { return item.field == node.id });  
  194.         }  
  195.     }  
  196.     this.edit.init = function () {  
  197.         self.edit.selectedTitle(null);  
  198.         self.edit.selectedTab = null;  
  199.         $('#edit-tab-setting').empty();  
  200.     };  
  201.     this.edit.addTab = function () {  
  202.         var title = 'tab' + (self.form.tabs().length + 1);  
  203.         var newTab = {  
  204.             title: ko.observable(title),  
  205.             type: ko.observable('empty'),  
  206.             subtable: ko.observable(self.form.table()),  
  207.             relationship: ko.observable(),  
  208.             columns: ko.observableArray(),  
  209.             primaryKeys:ko.observableArray()  
  210.         };  
  211.         newTab.type.subscribe(function (value) {  
  212.             if (value == 'grid') {  
  213.                 var item = $.grep(self.data.table(), function (row) { return row.id == self.form.table() + "Detail" })[0];  
  214.                 if (item)  
  215.                     newTab.subtable(item.id);  
  216.             }  
  217.             else if (value == 'form') {  
  218.                 newTab.subtable(self.form.table());  
  219.             }  
  220.         });  
  221.         newTab.columns.subscribe(self.tableDnDUpdate);  
  222.         newTab.subtable.subscribe(function (value) {  
  223.             self.edit.selectedTab.columns([]);  
  224.             self.edit.columntree2.url(self.getColumnUrl(value));  
  225.         });  
  226.  
  227.         self.form.tabs.push(newTab);  
  228.     };  
  229.       
  230.     this.edit.removeTab = function (row,event) {  
  231.         self.form.tabs.remove(row);  
  232.  
  233.         if (row.title() == self.edit.selectedTitle())  
  234.             self.edit.selectedTitle(null);  
  235.     };  
  236.     this.edit.selectedTitle = ko.observable();  
  237.     this.edit.clickTab = function (row, event) {  
  238.         if (row.title() == self.edit.selectedTitle()) return;  
  239.    
  240.         self.edit.selectedTitle(row.title());  
  241.         self.edit.selectedTab = row;  
  242.         self.edit.columntree2.url = ko.observable(self.getColumnUrl(self.edit.selectedTab.subtable()));  
  243.  
  244.         var currentTr = $(event.srcElement).parent("td").parent("tr");  
  245.         currentTr.parent().find("tr.tree-node-selected").removeClass("tree-node-selected");  
  246.         currentTr.addClass("tree-node-selected");  
  247.  
  248.         var tabTemplate = $('#template-edit-tab-setting').html();  
  249.         var wrapper = $('#edit-tab-setting').empty().html(tabTemplate);  
  250.  
  251.         ko.cleanNode(wrapper[0]);  
  252.         ko.applyBindings(self, wrapper[0]);  
  253.         wrapper.find("table").tableDnD({ onDrop: self.tableDnDSort });  
  254.     };  
  255.     this.edit.resetTableKey = function () {  
  256.         var relationship = self.edit.selectedTab.relationship();  
  257.         self.data.tablekey([]);  
  258.         var cols = self.data.column();  
  259.         for (var i in cols)  
  260.             if (cols[i].IsIdentity || cols[i].IsPrimaryKey)  
  261.                 self.data.tablekey.push(cols[i].ColumnName);  
  262.  
  263.         self.edit.selectedTab.relationship(relationship);  
  264.         self.edit.selectedTab.primaryKeys(self.data.tablekey());  
  265.     };  
  266.     this.edit.setDefaultForm = function () {  
  267.         var arr = [  
  268.             { field: 'ApproveState', title: '审批状态', type: 'text', readonly: true },  
  269.             { field: 'ApproveRemark', title: '审批意见', type: 'text', readonly: true },  
  270.             { field: 'ApprovePerson', title: '审批人', type: 'text', readonly: true },  
  271.             { field: 'ApproveDate', title: '审批日期', type: 'datebox', readonly: true },  
  272.             { field: 'CreatePerson', title: '编制人', type: 'text', readonly: true },  
  273.             { field: 'CreateDate', title: '编制日期', type: 'datebox', readonly: true },  
  274.             { field: 'UpdatePerson', title: '修改人', type: 'text', readonly: true },  
  275.             { field: 'UpdateDate', title: '修改日期', type: 'datebox', readonly: true }  
  276.         ];  
  277.  
  278.         var cols = self.data.column();  
  279.         var defaults = { field: '', title: '', hidden: false, sortable: true, align: 'left', width: 80, formatter: '', editor: 'text', type: '', readonly: true };  
  280.         for (var i in arr) {  
  281.             if (!$.grep(cols, function (item) { return item.ColumnName == arr[i].field; }).length)  
  282.                 return;  
  283.  
  284.             arr[i] = $.extend({}, defaults, arr[i]);  
  285.         }  
  286.  
  287.         self.edit.selectedTab.columns(arr);  
  288.  
  289.         var tree = self.edit.columntree2.$element();  
  290.         for (var i in arr) {  
  291.             var node = tree.tree('find', arr[i].field);  
  292.             if (node) tree.tree('check', node.target);  
  293.         }  
  294.     };  
  295.  
  296.     this.initWizard = function () {  
  297.         var stepTemplate = $('#template-' + self.form.type);  
  298.         if (!stepTemplate.length) return;  
  299.  
  300.         var wizard = $('#wizard').removeData('smartWizard').empty();  
  301.         ko.cleanNode(wizard[0]);  
  302.           
  303.         wizard.html(stepTemplate.html());  
  304.         wizard.smartWizard({  
  305.             labelNext: '下一步',  
  306.             labelPrevious: '上一步',  
  307.             labelFinish: '生成',  
  308.             onFinish: self.generator  
  309.         });  
  310.         var resizeStep = function () {  
  311.             $(".step").height($(window).height() - 145)  
  312.                       .width($(window).width() - 205);  
  313.             $(".actionBar").width($(window).width() - 195);  
  314.             var index = wizard.smartWizard('currentStep');  
  315.             wizard.smartWizard('goToStep', index);  
  316.         };  
  317.         $(window).resize(resizeStep);  
  318.         resizeStep();  
  319.         ko.applyBindings(self, wizard[0]);  
  320.         wizard.find("table").tableDnD({ onDrop: self.tableDnDSort });  
  321.  
  322.         for (var i in self.form) {  
  323.             if ($.isFunction(self.form[i]))  
  324.                 if (self.form[i]() instanceof Array)  
  325.                     if (self.form[i].subscribe)   
  326.                         self.form[i].subscribe(self.tableDnDUpdate);  
  327.         }  
  328.     };  
  329.     this.resetWizard = function () {  
  330.         var wizard = $("#wizard").smartWizard('goToStep', 1);  
  331.         for (var i = 1; i <= wizard.find(">ul>li").length; i++)  
  332.             wizard.smartWizard("disableStep", i);  
  333.     };  
  334.  
  335.     this.tableDnDUpdate = function () {  
  336.         setTimeout('$("table").tableDnDUpdate()', 300);  
  337.     };  
  338.      
  339.     this.tableDnDSort = function (table, row) {  
  340.         var name = $(table).find("tbody").attr("data-bind").replace('foreach:form.','');  
  341.         var array = self.form[name], i = 0;  
  342.  
  343.         if (name == 'foreach:edit.selectedTab.columns')  
  344.             array = self.edit.selectedTab.columns;  
  345.  
  346.         $("tr[id]", table).each(function () { array()[this.id].id = i++; });  
  347.         array.sort(function (left, right) { return left.id == right.id ? 0 : (left.id < right.id ? -1 : 1) });  
  348.  
  349.         //for fix ko bug refresh ui  
  350.         var tempArr = array();  
  351.         array([]);  
  352.         array(tempArr);  
  353.     };  
  354. }; 

razor模板

model.cshtml

  1. @using Zephyr.Core.Generator  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Text;  
  5. using Zephyr.Core;  
  6.  
  7. namespace Zephyr.Web.@(@Model.Area).Models  
  8. {  
  9.     [Module("@Model.Database")]  
  10.     public class @(Model.TableName)Service : ServiceBase<@Model.TableName> 
  11.     {  
  12.          
  13.     }  
  14.  
  15.     public class @Model.TableName : ModelBase  
  16.     {  
  17. @foreach(TableSchema item in Model.Columns)  
  18. {  
  19.     if (item.IsIdentity)  
  20.     {  
  21.         @:[Identity]  
  22.     }  
  23.  
  24.     if (item.IsPrimaryKey)  
  25.     {  
  26.         @:[PrimaryKey]     
  27.     }  
  28.         @:public @item.TypeName @item.ColumnName { get; set; }  
  29. }  
  30.     }  

其它各页面的模板我就不一一贴出来了,大家可以查看我以前的那些关于共通viewModel的博客,查询及编辑页面我都有详细介绍过,大家也可以自己提炼出自己的一套模板,然后也可以用这同一个思路去做一个代码生成器。

七、后述

有了这个代码生成的功能,5分钟做一个基本的页面应该是完全没有问题的。

我这里分享下自己的代码生成的思路,权当抛砖引玉,大家有什么更好的方法欢迎留言。

原文链接:http://www.cnblogs.com/xqin/p/3553597.html

责任编辑:林师授 来源: 博客园
相关推荐

2009-08-07 14:05:21

ASP.NET控件

2023-01-06 07:52:52

代码生成器开发

2010-06-23 15:44:03

ASP.NET MVC

2009-07-30 13:45:40

ASP.NET开发模式MVC模式

2009-07-22 16:34:36

使用T4ASP.NET MVC

2009-07-24 13:20:44

MVC框架ASP.NET

2009-04-02 11:00:09

微软ASP.NETMVC

2010-06-25 08:51:46

ASP.NET MVC

2014-07-29 10:00:30

ASP.NETMVCAutoFac

2009-07-31 12:43:59

ASP.NET MVC

2014-06-30 09:22:38

ASP.NETBootstrap

2015-06-29 10:00:02

ASP.NETMVC6

2014-08-26 09:22:40

ASP.NET MVCRouting

2009-07-28 17:17:19

ASP.NET概述

2015-06-23 16:47:53

ASP.NET

2009-07-22 13:24:24

ASP.NET MVC

2009-07-20 10:53:59

ASP.NET MVC

2009-07-22 10:09:59

ASP.NET MVC

2009-07-23 14:31:20

ASP.NET MVC

2009-07-23 15:44:39

ASP.NET MVC
点赞
收藏

51CTO技术栈公众号