# NL Admin System 开发手册 ## 1. 开发环境搭建 ### 1.1 环境要求 | 软件 | 版本 | 说明 | | :--- | :--- | :--- | | JDK | 1.8 | 必须使用 Java 8 | | Maven | 3.6+ | 依赖管理工具 | | MySQL | 5.7+ | 主数据库 | | Redis | 3.2+ | 缓存与会话管理 | ### 1.2 JDK 配置 ```bash # 设置环境变量 export JAVA_HOME=/path/to/jdk1.8 export PATH=$JAVA_HOME/bin:$PATH ``` ### 1.3 Maven 配置 `settings.xml` : ```xml nexus-aliyun central Nexus aliyun http://maven.aliyun.com/nexus/content/groups/public ``` --- ## 2. 项目结构详解 ### 2.1 模块划分 ``` src/main/java/org/nl/ ├── AppRun.java # Spring Boot 启动类 ├── acs/ # 设备控制模块(核心业务) │ ├── apiAdd/ # 地址管理 │ ├── autoThread/ # 自动线程管理 │ ├── device/ # 设备管理 │ ├── iot/ # IoT数据处理 │ ├── layout/ # 布局管理 │ ├── log/ # 日志管理 │ └── task/ # 任务调度 ├── common/ # 通用模块(工具、配置、异常等) │ ├── annotation/ # 自定义注解 │ ├── base/ # 基础类(DTO、Mapper等) │ ├── db/ # 数据库工具 │ ├── domain/ # 通用领域模型 │ ├── enums/ # 枚举类 │ ├── exception/ # 异常处理 │ ├── logging/ # 日志切面 │ ├── mnt/ # 监控与维护 │ ├── security/ # 安全配置 │ └── utils/ # 工具类 ├── config/ # 配置类 │ ├── jackson/ # JSON序列化配置 │ ├── language/ # 国际化配置 │ ├── lucene/ # 全文搜索配置 │ ├── mybatis/ # MyBatis配置 │ ├── redis/ # Redis配置 │ ├── saconfig/ # Sa-Token配置 │ └── thread/ # 线程池配置 ├── extInterface/ # 外部接口 │ ├── agvKit/ # AGV系统对接 │ └── wms/ # WMS系统对接 └── system/ # 系统管理 └── controller/ # 系统控制器 ``` ### 2.2 核心模块说明 | 模块 | 职责 | 说明 | | :--- | :--- | :--- | | `acs/` | 设备控制核心 | 包含设备管理、任务调度、IoT通信等核心业务 | | `common/` | 通用工具 | 提供基础工具类、异常处理、日志等通用能力 | | `config/` | 配置管理 | Spring配置类、第三方组件配置 | | `extInterface/` | 外部对接 | AGV、WMS等外部系统接口 | | `system/` | 系统管理 | 用户、角色、权限等系统管理功能 | --- ## 3. 代码规范 ### 3.1 命名规范 | 类型 | 规范 | 示例 | | :--- | :--- | :--- | | 包名 | 全小写,使用点分隔 | `org.nl.acs.device` | | 类名 | 大驼峰命名法 | `DeviceController` | | 方法名 | 小驼峰命名法 | `getDeviceById` | | 变量名 | 小驼峰命名法 | `deviceName` | | 常量名 | 全大写,下划线分隔 | `MAX_PAGE_SIZE` | | 接口名 | 大驼峰,以 `I` 开头 | `IDeviceService` | ### 3.2 格式规范 - 使用 4 个空格缩进(禁止使用 Tab) - 每行代码不超过 120 字符 - 方法之间空一行 - 类成员变量与方法之间空两行 ### 3.3 注释规范 ```java /** * 获取设备详情 * @param id 设备ID * @return 设备信息 */ public DeviceDto getDeviceById(Long id) { // 业务逻辑 } ``` ### 3.4 异常处理规范 ```java // 错误示例 try { // 业务逻辑 } catch (Exception e) { e.printStackTrace(); // 禁止直接打印堆栈 } // 正确示例 try { // 业务逻辑 } catch (Exception e) { log.error("获取设备失败, id: {}", id, e); throw new BadRequestException("获取设备失败"); } ``` --- ## 4. 开发流程 ### 4.1 需求分析 1. 明确需求范围和业务场景 2. 分析与现有模块的依赖关系 3. 设计数据模型和接口 ### 4.2 编码流程 ``` 需求分析 → 设计文档 → 创建DTO → 创建Entity → 创建Mapper → 创建Service → 创建Controller → 单元测试 ``` ### 4.3 Git 工作流 ```bash # 1. 从主分支拉取最新代码 git checkout develop git pull origin develop # 2. 创建特性分支 git checkout -b feature/xxx-feature # 3. 开发并提交 git add . git commit -m "feat: 实现xxx功能" # 4. 推送到远程 git push origin feature/xxx-feature # 5. 创建 Pull Request ``` --- ## 5. 数据库设计规范 ### 5.1 命名规范 | 对象 | 规范 | 示例 | | :--- | :--- | :--- | | 表名 | 小写,下划线分隔,前缀 `sys_` | `sys_device` | | 字段名 | 小写,下划线分隔 | `device_name` | | 主键 | 统一命名为 `id`,自增 | `id BIGINT PRIMARY KEY AUTO_INCREMENT` | ### 5.2 字段类型选择 | 类型 | 用途 | 示例 | | :--- | :--- | :--- | | BIGINT | 主键、ID字段 | `id`, `user_id` | | VARCHAR | 字符串,最大255 | `name`, `code` | | TEXT | 长文本 | `description` | | DATETIME | 日期时间 | `create_time`, `update_time` | | INT | 整数 | `status`, `sort` | | DECIMAL | 精确小数 | `price`, `quantity` | ### 5.3 通用字段 ```sql CREATE TABLE example ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', create_by VARCHAR(64) COMMENT '创建人', create_time DATETIME COMMENT '创建时间', update_by VARCHAR(64) COMMENT '更新人', update_time DATETIME COMMENT '更新时间', is_deleted TINYINT DEFAULT 0 COMMENT '删除标记(0-未删除,1-已删除)', remark VARCHAR(255) COMMENT '备注' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='示例表'; ``` --- ## 6. API 开发规范 ### 6.1 RESTful 风格 | 操作 | HTTP方法 | 路径 | | :--- | :--- | :--- | | 查询列表 | GET | `/api/device` | | 查询单个 | GET | `/api/device/{id}` | | 新增 | POST | `/api/device` | | 更新 | PUT | `/api/device/{id}` | | 删除 | DELETE | `/api/device/{id}` | ### 6.2 统一响应格式 ```java // 成功响应 { "code": 200, "message": "操作成功", "data": {...}, "timestamp": 1620000000000 } // 失败响应 { "code": 400, "message": "参数错误", "data": null, "timestamp": 1620000000000 } ``` ### 6.3 Controller 示例 ```java @RestController @RequestMapping("/api/device") public class DeviceController { @Autowired private IDeviceService deviceService; @GetMapping public ResponseEntity getAll(DeviceQuery query) { List devices = deviceService.queryAll(query); return ResponseEntity.ok(devices); } @GetMapping("/{id}") public ResponseEntity getById(@PathVariable Long id) { DeviceDto device = deviceService.getById(id); return ResponseEntity.ok(device); } @PostMapping public ResponseEntity create(@RequestBody DeviceDto dto) { deviceService.create(dto); return ResponseEntity.ok("创建成功"); } @PutMapping("/{id}") public ResponseEntity update(@PathVariable Long id, @RequestBody DeviceDto dto) { deviceService.update(id, dto); return ResponseEntity.ok("更新成功"); } @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { deviceService.delete(id); return ResponseEntity.ok("删除成功"); } } ``` --- ## 7. Service 层开发规范 ### 7.1 接口定义 ```java public interface IDeviceService { /** * 查询设备列表 */ List queryAll(DeviceQuery query); /** * 根据ID查询设备 */ DeviceDto getById(Long id); /** * 创建设备 */ void create(DeviceDto dto); /** * 更新设备 */ void update(Long id, DeviceDto dto); /** * 删除设备 */ void delete(Long id); } ``` ### 7.2 实现类规范 ```java @Service public class DeviceServiceImpl implements IDeviceService { @Autowired private DeviceMapper deviceMapper; @Autowired private RedisUtils redisUtils; @Override @Transactional(rollbackFor = Exception.class) public void create(DeviceDto dto) { // 参数校验 if (StrUtil.isEmpty(dto.getName())) { throw new BadRequestException("设备名称不能为空"); } // 转换为实体 Device entity = ConvertUtil.convert(dto, Device.class); // 保存到数据库 deviceMapper.insert(entity); // 更新缓存 redisUtils.set("device:" + entity.getId(), entity); } } ``` --- ## 8. 安全规范 ### 8.1 权限控制 使用 Sa-Token 进行权限控制: ```java @RestController @RequestMapping("/api/admin") public class AdminController { @GetMapping("/users") public ResponseEntity getUsers() { return ResponseEntity.ok(userService.getAll()); } } ``` ### 8.2 参数校验 使用 `@Valid` 注解进行参数校验: ```java public class DeviceDto { @NotBlank(message = "设备名称不能为空") @Size(max = 100, message = "设备名称不能超过100字符") private String name; @Min(value = 0, message = "状态值不能为负数") private Integer status; } ``` ### 8.3 SQL 注入防护 ```java // 正确:使用参数化查询 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("device_code", deviceCode); deviceMapper.selectOne(wrapper); // 错误:拼接SQL String sql = "SELECT * FROM device WHERE code = '" + deviceCode + "'"; ``` --- ## 9. 日志规范 ### 9.1 日志级别 | 级别 | 用途 | | :--- | :--- | | DEBUG | 详细的调试信息,生产环境关闭 | | INFO | 重要的业务流程日志 | | WARN | 警告信息,需要关注但不影响运行 | | ERROR | 错误信息,需要立即处理 | ### 9.2 日志格式 ```java // 错误示例 log.info("设备ID: " + id + ", 名称: " + name); // 正确示例 log.info("创建设备成功, id: {}, name: {}", id, name); log.error("创建设备失败, id: {}, error: {}", id, e.getMessage(), e); ``` --- ## 10. 测试规范 ### 10.1 单元测试 ```java @SpringBootTest class DeviceServiceTest { @Autowired private IDeviceService deviceService; @Test void testCreate() { DeviceDto dto = new DeviceDto(); dto.setName("测试设备"); dto.setCode("TEST001"); deviceService.create(dto); DeviceDto result = deviceService.getById(1L); assertEquals("测试设备", result.getName()); } } ``` ### 10.2 测试覆盖率 - 核心业务逻辑覆盖率 ≥ 80% - 工具类覆盖率 ≥ 90% - 新增代码必须有对应的单元测试 --- ## 11. 部署与发布 ### 11.1 配置管理 ```bash # 开发环境 java -jar nlsso-server.jar --spring.profiles.active=dev # 生产环境 java -jar nlsso-server.jar --spring.profiles.active=prod ``` ### 11.2 启动脚本 ```bash #!/bin/bash APP_NAME=nlsso-server APP_DIR=/opt/app cd $APP_DIR # 停止旧进程 PID=$(ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}') if [ -n "$PID" ]; then kill -9 $PID sleep 2 fi # 启动新进程 nohup java -jar $APP_DIR/$APP_NAME.jar --spring.profiles.active=prod > /dev/null 2>&1 & echo "服务已启动" ``` --- ## 12. 常见问题 ### 12.1 依赖冲突 问题:启动时报 `NoSuchMethodError` 解决方案:检查 `pom.xml` 中的依赖版本,使用 `mvn dependency:tree` 分析依赖树,排除冲突的依赖。 ### 12.2 数据库连接失败 问题:无法连接数据库 解决方案: 1. 检查数据库服务是否启动 2. 检查 `application.yml` 中的数据库配置 3. 检查数据库用户名和密码 ### 12.3 Redis 连接失败 问题:缓存操作失败 解决方案: 1. 检查 Redis 服务是否启动 2. 检查 Redis 配置(主机、端口、密码) 3. 检查防火墙规则 ### 12.4 权限不足 问题:访问接口时返回 403 解决方案: 1. 检查用户是否登录 2. 检查用户是否具有相应权限 3. 检查权限配置是否正确 ---