1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 办公自动化OA系统

办公自动化OA系统

时间:2018-08-21 03:06:10

相关推荐

办公自动化OA系统

办公自动化OA系统

办公自动化系统(Office Automation)是替代传统办公的解决方案OA系统是利用软件技术构建的单位内部办公平台,用于辅助办公利用OA系统可将办公数据数字化,可极大提高办公流程执行效率

项目源码:/pikachu2333/oa-system

文章目录

办公自动化OA系统项目设计与需求分析办公自动化OA系统请假流程框架&组件开发阶段环境配置与准备创建Maven Web工程Maven添加插件引用配置mybatis-config.xml开发MybatisUtils工具类测试MyBatis整合Druid连接池整合Freemarker配置logback日志格式编码阶段RBAC(Role-Based Access Control) - 基于角色的访问控制开发基于RBAC的权限控制模块RBAC底层设计数据库设计 - 核心表sys_role 角色表sys_node 功能菜单,节点表sys_role_node 角色和节点对照表数据库设计 - 完整表adm_department 部门表adm_employee 员工表sys_user 用户表sys_role_user 用户和角色对照表基于LayUI开发登录页实现用户登录 - 注意MVC架构模式的运用后台校验代码结合界面通过servlet完成校验任务分析后台首页布局与设计动态显示功能菜单技巧:XML配置下实现Mapper接口基于MD5算法对密码加密MD5摘要算法MD5特点Apache Commons Codec敏感数据"加盐"混淆实现注销功能请假流程数据库设计请假流程工作流程设计约束设计表实现Dao与数据交互开发请假申请功能实现请假申请控制器完整实现请假申请功能请假审批功能

项目设计与需求分析

办公自动化OA系统

办公自动化OA系统要求采用多用户B/S架构设计开发

HR为每一位员工分配系统账户,员工用此账户登录系统

公司采用分级定岗,从1-8依次提升,不同岗位薪资水平不同

6级(含)以下员工为业务岗,对应人员执行公司业务事宜

7-8级为管理岗,其中7级为部门经理,8级为总经理

业务岗与管理岗员工可用系统功能不同,要求运行灵活配置

请假流程

公司所有员工都可以使用"请假申请"功能申请休假。所有员工都可以查看系统通知,申请请假的员工可以查看自己的请假审批进度,经理可以查看待审批的请假申请。员工请假时间少于72小时,部门经理审批后直接通过。员工请假时间大于72小时,部门经理审批后还需总经理进行审批。部门经理只允许批准本部门员工申请部门经理请假需直接由总经理审批。总经理提起请假申请,系统自动批准通过。

框架&组件

数据库:MySQL 8

ORM框架:Mybatis 3.5

数据库连接池:Alibaba Druid

J2EE web组件:Servlet 3.1

模板引擎:Freemarker 2.3

UI框架:LayUI 2.5

开发阶段

环境配置与准备

创建Maven Web工程

创建oa_system数据库

创建maven工程,jdk版本1.8

工程名oa-system,增加web工程设置

在webapp下新建一个测试页,添加配置运行

下面应用程序上下文该成/,找不到窗口拖大点!!!!!

到此工程结构配置完成。

Maven添加插件引用

pom.xml

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>oa-system</artifactId><version>1.0-SNAPSHOT</version><!-- 配置阿里云仓库优先下载jar包 --><repositories><repository><id>aliyun</id><name>aliyun</name><url>/repository/public</url></repository></repositories><dependencies><!-- mybatis 框架 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!-- MySQL 8 JDBC驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.25</version></dependency><!-- 阿里巴巴Druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.14</version></dependency><!-- 单元测试组件 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- 日志组件 --><dependency><groupId>org.jboss.pnc.build-agent</groupId><artifactId>logback</artifactId><version>1.0.1</version></dependency></dependencies><properties><piler.source>8</piler.source><piler.target>8</piler.target></properties></project>

配置mybatis-config.xml

src/main/resources/mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?><!-- 官网复制DTD约束 --><!DOCTYPE configurationPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-config.dtd"><configuration><settings><!-- 开启驼峰命名转换 form_id -> formId --><setting name="mapUnderscoreToCamelCase" value="true"/></settings><environments default="dev"><!-- 开发环境配置 --><environment id="dev"><!-- 事务管理器采用JDBC方式 --><transactionManager type="JDBC"></transactionManager><!-- 利用Mybatis自带的连接池管理连接 --><dataSource type="POOLED"><!-- JDBC连接属性;mysql8之前去掉cj包 --><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/oa_system?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments></configuration>

开发MybatisUtils工具类

src/main/java/oa/utils/MybatisUtils.java

package oa.utils;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.Reader;import java.util.function.Function;public class MybatisUtils {//static 保证全局唯一private static SqlSessionFactory sqlSessionFactory = null;//利用静态块在初始化类时实例化SqlSessionFactorystatic {try {Reader reader = Resources.getResourceAsReader("mybatis-config.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (IOException e) {//初始化错误时,通过抛出ExceptionInInitializerError通知调用者throw new ExceptionInInitializerError(e);}}//查询和修改方法封装了数据库的连接与关闭(回收),使用lambda表达式做参数,把要执行的sql语句部分代码放到调用时/*** 执行SELECT查询SQL;* @param func 要执行查询语句的代码块* @return 查询结构*/public static Object executeQuery(Function<SqlSession, Object> func) {SqlSession sqlSession = sqlSessionFactory.openSession();try {Object obj = func.apply(sqlSession);return obj;} finally {sqlSession.close();}}/*** 执行INDERT/UPDATE/DELETE写操作SQl* @param func 要执行写操作的代码块* @return 写操作后返回的结果*/public static Object executeUpdate(Function<SqlSession, Object> func) {SqlSession sqlSession = sqlSessionFactory.openSession(false); //参数false关闭自动提交事务try {Object obj = func.apply(sqlSession);mit();return obj;} catch (RuntimeException e) {sqlSession.rollback();throw e;} finally {sqlSession.close();}}}

测试

resources/mappers/test.xml

<?xml version="1.0" encoding="UTF-8" ?><!-- 将之前的config DTD约束改为mapper DTD约束 --><!DOCTYPE mapperPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="test"><select id="sample" resultType="String">select 'success'- 直接返回success字符串</select></mapper>

mybatis-config.xml 配置映射地址

<mappers><mapper resource="mappers/test.xml"/></mappers>

test/java/oa/utils/MybatisUtilsTestor.java

package oa.utils;import org.junit.Test;public class MybatisUtilsTestor {@Testpublic void testcase1() {String result = (String) MybatisUtils.executeQuery(sqlSession -> {String out = sqlSession.selectOne("test.sample");return out;});System.out.println(result);}//只有一条语句,简化写法@Testpublic void testcase2() {String result = (String) MybatisUtils.executeQuery(sqlSession -> sqlSession.selectOne("test.sample"));System.out.println(result);}}

MyBatis整合Druid连接池

oa/datasource/DruidDataSourceFactory.java

package oa.datasource;import com.alibaba.druid.pool.DruidDataSource;import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;import javax.sql.DataSource;import java.sql.SQLException;public class DruidDataSourceFactory extends UnpooledDataSourceFactory {public DruidDataSourceFactory() {this.dataSource = new DruidDataSource();}@Overridepublic DataSource getDataSource() {try {((DruidDataSource)this.dataSource).init(); //初始化Druid数据源} catch (SQLException e) {throw new RuntimeException(e);}return this.dataSource;}}

mybatis-config.xml 修改连接池配置

<dataSource type="oa.datasource.DruidDataSourceFactory"><!-- JDBC连接属性;mysql8之前去掉cj包 --><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/oa_system?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"/><property name="username" value="root"/><property name="password" value="root"/><property name="initialSize" value="10"/><property name="maxActive" value="20"/></dataSource>

整合Freemarker

pom.xml 增加引用

<!-- Freemarker依赖 --><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.29</version></dependency><!-- servlet-api --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><!-- 依赖只参与编译测试,不进行发布 --><scope>provided</scope></dependency>

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="/xml/ns/javaee"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/xml/ns/javaee /xml/ns/javaee/web-app_3_1.xsd"version="3.1"><servlet><servlet-name>freemarker</servlet-name><servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class><init-param><param-name>TemplatePath</param-name><param-value>/WEB-INF/ftl</param-value></init-param><init-param><!-- 设置读取ftl文件时采用的字符集 --><param-name>default_encoding</param-name><param-value>UTF-8</param-value></init-param></servlet><servlet-mapping><servlet-name>freemarker</servlet-name><url-pattern>*.ftl</url-pattern></servlet-mapping></web-app>

新建一个servlet测试:

src/main/java/oa/test/TestServlet.java

package oa.test;import oa.utils.MybatisUtils;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.IOException;@WebServlet(name = "TestServlet", urlPatterns = "/test")public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String result = (String) MybatisUtils.executeQuery(sqlSession -> sqlSession.selectOne("test.sample"));request.setAttribute("result", result);request.getRequestDispatcher("test.ftl").forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

记得添加发布后引用的这堆jar包

网页输入地址http://localhost/test即可看到success,也就是刚刚写的案例sql代码返回的字符串,通过freemarker添加到网页中。

配置logback日志格式

resources/logback.xml 之前的项目已经写过,直接复制过来。

<?xml version="1.0" encoding="UTF-8" ?><configuration><!-- 指定在控制台中输出日志 --><!-- name属性可以随意,如果要在控制台输出,一般称之为console --><!-- class属性指定何处打印输出 --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><!-- 编码节点 --><encoder><!--%d{HH:mm:ss.SSS}:输出时间格式,精确到毫秒[%thread]:当前操作的线程%-5level:以5个字符右对齐以及级别%logger{36}:具体哪个类的日志(只显示36个字符)%msg:日志信息%n:换行这些表达式在logback官网上都有详细说明--><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!--日志输出级别(优先级高到低):error: 错误 - 系统的故障日志warn: 警告 - 存在风险或使用不当的日志info: 一般性消息debug: 程序内部用于调试信息trace: 程序运行的跟踪信息下方root标签表示日志的最低输出级别为debug,即debug级别以下的信息不进行输出--><root level="debug"><appender-ref ref="console"></appender-ref></root></configuration>

编码阶段

RBAC(Role-Based Access Control) - 基于角色的访问控制

基于角色权限控制(RBAC)是面向企业安全策略的访问控制方式

RBAC核心思想是将控制访问的资源与角色(Role)进行绑定

系统的用户(User)与角色(Role)再进行绑定,用户便拥有对应权限

开发基于RBAC的权限控制模块

RBAC底层设计

数据库设计 - 核心表

sys_role 角色表

数据

sys_node 功能菜单,节点表

数据

sys_role_node 角色和节点对照表

数据

数据库设计 - 完整表

adm_department 部门表

实际项目中字段很多,这里只创建最核心字段 ;adm开头行政管理模块;

数据

adm_employee 员工表

数据

sys_user 用户表

数据;m8总经理级别8,t开头是研发部用户,s开头是市场部,后面数字是序号级别,方便测试;

sys_role_user 用户和角色对照表

数据;role_id2对应的1,2,6是管理岗,其他是业务岗

基于LayUI开发登录页

LayUI前端框架:/

使用LayUI快速开发登录页面

引入下载的LayUI资源,放在main/webapp/resources目录

webapp下新建login.html登录页

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>办公自动化OA系统</title><link rel="stylesheet" href="/resources/layui/css/layui.css"><style>body{background-color: #f2f2f2;}.oa-container {/*background-color: white;*/position: absolute;width: 400px;height: 350px;top: 50%;left: 50%;padding: 20px;margin-left: -200px;margin-top: -175px;}#username,#password {text-align: center;font-size: 24px;}</style></head><body><div class="oa-container"><h1 style="text-align: center;margin-bottom: 20px;">办公自动化OA系统</h1><form class="layui-form"><div class="layui-form-item"><input type="text" id="username" name="username" required lay-verify="required" placeholder="请输入账号" autocomplete="off" class="layui-input"></div><div class="layui-form-item"><input type="password" id="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input"></div><div class="layui-form-item"><!-- layui-btn-fluid 按钮与div同宽 --><button class="layui-btn layui-btn-fluid" lay-submit lay-filter="login">登录</button></div></form></div></body></html>

实现用户登录 - 注意MVC架构模式的运用

后台校验代码

创建数据库表对应的实体类

src/main/java/oa/entity/User.java

package oa.entity;public class User {private Long userId;private String username;private String password;private Long employee;public Long getUserId() {return userId;}public void setUserId(Long userId) {this.userId = userId;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Long getEmployee() {return employee;}public void setEmployee(Long employee) {this.employee = employee;}}

mappers中定义新的sql语句

main/resources/mappers/user.xml

<?xml version="1.0" encoding="UTF-8" ?><!-- 将之前的config DTD约束改为mapper DTD约束 --><!DOCTYPE mapperPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="usermapper"><select id="selectByUsername" parameterType="String" resultType="oa.entity.User">select * from sys_user where username = #{value}</select></mapper>

mybatis-config.xml 添加user.xml引用

新建User数据库表操作类

src/main/java/oa/dao/UserDao.java

package oa.dao;import oa.entity.User;import oa.utils.MybatisUtils;/*** 用户表Dao*/public class UserDao {/*** 按用户名名查询用户表* @param username 用户名* @return User对象包含对应的用户信息,null则代表对象不存在*/public User selectByUsername(String username) {User user = (User)MybatisUtils.executeQuery(sqlSession -> sqlSession.selectOne("usermapper.selectByUsername", username));return user;}}

新建UserService服务类

src/main/java/oa/service/UserService.java

package oa.service;import oa.dao.UserDao;import oa.entity.User;import oa.service.exception.BussinessException;public class UserService {private UserDao userDao = new UserDao();/*** 根据前台输入进行登录校验* @param username 前台输入用户名* @param password 前台输入密码* @return 校验通过后,包含对应用户数据的User实体类* @throws BussinessException L001-用户不存在,L002-密码错误*/public User checkLogin(String username, String password) {User user = userDao.selectByUsername(username);if (user == null) {//用户不存在抛出自定义的业务逻辑异常throw new BussinessException("L001", "用户名不存在");}if (!password.equals(user.getPassword())) {throw new BussinessException("L002", "密码错误");}return user;}}

这里抛出一个自定义的运行时异常类

service/exception/BussinessException.java

package oa.service.exception;/*** 业务逻辑异常*/public class BussinessException extends RuntimeException{private String code; //异常编码,异常的以为标识private String message; //异常的具体文本信息public BussinessException(String code, String message) {super(code + ":" + message);this.code = code;this.message = message;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}@Overridepublic String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}

新建一个测试用例类测试一下,在UserService类类名上按ctrl+shift+T生成测试用例类。

UserServiceTest.java

package oa.service;import org.junit.Test;import static org.junit.Assert.*;public class UserServiceTest {private UserService userService = new UserService();@Testpublic void checkLogin1() {userService.checkLogin("uu", "23");}@Testpublic void checkLogin2() {userService.checkLogin("m8", "testf");}@Testpublic void checkLogin3() {userService.checkLogin("m8", "test");}}

结合界面通过servlet完成校验任务

准备fastjson序列化组件

pom.xml

<!-- FastJSON JSON序列化组件 --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency>

创建控制服务类

java/oa/controller/LoginServlet.java

package oa.controller;import com.alibaba.fastjson.JSON;import oa.entity.User;import oa.service.UserService;import oa.service.exception.BussinessException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.IOException;import java.util.HashMap;import java.util.Map;@WebServlet(name = "LoginServlet", urlPatterns = "/check_login")public class LoginServlet extends HttpServlet {//org.slf4j.Logger;日志输出器Logger logger = LoggerFactory.getLogger(LoginServlet.class);private UserService userService = new UserService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("utf-8");response.setContentType("text/html;charset=utf-8");//接收用户输入String username = request.getParameter("username");String password = request.getParameter("password");Map<String, Object> result = new HashMap<>();try {//调用业务逻辑User user = userService.checkLogin(username, password);result.put("code", "0");result.put("message", "success");} catch (BussinessException exception) {logger.error(exception.getMessage(), exception);result.put("code", exception.getCode());result.put("message", exception.getMessage());} catch (Exception exception) {logger.error(exception.getMessage(), exception);result.put("code", exception.getClass().getSimpleName());result.put("message", exception.getMessage());}//返回对应结果String json = JSON.toJSONString(result);response.getWriter().println(json);}}

前端增加ajax请求跟后台交互;在最下面界面加载完后引入script

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>办公自动化OA系统</title><link rel="stylesheet" href="/resources/layui/css/layui.css"><style>body{background-color: #f2f2f2;}.oa-container {/*background-color: white;*/position: absolute;width: 400px;height: 350px;top: 50%;left: 50%;padding: 20px;margin-left: -200px;margin-top: -175px;}#username,#password {text-align: center;font-size: 24px;}</style></head><body><div class="oa-container"><h1 style="text-align: center;margin-bottom: 20px;">办公自动化OA系统</h1><form class="layui-form"><div class="layui-form-item"><input type="text" id="username" name="username" required lay-verify="required" placeholder="请输入账号" autocomplete="off" class="layui-input"></div><div class="layui-form-item"><input type="password" id="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input"></div><div class="layui-form-item"><!-- layui-btn-fluid 按钮与div同宽 --><button class="layui-btn layui-btn-fluid" lay-submit lay-filter="login">登录</button></div></form></div><script src="/resources/layui/layui.js"></script><script>layui.form.on("submit(login)", function (formdata) {//data表单包含了当前表单的的数据console.log(formdata);// 利用Ajax异步通信提交数据,LayUI内置了jQuerylayui.$.ajax({url: "/check_login",data: formdata.field,type: "post",dataType: "json",success: function (json) {if (json.code == "0") {layui.layer.msg("登录成功");} else {layui.layer.msg(json.message);}}})return false;//submit提交实际返回true则表单提交,false则阻止本次提交,因为上面使用Ajax提交});</script></body></html>

分析后台首页布局与设计

index页面设计…

动态显示功能菜单

分析:

1 - 如何获取用户编号为1的用户用有哪些功能?

用户sys_user,功能sys_node;通过两张关系表关联,sys_role_user通过用户找到对应的角色,通过用户拥有的角色在再sys_role_node找到对应的节点,在通过sys_role_node找到sys_node中的节点信息(三表关联)

select distinct n.*from sys_role_user ru, sys_role_node rn, sys_node nwhere ru.role_id = rn.role_id and user_id = 1 and rn.node_id = n.node_idorder by n.node_code

创建一个node实体类

oa/entity/Node.java

package oa.entity;public class Node {private Long nodeId;private Integer nodeType;private String nodeName;private String url;private Integer nodeCode;private Long parentId;public Long getNodeId() {return nodeId;}public void setNodeId(Long nodeId) {this.nodeId = nodeId;}public Integer getNodeType() {return nodeType;}public void setNodeType(Integer nodeType) {this.nodeType = nodeType;}public String getNodeName() {return nodeName;}public void setNodeName(String nodeName) {this.nodeName = nodeName;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public Integer getNodeCode() {return nodeCode;}public void setNodeCode(Integer nodeCode) {this.nodeCode = nodeCode;}public Long getParentId() {return parentId;}public void setParentId(Long parentId) {this.parentId = parentId;}}

在项目mappers在新建xml查询文件,然后mybatis-config.xml添加引用

rbac.xml

<?xml version="1.0" encoding="UTF-8" ?><!-- 将之前的config DTD约束改为mapper DTD约束 --><!DOCTYPE mapperPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-mapper.dtd"><mapper namespace="rbacmapper"><!-- 获取用户编号对应的功能列表 --><select id="selectNodeByUserId" parameterType="Long" resultType="oa.entity.Node">select distinct n.*from sys_role_user ru, sys_role_node rn, sys_node nwhere ru.role_id = rn.role_id and ru.user_id = #{value} and rn.node_id = n.node_id</select></mapper>

oa/dao/RbacDao.java 调用sql

package oa.dao;import oa.entity.Node;import oa.utils.MybatisUtils;import java.util.List;public class RbacDao {public List<Node> selectNodeByUserId(Long userId) {return (List<Node>) MybatisUtils.executeQuery(sqlSession -> sqlSession.selectList("rbacmapper.selectNodeByUserId", userId));}}

打开UserService.java,因为刚才的Dao是selectNodeByUserId与用户是紧密相关的,所以调用放在这里。增加:

private RbacDao rbacDao = new RbacDao(); public List<Node> selectNodeByUserId(Long userId) {return rbacDao.selectNodeByUserId(userId);}

LoginServelt.java添加调整的地址,并将用户信息存入session等待跳转后页面index的使用

//调用业务逻辑User user = userService.checkLogin(username, password);HttpSession session = request.getSession();//向session存入登录用户信息,属性名 login_usersession.setAttribute("login_user", user);result.put("code", "0");result.put("message", "success");result.put("redirect_url", "/index");

login.html登录成功增加跳转

window.location.href = json.redirect_url;

创建IndexServlet.java处理index请求

package oa.controller;import oa.entity.Node;import oa.entity.User;import oa.service.UserService;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.IOException;import java.util.List;@WebServlet(name = "IndexServlet", urlPatterns = "/index")public class IndexServlet extends HttpServlet {private UserService userService = new UserService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpSession session = request.getSession();User user = (User) session.getAttribute("login_user");List<Node> nodeList = userService.selectNodeByUserId(user.getUserId());request.setAttribute("node_list", nodeList);request.getRequestDispatcher("/index.ftl").forward(request, response);}}

WEB-INF/ftl/index.ftl

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>慕课网办公OA系统</title><link rel="stylesheet" href="/resources/layui/css/layui.css"></head><body class="layui-layout-body"><!-- Layui后台布局CSS --><div class="layui-layout layui-layout-admin"><!--头部导航栏--><div class="layui-header"><!--系统标题--><div class="layui-logo" style="font-size:18px">慕课网办公OA系统</div><!--右侧当前用户信息--><ul class="layui-nav layui-layout-right"><li class="layui-nav-item"><a href="javascript:void(0)"><!--图标--><span class="layui-icon layui-icon-user" style="font-size: 20px"></span><!--用户信息--><#--${current_employee.name}[${current_department.departmentName}-${current_employee.title}]--></a></li><!--注销按钮--><li class="layui-nav-item"><a href="/logout">注销</a></li></ul></div><!--左侧菜单栏--><div class="layui-side layui-bg-black"><!--可滚动菜单--><div class="layui-side-scroll"><!--可折叠导航栏--><ul class="layui-nav layui-nav-tree"><#list node_list as node><#if node.nodeType == 1><!--父节点--><li class="layui-nav-item layui-nav-itemed"><a href="javascript:void(0)">${node.nodeName}</a><dl class="layui-nav-child module" data-node-id="${node.nodeId}"></dl></li></#if><#if node.nodeType == 2><!--子节点--><dd class="function" data-parent-id="${node.parentId}"><a href="javascript:void(0)" target="ifmMain">${node.nodeName}</a></dd></#if></#list></ul></div></div><!--主体部分采用iframe嵌入其他页面--><div class="layui-body" style="overflow-y: hidden"><iframe name="ifmMain" src="/forward/notice" style="border: 0px;width: 100%;height: 100%"></iframe></div><!--版权信息--><div class="layui-footer">Copyright © imooc. All Rights Reserved.</div></div><!--LayUI JS文件--><script src="/resources/layui/layui.js"></script><script>//将所有功能根据parent_id移动到指定模块下layui.$(".function").each(function () {var func = layui.$(this);var parentId = func.data("parent-id");layui.$("dl[data-node-id=" + parentId + "]").append(func);});//刷新折叠菜单layui.element.render('nav');</script></body></html>

效果:实现了根据不同账号等级动态显示功能菜单,原理是传入账号在数据库中根据条件查询返回节点信息

技巧:XML配置下实现Mapper接口

动态显示右上角登录信息

获取员工

entity/Employee.java 创建员工实体类

package oa.entity;public class Employee {private Long employeeId;private String name;private Long departmentId;private String title;private Integer level;public Long getEmployeeId() {return employeeId;}public void setEmployeeId(Long employeeId) {this.employeeId = employeeId;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Long getDepartmentId() {return departmentId;}public void setDepartmentId(Long departmentId) {this.departmentId = departmentId;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Integer getLevel() {return level;}public void setLevel(Integer level) {this.level = level;}}

dao下创建EmployeeDao接口

EmployeeDao.java

package oa.dao;import oa.entity.Employee;public interface EmployeeDao {public Employee selectById(Long employee);}

创建mappers/employee.xml并在mybatis-config.xml中注册

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-mapper.dtd"><!--namespace与包名一致--><mapper namespace="oa.dao.EmployeeDao1"><!--id与方法名一致;parameterType与方法参数类型对应;resultType与方法返回类型对应--><select id="selectById" parameterType="Long" resultType="oa.entity.Employee">select * from adm_employee where employee_id = #{value }</select></mapper>

到此所有的底层工作准备完毕

创建service/EmployeeService.java employeeDao按照刚才书写的xml规则自动生成,通过getMapper获取接口对象

package oa.service;import oa.dao.EmployeeDao;import oa.entity.Employee;import oa.utils.MybatisUtils;public class EmployeeService {public Employee selectById(Long employeeId) {return (Employee) MybatisUtils.executeQuery(sqlSession -> {EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);return employeeDao.selectById(employeeId);});}}

获取部门

新建实体类entity/Department.java

package oa.entity;public class Department {private Long departmentId;private String departmentName;public Long getDepartmentId() {return departmentId;}public void setDepartmentId(Long departmentId) {this.departmentId = departmentId;}public String getDepartmentName() {return departmentName;}public void setDepartmentName(String departmentName) {this.departmentName = departmentName;}}

新建dao/DepartmentDao.java接口

package oa.dao;import oa.entity.Department;public interface DepartmentDao {public Department selectById(Long departmentId);}

新建department.xml并注册

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-////DTD Config 3.0//EN""/dtd/mybatis-3-mapper.dtd"><!--namespace与包名一致--><mapper namespace="oa.dao.DepartmentDao"><!--id与方法名一致;parameterType与方法参数类型对应;resultType与方法返回类型对应--><select id="selectById" parameterType="Long" resultType="oa.entity.Department">select * from adm_department where department_id = #{value }</select></mapper>

创建service/DepartmentService.java部门服务

package oa.service;import oa.dao.DepartmentDao;import oa.entity.Department;import oa.utils.MybatisUtils;public class DepartmentService {public Department selectById(Long departmentId) {return (Department) MybatisUtils.executeQuery(sqlSession -> sqlSession.getMapper(DepartmentDao.class).selectById(departmentId));}}

打开IndexServlet在跳转页面之前获取当前登录对应的员工是哪个;获取部门名称

private UserService userService = new UserService();private EmployeeService employeeService = new EmployeeService();private DepartmentService departmentService = new DepartmentService();@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {HttpSession session = request.getSession();//得到当前用户登录对象User user = (User) session.getAttribute("login_user");//获取当前登录员工对象Employee employee = employeeService.selectById(user.getEmployeeId());//获取员工对应部门Department department = departmentService.selectById(employee.getDepartmentId());//获取登录用户可用功能模块列表List<Node> nodeList = userService.selectNodeByUserId(user.getUserId());//放入请求属性request.setAttribute("node_list", nodeList);session.setAttribute("current_employee", employee);session.setAttribute("current_department", department);//请求派发至ftl进行展现request.getRequestDispatcher("/index.ftl").forward(request, response);}

index.ftl增加

<!--用户信息-->${current_employee.name}[${current_department.departmentName}-${current_employee.title}]

基于MD5算法对密码加密

MD5摘要算法

MD5信息摘要算法广泛使用的密码散列函数MD5可以产生一个128位的散列值用于唯一标识源数据项目中通常使用MD5作为敏感数据的加密算法

MD5特点

压缩性,MD5生成的摘要长度固定扛修改,源数据哪怕有一个字节变化,MD5也会有巨大差异不可逆,无法通过MD5反向推算源数据

Apache Commons Codec

/proper/commons-codec/

Commons-Codec是Apache提供的编码/解码组件通过Commons-Codec可轻易生成源数据的MD5摘要MD5摘要方法:String md5 = DigestUtils.md5Hex(源数据)

使用:

pom.xml maven增加依赖并在项目结构中添加

<!-- MD5摘要工具包 --><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.15</version></dependency>

utils/MD5Utils.java 新建一个工具类

package oa.utils;import mons.codec.digest.DigestUtils;public class MD5Utils {public static String md5Digest(String source) {return DigestUtils.md5Hex(source);}}

ctrl+shift+T新建测试

@Testpublic void md5Digest() {System.out.println(MD5Utils.md5Digest("test"));System.out.println(MD5Utils.md5Digest("teat"));System.out.println(MD5Utils.md5Digest("test1"));}

可以得到MD5加密后的字符串。但是对于这些简短常用的字符串MD5的值是确定的容易被暴力破解,为了增强数据安全性,引入敏感数据加盐混淆。

敏感数据"加盐"混淆

MD5Utils.java

package oa.utils;import mons.codec.digest.DigestUtils;public class MD5Utils {public static String md5Digest(String source) {return DigestUtils.md5Hex(source);}/*** 对原始字符串加盐后生成MD5摘要* @param source 原始字符串* @param salt 盐值* @return MD5摘要*/public static String md5Digest(String source, Integer salt) {char[] ca = source.toCharArray();for(int i = 0; i < ca.length; i++) {ca[i] = (char) (ca[i] + salt);}String salted = new String(ca);return md5Digest(salted);}}

将数据库中sys_user表新增salt盐值字段,将密码该为加盐后生成的加密值,每个用户盐值可以不一样;User.java实体类增加salt属性

UserService.java改为md5算法对密码进行判断

String md5 = MD5Utils.md5Digest(password, user.getSalt());if (!md5.equals(user.getPassword())) {throw new BussinessException("L002", "密码错误");}

实现注销功能

LogoutServlet.java 清除session信息并跳回登录页即可

package oa.controller;import javax.servlet.*;import javax.servlet.http.*;import javax.servlet.annotation.*;import java.io.IOException;@WebServlet(name = "LogoutServlet", urlPatterns = "/logout")public class LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.getSession().invalidate();response.sendRedirect("/login.html");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}

请假流程数据库设计

请假流程

工作流程

设计约束

每一个请假对应一个审批流程请假单创建后,按业务规则生成部门经理、总经理审批任务审批任务的经办人只能审批自己辖区内的请假申请所有审批任务"通过",代表请假已经批准任意审批任务"驳回",其余审批任务取消,请假申请被驳回请假流程中任意节点产生的操作都要生成对应的系统通知

设计表

adm_leave_form请假申请表

adm_process_flow处理流程表

sys_notice系统通知

实现Dao与数据交互

先创建3个数据表对应的实体类LeaveForm、ProcessFlow、Notice

然后创建Dao接口和对应的xml,并新建3个详细的测试用例类进行测试。

巴拉巴拉巴拉太多太多了但是逻辑比较简单不写了直接看代码吧

开发请假申请功能

LeaveFormService中根据员工等级进行判断处理

实现请假申请控制器

完整实现请假申请功能

使用SweetAlert2对话框设计页面

请假审批功能

/pikachu2333/oa-system

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。