You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

443 lines
14 KiB
C#

// ============================================================================
// 【文件说明】HwPortalAjaxResult.cs - Ajax 统一响应结果类
// ============================================================================
// 这个类用于统一所有 API 接口的返回格式。
// 在 Java 若依RuoYi框架中有一个 AjaxResult 类做同样的事情。
//
// 统一返回格式的好处:
// 1. 前端可以用同一套逻辑处理所有接口响应
// 2. 便于统一添加日志、监控、错误处理
// 3. 接口文档更清晰,返回结构可预测
//
// 返回的 JSON 结构示例:
// 成功:{ "code": 200, "msg": "操作成功", "data": { ... } }
// 失败:{ "code": 500, "msg": "操作失败", "data": null }
// 警告:{ "code": 301, "msg": "警告信息", "data": null }
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// Ajax 统一响应结果类。
/// <para>
/// 【设计模式 - 静态工厂方法模式】
/// 这个类大量使用了"静态工厂方法"设计模式:
/// - Success() 返回成功结果
/// - Error() 返回失败结果
/// - Warn() 返回警告结果
///
/// 对比 Java
/// Java 中你可能会写:
/// AjaxResult result = new AjaxResult();
/// result.put("code", 200);
/// result.put("msg", "操作成功");
///
/// C# 这里用静态工厂方法更优雅:
/// return HwPortalAjaxResult.Success("操作成功", data);
///
/// 好处:
/// 1. 代码更简洁,一行搞定
/// 2. 避免忘记设置 code/msg
/// 3. 可以在工厂方法里统一加日志、校验等逻辑
/// </para>
/// </summary>
public class HwPortalAjaxResult
{
/// <summary>
/// 返回码字段名。
/// <para>
/// 【C# 语法知识点 - const 常量】
/// const 是"编译期常量",值在编译时就确定了,不能修改。
///
/// 对比 Java
/// Java 写法public static final String CODE_TAG = "code";
/// C# 写法public const string CodeTag = "code";
///
/// const 和 readonly 的区别:
/// - const编译期确定值直接嵌入调用处类似宏替换
/// - readonly运行时确定可以在构造函数中赋值
///
/// 这里用 const 是因为字段名永远不会变,编译期确定更高效。
/// </para>
/// 与原 Java AjaxResult 的 CODE_TAG 对齐。
/// </summary>
public const string CodeTag = "code";
/// <summary>
/// 返回消息字段名。
/// 与原 Java AjaxResult 的 MSG_TAG 对齐。
/// </summary>
public const string MsgTag = "msg";
/// <summary>
/// 返回数据字段名。
/// 与原 Java AjaxResult 的 DATA_TAG 对齐。
/// </summary>
public const string DataTag = "data";
/// <summary>
/// 成功状态码。
/// HTTP 200 OK 的含义是"请求成功",这里借用这个惯例。
/// </summary>
public const int SuccessCode = 200;
/// <summary>
/// 警告状态码。
/// RuoYi 默认使用 301 作为 warnHTTP 301 是重定向,但这里只是借用数字)。
/// 警告通常表示"操作部分成功"或"需要用户注意但不阻断"的情况。
/// </summary>
public const int WarnCode = 301;
/// <summary>
/// 错误状态码。
/// HTTP 500 Internal Server Error 的含义是"服务器内部错误"。
/// 这里用于表示"操作失败"的业务错误。
/// </summary>
public const int ErrorCode = 500;
/// <summary>
/// 状态码。
/// <para>
/// 【C# 语法知识点 - 自动属性】
/// public int Code { get; set; }
/// 这是 C# 的"自动属性"语法,编译器自动生成后备字段和 get/set 方法。
///
/// 对比 Java
/// Java 需要手写 getter/setter
/// private int code;
/// public int getCode() { return code; }
/// public void setCode(int code) { this.code = code; }
/// </para>
/// </summary>
public int Code { get; set; }
/// <summary>
/// 返回消息。
/// </summary>
public string Msg { get; set; }
/// <summary>
/// 返回数据。
/// <para>
/// 【C# 语法知识点 - object 类型】
/// object 是 C# 的"根类型",所有类型都继承自 object。
/// 类似 Java 的 Object但 C# 的 object 可以是值类型int, bool 等)。
///
/// 为什么用 object
/// 因为 Data 可以是任何类型:
/// - 单个对象:{ "id": 1, "name": "张三" }
/// - 列表:[{ "id": 1 }, { "id": 2 }]
/// - 字符串:"操作成功"
/// - null没有数据
///
/// 使用 object 可以容纳所有可能的数据类型。
/// </para>
/// </summary>
public object Data { get; set; }
/// <summary>
/// 无参构造函数。
/// <para>
/// 【C# 语法知识点 - 构造函数】
/// 构造函数名称必须与类名相同,没有返回类型。
///
/// 对比 Java
/// Java 和 C# 的构造函数语法几乎一致。
///
/// 为什么需要无参构造函数?
/// 某些序列化框架(如 JSON 反序列化)需要无参构造函数来创建对象,
/// 然后再通过属性赋值。
/// </para>
/// </summary>
public HwPortalAjaxResult()
{
}
/// <summary>
/// 带参数的构造函数。
/// <para>
/// 【C# 语法知识点 - 可选参数 data = null】
/// object data = null 中的 = null 是"默认参数值"。
/// 调用时可以不传这个参数,自动使用默认值 null。
///
/// 对比 Java
/// Java 不支持可选参数,需要写多个重载构造函数:
/// public HwPortalAjaxResult(int code, String msg) { this(code, msg, null); }
/// public HwPortalAjaxResult(int code, String msg, Object data) { ... }
///
/// C# 一个构造函数就搞定了,更简洁。
/// </para>
/// </summary>
/// <param name="code">状态码</param>
/// <param name="msg">返回消息</param>
/// <param name="data">返回数据,默认为 null</param>
public HwPortalAjaxResult(int code, string msg, object data = null)
{
Code = code;
Msg = msg;
Data = data;
}
/// <summary>
/// 返回成功结果(默认消息)。
/// <para>
/// 【C# 语法知识点 - 静态工厂方法】
/// public static HwPortalAjaxResult Success()
/// 这是一个静态方法,返回类本身的实例。
///
/// 为什么用静态工厂方法而不是直接 new
/// 1. 命名更清晰Success() 比 new AjaxResult(200, "操作成功") 更易读
/// 2. 可以缓存常用实例(这里没做,但可以扩展)
/// 3. 可以返回子类(这里没用到,但这是工厂模式的优势)
///
/// 对比 Java
/// Java 的静态工厂方法写法一样:
/// public static AjaxResult success() { return new AjaxResult(200, "操作成功"); }
/// </para>
/// </summary>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success()
{
// 方法重载链:调用带消息参数的版本
return Success("操作成功");
}
/// <summary>
/// 返回成功结果(带数据)。
/// </summary>
/// <param name="data">返回数据</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(object data)
{
return Success("操作成功", data);
}
/// <summary>
/// 返回成功结果(带自定义消息)。
/// </summary>
/// <param name="msg">返回消息</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(string msg)
{
return Success(msg, null);
}
/// <summary>
/// 返回成功结果(完整参数)。
/// <para>
/// 【C# 语法知识点 - 对象初始化器】
/// new HwPortalAjaxResult { Code = ..., Msg = ..., Data = ... }
/// 这是"对象初始化器"语法,可以在创建对象时直接给属性赋值。
///
/// 对比 Java
/// Java 需要这样写:
/// HwPortalAjaxResult result = new HwPortalAjaxResult();
/// result.setCode(SuccessCode);
/// result.setMsg(msg);
/// result.setData(data);
/// return result;
///
/// C# 一行搞定,更简洁。
/// </para>
/// </summary>
/// <param name="msg">返回消息</param>
/// <param name="data">返回数据</param>
/// <returns>成功结果实例</returns>
public static HwPortalAjaxResult Success(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = SuccessCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回警告结果(仅消息)。
/// </summary>
/// <param name="msg">警告消息</param>
/// <returns>警告结果实例</returns>
public static HwPortalAjaxResult Warn(string msg)
{
return Warn(msg, null);
}
/// <summary>
/// 返回警告结果(带数据)。
/// </summary>
/// <param name="msg">警告消息</param>
/// <param name="data">返回数据</param>
/// <returns>警告结果实例</returns>
public static HwPortalAjaxResult Warn(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = WarnCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回错误结果(默认消息)。
/// </summary>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error()
{
return Error("操作失败");
}
/// <summary>
/// 返回错误结果(自定义消息)。
/// </summary>
/// <param name="msg">错误消息</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(string msg)
{
return Error(msg, null);
}
/// <summary>
/// 返回错误结果(带数据)。
/// </summary>
/// <param name="msg">错误消息</param>
/// <param name="data">返回数据</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(string msg, object data)
{
return new HwPortalAjaxResult
{
Code = ErrorCode,
Msg = msg,
Data = data
};
}
/// <summary>
/// 返回错误结果(自定义状态码)。
/// </summary>
/// <param name="code">自定义状态码</param>
/// <param name="msg">错误消息</param>
/// <returns>错误结果实例</returns>
public static HwPortalAjaxResult Error(int code, string msg)
{
return new HwPortalAjaxResult
{
Code = code,
Msg = msg,
Data = null
};
}
/// <summary>
/// 根据影响行数返回成功或失败结果。
/// <para>
/// 【业务场景】
/// 在数据库操作中,增删改会返回"影响行数"
/// - rows > 0表示操作成功有数据被修改
/// - rows = 0表示操作失败没有数据被修改
///
/// 这个方法把"影响行数"转换为"响应结果",简化控制器代码:
/// return ToAjax(await service.Insert(input));
///
/// 对比 Java 若依:
/// 若依的 BaseController.toAjax(int rows) 做同样的事情。
/// </para>
/// </summary>
/// <param name="rows">数据库影响行数</param>
/// <returns>成功或失败结果</returns>
public static HwPortalAjaxResult FromRows(int rows)
{
// 【三元运算符】
// condition ? valueIfTrue : valueIfFalse
// 和 Java 完全一样的语法。
//
// WhyRuoYi 的 BaseController.toAjax(int rows) 只根据影响行数返回成功/失败,
// 不会把 rows 本身塞进 data这里必须保持同一口径否则前端判断会漂移。
return rows > 0 ? Success() : Error();
}
/// <summary>
/// 判断是否成功。
/// </summary>
/// <returns>是否成功</returns>
public bool IsSuccess()
{
return Code == SuccessCode;
}
/// <summary>
/// 判断是否警告。
/// </summary>
/// <returns>是否警告</returns>
public bool IsWarn()
{
return Code == WarnCode;
}
/// <summary>
/// 判断是否错误。
/// </summary>
/// <returns>是否错误</returns>
public bool IsError()
{
return Code == ErrorCode;
}
/// <summary>
/// 链式设置字段值(兼容原 Java AjaxResult 的 put 方法)。
/// <para>
/// 【C# 语法知识点 - 链式调用】
/// 这个方法返回 this可以链式调用
/// result.Put("code", 200).Put("msg", "成功");
///
/// 对比 Java
/// Java 若依的 AjaxResult 继承自 HashMap可以
/// result.put("code", 200).put("msg", "成功");
///
/// C# 这里用强类型对象实现,只对常见字段做兼容。
/// </para>
/// <para>
/// 【C# 语法知识点 - StringComparison.OrdinalIgnoreCase】
/// OrdinalIgnoreCase 表示"忽略大小写的序号比较"。
/// 这样 "Code" 和 "code" 会被视为相同,提高容错性。
///
/// 对比 Java
/// Java 用 equalsIgnoreCase() 方法:
/// key.equalsIgnoreCase(CodeTag)
/// </para>
/// </summary>
/// <param name="key">字段名</param>
/// <param name="value">字段值</param>
/// <returns>当前实例,支持链式调用</returns>
public HwPortalAjaxResult Put(string key, object value)
{
// 【字符串比较的最佳实践】
// string.Equals(a, b, StringComparison.OrdinalIgnoreCase)
// 比 a.ToLower() == b.ToLower() 更高效,不会产生新字符串对象。
if (string.Equals(key, CodeTag, StringComparison.OrdinalIgnoreCase))
{
// 【类型转换】
// Convert.ToInt32 可以处理多种类型string, long, double 等。
// CultureInfo.InvariantCulture 表示使用"不变的格式规则"
// 避免不同地区的数字格式差异(如某些地区用逗号作小数点)。
Code = Convert.ToInt32(value, CultureInfo.InvariantCulture);
return this;
}
if (string.Equals(key, MsgTag, StringComparison.OrdinalIgnoreCase))
{
Msg = Convert.ToString(value, CultureInfo.InvariantCulture);
return this;
}
if (string.Equals(key, DataTag, StringComparison.OrdinalIgnoreCase))
{
Data = value;
}
return this;
}
}