Java全栈项目-办公自动化OA系统
项目简介
办公自动化系统(OA系统)是一个基于Java开发的企业级应用系统,旨在提高企业的办公效率,实现无纸化办公。本项目采用前后端分离架构,运用当下流行的技术栈,实现了一个功能完善的OA系统。
技术栈
后端技术
- Spring Boot 2.x
- Spring Security
- MyBatis-Plus
- Redis
- MySQL
- JWT
前端技术
- Vue 3
- Element Plus
- Axios
- Vuex
- Vue Router
核心功能模块
-
用户权限管理
- 用户管理
- 角色管理
- 菜单管理
- 部门管理
-
审批流程管理
- 审批类型管理
- 审批模板配置
- 审批流程定义
- 审批流程实例
-
工作流引擎
- Activiti工作流集成
- 自定义表单
- 流程设计器
- 流程监控
-
消息通知
- 站内消息
- 邮件通知
- 微信推送
项目亮点
-
分布式架构
- 使用Spring Cloud实现微服务架构
- 服务注册与发现
- 负载均衡
- 服务熔断与降级
-
安全性
- 基于RBAC的权限控制
- JWT token认证
- 数据加密传输
- XSS防御
-
高性能
- Redis缓存优化
- MyBatis-Plus性能优化
- 数据库索引优化
项目部署
# 后端部署
mvn clean package
java -jar oa-system.jar
# 前端部署
npm install
npm run build
开发建议
- 遵循阿里巴巴Java开发规范
- 使用Git进行版本控制
- 编写完整的单元测试
- 注重代码质量和性能优化
- 做好文档记录和注释
项目展望
- 持续集成更多实用功能
- 优化用户体验
- 提高系统性能
- 加强安全性
- 支持更多部署方式
总结
本OA系统项目采用主流技术栈,实现了企业办公自动化的核心需求。通过分布式架构设计,确保了系统的可扩展性和高可用性。项目的开发过程注重代码质量和性能优化,为企业提供了一个可靠的办公自动化解决方案。
OA系统核心模块详解
一、用户权限管理模块
1. 用户管理
功能描述
- 用户CRUD操作
- 用户状态管理(启用/禁用)
- 用户密码重置
- 用户导入导出
- 用户登录日志
核心代码示例
@RestController
@RequestMapping("/admin/system/sysUser")
public class SysUserController {
@PostMapping("/save")
public Result save(@RequestBody SysUser user) {
// 密码加密
String passwordEncode = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(passwordEncode);
// 保存用户信息
sysUserService.save(user);
return Result.ok();
}
@GetMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable Long id, @PathVariable Integer status) {
// 更新用户状态
sysUserService.updateStatus(id, status);
return Result.ok();
}
}
2. 角色管理
功能描述
- 角色CRUD操作
- 角色权限分配
- 角色用户关联
- 角色数据权限
数据库设计
-- 角色表
CREATE TABLE sys_role (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(100) NOT NULL COMMENT '角色名称',
role_code VARCHAR(100) COMMENT '角色编码',
description VARCHAR(255) COMMENT '描述',
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户角色关联表
CREATE TABLE sys_user_role (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL
);
3. 菜单管理
功能描述
- 菜单树形展示
- 菜单CRUD操作
- 按钮权限管理
- 动态路由生成
核心实现
@Service
public class SysMenuServiceImpl implements SysMenuService {
@Override
public List<RouterVo> buildRouters(List<SysMenu> menus) {
List<RouterVo> routers = new ArrayList<>();
for (SysMenu menu : menus) {
RouterVo router = new RouterVo();
router.setPath(getRouterPath(menu));
router.setComponent(menu.getComponent());
router.setMeta(new MetaVo(menu.getName(), menu.getIcon()));
// 处理子路由
List<SysMenu> children = menu.getChildren();
if (children != null && children.size() > 0) {
router.setChildren(buildRouters(children));
}
routers.add(router);
}
return routers;
}
}
4. 部门管理
功能描述
- 部门树形展示
- 部门CRUD操作
- 部门人员管理
- 部门数据权限
数据模型
@Data
@TableName("sys_dept")
public class SysDept {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Long parentId;
private Integer sort;
private String leader;
private String phone;
private Integer status;
@TableField(exist = false)
private List<SysDept> children;
}
二、审批流程管理模块
1. 审批类型管理
功能描述
- 审批类型CRUD
- 审批分类管理
- 审批图标配置
- 审批表单关联
核心实现
@Service
public class OaProcessTypeServiceImpl implements OaProcessTypeService {
@Override
public List<OaProcessType> findProcessType() {
List<OaProcessType> processTypeList = baseMapper.selectList(null);
Map<Long, List<OaProcessType>> typeMap = processTypeList.stream()
.collect(Collectors.groupingBy(OaProcessType::getParentId));
List<OaProcessType> result = new ArrayList<>();
recursiveProcessType(result, typeMap, 0L);
return result;
}
}
2. 审批模板配置
功能描述
- 模板CRUD操作
- 表单设计器
- 模板权限配置
- 模板版本管理
表单设计器核心代码
export default {
data() {
return {
formItems: [],
formConf: {
size: 'medium',
labelPosition: 'right',
labelWidth: '80px'
}
}
},
methods: {
generateFormJson() {
return {
formItems: this.formItems,
formConf: this.formConf
}
}
}
}
3. 审批流程定义
功能描述
- 流程设计器
- 流程节点配置
- 审批人设置
- 条件分支设置
流程定义示例
@RestController
@RequestMapping("/admin/process/processDefinition")
public class ProcessDefinitionController {
@PostMapping("/saveProcessDefinition")
public Result saveProcessDefinition(@RequestBody ProcessDefinition processDefinition) {
processDefinitionService.saveProcessDefinition(processDefinition);
return Result.ok();
}
}
4. 审批流程实例
功能描述
- 流程发起
- 流程审批
- 流程撤回
- 流程监控
- 流程历史查询
流程实例核心代码
@Service
public class ProcessInstanceServiceImpl implements ProcessInstanceService {
@Override
@Transactional
public void startProcess(ProcessFormVo processFormVo) {
// 获取流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(processFormVo.getProcessDefinitionKey())
.latestVersion()
.singleResult();
// 启动流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceById(
processDefinition.getId(),
processFormVo.getBusinessKey(),
processFormVo.getVariables()
);
// 记录流程实例信息
ProcessRecord processRecord = new ProcessRecord();
processRecord.setProcessInstanceId(processInstance.getId());
processRecord.setStatus(1);
processRecordMapper.insert(processRecord);
}
}
总结
以上是OA系统中用户权限管理和审批流程管理两个核心模块的详细设计和实现。系统采用RBAC权限模型,结合Activiti工作流引擎,实现了完整的权限控制和灵活的审批流程管理。每个模块都遵循了高内聚低耦合的设计原则,便于后期维护和扩展。
OA系统工作流与消息模块详解
一、工作流引擎模块
1. Activiti工作流集成
配置集成
@Configuration
public class ActivitiConfig {
@Bean
public ProcessEngine processEngine(DataSource dataSource) {
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration()
.setDataSource(dataSource)
.setDatabaseSchemaUpdate("true")
.setAsyncExecutorActivate(false);
return configuration.buildProcessEngine();
}
@Bean
public RepositoryService repositoryService(ProcessEngine processEngine) {
return processEngine.getRepositoryService();
}
@Bean
public RuntimeService runtimeService(ProcessEngine processEngine) {
return processEngine.getRuntimeService();
}
}
核心服务实现
@Service
public class WorkflowServiceImpl implements WorkflowService {
@Autowired
private TaskService taskService;
@Override
public void completeTask(String taskId, Map<String, Object> variables) {
// 完成任务
taskService.complete(taskId, variables);
// 记录审批历史
saveApprovalHistory(taskId, variables);
}
@Override
public List<Task> getUserTasks(String userId) {
return taskService.createTaskQuery()
.taskAssignee(userId)
.orderByTaskCreateTime()
.desc()
.list();
}
}
2. 自定义表单
表单设计器组件
<template>
<div class="form-designer">
<div class="component-list">
<draggable v-model="componentList" group="form-items">
<div v-for="item in basicComponents" :key="item.type">
{{ item.label }}
</div>
</draggable>
</div>
<div class="form-canvas">
<draggable v-model="formItems" group="form-items">
<component
v-for="item in formItems"
:key="item.id"
:is="item.component"
v-bind="item.props"
/>
</draggable>
</div>
</div>
</template>
<script>
export default {
data() {
return {
basicComponents: [
{ type: 'input', label: '单行文本' },
{ type: 'textarea', label: '多行文本' },
{ type: 'select', label: '下拉选择' },
{ type: 'datepicker', label: '日期选择' }
],
formItems: []
}
}
}
</script>
表单数据模型
@Data
@TableName("wf_custom_form")
public class CustomForm {
@TableId(type = IdType.AUTO)
private Long id;
private String formKey;
private String formName;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<FormField> fields;
private String processDefinitionKey;
private Integer version;
private Integer status;
}
3. 流程设计器
流程设计器集成
import BpmnModeler from 'bpmn-js/lib/Modeler'
export default {
data() {
return {
bpmnModeler: null
}
},
mounted() {
this.initBpmnModeler()
},
methods: {
initBpmnModeler() {
this.bpmnModeler = new BpmnModeler({
container: '#canvas',
additionalModules: [
// 自定义模块
customPalette,
customContextPad
]
})
},
async saveProcess() {
const { xml } = await this.bpmnModeler.saveXML({ format: true })
// 保存流程定义
await this.saveProcessDefinition({
processKey: this.processKey,
processXml: xml
})
}
}
}
4. 流程监控
监控服务实现
@Service
public class ProcessMonitorServiceImpl implements ProcessMonitorService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
@Override
public ProcessInstanceStats getProcessStats() {
ProcessInstanceStats stats = new ProcessInstanceStats();
// 运行中的流程
long running = runtimeService.createProcessInstanceQuery()
.active()
.count();
// 已完成的流程
long completed = historyService.createHistoricProcessInstanceQuery()
.finished()
.count();
stats.setRunningCount(running);
stats.setCompletedCount(completed);
return stats;
}
@Override
public List<ProcessInstanceVO> getRunningInstances() {
return runtimeService.createProcessInstanceQuery()
.active()
.list()
.stream()
.map(this::convertToVO)
.collect(Collectors.toList());
}
}
二、消息通知模块
1. 站内消息
消息模型
消息服务实现
2. 邮件通知
邮件服务配置
邮件服务实现
3. 微信推送
微信配置
微信推送服务
总结
工作流引擎模块和消息通知模块是OA系统的重要组成部分:
- 工作流引擎基于Activiti实现,提供了完整的流程设计、执行和监控功能
- 自定义表单支持灵活的表单设计和数据收集
- 消息通知模块实现了多渠道的消息推送,确保重要信息及时送达
- 整个系统采用异步处理和缓存机制,保证了消息处理的高效性和可靠性
OA系统前端核心模块实现
一、工作流相关前端实现
1. 流程设计器页面
<template>
<div class="process-designer">
<!-- 工具栏 -->
<div class="toolbar">
<el-button type="primary" @click="saveProcess">保存</el-button>
<el-button @click="downloadXML">下载XML</el-button>
<el-button @click="previewProcess">预览</el-button>
</div>
<!-- 设计器画布 -->
<div class="canvas-container">
<div id="canvas"></div>
</div>
<!-- 属性面板 -->
<div class="properties-panel">
<properties-panel
v-if="selectedElement"
:element="selectedElement"
@properties-update="updateProperties"
/>
</div>
</div>
</template>
<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
import 'bpmn-js/dist/assets/diagram-js.css'
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
import PropertiesPanel from './components/PropertiesPanel.vue'
export default {
components: {
PropertiesPanel
},
data() {
return {
bpmnModeler: null,
selectedElement: null
}
},
mounted() {
this.initBpmnModeler()
},
methods: {
initBpmnModeler() {
this.bpmnModeler = new BpmnModeler({
container: '#canvas',
propertiesPanel: {
parent: '#properties'
}
})
// 监听元素选择
this.bpmnModeler.on('selection.changed', (e) => {
const { newSelection } = e
this.selectedElement = newSelection[0]
})
},
async saveProcess() {
try {
const { xml } = await this.bpmnModeler.saveXML({ format: true })
const result = await this.$api.workflow.saveProcessDefinition({
processKey: this.processKey,
processName: this.processName,
processXml: xml
})
this.$message.success('保存成功')
} catch (error) {
this.$message.error('保存失败')
}
}
}
}
</script>
<style lang="scss" scoped>
.process-designer {
display: flex;
height: 100%;
.canvas-container {
flex: 1;
height: 100%;
#canvas {
width: 100%;
height: 100%;
}
}
.properties-panel {
width: 300px;
border-left: 1px solid #ddd;
padding: 20px;
}
}
</style>
2. 自定义表单设计器
<template>
<div class="form-designer">
<!-- 左侧组件列表 -->
<div class="components-panel">
<draggable
v-model="componentList"
:group="{ name: 'form-items', pull: 'clone', put: false }"
:clone="cloneComponent"
>
<div
v-for="item in basicComponents"
:key="item.type"
class="component-item"
>
<i :class="item.icon"></i>
<span>{{ item.label }}</span>
</div>
</draggable>
</div>
<!-- 中间画布 -->
<div class="form-canvas">
<draggable
v-model="formItems"
group="form-items"
class="form-container"
>
<div
v-for="(item, index) in formItems"
:key="item.id"
class="form-item"
@click="selectItem(item)"
>
<component
:is="item.component"
v-bind="item.props"
:disabled="true"
/>
<div class="form-item-actions">
<i class="el-icon-delete" @click.stop="deleteItem(index)"></i>
</div>
</div>
</draggable>
</div>
<!-- 右侧属性面板 -->
<div class="properties-panel" v-if="selectedItem">
<el-form label-width="80px">
<el-form-item label="标签">
<el-input v-model="selectedItem.props.label"></el-input>
</el-form-item>
<el-form-item label="必填">
<el-switch v-model="selectedItem.props.required"></el-switch>
</el-form-item>
<!-- 根据不同组件类型显示不同属性配置 -->
<template v-if="selectedItem.type === 'select'">
<el-form-item label="选项">
<el-button size="small" @click="addOption">添加选项</el-button>
<div v-for="(option, index) in selectedItem.props.options" :key="index">
<el-input v-model="option.label" placeholder="选项名">
<template #append>
<el-button @click="removeOption(index)">删除</el-button>
</template>
</el-input>
</div>
</el-form-item>
</template>
</el-form>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
import { v4 as uuidv4 } from 'uuid'
export default {
components: {
draggable
},
data() {
return {
basicComponents: [
{ type: 'input', label: '单行文本', icon: 'el-icon-edit' },
{ type: 'textarea', label: '多行文本', icon: 'el-icon-edit-outline' },
{ type: 'select', label: '下拉选择', icon: 'el-icon-arrow-down' },
{ type: 'datepicker', label: '日期选择', icon: 'el-icon-date' }
],
formItems: [],
selectedItem: null
}
},
methods: {
cloneComponent(item) {
return {
id: uuidv4(),
type: item.type,
component: `el-${item.type}`,
props: {
label: item.label,
required: false,
options: item.type === 'select' ? [] : undefined
}
}
},
selectItem(item) {
this.selectedItem = item
},
deleteItem(index) {
this.formItems.splice(index, 1)
if (this.selectedItem === this.formItems[index]) {
this.selectedItem = null
}
},
async saveForm() {
try {
await this.$api.workflow.saveCustomForm({
formKey: this.formKey,
formName: this.formName,
formItems: this.formItems
})
this.$message.success('保存成功')
} catch (error) {
this.$message.error('保存失败')
}
}
}
}
</script>
3. 流程监控页面
<template>
<div class="process-monitor">
<!-- 统计卡片 -->
<el-row :gutter="20" class="statistics">
<el-col :span="6">
<el-card shadow="hover">
<template #header>运行中的流程</template>
<div class="statistics-number">{{ stats.runningCount }}</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover">
<template #header>已完成的流程</template>
<div class="statistics-number">{{ stats.completedCount }}</div>
</el-card>
</el-col>
</el-row>
<!-- 流程实例列表 -->
<el-card class="process-list">
<template #header>
<div class="card-header">
<span>流程实例列表</span>
<el-button type="primary" @click="refreshList">刷新</el-button>
</div>
</template>
<el-table :data="processList" border>
<el-table-column prop="processInstanceId" label="实例ID" width="180" />
<el-table-column prop="processDefinitionName" label="流程名称" />
<el-table-column prop="startTime" label="开始时间">
<template #default="scope">
{{ formatDate(scope.row.startTime) }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)">
{{ getStatusText(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button
type="primary"
size="small"
@click="viewProcess(scope.row)"
>
查看
</el-button>
<el-button
type="danger"
size="small"
@click="terminateProcess(scope.row)"
>
终止
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="page.current"
:page-size="page.size"
:total="page.total"
@current-change="handlePageChange"
/>
</el-card>
<!-- 流程图查看对话框 -->
<el-dialog
title="流程图"
v-model="dialogVisible"
width="80%"
>
<div class="process-diagram" ref="processViewer"></div>
</el-dialog>
</div>
</template>
<script>
import { formatDate } from '@/utils/date'
import BpmnViewer from 'bpmn-js/lib/Viewer'
export default {
data() {
return {
stats: {
runningCount: 0,
completedCount: 0
},
processList: [],
page: {
current: 1,
size: 10,
total: 0
},
dialogVisible: false,
bpmnViewer: null
}
},
created() {
this.loadStatistics()
this.loadProcessList()
},
methods: {
async loadStatistics() {
const result = await this.$api.workflow.getProcessStats()
this.stats = result.data
},
async loadProcessList() {
const result = await this.$api.workflow.getProcessInstances({
current: this.page.current,
size: this.page.size
})
this.processList = result.data.records
this.page.total = result.data.total
},
async viewProcess(process) {
this.dialogVisible = true
this.$nextTick(() => {
if (!this.bpmnViewer) {
this.bpmnViewer = new BpmnViewer({
container: this.$refs.processViewer
})
}
// 加载流程图
this.$api.workflow.getProcessXML(process.processInstanceId)
.then(response => {
this.bpmnViewer.importXML(response.data)
})
})
},
async terminateProcess(process) {
try {
await this.$confirm('确认终止该流程实例?', '提示', {
type: 'warning'
})
await this.$api.workflow.terminateProcess(process.processInstanceId)
this.$message.success('操作成功')
this.loadProcessList()
} catch (error) {
// 取消操作
}
},
getStatusType(status) {
const types = {
1: 'primary', // 运行中
2: 'success', // 已完成
3: 'danger' // 已终止
}
return types[status] || 'info'
},
getStatusText(status) {
const texts = {
1: '运行中',
2: '已完成',
3: '已终止'
}
return texts[status] || '未知'
}
}
}
</script>
二、消息通知相关前端实现
1. 消息中心页面
2. 消息发送组件
<template>
<div class="message-sender">
<el-form
ref="form"
:model="messageForm"
:rules="rules"
label-width="80px"
>
<el-form-item label="接收人" prop="receiverId">
<user-select v-model="messageForm.receiverId" />
</el-form-item>
<el-form-item label="消息类型" prop="messageType">
<el-select v-model="messageForm.messageType">
<el-option label="站内信" :value="1" />
<el-option label="邮件" :value="2" />
<el-option label="微信" :value="3" />
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="messageForm.title" />
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input
type="textarea"
v-model="messageForm.content"
:rows="4"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sendMessage">
发送
</el-button>
<el-button @click="resetForm">
重置
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import UserSelect from './UserSelect.vue'
export default {
components: {
UserSelect
},
data() {
return {
messageForm: {
receiverId: '',
messageType: 1,
title: '',
content: ''
},
rules: {
receiverId: [
{ required: true, message: '请选择接收人' }
],
messageType: [
{ required: true, message: '请选择消息类型' }
],
title: [
{ required: true, message: '请输入标题' }
],
content: [
{ required: true, message: '请输入内容' }
]
}
}
},
methods: {
async sendMessage() {
try {
await this.$refs.form.validate()
await this.$api.message.sendMessage(this.messageForm)
this.$message.success('发送成功')
this.resetForm()
} catch (error) {
// 表单验证失败或发送失败
}
},
resetForm() {
this.$refs.form.resetFields()
}
}
}
</script>
3. 消息通知设置
这些前端代码实现了工作流和消息通知模块的主要功能:
- 工作流模块:
- 流程设计器:支持拖拽式流程设计
- 表单设计器:支持自定义表单设计
- 流程监控:展示流程统计和实例列表
- 消息通知模块:
- 消息中心:展示各类消息,支持已读/未读管理
- 消息发送:支持多渠道消息发送
- 通知设置:支持个性化的消息通知配置
所有组件都采用了Element Plus组件库,并遵循Vue 3的组合式API写法。代码结构清晰,易于维护和扩展。