一、需求

我们在开发中经常会遇到一些枚举,而且这些枚举类型可能会在表单中的下拉中,或者单选按钮中会用到等。

这样用是没问题的,但是用过的人都知道一个问题,就是枚举的命名问题,当然有很多人枚举直接中文命名,我是不推荐这种命名规则,因为实在不够友好。

那有没有可以不用中文命名,而且可以显示中文的方法呢。答案是肯定的。

二、特性解决枚举命名问题

那就是用特性解决命名问题,这样的话既可以枚举用英文命名,显示又可以是中文的,岂不两全其美。

/// <summary>
/// 性别
/// </summary>
public enum Gender
{
/// <summary>
/// 女性
/// </summary>
[Description("女性")]
Female = , /// <summary>
/// 男性
/// </summary>
[Description("男性")]
Male = , /// <summary>
/// 未知
/// </summary>
[Description("未知")]
Unknown = , /// <summary>
/// 人妖
/// </summary>
[Description("人妖")]
Demon =
}

1、新建枚举的特性类

首先我们需要新建枚举的特性,用来描述枚举,这样既可以解决枚举的命名问题,又可以解决枚举的显示问题。

我们在下拉框或者单选按钮上显示各个枚举项,可能会出现一些排序问题,所以在枚举的特性上不仅有显示的名称还有排序。

  /// <summary>
/// 枚举特性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class DescriptionAttribute : Attribute
{
/// <summary>
/// 排序
/// </summary>
public int Order { get; set; } /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 显示自定义描述名称
/// </summary>
/// <param name="name">名称</param>
public DescriptionAttribute(string name)
{
Name = name;
} /// <summary>
/// 显示自定义名称
/// </summary>
/// <param name="name">名称</param>
/// <param name="order">排序</param>
public DescriptionAttribute(string name, int order)
{
Name = name;
Order = order;
} }

新建好枚举的特性类以后,我们就可以在枚举的字段上添加自定义的特性Description

/// <summary>
/// 性别
/// </summary>
public enum Gender
{
/// <summary>
/// 女性
/// </summary>
[Description("女性", )]
Female = , /// <summary>
/// 男性
/// </summary>
[Description("男性", )]
Male = , /// <summary>
/// 未知
/// </summary>
[Description("未知", )]
Unknown = , /// <summary>
/// 人妖
/// </summary>
[Description("人妖", )]
Demon =
}

特性第一个参数为名称,第二个为排序(int 类型,正序),这就是就是我们新建枚举时在需要显示和枚举名称不一样的枚举字段上添加即可。这个Gender枚举,在后面文章中会一直用到(Gender)。

2、新建枚举扩展方法获取枚举特性的描述

我们前面的工作已经把特性和在枚举上添加特性已经完成了,后面我们需要的就是要获取我们添加的描述和排序。

/// <summary>
/// 枚举帮助类
/// </summary>
public static class EnumTools
{ /// <summary>
/// 获取当前枚举值的描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string GetDescription(this Enum value)
{
int order;
return GetDescription(value, out order);
} /// <summary>
/// 获取当前枚举值的描述和排序
/// </summary>
/// <param name="value"></param>
/// <param name="order"></param>
/// <returns></returns>
public static string GetDescription(this Enum value, out int order)
{
string description = string.Empty; Type type = value.GetType(); // 获取枚举
FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttribute
object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = ;
description = fieldInfo.Name; if (attr != null)
{
order = attr.Order;
description = attr.Name;
}
return description; } }

3、获取枚举描述和排序

至此:我们可以很容易获取到枚举添加的特性描述和排序。

var des = Gender.Male.GetDescription();
// des = “男性” var name = Gender.Male.ToString();
// name= "Male" var key = (int)Gender.Male;
// key = 2 int order;
var des1 = Gender.Female.GetDescription(out order);
// des1 = “女性”, order= 2

这样我们就很好的解决了枚举命名问题, 可以很容易的获取到枚举的描述信息,也就是要显示的信息。但是我们需要的是一次性可以查询全部的枚举信息,以便我们进行显示。

三、获取所有枚举的描述和值,以便循环使用

我们已经可以很容易的获取到枚举的值,名称和描述了,所以后面的就很简单了。

/// <summary>
/// 枚举帮助类
/// </summary>
public static class EnumTools
{ /// <summary>
/// 获取当前枚举的所有描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static List<KeyValuePair<int, string>> GetAll<T>()
{
return GetAll(typeof(T));
} /// <summary>
/// 获取所有的枚举描述和值
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static List<KeyValuePair<int, string>> GetAll(Type type)
{ List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fields
foreach (var field in type.GetFields())
{
// 如果是枚举类型
if (field.FieldType.IsEnum)
{
object tmp = field.GetValue(null);
Enum enumValue = (Enum)tmp;
int intValue = Convert.ToInt32(enumValue);
int order;
string showName = enumValue.GetDescription(out order); // 获取描述和排序
list.Add(new EnumToolsModel { Key = intValue, Name = showName, Order = order });
}
} // 排序并转成KeyValue返回
return list.OrderBy(i => i.Order).Select(i => new KeyValuePair<int, string>(i.Key, i.Name)).ToList(); }
}

调用:这样我们就很容易的获取枚举所有字段的描述,如我们需要在cshtml中调用

<select class="form-control">
@{ var genders = EnumTools.GetAll<Gender>();} // 或者EnumTools.GetAll<>(Typeof(Gender))
@foreach (var item in genders)
{
<option value="@item.Key">
@item.Value
</option>
}
</select>

生成的html为:

<select class="form-control">
<option value="2">男性</option>
<option value="1">女性</option>
<option value="3">未知</option>
<option value="4">人妖</option>
</select>

这样我们就已顺利的解决了枚举的命名以及排序显示等问题。

四、枚举特性扩展至HtmlHelper

我们已经解决了枚举的命名以及排序显示问题,但是我们想做的更好,比如每次都要写一个foreach获取所有的枚举然后在判断默认值和哪个相等,循环遍历,周而复始,重复造轮子,bad code。所以我们要进行封装,封装成与 @Html.DropDownList一样好用的HtmlHelper扩展。

/// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), int.MaxValue, htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, int selectedValue, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), selectedValue, htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, T selectedValue, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), Convert.ToInt32(selectedValue), htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <param name="html"></param>
/// <param name="enumType">枚举类型</param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect(this HtmlHelper html, Type enumType, int selectedValue, object htmlAttributes = null)
{
// 创建标签
TagBuilder tag = new TagBuilder("select"); // 添加自定义标签
if (htmlAttributes != null)
{
RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
tag.MergeAttributes(htmlAttr);
}
// 创建option集合
StringBuilder options = new StringBuilder();
foreach (var item in GetAll(enumType))
{
// 创建option
TagBuilder option = new TagBuilder("option"); // 添加值
option.MergeAttribute("value", item.Key.ToString()); // 设置选择项
if (item.Key == selectedValue)
{
option.MergeAttribute("selected", "selected");
} // 设置option
option.SetInnerText(item.Value);
options.Append(option.ToString());
}
tag.InnerHtml = options.ToString(); // 返回MVCHtmlString
return MvcHtmlString.Create(tag.ToString()); }

然后调用

@(Html.EnumToolsSelect<Gender>())
@(Html.EnumToolsSelect<Gender>(Gender.Unknown))
@(Html.EnumToolsSelect<Gender>())
@(Html.EnumToolsSelect<Gender>(Gender.Female, new { @class = "form-control" }))
@(Html.EnumToolsSelect(typeof(Gender), )

这样就可以生成你所需要的下拉框的html,一行代码就可以解决复杂的枚举下拉。

你以为就这样结束了吗,很明显没有,因为不是我风格,我的风格是继续封装。

五、枚举特性扩展至HtmlHelper Model

这个可能有很多不会陌生,因为很多HtmlHelper都有一个For结尾的,如@Html.DropDownListFor等等,那我们也要有For结尾的,要不然都跟不上潮流了。

关于For的一些扩展和没有For的扩展的区别,简单来说带For就是和Model一起用的,如:@Html.TextBoxFor(i => i.Name)

这样就可以更加一步的封装,如Id,name,model的Name值以及验证等等。

话不多说,直接代码

/// <summary>
/// 下拉枚举
/// </summary>
/// <typeparam name="TModel">Model</typeparam>
/// <typeparam name="TProperty">属性</typeparam>
/// <param name="htmlHelper"></param>
/// <param name="expression"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
{
// 获取元数据meta
ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); Type enumType = modelMetadata.ModelType; // 设置id name的属性值
var rvd = new RouteValueDictionary
{
{ "id", modelMetadata.PropertyName },
{ "name", modelMetadata.PropertyName }
}; // 添加自定义属性
if (htmlAttributes != null)
{
RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
foreach (var item in htmlAttr)
{
rvd.Add(item.Key, item.Value);
}
} // 获取验证信息
IDictionary<string, object> validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(modelMetadata.PropertyName, modelMetadata); // 添加至自定义属性
if (validationAttributes != null)
{
foreach (var item in validationAttributes)
{
rvd.Add(item.Key, item.Value);
}
}
return htmlHelper.EnumToolsSelect(enumType, Convert.ToInt32(modelMetadata.Model), rvd);
}

关于使用:

首先我们需要返回view时需要返回Model

public class HomeController : Controller
{
public ActionResult Index()
{
return View(new Person { Age = , Name = "Emrys", Gender = Gender.Male });
} } public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Gender Gender { get; set; }
}

cshtm调用

@Html.EnumToolsSelectFor(i => i.Gender)

生成html代码

<select data-val="true" data-val-required="Gender 字段是必需的。" id="Gender" name="Gender">
<option selected="selected" value="2">男性</option>
<option value="1">女性</option>
<option value="3">未知</option>
<option value="4">人妖</option>
</select>

六、全部枚举特性和HtmlHelper代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing; namespace Emrys.EnumTools
{ /// <summary>
/// 枚举帮助类
/// </summary>
public static class EnumTools
{ /// <summary>
/// 获取当前枚举值的描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string GetDescription(this Enum value)
{
int order;
return GetDescription(value, out order);
} /// <summary>
/// 获取当前枚举值的描述和排序
/// </summary>
/// <param name="value"></param>
/// <param name="order"></param>
/// <returns></returns>
public static string GetDescription(this Enum value, out int order)
{
string description = string.Empty; Type type = value.GetType(); // 获取枚举
FieldInfo fieldInfo = type.GetField(value.ToString()); // 获取枚举自定义的特性DescriptionAttribute
object[] attrs = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
DescriptionAttribute attr = (DescriptionAttribute)attrs.FirstOrDefault(a => a is DescriptionAttribute); order = ;
description = fieldInfo.Name; if (attr != null)
{
order = attr.Order;
description = attr.Name;
}
return description; } /// <summary>
/// 获取当前枚举的所有描述
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static List<KeyValuePair<int, string>> GetAll<T>()
{
return GetAll(typeof(T));
} /// <summary>
/// 获取所有的枚举描述和值
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static List<KeyValuePair<int, string>> GetAll(Type type)
{ List<EnumToolsModel> list = new List<EnumToolsModel>(); // 循环枚举获取所有的Fields
foreach (var field in type.GetFields())
{
// 如果是枚举类型
if (field.FieldType.IsEnum)
{
object tmp = field.GetValue(null);
Enum enumValue = (Enum)tmp;
int intValue = Convert.ToInt32(enumValue);
int order;
string showName = enumValue.GetDescription(out order); // 获取描述和排序
list.Add(new EnumToolsModel { Key = intValue, Name = showName, Order = order });
}
} // 排序并转成KeyValue返回
return list.OrderBy(i => i.Order).Select(i => new KeyValuePair<int, string>(i.Key, i.Name)).ToList(); } /// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), int.MaxValue, htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, int selectedValue, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), selectedValue, htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="html"></param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect<T>(this HtmlHelper html, T selectedValue, object htmlAttributes = null)
{
return html.EnumToolsSelect(typeof(T), Convert.ToInt32(selectedValue), htmlAttributes);
} /// <summary>
/// 枚举下拉
/// </summary>
/// <param name="html"></param>
/// <param name="enumType">枚举类型</param>
/// <param name="selectedValue">选择项</param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelect(this HtmlHelper html, Type enumType, int selectedValue, object htmlAttributes = null)
{
// 创建标签
TagBuilder tag = new TagBuilder("select"); // 添加自定义标签
if (htmlAttributes != null)
{
RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
tag.MergeAttributes(htmlAttr);
}
// 创建option集合
StringBuilder options = new StringBuilder();
foreach (var item in GetAll(enumType))
{
// 创建option
TagBuilder option = new TagBuilder("option"); // 添加值
option.MergeAttribute("value", item.Key.ToString()); // 设置选择项
if (item.Key == selectedValue)
{
option.MergeAttribute("selected", "selected");
} // 设置option
option.SetInnerText(item.Value);
options.Append(option.ToString());
}
tag.InnerHtml = options.ToString(); // 返回MVCHtmlString
return MvcHtmlString.Create(tag.ToString()); }
/// <summary>
/// 下拉枚举
/// </summary>
/// <typeparam name="TModel">Model</typeparam>
/// <typeparam name="TProperty">属性</typeparam>
/// <param name="htmlHelper"></param>
/// <param name="expression"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString EnumToolsSelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
{
// 获取元数据meta
ModelMetadata modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); Type enumType = modelMetadata.ModelType; // 设置id name的属性值
var rvd = new RouteValueDictionary
{
{ "id", modelMetadata.PropertyName },
{ "name", modelMetadata.PropertyName }
}; // 添加自定义属性
if (htmlAttributes != null)
{
RouteValueDictionary htmlAttr = htmlAttributes as RouteValueDictionary ?? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
foreach (var item in htmlAttr)
{
rvd.Add(item.Key, item.Value);
}
} // 获取验证信息
IDictionary<string, object> validationAttributes = htmlHelper.GetUnobtrusiveValidationAttributes(modelMetadata.PropertyName, modelMetadata); // 添加至自定义属性
if (validationAttributes != null)
{
foreach (var item in validationAttributes)
{
rvd.Add(item.Key, item.Value);
}
}
return htmlHelper.EnumToolsSelect(enumType, Convert.ToInt32(modelMetadata.Model), rvd);
}
} /// <summary>
/// 枚举特性
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class DescriptionAttribute : Attribute
{
/// <summary>
/// 排序
/// </summary>
public int Order { get; set; } /// <summary>
/// 名称
/// </summary>
public string Name { get; set; } /// <summary>
/// 显示自定义描述名称
/// </summary>
/// <param name="name">名称</param>
public DescriptionAttribute(string name)
{
Name = name;
} /// <summary>
/// 显示自定义名称
/// </summary>
/// <param name="name">名称</param>
/// <param name="order">排序</param>
public DescriptionAttribute(string name, int order)
{
Name = name;
Order = order;
} } /// <summary>
/// 枚举Model
/// </summary>
partial class EnumToolsModel
{
public int Order { get; set; }
public string Name { get; set; }
public int Key { get; set; }
}
}

最后望对各位有所帮助,本文原创,欢迎拍砖和推荐。

Github:https://github.com/Emrys5/Asp.MVC-03-Enum-rename-htmlhelper

系列课程

[asp.net mvc 奇淫巧技] 03 - 枚举特性扩展解决枚举命名问题和支持HtmlHelper的更多相关文章

  1. [asp.net mvc 奇淫巧技] 01 - 封装上下文 - 在View中获取自定义的上下文

    我们在asp.net 开发中已经封装了最强大的HttpContext,我们可以在HttpContext中可以获取到几乎任何想获取的东西,也可以在HttpContext写入需要返回客户端的信息.但是这些 ...

  2. [asp.net mvc 奇淫巧技] 02 - 巧用Razor引擎在Action内生成Html代码

    在web开发中经常会遇到在内部代码中获取Html,这些Html是需要和数据进行一起渲染.并不是直接把Html代码返回给客户端.这样的做法有很多应用场景,例如分页.Ajax一次性获取几段Html片段.生 ...

  3. [asp.net mvc 奇淫巧技] 04 - 你真的会用Action的模型绑定吗?

    在QQ群或者一些程序的交流平台,经常会有人问:我怎么传一个数组在Action中接收.我传的数组为什么Action的model中接收不到.或者我在ajax的data中设置了一些数组,为什么后台还是接收不 ...

  4. [asp.net mvc 奇淫巧技] 05 - 扩展ScriptBundle,支持混淆加密javascript

    一.需求: 在web开发中,经常会处理javascript的一些问题,其中就包括js的压缩,合并,发布版本以及混淆加密等等问题.在asp.net 开发中我们使用ScriptBundle已经可以解决ja ...

  5. [asp.net mvc 奇淫巧技] 06 - 也许你的项目同一个用户的请求都是同步的

    一.感慨 很久前看到一篇博客中有句话大致的意思是:“asp.net 程序性能低下的主要原因是开发人员技术参差不齐”,当时看到这句话不以为然,然而时间过的越久接触的.net 开发人员越多就越认同这句话: ...

  6. ASP.NET Core 奇淫技巧之伪属性注入

    一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上.还好当我度过了所谓的本命年后,许多事情都在慢慢变 ...

  7. [javascript 实践篇]——那些你不知道的“奇淫巧技”

    1. 空(null, undefined)验证 刚开始,我是比较蠢的验证(我还真是这样子验证的) if (variable1 !== null || variable1 !== undefined | ...

  8. Asp.net MVC的Model Binder工作流程以及扩展方法(2) - Binder Attribute

    上篇文章中分析了Custom Binder的弊端: 由于Custom Binder是和具体的类型相关,比如指定类型A由我们的Custom Binder解析,那么导致系统运行中的所有Action的访问参 ...

  9. ASP.NET MVC中对Model进行分步验证的解决方法

    原文:ASP.NET MVC中对Model进行分步验证的解决方法 在我之前的文章:ASP.NET MVC2.0结合WF4.0实现用户多步注册流程中将一个用户的注册分成了四步,而这四个步骤都是在完善一个 ...

随机推荐

  1. 海康/大华 IpCamera RTSP地址和格式

    海康:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream说明:username: 用户名.例如 ...

  2. Linux - atexit()(注册终止)函数

    进程终⽌的⽅式有8种,前5种为正常终⽌,后三种为异常终⽌: 1. 从main函数返回: 2 .调⽤exit函数:3 .调⽤_exit或_Exit:4 .最后⼀个线程从启动例程返回:5 .最后⼀个线程调 ...

  3. Linux下修改环境终端提示符

    Linux修改环境变量PS1(命令行提示符),可以使用vi编辑/etc/bashrc或/etc/profile文件,在最后加上: export PS1='[\u@\h \W]\$ ' 即可,其中\u显 ...

  4. 修改linux系统时间和同步

    date 查看当前时间 date -s 15:14:13 修改时间 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 修改时区 yes cront ...

  5. 使用Docker

    1. 使用镜像 1.1 在Docker Hub上查找镜像 我们查找一下之前博客里面,推送到Docker Hub里面的bage88/docker-demo,能看到有2个仓库,第一个就是我们上次上传的镜像 ...

  6. Vim安装YouCompletMe插件。

    1.Centos7.0自带含有支持python2.x的vim.(:version 后看python+则支持,python-则不支持)若不支持,卸载vim后源码编译安装. yum install pyt ...

  7. ELK菜鸟手记 (三) - X-Pack权限控制之给Kibana加上登录控制以及index_not_found_exception问题解决

    0. 背景 我们在使用ELK进行日志记录的时候,通过网址在Kibana中查看我们的应用程序(eg: Java Web)记录的日志, 但是默认是任何客户端都可以访问Kibana的, 这样就会造成很不安全 ...

  8. [CTSC2008] 网络管理

    题目描述 Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构 ...

  9. Transform java future into completable future 【将 future 转成 completable future】

    Future is introduced in JDK 1.5 by Doug Lea to represent "the result of an asynchronous computa ...

  10. Windows上Ruby开发环境的配置

    最近公司项目上有需要,需要开发一个puppet的自动化工具,这个工具需要操作存储设备上的各种资源,而鉴于puppet不是善于完成这个任务的首选语言,于是我们选择了puppet的“爹”,Ruby. 熟悉 ...