|
|
// ============================================================================
|
|
|
// 【文件说明】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<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 更简洁,是语言级别的支持。
|
|
|
/// </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<String, String> 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:长整数
|
|
|
/// - :guid:GUID
|
|
|
/// - :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<HwPortalAjaxResult> 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));
|
|
|
}
|
|
|
}
|