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.

314 lines
11 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// ============================================================================
// 【文件说明】HwWebController.cs - 官网页面控制器
// ============================================================================
// 这个控制器负责处理官网页面相关的 HTTP 请求。
//
// 【ASP.NET Core 控制器基础】
// 控制器是 MVC 架构中的"C",负责:
// 1. 接收 HTTP 请求
// 2. 调用业务逻辑Service 层)
// 3. 返回 HTTP 响应
//
// 【路由规则】
// [Route("portal/hwWeb")] 定义了路由前缀:
// - GET portal/hwWeb/list -> List() 方法
// - GET portal/hwWeb/{webCode} -> GetInfo() 方法
// - POST portal/hwWeb -> Add() 方法
// - PUT portal/hwWeb -> Edit() 方法
// - DELETE portal/hwWeb/{webIds} -> Remove() 方法
//
// 【与 Java Spring Boot 的对比】
// Java Spring Boot:
// @RestController
// @RequestMapping("/portal/hwWeb")
// public class HwWebController { ... }
//
// ASP.NET Core:
// [ApiController]
// [Route("portal/hwWeb")]
// public class HwWebController : ControllerBase { ... }
//
// 两者概念相同,只是注解/特性的写法不同。
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// 官网页面控制器。
/// <para>
/// 【C# 语法知识点 - 特性组合】
/// [AllowAnonymous] + [Route("portal/hwWeb")] 是多个特性组合使用。
///
/// [AllowAnonymous] 表示"允许匿名访问",不需要登录就能调用这些接口。
/// 这对于官网前台是必要的,因为访问官网的用户通常不需要登录。
///
/// 对比 Java Spring Security
/// Java: @PermitAll 或在 SecurityConfig 中配置 permitAll()
/// C#: [AllowAnonymous] 特性
/// </para>
/// <para>
/// 【RESTful API 设计】
/// 这个控制器遵循 RESTful 风格:
/// - GET查询操作
/// - POST新增操作
/// - PUT更新操作
/// - DELETE删除操作
///
/// 对比 Java Spring Boot
/// Java: @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
/// C#: [HttpGet], [HttpPost], [HttpPut], [HttpDelete]
///
/// 写法几乎一样,只是特性名称略有不同。
/// </para>
/// </summary>
[AllowAnonymous]
[Route("portal/hwWeb")]
public class HwWebController : HwPortalControllerBase
{
/// <summary>
/// 页面服务实例。
/// <para>
/// 【C# 语法知识点 - readonly 字段】
/// readonly 表示"只读字段",只能在构造函数中赋值,之后不能修改。
///
/// 为什么用 readonly
/// 1. 防止意外修改:服务实例不应该被替换
/// 2. 线程安全readonly 字段天然线程安全
/// 3. 编译器优化:编译器可以对 readonly 字段做优化
///
/// 对比 Java
/// Java 通常用 final 关键字:
/// private final HwWebService service;
/// </para>
/// <para>
/// 【命名约定】
/// _service 是 C# 的私有字段命名约定(下划线前缀)。
/// 也可以用 service无前缀但 _service 更常见于依赖注入字段。
/// </para>
/// </summary>
private readonly HwWebService _service;
/// <summary>
/// 构造函数(依赖注入)。
/// <para>
/// 【C# 语法知识点 - 构造函数依赖注入】
/// public HwWebController(HwWebService service)
///
/// 这是 ASP.NET Core 最核心的设计模式依赖注入DI
///
/// 工作原理:
/// 1. 应用启动时,框架扫描所有服务并注册到 DI 容器
/// 2. 当请求到达控制器时,框架自动创建所需的服务实例
/// 3. 通过构造函数把服务实例"注入"进来
///
/// 对比 Java Spring Boot
/// Java 有三种注入方式:
/// // 1. 字段注入(不推荐)
/// @Autowired
/// private HwWebService service;
///
/// // 2. Setter 注入(较少用)
/// @Autowired
/// public void setService(HwWebService service) { this.service = service; }
///
/// // 3. 构造函数注入(推荐,和 C# 一样)
/// @Autowired
/// public HwWebController(HwWebService service) { this.service = service; }
///
/// C# ASP.NET Core 只推荐构造函数注入,这是最佳实践。
/// </para>
/// </summary>
/// <param name="service">页面服务实例(由框架自动注入)</param>
public HwWebController(HwWebService service)
{
_service = service;
}
/// <summary>
/// 查询页面列表。
/// <para>
/// 【HTTP 路由】
/// [HttpGet("list")] 定义了路由GET portal/hwWeb/list
///
/// 对比 Java Spring Boot
/// Java: @GetMapping("/list") 或 @GetMapping("list")
/// C#: [HttpGet("list")]
/// </para>
/// <para>
/// 【C# 语法知识点 - async/await 异步编程】
/// public async Task&lt;HwPortalTableDataInfo&lt;HwWeb&gt;&gt; List(...)
///
/// async/await 是 C# 的异步编程语法:
/// - async标记方法为异步方法
/// - await等待异步操作完成
/// - Task&lt;T&gt;:表示一个返回 T 类型的异步操作
///
/// 为什么用异步?
/// 数据库操作是 I/O 密集型,使用异步可以:
/// 1. 不阻塞线程:等待数据库时,线程可以处理其他请求
/// 2. 提高吞吐量:同样的线程数可以处理更多请求
///
/// 对比 Java
/// Java 的异步写法:
/// public CompletableFuture&lt;TableDataInfo&lt;HwWeb&gt;&gt; list(...) {
/// return CompletableFuture.supplyAsync(() -> service.selectList(input));
/// }
///
/// 或者用 Spring 的 @Async 注解。
///
/// C# 的 async/await 更简洁,是语言级别的支持。
/// </para>
/// </summary>
/// <param name="input">
/// 查询参数。
/// <para>
/// 【C# 语法知识点 - [FromQuery] 特性】
/// [FromQuery] 表示从 URL 查询字符串绑定参数。
/// 例如GET portal/hwWeb/list?webCode=100
/// 框架会自动把 webCode=100 绑定到 input.WebCode 属性。
///
/// 对比 Java Spring Boot
/// Java: public Result list(@RequestParam Map&lt;String, String&gt; params)
/// 或者public Result list(HwWeb input) // Spring 会自动绑定
/// </para>
/// </param>
/// <returns>分页数据包装对象</returns>
[HttpGet("list")]
public async Task<HwPortalTableDataInfo<HwWeb>> List([FromQuery] HwWeb input)
{
// await 表示"等待异步操作完成"。
// GetDataTableWithoutPaging 是基类方法,不做分页,返回全部数据。
return GetDataTableWithoutPaging(await _service.SelectHwWebList(input));
}
/// <summary>
/// 导出页面数据到 Excel。
/// <para>
/// 【幂等性设计】
/// [Idempotent] 是 Furion 框架的特性,表示"幂等操作"。
///
/// 什么是幂等?
/// 多次执行相同的请求,结果和执行一次一样。
///
/// 为什么导出需要幂等?
/// 1. 防止重复请求:用户多次点击导出按钮
/// 2. 限流保护:避免服务器被大量导出请求打垮
///
/// 实现原理:
/// 框架会根据请求的唯一标识如请求头中的请求ID判断是否重复请求。
/// 如果是重复请求,直接返回之前的结果,不再执行方法体。
/// </para>
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>Excel 文件下载响应</returns>
[HttpPost("export")]
[Idempotent]
public async Task<IActionResult> Export([FromQuery] HwWeb input)
{
// ExportExcel 是基类方法,返回 IActionResult。
// IActionResult 是 ASP.NET Core 的"动作结果"接口,
// 可以是 JsonResult、FileResult、StatusCodeResult 等。
return ExportExcel(await _service.SelectHwWebList(input), "官网页面数据");
}
/// <summary>
/// 根据编码查询页面详情。
/// <para>
/// 【C# 语法知识点 - 路由参数约束】
/// [HttpGet("{webCode:long}")] 中的 :long 是"路由约束"。
///
/// 含义webCode 参数必须是 long 类型。
/// 如果传入非数字,会返回 404 而不是 400。
///
/// 常见的路由约束:
/// - :int整数
/// - :long长整数
/// - :guidGUID
/// - :regex(pattern):正则表达式
///
/// 对比 Java Spring Boot
/// Java: @GetMapping("/{webCode}")
/// public Result getInfo(@PathVariable Long webCode)
///
/// C# 的路由约束在路由模板中定义,更声明式。
/// </para>
/// </summary>
/// <param name="webCode">页面编码(从路由中获取)</param>
/// <returns>Ajax 响应结果</returns>
[HttpGet("{webCode:long}")]
public async Task<HwPortalAjaxResult> GetInfo(long webCode)
{
// Success 是基类方法,返回成功结果。
// 这里把查询到的数据包装成 AjaxResult 返回。
return Success(await _service.SelectHwWebByWebcode(webCode));
}
/// <summary>
/// 新增页面。
/// <para>
/// 【C# 语法知识点 - [FromBody] 特性】
/// [FromBody] 表示从请求体Request Body绑定参数。
/// 框架会自动把 JSON 请求体反序列化为 HwWeb 对象。
///
/// 对比 Java Spring Boot
/// Java: public Result add(@RequestBody HwWeb input)
/// C#: public async Task&lt;HwPortalAjaxResult&gt; Add([FromBody] HwWeb input)
///
/// 两者完全一样,都是 @RequestBody / [FromBody]。
/// </para>
/// </summary>
/// <param name="input">页面数据(从请求体 JSON 反序列化)</param>
/// <returns>Ajax 响应结果</returns>
[HttpPost]
[Idempotent]
public async Task<HwPortalAjaxResult> Add([FromBody] HwWeb input)
{
// ToAjax 是基类方法,根据影响行数返回成功或失败。
// 如果 rows > 0 返回成功,否则返回失败。
return ToAjax(await _service.InsertHwWeb(input));
}
/// <summary>
/// 更新页面。
/// </summary>
/// <param name="input">页面数据</param>
/// <returns>Ajax 响应结果</returns>
[HttpPut]
[Idempotent]
public async Task<HwPortalAjaxResult> Edit([FromBody] HwWeb input)
{
return ToAjax(await _service.UpdateHwWeb(input));
}
/// <summary>
/// 批量删除页面。
/// <para>
/// 【批量删除的设计】
/// 前端传来的删除请求通常是DELETE portal/hwWeb/1,2,3,4,5
/// 这里的 webIds 是 "1,2,3,4,5" 字符串,需要解析成数组。
///
/// ParseLongArray 是基类方法,把 "1,2,3" 解析成 [1, 2, 3]。
/// </para>
/// </summary>
/// <param name="webIds">逗号分隔的 ID 字符串</param>
/// <returns>Ajax 响应结果</returns>
[HttpDelete("{webIds}")]
[Idempotent]
public async Task<HwPortalAjaxResult> Remove(string webIds)
{
// ParseLongArray 把 "1,2,3" 解析成 [1, 2, 3]。
return ToAjax(await _service.DeleteHwWebByWebIds(ParseLongArray(webIds)));
}
/// <summary>
/// 查询页面列表(不分页)。
/// </summary>
/// <param name="input">查询参数</param>
/// <returns>Ajax 响应结果</returns>
[HttpGet("getHwWebList")]
public async Task<HwPortalAjaxResult> GetHwWebList([FromQuery] HwWeb input)
{
return Success(await _service.SelectHwWebList(input));
}
}