Java毕业设计:办公自动化系统的设计与实现
JAVA办公自动化系统
一、系统概述
本办公自动化系统基于Java EE平台开发,实现了企业日常办公的数字化管理。系统包含文档管理、流程审批、会议管理、日程安排、通讯录等核心功能模块,采用B/S架构设计,支持多用户协同工作。系统使用Spring Boot框架简化开发流程,结合MyBatis实现数据持久化,前端采用Vue.js构建现代交互界面,确保系统具有良好的可扩展性和用户体验。
二、系统架构设计
1. 技术选型
- 前端:Vue.js、Element UI
- 后端:Spring Boot、Spring Security、MyBatis
- 数据库:MySQL
- 开发工具:IntelliJ IDEA
- 部署环境:Docker、Nginx
2. 系统架构
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── officeautomation
│ │ │ ├── controller (控制器层)
│ │ │ ├── service (服务层)
│ │ │ ├── mapper (数据访问层)
│ │ │ ├── entity (实体类)
│ │ │ ├── dto (数据传输对象)
│ │ │ ├── config (配置类)
│ │ │ └── utils (工具类)
│ │ ├── resources
│ │ │ ├── mapper (MyBatis映射文件)
│ │ │ ├── application.yml (配置文件)
│ │ │ └── static (静态资源)
│ │ └── webapp
│ │ └── WEB-INF
三、核心代码实现
1. 数据模型设计
// User.java
@Data
@TableName("sys_user")
public class User {@TableId(type = IdType.AUTO)private Long id;@NotBlank(message = "用户名不能为空")private String username;@NotBlank(message = "密码不能为空")private String password;private String realName;private String email;private String phone;private Integer status;private LocalDateTime createTime;private LocalDateTime updateTime;@TableField(exist = false)private List<Role> roles;
}// Document.java
@Data
@TableName("oa_document")
public class Document {@TableId(type = IdType.AUTO)private Long id;@NotBlank(message = "文档标题不能为空")private String title;private String content;private String filePath;private String fileType;private Long fileSize;private Long creatorId;private LocalDateTime createTime;private LocalDateTime updateTime;private Integer status;private String keywords;@TableField(exist = false)private User creator;
}// ApprovalProcess.java
@Data
@TableName("oa_approval_process")
public class ApprovalProcess {@TableId(type = IdType.AUTO)private Long id;@NotBlank(message = "流程名称不能为空")private String processName;private String processKey;private Integer status;private String description;private LocalDateTime createTime;private LocalDateTime updateTime;@TableField(exist = false)private List<ApprovalNode> nodes;
}// Meeting.java
@Data
@TableName("oa_meeting")
public class Meeting {@TableId(type = IdType.AUTO)private Long id;@NotBlank(message = "会议主题不能为空")private String title;private String content;private LocalDateTime startTime;private LocalDateTime endTime;private String location;private Long organizerId;private Integer status;private LocalDateTime createTime;@TableField(exist = false)private User organizer;@TableField(exist = false)private List<User> participants;
}
2. 数据库连接配置
// MyBatisConfig.java
@Configuration
public class MyBatisConfig {@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);// 设置MyBatis配置org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(true);factoryBean.setConfiguration(configuration);// 设置TypeAliases包factoryBean.setTypeAliasesPackage("com.officeautomation.entity");// 设置MapperLocationsResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));return factoryBean.getObject();}@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
3. 服务层实现
// UserServiceImpl.java
@Service
@Transactional
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RoleMapper roleMapper;@Overridepublic User getUserById(Long id) {User user = userMapper.selectById(id);if (user != null) {List<Role> roles = roleMapper.getRolesByUserId(id);user.setRoles(roles);}return user;}@Overridepublic User getUserByUsername(String username) {QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", username);User user = userMapper.selectOne(wrapper);if (user != null) {List<Role> roles = roleMapper.getRolesByUserId(user.getId());user.setRoles(roles);}return user;}@Overridepublic List<User> getAllUsers() {List<User> userList = userMapper.selectList(null);for (User user : userList) {List<Role> roles = roleMapper.getRolesByUserId(user.getId());user.setRoles(roles);}return userList;}@Overridepublic boolean saveUser(User user) {if (user.getId() == null) {// 新增用户user.setCreateTime(LocalDateTime.now());user.setUpdateTime(LocalDateTime.now());user.setStatus(1);// 加密密码String password = user.getPassword();user.setPassword(PasswordEncoderUtil.encode(password));int result = userMapper.insert(user);return result > 0;} else {// 更新用户user.setUpdateTime(LocalDateTime.now());// 如果密码不为空,则更新密码if (!StringUtils.isEmpty(user.getPassword())) {user.setPassword(PasswordEncoderUtil.encode(user.getPassword()));} else {// 不更新密码,移除该字段user.setPassword(null);}int result = userMapper.updateById(user);return result > 0;}}@Overridepublic boolean deleteUser(Long id) {int result = userMapper.deleteById(id);// 删除用户角色关联roleMapper.deleteUserRoleByUserId(id);return result > 0;}
}// DocumentServiceImpl.java
@Service
@Transactional
public class DocumentServiceImpl implements DocumentService {@Autowiredprivate DocumentMapper documentMapper;@Autowiredprivate UserService userService;@Overridepublic Document getDocumentById(Long id) {Document document = documentMapper.selectById(id);if (document != null) {User creator = userService.getUserById(document.getCreatorId());document.setCreator(creator);}return document;}@Overridepublic List<Document> getDocumentsByPage(Page<Document> page, DocumentQuery query) {QueryWrapper<Document> wrapper = new QueryWrapper<>();if (!StringUtils.isEmpty(query.getTitle())) {wrapper.like("title", query.getTitle());}if (query.getCreatorId() != null) {wrapper.eq("creator_id", query.getCreatorId());}if (query.getStatus() != null) {wrapper.eq("status", query.getStatus());}if (query.getStartTime() != null) {wrapper.ge("create_time", query.getStartTime());}if (query.getEndTime() != null) {wrapper.le("create_time", query.getEndTime());}wrapper.orderByDesc("create_time");Page<Document> documentPage = documentMapper.selectPage(page, wrapper);List<Document> documentList = documentPage.getRecords();// 设置创建人信息for (Document document : documentList) {User creator = userService.getUserById(document.getCreatorId());document.setCreator(creator);}return documentList;}@Overridepublic boolean saveDocument(Document document, MultipartFile file) {try {if (document.getId() == null) {// 新增文档document.setCreateTime(LocalDateTime.now());document.setUpdateTime(LocalDateTime.now());document.setStatus(1);// 处理上传文件if (file != null && !file.isEmpty()) {String filePath = FileUploadUtil.uploadFile(file, "documents");document.setFilePath(filePath);document.setFileName(file.getOriginalFilename());document.setFileSize(file.getSize());document.setFileType(file.getContentType());}int result = documentMapper.insert(document);return result > 0;} else {// 更新文档document.setUpdateTime(LocalDateTime.now());// 处理上传文件if (file != null && !file.isEmpty()) {// 删除原有文件Document oldDocument = documentMapper.selectById(document.getId());if (oldDocument != null && !StringUtils.isEmpty(oldDocument.getFilePath())) {FileUploadUtil.deleteFile(oldDocument.getFilePath());}String filePath = FileUploadUtil.uploadFile(file, "documents");document.setFilePath(filePath);document.setFileName(file.getOriginalFilename());document.setFileSize(file.getSize());document.setFileType(file.getContentType());}int result = documentMapper.updateById(document);return result > 0;}} catch (Exception e) {e.printStackTrace();return false;}}@Overridepublic boolean deleteDocument(Long id) {// 删除文档前先删除关联文件Document document = documentMapper.selectById(id);if (document != null && !StringUtils.isEmpty(document.getFilePath())) {FileUploadUtil.deleteFile(document.getFilePath());}int result = documentMapper.deleteById(id);return result > 0;}
}
4. 控制器层实现
// UserController.java
@RestController
@RequestMapping("/api/users")
@Api(tags = "用户管理")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")@ApiOperation("获取用户详情")public Result<User> getUser(@PathVariable Long id) {User user = userService.getUserById(id);return Result.success(user);}@GetMapping@ApiOperation("获取用户列表")public Result<List<User>> listUsers() {List<User> userList = userService.getAllUsers();return Result.success(userList);}@PostMapping@ApiOperation("新增用户")@PreAuthorize("hasAuthority('sys:user:add')")public Result<?> addUser(@RequestBody User user) {boolean result = userService.saveUser(user);if (result) {return Result.success();} else {return Result.error("新增用户失败");}}@PutMapping@ApiOperation("更新用户")@PreAuthorize("hasAuthority('sys:user:edit')")public Result<?> updateUser(@RequestBody User user) {boolean result = userService.saveUser(user);if (result) {return Result.success();} else {return Result.error("更新用户失败");}}@DeleteMapping("/{id}")@ApiOperation("删除用户")@PreAuthorize("hasAuthority('sys:user:delete')")public Result<?> deleteUser(@PathVariable Long id) {boolean result = userService.deleteUser(id);if (result) {return Result.success();} else {return Result.error("删除用户失败");}}
}// DocumentController.java
@RestController
@RequestMapping("/api/documents")
@Api(tags = "文档管理")
public class DocumentController {@Autowiredprivate DocumentService documentService;@GetMapping("/{id}")@ApiOperation("获取文档详情")public Result<Document> getDocument(@PathVariable Long id) {Document document = documentService.getDocumentById(id);return Result.success(document);}@GetMapping@ApiOperation("获取文档列表")public Result<PageInfo<Document>> listDocuments(@RequestParam(required = false, defaultValue = "1") Integer pageNum,@RequestParam(required = false, defaultValue = "10") Integer pageSize,DocumentQuery query) {Page<Document> page = new Page<>(pageNum, pageSize);List<Document> documentList = documentService.getDocumentsByPage(page, query);PageInfo<Document> pageInfo = new PageInfo<>(documentList);pageInfo.setTotal(page.getTotal());pageInfo.setPages((int) page.getPages());return Result.success(pageInfo);}@PostMapping@ApiOperation("新增文档")@PreAuthorize("hasAuthority('oa:document:add')")public Result<?> addDocument(@RequestBody Document document) {boolean result = documentService.saveDocument(document, null);if (result) {return Result.success();} else {return Result.error("新增文档失败");}}@PostMapping("/upload")@ApiOperation("上传文档")@PreAuthorize("hasAuthority('oa:document:add')")public Result<?> uploadDocument(@RequestParam("file") MultipartFile file,@RequestParam("title") String title,@RequestParam("content") String content,@RequestParam("creatorId") Long creatorId) {Document document = new Document();document.setTitle(title);document.setContent(content);document.setCreatorId(creatorId);boolean result = documentService.saveDocument(document, file);if (result) {return Result.success();} else {return Result.error("上传文档失败");}}@PutMapping@ApiOperation("更新文档")@PreAuthorize("hasAuthority('oa:document:edit')")public Result<?> updateDocument(@RequestBody Document document) {boolean result = documentService.saveDocument(document, null);if (result) {return Result.success();} else {return Result.error("更新文档失败");}}@DeleteMapping("/{id}")@ApiOperation("删除文档")@PreAuthorize("hasAuthority('oa:document:delete')")public Result<?> deleteDocument(@PathVariable Long id) {boolean result = documentService.deleteDocument(id);if (result) {return Result.success();} else {return Result.error("删除文档失败");}}
}
5. 前端组件示例(Vue.js)
<!-- DocumentList.vue -->
<template><div class="document-list"><el-card class="box-card"><template #header><div class="clearfix"><span>文档列表</span><el-button style="float: right; padding: 3px 0" type="primary" @click="handleAdd">新增文档</el-button></div></template><el-form :inline="true" :model="queryParams" class="demo-form-inline"><el-form-item label="标题"><el-input v-model="queryParams.title" placeholder="请输入标题"></el-input></el-form-item><el-form-item label="创建人"><el-select v-model="queryParams.creatorId" placeholder="请选择创建人"><el-option v-for="user in userList" :key="user.id" :label="user.realName" :value="user.id"></el-option></el-select></el-form-item><el-form-item><el-date-pickerv-model="queryParams.startTime"type="date"placeholder="开始日期"></el-date-picker></el-form-item><el-form-item><el-date-pickerv-model="queryParams.endTime"type="date"placeholder="结束日期"></el-date-picker></el-form-item><el-form-item><el-button type="primary" @click="handleQuery">查询</el-button><el-button @click="handleReset">重置</el-button></el-form-item></el-form><el-table :data="documentList" stripe border fit highlight-current-row><el-table-column prop="id" label="ID" width="80"></el-table-column><el-table-column prop="title" label="标题"></el-table-column><el-table-column prop="creator.realName" label="创建人"></el-table-column><el-table-column prop="createTime" label="创建时间" width="180"></el-table-column><el-table-column prop="fileSize" label="文件大小" width="100"><template #default="scope">{{ formatFileSize(scope.row.fileSize) }}</template></el-table-column><el-table-column label="操作" width="200"><template #default="scope"><el-button size="mini" @click="handleView(scope.row)">查看</el-button><el-button size="mini" type="warning" @click="handleEdit(scope.row)">编辑</el-button><el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button></template></el-table-column></el-table><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 50, 100]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="total"></el-pagination></el-card><!-- 新增/编辑对话框 --><el-dialog :visible.sync="dialogVisible" title="文档管理"><el-form :model="formData" ref="formRef" label-width="120px"><el-form-item label="标题" :rules="{ required: true, message: '请输入标题', trigger: 'blur' }"><el-input v-model="formData.title"></el-input></el-form-item><el-form-item label="内容"><el-input type="textarea" v-model="formData.content" rows="4"></el-input></el-form-item><el-form-item label="上传文件"><el-uploadclass="upload-demo"action="/api/documents/upload":on-success="handleUploadSuccess":before-upload="beforeUpload":show-file-list="false"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传PDF、Word、Excel文件,且不超过10MB</div></el-upload><div v-if="formData.fileName" class="mt-2"><el-link :href="formData.filePath" type="primary" target="_blank">{{ formData.fileName }}</el-link><el-button size="mini" type="danger" @click="removeFile">删除文件</el-button></div></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" @click="saveDocument">确定</el-button></span></template></el-dialog></div>
</template><script>
export default {data() {return {documentList: [],userList: [],queryParams: {title: '',creatorId: null,startTime: null,endTime: null},currentPage: 1,pageSize: 10,total: 0,dialogVisible: false,formData: {},isEdit: false}},created() {this.fetchDocumentList();this.fetchUserList();},methods: {// 获取文档列表fetchDocumentList() {this.$http.get('/api/documents', {params: {pageNum: this.currentPage,pageSize: this.pageSize,...this.queryParams}}).then(res => {if (res.code === 200) {this.documentList = res.data.list;this.total = res.data.total;} else {this.$message.error(res.message);}}).catch(err => {console.error(err);this.$message.error('获取文档列表失败');});},// 获取用户列表fetchUserList() {this.$http.get('/api/users').then(res => {if (res.code === 200) {this.userList = res.data;} else {this.$message.error(res.message);}}).catch(err => {console.error(err);this.$message.error('获取用户列表失败');});},// 格式化文件大小formatFileSize(bytes) {if (bytes === 0) return '0 B';const k = 1024;const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];const i = Math.floor(Math.log(bytes) / Math.log(k));return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];},// 分页相关handleSizeChange(size) {this.pageSize = size;this.fetchDocumentList();},handleCurrentChange(page) {this.currentPage = page;this.fetchDocumentList();},// 查询与重置handleQuery() {this.currentPage = 1;this.fetchDocumentList();},handleReset() {this.queryParams = {title: '',creatorId: null,startTime: null,endTime: null};this.currentPage = 1;this.fetchDocumentList();},// 新增文档handleAdd() {this.isEdit = false;this.formData = {creatorId: this.$store.state.user.id};this.dialogVisible = true;},// 查看文档handleView(row) {this.$router.push({ name: 'DocumentDetail', params: { id: row.id } });},// 编辑文档handleEdit(row) {this.isEdit = true;this.formData = { ...row };this.dialogVisible = true;},// 删除文档handleDelete(row) {this.$confirm('确定要删除该文档吗?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.$http.delete(`/api/documents/${row.id}`).then(res => {if (res.code === 200) {this.$message.success('删除成功');this.fetchDocumentList();} else {this.$message.error(res.message);}}).catch(err => {console.error(err);this.$message.error('删除失败');});}).catch(() => {// 取消操作});},// 上传文件前的校验beforeUpload(file) {const isPdf = file.type === 'application/pdf';const isWord = file.type === 'application/msword' || file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';const isExcel = file.type === 'application/vnd.ms-excel' || file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';const isLt10M = file.size / 1024 / 1024 < 10;if (!(isPdf || isWord || isExcel)) {this.$message.error('只能上传PDF、Word、Excel文件');return false;}if (!isLt10M) {this.$message.error('文件大小不能超过10MB');return false;}return true;},// 上传成功处理handleUploadSuccess(response, file) {if (response.code === 200) {this.$message.success('上传成功');this.formData.fileName = file.originalName;this.formData.filePath = response.data.filePath;this.formData.fileSize = file.size;} else {this.$message.error(response.message);}},// 删除已上传文件removeFile() {this.formData.fileName = null;this.formData.filePath = null;this.formData.fileSize = null;},// 保存文档saveDocument() {this.$refs.formRef.validate(valid => {if (valid) {const url = this.isEdit ? `/api/documents` : `/api/documents`;const method = this.isEdit ? 'put' : 'post';this.$http[method](url, this.formData).then(res => {if (res.code === 200) {this.$message.success(this.isEdit ? '更新成功' : '创建成功');this.dialogVisible = false;this.fetchDocumentList();} else {this.$message.error(res.message);}}).catch(err => {console.error(err);this.$message.error(this.isEdit ? '更新失败' : '创建失败');});} else {return false;}});}}
}
</script><style scoped>
.upload-demo {margin-bottom: 10px;
}.mt-2 {margin-top: 10px;
}
</style>
四、系统功能模块
1. 用户权限管理
- 用户管理:用户信息的增删改查
- 角色管理:角色信息的管理和权限分配
- 权限管理:系统功能权限的定义和分配
2. 文档管理
- 文档上传:支持多种格式文档上传
- 文档分类:自定义文档分类体系
- 文档检索:基于关键词的文档搜索
- 文档权限:细粒度的文档访问权限控制
3. 流程审批
- 流程设计:可视化流程设计器
- 审批管理:流程发起、审批、跟踪
- 统计分析:审批效率统计和分析
4. 会议管理
- 会议安排:会议计划和安排
- 会议通知:自动发送会议通知
- 会议纪要:会议记录和归档
5. 日程安排
- 个人日程:个人工作计划和安排
- 共享日程:团队成员之间的日程共享
- 日程提醒:定时提醒功能
五、系统部署与测试
1. 环境要求
- JDK 11+
- MySQL 8.0+
- Maven 3.6+
- Node.js 14+
2. 部署步骤
- 创建数据库并导入表结构
- 配置数据库连接信息
- 编译后端项目:
mvn clean package
- 编译前端项目:
npm install && npm run build
- 部署后端应用到服务器
- 配置Nginx代理前端静态资源
3. 测试用例
// UserServiceTest.java
@SpringBootTest
class UserServiceTest {@Autowiredprivate UserService userService;@Testvoid testGetUserById() {User user = userService.getUserById(1L);assertNotNull(user);assertEquals("admin", user.getUsername());}@Testvoid testGetUserByUsername() {User user = userService.getUserByUsername("admin");assertNotNull(user);assertEquals("admin", user.getUsername());}@Testvoid testSaveUser() {User user = new User();user.setUsername("testuser");user.setPassword("123456");user.setRealName("测试用户");user.setEmail("test@example.com");user.setPhone("13800138000");boolean result = userService.saveUser(user);assertTrue(result);User savedUser = userService.getUserByUsername("testuser");assertNotNull(savedUser);assertEquals("测试用户", savedUser.getRealName());}@Testvoid testDeleteUser() {// 先创建一个用户User user = new User();user.setUsername("testuser");user.setPassword("123456");user.setRealName("测试用户");user.setEmail("test@example.com");user.setPhone("13800138000");userService.saveUser(user);User savedUser = userService.getUserByUsername("testuser");assertNotNull(savedUser);// 删除用户boolean result = userService.deleteUser(savedUser.getId());assertTrue(result);// 验证用户已删除User deletedUser = userService.getUserById(savedUser.getId());assertNull(deletedUser);}
}
六、毕业设计文档框架
1. 论文框架
- 引言
- 相关技术综述
- 系统需求分析
- 系统设计
- 系统实现
- 系统测试
- 总结与展望
2. 外文翻译
- 推荐翻译Java EE开发、办公自动化系统设计等相关的外文文献
- 翻译内容应与系统实现技术密切相关
七、总结
本办公自动化系统基于Java EE平台开发,实现了企业日常办公的数字化管理。系统采用前后端分离架构,结合Spring Boot、MyBatis和Vue.js等技术,具有良好的可扩展性和用户体验。通过本项目的开发,深入掌握了Java EE开发、数据库设计、前端开发等多项技术,为企业办公自动化提供了完整的解决方案。