.NET+MVC+IbatisNet+log4net+ExtJS

最新修改文章请移步到这里查看

1. 简介

通过一个用户的增删改查来讲一下标题所说的架构,对于相关原理及细节不做深入讲解。

先看下最终界面,虽然只有一个页面。


图1-1 用户管理界面


图1-2 用户新增


图1-3 用户修改

再来看下项目代码目录结构的截图。

图1-4 项目代码目录结构

其中引用到的类库截图如下,红色框内为新引入的类库。


图1-5 项目引用

2. 搭建


2.1 MVC搭建

利用VS2010建立一个MVC项,这里的MVC版本是2.0,如图2-1-1所示。

图2-1-1 建立MVC项目

图2-1-2 MVC项目

2.2 ExtJS导入

本项目采用的是ExtJS,所以Scripts下面的都可以删掉,然后引入ExtJS包,这里只需引入ExtJS中的resource文件夹和ext-all.js,当然引入压缩版的ExtJS更好,如图2-1-3所示。



图2-2-1 引入ExtJS

2.3 Ibatis.net配置

先添加引用,添加的包括开始所讲的哪些dll文件,最后结果如图2-3-1所示。

图2-3-1 添加相关引用

接下来就得引入Ibatis的一些配置文件并做修改。复制Ibatis.DataMapper.1.6.2.bin下的providers.config文件到项目中,你会发现里面有很多类型的数据库的配置,这个配置主要是给Ibatis访问数据库提供驱动信息。因为这里用的是MySQL数据库,因此只需要保留MySQL配置的节点就可以了,然后将enable属性值修改为true,这里要注意下MySQL类库的版本,版本可以通过查看MySQL类库的属性获得。然后修改description,assemblyName中版本号。最终修改完后的providers.config如图2-3-3所示。

图2-3-2MySQL.Data版本查看



图2-3-3 providers.config配置最终结果

复制Ibatis.DataMapper.1.6.2.bin下的sample.SqlMap.config到项目中,将文件名称修改为SqlMap.config,删掉properties节点,修改providers节点中的resource属性,属性值就是上面providers.config文件的路径,接着修改database节点中的provider节点name属性值改为providers.config中的name属性值,connectionString改为本地的数据库连接信息,最终修改后的结果如图2-3-4所示。



图2-3-4 SqlMap.config配置最终结果

2.4 log4net配置

修改Web.config文件,将以下内容添加到Web.config的configuration节点下。内容主要是log4net的配置信息。

<configSections>
    <sectionGroup name="iBATIS">
      <section name="logging" type="IBatisNet.Common.Logging.ConfigurationSectionHandler, IBatisNet.Common"/>
    </sectionGroup>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <iBATIS>
    <logging>
      <logFactoryAdapter type="IBatisNet.Common.Logging.Impl.Log4NetLoggerFA, IBatisNet.Common.Logging.Log4Net">
        <arg key="configType" value="inline"/>
        <arg key="showLogName" value="true"/>
        <arg key="showDataTime" value="true"/>
        <arg key="level" value="ALL"/>
        <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:SSS"/>
      </logFactoryAdapter>
    </logging>
  </iBATIS>
  <log4net>
    <!-- Define some output appenders -->
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <param name="File" value="mybatis.log"/>
      <param name="AppendToFile" value="true"/>
      <param name="MaxSizeRollBackups" value="2"/>
      <param name="MaximumFileSize" value="100KB"/>
      <param name="RollingStyle" value="Size"/>
      <param name="StaticLogFileName" value="true"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n"/>
        <param name="Footer" value="[Footer]\r\n"/>
        <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n"/>
      </layout>
    </appender>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"/>
      </layout>
    </appender>
    <!-- Set root logger level to ERROR and its appenders -->
    <root>
      <level value="DEBUG"/>
      <appender-ref ref="RollingLogFileAppender"/>
      <appender-ref ref="ConsoleAppender"/>
    </root>
    <!-- Print only messages of level DEBUG or above in the packages -->
    <logger name="IBatisNet.DataMapper.Configuration.Cache.CacheModel">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.DataMapper.Configuration.Statements.PreparedStatementFactory">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.DataMapper.LazyLoadList">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.DataAccess.DaoSession">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.DataMapper.SqlMapSession">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.Common.Transaction.TransactionScope">
      <level value="DEBUG"/>
    </logger>
    <logger name="IBatisNet.DataAccess.Configuration.DaoProxy">
      <level value="DEBUG"/>
    </logger>
  </log4net>


2.5 数据库建表

文章开头指出了这里主要是做一个用户的增删改查,那么只需建一个用户表即可,数据库名称为donet,MySQL建表语句如下。

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `address` varchar(256) DEFAULT NULL,
  `email` varchar(100) DEFAULT NULL,
  `phone` varchar(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1  DEFAULT CHARSET=utf8;


3 前后台开发


3.1 新增页面

在Views下新建一个名为System的文件夹,然后增加一个名为User的视图(不要选择母版),如图3-1-1所示。


图3-1-1 新增视图

在页面中引入ExtJS库及CSS样式。最终页面代码如下,对于ExtJS的开发这里就不细讲,以下代码主要完成了一个支持查询、新增、删除、修改的用户信息列表,前后端交互主要用json格式数据完成。

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>用户管理</title>
    <script src="../../Scripts/ext/ext-all.js" type="text/javascript"></script>
    <link href="../../Scripts/ext/resources/ext-theme-neptune/ext-theme-neptune-all.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript">


        Ext.onReady(function () {



            var store = Ext.create('Ext.data.Store', {
                autoLoad: true,
                pageSize: 10,
                fields: ['id', 'name', 'age', 'address', 'email', 'phone'],
                proxy: {
                    type: 'ajax',
                    url: '/user/list',
                    reader: {
                        root: 'dataList',
                        totalProperty: 'totalCount'
                    }
                }

            });
            var gridPanel = Ext.create('Ext.grid.Panel', {
                title: '用户管理',
                margin: 20,
                id: 'usergrid',
                renderTo: Ext.getBody(),
                selType: 'checkboxmodel',
                store: store,
                dockedItems: [{
                    xtype: 'toolbar',
                    layout: 'fit',
                    items: [{
                        xtype: 'form',
                        border: 0,
                        layout: {
                            type: 'column'
                        },
                        defaults: {
                            xtype: 'textfield',
                            labelAlign: 'right',
                            labelWidth: 'auto',
                            margin: 2
                        },
                        items: [{
                            fieldLabel: '姓名',
                            name: 'name'
                        }, {
                            xtype: 'container',
                            items: [{
                                xtype: 'button',
                                text: '查询',
                                handler: function () {
                                    Ext.apply(gridPanel.getStore().proxy.extraParams, this.up('form').getForm().getValues());
                                    gridPanel.getStore().loadPage(1);
                                }
                            }, {
                                xtype: 'button',
                                margin: '0 0 0 4',
                                text: '清除',
                                handler: function () {
                                    this.up('form').getForm().reset();
                                    Ext.apply(gridPanel.getStore().proxy.extraParams, this.up('form').getForm().getValues());
                                    gridPanel.getStore().loadPage(1);
                                }
                            }]
                        }]
                    }]
                }, {
                    xtype: 'toolbar',
                    items: [{
                        text: '新增',
                        iconCls: 'icon-add',
                        handler: addUser
                    }, {
                        text: '删除',
                        iconCls: 'icon-delete',
                        handler: deleteUser
                    }]
                }, {
                    xtype: 'pagingtoolbar',
                    store: store,
                    displayInfo: true,
                    dock: 'bottom'
                }],
                columns: [
                            { text: '姓名', dataIndex: 'name', flex: 1, align: 'center' },
                            { text: '年龄', dataIndex: 'age', flex: 1, align: 'center' },
                            { text: '地址', dataIndex: 'address', flex: 1, align: 'center' },
                            { text: '邮箱', dataIndex: 'email', flex: 1, align: 'center' },
                            { text: '电话', dataIndex: 'phone', flex: 1, align: 'center' },
                            { text: '操作', flex: 1, align: 'center', renderer: operationRenderer }
                        ]


            });

            function operationRenderer(value, metaData, record, rowIndex) {
                return '<a href="javascript:void(0);" οnclick="modifyUser(' + rowIndex + ')">修改</a>';
            }

            Ext.get(window).on('resize', function () {
                gridPanel.doLayout();
            });



        });


        function addUser() {
            var win = getWindow();
            win.setTitle('新增用户');
            win.show();
        }

        function modifyUser(rowIndex) {
            var win = getWindow();
            win.setTitle('修改用户');
            var record = Ext.getCmp('usergrid').getStore().getAt(rowIndex).getData();
            win.down('form').getForm().setValues(record);
            win.show();
        }


        function getWindow() {
            return Ext.create('Ext.window.Window', {
                modal: true,
                width: 500,
                id: 'win',
                items: [{
                    xtype: 'form',
                    layout: {
                        type: 'vbox',
                        align: 'center'
                    },
                    defaults: {
                        labelAlign: 'right',
                        margin: '5 0 5 0',
                        labelWidth: 50
                    },
                    defaultType: 'textfield',
                    items: [{
                        xtype: 'hiddenfield',
                        name: 'id',
                        value: 0
                    }, {
                        fieldLabel: '姓名',
                        name: 'name'
                    }, {
                        xtype: 'numberfield',
                        fieldLabel: '年龄',
                        name: 'age'
                    }, {
                        fieldLabel: '地址',
                        name: 'address'
                    }, {
                        fieldLabel: '邮箱',
                        name: 'email'
                    }, {
                        fieldLabel: '电话',
                        name: 'phone'
                    }]
                }],
                buttonAlign: 'center',
                buttons: [{
                    text: '提交',
                    handler: function () {
                        var params = this.up('window').down('form').getForm().getValues();
                        Ext.Ajax.request({
                            url: '/user/save',
                            headers: {
                                Accept: 'application/json',
                                'Content-Type': 'application/json'
                            },
                            params: Ext.encode(params),
                            success: function (response) {
                                Ext.getCmp('usergrid').getStore().load();
                                Ext.getCmp('win').close();
                            }
                        });

                    }
                }, {
                    text: '取消',
                    handler: function () {
                        this.up('window').close();
                    }
                }]
            });
        }


        function deleteUser() {
            var rows = Ext.getCmp('usergrid').getSelectionModel().getSelection();
            if (rows.length) {
                var ids = [];
                for (var i = rows.length - 1; i >= 0; i--) {
                    ids.push(rows[i].get('id'));
                }
                Ext.Ajax.request({
                    url: '/user/delete',
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json'
                    },
                    params: Ext.encode(ids),
                    success: function (response) {
                        Ext.getCmp('usergrid').getStore().load();
                    }
                });
            }
        }
    
    </script>
</head>
<body style="overflow: hidden">
</body>
</html>

对于MVC开发模式的话,新增视图后还需要新增对应的Controller类来返回视图。在Controllers下新增名为SystemController的控制器。代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyServer.Controllers
{
    public class SystemController : Controller
    {
        //
        // GET: /System/User

        public ActionResult User()
        {
            return View();
        }

    }
}

3.2 增删改查功能开发

基于Ibatis.net开发最方便的一点是可以自己写SQL,其中增删改查功能都通过自己写的SQL文件来完成。下面讲如何配置相应的SQL,先在项目中增加个Maps的文件夹,然后增加一个User.xml文件,这里要相应的在SqlMap.config的sqlMaps节点下添加这个文件路径。每加一个xml文件都需要在SqlMap中添加映射。

SqlMap.config的sqlMaps节点内容如下。

<sqlMaps>
			<sqlMap resource="Maps/User.xml" />
	</sqlMaps>

User.xml文件如下,包含了增删改查的SQL,具体Ibatis的语法可以在网上学习下。语法很简单,这里就不赘述了。

<?xml version="1.0" encoding="utf-8" ?>
<sqlMap namespace="EntityModel" xmlns="http://ibatis.apache.org/mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <alias>
    <typeAlias alias="User" type="MyServer.User,MyServer"/>
  </alias>

  <resultMaps>
    <resultMap id="SelectAllResult" class="User">
      <result property="id" column="id"/>
      <result property="name" column="name"/>
      <result property="age" column="age" />
      <result property="address" column="address" />
      <result property="email" column="email" />
      <result property="phone" column="phone" />
    </resultMap>
  </resultMaps>

  <statements>
    
    <select id="SelectAllUser" resultMap="SelectAllResult" parameterClass="User">
      select id,name,age,email,address,phone from t_user
      <dynamic prepend="where">
        <isParameterPresent>
          <isNotEmpty  property="name"  >
            name like CONCAT('%',#name#,'%')
          </isNotEmpty>
        </isParameterPresent>
      </dynamic>
      order by id desc
      <dynamic prepend="limit">
        <isParameterPresent>
          <isNotEmpty  property="start"  >
            #start#,#limit#
          </isNotEmpty>
        </isParameterPresent>
      </dynamic>
    </select>

    <select id="SelectUserCount"  resultClass="int">
      select count(id) from t_user
      <dynamic prepend="where">
        <isParameterPresent>
          <isNotEmpty  property="name"  >
            name like CONCAT('%',#name#,'%')
          </isNotEmpty>
        </isParameterPresent>
      </dynamic>
    </select>

    <insert id="InsertUser" parameterClass="User">
      insert into t_user(name,age,address,email,phone)
      values(#name#, #age#, #address#, #email#, #phone# )
      <selectKey property="id" type="pre" resultClass="int">
        SELECT LAST_INSERT_ID() as Id
      </selectKey>
    </insert>

    <delete id="DeleteUserByIdList" parameterClass="list">
      delete from t_user
      <dynamic prepend="where">
        <isParameterPresent>
          <iterate open="(" close=")" conjunction="OR">
            id = #[]#
          </iterate>
        </isParameterPresent>
      </dynamic>
    </delete>

    <update id="UpdateUser" parameterClass="User">
      update t_user set
      <dynamic>
        <isParameterPresent>
          <isNotEmpty property="name" >
            name = #name#
          </isNotEmpty>
          <isNotEmpty prepend="," property="age" >
            age = #age#
          </isNotEmpty>
          <isNotEmpty prepend="," property="address" >
            address = #address#
          </isNotEmpty>
          <isNotEmpty prepend="," property="email" >
            email = #email#
          </isNotEmpty>
          <isNotEmpty prepend="," property="phone" >
            phone = #phone#
          </isNotEmpty>
        </isParameterPresent>
      </dynamic>
      Where id=#id#
    </update>
  </statements>

</sqlMap>

那么如何去调用上面的这些sql了,通过上面的sql也可以知道每个语句都有一个id,要调用哪个只需要找到对应的id就行了,具体的调用方法,ibatis.net提供了方法。这里可以在项目中新增一个DAL文件夹,增加一个BaseDA.cs 的类,这个类提供了通用的一些调用sql语句的方法,一般参数就是上面的sql的id以及要传入到sql的参数,参数可以是实体类的实例或单个参数等。代码如下。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using IBatisNet.DataMapper;

namespace MyServer
{
    public class BaseDA
    {
        public static int Insert<T>(string statementName, T t)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return (int)iSqlMapper.Insert(statementName, t);
            }
            return 0;
        }

        public static int Update<T>(string statementName, T t)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.Update(statementName, t);
            }
            return 0;
        }

        public static int Delete(string statementName, int primaryKeyId)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.Delete(statementName, primaryKeyId);
            }
            return 0;
        }

        public static int Delete(string statementName, int[] primaryKeyIdList)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.Delete(statementName, primaryKeyIdList);
            }
            return 0;
        }

        public static T Get<T>(string statementName, int primaryKeyId) where T : class
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.QueryForObject<T>(statementName, primaryKeyId);
            }
            return null;
        }

        public static IList<T> QueryForList<T>(string statementName, T t)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.QueryForList<T>(statementName, t);
            }
            return null;
        }

        public static object QueryForObject<T>(string statementName, T t)
        {
            ISqlMapper iSqlMapper = Mapper.Instance();
            if (iSqlMapper != null)
            {
                return iSqlMapper.QueryForObject(statementName, t);
            }
            return null;
        }
    }
}

上面相当于完成了数据库层面的增删改查功能,接着就是完成前端要调用的增删改查接口。先新增一个User的实体类(去掉命名空间中的Models),放在Models文件夹下,然后新增一个名为UserController的控制器,用来提供User的增删改查接口,代码如下。


using System.Web.Mvc;
using Newtonsoft.Json;
using System.IO;
using System.Collections;
using log4net;
	
namespace MyServer.Controllers
{
    [HandleError]
    public class UserController : Controller
    {

        ILog logger = LogManager.GetLogger(typeof(UserController));
        /// <summary>
        /// 获取用户列表
        /// </summary>
        /// <returns></returns>
        public string List()
        {
            string[] allKeys = Request.QueryString.AllKeys;
            Hashtable ht = new Hashtable();
            foreach (string key in allKeys)
            {
                ht[key] = Request.QueryString[key];
            }
            User user = JsonConvert.DeserializeObject<User>(JsonConvert.SerializeObject(ht));
            object obj = BaseDA.QueryForList<User>("SelectAllUser", user);
            object count = BaseDA.QueryForObject<User>("SelectUserCount", user);
            DataList dataList = new DataList()
            {
                success = true,
                msg = "",
                totalCount = (int)count,
                dataList = obj
            };
            return JsonConvert.SerializeObject(dataList);
        }

        /// <summary>
        /// 新增及修改用户
        /// </summary>
        /// <returns></returns>
        public string Save()
        {
            StreamReader sr = new StreamReader(Request.InputStream);
            string userStr = sr.ReadToEnd();
            User user = JsonConvert.DeserializeObject<User>(userStr);
            if (user.id == 0)
            {
                BaseDA.Insert<User>("InsertUser", user);
                logger.Info("new user " + user.ToString());
            }
            else
            {
                BaseDA.Update<User>("UpdateUser", user);
                logger.Info("update user " + user.ToString());
            }
            
            
            Data data = new Data()
            {
                success = true,
                msg = "",
                data = null
            };
            return JsonConvert.SerializeObject(data);
        }

        /// <summary>
        /// 删除用户
        /// </summary>
        /// <returns></returns>
        public string Delete()
        {
            StreamReader sr = new StreamReader(Request.InputStream);
            string userStr = sr.ReadToEnd();
            int[] ids = JsonConvert.DeserializeObject<int[]>(userStr);
            BaseDA.Delete("DeleteUserByIdList", ids);
            Data data = new Data()
            {
                success = true,
                msg = "",
                data = null
            };
            return JsonConvert.SerializeObject(data);
        }

    }
}

3.3 运行

修改Global.asax文件,主要改一些路由匹配的规则,修改路由参数默认值为上面添加的User视图,controller改为System,action改为User,代码如图。

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // 路由名称
                "{controller}/{action}/{id}", // 带有参数的 URL
                new { controller = "System", action = "User", id = UrlParameter.Optional } // 参数默认值
            );

        }

接着就是直接按ctrl+F5运行了。在用户管理面可以添加用户,删除用户,修改用户,根据姓名查询用户。效果图在文章开头就已给出,这里就不在重复了。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值