【MVC 4】3.MVC 基本工具(创建示例项目、使用 Ninject)
作者:[美]Adam Freeman 来源:《精通ASP.NET MVC 4》
本次将考察三类工具,它们是每一位 MVC 程序员工具库的成员:DI容器、单元测试框架和模仿工具。
1.创建一个示例项目
创建一个空 ASP.NET MVC 4 项目 EssentiaTools 。
1.1 创建模型类
在 Models 文件夹下新建 Product.cs 类文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Catogory { get; set; }
}
}
另外,再新建 LinqValueCalculator.cs 类文件,它将计算 Product 对象集合的总价。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class LinqValueCalculator : IValueCalculator
{
public decimal ValueProducts(IEnumerable<Product> products)
{
return products.Sum(p=>p.Price);
}
}
}
接着,再新建一个模型类 ShoppingCart ,它表示了 Product 对象的集合,并且使用 LinqValueCalculator 来确定总价。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class ShoppingCart
{
private IValueCalculator calc; public ShoppingCart(IValueCalculator calcParam) {
calc = calcParam;
} public IEnumerable<Product> Products { get; set; } public decimal CalcularProductTotal() {
return calc.ValueProducts(Products);
}
}
}
1.2 添加控制器
在 Controller 文件夹下新建控制器文件 HomeController.cs
using EssentiaTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace EssentiaTools.Controllers
{
public class HomeController : Controller
{
private Product[] products = {
new Product{Name="Kayak",Catogory="Watersports",Price=275M},
new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M},
new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
};
public ActionResult Index()
{
LinqValueCalculator calc = new LinqValueCalculator();
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalcularProductTotal();
return View(totalValue);
}
}
}
1.3 添加视图
根据动作方法,创建对应的视图文件 Index.cshtml
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Value</title>
</head>
<body>
<div>
Total value is $@Model
</div>
</body>
</html>
运行程序,效果如下:

2.使用 Ninject
Ninject 是人们所喜欢的DI容器,它简单、优雅且易用。
DI容器,其思想是对MVC 应用程序中的组件进行解耦,这是通过接口与DI 相结合来实现的。
2.1 理解问题
在前面示例中,构造了一个能够用 DI 解决的问题。该项目依赖于一些紧耦合的类:ShoppingCart 类与 LinqValueCalculator 类是紧耦合的,而 HomeController 类与 ShoppingCart 和 LinqValueCalculator 都是紧耦合的。这意味着,如果想替换 LinqValueCalculator 类,就必须在与它有紧耦合关系的类中找出对它的引用,并进行修改。对这种简单的项目来说,这不是问题。但是,在一个实际项目中,这可能会成为一个乏味且易错的过程,尤其是,如果想在两个不同的计算器实现之间进行切换,而不只是用另一个类来替换另一个类的情况下。
运用接口
通过使用 C# 接口,从计算器的实现中抽象出其功能定义,可以解决部分问题。在 Models 文件夹下添加接口文件 IValueCalculator:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EssentiaTools.Models
{
public interface IValueCalculator
{
decimal ValueProducts(IEnumerable<Product> products);
}
}
然后,可以在 LinqValueCalcular 类中实现这一接口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class LinqValueCalculator: IValueCalculator
{
public decimal ValueProducts(IEnumerable<Product> products)
{
return products.Sum(p=>p.Price);
}
}
}
该接口能够打断 ShoppingCart 与 LinqValueCalcular 类之间的紧耦合关系,将该接口运用于 ShoppingCart 类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class ShoppingCart
{
private IValueCalculator calc; public ShoppingCart(IValueCalculator calcParam) {
calc = calcParam;
} public IEnumerable<Product> Products { get; set; } public decimal CalcularProductTotal() {
return calc.ValueProducts(Products);
}
}
}
在上述过程中,已经解除了 ShoppingCart 与 LinqValueCalculator 之间的耦合,因为在使用 ShoppingCart时,只要为其构造器传递一个 IValueCalculator 接口对象就行了。于是,SHoppingCart 类与 IValueCalculator 的实现类之间不再有直接联系,但是C# 要求在接口实例化时需要指定其实现类。这很自然,因为它需要知道用户想用的是哪一个实现类。这意味着,Home 控制器在创建 LinqValueCalculatoe 对象时仍有问题。
...
public ActionResult Index(){
IValueCalculator calc = new LinqValueCalculator();
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalcularProductTotal();
return View(totalValue);
}
...
使用 Ninject 的目的就是要解决这一问题,用以对 IValueCalculator 接口的实现进行实例化,但所需的实现细节却又不是 Home 控制器代码的一部分(即,通过 Ninject,可以去掉 Home 控制器中的这行黑体语句所示的代码,这项工作由 Ninject 完成,这样便去掉了 Home 控制器与总价计算器 LinqValueCalculator 之间的耦合)
2.2 将 Ninject 添加到 Visual Studio 项目
通过工具菜单找到 “管理解决方案的 NuGet 程序包”选项,添加 Ninject:


或者直接右击项目名,找到 “管理 NuGet 程序包” 选项也可以添加 Ninject

2.3 Ninject 初步
为了得到 Ninject 的基本功能,要做的工作有三个步骤。给 Index 动作方法添加基本的 Ninject 功能代码如下:
using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace EssentiaTools.Controllers
{
public class HomeController : Controller
{
private Product[] products = {
new Product{Name="Kayak",Catogory="Watersports",Price=275M},
new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M},
new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
};
public ActionResult Index()
{
//第一步,准备使用 Ninject,创建一个 Ninject 内核的实例。
//这是一个对象,它与Ninject 进行通信,并请求接口的实现。
IKernel ninjectKernel = new StandardKernel(); //第二步,建立应用程序中的接口和想要使用的实现类之间的关系
//Ninject 使用C# 的类型参数创建了一种关系:
//将想要使用的接口为 Bind 方法的类型参数,并在其返回的结果上调用To 方法。
//将希望实例化的实现类设置为 To 方法的类型参数。
//该语句告诉 Ninject:
//当要求它实现 IValueCalculator 接口时,应当创建 LinqValueCalculator 类的新实例,以便对请求进行服务。
ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>(); //第三步,实际使用 Ninject,通过其 Get 方法完成这一工作。
//Get 方法所使用的类型参数告诉 Ninject ,用户感兴趣的是哪一个接口,
//而该方法的结果是刚才用 To 方法指定的实现类型的一个实例。
IValueCalculator calc = ninjectKernel.Get<IValueCalculator>();
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalcularProductTotal();
return View(totalValue);
}
}
}
2.4 建立MVC 依赖性注入
上面Index 动作方法所展示的三个步骤的结果是:在 Ninject 中已经建立了一些相关的知识,即使用哪一个实现类来完成对 IValueCalculator 接口的请求。但是,应用程序未做任何改进,因为 Home 控制器与 LinqValueCalculator 类仍然是紧耦合的。
创建依赖解析器
示例要做的第一个修改时创建一个自定义的依赖解析器。MVC 框架需要使用依赖解析器来创建类的实例,以便对请求进行服务。通过创建自定义解析器,保证每当要创建一个对象时,便使用 Ninject 。
在项目中添加新文件夹 Infrastructure ,并添加一个类文件 NinjectDependencyResolver.cs
using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace EssentiaTools.Infrastructure
{
public class NinjectDependencyResolver:IDependencyResolver
{
private IKernel kernel; public NinjectDependencyResolver() {
kernel = new StandardKernel();
AddBindings();
} public object GetService(Type serviceType) {
return kernel.TryGet(serviceType);
} public IEnumerable<object> GetServices(Type serviceType) {
return kernel.GetAll(serviceType);
} private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
} }
}
MVC 框架在需要一个类实例以便对一个传入的请求进行服务时,会调用GetService 或 GetServices 方法。依赖解析器要做的工作便是创建这一实例 —— 这是一项要通过 Ninject 的 TryGet 和 GetAll 方法来完成的任务。 TryGet 方法的工作方式类似于前面所用的Get 方法,但当没有合适的绑定时,它会返回 null ,而不是抛出异常。GetAll 方法支持对单一类型的多个绑定,当多个不同的服务提供器可用时,可以使用它。
上述依赖解析器类也是建立 Ninject 绑定的地方。在AddBindings 方法中,本例用Bind 和 To 方法建立了 IValueCalculator 接口和 LinqValueCalculator 类之间的关系。
注册依赖解析器
必须告诉 MVC 框架,用户希望使用自己的依赖解析器,此事可以通过修改 Global.asax 文件来完成。
using EssentiaTools.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing; namespace EssentiaTools
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); //通过这里添加的语句,能让 Ninject 来创建 MVC 框架所需的任何对象实例,
//这便将 DI 放到了这一示例应用程序中
DependencyResolver.SetResolver(new NinjectDependencyResolver()); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
}
}
重构 Home 控制器
最后一个步骤是重构 Home 控制器,以使它能够利用前面所建立的工具。
using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace EssentiaTools.Controllers
{
public class HomeController : Controller
{
private Product[] products = {
new Product{Name="Kayak",Catogory="Watersports",Price=275M},
new Product{Name="Lifejacket",Catogory="Watersports",Price=48.95M},
new Product{Name="Soccer ball",Catogory="Soccer",Price=19.50M},
new Product{Name="Corner flag",Catogory="Soccer",Price=34.95M}
}; private IValueCalculator calc; public HomeController(IValueCalculator calcParam)
{
calc = calcParam;
} public ActionResult Index()
{
ShoppingCart cart = new ShoppingCart(calc) { Products = products };
decimal totalValue = cart.CalcularProductTotal();
return View(totalValue);
}
}
}
所做的主要修改时添加了一个构造器,它接受 IValueCalculator 接口的实现。示例并未指定想要使用的是哪一个实现,而且已经添加了一个名为“calc”的实例变量,可以在整个控制器中用它来表示构造器所接收到的 IValueCalculator 。
所做的另一个修改时删除了任何关于 Ninject 或 LinqValueCalculator 类的代码 —— 最终打破了 HomeController 和 LinqValueCalculator 类之间的紧耦合。
运行结果和前例一样:

示例创建的是一个构造器注入示例,这是依赖性注入的一种形式。以下是运行示例应用程序,且 Internet Explorer 对应用程序的跟 URL 发送请求时所发生的情况。
(1)浏览器向 MVC 框架发送一个请求 Home 的URL, MVC 框架猜出该请求意指 Home 控制器,于是会创建 HomeController 类实例。
(2)MVC 框架在创建 HomeController 类实例过程中会发现其构造器有一个对 IValueCalculator 接口的依赖项,于是会要求依赖性解析器对此依赖项进行解析,将该接口指定为依赖性解析器中 GetService 方法所使用的类型参数。
(3)依赖项解析器会将传递过来的类型参数交给 TryGet 方法,要求 Ninject 创建一个新的 IValueCalculator 接口类实例。
(4)Ninject 会检测到该接口与其实现类 LinqValueCalculator 具有绑定关系,于是为该接口创建一个 LinqValueCalculator 类实例,并将其回递给依赖性解析器。
(5)依赖性解析器将 Ninject 所返回的 LinqValueCalculator 类作为 IValueCalculator 接口实现类实例回递给 MVC 框架。
(6)MVC 框架利用依赖性解析器返回的接口类实例创建 HomeController 控制器实例,并使用控制器实例度请求进行服务。
这里所采取的办法其好处之一是,任何控制器都可以在其构造器中声明一个 IValueCalculator ,并通过自定义依赖性解析器使用 Ninject 来创建一个在 AddBindings 方法中指定的实现实例。
所得到的最大好处是,在希望用另一个实现来替代 LinqValueCalculator 时,只需要对依赖性解析器类进行修改,因为为了满足对于 IValueCalculator 接口的请求,这里是唯一一处为该接口指定实现类的地方。
创建依赖性链
当要求 Ninject 创建一个类型时,它会检查该类型与其他类型之间的耦合。如果有额外的依赖性, Ninject 会自动地解析这些依赖性,并创建所需要的所有类型实例。
在 Models 文件夹下新建文件 Discount.cs ,并定义了一个新的接口及其实现类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public interface IDiscountHelper
{
//将一个折扣运用于一个十进制的值
decimal ApplyDiscount(decimal totalParam);
} public class DefaultDiscountHelper : IDiscountHelper
{
//实现接口 IDiscountHelper,并运用固定的10% 折扣
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (10m / 100m * totalParam));
}
}
}
然后在 LinqValueCalculator 类中添加一个依赖性,修改 LinqValueCalculator 类,以使它执行计算时使用 IDiscountHelper 接口:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web; namespace EssentiaTools.Models
{
public class LinqValueCalculator : IValueCalculator
{
private IDiscountHelper discounter; public LinqValueCalculator(IDiscountHelper discountParam)
{
discounter = discountParam;
}
public decimal ValueProducts(IEnumerable<Product> products)
{
return discounter.ApplyDiscount(products.Sum(p => p.Price));
}
}
}
新添加的构造器以 IDiscountHelper 的接口实现为参数,然后将其用于 ValueProducts 方法,以便对所处理的 Products 对象的累计值运用一个折扣。
就像对 IValueCalculator 所做的那样,在 NinjectDependencyResolver 类中,用 Ninject 内核将 IDiscountHelper 接口与其实现类进行了绑定,将另一个接口绑定到它的实现:
using EssentiaTools.Models;
using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace EssentiaTools.Infrastructure
{
public class NinjectDependencyResolver:IDependencyResolver
{
private IKernel kernel; public NinjectDependencyResolver() {
kernel = new StandardKernel();
AddBindings();
} public object GetService(Type serviceType) {
return kernel.TryGet(serviceType);
} public IEnumerable<object> GetServices(Type serviceType) {
return kernel.GetAll(serviceType);
} private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>();
} }
}
上述这一做法已经创建了一个 Ninject 可以轻松解析的依赖性链,这是通过在自定义依赖性解析器中所定义的绑定实现的。为了满足对 HomeController 类的请求,Ninject 会意识到它需要创建一个用于 IValueCalculator 类的实现,通过考察其绑定,便会看出该接口的实现策略是使用 LinqValueCalculator 类。但在创建 LinqValueCalculator 对象过程, Ninject 又会意识到它需要使用 IDiscountHelper 接口实现,因此会查看其绑定,并创建一个 DefaultDiscountHelper 对象。 Ninject 会创建这一 DefaultDiscountHelper ,并将其传递给 LinqValueCalculator 对象的构造器, LinqValueCalculator 对象又转而被传递给 HomeController 类的构造器,最后所得到的 HomeController 用于对用户的请求进行服务。 Ninject 会以这种方式检查它要实例化的每一个依赖性类,无论其依赖性链有多长,多复杂。
2.5 指定属性与构造器参数值
在把接口绑定到它的实现时,可以提供想要运用到属性上的一些属性细节,以便对 Ninject 创建的类进行配置。修改 DefaultDiscountHelper 类,以使它定义一个 DiscountSize属性,该属性用于计算折扣量:
public class DefaultDiscountHelper : IDiscountHelper
{
public decimal DiscountSize { get; set; }
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (DiscountSize / 100m * totalParam));
}
}
在用 Ninject 将具体类绑定到类型时,可以使用 WithPropertyValue 方法来设置 DefaultDiscountHelper 类中的 DiscountSize 属性的值。
...
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize",50M);
}
...
注意,必须提供一个字符串值作为要设置的属性名。既不需要修改任何绑定,也不需要修改使用 Get 方法获取 ShoppingCart 类实例的方式。
该属性值会按照 DefaultDiscountHelper 的构造进行设置,并起到半价的效果。显示结果如下:

如果需要设置多个属性值,可以链接调用 WithPropertyValue 方法涵盖所有这些属性,也可以用构造器参数做同样的事情。可以重写 DefaultDiscountHelper 类如下,以便折扣大小作为构造器参数进行传递。
public class DefaultDiscountHelper : IDiscountHelper
{
public decimal discountSize; public DefaultDiscountHelper(decimal discountParam)
{
discountSize = discountParam;
}
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (discountSize / 100m * totalParam));
}
}
为了用 Ninject 绑定这个类,可以在 AddBindings 方法中使用 WithConstructorArgument 方法来指定构造器参数的值:
...
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam",50M);
}
...
这一技术允许用户将一个值注入到构造器中。同样,可以将这些方法调用链接在一起,以提供多值,并与依赖性混合和匹配。 Ninject 会判断出用户的需要,并依此来创建它。
2.6 使用条件绑定
Ninject 支持多个条件的绑定方法,这能够指定用哪一个类对某一特定的请求进行响应。
在 Models 文件夹下新建类文件 FlexibleDiscountHelper.cs :
namespace EssentiaTools.Models
{
public class FlexibleDiscountHelper : IDiscountHelper
{ public decimal ApplyDiscount(decimal totalParam)
{
decimal discount = totalParam > ? : ;
return (totalParam - (discount / 100M * totalParam));
}
}
}
FlexibleDiscountHelper 类根据要打折的总额大小运用不同的折扣,然后修改 NinjectDependencyResolver 的 AddBindings 方法,以告诉 Ninject 何时使用 FlexibleDiscountHelper ,何时使用 DefaultDiscountHelper:
...
private void AddBindings()
{
kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam",50M);
kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();
}
...
上述绑定指明,在 Ninejct 要将一个实现注入LinqValueCalculator 对象时,应该使用 FlexibleDiscountHelper 类作为 IDiscountHelper 接口的实现。
本例在适当的位置留下了对 IDiscountHelper 的原有绑定。 Ninject 会尝试找出最佳匹配,而且这有助于对同一类或接口采用一个默认绑定,以便在条件判据不能得到满足时,让 Ninject 能够进行回滚。 Ninject 有许多不同的条件绑定方法,最有用的一些条件绑定如下:

源码地址:https://github.com/YeXiaoChao/EssentiaTools
【MVC 4】3.MVC 基本工具(创建示例项目、使用 Ninject)的更多相关文章
- 学习ASP.NET MVC(九)——“Code First Migrations ”工具使用示例
在上一篇文章中,我们学习了如何使用实体框架的“Code First Migrations ”工具,使用其中的“迁移”功能对模型类进行一些修改,同时同步更新对应数据库的表结构. 在本文章中,我们将使用“ ...
- 使用IDEA工具创建本地项目并且上传到码云
需要条件: 1.码云/Github建好的git项目 2.IDEA编辑器 3.本地项目 步骤1:创建远程项目 步骤2:复制远程项目地址 注意:此处码云官方已经给出上传项目方法,不过用的是命令行的形式, ...
- Android SDK上手指南:示例项目
Android SDK上手指南:示例项目 2013-12-26 15:40 核子可乐译 51CTO 字号:T | T Android SDK示例项目中的应用能够执行种种功能,例如各类用户界面元素.数据 ...
- 【Asp.net入门3-01】使用jQuery-创建示例项目
过去,浏览器除了显示HTML外,很少具有其他功能.因此,早期的Web应用程序需要依赖服务 器端代码来响应用户交互并执行数据操作.Web应用程序的交互依赖HTML表单元素和浏览器向服务 器发送数据的功能 ...
- IDEA创建Maven项目显示一直加载中的问题
使用IDEA这款工具创建Maven项目的时候出现过下面这种情况: 红色区域即maven骨架加载不出来... 或 loading loading loading ... 有时候需要很长一段时间才能加载出 ...
- Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四)
Vue.js+vue-element搭建属于自己的后台管理模板:创建一个项目(四) 前言 本章主要讲解通过Vue CLI 脚手架构建工具创建一个项目,在学习Vue CLI之前我们需要先了解下webpa ...
- ABP示例程序-使用AngularJs,ASP.NET MVC,Web API和EntityFramework创建N层的单页面Web应用
本片文章翻译自ABP在CodeProject上的一个简单示例程序,网站上的程序是用ABP之前的版本创建的,模板创建界面及工程文档有所改变,本文基于最新的模板创建.通过这个简单的示例可以对ABP有个更深 ...
- ASP.NET MVC 5 03 - 安装MVC5并创建第一个应用程序
不知不觉 又逢年底, 穷的钞票 所剩无几. 朋友圈里 各种装逼, 抹抹眼泪 MVC 继续走起.. 本系列纯属学习笔记,如果哪里有错误或遗漏的地方,希望大家高调指出,当然,我肯定不会低调改正的.(开个小 ...
- (转)ASP.NET Mvc 2.0 - 1. Areas的创建与执行
转自:http://www.cnblogs.com/terrysun/archive/2010/04/13/1711218.html ASP.NET Mvc 2.0 - 1. Areas的创建与执行 ...
随机推荐
- JavaScript常用代码
页面的按钮全选: function CheckBoxAll() { //得到页面上所有input表单元素:document.getElementsByTagName( ...
- ThinkPHP去掉URL中的index.php
我的环境是apache+ubuntu 1,先确认你有没mod_rewrite.so模块 /usr/lib/apache2/modules/mod_rewrite.so 然后在httpd.conf最后一 ...
- $(document).ready()即$()方法和window.onload方法的比较
以浏览器装载文档为例,我们都知道在页面完毕后,浏览器会通过JavaScript为DOM元素添加事件.在常规的JavaScript代码中,通常使用window.onload方法,而在jQuery中,使用 ...
- mysql并发insert deadlock分析以及解决,无delete/update/for update
关于并发insert操作发生deadlock这个情况,一直有很多争议,而且网上的帖子所有的例证和模拟其实不一定反映了真实的情况,例如:https://www.percona.com/blog/2012 ...
- ALV常用参数详细描述
调用功能模块: CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY' EXPORTING i_interface_check = '' ...
- CRM2013版本 IOS APP 说明(IPhone、IPad)
CRM2013版本 IOS APP 说明(IPhone.IPad) IPhone版本 首页 CRM APP在登录时输入账号信息,可以进行首面.其首页显示内容可以在CRM后台设置. 系统默认显示:Pho ...
- Snort - manual 笔记(三)
1.6 Reading pcap files Snort 不仅可以监听interface, 还可以读取和分析已经捕获的数据包. 1.6.1 Command line arguments 下面的命令都可 ...
- 实验12:Problem C: 重载字符的加减法
Home Web Board ProblemSet Standing Status Statistics Problem C: 重载字符的加减法 Problem C: 重载字符的加减法 Time ...
- 用Gradle构建时,将密码等敏感信息放在build.gradle之外
密码 在做版本release时你app的 build.gradle你需要定义 signingConfigs.此时你应该避免以下内容: 不要做这个 . 这会出现在版本控制中. signingConfig ...
- OC正则表达式的使用
OC中一般正则表达式的使用方法为2步 1.创建一个正则表达式对象 2.利用正则表达式来测试对应的字符串 例如 NSString *checkString = @"a34sd231" ...