zoukankan      html  css  js  c++  java
  • Asp.Net Mvc 自定义扩展

    目录:

    1. 自定义模型IModelBinder
    2. 自定义模型验证
    3. 自定义视图引擎
    4. 自定义Html辅助方法
    5. 自定义Razor辅助方法
    6. 自定义Ajax辅助方法
    7. 自定义控制器扩展
    8. 自定义过滤器
    9. 自定义ActionResult

    自定义模型IModelBinder

    IModelBinder主要解决的问题是,将请求的数据转换成需要的数据这部分逻辑进行了封装。比如说 http://localhost:4742/Person/Person/2 请求的参数Id是2,通过参数2,获得2相关的所有数据。

    这样做的好处是:

    1. 使代码变得更加简洁
    2. 帮助我们获取HTTP请求中的数据
    3. 帮助我们完成必要的数据类型转换

    Controller部分:

    当访问http://localhost:4742/Person/Person?Name=admin&Age=12时,自动转换为setting对象

    [HttpPost]
        public ActionResult Person2([ModelBinder(typeof(SettingsBinder))]Settings settings)
        {       
            return View("Person");
        }

    IModelBinder部分

    SettingsBinder继承了IModelBinder,并实现了BindModel,通过controllerContext.HttpContext.Request获取请求,从请求中获取参数值,然后转换为对象

    public class SettingsBinder : IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            var request = controllerContext.HttpContext.Request;
            //  从request中获取参数值
            var name = request["Name"];
            var age = request["Age"];
            //  然后将参数值转为对象
            var setting = new { Name = name, Age = age };
            return setting;
        }
    }

    注:当Person2([ModelBinder(typeof(SettingsBinder))]Settings settings)已存在时,不能再定义Person2方法

    自定义验证

    通过定义自定义验证特性类,实现View的模型验证,NotEqualTo即自定义验证

    public class RegisterModel
        {
            [Required]
            [StringLength(6, MinimumLength = 2)] //
            [Display(Name = "用户名")]
            public string UserName { get; set; }
    
    
            [NotEqualTo("UserName", ErrorMessage = "不能与用户名的值相同")]
            public string OtherName { get; set; }
    
            //  NotEqualTo  是自定义模型验证特性
        }

    NotEqualToAttribute继承了ValidationAttribute和IClientValidatable ,并实现了IsValid和GetClientValidationRules方法

    通过NotEqualTo构造参数的值UserName,获得该对象对应该参数值的属性值,匹配属性的值和约束的值OtherName是否相等,然后返回结果信息

    using System.ComponentModel.DataAnnotations;
    using System.Globalization;
    using System.Web.Mvc;
    
    namespace MvcValidation.Extension
    {
        //  ValidationAttribute 验证特性
        //  IClientValidatable  客户端验证接口(View视图验证)
        public class NotEqualToAttribute : ValidationAttribute, IClientValidatable
        {
            public string OtherProperty { get; set; }
    
            //  构造参数
            public NotEqualToAttribute(string otherProperty)
            {
                OtherProperty = otherProperty;
            }
    
            //  验证方法
            protected override ValidationResult IsValid(object value, ValidationContext validationContext)
            {
                //从验证上下文中可以获取我们想要的的属性
                var property = validationContext.ObjectType.GetProperty(OtherProperty);
                if (property == null)
                {
                    return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "{0} 不存在", OtherProperty));
                }
    
                //获取属性的值
                var otherValue = property.GetValue(validationContext.ObjectInstance, null);
    
                //  判断并返回验证结果
                if (object.Equals(value, otherValue))
                {
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
                }
                return null;
            }
            //  客户端验证
            public System.Collections.Generic.IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
            {
                //  设置客户端验证结果信息
                var rule = new ModelClientValidationRule
                {
                    ValidationType = "notequalto",
                    ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
                };
                rule.ValidationParameters["other"] = OtherProperty;
                yield return rule;
            }
        }
    }


    自定义视图引擎

    系统提供了视图和视图引擎,我们需要了解它之后继承并重写它的逻辑。

    /*  
         *  思路
         *  1、控制器方法返回ActionResult是一个抽象类 
         *  2、ActionResult的其中一个子类ViewResult,正是她使用IView实例最终渲染出视图 
         *  3、需要自定义IView 
         *  4、IViewEngine管理着IView,同时也需要自定义IViewEngine
         *  5、自定义IViewEngine是需要全局注册的
         */
    //namespace System.Web.Mvc
    
        //public interface IView
        //{
        //  第一个参数ViewContext包含了需要被渲染的信息,被传递到前台的强类型Model也包含在其中。 
        //  第二个参数TextWriter可以帮助我们写出想要的html格式。
        //  void Render(ViewContext viewContent, TextWriter textWriter);
        //}
    //namespace System.Web.Mvc
        //public interface IViewEngine
        //{
        //    //  FindPartialView:在当前控制器上下文ControllerContext中找到部分视图。 
        //    System.Web.Mvc.ViewEngineResult FindPartialView(System.Web.Mvc.ControllerContext controllerContext, string partialViewName, bool useCache);
        //    //  FindView:在当前控制器上下文ControllerContext中找到视图。 
        //    System.Web.Mvc.ViewEngineResult FindView(System.Web.Mvc.ControllerContext controllerContext, string viewName, string masterName, bool useCache);
        //    //  ReleaseView:释放当前控制器上下文ControllerContext中的视图。
        //    void ReleaseView(System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.IView view);
        //}

    我们将派生出它们的类,通过自定义视图引擎类实现渲染,并显示。
    准备资源:

    public class Student
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Score { get; set; }
        }
    
        public class DataAccess
        {
            List<Student> students = new List<Student>();
    
            public DataAccess()
            {
                for (int i = 0; i < 10; i++)
                {
                    students.Add(new Student()
                    {
                        Id=i+1,
                        Name="Name"+Convert.ToString(i+1),
                        Score = i+80
                    });
                }
            }
    
            public List<Student> GetStudents()
            {
                return students;
            }
        }

    自定义扩展

    public class StudentView : IView
        {
            /// <summary>
            /// 渲染
            /// 通过获得视图上下文数据,然后自定义输出格式通过TextWriter输出数据
            /// </summary>
            /// <param name="viewContent"></param>
            /// <param name="writer"></param>
            public void Render(ViewContext viewContent, TextWriter writer)
            {
                //  从视图上下文ViewContext拿到model
                var model = viewContent.ViewData.Model;
                var students=model as List<Student>;
                //  自定义输出视图的html格式
                writer.Write("<table border=1><tr><th>编号</th><th>名称</th><th>分数</th></tr>");
                foreach (Student stu in students)
                {
                    writer.Write("<tr><td>" + stu.Id + "</td><td>" + stu.Name + "</td><td>" + stu.Score + "</td></tr>");
                }
                writer.Write("</table>");
            }
        }
    
        public class StudentViewEngine : IViewEngine
        {
            //呈现部分视图
            public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
            {
                throw new NotImplementedException();
            }
            //呈现视图
            public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
            {
                if (viewName == "StudentView")
                {
                    //  呈现自定义视图
                    return new ViewEngineResult(new StudentView(), this);
                }
                else
                {
                    return new ViewEngineResult(new string[] { "针对Student的视图还没创建!" });
                }
            }
            //显示视图
            public void ReleaseView(ControllerContext controllerContext, System.Web.Mvc.IView view)
            {
                
            }
        }

    至此自定义视图引擎完成。接下来我们进行调用:
    我们只需要在View中指定自定义视图的名称即可。

    public ActionResult Index()
            {
                var students = new DataAccess().GetStudents();
                ViewData.Model = students;
    
                return View("StudentView");
            }

    设置默认的,全局的视图引擎
    只需要添加ViewEngines.Engines.Add(new StudentViewEngine());即可实现。

    protected void Application_Start()
            {
                AreaRegistration.RegisterAllAreas();
    
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
    
    
                ViewEngines.Engines.Add(new StudentViewEngine());
            }

    自定义HtmlHelper辅助方法

    定义扩展方法类和扩展方法

    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    //  设置命名空间为统一的Html命名空间
    namespace System.Web.WebPages.Html
    {
        //  设置静态类
        public static class HtmlExtensions
        {
            //  为HtmlHelper类提辅助方法Img,参数为src和alt
            public static MvcHtmlString Img(this HtmlHelper html,string src,string alt)
            {
                return MvcHtmlString.Create("<img src="" + src + "" alt="" + alt + "" />");
            }
    } }

    在View页面中调用该扩展方法

    @* 调用Img方法,前者为src,后者为alt,生成的结果是:<img src="C:imagestn.ico" alt="" /> *@
    @Html.Img("C:\images\btn.ico","")

    自定义Razor辅助方法

    在MVC项目根目录下新建一个文件夹名为:App_Code,用于存放MyHelpers.cshtml

    编写MyHelpers.cshtml内容如下:

    相当于定义了MyHelpers.li(List<string> arrays)方法,通过关键字helper进行声明,这样其他的cshtml页面都可以访问该方法

    @helper li(List<string> arrays) { 
        <ul>
            @foreach (var item in arrays)
            {
                <li>@(item)</li>
            }
        </ul>
    }

    cshtml页面访问li方法

    Index.cshtml页面调用:

    @MyHelpers.li(new List<string>() { "甲","乙","丙","丁"})

    页面输出结果:

    自定义AjaxHelper辅助方法

    与HtmlHelper扩展一样,为AjaxHelper扩展一个方法Textbox,并设置相应的属性

    public static class HtmlExtensions
        {
            //  为HtmlHelper类提辅助方法Img,参数为src和alt
            public static MvcHtmlString Img(this HtmlHelper html, string src, string alt)
            {
                return MvcHtmlString.Create("<img src="" + src + "" alt="" + alt + "" />");
            }
    
            public static MvcHtmlString Textbox(this AjaxHelper ajaxHelper, string name,  AjaxOptions ajaxOptions, object htmlAttributes)
            {
                //  设置标签名
                var tag = new TagBuilder("input");
                //  设置属性值
                tag.MergeAttribute("name", name);
                tag.MergeAttribute("type", "text");
    
                tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
                tag.MergeAttributes((ajaxOptions ?? new AjaxOptions()).ToUnobtrusiveHtmlAttributes());
                tag.MergeAttribute("value", "自定义Ajax扩展");
                //  输出Html
                return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
            }
        }

    View调用:

    @Ajax.Textbox("search",
        new AjaxOptions
        {
            Url = @Url.Action("GetTime"),
            UpdateTargetId = "divTime",
            InsertionMode = InsertionMode.Replace
        },
    new { size = 50 })

    输出结果:
    输出结果的源码:

    <input data-ajax="true" data-ajax-mode="replace" data-ajax-update="#divTime" data-ajax-url="/AjaxHelperExt/GetTime" name="search" size="50" type="text" value="自定义Ajax扩展"></input>

    自定义UrlHelper辅助方法

    略.

    自定义控制器扩展BaseController

    //  BaseController  针对Controller进行重写
        //  并且提供了一些公用的方法如权限校验,Action跳转、日志记录等
        public class BaseController : Controller
        {
    
            protected override void OnException(ExceptionContext filterContext)
            {
                //  处理异常
                base.OnException(filterContext);
            }
    
            protected override void Initialize(RequestContext requestContext)
            {
                //  处理初始化信息,如Cookie,Session等缓存信息
                base.Initialize(requestContext);
            }
    
            protected override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                //  在调用操作方法前调用
                base.OnActionExecuting(filterContext);
            }
    
            protected override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                //  在调用操作方法后调用
                base.OnActionExecuted(filterContext);
            }
    
            
        }

    自定义过滤器

    原文

    路由访问过滤器

    /// <summary>
        /// 路由访问过滤器
        /// </summary>
        public class SystemIActionFilter : IActionFilter
        {
            //  
            // Summary:  
            //     Called after the action method is invoked.  
            //      在Action返回之后  
            // Parameters:  
            //   filterContext:  
            //     Information about the current request and action.  
            public void OnActionExecuted(ActionExecutedContext filterContext)
            {
            }
            //  
            // Summary:  
            //     Called before the action method is invoked.  
            //      在进入Action之前  
            //      说明:使用RedirectToRouteResult进行路由值进行重定向时  
            //      RouteName 路由名称   
            //      RouteValues 路由值  特别注意第三个值 Permanent 获取一个值  
            //      该值指示重定向是否应为永久重定向 如果为true 在本程序会出现问题  
            // Parameters:  
            //   filterContext:  
            //     Information about the current request and action.  
            public void OnActionExecuting(ActionExecutingContext filterContext)
            {
                //验证 控制器 视图   
                string tempAction = filterContext.RouteData.Values["action"].ToString();
                string tempController = filterContext.RouteData.Values["controller"].ToString();
                string tempLoginAction = filterContext.RouteData.Values["action"].ToString();
    
                if (tempAction == "HomeLogin" && tempController == "Home" || tempLoginAction == "UserLogin" ? false : true)
                {
                    //请求登录时  
                    if (tempAction == "UserLogin" && tempController == "Home" ? false : true)
                    {
                        //Cookie  
                        HttpCookie tempToken = filterContext.HttpContext.Request.Cookies["exclusiveuser_token"];
                        if (tempToken == null)
                        {
                            filterContext.Result = new RedirectToRouteResult("HomeLogin", new RouteValueDictionary(new { controller = "Home", action = "HomeLogin" }), false);
                        }
                        //登录token不为null时  进行合法性验证token 头部,载荷,签名,cookie过期时间  
                        if (tempToken == null ? false : true)
                        {
                            //UserToken 方法 将验证 token 合法性 包括token 签名 ,token载荷,cookie 过期时间等  
                            //string SystemToken = new SecondTrackToken().UserToken();
                            //if (SystemToken == null)
                            //{
                            //    filterContext.Result = new RedirectToRouteResult("HomeLogin", new RouteValueDictionary(new { controller = "Home", action = "HomeLogin" }), false);
                            //};
                        }
                    }
                }
            }
        }
    路由访问过滤器

    异常处理过滤器

    /// <summary>
        /// 异常处理过滤器 
        /// </summary>
        public class SystemIExceptionFilter : IExceptionFilter
        {
            void IExceptionFilter.OnException(ExceptionContext filterContext)
            {
                Exception exception = filterContext.Exception;
                if (filterContext.ExceptionHandled)
                {
                    return;
                }
                HttpException http = new HttpException(null, exception);
                /*  
                 * filterContext.Exception.Message 错误信息 
                  */
                string messager = filterContext.Exception.Message;
    
                /*  
                 * 错误日志 
                  */
                //Log4NetHelp help = new Log4NetHelp();
                //help.ErrorString(filterContext.Exception.Message);
                /*  
                 * 设置自定义异常已经处理,避免其他过滤器异常覆盖 
                  */
                filterContext.ExceptionHandled = true;
    
                /*  
                 * 在派生类重写时,设置或者重写一个值该值指定是否禁用ISS7.0中自定义错误 
                  */
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
        }
    异常处理过滤器

    授权处理(获取客户端信息)

    public class SystemIAuthorizationFilter : IAuthorizationFilter
        {
            void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext)
            {
                //当前操作计算机用户   
                string pcName = ((System.Web.HttpServerUtilityWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Server).MachineName;
                //视图  
                string action = ((System.Web.Mvc.ReflectedActionDescriptor)filterContext.ActionDescriptor).ActionName;
                //控制器  
                string controller = ((System.Web.Mvc.ReflectedActionDescriptor)filterContext.ActionDescriptor).ControllerDescriptor.ControllerName;
                //请求时间  
                string time = filterContext.RequestContext.HttpContext.Timestamp.ToString();
                //请求相对路径  
                string absturl = ((System.Web.UnvalidatedRequestValuesWrapper)((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Request).Unvalidated).Url.AbsoluteUri;
                //状态  
                string code = ((System.Web.HttpResponseWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Response).Status;
                // 浏览器版本  
                string browser = ((System.Web.HttpBrowserCapabilitiesWrapper)((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.RequestContext.HttpContext).Request).Browser).Type;
                //请求方式  
                string gepPost = ((System.Web.HttpRequestWrapper)((System.Web.Mvc.Controller)filterContext.Controller).Request).RequestType;
                //本地主机名称解析DNS本身处理。  
                string server = ((System.Web.HttpRequestWrapper)((System.Web.HttpContextWrapper)filterContext.HttpContext).Request).UserHostAddress;
                #region  server 说明  
                /* 
                  * 版权(c)1993 - 2009微软(msft . o:行情)。 
                  * 
                  * 这是一个示例所使用的主机文件微软为Windows TCP / IP。 
                  * 
                  * 这个文件包含IP地址到主机名的映射。 
                              每一个 
                  * 条目应该保存在单个行。 
                  IP地址应 
                  *被放置在第一列对应的主机名。 
                  *的IP地址和主机名应该由至少一个 
                  *空间。 
                  * 
                  *此外,评论(这样的)可能是插入的个人 
                  *线或后机器名称用“*”符号。 
                  * 
                  例如: 
                  * 
                  * 102.54.94.97 rhino.acme.com源服务器 
                  * 38.25.63.10 x.acme.com x客户机主机 
    
                  *本地主机名称解析DNS本身处理。 
                  * 127.0.0.1 localhost 
                  *::1 localhost 
                  */
                #endregion
                //用户  
                //部门  
                //职位  
    
            }
        }
    授权处理过滤器

    自定义属性过滤器

    public class CheckLogin: ActionFilterAttribute
        {
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                HttpCookieCollection CookieCollect = System.Web.HttpContext.Current.Request.Cookies;
                if (CookieCollect["username"] == null || CookieCollect["password"] == null)
                {
                    filterContext.Result = new RedirectResult("/Home/Login");
                }
                else
                {
                    if (CookieCollect["username"].Value != "admin" && CookieCollect["password"].Value != "123456")
                    {
                        filterContext.Result = new RedirectResult("/Home/Login");
                    }
                }
            }
        }
    检查登录的过滤器

    过滤器定义好后,需要在过滤器配置类FilterConfig中添加

    public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                filters.Add(new HandleErrorAttribute());
    
                //将自定义异常过滤器的优先级提高,防止异常被默认的HandleError处理(也可以自定义类重写HandleErrorAttribute 实现错误处理)  
                filters.Add(new SystemIExceptionFilter(), 1);
                //控制器过滤器  
                filters.Add(new SystemIActionFilter(), 2);
                //授权过滤器  
                filters.Add(new SystemIAuthorizationFilter(), 3);
            //  自定义属性过滤器
                filters.Add(new CheckLogin());
    } }

    自定义属性过滤器在控制器中调用:
    在方法的上面加上特性:CheckLogin,当调用该方法时会先进行过滤再执行下面的逻辑。

     [CheckLogin]
            public ActionResult About()
            {
                
                ViewBag.Message = "Your application description page.";
    
                return View();
            }

    自定义ActionResult

    扩展的ActionResult,继承自ActionResult,需要重写ExecuteResult方法,通过构造函数传入参数值,

    使用ExecuteResult方法的ControllerContext上下文获得HttpResponse,HttpResponse使用输出参数值结果。

     /// <summary>
        /// 自定义JObject返回结果
        /// </summary>
        public class JObjectActionResult : ActionResult
        {
            /// <summary>
            /// 结果集
            /// </summary>
            public JObject JObject
            {
                get;
                set;
            }
    
            public Encoding ContentEncoding
            {
                get;
                set;
            }
    
            public override void ExecuteResult(ControllerContext context)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }
                HttpResponseBase response = context.HttpContext.Response;
                response.ContentType = "application/json";
                if (ContentEncoding != null)
                {
                    response.ContentEncoding = ContentEncoding;
                }
                if (JObject != null)
                {
                    response.Write(JObject.ToString());
                }
            }
        }
    JObjectActionResult

    通过response.Write(JObject.ToString());最后输出结果。
    接下来我们看看调用:

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

    默认的View()是Controller.View()的方法,因此我们为Controller类扩展一个方法。定义扩展内容如下:

    public static class JObjectActionResultExtensions
        {
            public static JObjectActionResult JObjectResult(this Controller controller, JObject obj)
            {
                return new JObjectActionResult { JObject = obj };
            }
    
            public static JObjectActionResult JObjectResult(this Controller controller, bool success)
            {
                JObject obj = new JObject();
                obj.Add("success", success);
                if (success)
                {
                    obj.Add("code", 200);
                    obj.Add("msg", "Success!");
                }
                else
                {
                    obj.Add("code", 500);
                    obj.Add("msg", "Error!");
                }
                return JObjectResult(controller, obj);
            }
    
            public static JObjectActionResult JObjectResult(this Controller controller, bool success, int code, string msg)
            {
                JObject obj = new JObject();
                obj.Add("success", success);
                obj.Add("code", code);
                obj.Add("msg", msg);
                return JObjectResult(controller, obj);
            }
        }
    JObjectActionResult的扩展

    控制器中调用输出:
    使用this关键字调用JObjectResult即可输出结果。

    public ActionResult About()
            {            
                ViewBag.Message = "Your application description page.";
                return this.JObjectResult(true);
            }

    接下来我们再扩展一个序列化的Result.

    /// <summary>
        /// 泛型的序列化结果
        /// </summary>
        /// <typeparam name="TData"></typeparam>
        public class CustomView<TData>  : ActionResult where TData:class,new()
        {
            /// <summary>
            /// 构造函数传入参数
            /// </summary>
            /// <param name="t"></param>
            public CustomView(TData t) { data = t; }
            public TData data;
    
            protected JsonSerializerSettings SerializerSettings;
    
            protected void InitSerialization(ControllerContext context)
            {
                HttpResponseBase response = context.HttpContext.Response;
                response.ContentType = "text/html";
                if (SerializerSettings == null)
                {
                    SetSerializerSettings();
                }
                response.Write(JsonConvert.SerializeObject(data, Formatting.None, SerializerSettings));
            }
    
            protected virtual void SetSerializerSettings()
            {
                SerializerSettings = new JsonSerializerSettings
                {
                    Converters = new List<JsonConverter>
                    {
                        new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd hh:mm" }
                    }
                };
            }
    
            public override void ExecuteResult(ControllerContext context)
            {
                InitSerialization(context);
            }
        }
    CustomView

    调用它,只需要实例化一下就行了。

    public ActionResult Contact()
            {
                ViewBag.Message = "Your contact page.";
                User u = new Models.User();
                return  new CustomView<User>(u);
            }

     下载地址

    大家还有什么好的扩展方法,可以回复该帖哦。

  • 相关阅读:
    姐姐的vue(1)
    LeetCode 64. Minimum Path Sum 20170515
    LeetCode 56. 56. Merge Intervals 20170508
    LeetCode 26. Remove Duplicates from Sorted Array
    LeetCode 24. Swap Nodes in Pairs 20170424
    LeetCode 19. Remove Nth Node From End of List 20170417
    LeetCode No.9 Palindrome Number 20170410
    LeetCode No.8. String to Integer (atoi) 2017/4/10(补上一周)
    LeetCode No.7 Reverse Integer 2017/3/27
    LeetCode No.4 Median of Two Sorted Arrays 20170319
  • 原文地址:https://www.cnblogs.com/licin/p/8459778.html
Copyright © 2011-2022 走看看