zoukankan      html  css  js  c++  java
  • .NET开源敏捷开发框架: SlickOne介绍(一) -- 基于Dapper, Mvc和WebAPI 的快速开发框架

    前言:在两年前(最初发布时间:2013年1月9日(csdn),当前文章时间2015年11月10日),项目组推出了基于Dapper,Mvc和WebApi的快速开发框架,随着后续Slickflow产品的实践和应用,今再次对SlickOne项目做以回顾和总结。其目的是精简,持续改进,保持重构,让开发人员了解到最新的变化,尤其是全栈开发人员做以参考。

    两年之前的博客文章可以查阅(最初发布时间:2013年1月9日):

    http://blog.csdn.net/besley/article/details/8479943

    1. 新版本变化综述:

    1) Dapper部分的变化:

    Dapper本身有支持对数据库底层接口,此次主要是增加了Oracle和MySQL数据库的接口,也修改了Dapper里面的SqlMapper文件。

    2) SlickOne.Data 数据访问

    在泛型封装的基础上,提供了列表分页,新增主键ID返回,根据多ID值查询返回列表,新增查询功能的存储过程等接口。

    3) Mvc/WebApi

    将两个类型的项目动态库文件整合在一个Web项目里面,同时响应页面请求和Api请求。

    4) Web前端

    由JQueryUI 转换到 Bootstrap框架,核心组件SlickGrid 转换为Bootstrap样式。

    2. 框架设计

    1) 数据访问Repository泛型类

    Repository泛型类,彻底实现数据快速访问,不用重复编写不同实体的通用基本方法;而且此泛型类的存在也用以支持Dapper,EF,Heibernate等各种数据访问框架,考虑到不同用户的技术储备,只要去实现IRepository的接口方法就可以继续使用自己喜欢的框架。

    2) 基于简单实体访问

    简单实体,原始来源为数据库表的对应实体,而且并限定为只包含属性字段。在早期版本区分了数据实体和业务实体,有AutoMapper的转换工具,在新版本里面,不再强调业务实体,而是统一命名为简单实体,始终根据简单实体做业务功能开发,做数据的存储和读取。

    3) 接口定义优先策略

    接口方法更加侧重于业务过程的定义。基本方法如新增,编辑和删除可以直接快速调用Repository里的泛型方法,不再默认自动生成Partial文件去维护,包括Interface, Service类和ApiController类都不再生成Partial类文件。

    4) WebApi 接口封装

    消息体引用ResponseResult泛型类,包括状态(Status),消息(Message)和实体(Entity)关键属性。ResponseResult类用于服务端到前端的数据和消息封装,消息内容格式是JSON数据格式。

    5) Javascript模板引擎

    采用前端Javascript模板引擎,解析WebApi传递回的JSON对象,做前端界面展现。模板引擎可以采用HandlebarsJS或DustJS。也可以选择其它模板引擎。

    6) Bootstrap 

    前端框架过渡到Bootstrap框架,相应的控件,如SlickGrid和ZTree等控件都可以找到对应Bootstrap的样式版本。

    3. 解决方案结构图示

    4. 项目代码实例

     1) 实体对象

        /// <summary>
        /// 产品实体对象
        /// </summary>
        [Table("PrdProduct")]
        public class ProductEntity
        {
            public int ID { get; set; }
            public string ProductName { get; set; }
            public string ProductCode { get; set; }
            public string ProductType { get; set; }
            public Nullable<decimal> UnitPrice { get; set; }
            public string Notes { get; set; }
        }
    

    2) 接口定义

        /// <summary>
        /// 产品服务接口
        /// </summary>
        public interface IProductService
        {
            List<ProductEntity> GetProductList();
        }

    3) 服务实现

            /// <summary>
            /// 获取列表数据(示例查询方法,实际会用到分页,此处用于演示。)
            /// </summary>
            /// <returns></returns>
            public List<ProductEntity> GetProductList()
            {
                var sql = @"SELECT ID, 
                                ProductName, 
                                ProductCode, 
                                ProductType, 
                                UnitPrice, 
                                CreatedDate 
                            FROM PrdProduct";
                var list = QuickReporsitory.Query<ProductEntity>(sql, null)
                            .ToList();
                return list;
            }

    4) WebApi

            /// <summary>
            /// 获取产品列表
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public ResponseResult<List<ProductEntity>> GetProductList()
            {
                var result = ResponseResult<List<ProductEntity>>.Default();
                try
                {
                    var list = ProductService.GetProductList();
                    result = ResponseResult<List<ProductEntity>>.Success(list);
                }
                catch (System.Exception ex)
                {
                    result = ResponseResult<List<ProductEntity>>.Error(
                        string.Format("读取{0}数据失败, 错误:{1}", "产品列表", ex.Message)
                    );
                }
                return result;
            }

    5) 前端脚本

    productlist.load = function () {
            jshelper.ajaxGet("/soneweb/api/product/GetProductList", null, function (result) {
                if (result.Status == 1) {
                    var columnProduct = [
                        { id: "ID", name: "ID", field: "ID",  40, cssClass: "bg-gray" },
                        { id: "ProductName", name: "名称", field: "ProductName",  120, cssClass: "bg-gray" },
                        { id: "ProductCode", name: "编码", field: "ProductCode",  120, cssClass: "bg-gray" },
                        { id: "ProductType", name: "类型", field: "ProductType",  160, cssClass: "bg-gray" },
                        { id: "UnitPrice", name: "单价", field: "UnitPrice",  160, cssClass: "bg-gray" },
                        { id: "CreatedDate", name: "创建时间", field: "CreatedDate",  200, cssClass: "bg-gray", formatter: datetimeFormatter },
                    ];
    
                    var optionsProduct = {
                        editable: true,
                        enableCellNavigation: true,
                        enableColumnReorder: true,
                        asyncEditorLoading: true,
                        forceFitColumns: false,
                        topPanelHeight: 25
                    };
    
                    var dsProduct = result.Entity;
                    var dvProduct = new Slick.Data.DataView({ inlineFilters: true });
                    var gridProduct = new Slick.Grid("#myProductGrid", dvProduct, columnProduct, optionsProduct);
    
                    dvProduct.onRowsChanged.subscribe(function (e, args) {
                        gridProduct.invalidateRows(args.rows);
                        gridProduct.render();
    
                    });
    
                    dvProduct.onRowCountChanged.subscribe(function (e, args) {
                        gridProduct.updateRowCount();
                        gridProduct.render();
                    });
    
                    dvProduct.beginUpdate();
                    dvProduct.setItems(dsProduct, "ID");
                    gridProduct.setSelectionModel(new Slick.RowSelectionModel());
                    dvProduct.endUpdate();
    
                    gridProduct.onSelectedRowsChanged.subscribe(function (e, args) {
                        var selectionRowIndex = args.rows[0];
                        var row = dvProduct.getItemByIdx(selectionRowIndex);
    
                        if (row) {
                            productlist.mselectedProductID = row.ID;
                            productlist.mselectedProductRow = row;
                        }
                    });
                };
            });
    
            function datetimeFormatter(row, cell, value, columnDef, dataContext) {
                if (value != null && value != "") {
                    return value.substring(0, 10);
                }
            }
        }
    

    6) 页面呈现

    5. 项目应用场景

    SlickOne适用于BS/CS等架构的系统,目前已经用于Web网站项目,电商ERP,OA,工作流和App等各种类型的系统。

    6. 项目资源

    SlickOne项目开源地址:

    http://github.com/besley/slickone

    (包含数据库脚本文件)

     SlickOne 做框架基础的权限管理:

    http://github.com/besley/slicksafe

    SlickSafe 权限管理在线DEMO:

    http://demo.slickflow.com/ssweb/

    7. 特别致谢

    感谢随风,青文等网友对项目代码的贡献,开源能让大家集体参与,能让更多人分享代码成果。

    8. 培训及技术支持

    为团队开发人员快速上手,Slickflow项目组提供线上开发框架架构设计培训,流程引擎培训,SlickGrid插件开发培训等服务,欢迎留言或咨询。

    9. 在线QQ交流群

    QQ群: 151650479

  • 相关阅读:
    【leetcode】1. Two Sum
    【leetcode】32. Longest Valid Parentheses
    【leetcode】20. Valid Parentheses
    scala细节
    【转】CentOS下firefox安装flash说明
    Spring 容器(一)
    源码学习快捷键
    Gradle编译spring3.x报错找不到itextpdf4.2.2解决方案
    Insertion Sort
    Bubble Sort
  • 原文地址:https://www.cnblogs.com/slickflow/p/4951920.html
Copyright © 2011-2022 走看看