【员工管理系统】

article/2025/10/9 0:40:30

员工管理系统

  • 前言
  • 需求分析
  • 系统设计
    • 系统框图
    • 所需技术
  • 系统实现
    • 编写代码
    • 测试

前言

这是一个使用epoll实现TCP并发服务器,并让客户端登录服务器可以进行员工的管理,员工的信息存储在sqlite数据库中,对数据库进行增删改查实现对员工的添加,删除,修改,查询等功能;

需求分析

1)服务器负责管理所有员工表单(以数据库形式),其他客户端可通过网络连接服务器来查询员工表单。
2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。
3)管理员账号可以查看、修改、添加、删除员工信息,同时具有查询历史记录功能,管理员要负责管理所有的普通用户。
4)普通用户只能查询修改与本人有关的相关信息,其他员工信息不得查看修改。
5)服务器能同时相应多台客户端的请求功能。实现并发

系统设计

系统框图

server端:
在这里插入图片描述
client端:

在这里插入图片描述

所需技术

一、信息存储:
使用sqlite数据库对员工信息的存储,其中包括管理员信息和普通员工信息;同时也要对历史记录进行存储;
二、TCP通信:
使用TCP服务器,实现服务器和客户端之间的接发数据,处理客户端发来的请求,实现对员工的管理;
三、并发服务器:
并发服务器的实现方法很多,可以使用多进程多线程,也可以使用IO多路复用,这里我使用了epoll的方法来实现并发服务器,可以同时处理多个客户端发来的请求;

系统实现

编写代码

一、函数和结构体的封装

#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <time.h>
//定义大小
#define NAMELEN 20
#define DATALEN 50
#define MSGLEN 500
#define MAX_EVENTS 10
//定义IP地址和端口号
#define IP "192.168.250.100"
#define PORT 8888
// 定义消息类型
#define LOGIN 1
#define ADD 2
#define DELETE 3
#define MODIFY 4
#define SEARCH 5
#define HISTORY 6
//用户类型
#define ADMIN 0
#define USER 1
//定义员工信息结构体
typedef struct staff_info
{int id;              // 员工编号int usertype;        // ADMIN 0    USER 1char name[NAMELEN];  // 姓名char passwd[8];      // 密码int age;             // 年龄char phone[NAMELEN]; // 电话char addr[DATALEN];  // 地址char work[DATALEN];  // 职位char date[DATALEN];  // 入职年月int level;           // 等级double salary;       // 工资
} staff_info_t;
/*定义双方通信的结构体信息*/
typedef struct
{int msgtype;           // 请求的消息类型char recvmsg[MSGLEN]; // 通信的消息int flags;             // 标志位staff_info_t info;     // 员工信息
} MSG;//服务器用到的函数
int create_socket(const char *address, int port);
void init_sql(sqlite3 *db);
int handle_client(int clientfd, sqlite3 *db);
void getdata(char *date);   //获取时间
int do_login(int clientfd, MSG *msg, sqlite3 *db);
int do_add(int clientfd, MSG *msg, sqlite3 *db);
int do_delete(int clientfd, MSG *msg, sqlite3 *db);
int do_change(int clientfd, MSG *msg, sqlite3 *db);
int do_search(int clientfd, MSG *msg, sqlite3 *db);
int do_history(int clientfd, MSG *msg, sqlite3 *db);
//客户端用到的函数
int create_socket(const char *address, int port);
int login(int socket, MSG *msg, int flag);
int add(int sockfd, MSG *msg);
int delete(int sockfd, MSG *msg);
int change(int sockfd, MSG *msg);
int search(int sockfd, MSG *msg);
int history(int sockfd, MSG *msg);#endif

二、epoll并发服务器模型

    epfd = epoll_create(1);if (epfd == -1){perror("epoll_create1() error");exit(1);}// 将服务器套接字加入epoll实例的监听列表event.data.fd = sockfd;event.events = EPOLLIN;if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event) == -1){perror("epoll_ctl() error");exit(1);}while (1){epct = epoll_wait(epfd, events, MAX_EVENTS, -1); // 等待事件到来,阻塞模式if (epct == -1){perror("epoll_wait() error");exit(1);}// 处理准备就绪的套接字for (i = 0; i < epct; i++){if (events[i].data.fd == sockfd){// 新的客户端连接请求clientfd = accept(sockfd, (struct sockaddr *)&cin, &cin_len);if (clientfd < 0){perror("accept() error");exit(1);}printf("[%s:%d]连接到服务器..\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));// 将客户端套接字加入epoll实例的监听列表event.data.fd = clientfd;event.events = EPOLLIN;if (epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &event) == -1){perror("epoll_ctl() error");exit(1);}}else{// 客户端数据可读handle_client(events[i].data.fd, db);}}}

三、初始化数据库

void init_sql(sqlite3 *db)
{printf("正在初始化...\n");// 创建表char sql[256] = "";char *errmsg = NULL;strcpy(sql, "create table if not exists usr (id int,name char PRIMARY KEY,passwd char,age int,phone char,addr char,work char,data char,level int,salary double);");if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec error:%s\n", errmsg);return;}strcpy(sql, "create table if not exists log (name char,operations char,time char);");if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec error:%s\n", errmsg);return;}// 判断管理员的信息是否在数据库中char **result = NULL;int rows = -1;int columns = 0;strcpy(sql, "select * from usr where name='admin'");if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK){printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);return;}if (rows == 0){// 插入管理员信息sprintf(sql, "insert into usr values('1000','admin','admin','20','19156058040','上海','嵌入式','2022.09','4','20000');");}sqlite3_free_table(result);
}

这里直接初始化了一个管理员账户信息,管理员信息后续无法修改,有且只有一个管理员,后续对员工的管理只可以通过此管理员进行管理。

四、员工登录界面无法使用管理员账号登录
在客户端记录了登录身份信息,当处于普通员工登录界面时,无法使用管理员账户登录,服务器端会对客户端发来的数据进行判断,如果处于员工登录界面时,且用户信息是管理员,则发送登录失败。

int do_login(int clientfd, MSG *msg, sqlite3 *db)
{char data[128];int row;int cloumn;char sql[128];char *errmsg = NULL;char **result;// 匹配用户信息是否与密码表中相同sprintf(sql, "select * from usr where name = '%s' and passwd = '%s';", msg->info.name, msg->info.passwd);if (sqlite3_get_table(db, sql, &result, &row, &cloumn, &errmsg) != SQLITE_OK){printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);return -1;}// 密码表中存在改用户if (row == 1){strcpy(msg->recvmsg, "登录成功!!");msg->flags = 1; // 代表操作成功// 插入记录(用户登陆成功)getdata(data);sprintf(sql, "insert into log values('%s', 'login', '%s')", msg->info.name, data);if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK){printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);return -1;}}// 密码表中不存在改用户或者用户登录管理员账号if (row == 0 || (msg->info.usertype == 1 && strcmp(msg->info.name, "admin") == 0)){printf("登录失败\n");strcpy(msg->recvmsg, "登录失败!!");msg->flags = 0; // 代表操作失败}// 返回用户登录信息if (send(clientfd, msg, sizeof(MSG), 0) < 0){perror("send err");}return 0;
}

五、查找用户信息(添加,修改,删除 功能类似)
查找分为普通员工查找和管理员查找,管理员查找又可以根据姓名查找和查找全部,由于普通员工查找信息也是根据自己的用户名查找,所以这里只需要分两种情况编写代码,一种是根据用户名,一种是查找全部,这里是通过判断客户端传来的flag来进行判断,如果是员工查找或者是管理员通过用户名查找,flag=1,查找全部flag=0。
在使用sqlite3_get_table时,循环向客户端发送信息,一行一行的发送,客户端循环接收,当循环发送结束时,向客户端发送结束标志。
客户端

int search(int sockfd, MSG *msg)
{int n;msg->msgtype = SEARCH;if (msg->info.usertype == ADMIN){system("clear");printf("======================可查找选项==========================\n");printf("------------------------菜单-----------------------------\n");printf("\t\t\t1.根据用户名查找\n");printf("\t\t\t2.查找全部\n");printf("-----------------------------------------------------------\n");printf("请输入选项:\n");scanf("%d", &n);getchar();if (n == 1){msg->flags = 1;printf("请输入要查找的用户名:\n");scanf("%s", msg->info.name);getchar();if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("send err\n");return -1;}printf("id\t\tname\t\tpasswd\t\tage\tphone\t\taddr\twork\tdate\t\tlevel\tsalary\t\t\n");// 接收成功与否while (1){if (recv(sockfd, msg, sizeof(MSG), 0) < 0){printf("recv err\n");return -1;}printf("%s\n", msg->recvmsg);if (0 == strcmp(msg->recvmsg, "query end")){break;}}// 本次操作如果失败直接返回if (msg->flags == 0){printf("查找失败%s\n2秒刷新页面\n", msg->recvmsg);sleep(2);return -1;}// 操作成功打印查找之后的信息printf("按任意键退出查询界面:\n");getchar();return 0;}else if (n == 2){msg->flags = 0;if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("send err\n");return -1;}// 接收成功与否printf("id\t\tname\t\tpasswd\t\tage\tphone\t\taddr\twork\tdate\t\tlevel\tsalary\t\t\n");while (1){if (recv(sockfd, msg, sizeof(MSG), 0) < 0){printf("recv err\n");return -1;}printf("%s\n", msg->recvmsg);if (0 == strcmp(msg->recvmsg, "query end")){break;}}// 本次操作如果失败直接返回if (msg->flags == 0){printf("查找失败%s\n2秒刷新页面\n", msg->recvmsg);sleep(2);return -1;}// 操作成功打印查找之后的信息printf("按任意键退出查询界面:\n");getchar();return 0;}return 0;}else{// 员工查询自己msg->flags = 1;strcpy(msg->info.name, name);if (send(sockfd, msg, sizeof(MSG), 0) < 0){printf("send err\n");return -1;}printf("id\t\tname\t\tpasswd\t\tage\tphone\t\taddr\twork\tdate\t\tlevel\tsalary\t\t\n");// 接收成功与否while (1){if (recv(sockfd, msg, sizeof(MSG), 0) < 0){printf("recv err\n");return -1;}printf("%s\n", msg->recvmsg);if (0 == strcmp(msg->recvmsg, "query end")){break;}}// 本次操作如果失败直接返回if (msg->flags == 0){printf("查找失败%s\n2秒刷新页面\n", msg->recvmsg);sleep(2);return -1;}printf("按任意键退出查询界面:\n");getchar();return 0;}
}

服务器

int do_search(int clientfd, MSG *msg, sqlite3 *db)
{char sql[128];char *errmsg;char **result;int row;int cloum;int i, j;if (msg->flags == 1) // 根据姓名查找{sprintf(sql, "select *from usr where name = '%s' ", msg->info.name);}else if (msg->flags == 0) // 查找全部{sprintf(sql, "select *from usr ");}if (sqlite3_get_table(db, sql, &result, &row, &cloum, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);msg->flags = 0; // 失败标志}else{msg->flags = 1; // 成功标志}for (int i = 1; i <= row; i++){sprintf(msg->recvmsg, "%-8s\t%-8s\t%-8s\t%-5s\t%-15s\t%-8s\t%-8s\t%-10s\t%-5s\t%-10s\n", result[i * cloum], result[i * cloum + 1], result[i * cloum + 2], result[i * cloum + 3], result[i * cloum + 4], result[i * cloum + 5], result[i * cloum + 6], result[i * cloum + 7], result[i * cloum + 8], result[i * cloum + 9]);if (send(clientfd, msg, sizeof(MSG), 0) < 0){perror("send err");}}strcpy(msg->recvmsg, "query end");if (send(clientfd, msg, sizeof(MSG), 0) < 0){perror("send err");}sqlite3_free_table(result);return 0;
}

六、查询历史记录功能
管理员可以查询历史记录,在执行登录、添加员工、删除员工、修改员工信息时,都会将记录插入到记录表中,管理员可以查询记录表中的内容。查询记录和查询员工信息相似。

int do_history(int clientfd, MSG *msg, sqlite3 *db)
{char sql[128];char *errmsg;char **result;int row;int cloum;int i, j;sprintf(sql, "select *from log ");if (sqlite3_get_table(db, sql, &result, &row, &cloum, &errmsg) != SQLITE_OK){printf("%s\n", errmsg);msg->flags = 0; // 失败标志}else{msg->flags = 1; // 成功标志}for (int i = 1; i <= row; i++){sprintf(msg->recvmsg, "%-8s\t%-8s\t%-8s\t\n", result[i * cloum], result[i * cloum + 1], result[i * cloum + 2]);if (send(clientfd, msg, sizeof(MSG), 0) < 0){perror("send err");}}strcpy(msg->recvmsg, "query end");if (send(clientfd, msg, sizeof(MSG), 0) < 0){perror("send err");}sqlite3_free_table(result);return 0;
}

注:完整代码见:员工管理系统

测试

对所有功能进行测试,是否可以实现多个客户端同时登录,是否可以添加、删除、修改、查看员工信息,以及管理员查看历史记录等功能:

员工管理系统


http://chatgpt.dhexx.cn/article/Z2NP6Jqo.shtml

相关文章

一个简单的请假系统

本项目是一个简单的spring项目&#xff0c;使用了springmybatis&#xff0c;实现数据的增&#xff0c;删&#xff0c;查&#xff0c;和poi的基本使用&#xff0c;导出数据库中的请假信息到excel中等一些基本的功能。有很多不足之处欢迎大家指出&#xff0c;后面慢慢学习会慢慢优…

Java项目:JSP员工出差请假考勤管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目为后台管理系统&#xff1b; 管理员角色包含以下功能&#xff1a; 登录,首页,考勤记录增删改查,假期申请记录增删改查,出差申请记录增删…

适合学生写的请假管理系统

学生请假管理系统 可以浅浅的看一下目 录了解一下 第1章 概述 6 1.1案例功能简介 6 1.2大纲 6 1.3总体设计 8 1.4数据库 8 第2章 设计步骤及实现 11 2.1 注册并登录学生请假管理系统 11 2.2 用户管理界面 15 2.3 请假管理界面 18 2.4 公告管理界面 21 2.5 本分源代码的展示 24…

基于javaweb的员工出差请假考勤管理系统(java+jsp+layui+html+servlet+mysql)

基于javaweb的员工出差请假考勤管理系统(javajsplayuihtmlservletmysql) 运行环境 Java≥8、MySQL≥5.7、Tomcat≥8 开发工具 eclipse/idea/myeclipse/sts等均可配置运行 适用 课程设计&#xff0c;大作业&#xff0c;毕业设计&#xff0c;项目练习&#xff0c;学习演示等…

员工请假系统

演示地址&#xff1a; http://222.73.130.227:8100 已有用户及密码&#xff1a; adminleave.com/123 zhangsanqq.com/123 lisiqq.com/123 注意&#xff1a;如果需要对演示系统新添加用户&#xff0c;密码建议使用不常用的&#xff0c;尽管用户信息已使用加密存储 源码下载…

员工考勤管理系统

这里写自定义目录标题 1、需求分析1.1系统概述、产品说明1.2功能需求分析1.3开发使用工具1.4开发原则1.5开发目标1.6项目进度 2、概要设计、项目简介2.1 页面概述2.2设计思路2.3流程图&#xff08;页面结构&#xff09; 3、详细设计3.1页面介绍&#xff08;包含页面截图、功能说…

学生请假管理系统(需求说明+项目(部分代码))

一、需求说明书 软件需求说明书 1引言 1.1编写目的 开发本系统的目的&#xff0c;就是要解决目前我校关于学生请假和管理请假事务所面临的一系列问题。 1.2背景 说明&#xff1a; 计算机学院请假管理系统&#xff1b;目前我校基本上是采用线下请假&#xff0c;学生先是向班主任…

请假管理系统

更多技术文章请访问我的个人博客http://www.rain1024.com 请假管理系统 这几天受朋友之托&#xff0c;写了一个请假管理系统&#xff0c;使用PHP作为开发语言&#xff0c;使用ThinkPHP作为开发框架&#xff0c;使用了大量的ajax进行数据的传输验证&#xff0c;当然还有很多细…

Java项目:员工出差请假考勤管理系统(java+JSP+LayUI+HTML+servlet+Mysql)

源码获取&#xff1a;俺的博客首页 "资源" 里下载&#xff01; 项目介绍 本项目为后台管理系统&#xff1b; 管理员角色包含以下功能&#xff1a; 登录,首页,考勤记录增删改查,假期申请记录增删改查,出差申请记录增删改查,加班申请记录增删改查,调休申请,考勤查询,…

员工请假管理系统(MFC+ACCESS数据库+ODBC数据源)

主要界面:(未添加皮肤) 登陆界面: 主界面: 1.题目要求 用MFC和ACCESS数据库设计一个请假管理系统可以进行对员工请假的管理和对公司假期及国定假期的设定。 2.功能需求 2.1.系统管理 更换登录用户 退出 2.2.请假管理窗体 员工请假登记 删…

基于VB的员工请假管理系统设计与实现

目录 第一章 概述 1 1.1 项目背景与意义 1 1.2 可行性分析 1 1.2.1 技术可行性 1 1.2.2 经济可行性 2 1.2.3 运行可行性 2 1.3 相关技术与开发工具介绍 3 1.3.1 Visual Basic 6.0简介 3 1.3.2 Access数据库的介绍 5 第2章 总体设计 6 2.1 员工请假管理系统简介 6 2.1.1 整体说…

sql语句--模糊查询

模糊查询 1.like 表示模糊查询&#xff0c;这个没什么难的&#xff0c;已经见识过了。 2.配合like关键字&#xff0c;% 表示任意多个字符&#xff0c;表示这个玩意第一次知道&#xff0c;走着…… select * from students where hometown like %苏;3.同样是配合like关键字使…

模糊查询和sql语句的拼接

如下面图片所示&#xff1a;进行模糊查询 前端的页面代码&#xff1a; 注意&#xff1a;请选择那里的value"" 一定要写 <body><form action"SearchStuServlet" method"post"><table border"1px" width"700"…

sql查询之模糊查询

like 这里可以参照一下菜鸟教程、mysql like一般用于字符串查询%代表半匹配查询 SELECT * FROM student WHERE name "孙悟空";SELECT * FROM student WHERE name LIKE "孙悟空";SELECT * FROM student WHERE name LIKE "孙%";以上第一个sql语…

Mybatis模糊查询SQL语句

模糊查询 <sql id"where_case"><if test"username!null and username ! ">and username like concat(%,#{username},%)</if><if test"userrole!null">and userrole#{userrole} </if></sql> #{ }预编译S…

java中模糊查询sql怎么写,mybatis模糊查询sql,

mybatis模糊查询sql, 今天下午做的一个功能,要用到模糊查询,字段是description,刚开始我的写法用的是sql中的模糊查询语句, 但是这个有问题,只有将字段的全部值传入其中,才能查询,所以不是迷糊查询。 后来经过搜索,发现要加上一个concat字段,要先将字符串拼接后,才能…

java中sql模糊查询_模糊查询的sql语句(java模糊查询sql语句)

模糊查询的sql语句(java模糊查询sql语句) 2020-07-24 11:06:02 共10个回答 假设表名为product,商品名为name,简界为remark.则可如下写:select[name],[remark]fromproductnamelike%aa%orremarklike%aa%.注:上面单引号的aa你表模糊查询输入的字符. 一般模糊查询语句如下:SELECT字…

连接Oracle出现协议适配器错误

在连接Oracle的时候出现如下图所示的协议适配器错误时 说明此时电脑上的Oracle服务没有开 解决步骤: 1.WindowsR 输入services.msc 点击确定 2.找到字母O开头的服务 将OracleServiceXE服务和OracleXETNSListener服务打开 注意: 如果电脑性能比较好,推荐将这两个服务的启动类…

【已解决】SQL PLUS出现协议适配器错误

今天在做c#课程设计的时候&#xff0c;在登录页面实现数据库插入时候出现insert into语句错误&#xff08;使用access数据库&#xff09;。 在和其他专业小伙伴讨论他们使用access也出现了错误&#xff0c;但换了sql server之后成功实现&#xff0c;于是也想换成sql server&am…

ORACLE登录时,协议适配器错误的可能原因

我们进入sqlplus登录界面用管理员账号登录时会显示协议适配器错误 这种情况我们首先看一下&#xff0c;我们监听服务是否是打开的。 如果没有启动&#xff0c;把他启动就好了。 如果是打开的&#xff0c;就可能是你的注册表的oracle_sid没设置好 首先&#xff0c;我们先查看我…