# hw-portal 官网模块说明(HwWeb / HwWeb1 / HwWebDocument / HwWebMenu / HwWebMenu1)
> 仅关注与 `HwWeb`、`HwWeb1`、`HwWebDocument`、`HwWebMenu`、`HwWebMenu1` 相关的代码逻辑,方便 AI 与技术人员统一阅读和分析。
## 0.后端代码注意事项
- hw-portal是微服务旧项目(springboot2+mybatis)的某个模块直接复制过来,现在是springboot3+MybatisPlus的单体新项目,需要将旧项目hw-portal模块的HwWeb、HwWeb1、HwWebDocument、HwWebMenu、HwWebMenu1的后端代码逻辑全部迁移到新项目的rfid-middleware\ruoyi-modules\hw-web模块中
- 注意只关注HwWeb、HwWeb1、HwWebDocument、HwWebMenu、HwWebMenu1!
- 要求实体类的字段类型都与旧项目一致!
- 注意前端的判断依据大多都是code!
- 接口必须与旧项目完全一致,以方便前端直接调用!
- 注意旧项目接口的权限控制已经全部注释掉了!
- 要求代码逻辑不变,尽量贴合现在新项目的springboot3+MybatisPlus!
- 代码的实现方式可以考虑MybatisPlus自带方法,比如说增删改查或者是逻辑删除,但是业务逻辑必须要一致!
- 数据库表结构中is_delete字段0表示未删除,1表示已删除
- 注意现在新项目的文件服务也已经与旧项目完全不一样了,需要匹配现有新项目!
- 数据库表结构与BaseEntity或者TenantEntity不一致,不应该继承,将相关字段填入在自己实体类中即可,注意@TableField(fill = FieldFill.INSERT)
---
## 1. 模块总览
- **页面 JSON 配置**
- 表:`hw_web`,实体:`HwWeb`
- 表:`hw_web1`,实体:`HwWeb1`
- 作用:存储官网页面的 JSON 配置(含中英文),`hw_web1` 在 `hw_web` 基础上增加了 `deviceId`、`typeId` 维度,实现「页面编码 + 设备 + 类型」组合唯一。
- **官网菜单**
- 表:`hw_web_menu`,实体:`HwWebMenu`
- 表:`hw_web_menu1`,实体:`HwWebMenu1`
- 作用:存储官网菜单树结构,支持多层级父子关系;其中 `HwWebMenu1` 相比 `HwWebMenu` 额外包含 `valuel` 字段(数据库列名为 `value`),用于绑定前端路由值或业务编码。
- **资料文件(带密钥保护)**
- 表:`hw_web_document`,实体:`HwWebDocument`
- 作用:存储资料文件的访问地址、所属页面编码、类型等,同时支持可选密钥保护(有密钥就必须验证才能拿到真实地址)。
- **软删除统一约定**
- 所有上述表都使用 `is_delete` 字段做逻辑删除:
- `'0'`:未删除
- `'1'`:已删除
- Mapper XML 中所有查询均默认附带 `and is_delete = '0'` 条件。
---
## 2. 页面 JSON:HwWeb / HwWeb1
### 2.1 实体结构
- **`HwWeb`(表:`hw_web`)**
- `webId`:主键 ID
- `webJson`:JSON 内容
- `webJsonString`:JSON 的字符串表示(便于展示或简单查询)
- `webCode`:页面编码,作为业务主键
- `isDelete`:逻辑删除标志
- `webJsonEnglish`:英文 JSON 字符串
- **`HwWeb1`(表:`hw_web1`)**
- 在 `HwWeb` 的基础上新增:
- `deviceId`:设备 ID
- `typeId`:类型 ID
- 唯一约束在服务层通过 `(webCode, deviceId, typeId)` 组合保证。
**字段类型与数据库映射:**
- `HwWeb`:
| 字段名 | Java 类型 | 数据库列名 | 说明 |
|--------|-----------|------------|------|
| `webId` | `Long` | `web_id` | 主键 ID |
| `webJson` | `String` | `web_json` | 页面 JSON 内容 |
| `webJsonString` | `String` | `web_json_string` | JSON 的字符串形式 |
| `webCode` | `Long` | `web_code` | 页面编码,业务主键 |
| `isDelete` | `String` | `is_delete` | 逻辑删除标志,`0` 未删,`1` 已删 |
| `webJsonEnglish` | `String` | `web_json_english` | 英文 JSON 字符串 |
- `HwWeb1`:
| 字段名 | Java 类型 | 数据库列名 | 说明 |
|--------|-----------|------------|------|
| `webId` | `Long` | `web_id` | 主键 ID |
| `webJson` | `String` | `web_json` | 页面 JSON 内容 |
| `webJsonString` | `String` | `web_json_string` | JSON 的字符串形式 |
| `webCode` | `Long` | `web_code` | 页面编码,业务主键 |
| `deviceId` | `Long` | `device_id` | 设备 ID,用于区分终端 |
| `typeId` | `Long` | `typeId` | 类型 ID,用于区分业务/场景 |
| `isDelete` | `String` | `is_delete` | 逻辑删除标志,`0` 未删,`1` 已删 |
| `webJsonEnglish` | `String` | `web_json_english` | 英文 JSON 字符串 |
### 2.2 Mapper & XML 行为
#### 2.2.1 `HwWebMapper` + `HwWebMapper.xml`
- **查询列表**:`selectHwWebList(HwWeb hwWeb)`
- 基础 SQL:`select web_id, web_json, ... from hw_web`
- 统一条件:`and is_delete = '0'`
- 支持按 `webId`、`webJson`、`webJsonString`、`webCode`、`webJsonEnglish` 等过滤。
- **单条查询**:`selectHwWebByWebcode(Long webCode)`
- 在基础 SQL 上追加:`where is_delete = '0' and web_code = #{webCode}`
- **插入**:`insertHwWeb(HwWeb hwWeb)`
- 按字段非空插入,并默认 `is_delete = '0'`
- **更新**:`updateHwWeb(HwWeb hwWeb)`
- 只允许更新 `web_json`、`web_json_string`、`web_json_english`,不更新 `web_code` 和主键。
- 更新条件为:`where web_code = #{webCode}`。
- **删除 / 批量删除**
- `deleteHwWebByWebId(Long webId)`:`update hw_web set is_delete = '1' where web_id = #{webId}`
- `deleteHwWebByWebIds(Long[] webIds)`:`update ... where web_id in (...)`,同样为逻辑删除。
#### 2.2.2 `HwWebMapper1` + `HwWebMapper1.xml`
- 行为与 `HwWebMapper` 类似,差异:
- 额外字段 `device_id`、`typeId`、`web_json_english`。
- `selectHwWebOne(HwWeb1 hwWeb1)`:按 `web_code + device_id + typeId` 精确查询一条记录。
- `updateHwWeb(HwWeb1 hwWeb1)` 的 where 条件为:
- `where web_code = #{webCode} and device_id = #{deviceId} and typeId = #{typeId}`
### 2.3 Service 接口与实现
#### 2.3.1 接口:`IHwWebService` / `IHwWebService1`
- 统一约定的方法:
- `selectHwWebByWebcode(Long webCode)`
- `selectHwWebList(...)`
- `insertHwWeb(...)`
- `updateHwWeb(...)`
- `deleteHwWebByWebIds(Long[] webIds)`
- `deleteHwWebByWebId(Long webId)`
- `IHwWebService1` 额外提供:`selectHwWebOne(HwWeb1 hwWeb1)`
#### 2.3.2 实现:`HwWebServiceImpl`(基于 `hw_web`)
- **查询**
- `selectHwWebByWebcode`:直接委托 Mapper,对 `webCode` 进行精确查询。
- `selectHwWebList`:委托 Mapper,按入参条件筛选列表。
- **新增**
- `insertHwWeb`:调用 Mapper 插入,未做额外业务校验。
- **更新(逻辑:版本化替换)**
- `updateHwWeb(HwWeb hwWeb)`:
- 构造 `codeWeb`,只设置 `webCode`。
- 调用 `selectHwWebList(codeWeb)` 查出该编码下所有未删除记录。
- 若存在:
- 提取这些记录的 `webId`,组装为数组。
- 调用 `deleteHwWebByWebIds` 对这些旧记录做「逻辑删除」。
- 为新纪录显式设置 `isDelete = "0"`。
- 调用 `insertHwWeb(hwWeb)` 插入一条**新的**记录(而不是更新原来的主键)。
- **效果**:
- 每次更新页面 JSON,都会为同一个 `webCode` 生成一个新版本的记录,同时逻辑删除旧版本。
- 可保留历史记录(在数据库中),但系统只会查询 `is_delete = '0'` 的最新版本。
- **删除**
- `deleteHwWebByWebIds` / `deleteHwWebByWebId`:通过 Mapper 将记录逻辑删除。
#### 2.3.3 实现:`HwWebServiceImpl1`(基于 `hw_web1`)
- 与 `HwWebServiceImpl` 基本一致,差异在于**唯一键逻辑**:
- 更新时构造 `codeWeb`:
- `codeWeb.setWebCode(hwWeb1.getWebCode())`;
- `codeWeb.setTypeId(hwWeb1.getTypeId())`;
- `codeWeb.setDeviceId(hwWeb1.getDeviceId())`;
- 调用 `selectHwWebList(codeWeb)` 按「页面编码 + 设备 + 类型」三元组过滤。
- 若存在老记录,同样调用 `deleteHwWebByWebIds` 做逻辑删除,然后插入一条新的记录,并设置 `isDelete = "0"`。
- 这样保证了 (`webCode`, `deviceId`, `typeId`) 组合在「未删除记录」中唯一,并且每次更新产生新版本。
### 2.4 Controller:`HwWebController`
基路径:`/hwWeb`
- **GET `/hwWeb/list`**
- 入参:`HwWeb`(作为查询条件)。
- 调用:`hwWebService.selectHwWebList(hwWeb)`。
- 返回:`TableDataInfo`(分页表格数据)。
- **POST `/hwWeb/export`**
- 导出 JSON 配置列表到 Excel,使用 `ExcelUtil`。
- **GET `/hwWeb/{webCode}`**
- 通过页面编码 `webCode` 查询单条 JSON 配置。
- **POST `/hwWeb`**
- 新增 JSON 配置,直接调用 `insertHwWeb`。
- **PUT `/hwWeb`**
- 更新 JSON 配置,调用 `updateHwWeb`:
- 实际为「逻辑删除旧版本 + 插入新版本」。
- **DELETE `/hwWeb/{webIds}`**
- 批量逻辑删除。
- **GET `/hwWeb/getHwWebList`**
- 返回 JSON 配置列表,包一层 `AjaxResult.success(...)`。
---
## 3. 官网菜单:HwWebMenu / HwWebMenu1
### 3.1 实体结构
两者都继承自 `TreeEntity`,支持树形结构字段:`ancestors`、`children` 等。
- **公共字段**(`HwWebMenu`、`HwWebMenu1` 均有):
- `webMenuId`:菜单主键 ID
- `parent`:父节点 ID(根节点为 `null` 或 `0`)
- `status`:状态
- `webMenuName`:菜单名称
- `tenantId`:租户 ID
- `webMenuPic`:图片地址
- `webMenuType`:菜单类型
- `isDelete`:逻辑删除标志
- `webMenuNameEnglish`:英文名称
- **`HwWebMenu1` 特有字段**
- `valuel`:对应数据库中的 `value` 字段(字段名有一处 `valuel`,应理解为 value),用于携带菜单值(如路由或业务键)。
**字段类型与数据库列映射:**
- `HwWebMenu`:
| 字段名 | Java 类型 | 数据库列名 | 说明 |
|--------|-----------|------------|------|
| `webMenuId` | `Long` | `web_menu_id` | 菜单主键 ID |
| `parent` | `Long` | `parent` | 父节点 ID(根节点为 0 或 NULL) |
| `status` | `String` | `status` | 状态 |
| `webMenuName` | `String` | `web_menu_name` | 菜单名称 |
| `tenantId` | `Long` | `tenant_id` | 租户 ID |
| `webMenuPic` | `String` | `web_menu__pic` | 图片地址 |
| `webMenuType` | `Long` | `web_menu_type` | 菜单类型 |
| `isDelete` | `String` | `is_delete` | 逻辑删除标志,`0` 未删,`1` 已删 |
| `webMenuNameEnglish` | `String` | `web_menu_name_english` | 英文菜单名称 |
- `HwWebMenu1`:
| 字段名 | Java 类型 | 数据库列名 | 说明 |
|--------|-----------|------------|------|
| `webMenuId` | `Long` | `web_menu_id` | 菜单主键 ID |
| `parent` | `Long` | `parent` | 父节点 ID(根节点为 0 或 NULL) |
| `status` | `String` | `status` | 状态 |
| `webMenuName` | `String` | `web_menu_name` | 菜单名称 |
| `tenantId` | `Long` | `tenant_id` | 租户 ID |
| `webMenuPic` | `String` | `web_menu__pic` | 图片地址 |
| `webMenuType` | `Long` | `web_menu_type` | 菜单类型 |
| `valuel` | `String` | `value` | 菜单绑定值(如路由、业务编码);实体字段名为 `valuel` |
| `isDelete` | `String` | `is_delete` | 逻辑删除标志,`0` 未删,`1` 已删 |
| `webMenuNameEnglish` | `String` | `web_menu_name_english` | 英文菜单名称 |
### 3.2 Mapper & XML 行为
#### 3.2.1 `HwWebMenuMapper` / `HwWebMenuMapper.xml`
- 查询列表 `selectHwWebMenuList(HwWebMenu hwWebMenu)`:
- 统一条件:`and is_delete = '0'`。
- 支持按 `parent`、`ancestors`、`status`、`webMenuName (like)`、`tenantId`、`webMenuPic`、`webMenuType`、`webMenuNameEnglish (like)` 等过滤。
- 单条查询 `selectHwWebMenuByWebMenuId(Long webMenuId)`:按主键 ID + `is_delete = '0'` 查询。
- 插入 / 更新 / 删除:
- 插入时按字段非空写入,并默认 `is_delete = '0'`。
- 更新仅更新业务字段,不改变 `is_delete`。
- 删除/批量删除采用 `update ... set is_delete = '1'` 实现软删除。
#### 3.2.2 `HwWebMenuMapper1` / `HwWebMenuMapper1.xml`
- 与 `HwWebMenuMapper` 基本一致,差异:
- 多了 `value` 字段(对应实体的 `valuel`)。
- 查询列表时可按 `value like` 模糊匹配。
### 3.3 Service:菜单树构建算法
`HwWebMenuServiceImpl` 与 `HwWebMenuServiceImpl1` 的结构几乎一致,只是实体类型和 Mapper 不同。核心逻辑:
#### 3.3.1 列表 & 新增/修改/删除
- `selectHwWebMenuList`:直接委托 Mapper,对应接口方法。
- **新增**:`insertHwWebMenu`:
- 调用 Mapper 插入,未做额外业务校验。
- **更新**:`updateHwWebMenu`:
- 调用 Mapper 更新,仅更新业务字段,不改变 `is_delete`。
- **删除**:`deleteHwWebMenuByWebMenuId` / `deleteHwWebMenuByWebMenuIds`:
- 调用 Mapper 删除/批量删除,实现软删除。
#### 3.3.2 构建菜单树:`selectMenuTree` + `buildWebMenuTree`
- **入口**:
- `selectMenuTree(HwWebMenu hwWebMenu)` / `selectMenuTree(HwWebMenu1 hwWebMenu1)`:
- 先查询平铺列表:`hwWebMenuMapper.selectHwWebMenuList(...)`。
- 调用 `buildWebMenuTree(List<...> menus)` 构造树结构。
- **`buildWebMenuTree` 逻辑**(两者完全类似):
1. 收集所有菜单的 `webMenuId` 到列表 `tempList`。
2. 遍历每个菜单 `menu`:
- 若满足以下任一条件,则视为根节点:
- `menu.getParent() == null`
- `menu.getParent() == 0L`
- `tempList` 中不包含 `menu.getParent()`(父节点不在当前集合中)
- 对于根节点调用 `recursionFn(menus, menu)` 递归设置子节点,并加入返回列表 `returnList`。
3. 若最终 `returnList` 为空(极端情况),则直接返回原始 `menus`。
- **`recursionFn` 递归设置子节点**:
- 通过 `getChildList(list, t)` 获取所有 `parent == t.webMenuId` 的子菜单列表。
- 调用 `t.setChildren(childList)` 建立树结构。
- 对每个子节点 `tChild`,若 `hasChild(list, tChild)` 返回 `true`,则继续递归。
- **`getChildList` / `hasChild`**:
- `getChildList` 遍历整张平铺列表,筛选 `parent` 等于当前节点 ID 的记录。
- `hasChild` 则判断 `getChildList` 返回列表是否为空。
- 使用 `StringUtils.isNotNull(n.getParent())` 判断父节点不为空,提高健壮性。
> 前端只需要调用 `/hwWebMenu/selectMenuTree` 或 `/hwWebMenu1/selectMenuTree`,即可得到带 `children` 字段的完整菜单树结构。
### 3.4 Controller:菜单接口
#### 3.4.1 旧菜单:`HwWebMenuController`(`/hwWebMenu`)
- **GET `/hwWebMenu/list`**:返回菜单列表(平铺)。
- **POST `/hwWebMenu/export`**:导出 Excel。
- **GET `/hwWebMenu/{webMenuId}`**:按 ID 查询明细。
- **POST `/hwWebMenu`**:新增菜单。
- **PUT `/hwWebMenu`**:修改菜单。
- **DELETE `/hwWebMenu/{webMenuIds}`**:批量删除(软删除)。
- **GET `/hwWebMenu/selectMenuTree`**:返回菜单树。
#### 3.4.2 新菜单:`HwWebMenuController1`(`/hwWebMenu1`)
- 与 `HwWebMenuController` 完全对齐,只是实体类型换成 `HwWebMenu1`,以及调用 `IHwWebMenuService1`。
---
## 4. 资料文件与密钥访问:HwWebDocument
### 4.1 实体结构:`HwWebDocument`(表:`hw_web_document`)
- `documentId`:主键(`String` 类型)。
- `tenantId`:租户 ID。
- `documentAddress`:真实文件存储地址(URL 或路径)。
- `webCode`:页面编码,用于和页面/菜单做关联。
- `secretKey`:访问密钥。
- 使用 `@JsonProperty(access = WRITE_ONLY)`,序列化时不会返回给前端。
- `json`:附加 JSON 信息(例如文件元数据)。
- `type`:文件类型。(如 pdf、doc 等)
- `isDelete`:逻辑删除标志。
- 衍生方法:`getHasSecret()` 返回是否配置了密钥(用于前端判断是否需要弹出输入密钥的对话框)。
**字段类型与数据库列映射:**
| 字段名 | Java 类型 | 数据库列名 | 说明 |
|--------|-----------|------------|------|
| `documentId` | `String` | `document_id` | 主键 ID(字符串类型) |
| `tenantId` | `Long` | `tenant_id` | 租户 ID |
| `documentAddress` | `String` | `document_address` | 文件存储地址(URL 或路径) |
| `webCode` | `String` | `web_code` | 页面编码,用于连表或关联页面 |
| `secretKey` | `String` | `secretKey` | 访问密钥(仅写入,序列化时不返回) |
| `json` | `String` | `json` | 附加 JSON 信息(如文件元数据) |
| `type` | `String` | `type` | 文件类型(如 pdf、doc) |
| `isDelete` | `String` | `is_delete` | 逻辑删除标志,`0` 未删,`1` 已删 |
### 4.2 Mapper & XML 行为
- 列表查询 `selectHwWebDocumentList`:
- 强制 `and is_delete = '0'`。
- 支持按 `documentId`、`tenantId`、`documentAddress`、`webCode`、`secretKey`、`json`、`type` 等过滤。
- 单条查询 `selectHwWebDocumentByDocumentId`:按主键 + `is_delete = '0'` 查询。
- 插入 `insertHwWebDocument`:
- 按字段非空插入,并默认 `is_delete = '0'`。
- 更新 `updateHwWebDocument` 的特殊处理:
- 对 `secretKey` 字段使用:
```xml
secretKey =
NULL
#{secretKey}
,
```
- 配合 Service 层的「null 转空串」逻辑,实现:
- **前端不传或传 null**:认为要清空数据库中的密钥(置为 `NULL`)。
- **前端传非空字符串**:更新为新的密钥。
- 删除 / 批量删除:
- `deleteHwWebDocumentByDocumentId` / `deleteHwWebDocumentByDocumentIds`:逻辑删除(`is_delete = '1'`)。
### 4.3 Service 实现:`HwWebDocumentServiceImpl`
- **查询/列表/删除**:直接委托 Mapper,对应接口方法。
- **新增**:`insertHwWebDocument`:
- 在插入前设置 `createTime = DateUtils.getNowDate()`。
- **更新**:`updateHwWebDocument`:
- 如果 `hwWebDocument.getSecretKey() == null`,则强制 `setSecretKey("")`:
- 触发 Mapper 中 `` 条件。
- 在 XML 中根据空串设置数据库列为 `NULL`,从而**清空密钥**。
- 若前端传入非空密钥字符串,则按正常更新覆盖原密钥。
- **密钥验证与安全地址获取**:`verifyAndGetDocumentAddress(String documentId, String providedKey)`
1. 根据 `documentId` 查询文档,若为空:抛出 `ServiceException("文件不存在")`。
2. 取出 `secretKey` 与 `documentAddress`。
3. 若 `secretKey` 为空或空白:
- 说明此文件不需要密钥,直接返回 `documentAddress`。
4. 若 `secretKey` 非空:
- 将入参 `providedKey` 去空格;若为空:抛出 `ServiceException("密钥不能为空")`。
- 若 `secretKey.trim().equals(trimmedProvided)`:返回 `documentAddress`。
- 否则抛出 `ServiceException("密钥错误")`。
> 因为这里抛出的都是 `ServiceException`,Controller 层可统一捕获并将 `e.getMessage()` 作为错误提示返回给前端。
### 4.4 Controller:`HwWebDocumentController`(`/hwWebDocument`)
- **GET `/hwWebDocument/list`**
- 调用 `startPage()` 分页。
- 查询列表后,对每个 `HwWebDocument doc` 做二次处理:
- `doc.setSecretKey(null)`:隐藏密钥字段。
- 若 `doc.getHasSecret()` 为 `true`:`doc.setDocumentAddress(null)`,隐藏真实文件地址,只暴露「是否加密」。
- 通过 `getDataTable(list)` 返回分页数据。
- **POST `/hwWebDocument/export`**
- 导出列表到 Excel。
- **GET `/hwWebDocument/{documentId}`**
- 查询单条记录,并同样隐藏密钥字段;如果有密钥,也会隐藏 `documentAddress`。
- **POST `/hwWebDocument`**
- 新增文档记录。
- **PUT `/hwWebDocument`**
- 修改文档记录,调用 `updateHwWebDocument`。通过 Service + XML 的联合逻辑实现「设置/修改/清空密钥」。
- **DELETE `/hwWebDocument/{documentIds}`**
- 批量逻辑删除。
- **POST `/hwWebDocument/getSecureDocumentAddress`**
- 入参:`SecureDocumentRequest`(包含 `documentId` 和 `providedKey`)。
- 调用 `hwWebDocumentService.verifyAndGetDocumentAddress(...)`:
- 成功:返回真实 `documentAddress`。
- 失败:捕获异常,返回 `error(e.getMessage())`,前端可展示友好提示(文件不存在 / 密钥不能为空 / 密钥错误等)。
---
## 5. 典型业务流程梳理
### 5.1 更新页面 JSON(HwWeb/HwWeb1)
1. 后台管理前端提交新的 JSON 配置到:
- `PUT /hwWeb`(基于 `hw_web`),或
- `PUT /hwWeb1` 对应的 Controller(若有,对应 `HwWebServiceImpl1`)。
2. Service 层根据页面编码(以及 `deviceId`、`typeId`)查询已存在记录。
3. 将旧记录全部逻辑删除(`is_delete = '1'`)。
4. 插入一条新记录,`isDelete = '0'`。
5. 前端访问页面时,只会根据编码查询到最新一条记录。
### 5.2 构建官网菜单树(HwWebMenu/HwWebMenu1)
1. 前端调用:
- 旧菜单:`GET /hwWebMenu/selectMenuTree`
- 新菜单:`GET /hwWebMenu1/selectMenuTree`
2. Service 调用 Mapper 查询 **平铺列表**(均为 `is_delete = '0'` 的记录)。
3. 通过 `buildWebMenuTree` 按 `parent` 字段递归构建树形结构:
- 识别所有根节点(`parent == null/0` 或父节点不在列表中)。
- 递归为每个节点挂接 `children`。
4. 返回给前端一个包含 `children` 的树形菜单结构,用于渲染导航栏或侧边栏。
### 5.3 受密钥保护的文件访问(HwWebDocument)
1. 后台配置文件记录时可以选择是否设置 `secretKey`:
- 不设置:文件公开可访问。
- 设置:文件地址将被后端隐藏,需要密钥校验。
2. 前端先调用 `GET /hwWebDocument/list` 或 `GET /hwWebDocument/{documentId}` 获取文件列表/详情:
- 只会看到 `hasSecret`(通过 `getHasSecret()` 间接体现),看不到真实地址。
3. 用户在前端输入密钥后,前端调用:
- `POST /hwWebDocument/getSecureDocumentAddress`,携带 `documentId` 与 `providedKey`。
4. Service 层校验密钥:
- 无密钥:直接返回地址。
- 密钥为空:抛错 `"密钥不能为空"`。
- 密钥不匹配:抛错 `"密钥错误"`。
5. 前端拿到真实地址后,可发起真正的文件下载/打开请求。
---
## 6. 核心源码(Controller + Service 实现)
> 以下为与 `HwWeb / HwWeb1 / HwWebDocument / HwWebMenu / HwWebMenu1` 强相关的控制层和服务实现类的完整源码,方便 AI 与人工检索、分析。实体类、接口与 Mapper XML 已在上文详细说明,可在 IDE 中直接定位查看原文件。
### 6.1 Controller 源码
#### 6.1.1 `HwWebController`
```java
package com.ruoyi.portal.controller;
import java.util.List;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.portal.domain.HwWeb1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.portal.domain.HwWeb;
import com.ruoyi.portal.service.IHwWebService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;
/**
* haiwei官网jsonController
*
* @author ruoyi
* @date 2025-08-18
*/
@RestController
@RequestMapping("/hwWeb")
public class HwWebController extends BaseController
{
@Autowired
private IHwWebService hwWebService;
/**
* 查询haiwei官网json列表
*/
//@RequiresPermissions("portalhwWeb:list")
@GetMapping("/list")
public TableDataInfo list(HwWeb hwWeb)
{
// startPage();
List list = hwWebService.selectHwWebList(hwWeb);
return getDataTable(list);
}
/**
* 导出haiwei官网json列表
*/
//@RequiresPermissions("portalhwWeb:export")
//@Log(title = "haiwei官网json", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, HwWeb hwWeb)
{
List list = hwWebService.selectHwWebList(hwWeb);
ExcelUtil util = new ExcelUtil(HwWeb.class);
util.exportExcel(response, list, "haiwei官网json数据");
}
/**
* 获取haiwei官网json详细信息
*/
//@RequiresPermissions("portalhwWeb:query")
@GetMapping(value = "/{webCode}")
public AjaxResult getInfo(@PathVariable("webCode") Long webCode)
{
return success(hwWebService.selectHwWebByWebcode(webCode));
}
/**
* 新增haiwei官网json
*/
//@RequiresPermissions("portalhwWeb:add")
//@Log(title = "haiwei官网json", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody HwWeb hwWeb)
{
return toAjax(hwWebService.insertHwWeb(hwWeb));
}
/**
* 修改haiwei官网json
*/
//@RequiresPermissions("portalhwWeb:edit")
//@Log(title = "haiwei官网json", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody HwWeb hwWeb)
{
int i = hwWebService.updateHwWeb(hwWeb);
return toAjax(i);
}
/**
* 删除haiwei官网json
*/
//@RequiresPermissions("portalhwWeb:remove")
//@Log(title = "haiwei官网json", businessType = BusinessType.DELETE)
@DeleteMapping("/{webIds}")
public AjaxResult remove(@PathVariable Long[] webIds)
{
return toAjax(hwWebService.deleteHwWebByWebIds(webIds));
}
@GetMapping("/getHwWebList")
public AjaxResult getHwWebList(HwWeb HwWeb)
{
return success(hwWebService.selectHwWebList(HwWeb)) ;
}
}
```
#### 6.1.2 `HwWebMenuController`
```java
package com.ruoyi.portal.controller;
import java.util.List;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.portal.domain.HwWebMenu;
import com.ruoyi.portal.service.IHwWebMenuService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
/**
* haiwei官网菜单Controller
*
* @author zch
* @date 2025-08-18
*/
@RestController
@RequestMapping("/hwWebMenu")
public class HwWebMenuController extends BaseController
{
@Autowired
private IHwWebMenuService hwWebMenuService;
/**
* 查询haiwei官网菜单列表
*/
//@RequiresPermissions("portalhwWebMenu:list")
@GetMapping("/list")
public AjaxResult list(HwWebMenu hwWebMenu)
{
List list = hwWebMenuService.selectHwWebMenuList(hwWebMenu);
return success(list);
}
/**
* 导出haiwei官网菜单列表
*/
//@RequiresPermissions("portalhwWebMenu:export")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, HwWebMenu hwWebMenu)
{
List list = hwWebMenuService.selectHwWebMenuList(hwWebMenu);
ExcelUtil util = new ExcelUtil(HwWebMenu.class);
util.exportExcel(response, list, "haiwei官网菜单数据");
}
/**
* 获取haiwei官网菜单详细信息
*/
//@RequiresPermissions("portalhwWebMenu:query")
@GetMapping(value = "/{webMenuId}")
public AjaxResult getInfo(@PathVariable("webMenuId") Long webMenuId)
{
return success(hwWebMenuService.selectHwWebMenuByWebMenuId(webMenuId));
}
/**
* 新增haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:add")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody HwWebMenu hwWebMenu)
{
return toAjax(hwWebMenuService.insertHwWebMenu(hwWebMenu));
}
/**
* 修改haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:edit")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody HwWebMenu hwWebMenu)
{
return toAjax(hwWebMenuService.updateHwWebMenu(hwWebMenu));
}
/**
* 删除haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:remove")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.DELETE)
@DeleteMapping("/{webMenuIds}")
public AjaxResult remove(@PathVariable Long[] webMenuIds)
{
return toAjax(hwWebMenuService.deleteHwWebMenuByWebMenuIds(webMenuIds));
}
/**
* 获取菜单树列表
*/
@GetMapping("/selectMenuTree")
public AjaxResult selectMenuTree(HwWebMenu hwWebMenu){
return success(hwWebMenuService.selectMenuTree(hwWebMenu));
}
}
```
#### 6.1.3 `HwWebMenuController1`
```java
package com.ruoyi.portal.controller;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.portal.domain.HwWebMenu1;
import com.ruoyi.portal.service.IHwWebMenuService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* haiwei官网菜单Controller
*
* @author zch
* @date 2025-08-18
*/
@RestController
@RequestMapping("/hwWebMenu1")
public class HwWebMenuController1 extends BaseController
{
@Autowired
private IHwWebMenuService1 hwWebMenuService1;
/**
* 查询haiwei官网菜单列表
*/
//@RequiresPermissions("portalhwWebMenu:list")
@GetMapping("/list")
public AjaxResult list(HwWebMenu1 hwWebMenu1)
{
List list = hwWebMenuService1.selectHwWebMenuList(hwWebMenu1);
return success(list);
}
/**
* 导出haiwei官网菜单列表
*/
//@RequiresPermissions("portalhwWebMenu:export")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, HwWebMenu1 hwWebMenu1)
{
List list = hwWebMenuService1.selectHwWebMenuList(hwWebMenu1);
ExcelUtil util = new ExcelUtil(HwWebMenu1.class);
util.exportExcel(response, list, "haiwei官网菜单数据");
}
/**
* 获取haiwei官网菜单详细信息
*/
//@RequiresPermissions("portalhwWebMenu:query")
@GetMapping(value = "/{webMenuId}")
public AjaxResult getInfo(@PathVariable("webMenuId") Long webMenuId)
{
return success(hwWebMenuService1.selectHwWebMenuByWebMenuId(webMenuId));
}
/**
* 新增haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:add")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody HwWebMenu1 hwWebMenu1)
{
return toAjax(hwWebMenuService1.insertHwWebMenu(hwWebMenu1));
}
/**
* 修改haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:edit")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody HwWebMenu1 hwWebMenu1)
{
return toAjax(hwWebMenuService1.updateHwWebMenu(hwWebMenu1));
}
/**
* 删除haiwei官网菜单
*/
//@RequiresPermissions("portalhwWebMenu:remove")
//@Log(title = "haiwei官网菜单", businessType = BusinessType.DELETE)
@DeleteMapping("/{webMenuIds}")
public AjaxResult remove(@PathVariable Long[] webMenuIds)
{
return toAjax(hwWebMenuService1.deleteHwWebMenuByWebMenuIds(webMenuIds));
}
/**
* 获取菜单树列表
*/
@GetMapping("/selectMenuTree")
public AjaxResult selectMenuTree(HwWebMenu1 hwWebMenu1){
return success(hwWebMenuService1.selectMenuTree(hwWebMenu1));
}
}
```
#### 6.1.4 `HwWebDocumentController`
```java
package com.ruoyi.portal.controller;
import java.util.List;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.portal.domain.SecureDocumentRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.portal.domain.HwWebDocument;
import com.ruoyi.portal.service.IHwWebDocumentService;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.page.TableDataInfo;
/**
* Hw资料文件Controller
*
* @author zch
* @date 2025-09-22
*/
@RestController
@RequestMapping("/hwWebDocument")
public class HwWebDocumentController extends BaseController
{
@Autowired
private IHwWebDocumentService hwWebDocumentService;
/**
* 查询Hw资料文件列表
*/
// @RequiresPermissions("portal:hwWebDocument:list")
@GetMapping("/list")
public TableDataInfo list(HwWebDocument hwWebDocument)
{
startPage();
List list = hwWebDocumentService.selectHwWebDocumentList(hwWebDocument);
for (HwWebDocument doc : list) {
// 隐藏密钥,若设置了密钥则隐藏文件地址
doc.setSecretKey(null);
if (doc.getHasSecret()) {
doc.setDocumentAddress(null);
}
}
return getDataTable(list);
}
/**
* 导出Hw资料文件列表
*/
// @RequiresPermissions("portal:hwWebDocument:export")
//@Log(title = "Hw资料文件", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, HwWebDocument hwWebDocument)
{
List list = hwWebDocumentService.selectHwWebDocumentList(hwWebDocument);
ExcelUtil util = new ExcelUtil(HwWebDocument.class);
util.exportExcel(response, list, "Hw资料文件数据");
}
/**
* 获取Hw资料文件详细信息
*/
// @RequiresPermissions("portal:hwWebDocument:query")
@GetMapping(value = "/{documentId}")
public AjaxResult getInfo(@PathVariable("documentId") String documentId)
{
HwWebDocument doc = hwWebDocumentService.selectHwWebDocumentByDocumentId(documentId);
if (doc != null) {
// 隐藏密钥,若设置了密钥则隐藏文件地址
doc.setSecretKey(null);
if (doc.getHasSecret()) {
doc.setDocumentAddress(null);
}
}
return success(doc);
}
/**
* 新增Hw资料文件
*/
// @RequiresPermissions("portal:hwWebDocument:add")
//@Log(title = "Hw资料文件", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody HwWebDocument hwWebDocument)
{
return toAjax(hwWebDocumentService.insertHwWebDocument(hwWebDocument));
}
/**
* 修改Hw资料文件
*/
// @RequiresPermissions("portal:hwWebDocument:edit")
//@Log(title = "Hw资料文件", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody HwWebDocument hwWebDocument)
{
System.out.println(hwWebDocument.getSecretKey());
return toAjax(hwWebDocumentService.updateHwWebDocument(hwWebDocument));
}
/**
* 删除Hw资料文件
*/
// @RequiresPermissions("portal:hwWebDocument:remove")
//@Log(title = "Hw资料文件", businessType = BusinessType.DELETE)
@DeleteMapping("/{documentIds}")
public AjaxResult remove(@PathVariable String[] documentIds)
{
return toAjax(hwWebDocumentService.deleteHwWebDocumentByDocumentIds(documentIds));
}
/**
* 获取安全文件地址
*/
// @RequiresPermissions("portal:hwWebDocument:query")
//@Log(title = "获取安全文件地址", businessType = BusinessType.OTHER)
@PostMapping("/getSecureDocumentAddress")
public AjaxResult getSecureDocumentAddress(@RequestBody SecureDocumentRequest request)
{
try {
String address = hwWebDocumentService.verifyAndGetDocumentAddress(request.getDocumentId(), request.getProvidedKey());
return success(address);
} catch (Exception e) {
return error(e.getMessage());
}
}
}
```
### 6.2 Service 实现源码
#### 6.2.1 `HwWebServiceImpl`
```java
package com.ruoyi.portal.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.portal.mapper.HwWebMapper;
import com.ruoyi.portal.domain.HwWeb;
import com.ruoyi.portal.service.IHwWebService;
import org.springframework.transaction.annotation.Transactional;
/**
* haiwei官网jsonService业务层处理
*
* @author ruoyi
* @date 2025-08-18
*/
@Service
public class HwWebServiceImpl implements IHwWebService
{
@Autowired
private HwWebMapper hwWebMapper;
/**
* 查询haiwei官网json
*
* @param webId haiwei官网json主键
* @return haiwei官网json
*/
@Override
public HwWeb selectHwWebByWebcode(Long webCode)
{
HwWeb hwWeb = hwWebMapper.selectHwWebByWebcode(webCode);
return hwWeb;
}
/**
* 查询haiwei官网json列表
*
* @param hwWeb haiwei官网json
* @return haiwei官网json
*/
@Override
public List selectHwWebList(HwWeb hwWeb)
{
return hwWebMapper.selectHwWebList(hwWeb);
}
/**
* 新增haiwei官网json
*
* @param hwWeb haiwei官网json
* @return 结果
*/
@Override
public int insertHwWeb(HwWeb hwWeb)
{
return hwWebMapper.insertHwWeb(hwWeb);
}
/**
* 修改haiwei官网json
*
* @param hwWeb haiwei官网json
* @return 结果
*/
@Override
@Transactional( rollbackFor = Exception.class )
public int updateHwWeb(HwWeb hwWeb)
{
HwWeb codeWeb = new HwWeb();
//编号唯一
codeWeb.setWebCode(hwWeb.getWebCode());
List exists = hwWebMapper.selectHwWebList(codeWeb);
if (!exists.isEmpty()) {
Long[] webIds = exists.stream().map(HwWeb::getWebId).toArray(Long[]::new);
//逻辑删除旧纪录
hwWebMapper.deleteHwWebByWebIds(webIds);
}
// 插入新记录,避免复用旧主键
// hwWeb.setWebId(null);
hwWeb.setIsDelete("0");
return hwWebMapper.insertHwWeb(hwWeb);
}
/**
* 批量删除haiwei官网json
*
* @param webIds 需要删除的haiwei官网json主键
* @return 结果
*/
@Override
public int deleteHwWebByWebIds(Long[] webIds)
{
return hwWebMapper.deleteHwWebByWebIds(webIds);
}
/**
* 删除haiwei官网json信息
*
* @param webId haiwei官网json主键
* @return 结果
*/
@Override
public int deleteHwWebByWebId(Long webId)
{
return hwWebMapper.deleteHwWebByWebId(webId);
}
}
```
#### 6.2.2 `HwWebServiceImpl1`
```java
package com.ruoyi.portal.service.impl;
import com.ruoyi.portal.mapper.HwWebMapper1;
import com.ruoyi.portal.service.IHwWebService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import com.ruoyi.portal.domain.HwWeb1;
import com.ruoyi.portal.domain.HwWeb;
import org.springframework.transaction.annotation.Transactional;
/**
* haiwei官网jsonService业务层处理
*
* @author ruoyi
* @date 2025-08-18
*/
@Service
public class HwWebServiceImpl1 implements IHwWebService1
{
@Autowired
private HwWebMapper1 hwWebMapper1;
/**
* 查询haiwei官网json
*
* @param webId haiwei官网json主键
* @return haiwei官网json
*/
@Override
public HwWeb1 selectHwWebByWebcode(Long webCode)
{
return hwWebMapper1.selectHwWebByWebcode(webCode);
}
@Override
public HwWeb1 selectHwWebOne(HwWeb1 hwWeb1)
{
return hwWebMapper1.selectHwWebOne(hwWeb1);
}
/**
* 查询haiwei官网json列表
*
* @param HwWeb1 haiwei官网json
* @return haiwei官网json
*/
@Override
public List selectHwWebList(HwWeb1 hwWeb1)
{
return hwWebMapper1.selectHwWebList(hwWeb1);
}
/**
* 新增haiwei官网json
*
* @param HwWeb1 haiwei官网json
* @return 结果
*/
@Override
public int insertHwWeb(HwWeb1 hwWeb1)
{
return hwWebMapper1.insertHwWeb(hwWeb1);
}
/**
* 修改haiwei官网json
*
* @param HwWeb1 haiwei官网json
* @return 结果
*/
@Override
@Transactional( rollbackFor = Exception.class )
public int updateHwWeb(HwWeb1 hwWeb1)
{
HwWeb1 codeWeb = new HwWeb1();
// 编号、typeid、deviceID保证唯一
codeWeb.setWebCode(hwWeb1.getWebCode());
codeWeb.setTypeId(hwWeb1.getTypeId());
codeWeb.setDeviceId(hwWeb1.getDeviceId());
List exists = hwWebMapper1.selectHwWebList(codeWeb);
if (!exists.isEmpty()) {
Long[] webIds = exists.stream().map(HwWeb1::getWebId).toArray(Long[]::new);
//逻辑删除旧纪录
hwWebMapper1.deleteHwWebByWebIds(webIds);
}
// 插入新记录,避免复用旧主键
// hwWeb1.setWebId(null);
hwWeb1.setIsDelete("0");
return hwWebMapper1.insertHwWeb(hwWeb1);
}
/**
* 批量删除haiwei官网json
*
* @param webIds 需要删除的haiwei官网json主键
* @return 结果
*/
@Override
public int deleteHwWebByWebIds(Long[] webIds)
{
return hwWebMapper1.deleteHwWebByWebIds(webIds);
}
/**
* 删除haiwei官网json信息
*
* @param webId haiwei官网json主键
* @return 结果
*/
@Override
public int deleteHwWebByWebId(Long webId)
{
return hwWebMapper1.deleteHwWebByWebId(webId);
}
}
```
#### 6.2.3 `HwWebMenuServiceImpl`
```java
package com.ruoyi.portal.service.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.portal.domain.HwProductInfoDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.portal.mapper.HwWebMenuMapper;
import com.ruoyi.portal.domain.HwWebMenu;
import com.ruoyi.portal.service.IHwWebMenuService;
/**
* haiwei官网菜单Service业务层处理
*
* @author zch
* @date 2025-08-18
*/
@Service
public class HwWebMenuServiceImpl implements IHwWebMenuService
{
@Autowired
private HwWebMenuMapper hwWebMenuMapper;
/**
* 查询haiwei官网菜单
*
* @param webMenuId haiwei官网菜单主键
* @return haiwei官网菜单
*/
@Override
public HwWebMenu selectHwWebMenuByWebMenuId(Long webMenuId)
{
return hwWebMenuMapper.selectHwWebMenuByWebMenuId(webMenuId);
}
/**
* 查询haiwei官网菜单列表
*
* @param hwWebMenu haiwei官网菜单
* @return haiwei官网菜单
*/
@Override
public List selectHwWebMenuList(HwWebMenu hwWebMenu)
{
List hwWebMenus = hwWebMenuMapper.selectHwWebMenuList(hwWebMenu);
return hwWebMenus;
}
/**
* 获取菜单树列表
*/
@Override
public List selectMenuTree(HwWebMenu hwWebMenu)
{
List hwWebMenus = hwWebMenuMapper.selectHwWebMenuList(hwWebMenu);
return buildWebMenuTree(hwWebMenus);
}
/**
* 新增haiwei官网菜单
*
* @param hwWebMenu haiwei官网菜单
* @return 结果
*/
@Override
public int insertHwWebMenu(HwWebMenu hwWebMenu)
{
return hwWebMenuMapper.insertHwWebMenu(hwWebMenu);
}
/**
* 修改haiwei官网菜单
*
* @param hwWebMenu haiwei官网菜单
* @return 结果
*/
@Override
public int updateHwWebMenu(HwWebMenu hwWebMenu)
{
return hwWebMenuMapper.updateHwWebMenu(hwWebMenu);
}
/**
* 批量删除haiwei官网菜单
*
* @param webMenuIds 需要删除的haiwei官网菜单主键
* @return 结果
*/
@Override
public int deleteHwWebMenuByWebMenuIds(Long[] webMenuIds)
{
return hwWebMenuMapper.deleteHwWebMenuByWebMenuIds(webMenuIds);
}
/**
* 删除haiwei官网菜单信息
*
* @param webMenuId haiwei官网菜单主键
* @return 结果
*/
@Override
public int deleteHwWebMenuByWebMenuId(Long webMenuId)
{
return hwWebMenuMapper.deleteHwWebMenuByWebMenuId(webMenuId);
}
/**
* 构建前端所需要树结构(根据传入的平铺菜单列表构造树)
*
* @param menus 菜单列表
* @return 树结构列表
*/
public List buildWebMenuTree(List menus) {
List returnList = new ArrayList<>();
List tempList = menus.stream().map(HwWebMenu::getWebMenuId).collect(Collectors.toList());
for (HwWebMenu menu : menus) {
// 如果是顶级节点(parent为null、0或者不在当前列表中), 遍历该父节点的所有子节点
if (menu.getParent() == null || menu.getParent() == 0L || !tempList.contains(menu.getParent())) {
recursionFn(menus, menu);
returnList.add(menu);
}
}
if (returnList.isEmpty()) {
returnList = menus;
}
return returnList;
}
/**
* 递归设置子节点
*/
private void recursionFn(List list, HwWebMenu t) {
// 得到子节点列表
List childList = getChildList(list, t);
t.setChildren(childList);
for (HwWebMenu tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
/**
* 得到子节点列表
*/
private List getChildList(List list, HwWebMenu t) {
List tlist = new ArrayList();
Iterator it = list.iterator();
while (it.hasNext()) {
HwWebMenu n = it.next();
if (StringUtils.isNotNull(n.getParent()) && n.getParent().longValue() == t.getWebMenuId().longValue()) {
tlist.add(n);
}
}
return tlist;
}
/**
* 判断是否有子节点
*/
private boolean hasChild(List list, HwWebMenu t) {
return !getChildList(list, t).isEmpty();
}
}
```
#### 6.2.4 `HwWebMenuServiceImpl1`
```java
package com.ruoyi.portal.service.impl;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.portal.domain.HwWebMenu1;
import com.ruoyi.portal.mapper.HwWebMenuMapper1;
import com.ruoyi.portal.service.IHwWebMenuService1;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* haiwei官网菜单Service业务层处理
*
* @author zch
* @date 2025-08-18
*/
@Service
public class HwWebMenuServiceImpl1 implements IHwWebMenuService1
{
@Autowired
private HwWebMenuMapper1 HwWebMenuMapper1;
/**
* 查询haiwei官网菜单
*
* @param webMenuId haiwei官网菜单主键
* @return haiwei官网菜单
*/
@Override
public HwWebMenu1 selectHwWebMenuByWebMenuId(Long webMenuId)
{
return HwWebMenuMapper1.selectHwWebMenuByWebMenuId(webMenuId);
}
/**
* 查询haiwei官网菜单列表
*
* @param HwWebMenu1 haiwei官网菜单
* @return haiwei官网菜单
*/
@Override
public List selectHwWebMenuList(HwWebMenu1 HwWebMenu1)
{
List hwWebMenus = HwWebMenuMapper1.selectHwWebMenuList(HwWebMenu1);
return hwWebMenus;
}
/**
* 获取菜单树列表
*/
@Override
public List selectMenuTree(HwWebMenu1 HwWebMenu1)
{
List hwWebMenus = HwWebMenuMapper1.selectHwWebMenuList(HwWebMenu1);
return buildWebMenuTree(hwWebMenus);
}
/**
* 新增haiwei官网菜单
*
* @param HwWebMenu1 haiwei官网菜单
* @return 结果
*/
@Override
public int insertHwWebMenu(HwWebMenu1 HwWebMenu1)
{
return HwWebMenuMapper1.insertHwWebMenu(HwWebMenu1);
}
/**
* 修改haiwei官网菜单
*
* @param HwWebMenu1 haiwei官网菜单
* @return 结果
*/
@Override
public int updateHwWebMenu(HwWebMenu1 HwWebMenu1)
{
return HwWebMenuMapper1.updateHwWebMenu(HwWebMenu1);
}
/**
* 批量删除haiwei官网菜单
*
* @param webMenuIds 需要删除的haiwei官网菜单主键
* @return 结果
*/
@Override
public int deleteHwWebMenuByWebMenuIds(Long[] webMenuIds)
{
return HwWebMenuMapper1.deleteHwWebMenuByWebMenuIds(webMenuIds);
}
/**
* 删除haiwei官网菜单信息
*
* @param webMenuId haiwei官网菜单主键
* @return 结果
*/
@Override
public int deleteHwWebMenuByWebMenuId(Long webMenuId)
{
return HwWebMenuMapper1.deleteHwWebMenuByWebMenuId(webMenuId);
}
/**
* 构建前端所需要树结构(根据传入的平铺菜单列表构造树)
*
* @param menus 菜单列表
* @return 树结构列表
*/
public List buildWebMenuTree(List menus) {
List returnList = new ArrayList<>();
List tempList = menus.stream().map(HwWebMenu1::getWebMenuId).collect(Collectors.toList());
for (HwWebMenu1 menu : menus) {
// 如果是顶级节点(parent为null、0或者不在当前列表中), 遍历该父节点的所有子节点
if (menu.getParent() == null || menu.getParent() == 0L || !tempList.contains(menu.getParent())) {
recursionFn(menus, menu);
returnList.add(menu);
}
}
if (returnList.isEmpty()) {
returnList = menus;
}
return returnList;
}
/**
* 递归设置子节点
*/
private void recursionFn(List list, HwWebMenu1 t) {
// 得到子节点列表
List childList = getChildList(list, t);
t.setChildren(childList);
for (HwWebMenu1 tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
/**
* 得到子节点列表
*/
private List getChildList(List list, HwWebMenu1 t) {
List tlist = new ArrayList();
Iterator it = list.iterator();
while (it.hasNext()) {
HwWebMenu1 n = it.next();
if (StringUtils.isNotNull(n.getParent()) && n.getParent().longValue() == t.getWebMenuId().longValue()) {
tlist.add(n);
}
}
return tlist;
}
/**
* 判断是否有子节点
*/
private boolean hasChild(List list, HwWebMenu1 t) {
return !getChildList(list, t).isEmpty();
}
}
```
#### 6.2.5 `HwWebDocumentServiceImpl`
```java
package com.ruoyi.portal.service.impl;
import java.util.List;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.portal.mapper.HwWebDocumentMapper;
import com.ruoyi.portal.domain.HwWebDocument;
import com.ruoyi.portal.service.IHwWebDocumentService;
/**
* Hw资料文件Service业务层处理
*
* @author zch
* @date 2025-09-22
*/
@Service
public class HwWebDocumentServiceImpl implements IHwWebDocumentService
{
@Autowired
private HwWebDocumentMapper hwWebDocumentMapper;
/**
* 查询Hw资料文件
*
* @param documentId Hw资料文件主键
* @return Hw资料文件
*/
@Override
public HwWebDocument selectHwWebDocumentByDocumentId(String documentId)
{
return hwWebDocumentMapper.selectHwWebDocumentByDocumentId(documentId);
}
/**
* 查询Hw资料文件列表
*
* @param hwWebDocument Hw资料文件
* @return Hw资料文件
*/
@Override
public List selectHwWebDocumentList(HwWebDocument hwWebDocument)
{
return hwWebDocumentMapper.selectHwWebDocumentList(hwWebDocument);
}
/**
* 新增Hw资料文件
*
* @param hwWebDocument Hw资料文件
* @return 结果
*/
@Override
public int insertHwWebDocument(HwWebDocument hwWebDocument)
{
hwWebDocument.setCreateTime(DateUtils.getNowDate());
return hwWebDocumentMapper.insertHwWebDocument(hwWebDocument);
}
/**
* 修改Hw资料文件
*
* @param hwWebDocument Hw资料文件
* @return 结果
*/
@Override
public int updateHwWebDocument(HwWebDocument hwWebDocument)
{
// 特殊处理 secretKey:前端不传或传 null 时清空数据库密钥
// 将 null 转换为空字符串,触发 Mapper 更新条件
if (hwWebDocument.getSecretKey() == null) {
hwWebDocument.setSecretKey("");
}
return hwWebDocumentMapper.updateHwWebDocument(hwWebDocument);
}
/**
* 批量删除Hw资料文件
*
* @param documentIds 需要删除的Hw资料文件主键
* @return 结果
*/
@Override
public int deleteHwWebDocumentByDocumentIds(String[] documentIds)
{
return hwWebDocumentMapper.deleteHwWebDocumentByDocumentIds(documentIds);
}
/**
* 删除Hw资料文件信息
*
* @param documentId Hw资料文件主键
* @return 结果
*/
@Override
public int deleteHwWebDocumentByDocumentId(String documentId)
{
return hwWebDocumentMapper.deleteHwWebDocumentByDocumentId(documentId);
}
@Override
public String verifyAndGetDocumentAddress(String documentId, String providedKey) throws Exception {
HwWebDocument document = selectHwWebDocumentByDocumentId(documentId);
if (document == null) {
throw new ServiceException("文件不存在");
}
String secretKey = document.getSecretKey();
String address = document.getDocumentAddress();
// 若数据库密钥为空,则直接返回文件地址
if (secretKey == null || secretKey.trim().isEmpty()) {
return address;
}
// 若密钥不为空,则需要验证提供的密钥是否相等
String trimmedProvided = providedKey == null ? null : providedKey.trim();
if (trimmedProvided == null || trimmedProvided.isEmpty()) {
throw new ServiceException("密钥不能为空");
}
if (secretKey.trim().equals(trimmedProvided)) {
return address;
} else {
throw new ServiceException("密钥错误");
}
}
```
### 6.5 Mapper XML 源码
> 本节保留 5 个模块对应的 MyBatis Mapper XML 全量源码,便于直接查看 SQL、结果映射与软删除实现细节。
#### 6.5.1 `HwWebMapper.xml`
```xml
select web_id, web_json, web_json_string, web_code,
web_json_english,
is_delete
from hw_web
insert into hw_web
web_json,
web_json_string,
web_code,
web_json_english,
is_delete,
#{webJson},
#{webJsonString},
#{webCode},
#{webJsonEnglish},
#{isDelete},
'0',
update hw_web
web_json = #{webJson},
web_json_string = #{webJsonString},
web_json_english = #{webJsonEnglish},
where web_code = #{webCode}
update hw_web set is_delete = '1' where web_id = #{webId}
update hw_web set is_delete = '1' where web_id in
#{webId}
```
#### 6.5.2 `HwWebMapper1.xml`
```xml
select web_id, web_json, web_json_string, web_code,
device_id, typeId, web_json_english,
is_delete
from hw_web1
insert into hw_web1
web_json,
web_json_string,
web_code,
device_id,
typeId,
web_json_english,
is_delete,
#{webJson},
#{webJsonString},
#{webCode},
#{deviceId},
#{typeId},
#{webJsonEnglish},
#{isDelete},
'0',
update hw_web1
web_json = #{webJson},
web_json_string = #{webJsonString},
web_json_english = #{webJsonEnglish},
where web_code = #{webCode}
and device_id = #{deviceId}
and typeId = #{typeId}
update hw_web1 set is_delete = '1' where web_id = #{webId}
update hw_web1 set is_delete = '1' where web_id in
#{webId}
```
#### 6.5.3 `HwWebDocumentMapper.xml`
```xml
select document_id, tenant_id, document_address, create_time, web_code, secretKey ,
json, type,
is_delete
from hw_web_document
insert into hw_web_document
document_id,
tenant_id,
document_address,
create_time,
web_code,
secretKey,
json,
type,
is_delete,
#{documentId},
#{tenantId},
#{documentAddress},
#{createTime},
#{webCode},
#{secretKey},
#{json},
#{type},
#{isDelete},
'0',
update hw_web_document
document_id = #{documentId},
tenant_id = #{tenantId},
document_address = #{documentAddress},
create_time = #{createTime},
web_code = #{webCode},
secretKey =
NULL
#{secretKey}
,
json = #{json},
type = #{type},
where document_id = #{documentId}
update hw_web_document set is_delete = '1' where document_id = #{documentId}
update hw_web_document set is_delete = '1' where document_id in
#{documentId}
```
#### 6.5.4 `HwWebMenuMapper.xml`
```xml
```
#### 6.5.5 `HwWebMenuMapper1.xml`
```xml