外卖订餐系统
摘 要
随着外卖订餐在高校越来越普及,传统的电话订餐给顾客跟外卖店带来不方便,如何使订餐更快速,更方便已成为众多高校学生关注的问题了。本外卖订餐管理系统是针对高校外卖店进行具体的需求分析,采用OOA(面向对象分析)和采用UML工具辅助开发分析,基于S2SH(Struts2+Spring+Hibernate)架构进行设计和开发。论文主要描述外卖订餐管理系统的开发流程,分别从需求分析和系统设计、详细设计与系统实现这几个阶段进行描述。
关键词:订餐管理系统 S2SH OOA
ABSTRACT
With more and more popular in universities order take-out, due to the traditional telephone reservation for customers to bring inconvenience take-away meal, how to make more quickly, more convenient has become the concern of the students. The take-away meal management system in colleges and universities is the concrete take-away demand analysis, using object-oriented analysis (OOA) and using UML tools to assist in the development, using Struts2-Spring-Hibernate framework to design and development. Thesis mainly describes take-away meal management system process, separately from the demand analysis and system design, detailed design and realization of this system are described several stages.
Key words: meal management system S2SH OOA
目 录
一、绪论 1
1.1 背景 1
一 、绪 论
1.1 背景
进入21世纪以来,餐饮行业以年均20%的增长速度,成为国民经济中的发展最快的行业之一。随着人们生活水平的不断提高,人们甚至想要不出门就能吃到可口的饭菜——这就是外卖。在我国高校内餐饮行业外卖行业更是发展最快的一个行业,在北师大珠海分校每年都有几间新的外卖店的产生。外卖订餐已经成为北师大珠海分校学生生活中不可缺的一部分,而订餐的方式也随着学生们的要求提高,不断的多样化和成熟化。
1.2外卖订餐行业的现状分析
- 外卖店数量众多,各店竞争较大。
- 外卖店多数实行人工方式订餐,即打电话订餐登记。这种订餐方式造成订餐很不方便特别在订餐高峰期,经常出现打电话打不通的现象。
- 外卖店多数没有实行市场分析,一些菜式在顶峰期出现缺菜现象,而一些菜式却出现积累现象,造成了资源的浪费和经济损失。
- 外卖店没有对外卖进行财务管理,造成对店内资金管理不明确和店员滥用资金的可能。
- 无法为店内管理层提供准确的决策信息,掌握及时的市场消息。
通过分析北师大的外卖行业的现状,不难发现国内高校的外卖店大多数都是依靠手工的管理方式,没有实行外卖订餐管理的信息化,所以造成了不少问题。
1.3 外卖订餐管理系统的可行性分析及其作用
依靠传统的电话订餐实行外卖订餐不仅造成学生的方便,也对外卖店的经营产生了不良影响。实行电话订餐有以下几个缺点:一、在订餐高峰期,一架电话根本那么多的订餐顾客,有时候要多次拨打才能接通,这种情况下有时也造成双方语气匆忙,态度暴躁,给订餐带来极大的不便;二、点菜不方便,学生如果没有点菜单,很难点菜,另外外卖店得每栋宿舍每间地派传单,无疑又是一笔不小的开资了;三、学生必须支付打电话的成本,虽然有些外卖店有校园短号但对于一些没开通校园短号的学生也不是很方便。
通过上面分析,电话订餐已成为一种阻碍外卖行业发展的落后方式了,实行订餐管理的信息化迫在眉睫,利用外卖订餐管理系统对外卖流程实行信息化,不仅给订餐顾客带来了方便更给外卖店带来了经济利益。外卖订餐管理给顾客和外卖店带来了双赢。对于顾客,不用再担心高峰期打电话订餐失败了,顾客可以在网站浏览相关菜式,添加喜欢的菜式,解决了以前的那种电话订餐造成订错菜式的现象。对于外卖店更是带来了长远的利益,减少外卖店的人力和财力,通过订餐管理系统使外卖店能够及时掌握市场信息,推销新菜式和实行更有效的经营策略。
1.4 系统简介
本系统主要针对高校的外卖订餐流程和对订单处理实行信息化而构建出来的B/S平台,学生通过浏览器上网访问订餐网站可以实现网上浏览菜式和订餐功能,店员通过后台管理登陆实现对订单的处理,通过信息化处理给学生订餐带来方便更给外卖店管理人员带来了长远利益。
二 、相关技术介绍
本外卖订餐管理系统选取S2SH架构来设计和开发,S2SH是SSH升级版,以前的SSH架构中的用到的MVC框架是struts,而S2SH中的MVC框架用到的是struts2,struts2与struts有很大的区别,配置更灵活,开发更方便,利用其开发的插件与hibernate,spring能达到无缝集成,本系统采用三层架构,用struts2处理前端,hibernate封装对数据库的访问,spring对struts2、hibernate和业务逻辑层中进行对象的管理,三个框架各司其职,有利于项目开发的分工,使项目开发达到更灵活性和可维护性。S2SH三层架构如图1所示:
图1:S2SH三层架构
2.1 struts2技术介绍
Struts2是目前比较成熟的Web开发框架, Struts 2框架是Struts 1.X的替代版本,Struts 2框架整合了Struts 1.X框架和WebWork框架的优点。相对Struts 1.X,Struts 2已经有了非常大的改变,去掉了ActionForm,降低了框架组件之间的耦合性,Struts 2的Action只是普通的Java类(POJO),给模块测试工作带来了极大的方便。Struts 2提供了强大的整合能力,支持多种返回结果类型,改进了Struts 1.X的标签库,引入OGNL表达式和值栈的概念,给开发者带来了更好的体验[1]。从全局的角度来看 ,Struts2是一个pull(拉)类型的MVC(或者MVC2)框架,它与传统类型的MVC框架的不同之处就在于在Struts2中,Action担任的是模型的角色,而非控制器的角色,虽然它的角色仍然有些重叠。“pull”的动作由视图发起,它直接从Action里拉取所需的数据,而不是另外还需要一个单独的模型对象存在[2]。
图 2: MVC / Struts2架构
图2描述了Struts2架构中的模型、视图和控制器。控制器通过Struts2分发Servlet过滤器(也就是人们常说的拦截器)来实现,模型通过Action实现,视图则通过结果类型和结果组合实现。值栈和OGNL提供了公共的线程和链接,并使得不同组件可以相互集成。Struts 2设计的精巧之处就是使用了Action代理,Action代理可以根据系统的配置,加载一系列的拦截器,由拦截器将HttpServletRequest参数解析出来,传入Action。同样,Action处理的结果也是通过拦截器传入HttpServletResponse,然后由HttpServletRequest传给用户。其实,该处理过程是典型的AOP(面向切面编程)的方式,Struts 2处理过程模型如图3所示:
图 3: Struts2处理过程模型
2.2 hibernate技术介绍
Hibernate 是一个优秀的ORM框架,通过使用Hibernate框架,允许开发人员使用面向对象的方式对数据库进行访问,避免采用JDBC访问,造成面向对象编程与面向过程编程的冲突。在这种方式下,企业应用的面向对象分析、面向对象设计和面向对象编程一脉相承,让系统分析、设计更加简洁。
Hibernate作为Java EE持久化的标准方案,使用传统的POJO作为系统的持久化类,具有低侵入式设计,不会造成代码污染。系统的持久化类无需继承任何Hibernate基类,或者实现任何Hibernate接口,提供了极好的代码复用[4]。Hibernate与数据库、应用程序关联关系如图4所示:
图 4: Hibernate关联关系图
虽然Hibernate这个框架问世的时间不长,但已经成为目前最流行的持久层解决方案,较之另一个持久层框架iBATIS,Hibernate更具有面向对象的特征;较之传统的Entity EJB的持久层解决方案,Hibernate则采用低侵入式的设计,即完全采用普通的Java对象(POJO),而不必继承Hibernate的某个超类或实现Hibernate的某个接口。Hibernate是面向对象的程序设计语言和关系数据库之间的桥梁,Hibernate允许程序开发者采用面向对象的方式来操作数据库。
2.3 spring技术介绍
Spring是一个优秀的Web开发框架。它是一个分层的架构,由7个模块组成,如图5所示。其中比较重要的是核心容器模块,其他模块构建在这个核心容器之上,核心容器定义创建、配置和管理Bean的方式,它提供Spring框架的基本功能。其主要组件是BeanFactory,它是工厂模式的实现。BeanFactory通过使用反转控制(IOC)模式,将应用程序的配置和依赖性规范与实际的应用程序代码分开
图5 spring七大模块
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
- Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。[5]
2.4 DWR技术介绍
DWR是一种AJAX解决方案。DWR包括一个java库,以及一套javascript,使得我们可以用一种非常简单的方式,在页面上使用javascript直接调用后台的java对象 。
DWR的javascript库包括几个部分:dwr的javascript引擎(即对AJAX调用的封装)、dwr提供的一些非常有用的辅助javascript函数库、以及dwr自动帮我们生成的专门用于调用后台JavaBean方法的javascript库。DWR在运行的时候,动态生成一个javascript库,这个库是对后台javabean调用的封装,我们可以直接使用这个库来实现直接调用JavaBean的目的[6],其流程图6所示:
图6:DWR调用过程
三 、系统需求
本系统采用OOA(面向对象分析)和UML(Unified Modeling Language)工具为指导,本章主要对系统的需求以及系统功能进行分析描述。
3.1 UML
UML(Unified Modeling Language)是一种用来创建程序模型的图形语言(即带有语意的一种图形记号)[7],常用的UML图有类图、时序图、用例图、活动图和状态图。
3.2 需求分析
本外卖订餐管理系统包括两个子系统,前台订餐和后台管理,前台订餐是供用户浏览菜式和提交订单进行订餐;后台管理是供餐厅管理人员进行外卖订单管理、菜式管理、统计报表管理、系统管理。
3.3 系统功能
本系统采用面向对象分析方法,下面是对本系统的两个子系统进行分析说明。
- 前台管理系统
前台管理系统供用户浏览菜式,进行菜式添加到购菜车,用户可以对购菜车进行更新、清除,用户提交订单后可以在订单列表查看外卖状态,用例如图7所示:
图7:用户用例图
- 后台管理系统
后台管理系统有菜式管理、外卖订单管理、统计报表管理和系统管理四大模块。
顶层用例:后台管理有两大角色即店长跟店员,店长拥有系统全部权限,店员只能操作菜式管理跟外卖订单管理两大模块。其顶层用例如图8:
图8::顶层用例
菜式管理:可以对菜式进行查看、添加、修改和删除。用例如图9所示。
图9 菜式管理用例图
外卖订单管理:可以对外卖订单的状态进行查看,改变。用例如图10所示:
图10 外卖订单管理用例图
- 统计报表管理
菜式统计报表:对每月的菜式进行统计,可以查看哪些菜式在本月份销量比较好。
用户统计报表:对用户进行统计,可以对其经常订餐的用户实行优惠政策。
- 系统管理
用户维护:可以查看所有已注册的用户,查看该用户的所有订单列表,和删除该用户。
店员维护:可以对店员进行添加、删除、更新。
修改密码:输入旧密码,如果旧密码输入不正确会进行提示叫你重新输入,输入正确后再输入新密码和确认新密码可进行修改。用例图如图11所示:
图11 系统管理用例
四 、系统设计
本系统的设计采用OOA(面向对象分析)和利用UML工具辅助开发设计。
4.1 系统总体结构
通过前一章的需求分析跟功能分析可以得出本系统总体结构如图12所示:
图12 系统总体框架图
4.2 系统架构方式
本系统采用三层架构模式,即展现层,业务逻辑层,数据访问层,各层之间都独立,展现层与业务逻辑层接口通信,业务逻辑层与数据访问层接口通信,数据访问层直接跟数据库打交道,这样具有很好的解耦性,每一层逻辑改变不会影响到另一层,对项目以后的可维护性及团队开发具有很大的作用,三层架构流程如图13所示:
图13 三层架构
4.3 Hibernate自动建表
传统的数据库设计都是先经过建立E-R图,然后通过E-R图生成数据表。而Hibernate开发团队提倡我们用另外一种开发模式,就是先建立实体类和编写实体类映射文件,然后通过实体类和映射文件自动生成数据表。这种开发模式也是体现出来OOD思想,数据的持久化这些都是非常机械的,基本没有变动的,hibernate就是把这些行为抽取出来自动完成并在效率上做一优化等,让我们轻松实现数据库的移植。这样我们在开发中更关注于类中的设计而不必受到数据库的牵制,因为数据库本身就跟面向对象存在阻抗。国内有位领域驱动设计(DDD)专家曾经发表了一遍文章《数据库已死》,在文章中他阐述了数据库成为了大多数企业应用的主要瓶颈,也成为了运行环境中最不具伸缩性的一层,他认为软件开发应集中在领域分析,数据库应该是为领域服务而不能让我们的领域层受牵制于数据库。本系统是采用建立实体类和编写映射文件来生成数据表的开发模式。
(1)实体类POJO设计
类名 | 功能说明 |
User | 用户 |
Admin | 管理员 |
Item | 订单项 |
Menu | 菜式 |
Order | 订单 |
属性 | 类型 | 属性说明 |
id | Integer |
|
username | String | 姓名 |
password | String | 密码 |
orders | List<Order> | 订单列表 |
实体类 Admin
属性 | 类型 | 属性说明 |
id | Integer |
|
username | String | 姓名 |
password | String | 密码 |
type | Integer | 管理员类型 |
实体类 Item
属性 | 类型 | 属性说明 |
id | Integer |
|
itemName | String | 订单项名称 |
itemPrice | double | 订单项价格 |
itemNumber | Integer | 订单项数量 |
itemType | Integer | 订单项类型 |
itemIntroduction | String | 订单项描述 |
order | Order | 所属订单 |
实体类 Menu
属性 | 类型 | 属性说明 |
id | Integer |
|
name | String | 菜式名称 |
price | double | 菜式价格 |
type | Integer | 菜式类型 |
state | Integer | 菜式状态 |
itemIntroduction | String | 菜式简介 |
实体类 Order
属性 | 类型 | 属性说明 |
id | Integer |
|
phone | String | 电话号码 |
address | String | 宿舍地址 |
total | double | 总价 |
state | Integer | 订单状态 |
date | Date | 订单日期 |
barcode | Order | 订单流水号 |
user | User | 所属用户 |
items | List<Item> | 所有订单项 |
(2) hibernate映射文件编写
User.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.order.bean.User" table="user"> <id name="id" type="java.lang.Integer"> <column name="id_" /> <generator class="native" /> </id> <property name="username" type="java.lang.String"> <column name="username_" length="80" not-null="true" /> </property> <property name="password" type="java.lang.String"> <column name="password_" length="80" not-null="true" /> </property> <list name="orders" table="order2" cascade="all" lazy="false"> <key column="user_id_"> </key> <list-index column="order_index_"></list-index> <one-to-many class="com.order.bean.Order"/> </list> </class> </hibernate-mapping> |
Admin.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.order.bean.Admin" table="admin"> <id name="id" type="java.lang.Integer"> <column name="id_" /> <generator class="native" /> </id> <property name="username" type="java.lang.String"> <column name="username_" length="80" not-null="true" /> </property> <property name="password" type="java.lang.String"> <column name="password_" length="80" not-null="true" /> </property> <property name="type" type="java.lang.Integer"> <column name="type_" not-null="true" /> </property> </class> </hibernate-mapping> |
Item.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.order.bean.Item" table="item"> <id name="id" type="int"> <column name="id_"></column> <generator class="native"></generator> </id> <property name="itemName" type="string"> <column name="itemName_" length="50" not-null="true"></column> </property> <property name="itemPrice" type="double"> <column name="itemPrice_" not-null="true"></column> </property> <property name="itemIntroduction" type="string"> <column name="itemIntroduction_" not-null="true"></column> </property> <property name="itemNumber" type="int"> <column name="itemNumber_" not-null="true"></column> </property> <property name="itemType" type="int"> <column name="itemType_" not-null="true"></column> </property> <many-to-one name="order" class="com.order.bean.Order"> <column name="order_id_"></column> </many-to-one> </class> </hibernate-mapping> |
Menu.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.order.bean.Menu" table="menu"> <id name="id" type="int"> <column name="id_"></column> <generator class="native"></generator> </id> <property name="name" type="string"> <column name="name_" length="50" not-null="true"></column> </property> <property name="price" type="double"> <column name="price_" not-null="true"></column> </property> <property name="introduction" type="string"> <column name="introduction_" length="80" not-null="true"></column> </property> <property name="type" type="int"> <column name="type_" not-null="true"></column> </property> <property name="state" type="int"> <column name="state_" not-null="true"></column> </property> </class> </hibernate-mapping> |
Order.hbm.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.order.bean.Order" table="order2"> <id name="id" type="int"> <column name="id_"></column> <generator class="native"></generator> </id> <property name="phone" type="string"> <column name="phone_" length="50" not-null="true"></column> </property> <property name="address" type="string"> <column name="address_" length="50" not-null="true"></column> </property> <property name="barcode" type="string"> <column name="barcode_" length="50" not-null="true"></column> </property> <property name="total" type="double"> <column name="total_" not-null="true"></column> </property> <property name="state" type="int"> <column name="state_" not-null="true" default="1"></column> </property> <property name="date" type="java.util.Date"> <column name="date_" not-null="true"></column> </property> <many-to-one name="user" class="com.order.bean.User"> <column name="user_id_"></column> </many-to-one> <list name="items" cascade="all-delete-orphan" lazy="false" table="item"> <key column="order_id_"></key> <list-index column="item_index_"></list-index> <one-to-many class="com.order.bean.Item" /> </list> </class> </hibernate-mapping> |