作者主页:编程指南针
简介:Java领域优质创作者、CSDN博客专家 Java项目、简历模板、学习资料、面试题库、技术互助
文末获取源码
项目编号:BS-XX-003
前言:
当今互联网技术发展的非常迅速,而以往的定点办公模式已经不能满足现代人们的需要,迫切地需要我们设计一款办公自动化的OA系统才可以解决目前日益突出的问题。本系统采用了Java开发工具IntelliJ IDEA,数据库MySQL和轻量级框架SpringMVC,Hibernate,Spring开发出基于JavaEE的文珺OA系统。本课题主要实现了用户,部门,岗位等模块的增删改查,请假流程的审批,公共相册管理,个人信息管理,公告管理等功能。其中岗位管理中实现了对不同用户角色的权限管理,根据不同用户的角色授权登录系统而划分不同的功能模块。核心工作流采用自主设计的方式实现,无风险控制流程管理,解决了定点办公方式的局限性,最终实现信息以无线的方式进行流转,对提高人们的办公效率和改善企业的办公生产能力,减少企业运营成本有着重大的意义。
一,项目介绍
本系统基于springboot+ssm+shiro来进行开发实现,数据库采用mysql,开发工具为IDEA或Eclipse.利用redis进行数据缓存存储处理,使用 quartz来进行定时任务执行处理。
于SpingBoot2.0轻量级的java快速开发框架。以Spring Framework为核心容器, Spring MVC为模型视图控制器,Mybatis Plus为数据访问层, Apache Shiro为权限授权层, Redis为分布式缓存,Quartz为分布式集群调度,JSP作为前端页面引擎, 采用JSTL标签库封装组件的开源框架。
项目特点:
- 开箱即用,节省开发时间,提高开发效率
- 代码全部开源,持续更新,共同维护
- 支持分布式部署,session统一由redis进行管理
- 基于SpringBoot,简化了大量项目配置和maven依赖,让您更专注于业务开发
- 使用分层设计,分为dao,service,Controller,view层,层次清楚,低耦合,高内聚
- 提供了诸多的UI组件
- 友好的代码结构及注释,便于阅读及二次开发
- 灵活的权限控制, 整合shiro,可控制到页面或按钮,满足绝大部分的权限需求,优化权限注解方便权限配置
- 日志记录采用aop(LogAop类)方式,可对用户所有操作进行记录
- 数据统计报表:丰富的报表统计功能
- 集成jsp页面,采用标准JSTL标签库对常用组件进行封装,便于将传统项目过度到springboot
- 组件库丰富,对常用页面组件进行了代码封装,提高开发效率
- 前端页面简洁优美,支持移动端
系统功能较为全面,可根据需求删减相关功能实现。
二,项目展示
部分功能展示如下:
用户管理
部门管理
菜单管理
角色管理
数据字典管理
日志管理
个人办公-系统消息
会议管理
日报管理
日程管理
任务管理
目标管理
人力资源模块:包含档案管理、考勤管理、薪资管理、招聘管理、培训管理几大模块,不再一一展示。
三,核心代码
package com.active4j.hr.hr.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.active4j.hr.base.controller.BaseController;
import com.active4j.hr.common.constant.SysConstant;
import com.active4j.hr.core.model.AjaxJson;
import com.active4j.hr.system.entity.SysDeptEntity;
import com.active4j.hr.system.entity.SysDicValueEntity;
import com.active4j.hr.system.service.SysDeptService;
import com.active4j.hr.system.util.SystemUtils;
import lombok.extern.slf4j.Slf4j;
/**
* @title OaHrDepartController.java
* @description
oa 部门管理
* @time 2022年4月9日 上午9:10:55
* @author znz
* @version 1.0
*/
@Controller
@RequestMapping("/oa/hr/depart")
@Slf4j
public class OaHrDepartController extends BaseController {
@Autowired
private SysDeptService sysDeptService;
/**
*
* @description
* 组织架构-部门信息跳转
* @params
* @return ModelAndView
* @author guyp
* @time 2020年4月9日 上午9:47:20
*/
@RequestMapping("/oadepart")
public ModelAndView oaDepart(HttpServletRequest req) {
//查询数据字典
List<SysDicValueEntity> types = SystemUtils.getDictionaryLst(SysConstant.DIC_DEPART_TYPE);
req.setAttribute("types", types);
return new ModelAndView("oa/hr/organization/oadepart");
}
/**
*
* @description
* 获取部门信息
* @params
* @return AjaxJson
* @author guyp
* @time 2020年4月9日 下午2:27:43
*/
@RequestMapping("/getDepart")
@ResponseBody
public AjaxJson getDepart(String id, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try{
if(StringUtils.isNotEmpty(id)) {
Map<String, Object> map = new HashMap<String, Object>();
//获取部门信息
SysDeptEntity depart = sysDeptService.getById(id);
map.put("depart", depart);
//获取父部门信息
if(null != depart.getParentId()){
SysDeptEntity parent = sysDeptService.getById(depart.getParentId());
map.put("parentName", parent.getName());
map.put("parentId", parent.getId());
}
j.setAttributes(map);
}
}catch(Exception e) {
log.error("获取部门信息报错,错误信息:{}", e.getMessage());
j.setSuccess(false);
j.setMsg("获取部门信息错误");
e.printStackTrace();
}
return j;
}
}
package com.active4j.hr.hr.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.active4j.hr.base.controller.BaseController;
import com.active4j.hr.core.annotation.Log;
import com.active4j.hr.core.beanutil.MyBeanUtils;
import com.active4j.hr.core.model.AjaxJson;
import com.active4j.hr.core.model.LogType;
import com.active4j.hr.hr.entity.OaHrJobEntity;
import com.active4j.hr.hr.service.OaHrJobService;
import lombok.extern.slf4j.Slf4j;
/**
*
* @title OaHrJobController.java
* @description
oa 岗位管理
* @time 2022年4月9日 下午3:46:44
* @author znz
* @version 1.0
*/
@Controller
@RequestMapping("/oa/hr/job")
@Slf4j
public class OaHrJobController extends BaseController {
@Autowired
private OaHrJobService oaHrJobService;
/**
*
* @description
* 组织架构-部门信息跳转
* @params
* @return ModelAndView
* @author guyp
* @time 2020年4月9日 上午9:47:20
*/
@RequestMapping("/oajob")
public ModelAndView oaJob(HttpServletRequest req) {
return new ModelAndView("oa/hr/organization/oajob");
}
/**
*
* @description
* 获取岗位信息
* @params
* @return AjaxJson
* @author guyp
* @time 2020年4月9日 下午2:27:43
*/
@RequestMapping("/getJob")
@ResponseBody
public AjaxJson getJob(String id, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try{
if(StringUtils.isNotEmpty(id)) {
Map<String, Object> map = new HashMap<String, Object>();
//获取岗位信息
OaHrJobEntity job = oaHrJobService.getById(id);
map.put("job", job);
//获取父岗位信息
if(null != job.getParentId()){
OaHrJobEntity parent = oaHrJobService.getById(job.getParentId());
map.put("parentName", parent.getJobName());
map.put("parentId", parent.getId());
}
j.setAttributes(map);
}
}catch(Exception e) {
log.error("获取岗位信息报错,错误信息:{}", e.getMessage());
j.setSuccess(false);
j.setMsg("获取岗位信息错误");
e.printStackTrace();
}
return j;
}
/**
*
* @description
* 岗位保存
* @params
* @return AjaxJson
* @author guyp
* @time 2020年4月9日 下午4:18:11
*/
@RequestMapping("/save")
@ResponseBody
@Log(type = LogType.save, name = "保存部门信息", memo = "新增或编辑保存了部门信息")
public AjaxJson save(OaHrJobEntity job, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try {
if(StringUtils.isEmpty(job.getParentId())) {
job.setLevel(0);
job.setParentId(null);
}else {
OaHrJobEntity parent = oaHrJobService.getById(job.getParentId());
job.setLevel(parent.getLevel() + 1);
}
if(StringUtils.isNotEmpty(job.getParentId()) && StringUtils.equals(job.getParentId(), job.getId())) {
j.setSuccess(false);
j.setMsg("上级岗位不能选择自己,请重新选择");
return j;
}
if (StringUtils.isNotEmpty(job.getId())) {
//编辑保存
OaHrJobEntity tmp = oaHrJobService.getById(job.getId());
MyBeanUtils.copyBeanNotNull2Bean(job, tmp);
if(StringUtils.isEmpty(job.getParentId())) {
tmp.setParentId(null);
}
oaHrJobService.saveOrUpdate(tmp);
}else {
//新增保存
oaHrJobService.save(job);
}
}catch(Exception e) {
log.error("保存岗位信息报错,错误信息:" + e.getMessage());
j.setSuccess(false);
j.setMsg("保存岗位错误");
e.printStackTrace();
}
return j;
}
/**
*
* @description
* 删除岗位
* @params
* @return AjaxJson
* @author guyp
* @time 2020年4月9日 下午4:16:54
*/
@RequestMapping("/del")
@ResponseBody
@Log(type = LogType.del, name = "删除岗位信息", memo = "删除了岗位信息")
public AjaxJson del(OaHrJobEntity job, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try {
if(StringUtils.isNotEmpty(job.getId())) {
List<OaHrJobEntity> lstJobs = oaHrJobService.getChildJobsByJobId(job.getId());
if(null != lstJobs && lstJobs.size() > 0) {
j.setSuccess(false);
j.setMsg("该岗位下存在子岗位,不能直接删除");
return j;
}
//删除岗位
oaHrJobService.removeById(job.getId());
}
}catch(Exception e) {
log.error("删除岗位信息报错,错误信息:" + e.getMessage());
j.setSuccess(false);
j.setMsg("删除岗位错误");
e.printStackTrace();
}
return j;
}
}
package com.active4j.hr.hr.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.active4j.hr.base.controller.BaseController;
import com.active4j.hr.common.constant.GlobalConstant;
import com.active4j.hr.core.model.AjaxJson;
import com.active4j.hr.core.query.QueryUtils;
import com.active4j.hr.core.util.DateUtils;
import com.active4j.hr.core.util.ResponseUtil;
import com.active4j.hr.core.web.tag.model.DataGrid;
import com.active4j.hr.hr.domain.OaHrUserOverTimeModel;
import com.active4j.hr.hr.entity.OaHrOverTimeEntity;
import com.active4j.hr.hr.entity.OaHrUserEntity;
import com.active4j.hr.hr.service.OaHrOverTimeService;
import com.active4j.hr.hr.service.OaHrUserService;
import com.active4j.hr.system.entity.SysDeptEntity;
import com.active4j.hr.system.service.SysDeptService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
/**
*
* @title OaHrOverTimeController.java
* @description
加班维护管理
* @time 2022年4月24日 上午10:00:39
* @author znz
* @version 1.0
*/
@Slf4j
@Controller
@RequestMapping("/oa/hr/overtime")
public class OaHrOverTimeController extends BaseController{
@Autowired
private OaHrOverTimeService oaHrOverTimeService;
@Autowired
private OaHrUserService oaHrUserService;
@Autowired
private SysDeptService sysDeptService;
private static final String prefix_page = "oa/hr/overtime/";
/**
* 加班记录
* @param request
* @return
*/
@RequestMapping("/list")
public ModelAndView list(HttpServletRequest request) {
ModelAndView view = new ModelAndView(prefix_page + "overtimelist");
return view;
}
/**
* 加班统计界面
* @param request
* @return
*/
@RequestMapping("/statlist")
public ModelAndView statlist(HttpServletRequest request) {
ModelAndView view = new ModelAndView(prefix_page + "overtimestatlist");
List<OaHrUserOverTimeModel> lstResult = oaHrOverTimeService.queryOverTimeModel();
view.addObject("lstResult", lstResult);
return view;
}
/**
* 查询数据
* @param user
* @param request
* @param response
* @param dataGrid
*/
@RequestMapping("/datagrid")
public void datagrid(OaHrOverTimeEntity oaHrOverTimeEntity, String deptId, HttpServletRequest request, HttpServletResponse response, DataGrid dataGrid) {
oaHrOverTimeEntity.setDepartId(deptId);
//拼接查询条件
QueryWrapper<OaHrOverTimeEntity> queryWrapper = QueryUtils.installQueryWrapper(oaHrOverTimeEntity, request.getParameterMap(), dataGrid);
//执行查询
IPage<OaHrOverTimeEntity> lstResult = oaHrOverTimeService.page(new Page<OaHrOverTimeEntity>(dataGrid.getPage(), dataGrid.getRows()), queryWrapper);
//结果处理,直接写到客户端
ResponseUtil.writeJson(response, dataGrid, lstResult);
}
/**
* 跳转到新增页面
* @param request
* @return
*/
@RequestMapping("/add")
public ModelAndView add(HttpServletRequest request){
ModelAndView view = new ModelAndView(prefix_page + "overtimeadd");
//查询按用户分配权限使用的树形结构
String userTreeStr = oaHrUserService.getCompanyOfOaUser(null);
view.addObject("userTreeStr", userTreeStr);
return view;
}
/**
* 跳转到编辑页面
* @param request
* @return
*/
@RequestMapping("/edit")
public ModelAndView edit(String id, HttpServletRequest request){
ModelAndView view = new ModelAndView(prefix_page + "overtimeedit");
if(StringUtils.isNotEmpty(id)) {
//获取加班实体
OaHrOverTimeEntity time = oaHrOverTimeService.getById(id);
view.addObject("time", time);
}
return view;
}
/**
* 保存加班数据
* @param request
* @return
*/
@RequestMapping("/saveAdd")
@ResponseBody
public AjaxJson saveAdd(String[] UList, String type, String startTime, String endTime, String hours, String memo, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try{
if(null == UList || UList.length <= 0) {
j.setMsg("请选择用户!");
j.setSuccess(false);
return j;
}
if(StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime) || StringUtils.isEmpty(hours)) {
j.setSuccess(false);
j.setMsg("请填写完整的时间");
return j;
}
Date startDate = DateUtils.str2Date(startTime, DateUtils.SDF_YYYY_MM_DD_HH_MM);
Date endDate = DateUtils.str2Date(endTime, DateUtils.SDF_YYYY_MM_DD_HH_MM);
Double d = Double.valueOf(hours);
List<OaHrOverTimeEntity> lstTimes = new ArrayList<OaHrOverTimeEntity>();
for(String id : UList) {
OaHrUserEntity user = oaHrUserService.getById(id);
if(null == user) {
continue;
}
OaHrOverTimeEntity time = new OaHrOverTimeEntity();
time.setUserName(user.getRealName());
time.setUserId(user.getId());
//获取部门信息
SysDeptEntity depart = sysDeptService.getById(user.getDeptId());
time.setDepartCode(depart.getDeptNo());
time.setDepartName(depart.getName());
time.setDepartId(depart.getId());
time.setOptType(GlobalConstant.OPT_TYPE_ADD); //增加
time.setStartTime(startDate);
time.setEndTime(endDate);
time.setType(type);
time.setHours(d);
time.setMemo(memo);
lstTimes.add(time);
}
//批量保存
oaHrOverTimeService.saveBatch(lstTimes);
}catch(Exception e){
j.setSuccess(false);
j.setMsg("保存加班数据错误");
log.error("保存加班数据错误,错误原因:{}", e.getMessage());
}
return j;
}
/**
* 保存加班数据
* @param request
* @return
*/
@RequestMapping("/saveEdit")
@ResponseBody
public AjaxJson saveEdit(String id, String type, String startTime, String endTime, String hours, String memo, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try{
if(StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime) || StringUtils.isEmpty(hours)) {
j.setSuccess(false);
j.setMsg("请填写完整的时间");
return j;
}
Date startDate = DateUtils.str2Date(startTime, DateUtils.SDF_YYYY_MM_DD_HH_MM);
Date endDate = DateUtils.str2Date(endTime, DateUtils.SDF_YYYY_MM_DD_HH_MM);
Double d = Double.valueOf(hours);
OaHrOverTimeEntity time = oaHrOverTimeService.getById(id);
time.setType(type);
time.setStartTime(startDate);
time.setEndTime(endDate);
time.setHours(d);
time.setMemo(memo);
oaHrOverTimeService.saveOrUpdate(time);
}catch(Exception e){
j.setSuccess(false);
j.setMsg("保存加班数据错误");
log.error("保存加班数据错误,错误原因:{}", e.getMessage());
}
return j;
}
/**
* 删除加班数据
* @param request
* @return
*/
@RequestMapping("/del")
@ResponseBody
public AjaxJson del(String id, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
try{
if(StringUtils.isNotEmpty(id)) {
//删除
oaHrOverTimeService.removeById(id);
}
}catch(Exception e){
j.setSuccess(false);
j.setMsg("删除加班数据错误");
log.error("删除加班数据错误,错误原因:{}", e.getMessage());
}
return j;
}
}
四,项目总结
本系统功能完整,全面,可做商业应用,也可根据需求调整进行删减,做毕业设计使用。
通过明确的分析,对本文的组织结构做了以下概括:
第一部分是绪论:在这一部分,主要分析了文珺OA系统的研究背景以及意义,对文珺OA系统目前应用现状进行分析,以及最新发展概况,并且介绍了本文的研究内容以及结构安排。
第二部分是相关技术分析:这一部分主要介绍了设计和开发文珺OA系统所涉及的相关技术。重点介绍了J2EE相关技术、MySQL数据库技术、Gradle技术、Bootstrap技术,以及MVC分层结构的优缺点,后面关于系统的实现都会运用到这些技术。
第三部分是需求分析:通过相关人员的共同参与,在进行充分的探讨和调研后,确定系统的需求,并且加以整理,通过UML用例图,ER结构图以及数据库表格的方式,突出明显也更加直观的描述系统需求。
第四部分是系统设计:首先根据需求分析,系统的整体设计,分为几个重要板块,其次是系统的各种功能模块的设计,最后是数据库的设计包括了视图设计、数据表的设计,详细介绍了开发过程中系统支持的各项技术。
第五部分是系统实现:针对上面提出的每个部分进行具体的代码实现,得到最终的结果。
第六部分是系统测试:本章主要是对已经完成的文珺OA系统进行功能上的测试,看是否满足需求分析以及是否存在一些未知的Bug。