# 技术要求文档

## 1. 技术栈

| 分类 | 技术 | 版本 | 说明 |
| :--- | :--- | :--- | :--- |
| 语言 | Java | 17 | 后端开发语言 |
| 框架 | Spring Boot | 3.x | 后端应用框架 |
| 数据库 | 达梦数据库 | 8.x | 关系型数据库 |
| ORM | MyBatis | 3.x | 数据访问框架 |
| 前端框架 | Vue | 3.x | 前端开发框架 |
| 前端组件库 | Element Plus | 2.x | UI组件库 |
| 构建工具 | Maven | 3.x | Java依赖管理 |
| 构建工具 | npm | 9.x | 前端依赖管理 |

## 2. 项目结构

### 2.1 后端项目结构

```plaintext
gw-sbh/                                    # Spring Boot 后端模块
  ├── src/
  │   └── main/
  │       ├── java/
  │       │   └── com/goldenwater/sbh/
  │       │       ├── controller/           # REST API 控制层
  │       │       │   └── XxxController.java
  │       │       ├── service/              # 业务逻辑层
  │       │       │   ├── XxxService.java       # 服务接口
  │       │       │   └── impl/                # 服务实现
  │       │       │       └── XxxServiceImpl.java
  │       │       ├── mapper/               # 数据访问层（接口）
  │       │       │   └── XxxMapper.java
  │       │       ├── domain/               # 实体类
  │       │       │   └── Xxx.java
  │       │       └── SbhApplication.java   # 启动类
  │       └── resources/
  │           ├── mapper/                   # MyBatis XML映射文件
  │           │   └── XxxMapper.xml
  │           └── application.yml           # 应用配置
  └── pom.xml
```

### 2.2 前端项目结构

```plaintext
gw-ui/                                      # Vue 前端模块
  ├── src/
  │   ├── views/                            # 页面视图
  │   │   └── xxx/
  │   │       └── xxx.vue
  │   ├── api/                              # API 接口定义
  │   │   └── xxx.js
  │   ├── components/                       # 公共组件
  │   ├── utils/                            # 工具函数
  │   ├── App.vue                           # 根组件
  │   └── main.js                           # 入口文件
  └── package.json
```

## 3. 命名规范

### 3.1 文件命名

| 文件类型 | 命名规则 | 示例 |
| :--- | :--- | :--- |
| Controller | 大驼峰 + Controller | `WqAwqmdDController.java` |
| Service接口 | 大驼峰 + Service | `WqAwqmdDService.java` |
| Service实现 | 大驼峰 + ServiceImpl | `WqAwqmdDServiceImpl.java` |
| Mapper接口 | 大驼峰 + Mapper | `WqAwqmdDMapper.java` |
| Entity | 大驼峰（无后缀） | `WqAwqmdD.java` |
| XML映射文件 | 大驼峰 + Mapper.xml | `WqAwqmdDMapper.xml` |
| Vue组件 | 小驼峰或短横线分隔 | `autostat.vue`, `data-table.vue` |
| API文件 | 小驼峰 | `wqAwqmdD.js` |

### 3.2 类与方法命名

| 类型 | 命名规则 | 示例 |
| :--- | :--- | :--- |
| 类名 | 大驼峰（PascalCase） | `WqAwqmdDController` |
| 方法名 | 小驼峰（camelCase） | `queryByStcd`, `insertData` |
| 变量名 | 小驼峰（camelCase） | `stcd`, `startTm`, `dataList` |
| 常量名 | 全大写 + 下划线 | `MAX_SIZE`, `DEFAULT_PAGE_SIZE` |

### 3.3 数据库命名

| 类型 | 命名规则 | 示例 |
| :--- | :--- | :--- |
| 表名 | 大写 + 下划线 | `WQ_AWQMD_D`, `SYS_TAG` |
| 字段名 | 大写 + 下划线 | `STCD`, `SPT`, `STNM` |
| Schema名 | 大写 | `RTWQ`, `SBH` |

## 4. 代码规范

### 4.1 Controller层规范

**基础要求：**
- 继承 `BaseController`
- 使用 `@RestController` 注解
- 请求路径格式：`/模块名/实体名`，如 `/sbh/wqAwqmdD`
- 使用 Swagger 注解进行API文档

**示例代码：**

```java
package com.goldenwater.sbh.controller;

import com.goldenwater.common.core.controller.BaseController;
import com.goldenwater.common.core.domain.AjaxResult;
import com.goldenwater.common.core.page.TableDataInfo;
import com.goldenwater.sbh.domain.WqAwqmdD;
import com.goldenwater.sbh.service.WqAwqmdDService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/sbh/wqAwqmdD")
@Tag(name = "水质自动监测数据管理", description = "水质自动监测数据管理接口")
public class WqAwqmdDController extends BaseController {
    
    @Resource
    private WqAwqmdDService wqAwqmdDService;

    @GetMapping("/byStcd")
    @Operation(summary = "根据测站代码分页查询", description = "根据测站代码和时间范围分页查询监测数据")
    public TableDataInfo queryByStcd(
            @Parameter(description = "测站代码") @RequestParam(value = "stcd") String stcd,
            @Parameter(description = "开始时间") @RequestParam(value = "startTm", required = false) String startTm,
            @Parameter(description = "结束时间") @RequestParam(value = "endTm", required = false) String endTm) {
        startPage();
        List<WqAwqmdD> list = wqAwqmdDService.queryByStcd(stcd, startTm, endTm);
        return getDataTable(list);
    }

    @GetMapping("/byStcdAll")
    @Operation(summary = "根据测站代码查询所有数据", description = "不分页，用于图表")
    public AjaxResult queryByStcdAll(
            @Parameter(description = "测站代码") @RequestParam(value = "stcd") String stcd,
            @Parameter(description = "开始时间") @RequestParam(value = "startTm", required = false) String startTm,
            @Parameter(description = "结束时间") @RequestParam(value = "endTm", required = false) String endTm) {
        List<WqAwqmdD> list = wqAwqmdDService.queryByStcd(stcd, startTm, endTm);
        return AjaxResult.success(list);
    }
}
```

### 4.2 Service层规范

**Service接口：**
- 定义业务方法签名
- 使用清晰的方法命名

**示例代码：**

```java
package com.goldenwater.sbh.service;

import com.goldenwater.sbh.domain.WqAwqmdD;
import java.util.List;

public interface WqAwqmdDService {

    /**
     * 根据测站代码查询数据（不分页）
     */
    List<WqAwqmdD> queryByStcd(String stcd, String startTm, String endTm);

    /**
     * 统计符合条件的数据数量
     */
    int countByStcd(String stcd, String startTm, String endTm);
}
```

**ServiceImpl实现类：**
- 使用 `@Service` 注解
- 注入 Mapper 接口
- 实现业务逻辑

```java
package com.goldenwater.sbh.service.impl;

import com.goldenwater.sbh.domain.WqAwqmdD;
import com.goldenwater.sbh.mapper.WqAwqmdDMapper;
import com.goldenwater.sbh.service.WqAwqmdDService;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;
import java.util.List;

@Service("wqAwqmdDService")
public class WqAwqmdDServiceImpl implements WqAwqmdDService {
    
    @Resource
    private WqAwqmdDMapper wqAwqmdDMapper;

    @Override
    public List<WqAwqmdD> queryByStcd(String stcd, String startTm, String endTm) {
        return wqAwqmdDMapper.queryByStcd(stcd, startTm, endTm);
    }

    @Override
    public int countByStcd(String stcd, String startTm, String endTm) {
        return wqAwqmdDMapper.countByStcd(stcd, startTm, endTm);
    }
}
```

### 4.3 Mapper层规范

**Mapper接口：**
- 使用 `@Param` 注解声明参数
- 方法名与XML中SQL id一致

```java
package com.goldenwater.sbh.mapper;

import com.goldenwater.sbh.domain.WqAwqmdD;
import org.apache.ibatis.annotations.Param;
import java.util.List;

public interface WqAwqmdDMapper {

    List<WqAwqmdD> queryByStcd(@Param("stcd") String stcd, 
                                @Param("startTm") String startTm, 
                                @Param("endTm") String endTm);

    int countByStcd(@Param("stcd") String stcd, 
                    @Param("startTm") String startTm, 
                    @Param("endTm") String endTm);
}
```

### 4.4 Entity实体类规范

- 实现 `Serializable` 接口
- 字段名使用小驼峰，与数据库字段对应
- 提供标准的 getter/setter 方法

```java
package com.goldenwater.sbh.domain;

import java.io.Serializable;
import java.util.Date;

import lombok.Data;

@Data
public class WqAwqmdD extends BaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 测站编码
     */
    private String stcd;

    /**
     * 采样时间
     */
    private Date spt;
}
```

## 5. 达梦数据库规范

### 5.1 SQL语法规范

| 特性 | 说明 | 示例 |
| :--- | :--- | :--- |
| Schema前缀 | 跨Schema查询需指定Schema | `FROM RTWQ.WQ_AWQMD_D` |
| 字符串连接 | 使用 `CONCAT()` 函数 | `CONCAT(#{endTm}, ' 23:59:59')` |
| 日期函数 | 使用达梦日期函数 | `SYSDATE`, `TO_DATE()` |
| 小于等于转义 | XML中需转义 `<=` 为 `&lt;=` | `AND SPT &lt;= #{endTm}` |
| 分页 | 使用 `ROW_NUMBER()` 或 MyBatis分页插件 | `startPage()` |

### 5.2 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.goldenwater.sbh.mapper.WqAwqmdDMapper">

    <resultMap type="com.goldenwater.sbh.domain.WqAwqmdD" id="WqAwqmdDMap">
        <result property="stcd" column="STCD" />
        <result property="spt" column="SPT" />
        <!-- ... -->
    </resultMap>

    <select id="queryByStcd" resultMap="WqAwqmdDMap">
        SELECT STCD, SPT, WT, PH
        FROM WQ_AWQMD_D
        WHERE STCD = #{stcd}
        <if test="startTm != null and startTm != ''">
            AND SPT >= #{startTm}
        </if>
        <if test="endTm != null and endTm != ''">
            AND SPT &lt; CONCAT(#{endTm}, ' 23:59:59')
        </if>
        ORDER BY SPT DESC
    </select>
</mapper>
```

### 5.3 达梦数据库保留字

以下为达梦数据库常见保留字，字段名应避免使用：

```
SELECT, FROM, WHERE, AND, OR, NOT, IN, LIKE, BETWEEN, ORDER, GROUP, 
HAVING, LIMIT, OFFSET, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER,
NULL, DEFAULT, PRIMARY, FOREIGN, KEY, UNIQUE, INDEX, CONSTRAINT,
DATE, TIME, TIMESTAMP, VARCHAR, INTEGER, DECIMAL, FLOAT, DOUBLE,
BOOLEAN, TRUE, FALSE, CASE, WHEN, THEN, ELSE, END, AS, IS, JOIN,
LEFT, RIGHT, INNER, OUTER, ON, UNION, ALL, DISTINCT, COUNT, SUM,
AVG, MAX, MIN, EXISTS, COALESCE, NVL, SYSDATE, CURRENT_DATE
```

## 6. 前端规范

### 6.1 Vue组件规范

**基础结构：**
- 使用 `<script setup>` 语法
- 导入必要的组件和工具
- 定义响应式数据和方法

**示例代码：**

```vue
<template>
  <div class="app-container">
    <el-table :data="tableData" stripe border>
      <el-table-column prop="stcd" label="测站代码" />
      <el-table-column prop="spt" label="采样时间" />
    </el-table>
  </div>
</template>

<script setup name="AutoStat">
import { ref, onMounted } from 'vue'
import { listWqAwqmdD } from "@/api/sbh/wqAwqmdD"

const tableData = ref([])

onMounted(() => {
  loadData()
})

function loadData() {
  listWqAwqmdD({ stcd: 'ST001' }).then(response => {
    tableData.value = response.data.rows
  })
}
</script>
```

### 6.2 API接口规范

**统一返回格式：**
```javascript
import request from '@/utils/request'

export function listWqAwqmdD(query) {
    return request({
        url: '/sbh/wqAwqmdD/byStcd',
        method: 'get',
        params: query
    })
}
```

### 6.3 日期时间格式

| 场景 | 格式 | 示例 |
| :--- | :--- | :--- |
| 日期选择器 | `YYYY-MM-DD` | `2026-06-03` |
| 时间戳 | `YYYY-MM-DD HH:mm:ss` | `2026-06-03 14:30:00` |
| 日期范围 | `[startDate, endDate]` | `['2026-05-28', '2026-06-03']` |

## 7. 分页规范

### 7.1 后端分页

使用 `BaseController` 提供的分页方法：

```java
@GetMapping("/list")
public TableDataInfo list(WqAwqmdD wqAwqmdD) {
    startPage();  // 开启分页
    List<WqAwqmdD> list = wqAwqmdDService.selectWqAwqmdDList(wqAwqmdD);
    return getDataTable(list);  // 返回分页数据
}
```

### 7.2 前端分页

```vue
<el-pagination
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
    :current-page="pagination.pageNum"
    :page-sizes="[10, 20, 50, 100]"
    :page-size="pagination.pageSize"
    :total="pagination.total"
    layout="total, sizes, prev, pager, next, jumper"
/>
```

## 8. 错误处理规范

### 8.1 统一返回格式

```java
// 成功响应
{
  "code": 200,
  "msg": "操作成功",
  "data": {...}
}

// 失败响应
{
  "code": 500,
  "msg": "操作失败",
  "data": null
}
```

### 8.2 异常处理

使用全局异常处理器捕获并统一处理异常：

```java
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(ServiceException.class)
    public AjaxResult handleServiceException(ServiceException e) {
        return AjaxResult.error(e.getMessage());
    }
}
```

## 9. 安全规范

### 9.1 接口权限

- 使用 Spring Security 进行认证授权
- 敏感接口需添加权限注解
- 避免直接暴露数据库主键

### 9.2 SQL注入防护

- 使用 MyBatis 参数绑定（`#{}`）
- 禁止字符串拼接SQL
- 对用户输入进行校验和过滤

### 9.3 XSS防护

- 使用框架自带的XSS过滤器
- 对用户输入进行HTML转义
- 使用安全的富文本编辑器

## 10. 代码审查要点

| 检查项 | 说明 |
| :--- | :--- |
| 命名规范 | 类、方法、变量命名符合规范 |
| 代码格式 | 缩进、空行、括号位置符合规范 |
| 异常处理 | 有完善的异常捕获和处理机制 |
| SQL安全 | 使用参数绑定，避免SQL注入 |
| 注释规范 | 关键代码有必要的注释说明 |
| 性能优化 | 避免N+1查询，合理使用索引 |
| 日志记录 | 关键业务流程有日志记录 |
| 单元测试 | 核心业务逻辑有单元测试覆盖 |

---

**文档版本**: v1.0  
**创建日期**: 2026-06-03  
**适用项目**: 水质监测系统 (gw-sbh)