Linux+apache+mysql 搭建一个基于CGI的留言系统练习
一 系统概要:
1 系统一共有两个页面包括登录页面login.html和msg.html,showmsg.html
2 系统用户在login页面输入用户名和密码登录系统,登录成功后自动跳转到msg.html页面进行留言
3 在msg.html页面留言填入相关留言后点击提交
4 系统管理员登录后转到showmsg.html可以分页查看所有的留言信息。
二 数据库设计与实现
建立表user (id,name,password,role)
msg(title,content,submitTime)
在PowerDesigner中设计好表与表之间的关系得到 建立数据库的SQL语句如下:
/*==============================================================*/
/* DBMS name: MySQL 4.0 */
/* Created on: 2010-6-29 11:51:14 */
/*==============================================================*/
/* DBMS name: MySQL 4.0 */
/* Created on: 2010-6-29 11:51:14 */
/*==============================================================*/
drop index Relationship_1_FK on Msg;
drop table if exists Msg;
drop table if exists User;
/*==============================================================*/
/* Table: Msg */
/*==============================================================*/
create table Msg
(
MsgID decimal not null AUTO_INCREMENT,
UserID decimal not null,
Title varchar(50) not null,
Content text not null,
SubmitTime datetime not null,
primary key (MsgID)
)
type = InnoDB;
/* Table: Msg */
/*==============================================================*/
create table Msg
(
MsgID decimal not null AUTO_INCREMENT,
UserID decimal not null,
Title varchar(50) not null,
Content text not null,
SubmitTime datetime not null,
primary key (MsgID)
)
type = InnoDB;
/*==============================================================*/
/* Index: Relationship_1_FK */
/*==============================================================*/
create index Relationship_1_FK on Msg
(
UserID
);
/* Index: Relationship_1_FK */
/*==============================================================*/
create index Relationship_1_FK on Msg
(
UserID
);
/*==============================================================*/
/* Table: User */
/*==============================================================*/
create table User
(
UserID decimal not null AUTO_INCREMENT,
Name varchar(50) not null,
Password varchar(15) not null,
Role varchar(50) not null,
primary key (UserID)
)
type = InnoDB;
/* Table: User */
/*==============================================================*/
create table User
(
UserID decimal not null AUTO_INCREMENT,
Name varchar(50) not null,
Password varchar(15) not null,
Role varchar(50) not null,
primary key (UserID)
)
type = InnoDB;
alter table Msg add constraint FK_UserHaveMsg foreign key (UserID)
references User (UserID) on delete restrict on update restrict;
references User (UserID) on delete restrict on update restrict;
添加唯一约束的语句:
alter table User add constraint uq_name UNIQUE(Name);
注意的地方
编译C程序时的编译选项
gcc -I/usr/local/mysql/include mysqltest.c -o mysample -L/usr/local/mysql/lib -lmysqlclient -IZ
编译C++程序时的编译选项
g++ -I/usr/local/mysql/include mytest.cpp -o mysample -L/usr/local/mysql/lib -lmysqlclient -lz
(在加入了 -lz选项后总出现 cannot find -lz的错误 刚开始的时候以为是装mysql的时候装错了原来是装操作系统的时候少装zlib库,直接导致耽误了2个小时的时间)
三 C++ 连接MYSQL数据库后的CRUD操作的封装:
连接数据库用到的API :
mysql_init(&mysql)
mysql_real_connect(&mysql,_host,_user,_passwd,_db,0,NULL,0)
mysql_real_query(&mysql,chSql,strlen(chSql))==0
MYSQL_RES *rs = NULL;
if(ExecuteSql( chSql ))
{
rs = mysql_store_result(&mysql);
}
return rs;
if(ExecuteSql( chSql ))
{
rs = mysql_store_result(&mysql);
}
return rs;
mysql_free_result(result);
mysql_close(&mysql);
查询结果的处理
MYSQL_RES *result;
unsigned int num_fields;
unsigned int num_rows;
if (mysql_query(&mysql,query_string))
{
// error
}
else // query succeeded, process any data returned by it
{
result = mysql_store_result(&mysql);
if (result) // there are rows
{
num_fields = mysql_num_fields(result);
// retrieve rows, then call mysql_free_result(result)
}
else // mysql_store_result() returned nothing; should it have?
{
if (mysql_errno(&mysql))
{
fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}
else if (mysql_field_count(&mysql) == 0)
{
// query does not return data
// (it was not a SELECT)
num_rows = mysql_affected_rows(&mysql);
}
}
}
unsigned int num_fields;
unsigned int num_rows;
if (mysql_query(&mysql,query_string))
{
// error
}
else // query succeeded, process any data returned by it
{
result = mysql_store_result(&mysql);
if (result) // there are rows
{
num_fields = mysql_num_fields(result);
// retrieve rows, then call mysql_free_result(result)
}
else // mysql_store_result() returned nothing; should it have?
{
if (mysql_errno(&mysql))
{
fprintf(stderr, "Error: %s\n", mysql_error(&mysql));
}
else if (mysql_field_count(&mysql) == 0)
{
// query does not return data
// (it was not a SELECT)
num_rows = mysql_affected_rows(&mysql);
}
}
}
编译源程序的语句
g++ -I/usr/local/mysql/include msg.cpp DBmysql.cpp MsgEntity.cpp UserEntity.cpp -o mysample -L/usr/local/mysql/lib -lmysqlclient -lz
该端口映射的方法
/usr/sbin/iptables -F;
/usr/sbin/iptables -I INPUT -p tcp -i eth0 --dport 80 -j ACCEPT;
/usr/sbin/iptables -A INPUT -i eth0 -p tcp -j DROP;
/usr/sbin/iptables -A INPUT -i eth0 -p udp -j DROP;
/usr/sbin/iptables -I INPUT -p tcp -i eth0 --dport 80 -j ACCEPT;
/usr/sbin/iptables -A INPUT -i eth0 -p tcp -j DROP;
/usr/sbin/iptables -A INPUT -i eth0 -p udp -j DROP;
运行这些命令就可以访问80端口了
CGI读取前台表单的数据:
C语言的只能识别具有name 属性的 表单元素
由表单生成的"名/值"对用"&"符号隔开,空格变成加号"+"号,有些字符以16进制表示成"%××"。
四。 业务逻辑的实现:
通过CGI处理前台的页面请求的原理是:
1 前台表单页面在设置form标签的action属性时指定 相应的后台cgi的地址 例如<form action="http://localhost/cgi-bin/mysample" method="POST" name="msgform" > 这个CGI的地址是可以在apache的配置文件中修改相应的在服务器的映射地址的,我在本地机上httpd.conf文件中设置为:ScriptAlias /cgi-bin/ "/mnt/hgfs/PC share/project/msg/" 这样的话就达到了映射的目的
2 在前台表单中提交触发变得提交事件 document.msgform.submit(); 通过javascript实现 ,然后浏览器把表单数据进行编码后直接发送到apache服务器,apache根据表单书所请求的cgi,把该请求转叫给CGI程序处理, CGI的C程序可以通过在环境变量中读取该数据后进行处理。 在前台设置标签属性是要设定name属性,这样的话才能在后台读取,设置id的在后台读取时会出错
3
C语言的只能识别具有name 属性的 表单元素
由表单生成的"名/值"对用"&"符号隔开,空格变成加号"+"号,有些字符以16进制表示成"%××"。
所以未来联系还要再写一个字符串分离的函数,实现 把name和value分开,存于map结构中,用以方便实现后台逻辑
五。总结
1 通过写CGI来实现相关的业务逻辑,可以说对于整个后台架构来说,要求比较高,并且相当的灵活,而且具有很高的执行效率,而且我还没发现怎么来实现在CGI后台来托管用户登录的Session机制, 歪歪想了一下,可以通过写入一个唯一的数据库或文件来实现session机制。
2 在设置apache的时候要主要文件权限的设置。
3 对于C++的整个工程结构, 我还是按照了写C#的习惯, 一个表就有一个实体类对应起来,并且把相关的CRUD方法封装为静态方法。 感觉在设计整个业务系统时面向对象的设计方式并没有体现出来,工程文件结构有待学习。