12 KiB
12 KiB
NL Admin System 开发手册
1. 开发环境搭建
1.1 环境要求
| 软件 | 版本 | 说明 |
|---|---|---|
| JDK | 1.8 | 必须使用 Java 8 |
| Maven | 3.6+ | 依赖管理工具 |
| MySQL | 5.7+ | 主数据库 |
| Redis | 3.2+ | 缓存与会话管理 |
1.2 JDK 配置
# 设置环境变量
export JAVA_HOME=/path/to/jdk1.8
export PATH=$JAVA_HOME/bin:$PATH
1.3 Maven 配置
settings.xml :
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
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 注释规范
/**
* 获取设备详情
* @param id 设备ID
* @return 设备信息
*/
public DeviceDto getDeviceById(Long id) {
// 业务逻辑
}
3.4 异常处理规范
// 错误示例
try {
// 业务逻辑
} catch (Exception e) {
e.printStackTrace(); // 禁止直接打印堆栈
}
// 正确示例
try {
// 业务逻辑
} catch (Exception e) {
log.error("获取设备失败, id: {}", id, e);
throw new BadRequestException("获取设备失败");
}
4. 开发流程
4.1 需求分析
- 明确需求范围和业务场景
- 分析与现有模块的依赖关系
- 设计数据模型和接口
4.2 编码流程
需求分析 → 设计文档 → 创建DTO → 创建Entity → 创建Mapper → 创建Service → 创建Controller → 单元测试
4.3 Git 工作流
# 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 通用字段
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 统一响应格式
// 成功响应
{
"code": 200,
"message": "操作成功",
"data": {...},
"timestamp": 1620000000000
}
// 失败响应
{
"code": 400,
"message": "参数错误",
"data": null,
"timestamp": 1620000000000
}
6.3 Controller 示例
@RestController
@RequestMapping("/api/device")
public class DeviceController {
@Autowired
private IDeviceService deviceService;
@GetMapping
public ResponseEntity<Object> getAll(DeviceQuery query) {
List<DeviceDto> devices = deviceService.queryAll(query);
return ResponseEntity.ok(devices);
}
@GetMapping("/{id}")
public ResponseEntity<Object> getById(@PathVariable Long id) {
DeviceDto device = deviceService.getById(id);
return ResponseEntity.ok(device);
}
@PostMapping
public ResponseEntity<Object> create(@RequestBody DeviceDto dto) {
deviceService.create(dto);
return ResponseEntity.ok("创建成功");
}
@PutMapping("/{id}")
public ResponseEntity<Object> update(@PathVariable Long id, @RequestBody DeviceDto dto) {
deviceService.update(id, dto);
return ResponseEntity.ok("更新成功");
}
@DeleteMapping("/{id}")
public ResponseEntity<Object> delete(@PathVariable Long id) {
deviceService.delete(id);
return ResponseEntity.ok("删除成功");
}
}
7. Service 层开发规范
7.1 接口定义
public interface IDeviceService {
/**
* 查询设备列表
*/
List<DeviceDto> queryAll(DeviceQuery query);
/**
* 根据ID查询设备
*/
DeviceDto getById(Long id);
/**
* 创建设备
*/
void create(DeviceDto dto);
/**
* 更新设备
*/
void update(Long id, DeviceDto dto);
/**
* 删除设备
*/
void delete(Long id);
}
7.2 实现类规范
@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 进行权限控制:
@RestController
@RequestMapping("/api/admin")
public class AdminController {
@GetMapping("/users")
public ResponseEntity<Object> getUsers() {
return ResponseEntity.ok(userService.getAll());
}
}
8.2 参数校验
使用 @Valid 注解进行参数校验:
public class DeviceDto {
@NotBlank(message = "设备名称不能为空")
@Size(max = 100, message = "设备名称不能超过100字符")
private String name;
@Min(value = 0, message = "状态值不能为负数")
private Integer status;
}
8.3 SQL 注入防护
// 正确:使用参数化查询
QueryWrapper<Device> 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 日志格式
// 错误示例
log.info("设备ID: " + id + ", 名称: " + name);
// 正确示例
log.info("创建设备成功, id: {}, name: {}", id, name);
log.error("创建设备失败, id: {}, error: {}", id, e.getMessage(), e);
10. 测试规范
10.1 单元测试
@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 配置管理
# 开发环境
java -jar nlsso-server.jar --spring.profiles.active=dev
# 生产环境
java -jar nlsso-server.jar --spring.profiles.active=prod
11.2 启动脚本
#!/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 数据库连接失败
问题:无法连接数据库
解决方案:
- 检查数据库服务是否启动
- 检查
application.yml中的数据库配置 - 检查数据库用户名和密码
12.3 Redis 连接失败
问题:缓存操作失败
解决方案:
- 检查 Redis 服务是否启动
- 检查 Redis 配置(主机、端口、密码)
- 检查防火墙规则
12.4 权限不足
问题:访问接口时返回 403
解决方案:
- 检查用户是否登录
- 检查用户是否具有相应权限
- 检查权限配置是否正确