本来想写这个帖子已经很久了,但是公司事情多,做着做着就忘记了。公司因为需要做接口,而且用的还是asp.net的老框架,使用Handler来做,没得办法,自己照着MVC写了一个通过的接口操作模板。

上送json数据,返回的也是json数据。可以像MVC一样自动绑定并可以进行DataAnnotations验证。尽量达到在业务逻辑处理区域不用对上送参数做过多的获取和判断,能一次搞定就一次搞定。

话不多说,上代码!!!

BaseClass:用作接口参数的基类。接口参数类型可以继承该类,也可以不继承,或自己定义其他基类。

public abstract class BaseClass { }

EmptyClass:一个空类。当做一个参数类型传入到接口中,占用地方而已。

public class EmptyClass : BaseClass { }

ModelError:错误消息载体类型。

    [Serializable]
public class ModelError {
public ModelError(Exception exception) : this(exception, null) { } public ModelError(string errorMessage) {
this.ErrorMessage = errorMessage ?? string.Empty;
} public ModelError(Exception exception, string errorMessage) : this(errorMessage) {
if (exception == null)
throw new ArgumentNullException("exception");
this.Exception = exception;
} public Exception Exception { get; private set; }
public string ErrorMessage { get; private set; }
}

ModelErrorCollection:错误消息载体集合。

    [Serializable]
public class ModelErrorCollection : Collection<ModelError> {
public void Add(string errorMessage) {
base.Add(new ModelError(errorMessage));
} public void Add(Exception exception) {
base.Add(new ModelError(exception));
}
}

ModelState:模型绑定状态。

    /// <summary>
/// 模型绑定状态
/// </summary>
[Serializable]
public class ModelState {
private ModelErrorCollection _errors = new ModelErrorCollection();
public bool IsValid {
get {
return _errors.Count == ;
}
}
public ModelErrorCollection Errors {
get {
return _errors;
}
}
}

ModelBinder:模型绑定抽象类,需要继承此抽象类。用来绑定上送参数并验证的基类。

    /// <summary>
/// 模型绑定抽象类,需要继承此抽象类。
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class ModelBinder<T> where T : class {
protected ModelState _modelState; /// <summary>
/// 模型绑定状态
/// </summary>
public ModelState ModelState {
get {
if (_modelState == null)
_modelState = new ModelState();
return _modelState;
}
} /// <summary>
/// 绑定操作
/// </summary>
/// <returns></returns>
public abstract T Binder(); /// <summary>
/// 验证实体数据合法性。如果有错误,请在ModelState参数中获取。
/// </summary>
/// <param name="entity"></param>
protected void Valide(object entity) {
if (entity == null)
return;
//获取T类型的所有公共属性
Type type = entity.GetType();
PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); if (properties != null && properties.Count() > ) {
//针对每一个公共属性,获取其特性
foreach (var property in properties) {
//如果当前属性为一个自定义类型
if (property.PropertyType != typeof(object) && Type.GetTypeCode(property.PropertyType) == TypeCode.Object) {
this.Valide(property.GetValue(entity, null));
}
else
ValideProperty(entity, property); if (!_modelState.IsValid)
break;
}
}
} /// <summary>
/// 验证属性的每一个特性约束
/// </summary>
/// <param name="entity"></param>
/// <param name="property"></param>
private void ValideProperty(object entity, PropertyInfo property) {
if (entity != null && property != null) {
var attributes = property.GetCustomAttributes(typeof(ValidationAttribute), false);
foreach (ValidationAttribute attribute in attributes)
ValidatePropertyAttribute(entity, property, attribute);
}
} /// <summary>
/// 使用特性对属性进行验证
/// </summary>
/// <param name="entity"></param>
/// <param name="property"></param>
/// <param name="attribute"></param>
private void ValidatePropertyAttribute(object entity, PropertyInfo property, ValidationAttribute attribute) {
if (entity != null && property != null && attribute != null) {
//找到该属性
//注明:每一个函数都应当具有独立性.
PropertyInfo currentProperty = entity.GetType().GetProperties().Where(p => p.Name == property.Name).FirstOrDefault(); //判断当前特性是否有IsRequiredInstance字段,这是自定义的特性,用于验证同一个实例中两个不同共有属性的值
PropertyInfo[] pros = attribute.GetType().GetProperties();
if (pros.Where(it => it.Name == "IsRequiredInstance" && it.PropertyType == typeof(bool)).FirstOrDefault() != null)
attribute.GetType().GetProperty("Instance").SetValue(attribute, entity, null); if (currentProperty != null) {
var value = currentProperty.GetValue(entity, null);
if (!attribute.IsValid(value))
_modelState.Errors.Add(attribute.ErrorMessage);
}
}
} }

BaseHandler:一般处理逻辑的基类。

    /// <summary>
/// 一般处理逻辑的基类。
/// </summary>
/// <typeparam name="T">请求参数模型</typeparam>
/// <typeparam name="R">返回参数模型</typeparam>
public abstract class BaseHandler<T, R> : ModelBinder<T> where T : class where R : class {
protected readonly ILog log;
public BaseHandler() {
log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
public BaseHandler(string typeName) {
if ((typeName ?? "").Trim() != "")
log = LogManager.GetLogger(typeName);
else
log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
} /// <summary>
/// 处理接口API消息
/// </summary>
/// <returns></returns>
public abstract R Process(); /// <summary>
/// 真正需要处理的接口逻辑
/// </summary>
/// <param name="param">客户端传过来的请求参数</param>
/// <returns></returns>
protected abstract R DoWork(T param);
}

IndexHandler:一般业务接口的模板方法处理器。该接口是基础性接口,如果有其他业务需求,请自行另外自定义或继承该接口。

    /// <summary>
/// 一般业务接口的模板方法处理器。
/// 该接口是基础性接口,如果有其他业务需求,请自行另外自定义或继承该接口。
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class IndexHandler<T> : BaseHandler<T, BaseResponseResult> where T : class {
public IndexHandler() : base() { }
public IndexHandler(string typeName) : base(typeName) { } /// <summary>
/// 对实体模型进行绑定和参数的特性验证
/// </summary>
/// <returns></returns>
public override T Binder() {
//初始化模型
T rc = default(T); try {
//初始化ModelState
if (_modelState == null)
_modelState = new ModelState();
else
_modelState.Errors.Clear(); //获取数据
Stream stream = HttpContext.Current.Request.InputStream;
stream.Seek(, SeekOrigin.Begin);
byte[] buffer = new byte[stream.Length];
int count = stream.Read(buffer, , buffer.Length);
if (count > ) {
string requestParam = Encoding.UTF8.GetString(buffer);
//绑定数据
rc = new JavaScriptSerializer().Deserialize<T>(requestParam);
if (rc != null) {
//验证数据合法性
base.Valide(rc);
}
else
_modelState.Errors.Add("绑定数据失败!");
}
else
_modelState.Errors.Add("请求参数为空!");
}
catch (Exception ex) {
_modelState.Errors.Add("绑定数据出现错误!");
} return rc;
} /// <summary>
/// 处理接口API消息
/// </summary>
/// <returns></returns>
public override BaseResponseResult Process() {
BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError); try {
//绑定请求参数
T requestParam = Binder();
//开启逻辑操作
if (_modelState.IsValid)
rc = DoWork(requestParam);
else {
StringBuilder sbuilder = new StringBuilder();
foreach (var error in _modelState.Errors)
sbuilder.Append(error.ErrorMessage); rc.SetResult(ErrorCode.InvalideParameter, sbuilder.ToString());
}
}
catch (Exception ex) {
rc.SetResult(ErrorCode.SystemError);
rc.returnData = null;
log.Error("Process", ex);
} return rc;
}
}

BaseResponseResult:返回结果。

    /// <summary>
/// 返回结果
/// </summary>
public class BaseResponseResult {
public BaseResponseResult() { } public BaseResponseResult(int returnValue, string returnMsg) {
_code = returnValue;
_message = returnMsg;
} public BaseResponseResult(ErrorCode code, string returnMsg="") {
SetResult(code, returnMsg);
} private int _code = ;
private string _message = "";
private string _contentType = "application/json";
/// <summary>
/// 错误码,0表示成功,其他表示失败
/// </summary>
public virtual int returnValue { get { return _code; } }
/// <summary>
/// 错误码,0表示成功,其他表示失败
/// </summary>
public virtual string returnMsg { get { return _message; } }
/// <summary>
/// 返回的数据,json格式
/// </summary>
public virtual object returnData { get; set; } /// <summary>
/// 设置返回状态码
/// </summary>
/// <param name="code"></param>
public virtual void SetCode(int code) {
_code = code;
} /// <summary>
/// 设置返回状态码
/// </summary>
/// <param name="code"></param>
public virtual void SetCode(ErrorCode code) {
SetResult(code);
} /// <summary>
/// 设置返回消息
/// </summary>
/// <param name="message"></param>
public virtual void SetMessage(string message) {
_message = message;
}
/// <summary>
/// 设置返回状态码和消息
/// </summary>
/// <param name="returnValue"></param>
/// <param name="returnMsg"></param>
public virtual void SetResult(int returnValue, string returnMsg) {
_code = returnValue;
_message = returnMsg;
} /// <summary>
///
/// </summary>
/// <param name="code">ErrorCode代码</param>
/// <param name="returnMsg">返回消息。如果此项不输入值,则自动设置默认值!</param>
public virtual void SetResult(ErrorCode code, string returnMsg="") {
this._code = (int)code;
this._message = (returnMsg??"").Trim()!=""?returnMsg:ErrorMsg.ErrorMessage[code];
}
/// <summary>
/// 设置返回消息体
/// </summary>
/// <param name="obj"></param>
public virtual void SetReturnData(params object[] obj) {
if (obj != null && obj.Length > ) {
this.returnData = obj.ToList();
}
} public virtual void SetReturnData(object obj) {
this.returnData = obj;
} public virtual void SetContentType(string contentType) {
this._contentType = contentType;
} /// <summary>
/// 将当前结果转化为JSON字符串
/// </summary>
/// <returns></returns>
public virtual string ToJson() {
return new JavaScriptSerializer().Serialize(this);
} public virtual void Response(bool isEnd = true) {
HttpContext.Current.Response.ContentType = _contentType;
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.Write(this.ToJson());
if (isEnd)
HttpContext.Current.Response.End();
}
}

ErrorCode:返回状态码枚举。

 public enum ErrorCode {
/// <summary>
/// 操作错误
/// </summary>
OperationError = -,
/// <summary>
/// 成功
/// </summary>
Success = ,
/// <summary>
/// 失败
/// </summary>
Failed = ,
/// <summary>
/// 无数据
/// </summary>
NoData=,
/// <summary>
/// 不存在此页面
/// </summary>
NotExistPage=,
/// <summary>
/// 无权限
/// </summary>
NoPermission=,
/// <summary>
/// 未登录
/// </summary>
NoLogin=,
/// <summary>
/// 被禁止
/// </summary>
Forbidden=,
/// <summary>
/// 请求参数格式不符合要求
/// </summary>
InvalideParameter = ,
/// <summary>
/// 无此接口
/// </summary>
NoAction = ,
/// <summary>
/// 系统错误
/// </summary>
SystemError = ,
} public class ErrorMsg {
public static Dictionary<ErrorCode, string> ErrorMessage = new Dictionary<ErrorCode, string> {
{ ErrorCode.OperationError,"服务器响应错误!"},
{ ErrorCode.Success,"成功!"},
{ ErrorCode.Failed, "失败!"},
{ ErrorCode.NoData, "查无数据!"},
{ ErrorCode.NotExistPage,"此页码不存在!"},
{ ErrorCode.InvalideParameter,"请求参数非法!"},
{ ErrorCode.NoAction,"无此接口!"},
{ ErrorCode.SystemError,"系统错误!"},
{ ErrorCode.NoPermission,"无权限操作此功能!" },
{ ErrorCode.NoLogin,"未登录!"},
{ ErrorCode.Forbidden,"操作被禁止!"},
};
}

接下来介绍使用方法:

IndexHandler_Base64:定义一个接收base64字符串参数的接口处理器。代码如下:

    /// <summary>
/// 一般业务接口的模板方法处理器,适用于参数为base64字符串的请求
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class IndexHandler_Base64<T> : IndexHandler<T> where T:class {
//当前接口是否需要登录后才能操作
protected bool _isLoginRequired = false; /// <summary>
/// 实例化一个只接收base64字符串的接口操作
/// </summary>
/// <param name="isLoginRequired">当前接口是否需要登录。true:需要 false:不需要(默认)</param>
public IndexHandler_Base64(bool isLoginRequired = false) : base() { _isLoginRequired = isLoginRequired; }
/// <summary>
/// 实例化一个只接收base64字符串的接口操作
/// </summary>
/// <param name="typeName">发起日志记录的类名</param>
/// <param name="isLoginRequired">当前接口是否需要登录。true:需要 false:不需要(默认)</param>
public IndexHandler_Base64(string typeName,bool isLoginRequired=false) : base(typeName) { _isLoginRequired = isLoginRequired; } /// <summary>
/// 对实体模型进行绑定和参数的特性验证
/// </summary>
/// <returns></returns>
public override T Binder() {
//初始化模型
T rc = default(T); try {
//初始化ModelState
if (_modelState == null)
_modelState = new ModelState();
else
_modelState.Errors.Clear(); //获取数据
Stream stream = HttpContext.Current.Request.InputStream;
stream.Seek(, SeekOrigin.Begin);
byte[] buffer = new byte[stream.Length];
int count = stream.Read(buffer, , buffer.Length);
if (count > ) {
string requestParam = Encoding.UTF8.GetString(buffer);
requestParam = Encoding.UTF8.GetString(Convert.FromBase64String(requestParam));
//绑定数据
rc = new JavaScriptSerializer().Deserialize<T>(requestParam);
if (rc != null) {
//验证数据合法性
base.Valide(rc);
}
else
_modelState.Errors.Add("绑定数据失败!");
}
else
_modelState.Errors.Add("请求参数为空!");
}
catch (Exception ex) {
_modelState.Errors.Add("绑定数据出现错误!");
} return rc;
} public override BaseResponseResult Process() {
//如果该接口需要登录后才能操作,则检查当前用户是否登录
if (_isLoginRequired) {
int userId = ;
try {
userId = Login.GetSession("UserID");
}
catch { }
if (userId <= )
return new BaseResponseResult(ErrorCode.NoLogin);
} return base.Process();
}
}

接下来定义一个Index.ashx文件,开始使用模板接口。

    /// <summary>
/// index 的摘要说明
/// </summary>
public class Index : IHttpHandler {
private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
//当前登录的用户
public static int _thisUserId {
get {
return Login.GetSession("UserID");
}
}
public void ProcessRequest(HttpContext context) {
BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError, "获取数据失败!"); try {
string action = GetAction(); switch (action) {
//获取 xxx列表
case "":
rc = new ListHandler().Process();
break;
//获取 xxx信息
case "":
rc = new ItemHandler().Process();
break; default:
rc.SetResult(ErrorCode.NoAction);
break;
} }
catch (Exception ex) {
log.Error("ProcessRequest", ex);
rc.SetResult(ErrorCode.SystemError);
} rc.Response();
} public bool IsReusable {
get {
return false;
}
} /// <summary>
/// 获取Action接口名称
/// </summary>
/// <returns></returns>
private string GetAction() {
string rc = ""; try {
rc = HttpContext.Current.Request["action"] ?? "";
if ((rc ?? "").Trim() == "") {
Stream stream = HttpContext.Current.Request.InputStream;
if (stream != null) {
byte[] buffer = new byte[stream.Length];
int count = stream.Read(buffer, , buffer.Length);
if (count > ) {
try {
string requestParam = Encoding.UTF8.GetString(buffer);
requestParam = Encoding.UTF8.GetString(Convert.FromBase64String(requestParam));
JsonData jd = JsonMapper.ToObject(requestParam);
if (jd != null && jd.Keys.Contains("action"))
rc = jd["action"].ToString();
}
catch { }
}
}
}
}
catch (Exception ex) {
log.Error("GetAction", ex);
} return rc;
} } #region 接口处理区 #region 1001 获取 xxx列表
public class ListReqModel { [Required(ErrorMessage = "请上送需要类型!")]
[Range(0,5, ErrorMessage = "type参数值有误!")]
public int type { get; set; }
/// <summary>
/// 页码索引,从0开始
/// </summary>
[Required(ErrorMessage = "请上送页码索引!")]
[Min(, ErrorMessage = "pageIndex参数值有误!")]
public int pageIndex { get; set; } /// <summary>
/// 每页个数
/// </summary>
[Required(ErrorMessage = "请上送每页的个数!")]
[Min(, ErrorMessage = "pageSize参数值有误!")]
public int pageSize { get; set; } }
public class ListHandler : IndexHandler_Base64<ListReqModel> { public ListHandler() : base("ListHandler") { }
protected override BaseResponseResult DoWork(ListReqModel param) {
BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError);
int totalCount = ;
ProjectBLL biz = new ProjectBLL();
DataTable table = biz.GetList(param.type ,Index._thisUserId, out totalCount, param.pageIndex, param.pageSize); if (table != null && table.Rows.Count > ) {
rc.SetReturnData(new
{
//总个数
totalCount = totalCount,
list = table.AsEnumerable().Select(it => new
{
id = it["ID"].ToInt64(),
title = it["Title"].ToNormalString(),
frontCover = it["FrontCover"].ToNormalString()
}).ToList()
});
rc.SetResult(ErrorCode.Success, "成功!");
}
else if (totalCount > )
rc.SetResult(ErrorCode.NotExistPage, "当前页码不存在!");
else
rc.SetResult(ErrorCode.NoData, "没有数据哟!"); return rc;
}
}
#endregion #region 1002 获取xxx信息 public class ItemReqModel {
[Required(ErrorMessage = "请上送项目标识!")]
[Min(, ErrorMessage = "id参数值有误!")]
public long id { get; set; }
} public class ItemHandler : IndexHandler_Base64<ItemReqModel> {
public ItemHandler() : base("ItemHandler") { } protected override BaseResponseResult DoWork(ItemReqModel param) {
BaseResponseResult rc = new BaseResponseResult(ErrorCode.OperationError);return rc;
}
} #endregion#endregion

ajax的使用方式:

//接入说明:
//1、请使用POST方式上传;
//2、请将参数组装为Json字符串,如:{'action':'xxx','xx':'xx'};
//3、Json字符串组装好以后,将其变为Base64字符串后上传。 //上送数据案例如下所示:
$.ajax({
type: "POST",
dataType: "json",
url: GetHost() + 'Index.ashx',
data: Base.encode('{"action":"1001","type":"' + type + '","pgIndex":' + pageIndex + ',"pgSize":' + pageSize + '}'),
contentType:"application/json",
success: function (data) {
//获取数据
if (data) {
//成功获取数据
if (data.returnValue == ) {
//处理数据
}
}
}
});

至此,完毕!以上的通用接口处理器采用了模板方法设计模式,尽量减少重复工作量。

说明:本篇文章为作者原创,如需转载,请说明来源及出处!

asp.net 自定义的模板方法接口通用类型的更多相关文章

  1. asp.net core参数保护之自定义要保护的参数类型

    asp.net core参数保护之自定义要保护的参数类型 Intro 为了实现 asp.net core 下的参数保护,扩展了asp.net core 中 DataProtection,可以自动化的保 ...

  2. ASP.NET交互Rest服务接口(Jquery的Get与Post方式)

    ASP.NET交互Rest服务接口(Jquery的Get与Post方式) 本文将通过一个简单的实例,介绍如何创建一个Rest服务接口,以及通过JQUERY去对它进行调用;主要采取两种方式分别为Get跟 ...

  3. 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式

    连表查询都用Left Join吧   最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...

  4. 《连载 | 物联网框架ServerSuperIO教程》- 13.自定义视图显示接口开发,满足不同的显示需求

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  5. ABAP基本数据类型、通用类型

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  6. Android 代码库(自定义一套 Dialog通用提示框 )

          做Android开发五年了,期间做做停停(去做后台开发,服务器管理),当回来做Android的时候,发现很生疏,好些控件以前写得很顺手,现在好像忘记些什么了,总要打开这个项目,打开那个项目 ...

  7. ASP.NET中共有哪几种类型的控件?其中,HTML控件、HTML服务器控件和WEB服务器控件之间有什么区别

    ASP.NET的控件包括WEB服务器控件.WEB用户控件.WEB自定义控件.HTML服务器控件和HTML控件.HTML控件.HTML服务器控件和WEB服务器控件之间的区别如下所示.q      HTM ...

  8. ASP.NET WebAPI构建API接口服务实战演练

    一.课程介绍 一.王小二和他领导的第一次故事 有一天王小二和往常一下去上早班,刚吃完早餐刚一打开电脑没一会儿.王小二的领导宋大宝走到他的面前,我们现在的系统需要提供服务给其他内部业务系统,我看你平时喜 ...

  9. 使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证

    使用ASP.NET Identity 实现WebAPI接口的Oauth身份验证   目前WEB 前后端分离的开发模式比较流行,之前做过的几个小项目也都是前后分离的模式,后端使用asp.net weba ...

随机推荐

  1. 调试 ASP.NET Core 2.0 源代码

    在Visual Studio 2017中可以通过符号以及源链接,非常方便对 ASP.NET Core 2.0中源代码进行调试.在这篇文章中,我们将重点介绍如何使用源链接对ASP.NET Core源进行 ...

  2. spring boot系列01--快速构建spring boot项目

    最近的项目用spring boot 框架 借此学习了一下 这里做一下总结记录 非常便利的一个框架 它的优缺点我就不在这背书了 想了解的可以自行度娘谷歌 说一下要写什么吧 其实还真不是很清楚,只是想记录 ...

  3. Ubuntu 16安装GPU版本tensorflow

    pre { direction: ltr; color: rgb(0, 0, 0) } pre.western { font-family: "Liberation Mono", ...

  4. OpenVPN server端配置文件详细说明(转)

    本文将介绍如何配置OpenVPN服务器端的配置文件.在Windows系统中,该配置文件一般叫做server.ovpn:在Linux/BSD系统中,该配置文件一般叫做server.conf.虽然配置文件 ...

  5. CSS图片垂直居中方法整理集合

    原帖链接:http://bbs.blueidea.com/thread-2666987-1-1.html 1.因为Opera,FF3,IE8均支持display:talbe;这些特性了,因此改进的办法 ...

  6. 自动化selenium开发

    一.开发环境搭建 1.Firefox浏览器 1.1 下载firefix并安装. 1.2 Firefox中打开"开始菜单“ -> ”开发者“ -> ”获取更多工具“ -> 搜 ...

  7. spring cloud+dotnet core搭建微服务架构:配置中心(四)

    前言 我们项目中有很多需要配置的地方,最常见的就是各种服务URL地址,这些地址针对不同的运行环境还不一样,不管和打包还是部署都麻烦,需要非常的小心.一般配置都是存储到配置文件里面,不管多小的配置变动, ...

  8. slf4j+log4j在Java中实现日志记录

    小Alan今天来跟大家聊聊开发中既简单又常用但必不可少的一样东西,那是什么呢?那就是日志记录,日志输出,日志保存. 后面就统一用日志记录四个字来形容啦. 日志记录是项目的开发中必不可少的一个环节,特别 ...

  9. Mybatis,Spring,SpringMVC框架面试题

    Mybatis测试 1,   Mybatis的核心是(  sqlsessionfactory    ) 2,   使用Mybatis持久化框架进行数据查询需要返回的一个实体类的集合, 在<sel ...

  10. 【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结

    虽然看过一些Java 8新特性的资料,但是平时很少用到,时间长了就忘了,正好借着Java 9的发布,来总结下一些Java 8中的新特性. 接口中的默认方法和静态方法 先考虑一个问题,如何向Java中的 ...