【数据库】【课程设计】商品销售信息管理系统设计
作者:互联网
商品销售信息管理系统设计
1.设计目的
商品销售信息管理系统主要用于对商品信息的管理,包括客户端和管理端两部分,分别涉及商品购买和各类信息的处理。此系统的设计实现需要首先根据需求提出数据存储方案和信息管理技术方案,设计关系表上并规划相匹配的信息管理功能,分析其详细处理流程并用模块化程序设计思想进行程序系统设计、模块编程、测试,可以从中复习巩固关系型数据库的相关理论知识,运用所学开展信息管理对象的“实体-关联”分析,提高设计信息存储的“关系数据库、数据表”相关能力,积累数据库应用程序的综合开发能力,提高创新意识、创新能力。
2.需求分析
2.1系统业务分析
系统主要业务可分为客户需要的操作和管理员需要的操作。
其中,客户的业务包括:实名注册、查看商品信息、提交商品订单、查看自己订单、确认货到付款。
管理员的业务包括:信息查询、信息导入、信息管理、信息统计和导出报表,涉及到的信息包括客户信息、订单信息、商品信息和统计信息。
2.2系统数据处理分析
根据系统主要业务,可以分析得到管理员子系统和客户子系统两个主要子系统以及对应的数据流,系统顶层数据流图如图2-1所示。
客户子系统主要的数据处理过程分为对个人信息的处理、对商品的处理和对订单的处理,包括实名注册、查看个人信息、系统登录、查看商品信息、更新订单状态和查看订单信息,具体处理如下。
实名注册:提交个人信息,生成申请记录,转管理员端处理。
查看个人信息:给出个人信息记录。
系统登录:给出用户名和密码,提交登录,用户名存在且审核通过返回成功,否则返回对应错误。
查看商品信息:给出详细或模糊的商品描述,若能查询到,返回该商品信息否则返回对应错误。
更新订单状态:给出指定订单和相应操作,包括提交订单、修改订单、取消订单和确认货到付款,将操作结果转管理员端。
管理员子系统主要的数据处理过程分为对客户信息的处理、对商品的处理和对订单的处理,包括确认用户注册、查看客户信息、查看商品信息、更新商品信息、更新订单状态和查看订单信息,具体处理如下。
确认用户注册:给出申请记录和客户信息,若审核通过,更改申请记录状态和客户信息状态,返回给客户端。
查看客户信息:给出待查看客户信息编号或者待查看客户信息范围,给出指定客户信息或多条客户信息记录,若不存在指定客户,返回错误。
查看商品信息:给出待查看商品信息编号或者待查看商品信息范围,给出指定商品信息或多条商品信息记录,若不存在指定商品,返回错误。
更新商品信息:给出待更改商品编号及更新操作,可对该商品进行出库、入库、发货或者修改商品名称和价格。
更新订单状态:给出待更改订单编号及更新操作,可确认该订单发货、取消订单、修改订单中地址、商品数量等信息。
查看订单信息:给出待查看订单信息编号或者待查看订单信息范围,给出指定订单信息或多条订单信息记录,若不存在指定订单,返回错误。
2.3系统数据字典
由图2-1可知系统顶层数据流,进一步分析可知用户子系统和管理员子系统功能如下。
(1)客户子系统
查看、修改和校验个人信息:客户→P1,客户→P2,客户→P3;
提交注册信息:客户→P4;
查看、更新订单信息:客户→P5,客户→P6;
查看商品信息:客户→P7。
(2)管理员子系统
查看、修改客户信息:管理员→P7;
审核用户注册:管理员→P8;
查看、更新订单信息:管理员→P6;
查看、更新商品信息:管理员→P7,管理员→P9。
综上所述,可得如表2-1所示的系统主要数据流定义。
序号 | 数据流名称 | 数据流位置 | 结构定义 |
---|---|---|---|
1 | 查看个人信息/修改个人信息/系统登录/查看客户信息 | 客户→P1,客户→P3,客户→P2,管理员→P7 | 身份证号+姓名+电话+地址+用户名+密码 |
2 | 实名注册/确认注册 | 客户→P4,管理员→P8 | 用户名+审核状态+审核时间 |
3 | 查看订单信息/更新订单信息 | 客户→P5,客户→P6,管理员→P6 | 订单编号+用户名+商品名称+商品数量+价格+创建时间+发货状态+付款状态+地址 |
4 | 查看商品信息 | /更新商品信息 | 客户→P7,管理员→P7,管理员→P9 |
根据图2-1和表2-1分析可知,管理员子系统和客户子系统中包含有类似的数据,则系统中主要包含四类数据,即D1客户信息、D2订单信息、D3商品信息、D4申请记录,其主要存储结构定义如表2-2所示。
序号 | 数据流名称 | 输入 | 输出 | 结构 | 说明 |
---|---|---|---|---|---|
D1 | 客户信息 | 客户管理 | 查看、实名注册、更新客户信息 | 身份证号+姓名+电话+地址+用户名+密码 | 身份证号唯一非空符合格式,姓名密码电话非空,电话时间格式 |
D2 | 订单信息 | 订单管理 | 查看、更新订单信息 | 订单编号+用户名+商品名称+商品数量+价格+创建时间+发货状态+付款状态 | 用户名唯一非空,商品名称多值价格对应,发货付款状态非空 |
D3 | 商品信息 | 商品管理 | 查看、更新订单信息 | 商品编号+商品名称+商品数量+价格 | 名称唯一非空、价格格式 |
D4 | 申请记录 | 客户管理 | 实名注册 | 用户名+审核状态+审核时间 | 用户名非空,时间格式 |
综合表2-1和表2-2可知,客户子系统的数据处理过程包括对个人信息的处理部分P1和对购物信息的处理部分P2。在个人信息模块P1中包含的处理过程包括P1.1查看个人信息、P1.1查看个人信息、P1.2修改个人信息、P1.3实名注册和P1.4系统登录,在购物信息处理模块P2中包括P2.1确认货到付款、P2.2查看订单信息、P2.3查看商品信息、P2.4提交订单和P2.5取消订单。各部分输入输出和处理说明见表2-3。
编号 | 处理过程名 | 输入 | 输出 | 处理说明 |
---|---|---|---|---|
P1.1 | 查看个人信息 | 用户账号 | 该账号信息 | 在用户数据库中找指定账号信息 |
P1.2 | 修改个人信息 | 用户账号 | 修改结果、修改信息 | 在用户数据库中改指定账号信息 |
P1.3 | 实名注册 | 用户身份信息 | 注册结果 | 提交管理员 |
P1.4 | 系统登录 | 用户账号密码 | 登录结果 | 比对账号密码是否一致 |
P2.1 | 确认货到付款 | 用户账号、订单号 | 确认结果 | 修改订单状态 |
P2.2 | 查看订单信息 | 用户账号、订单号 | 订单信息 | 在订单数据库中查找指定信息 |
P2.3 | 查看商品信息 | 商品名称 | 商品信息 | 在商品数据库中查找指定信息 |
P2.4 | 提交订单 | 用户账号、数量、商品名称、时间 | 提交结果 | 在订单数据库中写入相关信息 |
P2.5 | 取消订单 | 用户账号、订单号 | 取消结果 | 改变该订单状态 |
综合表2-1和表2-2可知,管理员子系统的数据处理过程包括对客户信息的处理部分P1对商品信息的处理部分P2和对订单信息的处理部分P3。在个人信息模块P1中包含的处理过程包括P1.1查看客户信息、P1.2确认客户注册,在商品信息处理模块P2中包括P2.1查看商品信息和P2.2更新商品信息,在订单信息处理模块P3中包括P3.1查看订单信息、P3.2更新订单状态和P3.3确认发货。各部分输入输出和处理说明见表2-4。
过程编号 | 处理过程名 | 输入 | 输出 | 处理说明 |
---|---|---|---|---|
P1.1 | 查看客户信息 | / | 客户信息 | 到指定数据库中查找客户信息并输出 |
P1.2 | 确认客户注册 | 注册请求 | 注册答复 | 交由管理员确定是否允许注册 |
P2.1 | 查看商品信息 | / | 商品信息 | 到指定数据库中查找商品信息并输出 |
P2.2 | 更新商品信息 | 商品、操作 | 操作结果 | 对指定商品信息进行指定操作 |
P3.1 | 查看订单信息 | / | 订单信息 | 到指定数据库中查找订单信息并输出 |
P3.2 | 更新订单状态 | 订单、操作 | 操作结果 | 对指定订单信息进行指定操作 |
P3.3 | 确认发货 | 订单、商品、发货数量 | 发货状态 | 修改订单状态和商品状态 |
3.系统设计
3.1系统开发框架
系统设计基于ASP.NET Core,使用Entity Framework MVC框架进行开发,包含表示层、业务逻辑层和数据访问层三层结构。其中表示层使用网页技术设计页面及控件,业务逻辑层使用C#语言完成代码逻辑,数据访问层通过C#的MySQL扩展接口实现与MySQL数据库的连接。整体代码在Visual Studio 2019 和Visual Code2019中完成编写与调试,操作系统兼容Windows 7以上系统,数据库使用MySQL 8.0。
3.2系统功能组成设计
3.2.1 系统功能组成
分析可知,商品信息管理系统主要分为管理员子系统和客户子系统两部分,进入管理员子系统后可以管理整个系统,在整个系统中被管理的对象主要包括客户信息、商品信息和订单信息,此外,管理员还可以统计相关信息,并将内部信息导出为文件或从外部文件中导入相关信息(文件存储为Excel格式),进入客户子系统可以管理个人信息或者进行购物。由此可得系统除上述两个子系统外,还应划分为商品购物、个人信息管理、商品信息管理、订单信息管理、客户信息管理、信息统计(包含文件导入导出)这几个主要模块。
其中,客户子系统只能访问个人信息管理和商品购物两个模块,可以在前者中执行注册、登录、修改信息和查看信息功能,在商品购物模块中,可以查看商品信息、提交订单、修改订单或者确认货到付款。管理员除可以访问所有客户的客户子系统外,还可以访问其他模块。在管理员的客户信息模块中,管理员能够确认用户的注册或者修改用户信息,在商品管理模块中,可以管理商品信息(包含商品发货)或者查看商品信息,在订单信息管理状态模块中可以查看或者更新订单状态,在统计模块中可以对系统中管理的各个对象信息进行分析统计或者利用外部文件构造内部信息以及将内部信息导出为外部文件。具体的系统功能层次划分图如图3-1所示。综合上述分析可知,使用系统的角色主要包含“管理员”和“客户”两种角色,功能层次图最底层中功能为二者执行系统功能时的具体用例,其余层及其关系为二者使用系统时的顶层用例划分,则可依据图3-1得到系统顶层用例图如图3-2所示,管理员子系统对客户子系统的操作通过用例间的包含和扩展关系体现,同时可依据功能层次图最底层得到细分的系统功能用例图如图3-2所示。
综合上述分析可知,系统顶层用例图如图3-2所示。
3.2.2 子系统功能模块设计
根据上述3.1设计子系统功能模块和界面,开始时系统界面布局如图3-4所示,其中包含提示信息和“管理系统”、“用户登录”两个按钮。
上述图3-6与图3-7中管理权限获取界面和用户登录界面执行流程如图3-8所示,管理员验证默认秘钥成功后进入管理员界面,失败后给出提示信息,若三次不成功则登陆失败,返回主界面,并在一段时间内不能登录。用户在验证密码和用户名匹配后进入用户界面,若不匹配同样给出提示并在三次后暂时不能登陆,此时提示信息变为管理员联系方式,可联系管理员修改信息。
管理员子系统界面布局如图3-9所示,其中左边包括可执行功能的按钮栏目,右边为信息显示区域和对信息操作的按钮。
用户子系统界面布局如图3-10所示,与管理员子系统相同,其左右同样分别为操作按钮栏目和信息显示窗口,并可在信息显示窗口下方的按钮执行对上方信息的操作。
在管理员和用户界面中,所有对于信息的查看和修改操作执行流程均相同,只是对于不同的信息,将跳转到不同的执行界面,因而不在此赘述。两个子系统中所有查看、修改信息的执行流程图如图3-11所示。如果在左侧按钮栏选择查看某种信息,则在右方显示对应的信息,如果没有进一步的操作,信息将持续显示,如果有进一步的操作,跳转到对应的操作。在选择信息修改时,可修改的信息会从文本变为可编辑文本框,在框内输入符合格式的信息后按相应按钮确认,即可完成操作。上图3-10中内容即为用户在对个人信息中的地址修改时的样例,客户在选择修改个人信息后,可修改的地址后出现文本框,将其内容修改完成后选择确认修改,即可完成对个人地址信息的修改。查看个人信息时页面显示与图3-12当前状态相同,但不存在可编辑的文本框。
用户子系统中查看订单信息和商品信息界面布局如图3-12和3-13所示。订单信息中包含确认收货、修改订单信息和提交订单三个按钮,修改信息的流程如上图3-13所示。
确认收货与提交订单流程如图3-14(左)所示,在选择相应功能后订单中对应的状态会发生改变。如果需要购买商品,其流程如图3-14(右)所示,输入数量后加入订单即可。
3.3数据库结构设计
3.3.1 商品管理系统的对象/实体
首先将使用商品管理系统的角色转换为实体,由上文分析可知此角色包含客户和管理员,在此次设计中认为只存在一位持有秘钥的管理员且不考虑其管理员信息,故可将管理员实体省略。此外,系统中主要包含对商品的处理,故应将商品作为一实体。其主要联系包括:
客户通过浏览商品购买商品,并进行提交,申请者通过实名认证发出认证请求,管理员进行审核,管理员对客户信息、商品信息、订单信息进行维护更新和查看。
管理员还要进行定期的商品销售、客户信息以及订单等信息统计与分析。所以此系统的概念模型如图3-15所示,由于申请者信息与客户信息仅在申请状态上有所差异,其余信息完全相同,所以可以将申请状态作为客户信息的一个字段,将申请者同样视为客户,从而简化设计。
3.3.2 概念模型转换为关系模型
综合上述内容,分析可得系统关系模型图如图3-16所示。
客户(身份证号|姓名|电话|用户名|密码|地址|申请状态);
商品(商品编号|商品名称|商品数量|价格);
订单(订单号|用户名|商品名称|商品数量|总价|创建时间|发货状态|付款状态)。
3.3.2 定义关系模型
对于表“客户(身份证号|姓名|电话|用户名|密码|地址|申请状态)”,主键为用户名,属性间的仅存在函数依赖关系:{申请状态·姓名·密码·地址→身份证号,申请状态·姓名·密码·地址→电话,申请状态·姓名·密码·地址→用户名},符合3NF的要求。
对于表“订单(订单号,用户名,商品名称,商品数量,总价,创建时间,发货状态,付款状态)”,主键为订单号,属性间存在函数依赖关系:{商品名称→商品数量},根据3NF的要求,将表订单拆分为两张表,其中“订单”表作为主表,“订单商品”表作为从表,将订单表的主键作为订单商品表的外键。在订单中包含属性“订单编号|客户编号|订单总价|付款状态|发货状态”,在订单商品汇总包含属性“订单商品编号|订单编号|商品编号|商品数量|商品总价”。由此,可满足3NF的要求。
对于表“商品(商品编号,商品名称,商品数量,价格)”,主键为商品编号,属性间的仅存在函数依赖关系::{商品名称→商品数量,商品名称→价格},符合3NF的要求。
由上述内容归纳总结出三张表中属性的详细信息如表3-1所示,表中包含各表的表名、属性、数据类型、长度、是否可空、索引信息、属性约束和表级约束。在后续的设计过程中,个属性的基本信息均需遵从该表的规定。
表名 | 属性 | 数据类型 | 长度 | 可空 | 索引 | 属性约束 | 表级约束 |
---|---|---|---|---|---|---|---|
客户 | 身份证号 | char | 18 | no | 索引 | 全为数字 | 主码:用户名 |
- | 姓名 | varchar | 12 | no | 索引 | / | - |
- | 电话 | char | 11 | no | / | 全为数字 | - |
- | 用户名 | varchar | 12 | no | 索引 | 主属性 | - |
- | 密码 | varchar | 15 | no | 索引 | 字母数字混合 | - |
- | 地址 | text | 20 | no / | / | - | |
- | 申请状态 | tinyint(1) | 1 | no | / | 0无效,1有效,-1曾有效 | - |
商品 | 商品编号 | char | 10 | no | 索引 | 主属性 | 主码:商品编号 |
- | 商品名称 | varchar | 11 | no | 索引 | / | - |
- | 商品数量 | int | 4 | no | / | 非负 | - |
- | 价格 | double | 5 | no | / | 正数 | - |
订单 | 总价 | double | 5 | no | / | 非负 | 主码:订单号 从键:商品名称,用户名 |
- | 发货状态 | tinyint(1) | 3 | no | / | 0未发货,1已发货 | - |
- | 付款状态 | tinyint(1) | 3 | no | / | 0未付款,1已付款 | - |
- | 订单号 | varchar | 10 | no | 索引 | 主属性 | - |
- | 用户名 | varchar | 12 | no | 索引 | / | - |
订单商品 | 订单商品编号 | varchar | 10 | no | 索引 | 主属性 | |
- | 商品名称 | varchar | 11 | no | 索引 | / | - |
- | 购买数量 | int | 4 | no | / | 非负 | - |
- | 订单号 | varchar | 10 | no | 索引 | 外键 | - |
- | 商品总价 | double | 4 | no | / | / | - |
基于根据上述内容,可得到完整的数据关系图如图3-16所所示。图中矩形框代表一张表,其中矩形框的顶部为该表的表名,下方为表中各属性及该属性在数据库中的数据类型。如果该属性为该表的主属性,则在该属性处用下划线和标识。各表间的从属关系用由从表指向主表的箭头表示,作为外键的属性在从表中用加以标识。图中的表明、属性名符合MySQL数据库中关系表的命名规则,以便于后续编程实现。
在图3-16中,客户表为customer,商品表为product,订单表为orders,订单商品表为iporder,各表的主键分别为该表的编号,各属性信息与上表3-1相同。
4.数据库实施与数据准备
4.1数据库实施
根据附录中的小组分工表,此设计报主要针对订单相关的两张表单进行设计与实现。首先由图3-16中建立的数据关系图在数据库中建立相关表,建立orders表的SQL语句如代码4-1所示,用CREATE语句创建表orders,在括号中对所有属性命名并规定其类型,用NOT NULL标记该属性不为空,对于pay_state(付款状态)和send_state(发货状态)两个状态,其取值只能取1和0,分别表示已操作和未操作,则利用 CHECK ( pay_state IN ( 0, 1 ) ) 语句检查其取值是否在取值区间范围内,send_state 状态的-1用于标记该订单已被取消或退货,pay_state被用于标识该订单已被删除,利用PRIMARY KEY(cid) 表明其主键为oid。最后通过下方的语句,将该表对客户的外键依赖添加在该表上。
/* Table: orders*/
CREATE TABLE orders (
oid VARCHAR ( 10 ) NOT NULL,
cid VARCHAR ( 10 ) NOT NULL,
total_price DOUBLE NOT NULL,
pay_state INT NOT NULL CHECK ( pay_state IN ( 0, 1 , -1 ) ) ,
send_state INT NOT NULL CHECK ( send_state IN ( 0, 1 , -1 ) ) ,
PRIMARY KEY ( oid )
);
ALTER TABLE orders ADD CONSTRAINT FK_Reference_3 FOREIGN KEY ( cid ) REFERENCES constmer ( cid ) ON DELETE RESTRICT ON UPDATE RESTRICT;
建立odproduct表的SQL语句如代码4-2所示,同样用CREATE语句创建表并在括号中对所有属性命名并规定其类型,用NOT NULL标记该属性不为空,,利用PRIMARY KEY( opid ) 表明其主键为opid。最后通过下方的语句,将该表对客户的外键依赖添加在该表上。
CREATE TABLE odproduct (
opid VARCHAR ( 50 ) NOT NULL,
oid VARCHAR ( 50 ) NOT NULL,
pid VARCHAR ( 50 ) NOT NULL,
count INT NOT NULL,
price DOUBLE,
PRIMARY KEY ( opid ) );
ALTER TABLE odproduct ADD CONSTRAINT FK_Reference_1 FOREIGN KEY ( oid ) REFERENCES orders ( oid ) ON DELETE RESTRICT ON UPDATE RESTRICT;
ALTER TABLE odproduct ADD CONSTRAINT FK_Reference_2 FOREIGN KEY ( pid ) REFERENCES product ( pid ) ON DELETE RESTRICT ON UPDATE RESTRICT;
在上述代码段中通过CHECK语句标记数据的完整性,但并没有设置触发器,触发器实现的对数据完整性的保证将在数据控制层之上的代码中实现,这是基于系统性能需求和响应时间做出的选择。
由于后续的代码开发过程使用Entity Framework框架,该框架的一大弊端在于系统的性能较差,响应时间长,但优点在于其可通过高耦合、低内聚的特性减少代码量,使得开发者能将更多经历关注在业务逻辑上。该框架包含表示层、业务逻辑层、数据访问层三册架构,可通过数据访问层与数据库所在的数据层发生交互并操作数据库中的数据,即实际上使用该框架完成的系统至少包含四层结构。
其表示层与用户直接进行交互,业务逻辑层处理用户请求并将需要进行数据访问的请求传递给数据访问层,同时传递相关数据,数据访问层进行对数据库的操作。而数据在各层间传递时要占用一定量的资源,存在一定的时空耗费。在使用此类系统时,用户如果在表示层进行数据的操作,则不会直接与数据层的数据库发生联系,数据会经过业务逻辑层和数据访问层才能到达数据层。
在各层之间数据的传递需要一定的时间,如果将触发器直接建立在数据层,当用户输入了错误的数据,该数据会直接经过上三层的传递,直到数据访问层或者数据层才能被检测出错误,而该错误信息同样要经过上三层的传递才能由用户接收。而若每次用户的输入均需要经过这样的检测过程,则其等待时间必然远超过理想的系统响应时间。因而在设计时选择将触发器相关功能的实现建立在业务逻辑层之上以减少输入数据时处理和响应的时间。而底层建立的其他完整性约束,均可通过限制页面输入内容(如只能选择提供的备选输入)的方式处理,因而无需担心过长的响应时间,同样能保证其数据完整性。
4.2数据准备
成功建立相关表后的数据库截图如图4-1和图4-2所示,图4-1显示新建立后的orders表,其中包含上述3.3中订单表的各项属性。
图4-2显示新建立后的odproduct表,其中包含上述3.3中订单商品表的各项内容。
INSERT INTO orders ( oid, cid, total_price, pay_state, send_state )
VALUES
( 1, 1, 268.17, 0, 0 );
INSERT INTO odproduct ( opid, pid, oid, count, price )
VALUES
( 50, 1, 2, 14, 77.57 );
在完成上述插入数据操作后的数据库如下图4-3所示和图4-4。图4-3显示插入10条数据后orders表的状态,同样,其中oid(订单编号)和cid(客户编号)的值仅供代码调试和测试使用,此时显示的数据在数据库中的状态,pay_state(付款状态)、send_state(发货状态)在数据库中用0表示未操作,1表示已操作,在页面上对用户展示时显示时会进行对应转换,显示为相关操作。
图4-4中显示插入10条数据后的odproduct表,同样,其中的opid(订单商品编号)、pid(商品编号)和oid(订单编号)仅供测试使用,在最终的表示层,相关属性名称会以其表示的具体含义显示以便于用户处理。
5.系统功能模块设计与开发
5.1模块划分
根据小组分工,此设计报告中包含登录模和与订单(包括orders和odproduct两张表)相关的页面及控件的设计,即上图3-4-图3-8中的具体实现,以及其他功能模块中涉及到对订单信息处理的部分。为进一步简化系统设计、减少代码的冗余并提高所设计代码的复用性,进行系统设计的迭代,将图3-4~图3-8进一步简化,将管理员作为特殊的普通用户,指定其用户名为Admin,密码为123456,因而系统的登录模块(即开始页面)只需要上图3-7这一部分。对于订单中两张表的操作即为上图3-1中的订单模块,即对订单的修改和查看,此处的“修改”操作包含对于订单信息的修改和订单的删除操作,此外,商品页面中“加入购物车”这一功能将由系统调用对订单的插入操作,隐含对订单控制器的调用,最后,订单页面中还应包含对订单的统计模块与订单信息文件的导入模块。综上,此设计报告中包含登录模块、订单的插入、删除、查找、修改、统计和文件导入模块。
5.2系统功能模块设计与开发
5.2.1 登录模块
登录模块通过页面中form表单实现,系统开始运行后等待用户输入,直到用户在用户名和密码框内输入相关信息并点击“提交”按钮。当提交按钮上的单击事件被触发,将用户输入的相关信息通过post方法传递给当前页面的控制器。在控制器端,检查是否为合法用户、密码是否正确、是否为管理员,并将处理结果通过ViewData返回视图页面,在页面端,如果接收到的是“Illegal”则提醒用户注册,如果接收到的是“Unmatched”则提醒用户重新输入密码,如果接收到的是“Admin”则将页面跳转到管理员页面,如果接收到的是其他信息则跳转到普通用户界面。在ASP .Net中跳转到一个页面,实质上是调用该页面控制器的某个方法(默认为Index()方法),在跳转时可对该方法输入参数以实现数据的传递。则在后续的所有页面当中,在跳转时均将登录时接收到的用户名作为其第一个参数。在页面端检查控制器接收到的参数,如果该参数是“Admin”,则显示该页面的全部功能,如果该参数是普通用户名,则只显示该用户可执行与查看的部分信息与控件。由此,简化了设计管理员与用户两套系统的方案,进一步提高了代码的复用性和简洁性。其代码逻辑如下图5-1所示。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="Album.OnlineAlbum.Login" %>
<form id="form1" runat="server">
<span id="spanuser">用户名:</span>
<asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>
<span id="spanpsd">密码:</span>
<asp:TextBox ID="TextBox2" runat="server" TextMode="Password"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="登 录" OnClick="Login" />
</form>
其后端登录方法代码如代码5-2所示,通过两个TextBox获取页面上的登录信息,使用Linq语句在数据库中查找是否存在该用户。其后的判断逻辑与上述图5-1相同,如果存在, 查找该用户密码是否正确,不存在则提示用户非法。对于密码正确的用户,如果是Admin则页面重定向到管理员页面,如果不是则到普通用户页面。
protected void Login(object sender, EventArgs e)
{
using var context = new CommodityContext();
var costumer = context.Costumer.Where(x => x.Cid == TextBox1.Text).ToList();
if (costumer == null)
{
Response.Write(" < script > alert(非法用户') </ script > ");
return;
}
if (costumer[0].password == TextBox1.Text)
{
if (TextBox1.Text == "Admin") Response.Redirect("Admin.aspx");
else Response.Redirect("Cosutmer.aspx");
}
else
{
Response.Write(" < script > alert(密码错误') </ script > "); return;
}
}
在ASP .Net中跳转到一个页面,实质上是调用该页面控制器的某个方法(默认为Index() 方法),在跳转时可对该方法输入参数以实现数据的传递。则在后续的所有页面当中,在跳转时均将登录时接收到的用户名作为其第一个参数。在页面端检查控制器接收到的参数,如 果该参数是“Admin”,则显示该页面的全部功能,如果该参数是普通用户名,则只显示该用 户可执行与查看的部分信息与控件。由此,简化了设计管理员与用户两套系统的方案,进一 步提高了代码的复用性和简洁性。以查询数据为例,其前后端代码如代码5-3所示。在后端根据权限的不同提供不同的数据,前端根据权限不同给出不同的显示。二者通过ViewData进行通信。
//后端
public IActionResult Index(string cid)
{
using (var context = new CommodityContext())
{
if(cid=="Admin") var orderset = context.Orders.Where(x => x.CrsId !="null").ToList();
else var orderset = context.Orders.Where(x => x.CrsId == id).ToList();
foreach(var orders in orderset) orderset.Add(Orders);
this.ViewData["Orderss"] = orderset;
}
return View();
}
//前端
@{
var orders = ViewData["orders"] as List<Course>; var id = ViewData["id"] as string ;
}
@if( id == "admin") ……
else ……
5.2.2 插入订单
插入订单在商品页面中的“加入购物车”按钮被触发,在跳转到当前页面第一次触发该按钮时生成orders表中的新数据,以触发这一功能的商品的皮带和新生成的orders表项的oid作为外键生成新的odproduct数据,由客户选择数量,将该数量作为新生成的odproduct的count, 查找该商品价格,计算当前商品总价并累加到orders的total_price当中。其代码执行流程如图5-2所示。
插入订单在商品页面中的“加入购物车”按钮被触发,在跳转到当前页面第一次触发该按
钮时利用该客户的cid作为外键生成orders表中的新数据,新数据的oid在new方法中生成。以触发这一功能的商品的pid和新生成的orders表项的oid作为外键生成新的odproduct数据,由客户选择数量,将该数量作为新生成的odproduct的count,查找该商品价格,计算当前商品总价并累加到orders的total_price当中。其后端代码如代码5-4所示。
public IActionResult Index(string Cid, string Pid, int Count)
{
using var context = new CommodityContext();
var order = new Orders(Cid);
var odproduct = new Odproduct(order.Oid , Pid,count);
var price = (context.Product.Where(x => x.Pid == Pid).ToList())[0].Price;
order.TotalPrice += Count * price;
odproduct.Price = price; context.Odproduct.Add(odproduct);
context.Orders.Add(order); context.SaveChanges();
return View();
}
5.2.3 删除订单
在订单详情页面的删除按钮出发删除订单功能,在删除订单前检查该订单状态,如果该 订单状态为“未发货”或“已付款”则可直接删除,如果该订单状态为“已发货”且“未付款”则不 能删除该订单。对于客户,其只能删除自己的订单,管理员可删除任意顾客订单。但此删除操作仅将pay_state置为-1,并不在数据库中删除该数据,其执行流程如图5-3所示。
public IActionResult Delete(string Oid)
{
using (var context = new CommodityContext())
{
var order = context.Orders.Where(x => x.Oid == Oid).ToList()[0];
var pay = order.PayState; var send = order.SendState;
if (send == 0 || pay == 1) send = order.PayState = -1;
else this.ViewData["res"] = "fail";
context.Orders.Update(order); context.SaveChanges();
}
return View();
}
5.2.4 修改订单
对于管理员,在订单详情页面的修改按钮触发修改订单按钮,在修改订单前同样检查该 订单状态,如果该订单状态为“未发货”则可直接进行修改任何信息,对应于对商品、数量等 的修改和发货,对于状态为“已发货”且“未付款”的订单,可以修改其发货状态和状态,对应 退货、收款等操作,对于“已发货且已付款”的订单,不能修改。对于用户,修改订单信息应 联系管理员,可在未发货订单处点击取消订单或已发货订单处点击付款,同样触发修改订单 操作,但此时不进行页面的跳转,其执行流程如图5-4所示。
各功能按钮及条件判断在页面中实现,在控制器中只需接受要修改何种信息,并存储即 可,部分代码如代码5-6所示。
public void change(string change,string info,string oid)
{
using (var context = new CommodityContext())
{
var order = context.Orders.Where(x => x.Oid == Oid).ToList()[0];
var odproduct = context.Odproduct.Where(x => x.Oid == Oid).ToList()[0];
if (change == "pay") order.PayState = int.parse(Info);
……
context.Orders.Update(order);
context.SaveChanges();
}
}
5.2.5 查找订单
查找订单即为用户的“查看个人订单”和管理员的“查看所有订单”功能,对于管理员,还 可以根据订单号查找制定订单。在订单信息详情页面,根据传入的参数不同显示不同的表单 信息。在根据订单号查找时,同样需要利用form表单提交要查找的数据。在其控制器端,如果是普通用户,则只查找其个人订单,如果是管理员则返回所有订单,其执行流程如图5-5 所示,其代码见上述代码5-3。
5.2.6 统计订单
在管理员查看所有订单信息时可选择统计订单按钮,查找计算每个客户完成的订单数 目、总价并在前端页面中进行输出,其部分代码如代码5-7所示,同样,其前端代码中不含各类样式和标记信息。
/*前端代码*/
@{
//获取数据
var this.ViewData["cid"] as List<string>; var this.ViewData["count"] as int[];
var this.ViewData["price"] as double[];
}……
/*统计表单*/
<table>
<thead>
<tr>
<th>客户</th>
<th>订单数</th>
<th>总价</th>
</tr>
</thead>
<tbody>
@for (var i = 0; i < courses.Count; i++)
{
<tr>
<td>@cid[i].Cid</td>
<td> @count[i]</td>
<td>@price[i]</td>
</tr>
}
</tbody>
</table>
……
/*后端代码*/
……
public void counting()
{
using (var context = new CommodityContext())
{
var cids = context.Orders.Select(x => x.Cid ).ToList();
var counts =new int[cids.Count];
var prices = new double[cids.Count];
for (var i = 0; i < cids.Count; i++)
{
var list = context.Orders.Where(x => x.Cid ==cids[i]).ToList();
var count = list.Count;
var price = 0.0;
foreach (var k in list)
price += (double)k.TotalPrice; counts[i] = count;
prices[i] = price;
}
this.ViewData["cid"] = cids;
this.ViewData["count"] = counts;
this.ViewData["price"] = prices;
}
}……
5.2.7 导入文件
在管理员查看所有订单信息时可选择导入订单信息按钮,选择文件后将指定内容的
*.csv文件中的订单信息导入数据库。*.csv文件的读取和转换操作可封装在单独的类CSVReader中,其读取文件的代码如代码5-7所示,利用读取到的数据创建新的订单插入数据库即可。
public bool ReadRow(CsvRow row)
{
row.LineText = ReadLine();
if (String.IsNullOrEmpty(row.LineText)) return false;
int pos = 0;
int rows = 0;
while (pos < row.LineText.Length)
{
string value; //分情况处理不同的无意义字符
if (row.LineText[pos] == '"')
{
pos++;
// Parse quoted value
int start = pos;
while (pos < row.LineText.Length)
{
if (row.LineText[pos] == '"')
{ // Found one
pos++;
if (pos >= row.LineText.Length || row.LineText[pos] != '"')
{
pos--;
break;
}
}pos++;
}
value = row.LineText.Substring(start, pos - start);
value = value.Replace("\"\"", "\"");
}
else
{//将处理后的数据值存入LineText
int start = pos;
while (pos < row.LineText.Length && row.LineText[pos] != ',') pos++;
value = row.LineText.Substring(start, pos - start);
}
if (rows < row.Count) row[rows] = value;
else row.Add(value);
rows++;//去掉分隔符‘,’,查找字符串个数
while (pos < row.LineText.Length && row.LineText[pos] != ',') pos++;
if (pos < row.LineText.Length) pos++;
}//去除无用的字符
while (row.Count > rows) row.RemoveAt(rows);
return (row.Count > 0);//返回是否找到字符
}
5.2.8 订单页面
在订单详情页面中包含调用上述所有功能的控件,部分功能在执行时会跳转到对应信息的子页面,已在上文简述。下述代码5-8为订单页面中管理员权限可见的内容,其中简化了部分样式、盒模型、标签,对表单中的各项也有所删减。所示部分代码为订单页面的主要内容,其中包含从通信区获取数据、各功能控件的位置及相关的相应操作。其中,数据区的类Showorders包含订单和商品订单整合后的各项信息,作为信息展示的辅助类。数据的查询、处理以及功能相应,均由上文中各控制器加以执行相应。
/*获取数据*/
@{
var orders = ViewData["Show"] as List<Showorders>;
var cid = ViewData["Cid"] as string;
}
<center>订单明细</center>
/*表头*/
@if(cid== "Admin")
{
<table>
<thead>
<tr>
<th>订单号</th>
<th>用户名</th>
……
<th>状态</th>
</tr>
</thead>
/*表格内容*/
<tbody>
@for (var i = 0; i < courses.Count; i++)
{
<tr>
<td>@orders[i].Oid</td>
……
<td>@orders[i].State</td>
/*修改和删除按钮*/
<td>
<div>
<button onclick="Change()">修改</button>
<button onclick="Delete()">删除</button>
</div>
</td>
</tr>
}
</tbody>
</table>
/*查找文件提交按钮*/
<form method="post" action="@Url.Action("Index","Reader")?file=" + file>
<input type="text" id="textfield" class="txt" />
<input type="button" class="btn" value="浏览..." />
<input type="file" name="file" onchange="document.getElementById('textfield').value = this.files[0].name" />
<input type="submit" class="btn" value="上传" />
</form>
}……
6.系统测试与分析
在代码的编写和调试过程中,已经基本完成了对代码的白盒测试。对于已经完成部分子系统,在系统测试阶段可采用黑盒测试中的场景测试法进行测试。基于场景的测试是通过分析被测业务流程,构建基本流和备选流,并生成场景进而得到测试用例的测试方法。该法主要用于功能测试。在场景测试中需根据业务实际提炼出基本流,并控制备选流的数量,并选择少量典型场景进行测试,其过程包含构造事件流、构造场景和设计测试用例三个阶段。上述功能模块可归结为用户登录、管理员管理全体订单和用户管理个人订单三种基本业务,需要分别对其进行分析。
6.1事件流构造
6.1.1用户登录
围绕用户登录业务,构造基本流和备选流描述如下。
(1)基本流
用户登录的初始状态同样是系统的初始状态,在页面显示欢迎语并等待用户输入。其后续业务流程包括:
①用户输入:由用户输入账号和密码。
②账户校验:检测是否为合法用户,此处对应第1个校验点。
③密码校验:检测密码是否与用户名匹配,此处对应第2个校验点。
④权限校验:检测是否为管理员用户,此处对应第3个校验点。
⑤页面跳转:根据权限跳转到对应页面。
⑥退出:用户在相应页面中选择退出,返回开始页面。
(2)备选流
基本流中得到三个关键校验点如下:
校验点 1:对应步骤②,对用户名的有效性进行校验,判断用户名是否有效;
校验点 2:对应步骤③,对用户输入的密码进行校验,判断密码是否匹配预设密码; 校验点 3:对应步骤④,对用户权限进行校验,判断需跳转的界面。
根据上述校验点,可分别得到各校验点处的备选流,分析如下。
①备选流 1:用户名错误。
在基本流步骤②处触发,在校验用户名时发现该用户名无效,则应将并提示用户名无效, 系统回到准备就绪状态,本用例终止。
②备选流 2:密码错误。
在基本流步骤③处触发,校验密码错误后,则系统提示密码错误,要求用户再次输入密 码,系统返回密码输入状态,在步骤③处重新加入基本流。
③备选流 3:用户权限
该备选流在基本流步骤④处触发,假设基本流为管理员登录,则当权限非管理员时进入 普通用户页面,页面处理结束后在步骤⑥处重新加入基本流。
用户登录业务的基本流和备选流如图 6-1 所示。
(1)基本流
管理员管理订单的初始状态是进入订单详情界面。其后续业务流程包括:
①删除订单:删除可删除订单。
②修改订单:修改可修改订单,默认修改发货状态,此处对应第1个校验点。 订单统计:统计订单信息。
③查找订单:查找指定订单号的订单,此处对应第2个校验点。 导入订单数据:将指定格式的订单文件导入系统。
(2)备选流
基本流中得到 2 个关键校验点如下:
①校验点 1:对应步骤②,还可修改商品中的订单数量,修改完成后在步骤③返回基本流;
②校验点 2:查找的订单不存在时应给出提示信息。
根据上述校验点,可分别得到各校验点处的备选流,分析如下。
①备选流 1:修改商品数量。
在基本流步骤②处触发,修改指定商品的商品数量,完成后返回基本流。
②备选流 2:不存在的订单。
在基本流步骤④处触发,找到指定订单后,则系统提不存在该订单,在步骤③处重新加 入基本流。
6.1.3用户管理订单
用户对订单的大部分管理功能均已经在管理员管理订单当中测试,其余功能不包含校验 点,只需按照下述基本流保证其功能正常运行即可,用户管理订单的初始状态是进入个人订 单详情界面,其中显示个人全部订单数据和相关控件。其后续业务流程包括:
(1)删除订单:对可删除的订单,点击删除订单按钮,删除订单。
(2)货到付款:对已发货订单,点击付款按钮,进行付款。
(3)取消订单:对未发货订单,点击取消订单,取消订单。
用户管理订单的基本流和备选流如图 6-3 所示。
6.2场景设计
根据用户登录业务的基本流和备选流得到的场景集合如下: 场景 1(管理员正常登陆,且退出):基本流;
场景 2(非法账户):基本流+备选流 1;
场景 3(密码错误):基本流+备选流 2;
场景 4(普通用户正常登陆,且退出):基本流+备选流 3。根据用户登录业务的基本流和备选流得到的场景集合如下: 场景 5(管理员执行所有功能):基本流;
场景 6(管理员修改商品数量):基本流+备选流 1;
场景 7(管理员查找不到存在的订单):基本流+备选流 2。根据用户登录业务的基本流和备选流得到的场景集合如下: 场景 8(普通用户正常操作所有功能):基本流。
6.3测试用例设计与实施
对应每个场景测试用例,其规则包括:
(1)根据某场景所包含的执行流程,分析出系统应满足的所有输入条件和预期输出;
(2)当场景中包含备选流时,应确定触发该备选流执行的输入条件,并予以标记。
另外,由于除登录相关测试外,所有测试均为针对功能的测试,不包含测试数据,因而测试用例的设计可加以简化,仅需在页面上按照相关场景中业务流的要求,逐一触发其中的 控件,检查是否能按照正常流程运行程序,即可完成相关测试。因而测试用例中的输入被简 化为对相关控件,如按钮、文本框的的触发。在涉及到对数据的修改操作时,可通过直接由 其他数据库管理软件直接进入数据库的方式观察相应数据是否已经在数据库中发生变化。则 由此设计的测试用例如表 6-1 所示。
ID | 场景 | 输入 | 预期输出 |
---|---|---|---|
ODR-ST-001 | 1 | 账户:Admin,密码:123456 | 跳转至管理员页面 |
ODR-ST-002 | 2 | 账户:aaa(不存在),密码:111 | 消息提示,等待输入,用例结束 |
ODR-ST-003 | 3 | 账户:Admin,密码 123444(错误) | 消息提示,返回基本流步骤③ |
ODR-ST-004 | 4 | 账户:1,密码:123456(普通用户) | 跳转至普通用户页面 |
ODR-ST-005 | 5 | 触发删除、修改、查找、统计、导入按钮 | 正常执行所有功能 |
ODR-ST-006 | 6 | 查找订单cccc(不存在) | 消息提示,返回基本流步骤③ |
ODR-ST-007 | 7 | 修改订单中的商品数量 | 成功修改并存入数据库 |
ODR-ST-008 | 8 | 触发删除、付款、退货按钮 | 成功操作 |
场景 1 的测试结果如图 6-4 所示,系统成功跳转至管理员页面,完成该用例测试。
场景 2 和场景 3 的测试结果如图 6-5 所示,在发现用户名非法或密码错误时,给出相应提示,由用户重新输入,符合预期输出。
场景 5 开始时的数据库状态如图 6-6 所示,其左侧为 odproduct 表右侧为 orders 表。
场景 5 的初始化状态如图 6-7 所示,将两张表的信息整合后显示在页面当中,对于付款
和发货的不同状态,其后的操作也有所不同,其中修改对应场景 7 中的修改数量操作,发货
对应场景 5 中的修改状态操作。修改第一条数据中的 2 号商品的数量,删除第二条数据,并发货第 3 条数据,向数据库中传入文件 orders.csv 中的数据以完成对应场景 5 的测试。
完成前三条操作后的页面如图 6-8 所示,能操作成功并将改动后的数据显示在页面上, 与预期输出相符,测试成功。
单击上传按钮后的页面截图如图 6-9 所示,显示能查找系统中文件以插入数据库,选择orders.csv 导入数据库,其中包含一条订单数据:订单号为 5,用户名为 2,商品为 2 号商品1 件,总价 4.18,未付款,未发货。
场景 5 结束测试时的数据库状态如图 6-10 所示,其左侧为 odproduct 表右侧为 orders 表, 页面上更改后的数据能存入数据库,与预期输出相符,该测试用例通过测试。
场景 4 与场景 8 开始测试时的数据库状态如图 6-11 所示,其左侧为 odproduct 表右侧为
orders 表。
场景 4 进入普通用户页面后在进入订单信息页面,如图 6-12 所示,其中对应不同状态的
订单,可以执行不同的操作,取消订单 1 并付款订单 10 以完成测试。
场景 8 执行后数据库变化如图 6-13 所示,与预期输出相符,测试通过。
场景 6 的初始化与执行结果如图 6-14 所示,在查找订单页面中输入订单号 1,查找成功后在下方输出所查询到的订单信息,符合预期输出,通过测试。
7.课程设计技术经验总结
本次课程设计围绕数据库相关设计展开。在设计过程中,首先复习了数据库设计流程和 相关内容,通过构建实体关系图辅助完成关系表的设计,并通过范式理论中进一步优化相关 数据。随后了解了数据库设计工具的使用,比如利用Power Designer构建数据关系图并生成数据库代码,以及使用mocakaroo网站构建随机数据,相关辅助设计工具的使用可以减少设计时的重复劳动,将更多精力关注在业务逻辑和设计上。此外,还掌握了数据库中储触发器 相关事件的设计与处理。
除数据库的设计、构建和使用外,本次课程设计还包括对数据库中数据的处理与展示, 以及与用户的交互部分。该部分内容通过Web相关技术进行实现,进一步深化了对其他课程中ASP.NET Core 、Entity framework框架以及C#相关编程技术的理解,熟练掌握了基于Entity Framework 的MVC三层架构模式。其中,在本次系统中多次使用URL、ViewData和post方法进行页面间、页面与控制器端数据的传递和处理,能有效实现数据的隔离并体现该框架高内聚、低耦合的特点。但同时,也由于相关特性,使得框架在使用时性能较低,处理速度较慢,在未来的程序中,还应进一步优化。另外,对于数据在网页上的处理和展示,也使用了CSS、Java Script等前端编程技术。
在完成整体系统设计后,使用黑盒测试中的场景测试法进行测试。和以往相比,这是在课程设计中首次使用正规的测试方法对设计出的系统进行测试,进一步复习并深入理解了软件测试相关课程的内容。在系统测试阶段,场景测试法能有效测试系统的功能是否正常运行, 但需结合决策表等工具对场景和基本流、备选流加以限制,避免出现场景爆炸的问题。
综上所述,本次课程设计使用了数据库设计相关理论和技术、ASP .NET Core编程技术、前端编程技术以及黑盒测试技术,完成了任务书和小组分工表中的相关内容与要求。
参考文献
- [1]PatrickO’Neil, ElizabethO’Neil. 数据库,原理、编程与性能:第二版-影印版[M]. 高等教育出版社, 2001.
- [2]C. J. Date, 单世民, 何英昊,等. SQL 与关系数据库理论[M]. 机械工业出版社, 2014.
- [3]Gamma,E.Helm,R.Johnson,R.Vlissides,J.Design Patterns:Elements of Reuseable Objet-Oriented Software[M]. 李英军,马晓星,蔡敏,刘建忠,吕健.北京:机械工业出版社,2019.3
- [4] 王珊, 萨师煊. 数据库系统概论(第 5 版)[J]. 中国大学教学, 2018, No.333(05):100.
- [5]周定康, 许婕, 李云洪,等. 普通高等学校计算机专业系列教材 关系数据库理论及应用
[M]// 普通高等学校计算机专业系列教材, 关系数据库理论及应用. 华中科技大学出版社, 2005. - [6]杨晶浩.现代软件工程应用技术[M].北京:北京理工大学出版社,2017,5.
- [7]李必信,廖力,王璐璐,孔祥龙,周颖.软件架构理论与实践[M].北京:机械工业出版社,2019,1.
- [8]王晓东.计算机算法设计与分析[M].北京:电子工业出版社
- [9]武剑洁. 软件测试实用教程[M]. 电子工业出版社, 2012.
标签:商品销售,课程设计,数据库,用户,信息,订单,管理员,信息管理系统,页面 来源: https://blog.csdn.net/z1446731325/article/details/113190699