@TOC
springboot349基于协同过滤算法的黔醉酒业白酒销售系统_p091v--论文
绪论
1.1背景及意义
中国经济快速发展,人均GDP逐年上涨,非生活必须品的消费比重也随之增加 ,酒类销售额度,尤其是酱香型白酒销售额近些年可谓发展迅猛,年年大幅度增长,有了商机必然也会引得大批人员涌入白酒行业,以往白酒企业更多会注重销售的技巧与手法,但是消费者在信息化时代的今天选择权逐渐增多,需求自然也会有相应改变。如何建立企业的核心竞争力,尽最大可能满足客户的需求,这是企业该考虑的重大问题,只有做好以上几点才能占领市场,抢得资源。
国内的大型白酒企业通常会有自己的app或者小程序商场甚至全国开设线下门店来抢占市场,而中小型企业体量不够大时通常会选择在淘宝,京东等电商平台开设店铺,伴随而来的问题便是淘宝是否会给你很多的流量推荐,以及自己需要给平台支付的广告费,推荐费等等,对于中小型企业这些开销费用会使得成本大大增加,同时利润减少,做出来的产品自然性价比不会高.小型酒企业没有自己的系统记录管理产品,据我研究发现不少中小型企业还存在着使用电子报表来记录销售情况 每月每季每年会做一次汇总,工作量相当大,且有出错风险,效果也并不太好。倘若专门聘请计算机相关人员利用电子报表来做图形化的展示呢对于一家白酒企业而言显得。且不少企业销售人员还在通过微信等等社交软件进行白酒售卖,对于用户而言这种模式的安全性并不能等到保障。
贵州黔醉酒业(集团)有限公司是一家位于中国酒都茅台镇、2012年起进入集团化运营,涉及品牌营销、仓储、物流、包装印等业务。目前公司总占地350余亩,酿酒储酒居行业之中上游,现代化一流水准生产线可日灌装达20万平以上,重点以个性化定制为核心,适应个性化时代特点,釆用古法传统工艺酿制酱香型白酒,以酱香型白酒的研发、精酿、生产、销售为一体的综合性企业。完全符合中小型白酒企业的定义标准,同时存在着上述提到的诸多卖酒的不便。
基于以上几点,为类似与黔醉酒业这类中小型白酒企业量身打造一个销售管理系统是完全有必要的,运用计算机相关知识以及黔醉酒业自身的业务需求建立一个基于协同推荐的黔醉酒业白酒销售系统,最大限度的留住回头客,减少酒水企业的运作成本,将销售、进货、管理库存工作统一化、规范化、现代化才能在激烈的黔醉酒业销售行业竞争中争取一席之地。
1.2 国内外研究概况
随着电商模式的一步步发展,这种模式逐渐被消费者们接受,不在妖魔化网上购物,对其质量以及性价比给出高度赞扬的声音也逐渐加大,早些年开店做生意,对目标的用户的选取、地段选择与人口流动程度都会对收益产生重大影响,然后互联网高速发展的今天,店铺的核心竞争力已和往些年不同,如何让用户满意,对他的需求尽可能满足,让其用一次此系统,下次买东西再次光临就是最好的结果。也是国内外各个电商系统都在绞尽脑汁研究的东西,如国内的淘宝、京东国外的亚马逊等电子商务平台的崛起,良好的购物体验势必带来更高的用户转化率。
如今新零售也逐渐红火起来,如何线下留住顾客对产品进行体验,以便有需要时根据情况选择线上或线下进行下单,这种线上线下相结合的模式势必能增大用户的粘性与企业的流量半径。这种模式对于很多企业来说肯定会增加营业额度。从宏观角度来看问题,虽然说互联网信息化时代下的电子商务的确发展迅猛,但我国起步确实还是偏晚,很多传统市场的营销方式已经根深蒂固,有的不愿意打破原有模式,有的确能看到电子商务的发展潜力,因此国内许多大型的企业都建立了自身的电商平台,但还是老问题,发展太快势必会照成很多意料之外的结果,花了大价钱,但由于技术过于新颖不够稳定,往往都是投资一大笔钱,换来的收益远远低于线下门店,以及老模式所产生的价值。
在这种大背景下优秀的电商品台便脱颖而出,国内的淘宝,京东。国外的亚马逊二者都是行业的佼佼者,他们将系统部署到公有云上,利用公有云的海量带宽资源,解决了传统硬件所具有的的问题,而618,双十一等等大活动在临时申请更多的带宽资源,快速完成部署,活动结束立马释放掉,真真做到了按需付费,大大提升了效率,降低了成本。
1.3 研究的内容
全文结构安排如下:
第一章是绪论,主要介绍了本论文的研究背景,研究的目的和意义。
第二章是对汽车租赁系统所用到的关键技术和开发工具进行了详细的描述。
第三章是对黔醉酒业白酒销售系统的整体需求分析,根据黔醉酒业白酒销售系统的特点,给出了黔醉酒业白酒销售系统所采用的体系结构,并对该体系结构进行了非功能性分析。
第四章是本文的重点,它是对本文中所涉及的主要功能模块的具体分析与说明,并对本文中所涉及的每一个模块,分别从数据库的概念、逻辑结构等方面进行了详尽的说明,并提出了本文所要探讨的一些问题与解决方法。
第五章是对该系统的开发和运行环境的介绍,并对用户、管理员和业务员的相应功能做了详细的设计,并将相关的网页截图上传,用文字来描述其实现的具体功能。
第六章是通过测试用例,对黔醉酒业白酒销售系统中的几个主要功能模块进行了测试,最终得到了测试结果。
1.4 本章小结
本章先详细介绍了本文的选题背景与意义,按照时间的顺序说明了国内外的研究现状,然后结合系统存在的一些问题分析了它们的应对措施,并对本文的研究内容进行了具体阐述,最后按照论文的组织结构介绍了本文。
2 相关技术
2.1 Vue框架
目前市面上出现了许多优秀的前端框架可以解决了许多开发问题,Vue 就是这样一款优秀的框架,它与现代浏览器和支持ES2015的Node.js版本兼容,Vue.js的核心库只关注视图层,非常容易学习和集成到其他库或项目中[17]。本节将详细的介绍基于 MVVM模式的轻量级响应式框架 Vue[16]。
Vue.js的特点主要有以下几点:
1.模板和渲染函数:Vue.js支持使用模板和渲染函数来生成视图;
2.生态系统:Vue.js具有丰富的生态系统,包括Vue Router、Vuex、Vue CLI等工具和插件,可以帮助开发者更加高效地开发应用程序[18]。
总之,Vue.js是一款非常适合构建交互式Web应用程序的JavaScript框架,易于学习和使用,拥有丰富的生态系统和社区支持。
2.2 SpringBoot框架
Spring Boot是 Pivotal小组推出的一种以 Spring为基础的新型架构,旨在使 Spring程序在构建和发展中变得更加容易。这个架构的基本原理是“协议多于组态”,它使用了一种特殊的方法来进行组态,这样就不需要为开发人员定义许多 XML组态。这样, Spring Boot就会努力在迅速发展的应用程序开发方面保持领先地位。Spring Boot是基于原始 Spring的架构,同时也整合了为方便发展而设计的类库, Spring Boot就像一个大型的集装箱。
Spring Boot特性:
1.依靠性管理的方式来处理依赖性问题。
2.配置的复杂性和种类繁多的问题,由自动化结构来处理。
3.利用内置 web容器来处理部署的问题,而非 tomcat,而是应用程序使用Tomcat。
2.3 MySQL数据库
MySQL是一种广泛使用的关系数据库,由于其小巧、快速、便宜而深受开发人员青睐,因此我们经常把其用于开发。其源代码易于携带,仅需要编写一条 sql代码,就可以在不同的数据库中反复地应用。本系统主要是用MySQL数据库来进行存储数据,这样可以让开发者和用户使用起来更加高效、便捷。下面将介绍一下关系型数据库和非关系型数据库的大概情况。如今,关系数据库的使用日益广泛,它可以说是无处不在。实际上,在实际应用中,存在着大量的关系数据库,其中,以 MySQL, ORACLE, SQLServer为代表,应用最为广泛。一款由瑞典 MySQL AB公司开发的 Oracle的一款程序,它是一个开放源码的、关系型的数据库系统。在 WEB领域, MySQL是应用最多的一种关系型数据库。SQL是用于访问数据库的最常用的 MySQL标准。
2.4 本章小结
本章主要围绕系统开发过程中使用的技术进行了介绍。其中,本文用到的开发技术主要包括 Springboot、Vue 和 MySQL,它们都是开源的技术,再加上它们特有的技术优势,能进一步说明本系统的实现具有经济和技术可行性。
######### #########
######### ######### #########
3 系统分析
想要开发出一套健壮性强,用户粘性高,管理用使用方便的系统,前期工作必须做好,系统分析是重中之重,可以通过与企业的反复交流及企业本身的业务需求制定计划,做好各种调查分析,经过一系列的整理调查结果及分析,才能明白客户真正需要的是什么,管理员真正想管理的系统是怎样的.
本项目以真实企业的需求为标准,自顶而下逐层分析,以各个切入点对运行环境,系统等进行分析,最终制定好如何开发这套系统,认真研究需求,做了以下分析。包括可行性分析,需求分析,设计目标与原则,功能分析,流程分析接下来会逐步简绍
3.1 系统可行性分析
3.1.1技术可行性
本企业网站在Windows操作系统中进行开发,并且目前PC机的性能已经可以胜任普通网站的web服务器。系统开发所使用的技术也都是自身所具有的,也是当下广泛应用的技术之一。
本系统在Windows操作系统中独立进行开发,现在的PC电脑性能中上的一类完全可以胜任WEB服务器一职,此系统的开发技术是我自身也具有一定底子的,且这些技术也都挺时髦,用途普遍、广泛。
系统的开发环境及配置相对简单,IDEA平台也给了开发者提供诸多便利开发起来十分顺畅,用JAVA语言开发可移植性稳定性都比较强,加上成熟的Mysql数据库进行前后台的数据交互,根据业务需求逐步完善系统,使得网站运行稳定安全。
3.1.2经济可行性
本系统开发之前的所有调研基本都是本人独立完成,需求设计,功能开发等也都是自己及指导老师的帮助下完成,通过自己的努力解决掉开发过程中所遇到的问题经济支出可以忽略不计,固黔醉酒业白酒销售系统在经济可行性上完全可行可以开发。
3.1.3操作可行性
可操作性主要是对黔醉酒业白酒销售设计完成后,基于协同推荐的黔醉酒业白酒销售系统在设计完成时页面简单,不论是用户还是管理员登录系统后稍加适应,便可熟练掌握并使用。不需要专业的计算机人员进行指导,会些简单的鼠标点击及键盘输入就能使用。
3.2 需求分析
本系统需求主要从三方面进行介绍,一方面是黔醉酒业基于当前电商大环境下应该如何发开自己的系统才能具有核心竞争力,一方面是设计此系统管理员应该具有哪些需求,最后一方面则是用户的需求。
进行系统开发前应该先进行初步调查,自顶向下的系统化观点全面调查是必要的。首先对中国酒水企业和中国酒水消费情况进行详细调查,从而发现中小型酒水企业内部运作机制还存在哪些问题需要解决,他们还有需要什么样的功能来帮助企业获得最大利润网。经过对中小型白酒销售企业的多次调查和分析后,发现目前我国的大多数中小型酒类销售上的销售管理工作还停留在电子报表模式中。具体归纳有以下几点:
(1)销售业务管理工作上缺乏规范性,不按正规流程处理,大量的工作皆是手工处理,效率不高,容易出错。查询种种信息的时候只能通过Excel技术翻阅来得到信息,当销售信息,客户信息十分多的时候,速度就会非常慢。
(2)黔醉酒业销售企业内部管理工作效率低下,工作量十分巨大: 客户、供货商、和公司联系不够紧密:且销售模式还是以各级经销商通过社交软件以及线下门店进行交易。这种模式作为客户来讲线下门店受地域及时间的限制可能不方便前往,而基于微信登社交媒体的交易呢又显得不太安全
此系统管理员管理应该可以进行包括个人中心管理、首页管理、用户管理、类型管理、产品管理、订单管理、在线客服在内的几大功能模块。
用户则应该可以实现首页、热卖酒水、购物车、优惠资讯,在我的页面可以对个人中心、我的订单、我的收藏管理、我的地址等功能进行详细操作。
白酒销售的业务流程中一共有五个业务处理单位,分别是客户、财务、销售、库存、供应商,这是系统外部单位。这几个部门联系紧密牵一发能动全身,表的联动就显得十分关键。不应该存在已退款但是库存还是没有增长的情况。
3.3 项目设计目标与原则
1、关于黔醉酒业白酒销售系统的基本要求
(1)功能要求:管理员可以进行包括个人中心管理、首页管理、用户管理、类型管理、产品管理、订单管理、在线客服在内的几大功能模块。
(2)性能:在不同配置的电脑以及不同的操作系统的电脑都能完整的呈现与使用。
(3)安全与保密要求:用户的密码由自己注册时设定,且后续可以自己认为更改,即使是管理员也无法查看用户的密码。
(4)环境要求:在Windows系列、linux系统等多种操作系统下都使用,一定得支持多种平台,
2、开发目标
黔醉酒业白酒销售系统的主要开发目标如下:
(1)此系统信息关系的自动化、规范化,系统化;
(2)加强系统的健壮性,减少维修人员的工作量,提高系统的可用性。
(3)信息能很方便的进行查询检索等等;
(4)通过在线客服等功能实时解决用户的疑问,提高效率及用户满意程度;
(5)考虑到用户多样性及非计算机相关人员在本公司的占比极大操作简单势必为本系统的一大目标
3、设计原则
本黔醉酒业白酒销售系统采用Srpingboot框、,vue框架、Mysql数据库
Java语言开发,充分保证了系统稳定性、可移植性、完整性。
黔醉酒业白酒销售系统的设计与实现的思想如下:
1、操作简洁、功能完善安全性高、页面布局合理、拥有查询及检索能让用户快速跳转及浏览到自己想要的产品
2、即时生效,管理一发布信息,用户便能立马看到,响应快,用户及管理员通过点击等操做能立马得到系统的响应。避免浪费用户过多时间,大大提升效率。
3.4功能分析
考虑到实际生活中在基于协同推荐的黔醉酒业白酒销售系统管理方面的需要以及对该系统认真的分析,将系统权限按管理员,用户和两类涉及用户划分。
(1)管理员功能需求
管理员登陆后,主要模块包括首页、个人中心、用户管理、类型管理、热卖酒水管理、优惠资讯、系统简介管理、轮播图管理、订单、在线客服等功能。管理员用例图如图3-1所示。
图3-1 管理员用例图
(2)用户功能需求
用户登陆后进入首页,可以实现首页、热卖酒水、购物车、优惠资讯,在我的页面可以对个人中心、我的订单、我的收藏管理、我的地址等功能进行详细操作。用户用例图如图3-2所示。
图3-2用户用例图
3.5系统流程分析
3.5.1操作流程
系统登录流程图,如图所示:
图3-1登录流程图
3.5.2添加信息流程
添加信息流程图,如图所示:
图3-2添加信息流程图
3.5.3删除信息流程
删除信息流程图,如图所示:
图3-3删除信息流程图
3.6本章小结
本章先从用户角度出发,分析了系统应满足的功能性需求,接着根据系统功能性需求分析然后基于系统设计原则,具体描述了系统的非功能性需求,最后根据系统中的类对象和它们之间了关联关系,完成了系统的静态分析。
4 系统设计
4.1功能结构
本系统是基于三层结构的黔醉酒业白酒销售系统,架构包括了两个方便。一个是软件层次架构,二是软件功能结构
登录三层功能架构图,如图4-1所示:
图4-1 登录结构图
为了更好的去理清本系统整体思路,对该系统以结构图的形式表达出来,设计实现该基于协同推荐的黔醉酒业白酒销售系统的功能结构图如下所示:
图4-2 系统总体结构图
4.2 数据库设计
4.2.1 数据库实体图
实体图是由实体及其关系构成的图,通过实体图可以清楚地描述系统涉及到的实体之间的相互关系。在系统中对一些主要的几个关键实体如下图:
(1) 热卖酒水实体图如下所示:
图4-3产品实体图
(2) 购物车实体如下所示:
图4-4购物车实体图
数据库的概念模型转换成逻辑模型又称逻辑设计,通俗的讲就是实体图转化成以关系模式、层次模式表现出来的形式,水数据库E-R图逻辑结构如下:
图4-5 E-R图表
4.2.2 数据库表
数据库表的设计,如下表:
表4-1 用户表
Table 4-1 User Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
yonghuzhanghao | 用户账号 | varchar | 否 | |
mima | 密码 | varchar | 否 | |
yonghuxingming | 用户姓名 | varchar | 否 | |
touxiang | 头像 | longtext | 否 | |
xingbie | 性别 | varchar | 否 | |
lianxifangshi | 联系方式 | varchar | 否 | |
money | 余额 | float | 否 |
表4-2 购物表
Table 4-2 Shopping List
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
tablename | 商品表名 | varchar | 否 | |
userid | 用户id | bigint | 否 | |
goodid | 商品id | bigint | 否 | |
goodname | 商品名称 | varchar | 否 | |
picture | 图片 | longtext | 否 | |
buynumber | 购买数量 | int | 否 | |
price | 单价 | float | 否 |
表4-3 管理员表
Table 4-3 Administrator Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
username | 用户名 | varchar | 否 | |
password | 密码 | varchar | 否 | |
role | 角色 | varchar | 否 | |
addtime | 新增时间 | timestamp | 否 | |
表4-4 地址表
Table 4-4 Address Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
userid | 用户id | bigint | 否 | |
address | 地址 | varchar | 否 | |
name | 收货人 | varchar | 否 | |
phone | 电话 | varchar | 否 | |
isdefault | 是否默认地址[是/否] | varchar | 否 |
######### #########
表4-5 验证表
Table 4-5 Validation Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
userid | 用户id | bigint | 否 | |
username | 用户名 | varchar | 否 | |
tablename | 表名 | varchar | 否 | |
role | 角色 | varchar | 否 | |
token | 密码 | varchar | 否 | |
addtime | 新增时间 | timestamp | 否 | |
expiratedtime | 过期时间 | timestamp | 否 |
######### 表4-6 关于我们表
Table 4-6 About Our Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
title | 标题 | varchar | 否 | |
subtitle | 副标题 | varchar | 否 | |
content | 内容 | longtext | 否 | |
picture1 | 图片1 | longtext | 否 | |
picture2 | 图片2 | longtext | 否 |
表4-7 收藏表
Table 4-7 Collection Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
userid | 用户id | bigint | 否 | |
refid | 商品id | bigint | 否 | |
tablename | 表名 | varchar | 否 | |
name | 名称 | varchar | 否 | |
picture | 图片 | longtext | 否 | |
type | 类型(1:收藏,21:赞,22:踩,31:竞拍参与,41:关注) | varchar | 否 | |
inteltype | 推荐类型 | varchar | 否 |
表4-8 热卖酒水表
Table 4-8 Hot Selling Liquor List
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
jiushuimingcheng | 酒水名称 | varchar | 否 | |
fengmian | 封面 | longtext | 否 | |
jiushuileixing | 酒水类型 | varchar | 否 | |
baozhuangxingshi | 包装形式 | varchar | 否 | |
pinpai | 品牌 | varchar | 否 | |
dushu | 度数 | varchar | 否 | |
chuzangfangfa | 储藏方法 | varchar | 否 | |
shengchannianfen | 生产年份 | varchar | 否 | |
chandi | 产地 | varchar | 否 | |
changming | 厂名 | varchar | 否 | |
shiyongchangjing | 适用场景 | varchar | 否 | |
shengchanxukezheng | 生产许可证 | varchar | 否 | |
jiushuixiangqing | 酒水详情 | longtext | 否 | |
onelimittimes | 单限 | int | 否 | |
alllimittimes | 库存 | int | 否 | |
thumbsupnum | 赞 | int | 否 | |
crazilynum | 踩 | int | 否 | |
clicktime | 最近点击时间 | datetime | 否 | |
clicknum | 点击次数 | int | 否 |
表4-9 订单表
Table 4-9 Order Form
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
orderid | 订单编号 | varchar | 否 | |
tablename | 商品表名 | varchar | 否 | |
userid | 用户id | bigint | 否 | |
goodid | 商品id | bigint | 否 | |
goodname | 商品名称 | varchar | 否 | |
picture | 商品图片 | longtext | 否 | |
buynumber | 购买数量 | int | 否 | |
price | 价格 | float | 否 | |
discountprice | 折扣价格 | float | 否 | |
total | 总价格 | float | 否 | |
discounttotal | 折扣总价格 | float | 否 | |
type | 支付类型 | int | 否 | |
status | 状态 | varchar | 否 | |
address | 地址 | varchar | 否 | |
tel | 电话 | varchar | 否 | |
consignee | 收货人 | varchar | 否 | |
remark | 备注 | varchar | 否 | |
logistics | 物流 | longtext | 否 | |
goodtype | 商品类型 | varchar | 否 |
表4-10 优惠资讯表
Table 4-10 Discount Information Table
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
title | 标题 | varchar | 否 | |
introduction | 简介 | longtext | 否 | |
picture | 图片 | longtext | 否 | |
content | 内容 | longtext | 否 |
表4-11 热卖酒水评论表
Table 4-11 Hot Selling Liquor Review Form
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
refid | 关联表id | bigint | 否 | |
userid | 用户id | bigint | 否 | |
avatarurl | 头像 | longtext | 否 | |
nickname | 用户名 | varchar | 否 | |
content | 评论内容 | longtext | 否 | |
reply | 回复内容 | longtext | 否 |
表4-12 在线客服表
Table 4-12 Online Customer Service Form
字段名称 | 含义 | 数据类型 | 允许空值 | 主外键 |
---|---|---|---|---|
id | 主键 | bigint | 否 | 主键 |
addtime | 创建时间 | timestamp | 否 | |
userid | 用户id | bigint | 否 | |
adminid | 管理员id | bigint | 否 | |
ask | 提问 | longtext | 否 | |
reply | 回复 | longtext | 否 | |
isreply | 是否回复 | int | 否 |
4.3协同过滤算法
当今社会已经进入了一个信息化的社会,用户和信息提供者都面临着巨大的挑战,而作为一个使用者,要在海量的资料中寻找自己所需的信息,十分的不容易。瞎找会耗费很多的时间;作为黔醉酒业白酒销售的销售者,要在在短期之内,让系统呈现出特色准确推荐要引起使用者的注意,也存在一定的难度。协同推荐能很好的解决以上问题,它会根据用户之间的关联度或商品之间的关联度给顾客推荐出顾客可能喜欢的潜在商品。本系统由于个人能力原因无发写出实现用户或商品关联度的相关代码便退而求其次,转而协同推荐用户以往订单中已经购买过的白酒的相同系列酒。因为相同系列的酒水产品中,不论口感还是价格差异其实不太大,这么一来我们便可认为它们之间的商品关联度极高,便做此协同推荐。本系统的协同推荐的代码如下图4-6所示;
![]4F$7M5M98K)4EWK4U713H
4.4本章小结
本章围绕系统总体架构、功能交互和数据库等多个方面对系统进行了设计。总体架构部分是基于开发过程中采用的 Springboot 和 Vue 结合的前后分离的框架进行的设计,详细描述了每个功能在实现过程中的具体流程,并将功能分成了基本功能和推荐功能。最后,根据前一章系统的需求分析和静态分析的结果,完成了系统数据库的设计。
5 系统功能实现
5.1后台功能模块
后台登录,用户通过输入用户名、密码,选择角色并点击登录进行系统登录操作,如图5-1所示。
图5-1后台登录界面图 ######### 实现代码如下:
5.1.1管理员功能模块
管理员登陆系统后,可以对首页、个人中心、用户管理、类型管理、热卖酒水管理、系统管理、优惠资讯管理、系统简介管理、订单管理等功能进行相应操作,如图5-2所示。
图5-2管理员功能界面图
用户管理,在用户管理页面可以对索引、用户账号、用户姓名、性别、年龄、头像等内容进行详情、修改或删除等操作,如图5-3所示。
图5-3用户管理界面图
实现代码如下:
类型管理,在类型管理页面可以对索引、酒水类型等内容进行详情,修改或删除等操作,如图5-4所示。
图5-4类型管理界面图
实现代码如下:
热卖酒水管理,在热卖酒水页面可以对索引、酒水名称、封面、酒水类型、包装形式、品牌、度数、储藏方法、生产年份等内容进行详情,修改,查看评论或删除等操作,如图5-5所示。
图5-5热卖酒水管理界面图
实现代码如下: ######### 优惠资讯管理,在优惠资讯管理页面可以对索引、标题、图片、等内容进行详情、修改和删除等操作,如图5-6所示。
图5-6优惠资讯管理界面图
实现代码如下:
系统简介管理,在系统简介管理页面可以对索引、标题、副标题 、图片等内容进行详情,修改或删除等操作,如图5-7所示。
图5-7系统简介管理界面图
实现代码如下:
订单管理,在订单管理页面可以对索引、订单编号、商品名称、商品图片、购买数量、价格、折扣价格、总价格、折扣总价格、支付类型、状态、地址、电话等内容进行详情,修改或删除操作如图5-8所示。
图5-8订单管理界面图
5.2.2用户功能模块
用户登陆系统后,可以对首页、个人中心、热卖酒水、优惠资讯管理、购物车管理、订单管理等功能进行相应操作,如图5-9所示。
图5-9用户功能界面图
热卖酒水管理,在热卖酒水管理页面可以对酒水名称、包装形式、生产年份、适用场景、价格等内容进行详情,修改,查看评论或删除操作,如图5-10所示。
图5-10热卖酒水管理界面图
实现代码如下:
订单管理,在已支付订单页面可以对索引、订单编号、商品名称、商品图片、购买数量、价格、折扣价格、总价格、折扣总价格、支付类型、状态、地址、电话、收货人、商户名称、下单时间等内容进行详情或发货操作,还可对已完成订单、已发货订单、未支付订单、已取消订单、已退款订单进行相对应操作,如图5-11所示。
图5-11订单管理界面图
地址管理,在地址管理页面可以对联系人、手机号、地址、默认、等内容进行详情或发货操作,如图5-12所示。
图5-12地址管理界面图
在线客服管理,在在线客服页面可以对客服输入自己的需求及问题,然后提交,等待客服回复等操作,如图5-13所示。
图5-13在线客服管理界面图 ######### 实现代码如下:
5.2本章小结
本章主要的内容是白酒推荐系统的实现。它主要分为系统的基本功能和白酒推荐功能两个部分,其中基本功能主要包含:用户注册登录、用户信息修改、热卖酒水、优惠资讯、订单管理和购物车。本节主要是具体说明用户可以在前端用户系统对每个功能进行哪些系统操作,并将主要的前端页面实现的效果进行了展示。
6 系统测试
系统
CartServiceImpl.java
package com.service.impl;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.List;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.utils.PageUtils;
import com.utils.Query;
import com.dao.CartDao;
import com.entity.CartEntity;
import com.service.CartService;
import com.entity.vo.CartVO;
import com.entity.view.CartView;
@Service("cartService")
public class CartServiceImpl extends ServiceImpl<CartDao, CartEntity> implements CartService {
@Override
public PageUtils queryPage(Map<String, Object> params) {
Page<CartEntity> page = this.selectPage(
new Query<CartEntity>(params).getPage(),
new EntityWrapper<CartEntity>()
);
return new PageUtils(page);
}
@Override
public PageUtils queryPage(Map<String, Object> params, Wrapper<CartEntity> wrapper) {
Page<CartView> page =new Query<CartView>(params).getPage();
page.setRecords(baseMapper.selectListView(page,wrapper));
PageUtils pageUtil = new PageUtils(page);
return pageUtil;
}
@Override
public List<CartVO> selectListVO(Wrapper<CartEntity> wrapper) {
return baseMapper.selectListVO(wrapper);
}
@Override
public CartVO selectVO(Wrapper<CartEntity> wrapper) {
return baseMapper.selectVO(wrapper);
}
@Override
public List<CartView> selectListView(Wrapper<CartEntity> wrapper) {
return baseMapper.selectListView(wrapper);
}
@Override
public CartView selectView(Wrapper<CartEntity> wrapper) {
return baseMapper.selectView(wrapper);
}
}
UsersServiceImpl.java
package com.service.impl;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.dao.UsersDao;
import com.entity.UsersEntity;
import com.service.UsersService;
import com.utils.PageUtils;
import com.utils.Query;
/**
* 系统用户
*/
@Service("usersService")
public class UsersServiceImpl extends ServiceImpl<UsersDao, UsersEntity> implements UsersService {
@Override
public PageUtils queryPage(Map<String, Object> params) {
Page<UsersEntity> page = this.selectPage(
new Query<UsersEntity>(params).getPage(),
new EntityWrapper<UsersEntity>()
);
return new PageUtils(page);
}
@Override
public List<UsersEntity> selectListView(Wrapper<UsersEntity> wrapper) {
return baseMapper.selectListView(wrapper);
}
@Override
public PageUtils queryPage(Map<String, Object> params,
Wrapper<UsersEntity> wrapper) {
Page<UsersEntity> page =new Query<UsersEntity>(params).getPage();
page.setRecords(baseMapper.selectListView(page,wrapper));
PageUtils pageUtil = new PageUtils(page);
return pageUtil;
}
}
AddressController.java
package com.controller;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.utils.ValidatorUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.annotation.IgnoreAuth;
import com.entity.AddressEntity;
import com.entity.view.AddressView;
import com.service.AddressService;
import com.service.TokenService;
import com.utils.PageUtils;
import com.utils.R;
import com.utils.MD5Util;
import com.utils.MPUtil;
import com.utils.CommonUtil;
import java.io.IOException;
/**
* 地址
* 后端接口
* @author
* @email
* @date 2023-04-16 16:33:34
*/
@RestController
@RequestMapping("/address")
public class AddressController {
@Autowired
private AddressService addressService;
/**
* 后端列表
*/
@RequestMapping("/page")
public R page(@RequestParam Map<String, Object> params,AddressEntity address,
HttpServletRequest request){
if(!request.getSession().getAttribute("role").toString().equals("管理员")) {
address.setUserid((Long)request.getSession().getAttribute("userId"));
}
EntityWrapper<AddressEntity> ew = new EntityWrapper<AddressEntity>();
PageUtils page = addressService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, address), params), params));
return R.ok().put("data", page);
}
/**
* 前端列表
*/
@RequestMapping("/list")
public R list(@RequestParam Map<String, Object> params,AddressEntity address,
HttpServletRequest request){
if(!request.getSession().getAttribute("role").toString().equals("管理员")) {
address.setUserid((Long)request.getSession().getAttribute("userId"));
}
EntityWrapper<AddressEntity> ew = new EntityWrapper<AddressEntity>();
PageUtils page = addressService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, address), params), params));
return R.ok().put("data", page);
}
/**
* 列表
*/
@RequestMapping("/lists")
public R list( AddressEntity address){
EntityWrapper<AddressEntity> ew = new EntityWrapper<AddressEntity>();
ew.allEq(MPUtil.allEQMapPre( address, "address"));
return R.ok().put("data", addressService.selectListView(ew));
}
/**
* 查询
*/
@RequestMapping("/query")
public R query(AddressEntity address){
EntityWrapper< AddressEntity> ew = new EntityWrapper< AddressEntity>();
ew.allEq(MPUtil.allEQMapPre( address, "address"));
AddressView addressView = addressService.selectView(ew);
return R.ok("查询地址成功").put("data", addressView);
}
/**
* 后端详情
*/
@RequestMapping("/info/{id}")
public R info(@PathVariable("id") Long id){
AddressEntity address = addressService.selectById(id);
return R.ok().put("data", address);
}
/**
* 前端详情
*/
@IgnoreAuth
@RequestMapping("/detail/{id}")
public R detail(@PathVariable("id") Long id){
AddressEntity address = addressService.selectById(id);
return R.ok().put("data", address);
}
/**
* 后端保存
*/
@RequestMapping("/save")
public R save(@RequestBody AddressEntity address, HttpServletRequest request){
address.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());
//ValidatorUtils.validateEntity(address);
address.setUserid((Long)request.getSession().getAttribute("userId"));
Long userId = (Long)request.getSession().getAttribute("userId");
if(address.getIsdefault().equals("是")) {
addressService.updateForSet("isdefault='否'", new EntityWrapper<AddressEntity>().eq("userid", userId));
}
address.setUserid(userId);
addressService.insert(address);
return R.ok();
}
/**
* 前端保存
*/
@RequestMapping("/add")
public R add(@RequestBody AddressEntity address, HttpServletRequest request){
address.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());
//ValidatorUtils.validateEntity(address);
address.setUserid((Long)request.getSession().getAttribute("userId"));
Long userId = (Long)request.getSession().getAttribute("userId");
if(address.getIsdefault().equals("是")) {
addressService.updateForSet("isdefault='否'", new EntityWrapper<AddressEntity>().eq("userid", userId));
}
address.setUserid(userId);
addressService.insert(address);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
@Transactional
public R update(@RequestBody AddressEntity address, HttpServletRequest request){
//ValidatorUtils.validateEntity(address);
if(address.getIsdefault().equals("是")) {
addressService.updateForSet("isdefault='否'", new EntityWrapper<AddressEntity>().eq("userid", request.getSession().getAttribute("userId")));
}
addressService.updateById(address);//全部更新
return R.ok();
}
/**
* 获取默认地址
*/
@RequestMapping("/default")
public R defaultAddress(HttpServletRequest request){
Wrapper<AddressEntity> wrapper = new EntityWrapper<AddressEntity>().eq("isdefault", "是").eq("userid", request.getSession().getAttribute("userId"));
AddressEntity address = addressService.selectOne(wrapper);
return R.ok().put("data", address);
}
/**
* 删除
*/
@RequestMapping("/delete")
public R delete(@RequestBody Long[] ids){
addressService.deleteBatchIds(Arrays.asList(ids));
return R.ok();
}
/**
* 提醒接口
*/
@RequestMapping("/remind/{columnName}/{type}")
public R remindCount(@PathVariable("columnName") String columnName, HttpServletRequest request,
@PathVariable("type") String type,@RequestParam Map<String, Object> map) {
map.put("column", columnName);
map.put("type", type);
if(type.equals("2")) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar c = Calendar.getInstance();
Date remindStartDate = null;
Date remindEndDate = null;
if(map.get("remindstart")!=null) {
Integer remindStart = Integer.parseInt(map.get("remindstart").toString());
c.setTime(new Date());
c.add(Calendar.DAY_OF_MONTH,remindStart);
remindStartDate = c.getTime();
map.put("remindstart", sdf.format(remindStartDate));
}
if(map.get("remindend")!=null) {
Integer remindEnd = Integer.parseInt(map.get("remindend").toString());
c.setTime(new Date());
c.add(Calendar.DAY_OF_MONTH,remindEnd);
remindEndDate = c.getTime();
map.put("remindend", sdf.format(remindEndDate));
}
}
Wrapper<AddressEntity> wrapper = new EntityWrapper<AddressEntity>();
if(map.get("remindstart")!=null) {
wrapper.ge(columnName, map.get("remindstart"));
}
if(map.get("remindend")!=null) {
wrapper.le(columnName, map.get("remindend"));
}
if(!request.getSession().getAttribute("role").toString().equals("管理员")) {
wrapper.eq("userid", (Long)request.getSession().getAttribute("userId"));
}
int count = addressService.selectCount(wrapper);
return R.ok().put("count", count);
}
}
update-password.vue
<template>
<div :style='{"padding":"30px 0 0"}'>
<el-form
:style='{"width":"86%","padding":"30px","boxShadow":"0px 4px 10px 0px rgba(0,0,0,0.3020)","margin":"0 auto","borderRadius":"6px","background":"rgba(255,255,255,.8)"}'
class="add-update-preview"
ref="ruleForm"
:rules="rules"
:model="ruleForm"
label-width="140px"
>
<el-form-item :style='{"width":"100%","margin":"0 0 20px","display":"inline-block"}' label="原密码" prop="password">
<el-input v-model="ruleForm.password" show-password></el-input>
</el-form-item>
<el-form-item :style='{"width":"100%","margin":"0 0 20px","display":"inline-block"}' label="新密码" prop="newpassword">
<el-input v-model="ruleForm.newpassword" show-password></el-input>
</el-form-item>
<el-form-item :style='{"width":"100%","margin":"0 0 20px","display":"inline-block"}' label="确认密码" prop="repassword">
<el-input v-model="ruleForm.repassword" show-password></el-input>
</el-form-item>
<el-form-item :style='{"padding":"0","margin":"0"}'>
<el-button :style='{"border":"0","cursor":"pointer","padding":"0","margin":"0 20px 0 0","outline":"none","color":"rgba(255, 255, 255, 1)","borderRadius":"4px","background":"rgba(135, 154, 108, 1)","width":"128px","lineHeight":"40px","fontSize":"14px","height":"40px"}' type="primary" @click="onUpdateHandler">确 定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false,
ruleForm: {},
user: {},
rules: {
password: [
{
required: true,
message: "密码不能为空",
trigger: "blur"
}
],
newpassword: [
{
required: true,
message: "新密码不能为空",
trigger: "blur"
}
],
repassword: [
{
required: true,
message: "确认密码不能为空",
trigger: "blur"
}
]
}
};
},
mounted() {
this.$http({
url: `${this.$storage.get("sessionTable")}/session`,
method: "get"
}).then(({ data }) => {
if (data && data.code === 0) {
this.user = data.data;
} else {
this.$message.error(data.msg);
}
});
},
methods: {
onLogout() {
this.$storage.remove("Token");
this.$router.replace({ name: "login" });
},
// 修改密码
onUpdateHandler() {
this.$refs["ruleForm"].validate(valid => {
if (valid) {
var password = "";
if (this.user.mima) {
password = this.user.mima;
} else if (this.user.password) {
password = this.user.password;
}
if (this.user.password) {
password = this.user.password;
} else if (this.user.password) {
password = this.user.password;
}
if (this.ruleForm.password != password) {
this.$message.error("原密码错误");
return;
}
if (this.ruleForm.newpassword != this.ruleForm.repassword) {
this.$message.error("两次密码输入不一致");
return;
}
this.user.password = this.ruleForm.newpassword;
this.user.mima = this.ruleForm.newpassword;
this.$http({
url: `${this.$storage.get("sessionTable")}/update`,
method: "post",
data: this.user
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "修改密码成功,下次登录系统生效",
type: "success",
duration: 1500,
onClose: () => {
}
});
} else {
this.$message.error(data.msg);
}
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.el-date-editor.el-input {
width: auto;
}
.add-update-preview .el-form-item /deep/ .el-form-item__label {
padding: 0 10px 0 0;
color: #333;
font-weight: 500;
width: 140px;
font-size: 14px;
line-height: 40px;
text-align: right;
}
.add-update-preview .el-form-item /deep/ .el-form-item__content {
margin-left: 140px;
}
.add-update-preview .el-input /deep/ .el-input__inner {
border: 2px solid #797979;
border-radius: 4px;
padding: 0 12px;
outline: none;
color: rgba(121, 121, 121, 1);
width: auto;
font-size: 14px;
min-width: 400px;
height: 40px;
}
.add-update-preview .el-select /deep/ .el-input__inner {
border: 2px solid #797979;
border-radius: 4px;
padding: 0 10px;
outline: none;
color: rgba(121, 121, 121, 1);
width: auto;
font-size: 14px;
min-width: 300px;
height: 40px;
}
.add-update-preview .el-date-editor /deep/ .el-input__inner {
border: 2px solid #797979;
border-radius: 4px;
padding: 0 10px 0 30px;
outline: none;
color: rgba(121, 121, 121, 1);
width: auto;
font-size: 14px;
min-width: 300px;
height: 40px;
}
.add-update-preview /deep/ .el-upload--picture-card {
background: transparent;
border: 0;
border-radius: 0;
width: auto;
height: auto;
line-height: initial;
vertical-align: middle;
}
.add-update-preview /deep/ .el-upload-list .el-upload-list__item {
border: 2px dashed #797979;
cursor: pointer;
border-radius: 6px;
color: #797979;
width: 150px;
font-size: 32px;
line-height: 100px;
text-align: center;
height: 100px;
}
.add-update-preview /deep/ .el-upload .el-icon-plus {
border: 2px dashed #797979;
cursor: pointer;
border-radius: 6px;
color: #797979;
width: 150px;
font-size: 32px;
line-height: 100px;
text-align: center;
height: 100px;
}
.add-update-preview .el-textarea /deep/ .el-textarea__inner {
border: 2px solid #797979;
border-radius: 4px;
padding: 12px;
outline: none;
color: rgba(121, 121, 121, 1);
width: 100%;
font-size: 14px;
height: 120px;
}
</style>
声明
本博客适用于广泛的学术和教育用途,包括但不限于个人学习、开发设计,产品设计。仅供学习参考,旨在为读者提供深入理解和学术研究的材料。