# 闲瓜市场 **Repository Path**: lyc-nwpu/melonmart ## Basic Information - **Project Name**: 闲瓜市场 - **Description**: 数据库大作业 - **Primary Language**: Python - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2021-12-17 - **Last Updated**: 2025-12-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MelonMart二手市场设计文档 # 需求分析 MelonMart是一个发布二手货交易信息的平台,主要面向西工大校内师生,但也允许校外人士注册账号,MelonMart主要提供发布信息的服务,平台上不涉及金钱交易。 主要功能如下: 1. 用户注册 开放本校学生和社会人士注册,本校学生可以认证学号和校区信息。 2. 发布商品 用户可以在网站上发布商品,自定义价格和描述,每个商品支持上传一张图片。上传的商品会被展示在首页,用户打开网站时可以看到。 3. 购买商品 用户可以在网站上购买商品,用户购买时会生成一条交易记录。 购买流程:买家首先在商品详情页面发起购买,系统创建一条交易记录,此时商品状态改为“等待卖家同意”,卖家可以选择同意交易或拒绝交易,做出回应前买家可以随时取消交易,若卖家拒绝交易或买家放弃交易,交易将关闭,但交易记录会保留,状态改为“交易关闭”,若卖家同意交易,交易状态改为“等待交易”,交易双方自行商定交易方式并完成交易,完成后买家确认收货,交易结束,状态改为“交易完成”。 4. 评论 用户可以对商品发表公开的评论,可以删除自己发表的评论,卖家也可以在自己的商品下以评论的形式补充信息,卖家在自己的商品下发布的评论会带有“卖家”的标记。 5. 收藏 用户可以收藏商品,方便下次查看。 6. 权限管理 系统内有三种权限级别分布定义为L1、L2和L3,L1级别代表普通用户,只能删除自己发布的商品和评论,L2级别代表站务,可以删除他人的违规评论,但不能删除商品,L3级别代表系统管理员,可以删除他人的违规商品和评论。 任何用户登录后都可以在页面右上角处跳转到自己的信息页面,在页面中查看和修改自己的基本信息、修改和删除自己发布的商品、删除自己的收藏以及对自己的交易查看或进行操作。在商品详情页面,用户点击卖家用户名会跳转到卖家的个人信息页面,但只能查看卖家的基本信息和发布的商品。 # 数据库设计 ## 概念结构设计 MelonMart系统中的实体有用户、商品、评论,比较重要的关系有用户发布或购买商品、评论、收藏等,E-R图: ![image-20211125000408712](./doc/image-20211125000408712.png) ## 逻辑结构设计 ### 关系模式 user表 | 列名 | 类型 | 属性 | 说明 | | ---------- | ----------- | ---------- | ---------- | | uID | int | 主键,自增 | 用户唯一ID | | uName | varchar(30) | 唯一,非空 | 用户昵称 | | uPsw | varchar(50) | 非空 | 密码 | | schoolID | varchar(10) | | 学号 | | uCampus | varchar(5) | | 校区 | | uTel | varchar(15) | | 电话 | | uVx | varchar(45) | | 微信号 | | uQQ | varchar(45) | | QQ号 | | uEmail | varchar(45) | | 电子邮箱 | | uAuthority | int | 缺省:1 | 权限 | goods表 | 列名 | 类型 | 属性 | 说明 | | ------------ | ------------- | -------------------- | ------------------------------------------------------------ | | gID | int | 主键,自增 | 商品唯一ID | | gName | varchar(50) | 非空 | 商品名称 | | gDescription | varchar(200) | | 商品描述 | | gPrice | decimal(10,2) | 非空 | 商品价格,人民币的表示方式,小数点后两位 | | gImgSrc | varchar(100) | | 商品图片在服务器上工程目录中的相对路径 | | uploader | int | 非空,外键:user.uID | 上传者ID | | uploadTime | datetime | 非空 | 上传时间 | | hide | tinyint | 默认值:0 | 是否在首页显示,0显示,1不显示,交易中的商品不会被推荐到首页 | deal表 | 列名 | 类型 | 属性 | 说明 | | ------- | ------------- | --------------------- | ------------------------------------------------------------ | | gID | int | 主键,外键:goods.gID | 交易商品的ID | | seller | int | 主键,外键:user.uID | 卖家ID | | buyer | int | 主键,外键:user.uID | 买家ID | | dTime | datetime | | 交易开始时间 | | dPrice | decimal(10,2) | | 当前价格 | | dStatus | varchar(10) | | 交易状态,值:“等待卖家回复”、“等待交易”、“交易完成”、“交易关闭” | comments表 | 列名 | 类型 | 属性 | 说明 | | ------- | ------------ | -------------------- | ---------------------------------------------------- | | cID | int | 主键,自增 | 评论的唯一ID,目前没有使用,未来扩展回复等功能会用到 | | uID | int | 非空,外键:user.uID | 发表评论的用户的ID | | gID | int | 非空,外键:user.uID | 评论商品的ID | | cTime | datetime | 非空,外键:user.uID | 评论时间 | | content | varchar(200) | | 评论内容 | favorites表 | 列名 | 类型 | 属性 | 说明 | | ----- | -------- | --------------------- | ------------ | | uID | int | 主键,外键:user.uID | 收藏者ID | | gID | int | 主键,外键:goods.gID | 收藏的商品ID | | fTime | datetime | | 收藏时间 | 外键违例处理:除了deal表中的外键的删除违例的处理是拒绝操作以外,其他所有外键的更新和删除的违例处理都是级联操作。 ### 存储过程 MelonMart的Web程序对MySQL数据库的操作是通过pymysql实现的,pymysql提供了直接执行MySQL语句的API,但代码中不适合放入较长的MySQL语句,所以将一些常用的操作封装为存储过程,这里展示几个比较复杂的存储过程,其他存储过程可以在源代码中查看。 **修改交易信息modify_deal** ```MySQL CREATE DEFINER=`root`@`localhost` PROCEDURE `modify_deal`(seller_ int, buyer_ int, gid_ int, op varchar(10), txt varchar(10)) mdf:BEGIN if(op="remove") then delete from deal where gID=gid_ and seller=seller_ and buyer=buyer_; leave mdf; end if; if(op="status") then update deal set dStatus=txt where gID=gid_ and seller=seller_ and buyer=buyer_; if(txt!="交易关闭") then update goods set hide=1 where gID=gid_; else update goods set hide=0 where gID=gid_; end if; leave mdf; end if; if(op="price") then update deal set dPrice=txt where gID=gid_ and seller=seller_ and buyer=buyer_; leave mdf; end if; END ``` modify_deal支持三种操作:删除交易记录、修改交易状态和修改当前价格,用卖家ID、买家ID和商品ID确定一条记录,字符串op确定操作类型,txt是修改后的内容。在修改交易状态时,还要相应地修改商品的hide属性。 **添加交易create_deal** ```mysql CREATE DEFINER=`root`@`localhost` PROCEDURE `create_deal`(buy int, sel int, gid_ int, out o int) create_deal:begin declare t_cur datetime default now(); declare p_init decimal(10,2) default 0.0; if(buy=sel) then set o=1; leave create_deal; end if; select gPrice from goods where gID=gid_ limit 1 into p_init; insert into deal(gID,seller,buyer,dTime,dPrice,dStatus) values(gid_,sel,buy,t_cur,p_init,'等待卖家回复'); update goods set hide=1 where gID=gid_; set o=0; end ``` 创建交易时,需要确定卖家买家的ID和商品的ID,交易价格定为商品上传时的价格,状态为“等待卖家回复”,存储过程判断卖家和买家应不是同一个,否则拒绝创建。 **添加和修改商品add_upload_goods** ```mysql CREATE DEFINER=`root`@`localhost` PROCEDURE `add_upload_goods`(gname varchar(50),gdes varchar(200),price decimal(10,2),img varchar(100),uploader int, gid_ int) begin declare cur_time datetime default now(); if(gid_<0) then insert into goods(gName,gDescription,gPrice,gImgSrc,uploader,uploadTime) values(gname,gdes,price,img,uploader,cur_time); else update goods set gName=gname where gID=gid_; update goods set gDescription=gdes where gID=gid_; update goods set gPrice=price where gID=gid_; update goods set gDescription=gdes where gID=gid_; if(img!="") then update goods set gImgSrc=img where gID=gid_; end if; end if; end ``` 这个存储过程可以添加新的商品,也可以修改原有商品的信息,当添加新的商品时,参数gid\_传入-1,向goods表中插入,如果gid\_不等于-1,则修改对应的商品。修改数据时,如果不需要修改原来的图片,前端传来的数据中,图片路径就是空字符串,这里还需要再普安段一次。 ## 物理结构设计 表中的索引如下: | 表 | 常用查询条件列 | 索引 | | --------- | ---------------- | ------------------------------------------------------------ | | user | uID,uName | uID有MySQL自动创建的主键索引,另外对uName创建索引 | | goods | gID | gID有MySQL自动创建的主键索引 | | comments | uID,gID | UID和gID由于绑定了外键,都自动创建了索引 | | deal | gID,seller,buyer | gID,seller和buyer有主键复合索引,seller和buyer有外键创建的索引 | | favorites | uID | MySQL在uID和gID上自动创建了主键索引 | # Web程序 ## 简介 MelonMart是一个网站应用,服务器端的Web程序使用Python编写,使用Flask框架构建。Flask应用中最基本的元素是视图函数,视图函数是由Flask.route()方法或Blueprint.route()方法修饰的Python函数,用于处理对应特定URL的HTTP请求。 为了避免将所有视图函数全部写到同一个脚本中,Flask提供了蓝图机制,可以在不同脚本中定义视图函数,每个脚本创建一个蓝图,将脚本内的所有视图函数都绑定到这个蓝图上,最后在把所有蓝图注册到Flask App对象上,这样操作的结果和直接绑定Flask App对象是一样的。 MelonMart的工程中,每个页面的所有视图函数放在一个脚本中,共用一个蓝图,Flask App对象在main.py中定义。 ## 文件结构 ![image-20211219180944404](./doc/image-20211219180944404.png) 所有Python脚本都在工程根目录下,main.py是Web程序直接运行的脚本,其他.py文件都是蓝图,requirements.txt是项目的使用的库的清单,confi.ini是项目的配置文件。 backup目录下存放导出的数据库结构(包含存储过程、触发器等,但不包含数据),运行这个脚本可以创建项目所需的数据库。 static目录下存放网页和商品图片,templates下存放网页的.html文件和.css文件,js目录下存放JavaScript脚本,img目录下存放商品图片。 ## 配置和运行 项目的配置文件是config.ini,如果需要本地调试,请将配置文件中App节的host改为回环地址127.0.0.1,如果在生产环境中运行,改为0.0.0.0,端口改为Web服务器的端口80。 config.ini中MySQL节是MySQL数据库的配置,运行前请检查主机名、用户名和密码是否正确,如果需要连接远程数据库,请检查数据库服务器的防火墙或安全组,保证3306端口开放。 运行环境: ``` MySQL: Server version: 8.0.21 MySQL Community Server - GPL Python: Python 3.8.3 ``` 第一次运行需要初始化数据库,执行备份的脚本即可。首先cd到脚本的目录下,然后登录MySQL,执行语句: ```sql source melonmart_db.sql ``` 运行前,请检查requirements.txt中的包是否全部安装,可以直接运行命令: ```shell pip install -r requirements.txt ``` 测试或运行时,可以在IDE中执行main.py,或在命令行中进入工程目录,执行命令: ```shell python main.py ``` 或 ```shell python3 main.py ``` 如果生产环境部署在Linux服务器上,可以使用screen创建会话,在会话中运行服务。 建议在安装了Python环境下直接运行Python脚本,源码目录下的main.exe是pyinstaller打包的可执行文件,但由于系统或路径等原因,在其他计算机上可能无法直接运行,在Windows环境下,请执行可执行文件目录下的批处理文件start.bat。 ## 运行截图 首页 ![image-20211224200741673](./doc/image-20211224200741673.png) 登录页面 ![image-20211224200824542](./doc/image-20211224200824542.png) 个人主页 ![image-20211224200912621](./doc/image-20211224200912621.png) ![image-20211224200944056](./doc/image-20211224200944056.png) ![image-20211224201012210](./doc/image-20211224201012210.png) ![image-20211224201046519](./doc/image-20211224201046519.png) 发布商品页面 ![image-20211224201224755](./doc/image-20211224201224755.png) 商品详情页面 ![image-20211224201324834](./doc/image-20211224201324834.png) # 其他 ## 一些问题 1. 用户user表的设计 最初的想法是,user表的主键是int型的uID,在查找时以int型的列为条件会比较快,但uID只是一个数据库内部可见的值,用户不需要知道自己的ID,登录也是使用用户名和密码,那么这样一来用户名也不能重复。最后的决定是,uID作为user表的主键,uName加入唯一的限制。 2. 交易中商品显示的问题 按照系统的设计,一件商品同时只能处于一笔交易中,正在交易的商品不应该被推荐到首页,但首页推荐商品的逻辑就是随机选择一定数量的商品,为了解决这个问题,为goods表加入一列hide,表示是否会被推到首页,在修改交易信息时也同时修改hide的值。 3. pyinstaller打包的问题,直接打包后exe程序找不到静态文件,需要在pyinstaller生成的*.spec脚本的datas中添加需要使用的静态文件,并保证这些文件的解压路径与程序中使用的相对路径相同,例如,程序中使用了index.html,使用的相对路径是 ``` ./static/templates/index.html ``` 那么datas中添加的就应该是 ```python ('./static/templates/index.html','./static/templates') ``` 也可以同时添加目录下所有的文件 ```python datas = [ ('./static/templates/*','./static/templates'), ('./static/js/*','./static/js') ] ``` ## 未完成功能和扩展 1. 回复评论,数据库中已经建立了reply表用于存储评论,但所有评论都应该被当做同一种类型管理,最好在comment表中加入回复相关的列。 2. 头像,目前系统中没有头像功能,个人信息页面的头像只是静态展示。 3. 站内信,允许系统向用户发送消息,或用户之间发送消息,应该建立一个页面按照时间顺序显示所有的站内信。 4. 出价功能,用户可以对商品出价,出价信息公开,作为潜在买家购买意向的表示,若卖家能够接收潜在买家提出的价格,可以直接进入交易流程。 5. 交易快照,系统自动记录交易信息的变化,即交易每一次更新的时间等情况,以及双方沟通的信息,交易双方都可以查看。 6. 封号和禁言,高权限用户可以禁止其他用户发布商品、参与交易或发布评论。