946 lines
32 KiB
Markdown
946 lines
32 KiB
Markdown
# 资产管理系统 — 整体代码设计思路
|
||
|
||
---
|
||
|
||
## 一、分层设计思路
|
||
|
||
### 1.1 四层职责划分
|
||
|
||
| 层次 | 包路径 | 职责 | 核心原则 |
|
||
|------|--------|------|---------|
|
||
| 表示层 | `view/` | 用户交互、数据展示、事件响应 | 只做展示与交互,不包含业务逻辑 |
|
||
| 业务逻辑层 | `service/` | 业务规则校验、流程控制、事务协调 | 不含SQL,不包含UI逻辑 |
|
||
| 数据访问层 | `dao/` | 数据库CRUD操作、SQL封装 | 只做数据存取,不含业务判断 |
|
||
| 实体层 | `entity/` | 数据载体,与表结构对应 | 纯POJO,无业务逻辑 |
|
||
|
||
### 1.2 层间调用规则
|
||
|
||
```
|
||
view ──调用──▶ service ──调用──▶ dao ──操作──▶ MySQL
|
||
│ │ │
|
||
│ ├── util ├── util/DBUtil
|
||
│ ├── entity ├── entity
|
||
│ └── exception └── exception
|
||
│
|
||
├── util/ValidatorUtil(表单即时校验)
|
||
└── entity(界面数据绑定)
|
||
```
|
||
|
||
**严格规则:**
|
||
- view 只能调用 service,**禁止直接调用 dao**
|
||
- service 只调用 dao 和 util,**禁止包含 Swing 组件引用**
|
||
- dao 只操作数据库,**禁止包含业务判断逻辑**
|
||
- entity 被所有层共享,**禁止依赖其他任何层**
|
||
|
||
### 1.3 数据流转示例(资产录入)
|
||
|
||
```
|
||
用户填写表单 → AssetDialog收集输入 → 构造Asset对象
|
||
→ ValidatorUtil校验字段 → AssetService.addAsset(asset)
|
||
→ 校验资产编号唯一性 → AssetDAO.insert(asset)
|
||
→ DBUtil获取连接 → PreparedStatement执行SQL → 释放资源
|
||
→ 返回操作结果
|
||
→ 界面刷新表格 + 提示成功/失败
|
||
```
|
||
|
||
---
|
||
|
||
## 二、核心类设计
|
||
|
||
### 2.1 实体类(entity)
|
||
|
||
**设计原则:** 一个实体对应一张表,属性名=字段名(驼峰转换),提供全参构造+getter/setter+toString。
|
||
|
||
#### User.java
|
||
|
||
```java
|
||
// 字段:id, username, password, realName, role, status, createTime, updateTime
|
||
// 角色:role取值 "admin" / "user"
|
||
// 状态:status取值 1(启用) / 0(禁用)
|
||
// 构造:注册用构造(不含id/time)、查询用全参构造
|
||
```
|
||
|
||
#### Asset.java
|
||
|
||
```java
|
||
// 字段:id, assetCode, assetName, categoryId, status, value, purchaseDate, location, description, createTime, updateTime
|
||
// 状态:status取值 "available" / "borrowed" / "disposed"
|
||
// 关联:categoryId关联Category,界面展示时需关联查询分类名称
|
||
```
|
||
|
||
#### Category.java
|
||
|
||
```java
|
||
// 字段:id, categoryCode, categoryName, description, createTime, updateTime
|
||
// 用途:资产分类,如"办公设备"、"电子设备"、"家具"等
|
||
```
|
||
|
||
#### Borrow.java
|
||
|
||
```java
|
||
// 字段:id, assetId, userId, borrowDate, expectedReturnDate, actualReturnDate, reason, status, approverId, approveTime, approveRemark, createTime, updateTime
|
||
// 状态流转:pending → approved / rejected,approved → returned / overdue
|
||
```
|
||
|
||
#### Disposal.java
|
||
|
||
```java
|
||
// 字段:id, assetId, userId, reason, status, approverId, approveTime, approveRemark, disposalDate, createTime, updateTime
|
||
// 状态流转:pending → approved / rejected
|
||
```
|
||
|
||
### 2.2 DAO类(dao)
|
||
|
||
#### BaseDAO.java — 通用CRUD模板
|
||
|
||
```java
|
||
// 设计思路:抽取所有DAO共用的增删改查操作为模板方法
|
||
//
|
||
// 核心方法:
|
||
// int update(String sql, Object... params) — 通用增删改
|
||
// <T> T queryOne(String sql, RowMapper<T> mapper, Object... params) — 查询单条
|
||
// <T> List<T> queryList(String sql, RowMapper<T> mapper, Object... params) — 查询列表
|
||
// long count(String sql, Object... params) — 统计数量
|
||
//
|
||
// RowMapper接口:将ResultSet行映射为实体对象(函数式接口)
|
||
// @FunctionalInterface
|
||
// interface RowMapper<T> { T mapRow(ResultSet rs) throws SQLException; }
|
||
//
|
||
// 资源管理:所有方法内部保证Connection/PreparedStatement/ResultSet正确关闭
|
||
// 事务支持:提供getConnection()供Service层手动管理事务
|
||
```
|
||
|
||
#### UserDAO.java
|
||
|
||
```java
|
||
// 继承BaseDAO,实现用户特有查询
|
||
//
|
||
// 核心方法:
|
||
// User findByUsername(String username) — 按用户名查询(登录验证)
|
||
// User findById(int id) — 按ID查询(关联查询用)
|
||
// int insert(User user) — 新增用户
|
||
// int updatePassword(int id, String newPassword) — 修改密码
|
||
// int updateRole(int id, String role) — 修改角色
|
||
// int updateStatus(int id, int status) — 修改状态
|
||
// List<User> findAll() — 查询所有用户
|
||
// long countByUsername(String username) — 用户名唯一性校验
|
||
```
|
||
|
||
#### AssetDAO.java
|
||
|
||
```java
|
||
// 继承BaseDAO,实现资产特有查询
|
||
//
|
||
// 核心方法:
|
||
// int insert(Asset asset) — 新增资产
|
||
// int update(Asset asset) — 修改资产
|
||
// int deleteById(int id) — 删除资产
|
||
// Asset findById(int id) — 按ID查询
|
||
// Asset findByAssetCode(String assetCode) — 按编号查询(唯一性校验)
|
||
// List<Asset> findAll() — 查询所有
|
||
// List<Asset> findByCondition(String name, Integer categoryId, String status, String location)
|
||
// — 多条件组合查询
|
||
// int updateStatus(int id, String status) — 更新资产状态
|
||
// long countByCategoryId(int categoryId) — 统计分类下资产数量(删除前检查)
|
||
```
|
||
|
||
#### CategoryDAO.java
|
||
|
||
```java
|
||
// 继承BaseDAO,实现分类特有查询
|
||
//
|
||
// 核心方法:
|
||
// int insert(Category category) — 新增分类
|
||
// int update(Category category) — 修改分类
|
||
// int deleteById(int id) — 删除分类
|
||
// Category findById(int id) — 按ID查询
|
||
// List<Category> findAll() — 查询所有
|
||
// long countByCategoryCode(String code) — 编号唯一性校验
|
||
```
|
||
|
||
#### BorrowDAO.java
|
||
|
||
```java
|
||
// 继承BaseDAO,实现借用特有查询
|
||
//
|
||
// 核心方法:
|
||
// int insert(Borrow borrow) — 新增借用记录
|
||
// int updateStatus(int id, String status, Integer approverId, String remark)
|
||
// — 更新借用状态(审批)
|
||
// int updateReturn(int id, LocalDateTime returnDate) — 登记归还
|
||
// Borrow findById(int id) — 按ID查询
|
||
// List<Borrow> findByUserId(int userId) — 按借用人查询
|
||
// List<Borrow> findByAssetId(int assetId) — 按资产查询
|
||
// List<Borrow> findByStatus(String status) — 按状态查询
|
||
// List<Borrow> findAll() — 查询所有
|
||
// List<Borrow> findOverdue() — 查询逾期未还
|
||
```
|
||
|
||
#### DisposalDAO.java
|
||
|
||
```java
|
||
// 继承BaseDAO,实现报废特有查询
|
||
//
|
||
// 核心方法:
|
||
// int insert(Disposal disposal) — 新增报废记录
|
||
// int updateStatus(int id, String status, Integer approverId, String remark)
|
||
// — 更新报废状态(审批)
|
||
// Disposal findById(int id) — 按ID查询
|
||
// List<Disposal> findByUserId(int userId) — 按申请人查询
|
||
// List<Disposal> findByAssetId(int assetId) — 按资产查询
|
||
// List<Disposal> findByStatus(String status) — 按状态查询
|
||
// List<Disposal> findAll() — 查询所有
|
||
```
|
||
|
||
### 2.3 Service类(service)
|
||
|
||
#### UserService.java
|
||
|
||
```java
|
||
// 用户业务逻辑
|
||
//
|
||
// 核心方法:
|
||
// User login(String username, String password)
|
||
// → 校验用户名非空、密码非空
|
||
// → MD5加密密码后与数据库比对
|
||
// → 检查账户状态(是否禁用)
|
||
// → 失败抛出BusinessException
|
||
//
|
||
// void register(String username, String password, String realName)
|
||
// → 校验用户名长度(3-20)、密码长度(6-20)、真实姓名非空
|
||
// → 校验用户名唯一性
|
||
// → MD5加密密码
|
||
// → 调用DAO插入,默认角色user、状态1
|
||
//
|
||
// void changePassword(int userId, String oldPwd, String newPwd)
|
||
// → 验证旧密码正确性
|
||
// → 校验新密码格式
|
||
// → MD5加密新密码后更新
|
||
//
|
||
// List<User> getAllUsers()
|
||
// → 调用DAO查询所有用户
|
||
//
|
||
// void updateUserRole(int userId, String role)
|
||
// → 校验角色值合法性(admin/user)
|
||
// → 调用DAO更新角色
|
||
//
|
||
// void updateUserStatus(int userId, int status)
|
||
// → 校验状态值合法性(0/1)
|
||
// → 调用DAO更新状态
|
||
```
|
||
|
||
#### AssetService.java
|
||
|
||
```java
|
||
// 资产业务逻辑
|
||
//
|
||
// 核心方法:
|
||
// void addAsset(Asset asset)
|
||
// → 校验必填项(编号、名称、分类、价值、购入日期)
|
||
// → 校验资产编号唯一性
|
||
// → 校验价值为正数
|
||
// → 校验购入日期不晚于今天
|
||
// → 调用DAO插入
|
||
//
|
||
// void updateAsset(Asset asset)
|
||
// → 校验必填项
|
||
// → 调用DAO更新
|
||
//
|
||
// void deleteAsset(int assetId)
|
||
// → 检查资产状态,已被借用的不可删除
|
||
// → 调用DAO删除
|
||
//
|
||
// Asset getAssetById(int id)
|
||
// → 调用DAO查询
|
||
//
|
||
// List<Asset> getAllAssets()
|
||
// → 调用DAO查询所有
|
||
//
|
||
// List<Asset> searchAssets(String name, Integer categoryId, String status, String location)
|
||
// → 调用DAO多条件组合查询
|
||
// → 任意条件可为空(null表示不筛选)
|
||
//
|
||
// void updateAssetStatus(int assetId, String status)
|
||
// → 校验状态值合法性
|
||
// → 调用DAO更新状态
|
||
```
|
||
|
||
#### CategoryService.java
|
||
|
||
```java
|
||
// 分类业务逻辑
|
||
//
|
||
// 核心方法:
|
||
// void addCategory(Category category)
|
||
// → 校验分类名称非空、编号非空
|
||
// → 校验分类编号唯一性
|
||
// → 调用DAO插入
|
||
//
|
||
// void updateCategory(Category category)
|
||
// → 校验必填项
|
||
// → 调用DAO更新
|
||
//
|
||
// void deleteCategory(int categoryId)
|
||
// → 检查该分类下是否有资产(引用完整性)
|
||
// → 有资产则抛出BusinessException,禁止删除
|
||
// → 无资产则调用DAO删除
|
||
//
|
||
// List<Category> getAllCategories()
|
||
// → 调用DAO查询所有
|
||
//
|
||
// Category getCategoryById(int id)
|
||
// → 调用DAO查询
|
||
```
|
||
|
||
#### BorrowService.java
|
||
|
||
```java
|
||
// 借用业务逻辑(核心业务,状态流转复杂)
|
||
//
|
||
// 核心方法:
|
||
// void applyBorrow(int assetId, int userId, String reason, LocalDate expectedReturnDate)
|
||
// → 校验资产状态必须为"available"
|
||
// → 校验预计归还日期晚于今天
|
||
// → 校验借用原因非空
|
||
// → 创建Borrow记录(状态pending)
|
||
// → 更新资产状态为"borrowed"(预占,审批通过后确认)
|
||
// → 注意:此处需事务保证借用记录与资产状态一致
|
||
//
|
||
// void approveBorrow(int borrowId, int approverId, boolean approved, String remark)
|
||
// → 校验借用状态必须为"pending"
|
||
// → 校验操作人为管理员
|
||
// → 若同意:状态改为approved,资产状态保持borrowed
|
||
// → 若拒绝:状态改为rejected,资产状态恢复为available
|
||
// → 记录审批人、审批时间、审批备注
|
||
// → 需事务保证
|
||
//
|
||
// void returnAsset(int borrowId)
|
||
// → 校验借用状态必须为"approved"
|
||
// → 更新借用记录:状态改returned,记录实际归还日期
|
||
// → 更新资产状态为available
|
||
// → 需事务保证
|
||
//
|
||
// List<Borrow> getMyBorrows(int userId)
|
||
// → 查询当前用户的借用记录
|
||
//
|
||
// List<Borrow> getPendingBorrows()
|
||
// → 查询待审批借用记录
|
||
//
|
||
// List<Borrow> getAllBorrows()
|
||
// → 查询所有借用记录
|
||
//
|
||
// void checkOverdue()
|
||
// → 批量检查逾期:approved状态+预计归还日期<今天 → 更新为overdue
|
||
```
|
||
|
||
#### DisposalService.java
|
||
|
||
```java
|
||
// 报废业务逻辑
|
||
//
|
||
// 核心方法:
|
||
// void applyDisposal(int assetId, int userId, String reason)
|
||
// → 校验资产状态必须为"available"
|
||
// → 校验报废原因非空
|
||
// → 创建Disposal记录(状态pending)
|
||
// → 需事务保证
|
||
//
|
||
// void approveDisposal(int disposalId, int approverId, boolean approved, String remark)
|
||
// → 校验报废状态必须为"pending"
|
||
// → 校验操作人为管理员
|
||
// → 若同意:状态改approved,资产状态改为disposed,记录报废日期
|
||
// → 若拒绝:状态改rejected,资产状态保持available
|
||
// → 需事务保证
|
||
//
|
||
// List<Disposal> getMyDisposals(int userId)
|
||
// → 查询当前用户的报废申请
|
||
//
|
||
// List<Disposal> getPendingDisposals()
|
||
// → 查询待审批报废记录
|
||
//
|
||
// List<Disposal> getAllDisposals()
|
||
// → 查询所有报废记录
|
||
```
|
||
|
||
#### StatService.java
|
||
|
||
```java
|
||
// 统计业务逻辑
|
||
//
|
||
// 核心方法:
|
||
// Map<String, Integer> getCategoryStat()
|
||
// → 按分类统计资产数量,返回{分类名: 数量}
|
||
// → 用于饼图展示
|
||
//
|
||
// Map<String, Integer> getStatusStat()
|
||
// → 按状态统计资产数量,返回{状态名: 数量}
|
||
// → 用于柱状图展示
|
||
//
|
||
// List<Map<String, Object>> getBorrowFrequency(int topN)
|
||
// → 统计借用次数TOP N的资产
|
||
// → 返回[{资产名, 借用次数}, ...]
|
||
//
|
||
// Map<String, Double> getValueStat()
|
||
// → 按分类统计资产价值汇总
|
||
// → 返回{分类名: 总价值}
|
||
//
|
||
// int getTotalAssetCount()
|
||
// → 资产总数
|
||
//
|
||
// double getTotalAssetValue()
|
||
// → 资产总价值
|
||
//
|
||
// int getBorrowingCount()
|
||
// → 当前借出数量
|
||
//
|
||
// int getOverdueCount()
|
||
// → 逾期未还数量
|
||
```
|
||
|
||
### 2.4 界面类(view)
|
||
|
||
#### LoginFrame.java
|
||
|
||
```java
|
||
// 登录窗口 — 程序启动入口界面
|
||
// 布局:居中显示,用户名/密码输入框 + 登录按钮 + 注册链接
|
||
// 事件:
|
||
// 登录按钮 → 调用UserService.login()
|
||
// 成功 → 隐藏LoginFrame,显示MainFrame(传入User对象)
|
||
// 失败 → 弹出错误提示
|
||
// 注册链接 → 打开RegisterDialog
|
||
// 窗口:setSize(400, 300),居中,关闭时退出程序
|
||
```
|
||
|
||
#### RegisterDialog.java
|
||
|
||
```java
|
||
// 注册对话框 — JDialog模态窗口
|
||
// 表单:用户名、密码、确认密码、真实姓名 + 注册/取消按钮
|
||
// 校验:
|
||
// 用户名3-20位 → 即时校验
|
||
// 密码6-20位 → 即时校验
|
||
// 两次密码一致 → 提交时校验
|
||
// 真实姓名非空 → 提交时校验
|
||
// 提交 → 调用UserService.register()
|
||
```
|
||
|
||
#### MainFrame.java
|
||
|
||
```java
|
||
// 主窗口 — 功能导航容器
|
||
// 布局:BorderLayout
|
||
// 北部:顶部信息栏(欢迎语 + 当前用户 + 角色 + 修改密码按钮 + 退出按钮)
|
||
// 西部:左侧导航菜单(JList或JButton组)
|
||
// 菜单项:资产管理、分类管理、借用管理、报废管理、数据统计
|
||
// 管理员额外可见:用户管理
|
||
// 中部:右侧内容区(CardLayout切换各功能面板)
|
||
// 切换逻辑:
|
||
// 点击左侧菜单项 → CardLayout.show(对应Panel)
|
||
// 切换面板时自动刷新数据
|
||
```
|
||
|
||
#### panel/AssetPanel.java
|
||
|
||
```java
|
||
// 资产管理面板
|
||
// 布局:
|
||
// 顶部:搜索栏(名称输入 + 分类下拉 + 状态下拉 + 位置输入 + 搜索按钮 + 重置按钮)
|
||
// 中部:JTable资产列表(编号/名称/分类/状态/价值/购入日期/位置)
|
||
// 底部:操作按钮(新增/编辑/删除/详情)
|
||
// 右下:分页控件(可选)
|
||
// 事件:
|
||
// 搜索 → 调用AssetService.searchAssets() → 刷新表格
|
||
// 新增 → 打开AssetDialog(mode=ADD)
|
||
// 编辑 → 选中行 → 打开AssetDialog(mode=EDIT, asset)
|
||
// 删除 → 选中行 → 确认对话框 → AssetService.deleteAsset()
|
||
// 详情 → 选中行 → 打开AssetDialog(mode=VIEW, asset)
|
||
```
|
||
|
||
#### panel/CategoryPanel.java
|
||
|
||
```java
|
||
// 分类管理面板
|
||
// 布局:
|
||
// 中部:JTable分类列表(编号/名称/描述/资产数量/创建时间)
|
||
// 底部:操作按钮(新增/编辑/删除)
|
||
// 事件:
|
||
// 新增 → 打开CategoryDialog(mode=ADD)
|
||
// 编辑 → 选中行 → 打开CategoryDialog(mode=EDIT, category)
|
||
// 删除 → 选中行 → 确认对话框 → CategoryService.deleteCategory()
|
||
// → 捕获BusinessException提示"该分类下有资产,禁止删除"
|
||
```
|
||
|
||
#### panel/BorrowPanel.java
|
||
|
||
```java
|
||
// 借用管理面板
|
||
// 布局:
|
||
// 顶部:Tab切换(我的借用 / 待审批 / 全部记录)—— 根据角色显示不同Tab
|
||
// 中部:JTable借用列表
|
||
// 底部:操作按钮(借用申请 / 审批 / 归还)
|
||
// 事件:
|
||
// 借用申请 → 打开BorrowDialog
|
||
// 审批 → 选中待审批行 → 打开ApproveDialog(type=borrow)
|
||
// 归还 → 选中已审批行 → 确认归还 → BorrowService.returnAsset()
|
||
```
|
||
|
||
#### panel/DisposalPanel.java
|
||
|
||
```java
|
||
// 报废管理面板
|
||
// 布局:
|
||
// 顶部:Tab切换(我的申请 / 待审批 / 全部记录)
|
||
// 中部:JTable报废列表
|
||
// 底部:操作按钮(报废申请 / 审批)
|
||
// 事件:
|
||
// 报废申请 → 打开DisposalDialog
|
||
// 审批 → 选中待审批行 → 打开ApproveDialog(type=disposal)
|
||
```
|
||
|
||
#### panel/StatPanel.java
|
||
|
||
```java
|
||
// 数据统计面板
|
||
// 布局:
|
||
// 顶部:Tab切换(分类统计 / 状态统计 / 借用排行 / 价值汇总)
|
||
// 中部:JFreeChart图表区域
|
||
// 底部:汇总数据标签(资产总数/总价值/借出数/逾期数)
|
||
// 图表:
|
||
// 分类统计 → PieDataset + ChartFactory.createPieChart()
|
||
// 状态统计 → DefaultCategoryDataset + ChartFactory.createBarChart()
|
||
// 借用排行 → DefaultCategoryDataset + 横向柱状图
|
||
// 价值汇总 → DefaultCategoryDataset + 柱状图
|
||
```
|
||
|
||
#### panel/UserPanel.java
|
||
|
||
```java
|
||
// 用户管理面板(仅管理员可见)
|
||
// 布局:
|
||
// 中部:JTable用户列表(用户名/姓名/角色/状态/创建时间)
|
||
// 底部:操作按钮(修改角色 / 启用禁用)
|
||
// 事件:
|
||
// 修改角色 → 下拉选择admin/user → UserService.updateUserRole()
|
||
// 启用禁用 → 确认对话框 → UserService.updateUserStatus()
|
||
```
|
||
|
||
### 2.5 工具类(util)
|
||
|
||
#### DBUtil.java
|
||
|
||
```java
|
||
// 数据库连接管理工具
|
||
// 设计思路:读取db.properties配置,提供连接获取与释放
|
||
//
|
||
// 核心方法:
|
||
// static Connection getConnection() — 获取数据库连接
|
||
// static void close(Connection conn) — 关闭连接
|
||
// static void close(ResultSet rs, PreparedStatement pstmt, Connection conn)
|
||
// — 释放查询资源(重载)
|
||
//
|
||
// 实现要点:
|
||
// 1. 类加载时读取db.properties,只读一次
|
||
// 2. getConnection()每次创建新连接(课程项目无需连接池)
|
||
// 3. close方法判断null后再关闭,避免NPE
|
||
// 4. 所有DAO方法通过DBUtil获取连接,finally块中释放
|
||
```
|
||
|
||
#### MD5Util.java
|
||
|
||
```java
|
||
// MD5加密工具
|
||
//
|
||
// 核心方法:
|
||
// static String encrypt(String input) — 返回32位小写MD5摘要
|
||
//
|
||
// 实现:java.security.MessageDigest("MD5") + Hex转换
|
||
```
|
||
|
||
#### ValidatorUtil.java
|
||
|
||
```java
|
||
// 通用表单校验工具
|
||
//
|
||
// 核心方法:
|
||
// static boolean isEmpty(String str) — 判空(null或trim后为空)
|
||
// static boolean isPositive(BigDecimal value) — 判断为正数
|
||
// static boolean isLengthInRange(String str, int min, int max) — 长度范围校验
|
||
// static boolean isDateAfter(LocalDate date, LocalDate after) — 日期先后校验
|
||
// static boolean isAlphanumeric(String str) — 字母数字校验(用户名)
|
||
// static boolean isNumeric(String str) — 纯数字校验
|
||
//
|
||
// 使用场景:
|
||
// Service层校验 + View层即时校验
|
||
```
|
||
|
||
#### DateUtil.java
|
||
|
||
```java
|
||
// 日期工具类
|
||
//
|
||
// 核心方法:
|
||
// static String format(LocalDate date) — LocalDate → "yyyy-MM-dd"
|
||
// static String format(LocalDateTime dateTime) — LocalDateTime → "yyyy-MM-dd HH:mm:ss"
|
||
// static LocalDate parseDate(String str) — "yyyy-MM-dd" → LocalDate
|
||
// static LocalDateTime parseDateTime(String str) — "yyyy-MM-dd HH:mm:ss" → LocalDateTime
|
||
```
|
||
|
||
### 2.6 异常类(exception)
|
||
|
||
#### BusinessException.java
|
||
|
||
```java
|
||
// 业务异常,继承RuntimeException
|
||
// 字段:errorCode(错误码)、message(错误描述)
|
||
// 用途:Service层抛出,View层捕获并展示给用户
|
||
// 示例:throw new BusinessException("资产编号已存在")
|
||
```
|
||
|
||
#### DBException.java
|
||
|
||
```java
|
||
// 数据库异常,继承RuntimeException
|
||
// 字段:message(错误描述)、cause(原始SQLException)
|
||
// 用途:DAO层抛出,Service层捕获后包装为BusinessException或直接向上传播
|
||
```
|
||
|
||
---
|
||
|
||
## 三、业务逻辑设计
|
||
|
||
### 3.1 登录注册流程
|
||
|
||
```
|
||
登录流程:
|
||
用户输入 → ValidatorUtil判空 → UserService.login()
|
||
→ UserDAO.findByUsername() → 用户不存在?→ 抛异常"用户名或密码错误"
|
||
→ MD5Util.encrypt(输入密码) → 与数据库密码比对 → 不匹配?→ 抛异常"用户名或密码错误"
|
||
→ status==0?→ 抛异常"账户已被禁用"
|
||
→ 返回User对象 → LoginFrame隐藏 → MainFrame显示
|
||
|
||
注册流程:
|
||
用户输入 → ValidatorUtil校验格式 → 确认密码一致性
|
||
→ UserService.register() → 用户名唯一性校验 → MD5加密密码 → UserDAO.insert()
|
||
```
|
||
|
||
### 3.2 资产CRUD流程
|
||
|
||
```
|
||
录入:表单填写 → ValidatorUtil校验 → AssetService.addAsset()
|
||
→ 编号唯一性校验 → 价值正数校验 → 日期合理性校验 → AssetDAO.insert()
|
||
|
||
修改:选中行 → 回填表单 → 修改字段 → AssetService.updateAsset()
|
||
→ 校验必填项 → AssetDAO.update()
|
||
|
||
删除:选中行 → 确认对话框 → AssetService.deleteAsset()
|
||
→ 检查资产状态(borrowed不可删) → AssetDAO.deleteById()
|
||
|
||
查询:输入条件 → AssetService.searchAssets()
|
||
→ 任意条件为null则不筛选 → AssetDAO.findByCondition() → 返回结果列表
|
||
```
|
||
|
||
### 3.3 借用归还流程
|
||
|
||
```
|
||
借用申请:
|
||
选择可用资产 → 填写原因+预计归还日期 → BorrowService.applyBorrow()
|
||
→ 校验资产状态为available → 创建Borrow(pending)
|
||
→ 更新资产状态为borrowed → 事务提交
|
||
|
||
审批(管理员):
|
||
选中待审批记录 → 同意/拒绝 → BorrowService.approveBorrow()
|
||
→ 同意:Borrow.status → approved,资产保持borrowed
|
||
→ 拒绝:Borrow.status → rejected,资产恢复available
|
||
→ 事务提交
|
||
|
||
归还:
|
||
选中已审批记录 → 确认归还 → BorrowService.returnAsset()
|
||
→ Borrow.status → returned,记录实际归还日期
|
||
→ 资产状态恢复available → 事务提交
|
||
|
||
逾期检查:
|
||
BorrowService.checkOverdue() → approved + expectedReturnDate < 今天 → overdue
|
||
```
|
||
|
||
### 3.4 报废流程
|
||
|
||
```
|
||
报废申请:
|
||
选择可用资产 → 填写报废原因 → DisposalService.applyDisposal()
|
||
→ 校验资产状态为available → 创建Disposal(pending)
|
||
|
||
审批(管理员):
|
||
选中待审批记录 → 同意/拒绝 → DisposalService.approveDisposal()
|
||
→ 同意:Disposal.status → approved,资产状态 → disposed
|
||
→ 拒绝:Disposal.status → rejected,资产状态保持available
|
||
```
|
||
|
||
### 3.5 统计查询流程
|
||
|
||
```
|
||
分类统计:StatService.getCategoryStat()
|
||
→ SELECT c.category_name, COUNT(a.id) FROM t_asset a JOIN t_category c → PieDataset → 饼图
|
||
|
||
状态统计:StatService.getStatusStat()
|
||
→ SELECT status, COUNT(*) FROM t_asset GROUP BY status → DefaultCategoryDataset → 柱状图
|
||
|
||
借用排行:StatService.getBorrowFrequency(10)
|
||
→ SELECT a.asset_name, COUNT(b.id) FROM t_borrow b JOIN t_asset a GROUP BY a.id → TOP 10
|
||
|
||
价值汇总:StatService.getValueStat()
|
||
→ SELECT c.category_name, SUM(a.value) FROM t_asset a JOIN t_category c → 柱状图
|
||
```
|
||
|
||
### 3.6 表单校验设计
|
||
|
||
```
|
||
校验层级:
|
||
1. 即时校验(View层)— 输入时实时反馈
|
||
- JTextField.addKeyListener / FocusListener
|
||
- 用户名长度、密码长度、数值格式等
|
||
|
||
2. 提交校验(Service层)— 提交时完整性校验
|
||
- 必填项非空
|
||
- 唯一性(用户名、资产编号)
|
||
- 业务规则(资产状态、日期合理性)
|
||
|
||
3. 数据库校验(DAO层)— 数据库约束兜底
|
||
- UNIQUE约束
|
||
- NOT NULL约束
|
||
- 外键约束
|
||
|
||
校验反馈:
|
||
- 即时校验:字段旁红色提示文字
|
||
- 提交校验:JOptionPane.showMessageDialog警告
|
||
- 数据库校验:捕获SQLException转为友好提示
|
||
```
|
||
|
||
### 3.7 数据可视化设计
|
||
|
||
```
|
||
JFreeChart集成:
|
||
1. Maven依赖:org.jfreechart/jfreechart
|
||
2. 图表创建:ChartFactory + 数据集(PieDataset/CategoryDataset)
|
||
3. 图表展示:ChartPanel封装 → 添加到StatPanel
|
||
4. 样式定制:标题、颜色、字体、图例
|
||
|
||
四种图表:
|
||
- 饼图(PieChart):分类数量占比,颜色区分各类别
|
||
- 柱状图(BarChart):状态数量对比,横向展示
|
||
- 排行图:借用频率TOP 10,降序横向柱状图
|
||
- 价值图:各分类资产价值汇总,柱状图
|
||
```
|
||
|
||
---
|
||
|
||
## 四、数据库交互设计
|
||
|
||
### 4.1 JDBC连接管理
|
||
|
||
```java
|
||
// DBUtil核心逻辑
|
||
// 1. 静态初始化块加载db.properties
|
||
static {
|
||
Properties props = new Properties();
|
||
try (InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties")) {
|
||
props.load(is);
|
||
url = props.getProperty("db.url");
|
||
username = props.getProperty("db.username");
|
||
password = props.getProperty("db.password");
|
||
Class.forName(props.getProperty("db.driver"));
|
||
} catch (Exception e) {
|
||
throw new RuntimeException("数据库配置加载失败", e);
|
||
}
|
||
}
|
||
|
||
// 2. 获取连接
|
||
public static Connection getConnection() throws SQLException {
|
||
return DriverManager.getConnection(url, username, password);
|
||
}
|
||
|
||
// 3. 释放资源 — 判断null后关闭,顺序:ResultSet → PreparedStatement → Connection
|
||
```
|
||
|
||
### 4.2 PreparedStatement防注入
|
||
|
||
```java
|
||
// 所有SQL操作均使用PreparedStatement,禁止字符串拼接SQL
|
||
// 示例:
|
||
String sql = "SELECT * FROM t_user WHERE username = ? AND password = ?";
|
||
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
|
||
pstmt.setString(1, username); // 参数化,防SQL注入
|
||
pstmt.setString(2, password);
|
||
ResultSet rs = pstmt.executeQuery();
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 4.3 事务管理
|
||
|
||
```java
|
||
// 需要事务的操作:借用申请、借用审批、借用归还、报废审批
|
||
// 这些操作涉及多表更新,需保证原子性
|
||
//
|
||
// 事务管理模式:手动事务控制
|
||
// Connection conn = null;
|
||
// try {
|
||
// conn = DBUtil.getConnection();
|
||
// conn.setAutoCommit(false); // 开启事务
|
||
//
|
||
// // 执行多条SQL...
|
||
//
|
||
// conn.commit(); // 提交事务
|
||
// } catch (Exception e) {
|
||
// if (conn != null) conn.rollback(); // 回滚事务
|
||
// throw new BusinessException("操作失败:" + e.getMessage());
|
||
// } finally {
|
||
// if (conn != null) conn.setAutoCommit(true);
|
||
// DBUtil.close(conn);
|
||
// }
|
||
```
|
||
|
||
### 4.4 BaseDAO通用操作封装
|
||
|
||
```java
|
||
// 通用更新(INSERT/UPDATE/DELETE)
|
||
public int update(String sql, Object... params) {
|
||
Connection conn = null;
|
||
PreparedStatement pstmt = null;
|
||
try {
|
||
conn = DBUtil.getConnection();
|
||
pstmt = conn.prepareStatement(sql);
|
||
for (int i = 0; i < params.length; i++) {
|
||
pstmt.setObject(i + 1, params[i]);
|
||
}
|
||
return pstmt.executeUpdate();
|
||
} catch (SQLException e) {
|
||
throw new DBException("数据库操作失败", e);
|
||
} finally {
|
||
DBUtil.close(null, pstmt, conn);
|
||
}
|
||
}
|
||
|
||
// 通用查询列表
|
||
public <T> List<T> queryList(String sql, RowMapper<T> mapper, Object... params) {
|
||
// 类似结构,ResultSet遍历 + mapper映射
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 五、规范要求
|
||
|
||
### 5.1 Java命名规范
|
||
|
||
| 类型 | 规范 | 示例 |
|
||
|------|------|------|
|
||
| 类名 | 大驼峰 | AssetService, BorrowDAO |
|
||
| 方法名 | 小驼峰 | findByUsername, addAsset |
|
||
| 变量名 | 小驼峰 | assetList, currentUser |
|
||
| 常量名 | 全大写下划线 | MAX_RETRY_COUNT |
|
||
| 包名 | 全小写 | com.asset.service |
|
||
| 数据库表名 | t_前缀+小写下划线 | t_asset, t_borrow |
|
||
| 数据库字段名 | 小写下划线 | asset_code, create_time |
|
||
|
||
### 5.2 注释规范
|
||
|
||
```java
|
||
/**
|
||
* 资产业务逻辑类
|
||
* 提供资产的增删改查、状态管理、数据校验等业务功能
|
||
*
|
||
* @author 作者名
|
||
* @version 1.0
|
||
*/
|
||
public class AssetService {
|
||
|
||
/**
|
||
* 新增资产
|
||
* 校验资产编号唯一性、必填项、价值正数后调用DAO插入
|
||
*
|
||
* @param asset 资产实体对象
|
||
* @throws BusinessException 编号重复、校验不通过时抛出
|
||
*/
|
||
public void addAsset(Asset asset) {
|
||
// 校验资产编号唯一性
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 异常处理思路
|
||
|
||
```
|
||
异常分层处理策略:
|
||
DAO层:捕获SQLException → 包装为DBException向上抛出
|
||
Service层:捕获DBException → 转为BusinessException(对用户友好)
|
||
Service层:业务规则不满足 → 直接抛BusinessException
|
||
View层:捕获BusinessException → JOptionPane展示错误信息
|
||
View层:捕获未预期异常 → 记录日志 + 通用错误提示
|
||
|
||
禁止:
|
||
- 禁止空catch块吞掉异常
|
||
- 禁止catch Exception后不做处理
|
||
- 禁止在DAO/Service层直接弹出UI对话框
|
||
```
|
||
|
||
### 5.4 AI代码校验优化要求
|
||
|
||
| 校验维度 | 检查要点 |
|
||
|----------|---------|
|
||
| 逻辑正确性 | 业务流程是否完整、边界条件是否处理 |
|
||
| SQL安全性 | 是否使用PreparedStatement、参数是否正确绑定 |
|
||
| 资源泄漏 | Connection/Statement/ResultSet是否正确关闭 |
|
||
| 命名规范 | 是否符合Java命名规范 |
|
||
| 异常处理 | 是否合理捕获/抛出、异常信息是否明确 |
|
||
| 代码冗余 | 是否有重复代码可提取到BaseDAO或工具类 |
|
||
| 业务完整性 | 状态流转是否正确、事务是否保证 |
|
||
|
||
---
|
||
|
||
## 六、课程评分匹配设计
|
||
|
||
### 6.1 功能完整性(满分保障)
|
||
|
||
| 课程要求 | 本系统实现 |
|
||
|----------|-----------|
|
||
| 用户登录注册 | ✅ 登录+注册+修改密码+角色权限 |
|
||
| 资产数据增删改查 | ✅ 完整CRUD + 多条件组合查询 |
|
||
| 数据可视化展示 | ✅ 4种JFreeChart图表 |
|
||
| 表单数据校验 | ✅ 三层校验(即时+提交+数据库) |
|
||
| 资产管理基础业务 | ✅ 借用/归还/报废全流程 |
|
||
| 功能量级2-3倍 | ✅ 5张表、8个模块、审批流程、统计功能 |
|
||
|
||
### 6.2 代码质量
|
||
|
||
| 维度 | 保障措施 |
|
||
|------|---------|
|
||
| 分层清晰 | 严格四层架构,层间调用规则明确 |
|
||
| 命名规范 | 遵循Java命名规范+阿里巴巴开发手册 |
|
||
| 注释完整 | 类注释+方法注释+关键逻辑行内注释 |
|
||
| 异常处理 | 自定义异常+分层处理+友好提示 |
|
||
| SQL安全 | PreparedStatement+参数化查询 |
|
||
| 资源管理 | finally块关闭+DBUtil统一释放 |
|
||
|
||
### 6.3 文档配套
|
||
|
||
| 文档 | 内容 |
|
||
|------|------|
|
||
| 架构设计文档 | 技术架构+功能模块+数据库设计+AI规范+感悟 |
|
||
| 目录结构文档 | 项目结构+目录功能注释 |
|
||
| 代码设计思路文档 | 本文档,完整设计思路 |
|
||
| SQL脚本 | 建库建表+初始数据 |
|
||
| 代码内注释 | 类/方法/逻辑三层注释 |
|
||
|
||
### 6.4 创新拓展
|
||
|
||
| 拓展点 | 说明 |
|
||
|--------|------|
|
||
| 审批流程 | 借用/报废均需管理员审批,非简单状态切换 |
|
||
| 逾期自动检测 | 系统自动检测逾期借用记录 |
|
||
| 多维度统计 | 分类/状态/借用/价值四维度可视化 |
|
||
| 角色权限 | 管理员/普通用户功能差异化 |
|
||
| 组合查询 | 资产支持多条件组合筛选 |
|
||
| 数据关联完整性 | 删除分类检查资产引用、删除资产检查借用状态 |
|