⑵在订餐客户信息表中,包括的数据项:用户编号,用户名,密码,姓名,电话,身份证,注册时间等。 ⑶在菜品信息表中,包括的数据项:菜品编号,菜品名称,菜品价格,内容,类别,添加时间等,每道菜都有它的菜名、介绍、价格等信息,为了让菜品的这些信息在页面有个很好的呈现,我们把这些信息存入菜品信息表中进行维护。。 ⑷在定单列表中,包括的数据项:定单列表编号,用户名,菜品编号,下单时间等。 ⑸在购物车信息,包括的数据项:购物车信息唯一标识,食品id,订餐用户名,添加时间等。当顾客选购菜品放入购物车时,我们会把这些菜品的id、数量、价格记录存入订单关联表中,通过订单关联表中的信息算出会员将要支付的金额,再通过菜品id这个主健把相应的信息存入个人订单这张表中进行维护。 ⑹为了有效地管理菜品,在新增菜品时加了一个分类属性,在此需要建张分类表进行维护,系统总体功能图如图1所示。 网上订餐系统 前台 后台 用户管理 订单管理 菜单浏览 用户反馈 菜 肴 价 目 信 息 发 布 用户留言及售后服务 餐厅销售统计 图1 系统功能框图 2.3 系统流程设计 课程设计信息管理系统,包括用户注册、管理员登录、菜品查询、菜品详单等。任务执行的流程如图2所示。 欢迎下载 2
—
图2 系统流程图 结账 系统公告 加入购物数据库 数据库 订单查询 操作 页面 选购菜品搜索 浏览页面 用户注册 用户登录 管理员登录 进入系统主界面 用户注册 后台管理 注销登录 2.4 数据库设计 该系统是借助MySQL数据库对数据进行统一管理的。在网上订餐系统中需MySQL创建数据库“订餐管理系统”, MySQL数据库中数据的操作可以分为四种不同的类型,分别是添加、删除、查询和修改。该数据库包含的表有菜品信息表、管理员表、订单表等。 2.4.1菜品信息表 菜品信息表,记录系统中的菜品信息。把汉字转化为汉语拼音,作为字段名。把ID设为主键,且不为空,bianhao、mingcheng、leibie、tupian、jianjie、jiage、faburen、addtime与之相关联,如表1所示。 欢迎下载 3
—
表1菜品信息表 字段名 id bianhao mingcheng leibie tupian jianjie faburen 类型 int varchar varchar varchar varchar varchar varchar 长度 11 20 50 20 50 50 30 是否为主键 是否为空 是 否 否 否 否 否 否 否 是 是 是 是 是 是 说明 菜品编号 菜品编码 菜品名称 菜品类别 菜品图片 菜品简介 发布人 2.4.2 管理员信息表 管理员信息表,存储系统中的管理员信息。把汉字转化为汉语拼音,作为字段名。其中,ID设置为int型,并设为主键,且不能为空;username、pwd设置为varchar型,如表2所示。 表2 管理员信息表 字段名 Id username Pwd 类型 Int Varchar Varchar 长度 10 30 30 是否为主键 是 否 否 是否为空 否 是 是 说明 用户编号 用户姓名 用户密码 欢迎下载 4
—
2.4.3用户注册信息表 用户注册信息表,记录系统中的注册用户信息。把汉字转化为汉语拼音,作为字段名。把ID设为主键,且不为空,zhanghao、mima、ximgming、diqu、zhaopian、issh与之相关联。 表3 用户注册信息表 字段名 id Zhanghao mima Xingming Diqu Zhaopian Issh 类型 int varchar varchar varchar varchar varchar varchar 长度 11 30 20 30 50 50 10 是否为主键 是否为空 是 否 否 否 否 否 否 否 是 是 是 是 是 是 说明 编号 账号 密码 姓名 地区 照片 备注 2.5 主要功能 用struts框架中的异常处理机制,本系统自定义了异常类SystemException和异常处理类SystemExceptionHandler。在MessageResources.properties中定义需要在Dao中抛出异常时声明的内容。 在struts-config.xml中配置公共异常处理文件 — 图3 在struts-config.xml文件中的配置信息如下: — 图4 登录界面 功能描述:顾客登陆管理,包括登陆时管理员需要输入用户名、密码、验证码、也可已选择是否记录用户名和密码以便以后登录。如果管理员选择记住用户名和密码则下一次登陆的时候只需要输入验证码,即可直接登录。 (1) 登录页面控制模块Login相关代码如下: login.jsp: <%@ page language=\"java\" import=\"java.util.*,com.actions.*\" pageEncoding=\"gbk\"%> <%String path = request.getContextPath(); String basePath = request.getScheme() + \"://\" + request.getServerName() + \":\" + request.getServerPort() + path + \"/\"; %> <%@ taglib prefix=\"s\" uri=\"/struts-tags\"%> 7 — 8 — 用户可以通过订餐系统主页面进行订餐如图5所示。 图5 功能描述:顾客登陆管理,包括 (1) 登陆时可以以游客或者会员的两种方式进行订餐操作,如果是会员登陆,先前需要录入用户名、密码、验证码,以便系统确认登陆成功。 (2) 会员个人信息管理,会员可以修改个人资料(如:电话,地址等),也可以查看订餐信息,了解当前订餐的动态(详见会员登录流程图)。 (3) 选购美食,作为顾客,在挑选美食的过程中,可以直接将称心的美食选进购物车中也可通过一系列查询,进一步了解后,再选择美食(详见选购美食流程图)。 选购美食部分代码如下: ……//得到在Spring中动态注入的Service层对象 ……//得到日志对象log public ActionForward queryForAll(ActionMapping mapping, ActionForm form, String forward = \"first\"; if(request.getParameter(\"user\").equals(\"manager\")){ } 9 HttpServletRequest request, HttpServletResponse response) { forward = \"queryDishes\" ; 欢迎下载 — } Food food = new Food() ; List — 会将最后的传输到不同的页面中去。然后查询出所有美食的记录数,再对是否是第一次登录到此页面进行判断,以为,第一次登录时当前页数和每页显示行数是默认的,而此后登录到此页面时有可能发生改变,最后再用Spring中动态注入的服务层中食品类的对象调用查询食品信息的方法,再将结果通过request对象传输到对应的页面中去。 public String getFoodInfo(String src) { } //图片绝对路径 String picsrc = null; String foodInfo = null ; //只保留相对路径,将绝对路径去掉 String temp[] = src.split(\"/\"); for (int i = 0; i < temp.length; i++) { } Food fd = foodDAO.query(picsrc); foodInfo = fd.getFoodDescription() ; return foodInfo; //得到图片的相对路径 picsrc = temp[temp.length - 1]; 此方法要在jsp页面中有DWR的对象调用,其中得到的路径是图片在服务器上的绝对路径,首先用String类中的split方法将其截成数据库中所存入得图片路径形式,然后再作为查询条件在数据库中查询,查询出美食的信息。然后DWR对象会将查询出来的信息作为jsp页面中回调函数的参数传回页面端。 3.3 美食信息添加功能模块 欢迎下载 11 — 功能描述:对菜品信息进行维护,包括: ⑴添加菜品,添加菜品图品,价格,是否是推荐菜品等。 ⑵菜品过季下架,用于菜品原料缺少或菜品过季等情况,进行逻辑删除。 ⑶菜品的查询,可以按菜品的名称、价格、销售量、是否是推荐菜品进行查询,默认是推荐菜品查询。 ⑷修改维护菜品信息,主要针对菜品原料的价格更变菜品的价格及菜品是打折时的价格更变,如图6所示。 图6 美食添加中图片上传功能代码如下: /**图片上传**/ 欢迎下载 ……//定义局部变量 try { IPTimeStamp its = new IPTimeStamp(request.getRemoteAddr()) ; //自动为上传图片命名,以确定图片的唯一性,以防覆盖 foodPictureAddr = its.getIPTimeStampRand()+\".\"+its.getLastName(file.getFileName()) ; 12 — stream = file.getInputStream(); = filePath this.getServlet().getServletContext().getRealPath(\"/images/food\")+\"/\"+foodPictureAddr; bos = new FileOutputStream(filePath); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) { bos.write(buffer, 0, bytesRead); } }catch (Exception e) { e.printStackTrace() ; }finally{ } file.destroy(); try { bos.close(); stream.close(); } catch (IOException e) { e.printStackTrace(); } catch(Exception e){} /**图片上传结束**/ 首先,有系统自动未上传图片命名,防止覆盖,然后通过字符串拼接的方式作为图片的地址存入数据库(例如:图片名称叫aaa,扩展名为jpg,在存入数据库中的地址就是相对地址系统自动生成的名字.jpg),在通过输入输出流的方式将图片上传到服务器上。即由从form中得到的图片路径以流的方式服务器上的一本系统自动并命好的文件上,最后关闭输入流和输入流,并将文件损毁。 另附图片自动命名类的部分代码如下 //为了得到不重复的图片名称(首先用数字零给本机IP地址的点补位,然后再加上当前时间(精确到毫秒),最后再加上三个随机数) ……//定义局部变量 public String getIPTimeStampRand() { StringBuffer buf = new StringBuffer(); if (ip != null) { 欢迎下载 13 — } } String str[] = this.ip.split(\"\\\\.\"); for (int i = 0; i < str.length; i++) { } buf.append(this.addZero(str[i], 3)); buf.append(this.getTimeStamp()); Random rand = new Random(); for (int i = 0; i < 3; i++) { } return buf.toString() ; buf.append(rand.nextInt(10)) ; ip已经在实例化自动命名类对象是赋值,即是本机的ip地址,将ip地址通过“.”字符来分开有字符串数组接收,再将每部分未满三位的进行补零操作,再加上时间戳,最后加上三位随机数,再将StringBuffer转换成String对象最后得到的内容既是系统为图片自动赋好的名字。 另附美食类别处理代码如下: if((!attributeId.trim().equals(\"0\"))&&!(attributeId.trim().equals(\"\"))){ 的格式 attributeid = foodAttributeValue.changeAttributeId(foodAttributeId) ; food.setFoodTypeId(attributeId) ; }else{ //新类别 foodAttributeValue = foodService.queryFoodAttributeId() ; foodAttributeId = foodAttributeValue.getAttributeId() ; try { //调用bean中的changeAttributeId方法将foodAttributeId转换成foodattribute表中} catch (Exception e) { } // 超过3位,提示减少不必要的食品类型,或者联系hhq e.printStackTrace(); log.error(\"系统添加食品类别信息过多!hrow new SystemException(\"foodattributelargenum.error\欢迎下载 14 — } foodattribute = new FoodAttribute() ; foodattribute.setAttributeId(attributeid) ; foodattribute.setAttributeName(newAttributeName) ; //将新类别向属性表中插值 try { isAdd = foodService.addFoodAttribute(foodattribute) ; } catch (Exception e) { } if(isAdd==true){ } food.setFoodTypeId(attributeid) ; e.printStackTrace(); log.error(\"系统添加食品类别信息时错误!hrow new SystemException(\"foodattributeadd.error\基于美食的类别操作的可添加性,则需要判断是在文本框中填写的美食内容(即:新类别),还是在下拉菜单中选择的内容(即:老类别),如果是老类别则可以利用原有的类别编号直接填入数据库中。而如果是新类别则需要生成新的类别编号,再将类别编号填入到数据库中。 3.4订单查询 功能描述:对顾客的购物车所下的订单进行管理,包括: ⑴查看订单,可按订单号、用户姓名进行查询管理员可以查看到当前餐厅的订单,并可以进行打印订单以确认发货。 ⑵修改订单,管理员对不在自己店范围内的订单可进行手动或者可以在订单状态为等待中时为顾客修改菜品的数量及品种,若订单状态为以下单则不能为顾客修改。 ⑶打印订单,若打印订单表示以确认发货,并自动修改订单状态为已发送。 ⑷取消订单,若顾客不方便上网打电话要取消订餐的话,管理员查看订单状态若为已下单则不能为顾客取消订单,若订单状态在等待中,则可以为顾客取消订单,如图7所示。 欢迎下载 15 — 图7 订单信息查询页面 查询订单部分代码如下: WHERE )temp ( #currentPage# - 1 ) * #pageSize# ]]> 由于iBatis框架多持久层进行封装,所以SQL语句在写法上会有些不同,针对物理分页这一要求,采用由rownum来控制输出的列数,在查询结果上,也用到了oracle自己的函数to-char来对日期类型进行处理。 其中,在select标签中,id属性对应在DAO的实现类中对象smctemplate所调用的queryForList方法的第一个参数,借此找到此SQL,来进行查询操作。resultClass与parameterClass分别表示,结果类的类型和参数类的类型,其中还有标签是iBatis中使用rownum来进行分页操作所必须应用到的。 而如果在页面上点击“查看订单详情”则会弹出一个模态对话框,该对话框由两部分组成,上半部分是美食的信息,有美食名称、美食份数、美食单价、美食总价四个属性,而其中有“沿着此处剪开”的字样,下半部分则是顾客的信息有订单号、订单状态、收货人、地址、联系电话、总价、支付方式、订单时间、备注信息几项组成。 欢迎下载 17 — 4.设计体会 经过一段时间的设计和开发,网上订餐系统基本开发完毕。其功能基本符合大众需求,能够完成菜肴的更新,菜肴的查询,菜肴的下单,后台的管理等各种功能但是由于课程设计时间较短和本人水平所限,虽然谢老师给予了我很多的指导,但是该系统还有许多不尽如人意的地方,对于Java的框架技术我还需要深入的进行学习。如今信息化的普及,要想使该系统能在海量的网上订餐系统中脱颖而出,以我们的编写能力,及我们对需求的分析和了解以及业务上的熟练程度都显得远远的不够。还有一些后续工作需要完成,下一步的改进一定做到层次更清晰,功能划分更明确,以实现更好的扩展性和重用性。 欢迎下载 18 — 5.参考文献 [1] 严璋鹏.基于B-S的学生学籍管理系统的设计与实现[J].价值工程.2013.19:33-41 [2] 李刚. 轻量级J2EE企业应用实战—Struts+Spring+Hibernate整合开发[M] .北京:电子工业出版社, 2011.3:46-75 [3] 贾素玲,王强. JSP应用开发技术[M] .北京:清华大学出版社,2011.7:35-76 [4] 王海涛,贾宗璞.基于Struts和Hibernate的Web应用开发[J].计算机工程,2011, 37(9):113. [5] 沈应逵. Java Web数据库系统应用开发与实例M].北京:人民邮电出版社,2009.9:102-134. [6]胡涛涛. 基于MVC模式的课程管理系统的功能设计[J]. 山西煤炭管理干部学院学报,2013,04:140-142. [7]任广财. 基于JSP的高校学生工作管理系统的设计与开发[J]. 科技经济市场,2013,12:119-120. [8]施阳,张海燕,戴德伟. 基于JavaEE的毕业设计管理系统设计与实现[J]. 软件导刊,2015,02:86-88. [9]赵春生. 浅谈JavaEE程序设计课程教学改革[J]. 科教导刊(中旬刊),2014,08:119-120. [10] 刘晓华,张健,周慧贞.JSP应用开发详解(第三版) [M].北京:电子工业出版社, 2007.1 欢迎下载 19 — 6.附录: public class CommonServlet extends HttpServlet { //保存各页面Id对应的action类的对象 private Hashtable hPageHandler = new Hashtable(); //配置文件的存放位置 private JXPathContext configContext = null; public void init() { //取得配置文件,并获得其中的dom元素 String filePath = getInitParameter(\"configXML\"); String fileRealPath = getServletContext().getRealPath(filePath); //尝试建立配置文件的DOM try { org.jdom.input.SAXBuilder builder = new SAXBuilder(); org.jdom.Document pDoc = builder.build(fileRealPath ); configContext = JXPathContext.newContext(pDoc); GlobalObjectProvider.init( configContext ); } catch(Exception e) { System.out.println(\"Servlet初始化失败!\"); } //初始化共通类以获取页面信息 CommonConst.init(); } //每一种动作第一次执行的时候,初始化对应的类 public void doPost ( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { //设置提交表单的中文编码 request.setCharacterEncoding(\"GBK\"); HttpSession mySession = request.getSession(true); //得到用户输入信息 String sPageId = request.getParameter(\"pageId\"); 欢迎下载 20 — String sActionId = request.getParameter(\"actionId\"); if ( sPageId == null || sPageId.equals(\"\") || sActionId == null || sActionId.equals(\"\") ) { //非法进入页面,跳转到首页 mySession.invalidate(); response.sendRedirect(\"../login.jsp\"); return; } //如果非法进入页面(登录页面除外) if ( !sPageId.equals(\"S001\") && mySession.getAttribute(\"loginUser\") == null ) { //非法进入页面,跳转到首页 mySession.invalidate(); response.sendRedirect(\"../login.jsp\"); return; } try { //根据pageId获得处理对象,如果没有则创建一个对象 Object oActionObject = hPageHandler.get( sPageId ); if ( oActionObject == null ) { //根据配置文件创建一个新对象 String sClassName = (String)configContext.getValue( \"ch08-config/page[@id='\"+sPageId+\"']/@className\"); oActionObject = Class.forName( sClassName ).newInstance(); hPageHandler.put( sPageId, oActionObject); } //取得方法名 String sMethodName = (String)configContext.getValue( \"ch08-config/page[@id='\"+sPageId+\"']/action[@id='\"+sActionId+\"']/@methodName\"); //生成对应的参数,并调用对应对象的对应方法 //inputData是根据传入的参数做成的 Hashtable inputData = new Hashtable(); Enumeration params = request.getParameterNames(); while( params.hasMoreElements()) { String sParaName = (String)params.nextElement(); inputData.put( sParaName, request.getParameter(sParaName) ); } 欢迎下载 21 — //outputData是下一个页面的值域,在此只是被初始化 Hashtable outputData = new Hashtable(); //生成参数列表 Class[] paraType = { Class.forName(\"java.util.Hashtable\"), Class.forName(\"java.util.Hashtable\"), Class.forName(\"javax.servlet.http.HttpSession\") }; Object[] paraObj = { inputData, outputData, mySession }; //生成Method对象 Method invokeMethod = oActionObject.getClass().getMethod( sMethodName, paraType ); //调用方法 invokeMethod.invoke( oActionObject, paraObj ); //根据outputData的结果决定下一个页面 String sNextPageId = (String)outputData.get(\"pageId\"); String sRealPagePath = (String)configContext.getValue( \"ch08-config/page[@id='\"+sNextPageId+\"']/@path\"); //设置下一个页面的值域 mySession.setAttribute( sNextPageId, outputData ); response.sendRedirect( sRealPagePath ); return; } catch(Exception e) { //页面处理出错,跳转到错误处理页面 e.printStackTrace(); Hashtable outputData = new Hashtable(); outputData.put( \"exception\ //设置错误页面的值域 mySession.setAttribute( CommonConst.VIEWID_ERROR, outputData ); response.sendRedirect(\"../error.jsp\"); return; } } public void doGet ( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException { doPost( request, response ); } } login.jsp: 欢迎下载 22 — <%@ page language=\"java\" import=\"java.util.*,com.actions.*\" pageEncoding=\"gbk\"%> <%String path = request.getContextPath(); String basePath = request.getScheme() + \"://\" + request.getServerName() + \":\" + request.getServerPort() + path + \"/\"; %> <%@ taglib prefix=\"s\" uri=\"/struts-tags\"%> 因篇幅问题不能全部显示,请点此查看更多更全内容
订餐系统
订餐系统