|
|
// ============================================================================
|
|
|
// 【文件说明】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 作为 warn(HTTP 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 完全一样的语法。
|
|
|
//
|
|
|
// Why:RuoYi 的 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;
|
|
|
}
|
|
|
}
|