23.2.28 Staffing System

员工管理系统功能介绍:

1)服务器负责管理所有员工表单(以数据库形式),其他客户端可通过网络连接服务器来查询员工表单。

2)需要账号密码登陆,其中需要区分管理员账号还是普通用户账号。

3)管理员账号可以查看、修改、添加、删除员工信息,同时具有查询历史记录功能,管理员要负责管理所有的普通用户。

4)普通用户只能查询修改与本人有关的相关信息,其他员工信息不得查看修改。

5)服务器能同时相应多台客户端的请求功能。并发

1 流程图

服务器:

客户端:

 

2 通信结构体

typedef struct staff_info{

int no; //员工编号

int usertype; //ADMIN 0 USER 1

char 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; //请求的消息类型

int usertype; //ADMIN 1 USER 2

char username[NAMELEN]; //姓名

char passwd[8]; //登陆密码

char recvmsg[DATALEN]; //通信的消息

int flags; //标志位

staff_info_t info; //员工信息

}MSG;

3 所需知识点

自动探测

自动换行

【1】TCP通信的编程步骤

  1.服务器:

 1)创建套接字

 2)绑定ip和端口号

 3)监听

 4)等待客户端连接

 int main() 

 { 

//1.创建套接字 

int sockfd = socket(); 

//2.初始化通信结构 

struct sockaddr_in addr; 

addr.sin_family=AF_INET; 

addr.sin_port = port; 

addr.sin_addr=addr; 

bind(sockfd, &addr); 

//3.监听 

listen(); 

//4.连接 

while(1) 

int connfd = accept(); 

//5.循环数据收发 

while(1) 

recv(); 

send(); 

close(sockfd); 

close(connfd); 

 } 

  2.客户端:

 1)创建套接字

 2)连接服务器

 int main() 

 { 

//1.创建套接字 

int sockfd = socket(); 

//2.初始化通信结构 

struct sockaddr_in addr; 

addr.sin_family=AF_INET; 

addr.sin_port = port; 

addr.sin_addr=addr; 

//3.连接 

connect(); 

//5.循环数据收发 

while(1) 

send(); 

recv(); 

 } 

【2】服务器模型

 1.循环服务器

 2.并发服务器

 1)多线程

 2)多进程

 3)IO多路复用:

a. select:

基本思想:

1. 先构造一张有关文件描述符的表(集合、数组); fd_set fd; 

2. 将你关心的文件描述符加入到这个表中;FD_SET(); 

3. 然后调用一个函数。 select / poll

4. 当这些文件描述符中的一个或多个已准备好进行I/O操作的时候

该函数才返回(阻塞)。

5. 判断是哪一个或哪些文件描述符产生了事件(IO操作); 

6. 做对应的逻辑处理; 

****select函数返回之后,会自动将除了产生事件的文件描述符以外的位全部清空; 

程序步骤:

1.把关心的文件描述符放入集合--FD_SET

2.监听集合中的文件描述符--select 

3.依次判断哪个文件描述符有数据--FD_ISSET

4.依次处理有数据的文件描述符的数据

伪代码:

fd_set fd; 

FD_SET(sockfd); 

while(1) { 

设置监听读写文件描述符集合(FD_*); 

调用select; 

select();

如果是监听套接字就绪,说明有新的连接请求

if(sockfd) 

建立连接(); 

int connfd = accept(); 

加入到监听文件描述符集合; 

FD_SET(connfd); 

}否则说明是一个已经连接过的描述符

else 

进行操作(send或者recv); 

recv(); 

send(); 

}

select弊端:

1. 一个进程最多只能监听1024个文件描述符 (千级别)

2. select是一种轮询的机制; 

3. 涉及到用户态和内核态的数据拷贝; 

b. poll

1. 优化文件描述符个数的限制; 

2. poll是一种轮询的机制; 

3. 涉及到用户态和内核态的数据拷贝; 

函数接口:   

int poll(struct pollfd *fds, nfds_t nfds, int timeout); 

参数:

struct pollfd *fds

关心的文件描述符数组struct pollfd fds[N]; 

nfds:个数

timeout: 超市检测

毫秒级的:如果填1000,1秒

 如果-1,阻塞

问题:

我想检测是键盘事件(标准输入 文件描述如为0 ),

还是鼠标事件(文件描述符是/dev/input/mouse1);  

1. 创建一个结构体数组

struct pollfd fds[2]; 

2. 将你关心的文件描述符加入到结构体成员中

struct pollfd { 

  int   fd;         // 关心的文件描述符; 

  short events;     // 关心的事件,读 

  short revents;    // 如果产生事件,则会自动填充该成员的值 

}; 

// 键盘 

fds[0].fd = 0; 

fds[0].events = POLLIN; 

//鼠标 

fds[1].fd = mouse1_fd; 

fds[1].events = POLLIN; 

3. 调用poll函数

如果返回表示有事件产生; 

poll(fds,2,1000) 

4. 判断具体是哪个文件描述符产生了事件

if(fds[0].revents == POLLIN) 

.... 

c. epoll

1. 没有文件描述符的限制

2. 异步IO,当有事件产生,文件描述符主动调用callback

3. 不用数据拷贝; 

3个功能函数:

#include <sys/epoll.h> 

int epoll_create(int size);//创建红黑树根节点 

//成功时返回epoll文件描述符,失败时返回-1 

//控制epoll属性 

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 

epfd:epoll_create函数的返回句柄。

op:表示动作类型。有三个宏 来表示:

EPOLL_CTL_ADD:注册新的fd到epfd中

EPOLL_CTL_MOD:修改已注册fd的监听事件

EPOLL_CTL_DEL:从epfd中删除一个fd

FD:需要监听的fd。

event:告诉内核需要监听什么事件

EPOLLIN:表示对应文件描述符可读

EPOLLOUT:可写

EPOLLPRI:有紧急数据可读;

EPOLLERR:错误;

EPOLLHUP:被挂断;

EPOLLET:触发方式,电平触发;

ET模式:表示状态的变化;

//成功时返回0,失败时返回-1 

//等待事件到来 

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 

功能:等待事件的产生,类似于select嗲用

epfd:句柄;

events:用来从内核得到事件的集合;

maxevents:表示每次能处理事件最大个数;

timeout:超时时间,毫秒,0立即返回,-1阻塞

//成功时返回发生事件的文件描述数,失败时返回-1 

伪代码:

1.定义epoll事件,创建epoll的fd

int epfd,epct,i; 

struct epoll_event event;       //定义epoll 事件 

struct epoll_event events[20];  //定义epoll 事件集合 

epfd = epoll_create(1); // 创建epoll 的fd  

2.填充事件

event.data.fd = serverFd;           //填充事件的fd 

event.events = EPOLLIN | EPOLLET;   //填充 事件类型  

epoll_ctl(epfd,EPOLL_CTL_ADD,serverFd,&event);  //把serverFd(监听FD)注册到epfd中 

3.监听事件

while(1){

epct = epoll_wait(epfd,events,20,-1); // 等待事件到来,阻塞模式  

for(i=0;i<epct;i++){  //根据epoll返回的值来查询事件  

if(events[i].data.fd == serverFd){ // 如果事件的fd是监听fd,调用accept处理 

clientFd = accept(); 

//添加clientfd描述符 

epoll_ctl(epfd,EPOLL_CTL_ADD,clientFd,&event);

}else {  

//如果不是serverFd,应是client数据事件,调用读数据 

read(); 

}

【3】数据库函数接口

 1.int   sqlite3_open(char  *path,   sqlite3 **db);        

功能:打开sqlite数据库  

参数:

path: 数据库文件路径         

db: 指向sqlite句柄的指针     

返回值:成功返回0,失败返回错误码(非零值) 

 2.int   sqlite3_close(sqlite3 *db); 

功能:关闭sqlite数据库

    返回值:成功返回0,失败返回错误码

 3.int sqlite3_exec(sqlite3 *db, const  char  *sql,  

sqlite3_callback callback, void *,  char **errmsg); 

功能:执行SQL语句

参数:

db:数据库句柄

         sql:SQL语句 ("create table stu .....;") 

         callback:回调函数

void * arg:

当使用查询命令的时候,callback和arg才有意义;

select .....

         errmsg:错误信息指针的地址

char *errmsg;    

&errmsg; 

返回值:成功返回0,失败返回错误码

 int callback(void *para, int f_num, char **f_value, char **f_name); 

功能:每找到一条记录自动执行一次回调函数

参数:

para:   传递给回调函数的参数

f_num:  记录中包含的字段数目(id name score)

相当于有多少列; 

f_value:包含每个字段值的指针数组

f_name:包含每个字段名称的指针数组

返回值:成功返回0,失败返回-1 

 4.int  sqlite3_get_table(sqlite3 *db, const  char  *sql, 

char ***resultp,  int *nrow,  int *ncolumn, char **errmsg); 

    功能:执行SQL操作

参数:

db:数据库句柄

sql:SQL语句

resultp:用来指向sql执行结果的指针;实际上就是“指针数组指针”;

nrow:满足条件的记录的数目,实际上就是有多少行数据; 

ncolumn:每条记录包含的字段数目,实际上就是有多少个字段(多少列); 

errmsg:错误信息指针的地址

    返回值:成功返回0,失败返回错误码

练习:创建数据库stu.db,包含name、id、score字段,实现对数据库的增删改查。

【4】员工管理系统

  1.通信结构体的定义(5min)

  2.服务器负责处理操作

客户端不能直接操作数据库

 common.h

#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <pthread.h>

#define STAFF_DATABASE 	 "staff_manage_system.db"

#define USER_LOGIN 		0x00000000  // login	登陆    0x00000001
#define USER_MODIFY 	0x00000001  // user-modification  修改
#define USER_QUERY 		0x00000002  // user-query   查询

#define ADMIN_LOGIN 	0x10000000  // login	登陆    0x00000001
#define ADMIN_MODIFY 	0x10000001 // admin_modification
#define ADMIN_ADDUSER 	0x10000002 // admin_adduser
#define ADMIN_DELUSER 	0x10000004 // admin_deluser
#define ADMIN_QUERY 	0x10000008  //hitory_query
#define ADMIN_HISTORY 	0x10000010  //hitory_query

#define QUIT 			0x11111111

#define ADMIN 0	//管理员
#define USER  1	//用户

#define NAMELEN 16
#define DATALEN 128

/*员工基本信息*/
typedef struct staff_info{
	int  no; 			//员工编号
	int  usertype;  	//ADMIN 1	USER 2	 
	char 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;     //请求的消息类型
	int  usertype;    //ADMIN 1	USER 2	   
	char username[NAMELEN];  //姓名
	char passwd[8];			 //登陆密码
	char recvmsg[DATALEN];   //通信的消息
	int  flags;      //标志位
	staff_info_t info;      //员工信息
}MSG;

#endif

Makefile

all:
	gcc server.c -o server -lpthread -lsqlite3
	gcc client.c -o client

clean:
	rm server client

 client.c

#include "common.h"

/**************************************
 *函数名:do_query
 *参   数:消息结构体
 *功   能:登陆
 ****************************************/
void do_admin_query(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);



}

/**************************************
 *函数名:admin_modification
 *参   数:消息结构体
 *功   能:管理员修改
 ****************************************/
void do_admin_modification(int sockfd,MSG *msg)//管理员修改
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);


}

/**************************************
 *函数名:admin_adduser
 *参   数:消息结构体
 *功   能:管理员创建用户
 ****************************************/
void do_admin_adduser(int sockfd,MSG *msg)//管理员添加用户
{		
	printf("------------%s-----------%d.\n",__func__,__LINE__);
}

/**************************************
 *函数名:admin_deluser
 *参   数:消息结构体
 *功   能:管理员删除用户
 ****************************************/
void do_admin_deluser(int sockfd,MSG *msg)//管理员删除用户
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}

/**************************************
 *函数名:do_history
 *参   数:消息结构体
 *功   能:查看历史记录
 ****************************************/
void do_admin_history (int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}

/**************************************
 *函数名:admin_menu
 *参   数:套接字、消息结构体
 *功   能:管理员菜单
 ****************************************/
void admin_menu(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);
}

/**************************************
 *函数名:do_query
 *参   数:消息结构体
 *功   能:登陆
 ****************************************/
void do_user_query(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}

/**************************************
 *函数名:do_modification
 *参   数:消息结构体
 *功   能:修改
 ****************************************/
void do_user_modification(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}

/**************************************
 *函数名:user_menu
 *参   数:消息结构体
 *功   能:管理员菜单
 ****************************************/
void user_menu(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);
	
}

int admin_or_user_login(int sockfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);
	//输入用户名和密码
	memset(msg->username, 0, NAMELEN);
	printf("请输入用户名:");
	scanf("%s",msg->username);
	getchar();

	memset(msg->passwd, 0, DATALEN);
	printf("请输入密码(6位)");
	scanf("%s",msg->passwd);
	getchar();

	//发送登陆请求
	send(sockfd, msg, sizeof(MSG), 0);
	//接受服务器响应
	recv(sockfd, msg, sizeof(MSG), 0);
	printf("msg->recvmsg :%s\n",msg->recvmsg);

	//判断是否登陆成功
	if(strncmp(msg->recvmsg, "OK", 2) == 0)
	{
		if(msg->usertype == ADMIN)
		{
			printf("亲爱的管理员,欢迎您登陆员工管理系统!\n");
			admin_menu(sockfd,msg);
		}
		else if(msg->usertype == USER)
		{
			printf("亲爱的用户,欢迎您登陆员工管理系统!\n");
			user_menu(sockfd,msg);
		}
	}
	else
	{
		printf("登陆失败!%s\n", msg->recvmsg);
		return -1;
	}

	return 0;
}


/************************************************
 *函数名:do_login
 *参   数:套接字、消息结构体
 *返回值:是否登陆成功
 *功   能:登陆
 *************************************************/
int do_login(int sockfd)
{	
	int n;
	MSG msg;

	while(1){
		printf("*************************************************************\n");
		printf("********  1:管理员模式    2:普通用户模式    3:退出********\n");
		printf("*************************************************************\n");
		printf("请输入您的选择(数字)>>");
		scanf("%d",&n);
		getchar();

		switch(n)
		{
			case 1:
				msg.msgtype  = ADMIN_LOGIN;
				msg.usertype = ADMIN;
				break;
			case 2:
				msg.msgtype =  USER_LOGIN;
				msg.usertype = USER;
				break;
			case 3:
				msg.msgtype = QUIT;
				if(send(sockfd, &msg, sizeof(MSG), 0)<0)
				{
					perror("do_login send");
					return -1;
				}
				close(sockfd);
				exit(0);
			default:
				printf("您的输入有误,请重新输入\n"); 
		}

		admin_or_user_login(sockfd,&msg);
	}

}

int main(int argc, const char *argv[])
{
	//socket->填充->绑定->监听->等待连接->数据交互->关闭 

	//创建网络通信的套接字

	//填充网络结构体

	//连接服务器
	if(connect() == -1){
		perror("connect failed.\n");
		exit(-1);
	}

	do_login(sockfd);

	close(sockfd);

	return 0;
}

 server.c

#include "common.h"

sqlite3 *db;  //仅服务器使用

int process_user_or_admin_login_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);
	//封装sql命令,表中查询用户名和密码-存在-登录成功-发送响应-失败-发送失败响应	
	char sql[DATALEN] = {0};
	char *errmsg;
	char **result;
	int nrow,ncolumn;

	msg->info.usertype =  msg->usertype;
	strcpy(msg->info.name,msg->username);
	strcpy(msg->info.passwd,msg->passwd);
	
	printf("usrtype: %#x-----usrname: %s---passwd: %s.\n",msg->info.usertype,msg->info.name,msg->info.passwd);
	sprintf(sql,"select * from usrinfo where usertype=%d and name='%s' and passwd='%s';",msg->info.usertype,msg->info.name,msg->info.passwd);
	if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg) != SQLITE_OK){
		printf("---****----%s.\n",errmsg);		
	}else{
		//printf("----nrow-----%d,ncolumn-----%d.\n",nrow,ncolumn);		
		if(nrow == 0){
			strcpy(msg->recvmsg,"name or passwd failed.\n");
			send(acceptfd,msg,sizeof(MSG),0);
		}else{
			strcpy(msg->recvmsg,"OK");
			send(acceptfd,msg,sizeof(MSG),0);
		}
	}
	return 0;	
}

int process_user_modify_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}



int process_user_query_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}


int process_admin_modify_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}


int process_admin_adduser_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}



int process_admin_deluser_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}


int process_admin_query_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}

int process_admin_history_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}


int process_client_quit_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);

}


int process_client_request(int acceptfd,MSG *msg)
{
	printf("------------%s-----------%d.\n",__func__,__LINE__);
	switch (msg->msgtype)
	{
		case USER_LOGIN:
		case ADMIN_LOGIN:
			process_user_or_admin_login_request(acceptfd,msg);
			break;
		case USER_MODIFY:
			process_user_modify_request(acceptfd,msg);
			break;
		case USER_QUERY:
			process_user_query_request(acceptfd,msg);
			break;
		case ADMIN_MODIFY:
			process_admin_modify_request(acceptfd,msg);
			break;

		case ADMIN_ADDUSER:
			process_admin_adduser_request(acceptfd,msg);
			break;

		case ADMIN_DELUSER:
			process_admin_deluser_request(acceptfd,msg);
			break;
		case ADMIN_QUERY:
			process_admin_query_request(acceptfd,msg);
			break;
		case ADMIN_HISTORY:
			process_admin_history_request(acceptfd,msg);
			break;
		case QUIT:
			process_client_quit_request(acceptfd,msg);
			break;
		default:
			break;
	}

}


int main(int argc, const char *argv[])
{
	//判断命令行参数	
	
	//打开数据库
	if(sqlite3_open() != SQLITE_OK){
		printf("%s.\n",sqlite3_errmsg(db));
	}else{
		printf("the database open success.\n");
	}

	//执行数据库操作
	if(sqlite3_exec()!= SQLITE_OK){
		printf("%s.\n",errmsg);
	}else{
		printf("create usrinfo table success.\n");
	}
	
	//socket->填充->绑定->监听->等待连接->数据交互->关闭

	//创建网络通信的套接字
	sockfd = socket();
	if(sockfd == -1){
		perror("socket failed.\n");
		exit(-1);
	}
	
	//填充网络结构体	

	//绑定网络套接字和网络结构体
	if(bind() == -1){
		printf("bind failed.\n");
		exit(-1);
	}

	//监听套接字,将主动套接字转化为被动套接字
	if(listen() == -1){
		printf("listen failed.\n");
		exit(-1);
	}

	//通过select实现并发

	while(1){
		retval =select();
		//判断是否是集合里关注的事件
		if(判断是连接请求){
			//数据交互 
			acceptfd = accept();
			if(acceptfd == -1){
				printf("acceptfd failed.\n");
				exit(-1);
			}					
		}else{
			recvbytes = recv();
			if(recvbytes == -1){
				printf("recv failed.\n");
				continue;
			}else if(recvbytes == 0){
				printf("peer shutdown.\n");
				close(i);
				FD_CLR(i, &readfds);  //删除集合中的i
			}else{
				process_client_request(i,&msg);
			}
		}
	}
	close(sockfd);

	return 0;
}

 


以下为员工管理系统带调试信息的打印记录:
	管理员登陆:
		客户端的打印信息
		服务器端的打印信息
		
	普通员工登陆:
		客户端的打印信息
		服务器端的打印信息
		

@@@@@@@@@@@@@@@@@@@@@@管理员登陆--客户端的测试记录:@@@@@@@@@@@@@@@@@@@@@@

linux@ubuntu:/mnt/hgfs/KernelSource/staff_manage_select/stage4-user$ ./client
sockfd :3.
*************************************************************
********  1:管理员模式    2:普通用户模式    3:退出********
*************************************************************
请输入您的选择(数字)>>1
------------admin_or_user_login-----------489.
请输入用户名:admin
请输入密码(6位)admin
msg->recvmsg :OK
亲爱的管理员,欢迎您登陆员工管理系统!


*************************************************************
* 1:查询  2:修改 3:添加用户  4:删除用户  5:查询历史记录*
* 6:退出													*
*************************************************************
请输入您的选择(数字)>>1
------------do_admin_query-----------35.
*************************************************************
******* 1:按人名查找  	2:查找所有 	3:退出	 *******
*************************************************************
请输入您的选择(数字)>>1
请输入您要查找的用户名:xiaohui
工号	用户类型	 姓名	密码	年龄	电话	地址	职位	入职年月	等级	 工资
======================================================================================
1004,    1,    xiaohui,    1,    31,    1888x,    henan,    gagagaga,    9012.10.11,    1,    1.0;.
*************************************************************
******* 1:按人名查找  	2:查找所有 	3:退出	 *******
*************************************************************
请输入您的选择(数字)>>2
工号	用户类型	 姓名	密码	年龄	电话	地址	职位	入职年月	等级	 工资
======================================================================================
1001,    0,    admin,    admin,    18,    110,    华清远见创客学院,    嵌入式物联网方向讲师,    xxx,    5,    1.0;.
======================================================================================
1003,    1,    fengjunhui,    1,    30,    18888888888,    henan,    gaga,    2015.10.23,    1,    10.0;.
======================================================================================
1002,    1,    lisi,    1,    20,    119,    华清远见创客学院=北京,    ooo,    2019.11.11,    1,    50.0;.
======================================================================================
1004,    1,    xiaohui,    1,    31,    1888x,    henan,    gagagaga,    9012.10.11,    1,    1.0;.
*************************************************************
******* 1:按人名查找  	2:查找所有 	3:退出	 *******
*************************************************************
请输入您的选择(数字)>>3


*************************************************************
* 1:查询  2:修改 3:添加用户  4:删除用户  5:查询历史记录*
* 6:退出													*
*************************************************************
请输入您的选择(数字)>>2
------------do_admin_modification-----------100.
请输入您要修改只认的工号:1002
*******************请输入要修改的选项********************
******	1:姓名	  2:年龄	3:家庭住址   4:电话  ******
******	5:职位	   6:工资  7:入职年月   8:评级  ******
******	9:密码	 10:退出				  *******
*************************************************************
请输入您的选择(数字)>>2
请输入年龄:30 
数据库修改成功!修改结束.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值