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