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.

2235 lines
80 KiB
Markdown

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.

# 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. 页面 JSONHwWeb / 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
<if test="secretKey != null">
secretKey =
<choose>
<when test="secretKey == ''">NULL</when>
<otherwise>#{secretKey}</otherwise>
</choose>,
</if>
```
- 配合 Service 层的「null 转空串」逻辑,实现:
- **前端不传或传 null**:认为要清空数据库中的密钥(置为 `NULL`)。
- **前端传非空字符串**:更新为新的密钥。
- 删除 / 批量删除:
- `deleteHwWebDocumentByDocumentId` / `deleteHwWebDocumentByDocumentIds`:逻辑删除(`is_delete = '1'`)。
### 4.3 Service 实现:`HwWebDocumentServiceImpl`
- **查询/列表/删除**:直接委托 Mapper对应接口方法。
- **新增**`insertHwWebDocument`
- 在插入前设置 `createTime = DateUtils.getNowDate()`
- **更新**`updateHwWebDocument`
- 如果 `hwWebDocument.getSecretKey() == null`,则强制 `setSecretKey("")`
- 触发 Mapper 中 `<if test="secretKey != null">` 条件。
- 在 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 更新页面 JSONHwWeb/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<HwWeb> 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<HwWeb> list = hwWebService.selectHwWebList(hwWeb);
ExcelUtil<HwWeb> util = new ExcelUtil<HwWeb>(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<HwWebMenu> 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<HwWebMenu> list = hwWebMenuService.selectHwWebMenuList(hwWebMenu);
ExcelUtil<HwWebMenu> util = new ExcelUtil<HwWebMenu>(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<HwWebMenu1> 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<HwWebMenu1> list = hwWebMenuService1.selectHwWebMenuList(hwWebMenu1);
ExcelUtil<HwWebMenu1> util = new ExcelUtil<HwWebMenu1>(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<HwWebDocument> 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<HwWebDocument> list = hwWebDocumentService.selectHwWebDocumentList(hwWebDocument);
ExcelUtil<HwWebDocument> util = new ExcelUtil<HwWebDocument>(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<HwWeb> 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<HwWeb> 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<HwWeb1> 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<HwWeb1> 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<HwWebMenu> selectHwWebMenuList(HwWebMenu hwWebMenu)
{
List<HwWebMenu> hwWebMenus = hwWebMenuMapper.selectHwWebMenuList(hwWebMenu);
return hwWebMenus;
}
/**
* 获取菜单树列表
*/
@Override
public List<HwWebMenu> selectMenuTree(HwWebMenu hwWebMenu)
{
List<HwWebMenu> 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<HwWebMenu> buildWebMenuTree(List<HwWebMenu> menus) {
List<HwWebMenu> returnList = new ArrayList<>();
List<Long> 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<HwWebMenu> list, HwWebMenu t) {
// 得到子节点列表
List<HwWebMenu> childList = getChildList(list, t);
t.setChildren(childList);
for (HwWebMenu tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
/**
* 得到子节点列表
*/
private List<HwWebMenu> getChildList(List<HwWebMenu> list, HwWebMenu t) {
List<HwWebMenu> tlist = new ArrayList<HwWebMenu>();
Iterator<HwWebMenu> 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<HwWebMenu> 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<HwWebMenu1> selectHwWebMenuList(HwWebMenu1 HwWebMenu1)
{
List<HwWebMenu1> hwWebMenus = HwWebMenuMapper1.selectHwWebMenuList(HwWebMenu1);
return hwWebMenus;
}
/**
* 获取菜单树列表
*/
@Override
public List<HwWebMenu1> selectMenuTree(HwWebMenu1 HwWebMenu1)
{
List<HwWebMenu1> 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<HwWebMenu1> buildWebMenuTree(List<HwWebMenu1> menus) {
List<HwWebMenu1> returnList = new ArrayList<>();
List<Long> 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<HwWebMenu1> list, HwWebMenu1 t) {
// 得到子节点列表
List<HwWebMenu1> childList = getChildList(list, t);
t.setChildren(childList);
for (HwWebMenu1 tChild : childList) {
if (hasChild(list, tChild)) {
recursionFn(list, tChild);
}
}
}
/**
* 得到子节点列表
*/
private List<HwWebMenu1> getChildList(List<HwWebMenu1> list, HwWebMenu1 t) {
List<HwWebMenu1> tlist = new ArrayList<HwWebMenu1>();
Iterator<HwWebMenu1> 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<HwWebMenu1> 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<HwWebDocument> 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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.portal.mapper.HwWebMapper">
<resultMap type="HwWeb" id="HwWebResult">
<result property="webId" column="web_id" />
<result property="webJson" column="web_json" />
<result property="webJsonString" column="web_json_string" />
<result property="webCode" column="web_code" />
<result property="isDelete" column="is_delete" />
<result property="webJsonEnglish" column="web_json_english" />
</resultMap>
<sql id="selectHwWebVo">
select web_id, web_json, web_json_string, web_code,
web_json_english,
is_delete
from hw_web
</sql>
<select id="selectHwWebList" parameterType="HwWeb" resultMap="HwWebResult">
<include refid="selectHwWebVo"/>
<where>
and is_delete = '0'
<if test="webId != null "> and web_id = #{webId}</if>
<if test="webJson != null and webJson != ''"> and web_json = #{webJson}</if>
<if test="webJsonString != null and webJsonString != ''"> and web_json_string = #{webJsonString}</if>
<if test="webCode != null "> and web_code = #{webCode}</if>
<if test="webJsonEnglish != null"> and web_json_english = #{webJsonEnglish}</if>
</where>
</select>
<select id="selectHwWebByWebcode" parameterType="Long" resultMap="HwWebResult">
<include refid="selectHwWebVo"/>
where is_delete = '0' and web_code = #{webCode}
</select>
<insert id="insertHwWeb" parameterType="HwWeb" useGeneratedKeys="true" keyProperty="webId">
insert into hw_web
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="webJson != null">web_json,</if>
<if test="webJsonString != null">web_json_string,</if>
<if test="webCode != null">web_code,</if>
<if test="webJsonEnglish != null">web_json_english,</if>
is_delete,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="webJson != null">#{webJson},</if>
<if test="webJsonString != null">#{webJsonString},</if>
<if test="webCode != null">#{webCode},</if>
<if test="webJsonEnglish != null">#{webJsonEnglish},</if>
<choose>
<when test="isDelete != null and isDelete != ''">#{isDelete},</when>
<otherwise>'0',</otherwise>
</choose>
</trim>
</insert>
<update id="updateHwWeb" parameterType="HwWeb">
update hw_web
<trim prefix="SET" suffixOverrides=",">
<if test="webJson != null">web_json = #{webJson},</if>
<if test="webJsonString != null">web_json_string = #{webJsonString},</if>
<!-- <if test="webCode != null">web_code = #{webCode},</if>-->
<if test="webJsonEnglish != null">web_json_english = #{webJsonEnglish},</if>
</trim>
where web_code = #{webCode}
</update>
<update id="deleteHwWebByWebId" parameterType="Long">
update hw_web set is_delete = '1' where web_id = #{webId}
</update>
<update id="deleteHwWebByWebIds" parameterType="String">
update hw_web set is_delete = '1' where web_id in
<foreach item="webId" collection="array" open="(" separator="," close=")">
#{webId}
</foreach>
</update>
</mapper>
```
#### 6.5.2 `HwWebMapper1.xml`
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.portal.mapper.HwWebMapper1">
<resultMap type="HwWeb1" id="HwWebResult1">
<result property="webId" column="web_id" />
<result property="webJson" column="web_json" />
<result property="webJsonString" column="web_json_string" />
<result property="webCode" column="web_code" />
<result property="deviceId" column="device_id" />
<result property="typeId" column="typeId" />
<result property="isDelete" column="is_delete" />
<result property="webJsonEnglish" column="web_json_english" />
</resultMap>
<sql id="selectHwWebVo">
select web_id, web_json, web_json_string, web_code,
device_id, typeId, web_json_english,
is_delete
from hw_web1
</sql>
<select id="selectHwWebList" parameterType="HwWeb1" resultMap="HwWebResult1">
<include refid="selectHwWebVo"/>
<where>
and is_delete = '0'
<if test="webId != null "> and web_id = #{webId}</if>
<if test="webJson != null and webJson != ''"> and web_json = #{webJson}</if>
<if test="webJsonString != null and webJsonString != ''"> and web_json_string = #{webJsonString}</if>
<if test="webCode != null "> and web_code = #{webCode}</if>
<if test="deviceId != null "> and device_id = #{deviceId}</if>
<if test="typeId != null "> and typeId = #{typeId}</if>
<if test="webJsonEnglish != null "> and web_json_english = #{webJsonEnglish}</if>
</where>
</select>
<select id="selectHwWebByWebcode" parameterType="Long" resultMap="HwWebResult1">
<include refid="selectHwWebVo"/>
where is_delete = '0' and web_code = #{webCode}
</select>
<select id="selectHwWebOne" parameterType="HwWeb1" resultMap="HwWebResult1">
<include refid="selectHwWebVo"/>
where is_delete = '0' and web_code = #{webCode}
and device_id = #{deviceId}
and typeId = #{typeId}
</select>
<insert id="insertHwWeb" parameterType="HwWeb1" useGeneratedKeys="true" keyProperty="webId">
insert into hw_web1
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="webJson != null">web_json,</if>
<if test="webJsonString != null">web_json_string,</if>
<if test="webCode != null">web_code,</if>
<if test="deviceId != null">device_id,</if>
<if test="typeId != null">typeId,</if>
<if test="webJsonEnglish != null">web_json_english,</if>
is_delete,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="webJson != null">#{webJson},</if>
<if test="webJsonString != null">#{webJsonString},</if>
<if test="webCode != null">#{webCode},</if>
<if test="deviceId != null">#{deviceId},</if>
<if test="typeId != null">#{typeId},</if>
<if test="webJsonEnglish != null">#{webJsonEnglish},</if>
<choose>
<when test="isDelete != null and isDelete != ''">#{isDelete},</when>
<otherwise>'0',</otherwise>
</choose>
</trim>
</insert>
<update id="updateHwWeb" parameterType="HwWeb1">
update hw_web1
<trim prefix="SET" suffixOverrides=",">
<if test="webJson != null">web_json = #{webJson},</if>
<if test="webJsonString != null">web_json_string = #{webJsonString},</if>
<!-- <if test="webCode != null">web_code = #{webCode},</if>-->
<!-- <if test="deviceId != null">device_id = #{deviceId},</if>-->
<!-- <if test="typeId != null">typeId = #{typeId},</if>-->
<if test="webJsonEnglish != null">web_json_english = #{webJsonEnglish},</if>
</trim>
where web_code = #{webCode}
and device_id = #{deviceId}
and typeId = #{typeId}
</update>
<update id="deleteHwWebByWebId" parameterType="Long">
update hw_web1 set is_delete = '1' where web_id = #{webId}
</update>
<update id="deleteHwWebByWebIds" parameterType="String">
update hw_web1 set is_delete = '1' where web_id in
<foreach item="webId" collection="array" open="(" separator="," close=")">
#{webId}
</foreach>
</update>
</mapper>
```
#### 6.5.3 `HwWebDocumentMapper.xml`
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.portal.mapper.HwWebDocumentMapper">
<resultMap type="HwWebDocument" id="HwWebDocumentResult">
<result property="documentId" column="document_id" />
<result property="tenantId" column="tenant_id" />
<result property="documentAddress" column="document_address" />
<result property="createTime" column="create_time" />
<result property="webCode" column="web_code" />
<result property="secretKey" column="secretKey" />
<result property="json" column="json" />
<result property="type" column="type" />
<result property="isDelete" column="is_delete" />
</resultMap>
<sql id="selectHwWebDocumentVo">
select document_id, tenant_id, document_address, create_time, web_code, secretKey ,
json, type,
is_delete
from hw_web_document
</sql>
<select id="selectHwWebDocumentList" parameterType="HwWebDocument" resultMap="HwWebDocumentResult">
<include refid="selectHwWebDocumentVo"/>
<where>
and is_delete = '0'
<if test="documentId != null "> and document_id = #{documentId}</if>
<if test="tenantId != null "> and tenant_id = #{tenantId}</if>
<if test="documentAddress != null and documentAddress != ''"> and document_address = #{documentAddress}</if>
<if test="webCode != null and webCode != ''"> and web_code = #{webCode}</if>
<if test="secretKey != null and secretKey != ''"> and secretKey = #{secretKey}</if>
<if test="json != null and json != ''"> and json = #{json}</if>
<if test="type != null and type != ''"> and type = #{type}</if>
</where>
</select>
<select id="selectHwWebDocumentByDocumentId" parameterType="String" resultMap="HwWebDocumentResult">
<include refid="selectHwWebDocumentVo"/>
where is_delete = '0' and document_id = #{documentId}
</select>
<insert id="insertHwWebDocument" parameterType="HwWebDocument" useGeneratedKeys="true" keyProperty="documentId">
insert into hw_web_document
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="documentId != null">document_id,</if>
<if test="tenantId != null">tenant_id,</if>
<if test="documentAddress != null">document_address,</if>
<if test="createTime != null">create_time,</if>
<if test="webCode != null">web_code,</if>
<if test="secretKey != null">secretKey,</if>
<if test="json != null">json,</if>
<if test="type != null">type,</if>
is_delete,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="documentId != null">#{documentId},</if>
<if test="tenantId != null">#{tenantId},</if>
<if test="documentAddress != null">#{documentAddress},</if>
<if test="createTime != null">#{createTime},</if>
<if test="webCode != null">#{webCode},</if>
<if test="secretKey != null">#{secretKey},</if>
<if test="json != null">#{json},</if>
<if test="type != null">#{type},</if>
<choose>
<when test="isDelete != null and isDelete != ''">#{isDelete},</when>
<otherwise>'0',</otherwise>
</choose>
</trim>
</insert>
<update id="updateHwWebDocument" parameterType="HwWebDocument">
update hw_web_document
<trim prefix="SET" suffixOverrides=",">
<if test="documentId != null">document_id = #{documentId},</if>
<if test="tenantId != null">tenant_id = #{tenantId},</if>
<if test="documentAddress != null">document_address = #{documentAddress},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="webCode != null">web_code = #{webCode},</if>
<if test="secretKey != null">
secretKey = <choose>
<when test="secretKey == ''">NULL</when>
<otherwise>#{secretKey}</otherwise>
</choose>,
</if>
<if test="json != null">json = #{json},</if>
<if test="type != null">type = #{type},</if>
</trim>
where document_id = #{documentId}
</update>
<update id="deleteHwWebDocumentByDocumentId" parameterType="String">
update hw_web_document set is_delete = '1' where document_id = #{documentId}
</update>
<update id="deleteHwWebDocumentByDocumentIds" parameterType="String">
update hw_web_document set is_delete = '1' where document_id in
<foreach item="documentId" collection="array" open="(" separator="," close=")">
#{documentId}
</foreach>
</update>
</mapper>
```
#### 6.5.4 `HwWebMenuMapper.xml`
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.portal.mapper.HwWebMenuMapper">
<resultMap type="HwWebMenu" id="HwWebMenuResult">
<result property="webMenuId" column="web_menu_id" />
<result property="parent" column="parent" />
<result property="ancestors" column="ancestors" />
<result property="status" column="status" />
<result property="webMenuName" column="web_menu_name" />
<result property="tenantId" column="tenant_id" />
<result property="webMenuPic" column="web_menu__pic" />
<result property="webMenuType" column="web_menu_type" />
<result property="isDelete" column="is_delete" />
<result property="webMenuNameEnglish" column="web_menu_name_english" />
</resultMap>
<sql id="selectHwWebMenuVo">
select web_menu_id, parent, ancestors, status, web_menu_name, tenant_id, web_menu__pic, web_menu_type,
web_menu_name_english,
is_delete
from hw_web_menu
</sql>
<select id="selectHwWebMenuList" parameterType="HwWebMenu" resultMap="HwWebMenuResult">
<include refid="selectHwWebMenuVo"/>
<where>
and is_delete = '0'
<if test="parent != null "> and parent = #{parent}</if>
<if test="ancestors != null and ancestors != ''"> and ancestors = #{ancestors}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="webMenuName != null and webMenuName != ''"> and web_menu_name like concat('%', #{webMenuName}, '%')</if>
<if test="tenantId != null "> and tenant_id = #{tenantId}</if>
<if test="webMenuPic != null and webMenuPic != ''"> and web_menu__pic = #{webMenuPic}</if>
<if test="webMenuType != null "> and web_menu_type = #{webMenuType}</if>
<if test="webMenuNameEnglish != null and webMenuNameEnglish != ''"> and web_menu_name_english = #{webMenuNameEnglish}</if>
</where>
</select>
<select id="selectHwWebMenuByWebMenuId" parameterType="Long" resultMap="HwWebMenuResult">
<include refid="selectHwWebMenuVo"/>
where is_delete = '0' and web_menu_id = #{webMenuId}
</select>
<insert id="insertHwWebMenu" parameterType="HwWebMenu">
insert into hw_web_menu
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="webMenuId != null">web_menu_id,</if>
<if test="parent != null">parent,</if>
<if test="ancestors != null">ancestors,</if>
<if test="status != null">status,</if>
<if test="webMenuName != null">web_menu_name,</if>
<if test="tenantId != null">tenant_id,</if>
<if test="webMenuPic != null">web_menu__pic,</if>
<if test="webMenuType != null">web_menu_type,</if>
<if test="webMenuNameEnglish != null">web_menu_name_english,</if>
is_delete,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="webMenuId != null">#{webMenuId},</if>
<if test="parent != null">#{parent},</if>
<if test="ancestors != null">#{ancestors},</if>
<if test="status != null">#{status},</if>
<if test="webMenuName != null">#{webMenuName},</if>
<if test="tenantId != null">#{tenantId},</if>
<if test="webMenuPic != null">#{webMenuPic},</if>
<if test="webMenuType != null">#{webMenuType},</if>
<if test="webMenuNameEnglish != null">#{webMenuNameEnglish},</if>
<choose>
<when test="isDelete != null and isDelete != ''">#{isDelete},</when>
<otherwise>'0',</otherwise>
</choose>
</trim>
</insert>
<update id="updateHwWebMenu" parameterType="HwWebMenu">
update hw_web_menu
<trim prefix="SET" suffixOverrides=",">
<if test="parent != null">parent = #{parent},</if>
<if test="ancestors != null">ancestors = #{ancestors},</if>
<if test="status != null">status = #{status},</if>
<if test="webMenuName != null">web_menu_name = #{webMenuName},</if>
<if test="tenantId != null">tenant_id = #{tenantId},</if>
<if test="webMenuPic != null">web_menu__pic = #{webMenuPic},</if>
<if test="webMenuType != null">web_menu_type = #{webMenuType},</if>
<if test="webMenuNameEnglish != null">web_menu_name_english = #{webMenuNameEnglish},</if>
</trim>
where web_menu_id = #{webMenuId}
</update>
<update id="deleteHwWebMenuByWebMenuId" parameterType="Long">
update hw_web_menu set is_delete = '1' where web_menu_id = #{webMenuId}
</update>
<update id="deleteHwWebMenuByWebMenuIds" parameterType="String">
update hw_web_menu set is_delete = '1' where web_menu_id in
<foreach item="webMenuId" collection="array" open="(" separator="," close=")">
#{webMenuId}
</foreach>
</update>
</mapper>
```
#### 6.5.5 `HwWebMenuMapper1.xml`
```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.portal.mapper.HwWebMenuMapper1">
<resultMap type="HwWebMenu1" id="HwWebMenuResult1">
<result property="webMenuId" column="web_menu_id" />
<result property="parent" column="parent" />
<result property="ancestors" column="ancestors" />
<result property="status" column="status" />
<result property="webMenuName" column="web_menu_name" />
<result property="tenantId" column="tenant_id" />
<result property="webMenuPic" column="web_menu__pic" />
<result property="webMenuType" column="web_menu_type" />
<result property="value" column="value" />
<result property="isDelete" column="is_delete" />
<result property="webMenuNameEnglish" column="web_menu_name_english" />
</resultMap>
<sql id="selectHwWebMenuVo">
select web_menu_id, parent, ancestors, status, web_menu_name, tenant_id, web_menu__pic,
value,
web_menu_type,
web_menu_name_english,
is_delete
from hw_web_menu1
</sql>
<select id="selectHwWebMenuList" parameterType="HwWebMenu1" resultMap="HwWebMenuResult1">
<include refid="selectHwWebMenuVo"/>
<where>
and is_delete = '0'
<if test="parent != null "> and parent = #{parent}</if>
<if test="ancestors != null and ancestors != ''"> and ancestors = #{ancestors}</if>
<if test="status != null and status != ''"> and status = #{status}</if>
<if test="webMenuName != null and webMenuName != ''"> and web_menu_name like concat('%', #{webMenuName}, '%')</if>
<if test="tenantId != null "> and tenant_id = #{tenantId}</if>
<if test="webMenuPic != null and webMenuPic != ''"> and web_menu__pic = #{webMenuPic}</if>
<if test="webMenuType != null "> and web_menu_type = #{webMenuType}</if>
<if test="value != null and value != ''"> and value like concat('%', #{value}, '%')</if>
<if test="webMenuNameEnglish != null and webMenuNameEnglish != ''"> and web_menu_name_english like concat('%', #{webMenuNameEnglish}, '%')</if>
</where>
</select>
<select id="selectHwWebMenuByWebMenuId" parameterType="Long" resultMap="HwWebMenuResult1">
<include refid="selectHwWebMenuVo"/>
where is_delete = '0' and web_menu_id = #{webMenuId}
</select>
<insert id="insertHwWebMenu" parameterType="HwWebMenu1">
insert into hw_web_menu1
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="webMenuId != null">web_menu_id,</if>
<if test="parent != null">parent,</if>
<if test="ancestors != null">ancestors,</if>
<if test="status != null">status,</if>
<if test="webMenuName != null">web_menu_name,</if>
<if test="tenantId != null">tenant_id,</if>
<if test="webMenuPic != null">web_menu__pic,</if>
<if test="webMenuType != null">web_menu_type,</if>
<if test="value != null">value,</if>
<if test="webMenuNameEnglish != null">web_menu_name_english,</if>
is_delete,
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="webMenuId != null">#{webMenuId},</if>
<if test="parent != null">#{parent},</if>
<if test="ancestors != null">#{ancestors},</if>
<if test="status != null">#{status},</if>
<if test="webMenuName != null">#{webMenuName},</if>
<if test="tenantId != null">#{tenantId},</if>
<if test="webMenuPic != null">#{webMenuPic},</if>
<if test="webMenuType != null">#{webMenuType},</if>
<if test="value != null">#{value},</if>
<if test="webMenuNameEnglish != null">#{webMenuNameEnglish},</if>
<choose>
<when test="isDelete != null and isDelete != ''">#{isDelete},</when>
<otherwise>'0',</otherwise>
</choose>
</trim>
</insert>
<update id="updateHwWebMenu" parameterType="HwWebMenu1">
update hw_web_menu1
<trim prefix="SET" suffixOverrides=",">
<if test="parent != null">parent = #{parent},</if>
<if test="ancestors != null">ancestors = #{ancestors},</if>
<if test="status != null">status = #{status},</if>
<if test="webMenuName != null">web_menu_name = #{webMenuName},</if>
<if test="tenantId != null">tenant_id = #{tenantId},</if>
<if test="webMenuPic != null">web_menu__pic = #{webMenuPic},</if>
<if test="webMenuType != null">web_menu_type = #{webMenuType},</if>
<if test="value != null">value = #{value},</if>
<if test="webMenuNameEnglish != null">web_menu_name_english = #{webMenuNameEnglish},</if>
</trim>
where web_menu_id = #{webMenuId}
</update>
<update id="deleteHwWebMenuByWebMenuId" parameterType="Long">
update hw_web_menu1 set is_delete = '1' where web_menu_id = #{webMenuId}
</update>
<update id="deleteHwWebMenuByWebMenuIds" parameterType="String">
update hw_web_menu1 set is_delete = '1' where web_menu_id in
<foreach item="webMenuId" collection="array" open="(" separator="," close=")">
#{webMenuId}
</foreach>
</update>
</mapper>