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