一,项目简介
目前从国内外的网约车市场来看,网约车模式具有较大的发展前景,不论是国外的优步,还是国内的滴滴打车,阳光出行等网约车企业。都在不断的拓展市场,壮大发展规模。虽然拼车模式发展较好,但是大多为面向社会开放,专为学校学生服务的少之又少。
在开学与放假当中,越来越多的同学选择了拼车去火车站、公交车站等出行方式,虽然方便但是存在多种弊端,一是通过QQ空间或群聊天发布信息,查阅繁琐且无法获取乘车关键信息。二是存在安全隐患,无法确定发起人与乘坐人是否为校内同学,学校不能第一时间确定学生的出行状态,仅能依靠在线填表的方式进行统计。
针对以上问题,在本系统中得到了很好的解决,基于Java平台的高效系统保证了网站的平稳运行与网络安全。集成百度地图SDK,发布拼车时可直接拉起地图选择位置。系统也内置了基于Socket全双工实时通讯,点击聊一聊即可快速发起在线聊天。同时电子签证功能与个人信息风险性评估功能的实现确保了同学们的乘车安全。
前台功能概述与分析:
⑴ 学生功能模块应该包含用户登录、注册、找回密码、查看个人信息、修改个人信息、修改密码、生成个人电子签证等基本功能模块。在实现基本功能模块的基础之上实现用户可以根据指定条件检索拼车信息、查看拼车详情、收藏本次拼车、取消收藏、申请加入本次拼车、查看我发布的拼车、同意/拒绝加入拼车申请、发起实时聊天、查看公告。
⑵ 用户需要提供自己的的姓名(注册后不可更改)学号密码与真实手机号完成注册,同样在密码找回时,也需要提供手机号接收验证码完成密码找回。
⑶ 用户可以修改自己的性别、生日、邮箱等基本信息,同时提供旧密码与新密码可完成密码修改操作。当用户完成所有信息填写时,即可生成自己的唯一电子签证。
⑷ 在发布拼车功能中,用户需要提供出发地、目的地、出发时间、需要几人参与拼车、是否有车、拼车说明等信息完成拼车发布。同时是否有车中提供三个选项(有车、无车、平台),其中选择平台将由司机端司机进行接单。
⑸ 用户可以根据拼车时的关键信息进行检索,快速定位到符合自己要求的拼车信息。
⑹ 用户收藏拼车后应可以在个人中心我的收藏快速找到该拼车,同时用户可以取消收藏本次拼车。
⑺ 用户找到指定拼车信息后,可以提交拼车申请,拼车申请提交以后,拼车发起人个人中心将提示有新的用户。拼车申请人可以选择同意或者拒绝,也可以选择与申请人进行在线聊天。
⑻ 拼车发起人具有修改本次拼车信息,删除本次拼车,处理拼车申请等基本操作权限。
⑼ 用户可以在个人中心查看消息提醒。消息提醒包含有新的拼车申请,新车申请被拒绝,已被移出本次拼车,本次拼车司机已接单,司机已退单等基本消息类型
⑾ 用户在登录后可以通过顶部公告栏获取最新的通知公告。
⑿ 个人中心页面包含与用户有关的所有操作,例如联系客服、退出登录等。
⒀ 司机功能模块包含登陆、注册、浏览学生订单、退单、修改密码等基本操作。
⒁ 司机注册需要提供姓名、性别、手机号、驾龄、车牌号、汽车座位数,汽车型号等基本信息。完成注册后,需要向管理员提供驾照,身份证等证件核对,完成后即可登录。否则司机无法登陆系统。
⒂ 司机登录后在主页即可浏览订单信息进行选择性接单(只显示平台订单,有车和无车类型不在此处显示),选择接单后填写预估价格即可完成接单。
⒃ 司机可在我的中心页面完成退单、修改密码、联系客服等操作。
后台功能概述与分析:
⑴ 网站信息浏览可以显示注册用户、发布拼车、活跃度指数等关键信息,包括显示可视化报表。
⑵ 拼车管理、司机管理、用户管理、公告管理可以对相关内容进行增删改查等基本操作。
⑶ 网站配置模块可由超级管理员进行网站相关配置,例如客服联系方式、修改管理员密码、对前台页面参数控制等。
⑷ 管理员管理模块儿可由超级管理员访问,包含对普通管理员的增加、修改、删除、权限分配等基本操作。
用例图可以作为需求分析的手段,它将从每个角色的角度出发去考虑问题,可以分析出系统大致功能,本系统用例图具体如下:
如图4-1所示,司机可以进行查看平台订单、接单/退单、修改密码等基本操作。但这些功能的使用基础是司机注册后已登录的前提下。
如图4-3所示,学生除了登录注册/密码找回/修改信息等基本功能外,还具有对拼车信息相关的基本操作权限(仅限于学生个人)。
如图所示,超级管理员可以对拼车、学生、司机、订单、网站信息等进行管理,同时也可以新增普通管理员并赋予管理员权限。
二,环境介绍
语言环境:Java: jdk1.8
数据库:Mysql: mysql5.7 Redis
应用服务器:Tomcat: tomcat8.5.31
开发工具:IDEA或eclipse
后台开发技术:Springboot+Mybatis
前端开发技术:Vue+Element
三,系统展示
登录:顶部为通用导航栏点击返回按钮即可回到主页,登录页面动画为gif动态图片,中间部分为账户密码输入框,底部为登录、注册、找回密码按钮。用户输入账号密码后即可完成登录,在登录成功时会弹出是否保存密码,用户点击保存密码后将数据写入到H5本地存储中,在下次进入登录页面时,会自动检测是否保存了账户与密码,若有保存记录,则取出数据自动填入到输入框中。若用户点击取消则会清除H5中保存的账号记录,下次进入时输入框均需要重新输入账号密码(图5-1)。
图5-1 用户登录 |
图5-2 密码找回 |
主页设计:主页顶部为当前功能页面标题栏,左侧按钮点击后可以跳转到用户登录界面,右侧按钮点击后悔跳转到拼车信息检索页面。主要区域为用户发起的拼车信息,此处拼车信息只显示状态为正常的拼车列表,状态为结束和暂停的拼车将不会被显示。在拼车列表中会显示出发地 - 目的地、是否有车、加入拼车说明、出发时间、当前需要多少人以及已经加入了多少人(图5-3)。
图5-3 主页面 |
图5-4 搜索页面 |
图5-5 拼车详情页 |
图5-6 发布拼车页 |
拼车详情页面设计:进入到拼车详情页会展示本次拼车相关信息,在本页中可以看到是由谁发起了拼车,并且点击聊天可以和拼车发起者进行在线聊天。同时在下方也会显示有哪些用户加入了本次拼车,在每位用户的名字下方会提示该用户是否具有电子签证,若未生成电子签证,则会进行风险提醒。点击聊天按钮也可以和同行用户进行在线聊天。在当前页面中可以进行收藏操作与申请加入拼车操作,若当前拼车已收藏,则收藏按钮将不可点击置为锁定状态并给出“已收藏”提示。当遇到一下情况时,申请加入按钮也会进入锁定状态:1.拼车发起人暂停了拼车、2.当前拼车已经满员、3.已经加入了本次拼车、4.该拼车是由自己发起的(图5-5)。
发布拼车页面设计:发布拼车需要输入必填信息,包括出发地、目的地、出发时间、是否有车、限制几人、拼车备注(可以在拼车备注中说明加入拼车的具体要求,以便同学在提交拼车申请时考虑自身情况)。出发地与目的地类似,可以在输入框中输入想要的地址,也可以点击右侧的定位图标。点击图标后会在下方弹出地址选择框,用户可以滚动选择后台管理员已设置好的地址。在选择出发地与目的地时,二者必须有一个是学校,手动输入地址后,都会自动将另一个地址置为学校,弹出菜单滚动选择地址后同样如此。选择出发时间时点击右侧按钮可弹出时间选择插件,可以滚动选择预计出发时间。是否有车选择为单选框,根据有车无车情况选择。限制拼车人数为步进器控件,最多可拼7人,最少1人。全部选择完成后输入拼车说明(拼车说明字数限制在100字以内)即可点击发起拼车,返回首页即可看到自己发布的拼车(图5-6)。
图5-7 好友列表页 |
图5-8 个人信息页 |
聊天页面设计:在聊天好友列表界面中,整体布局采用了类似微信聊天布局,列表头像处可以显示消息角标展示几条未读消息,右侧可以显示最后一次聊天的时间信息,居中部分为用户姓名显示,姓名下方为最后一条聊天消息。该页面消息接收为实时接收,每隔五秒会向后台获取一次未读消息记录并且同步到好友列表中。当收到未读消息时,时间最晚的消息将会最先显示,同时指定用户的好友列表位置将会置顶显示,这样的设计增强了用户在线聊天体验,使消息获取更加及时与方便(图5-7)。
点击好友列表指定好友即可跳转到在线聊天页面。聊天页面设计仍参考主流聊天软件对话页面,好友消息在左侧显示,自己的消息在右侧显示。气泡也用蓝色与白色加与区分以便获得更好的对话体验。在聊天对接上本系统采用的是Socket全双工通信,在页面无需刷新情况下即可接收服务端消息推送并且实时更新,经过测试,平均响应速度在毫秒级,较传统ajax轮询接收消息有较大的性能提升。另外,在消息发送与接收时,消息列表将会自动下拉,无需用户拖拽页面(图5-8)。
图5-9 修改个人信息页 |
图5-10 我的拼车页 |
个人中心页面设计:个人中心页面主体部分为两个独立面板,第一个面板当用户登陆时会显示用的头像、姓名、生日、学院等关键信息,若用户完成修改信息或上传头像等操作之后,返回个人信息页面即可看到信息已同步更新(更换头像后拼车列表处的他们正在拼区域展示头像也会实时更新)。第二个面板为功能选项面板,包含功能有:修改个人信息、查看我发起的拼车、查看我加入的拼车、我的收藏、分享本站、退出登录六大功能选项(图5-9)。
司机端设计与拼车页面大同小异,主颜色为蓝色,除基本对的登录注册修改密码之外,用户可以在接单大厅进行选择性接单。订单会提示距离出发还有多长时间,方便司机进行选择,司机确认订单后需要输入本次行程预估金额,点击确定后即可完接单。在我的订单页面中可查看已接订单,同时司机也可以取消该订单。
图5-11 司机端注册页 |
图5-12 司机接单页面 |
拼车管理页面设计:进入拼车管理页面以后会显示所有拼车列表,包含目的地、出发地、出发时间、人数等关键信息。点击编辑按钮可以对主要信息进行修改,包含前台无法修改的目的地、出发地、出发时间等关键信息,在输入目的地与出发地时会弹出地址提示可以直接选择,需要注意的是,修改拼车人数不能小于当前已参加人数。点击删除按钮会对管理员弹出删除提示,点击确定后将会删除本次拼车。也可以使用批量删除功能,管理员在拼车前选择需要删除的拼车进行打钩,点击批量删除按钮后会弹出删除提示,单击确定后即可删除选择的指定拼车。关于筛选操作,管理员可以根据主要信息来检索指定拼车,通过设定筛选数据,即可快速选出指定的拼车信息。分页控件:在列表底部设计了非常详细的分页控制,用户可以看到一共有多少条数据,多少页数据。通过点击指定页面按钮或者上下页标识,即可跳转到指定页面数。同时管理员可以选择每一页显示多少条数据(包括每页10条 - 50条不等),当选择完成后即可刷新当前数据页完成显示。细节设计:用户点击出发时间与发布时间表头,即可完成对数据的基于时间项排序,包含正序、倒序、恢复初始顺序。点击是否有车表头下拉,即可选择需要展示的关键数据,例如勾选有车并点击筛选,即可显示所有有车的拼车数据。拼车状态同样也适用于此筛选操作。结合分页控件,可以做到对数据精确管理(图5-13)。
司机管理页面设计:除基本控件外,列表会显示姓名、驾龄、车型、车牌号、座位数、手机号、注册是否通过等关键信息。也可以进行司机添加、删除司机、按姓名模糊匹配司机等操作。当司机注册完成时,客服可根据司机提供证件的准确性进行注册通过与拒绝(点击审核列表可以进行“已通过”、“未通过”分类快速筛选)。
图5-15 公告管理页面
公告管理页面设计:除基本控件外,列表会显示公告标题、开始时间、结束时间、发布者或组织方、当期状态等关键信息。点击新增公告或者编辑公告会弹出全屏弹窗,管理员可以在输入框内使用富文本编辑器进行公告编辑(支持富文本样式调整操作)。下方可以选择公告时间范围和填写发布者或者组织,发布时间范围是指当前日期在指定时间内时,公告自动显示(图5-15与图5-16)。
后台首页数据展示:本页面顶部四个部分为拼车发布数量统计、注册用户统计、注册司机统计、用户七日活跃度统计,其中七日活跃度是指七天内用户收藏、申请加入拼车、在线聊天等操作的活跃程度。在中间部分采用了Charts插件构建可视化报表,报表1展示了用户近七日发布拼车的数量统计(统计图),报表2展示了用户七日活跃的动态趋势(曲线图),两个报表可以帮助管理员很好的分析网站目前的使用状况,根据出行流量方便管理员作出相应调整。底部为Jvm占用内存与系统占用内存指示,若内存指示条为红色则说明用户较多应考虑升级硬件或限流访问。下方会显示程序运行开始时间与当前运行系统(图5-17)。
订单管理页面设计:除基本控件外,列表会显示拼车发起者学号、出发地、目的地、出发时间、司机、车牌号、联系方式、拼车状态、预估价格等关键信息。同时管理员可以删除指定订单。
网站配置页面设计:只有超级管理员才能访问此页面,该页面可以对网站的基本配置信息进行管理。这些配置包括地址选择固定点设置、百度地图缩放级别控制(数字越大缩放级别越高)、百度地图初始中心区域设置(用户搜索地址时会以该区域为中心向外辐射搜索)、学生端客服(在司机端点击联系客服时会弹出此联系方式)、司机端客服(在司机端点击客服图标时会弹出此联系方式)。右侧为密码修改操作,root超级管理员可以在此处修改密码。
管理员管理页面设计:只有超级管理员才能访问此页面,页面设计上采用的是独立板块,每个管理员独占一个板块,板块内的开关开启代表着该管理员获得了指定模块的对应管理权限。在此页面中可以新增、删除管理员,为管理员分配对应管理权限。在输入账号密码新增管理员之后会弹出权限分配提示,超级管理员可以开启指定管理模块开关,配置完成后点击保存即可。若需修改密码,需要将该管理员删除重新添加并重新分配权限(图5-17)。
四,核心代码展示
package com.xsry2018.car.controller; import com.xsry2018.car.messageEnum.MessageReminderStructure; import com.xsry2018.car.messageEnum.MsgFlag; import com.xsry2018.car.utils.MessagePushUtil; import com.xsry2018.car.utils.ResponseStatus; import com.xsry2018.car.entity.*; import com.xsry2018.car.service.CarPoolService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import javax.servlet.http.HttpSession; import java.util.Map; @Controller @RequestMapping("/CarPool") @ResponseBody public class CarPoolController { @Resource private CarPoolService carPoolService; @Resource private MessagePushUtil messagePushUtil; // 获取所有拼车信息 @GetMapping("/getCarPoolAll.do") public Map<String, Object> getCarPoolAll(Integer page, Integer size, HttpSession session) { if(null == page) page = 1; if(null == size) size = 10; String sno = (String) session.getAttribute("sno"); if (null != sno && !("".equals(sno))) { // 如果用户登录了,那么就使用这个接口 return ResponseStatus.getStatusEntity(200, carPoolService.selectCarPoolAndCollection(page, size, sno)); } // 没有登陆还是走普通接口 return ResponseStatus.getStatusEntity(200, carPoolService.findCarPoolList(page, size)); } // 获取指定条件的拼车信息 @PostMapping("/getCarPoolByCondition.do") public Map<String, Object> getCarPoolByCondition(Carpool carpool, Integer page, Integer size, HttpSession session) { if(null == page) page = 1; if(null == size) size = 10; String sno = (String) session.getAttribute("sno"); if (null != sno && !("".equals(sno))) { // 如果用户登录了,那么就使用这个接口 return ResponseStatus.getStatusEntity(200, carPoolService.selectCarPoolAndCollectionByCondition(carpool, sno, page, size)); } // 时间范围的结束时间传给releaseTime return ResponseStatus.getStatusEntity(200, carPoolService.findCarPoolByCondition(carpool, page, size)); } // 获取指定拼车信息详情 @GetMapping("/getCarPoolInfo.do") public Map<String, Object> getCarPoolInfo(String id, HttpSession session) { String sno = (String) session.getAttribute("sno"); if (null != sno && !("".equals(sno))) { // 如果用户登录了,那么就使用这个接口 return ResponseStatus.getStatusEntity(200, carPoolService.getCarPoolCollectionInfo(id, sno)); } return ResponseStatus.getStatusEntity(200, carPoolService.getCarPoolInfo(id)); } // 发布拼车信息 @PostMapping("/releaseCarPool.do") public Map<String, Object> releaseCarPool(Carpool carpool, HttpSession session) { System.out.println(carpool); carpool.setReleaseSno((String) session.getAttribute("sno")); return ResponseStatus.getStatusEntity(200, carPoolService.ReleaseCarPool(carpool)); } // 提交拼车申请 @PostMapping("/addCarPool.do") public Map<String, Object> addCarPool(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); // 提交申请之前先判断,只有当被拒绝了才能重复提交 Apply apply = carPoolService.adoptSubmitted(carPoolId, sno); if(apply != null) { return ResponseStatus.getStatus(100, "申请已经提交过了,请勿重复申请!"); } int n = carPoolService.addCarPool(sno, carPoolId); if (n > 0) { return ResponseStatus.getStatus(200, "申请提交成功!"); } else { return ResponseStatus.getStatus(100, "申请提交失败,请重试!"); } } // 返回我发布的指定ID拼车与拼车申请 @PostMapping("/getMyCarPoolById.do") public Map<String, Object> getMyCarPoolById(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); CarpoolApply carpoolApply = carPoolService.getMyCarPoolById(sno, carPoolId); ApplyStudent[] apply = carPoolService.getApplyId(sno, String.valueOf(carpoolApply.getId())); carpoolApply.setApplyStudents(apply); return ResponseStatus.getStatusEntity(200, carpoolApply); } // 返回我发布的所有拼车与所有拼车申请 @PostMapping("/getMyCarPool.do") public Map<String, Object> getMyCarPool(HttpSession session) { String sno = (String) session.getAttribute("sno"); CarpoolApply[] carpoolApplies = carPoolService.getMyCarPool(sno); int i; for(i = 0; i < carpoolApplies.length; i++) { ApplyStudent[] apply = carPoolService.getApplyId(sno, String.valueOf(carpoolApplies[i].getId())); carpoolApplies[i].setApplyStudents(apply); } return ResponseStatus.getStatusEntity(200, carpoolApplies); } // 修改我的拼车信息 @PostMapping("/modifyMyCarPool.do") public Map<String, Object> modifyMyCarPool(Carpool carpool, HttpSession session) { String sno = (String) session.getAttribute("sno"); carpool.setReleaseSno(sno); int n = carPoolService.modifyMyCarPool(carpool); if(!("P".equals(carpool.getHaveCar()))) { int c = carPoolService.deleteOrder(String.valueOf(carpool.getId())); // 状态修改删除对应的平台订单 } if(n > 0) { Carpool carPool = carPoolService.getCarPoolInfo(String.valueOf(carpool.getId())); messagePushUtil.pushMsg(carPool.getPartakeUser(), MessageReminderStructure.Structure(MsgFlag.CarPoolChange, carPool)); return ResponseStatus.getStatus(200, "操作成功!"); } else { return ResponseStatus.getStatus(100, "操作失败,修改未生效!"); } } // 获取所有指定拼车信息Id申请 @PostMapping("/getCarPoolAdd.do") public Map<String, Object> getCarPoolAdd(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); Apply[] applies = carPoolService.getCarPoolAdd(sno); return ResponseStatus.getStatusEntity(200, applies); } // 查看我加入的拼车 @PostMapping("/selectMyCarPool.do") public Map<String, Object> selectMyCarPool(HttpSession session) { String sno = (String) session.getAttribute("sno"); Carpool[] carpools = carPoolService.selectMyCarPool(sno); return ResponseStatus.getStatusEntity(200, carpools); } // 同意或拒绝拼车申请 @PostMapping("/adoptApply.do") public Map<String, Object> adoptApply(String status, String id, String carPoolId, String sno) { int n = carPoolService.adoptApply(status, id); if (n > 0) { // 如果同意了加入,那么就更新拼车信息表 if("1".equals(status)) { int t = carPoolService.updateCarPoolPeople(sno, carPoolId); if(t > 0) { messagePushUtil.pushMsg(sno, MessageReminderStructure.Structure(MsgFlag.ApplyAgree, carPoolService.getCarPoolInfo(carPoolId))); return ResponseStatus.getStatus(200, "操作成功!"); } else if(t == -2) { return ResponseStatus.getStatus(100, "您的拼车同行人员已经满啦~"); } else { return ResponseStatus.getStatus(100, "操作失败,人员信息未能正确写入!"); } } else { messagePushUtil.pushMsg(sno, MessageReminderStructure.Structure(MsgFlag.ApplyRefuse, carPoolService.getCarPoolInfo(carPoolId))); return ResponseStatus.getStatus(200, "已拒绝该用户的拼车申请"); } } else { return ResponseStatus.getStatus(100, "修改申请失败,请重试!"); } } // 移除指定拼车信息的中的用户,同时将他的申请置为不通过状态 @PostMapping("/dropCarPoolPeople.do") public Map<String, Object> dropCarPoolPeople(String sno, String carPoolId, HttpSession session) { // 没有传递过来sno,说明是用户自己退出了拼车 int flag = 0; if(null == sno || "".equals(sno)) { flag = 1; // 是用户自己退出了拼车 sno = (String) session.getAttribute("sno"); } int n = carPoolService.dropCarPoolPeople(sno, carPoolId); if (n > 0) { Carpool carpool = carPoolService.getCarPoolInfo(carPoolId); carpool.setId(flag); // 把flag放入id判断 // 如果是自己退出的就把拼车发起者的学号推上去 messagePushUtil.pushMsg(flag == 0 ? sno : carpool.getReleaseSno(), MessageReminderStructure.Structure(MsgFlag.CarPoolDelete, carpool)); int t = carPoolService.adoptRefuseAll(sno, carPoolId); if(t > 0) return ResponseStatus.getStatus(200, "操作成功!"); else return ResponseStatus.getStatus(100, "操作失败,申请列表未能正确移除!"); } else { return ResponseStatus.getStatus(100, "拼车人员信息移除失败!"); } } // 修改我发布的拼车状态 @PostMapping("/updateCarPoolStatus.do") public Map<String, Object> updateCarPoolStatus(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); int n = carPoolService.updateCarPoolStatus(carPoolId, sno); if (n > 0) { return ResponseStatus.getStatus(200, "拼车状态修改成功!"); } else { return ResponseStatus.getStatus(100, "拼车状态修改失败,请重试!"); } } // 删除我发布的拼车 @PostMapping("/deleteMyCarPool.do") public Map<String, Object> deleteMyCarPool(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); Carpool carPool = carPoolService.getCarPoolInfo(carPoolId); int n = carPoolService.deleteMyCarPool(carPoolId, sno); if (n > 0) { messagePushUtil.pushMsg(carPool.getPartakeUser(), MessageReminderStructure.Structure(MsgFlag.CarPoolDissolution, carPool)); return ResponseStatus.getStatus(200, "拼车删除成功!"); } else { return ResponseStatus.getStatus(100, "拼车删除失败,请重试!"); } } // 收藏指定的拼车信息 @PostMapping("/collectionCarPool.do") public Map<String, Object> collectionCarPool(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); Collection collection = carPoolService.checkCollection(sno, carPoolId); if(collection != null) { return ResponseStatus.getStatus(100, "您已经收藏过了,请前往我的收藏查看"); } int n = carPoolService.collectionCarPool(sno, carPoolId); if (n > 0) { return ResponseStatus.getStatus(200, "拼车信息收藏成功!"); } else { return ResponseStatus.getStatus(100, "信息收藏失败,请重试!"); } } // 取消收藏指定的拼车信息 @PostMapping("/deleteCollectionCarPool.do") public Map<String, Object> deleteCollectionCarPool(String carPoolId, HttpSession session) { String sno = (String) session.getAttribute("sno"); int n = carPoolService.deleteCollectionCarPool(sno, carPoolId); if (n > 0) { return ResponseStatus.getStatus(200, "拼车信息取消收藏成功!"); } else { return ResponseStatus.getStatus(100, "信息收藏取消失败,请重试!"); } } // 查看自己的拼车收藏 @PostMapping("/skimCollectionAll.do") public Map<String, Object> skimCollectionAll(HttpSession session) { String sno = (String) session.getAttribute("sno"); Carpool[] carpools = carPoolService.skimCollectionAll(sno); return ResponseStatus.getStatusEntity(200, carpools); } // 查看指定拼车的接单司机 @PostMapping("/DriverByCarPool.do") public Map<String, Object> DriverByCarPool(String carpoolId) { return ResponseStatus.getStatusEntity(200, carPoolService.DriverByOrder(carpoolId)); } }
package com.xsry2018.car.controller; import com.xsry2018.car.entity.Login; import com.xsry2018.car.messageEnum.MessageReminderStructure; import com.xsry2018.car.messageEnum.MsgFlag; import com.xsry2018.car.service.CarPoolService; import com.xsry2018.car.utils.MD5Util; import com.xsry2018.car.utils.MessagePushUtil; import com.xsry2018.car.utils.RedisUtil; import com.xsry2018.car.utils.ResponseStatus; import com.xsry2018.car.entity.Carpool; import com.xsry2018.car.entity.Driver; import com.xsry2018.car.entity.DriverOrder; import com.xsry2018.car.service.DriverOrderService; import com.xsry2018.car.service.DriverService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import javax.servlet.http.HttpSession; import java.util.Map; @Controller @ResponseBody @RequestMapping("/Driver") public class DriverController { @Resource private DriverService driverService; @Resource private DriverOrderService driverOrderService; @Resource private CarPoolService carPoolService; @Resource private MessagePushUtil messagePushUtil; @Resource RedisUtil redisUtil; @PostMapping("/login.do") public Map<String, Object> StudentLogin(String phone, String password, HttpSession session) { if(phone == null || password == null || "".equals(phone) || "".equals(password)) { return ResponseStatus.getStatus(100, "账号或密码不能为空!"); } String md_Pass = MD5Util.stringMD5(password); Driver login = driverService.driverLogin(phone, md_Pass); if (login != null && !("".equals(login.getName()))) { if("false".equals(login.getStates())) { return ResponseStatus.getStatus(100, "您的账号还未通过审核,请联系管理员!"); } // 司机登录成功并且已经通过审核 session.setAttribute("driver", login.getId()); return ResponseStatus.getStatus(200, "登录成功!"); } else { return ResponseStatus.getStatus(100, "登陆失败,账号或密码不正确!"); } } @PostMapping("/register.do") public Map<String, Object> register(Driver driver, HttpSession session) { Driver Is = driverService.driverIsRegister(driver.getPhone(), driver.getName()); System.out.println(driver); if (null != Is) { return ResponseStatus.getStatus(100, "注册失败,该用户已经注册过了"); } driver.setPassword(MD5Util.stringMD5(driver.getPassword())); //密码加密 driver.setStates("false"); // 先置为未通过状态 int n = driverService.insertDriver(driver); if (n > 0) { //session.setAttribute("driver", driver.getId()); // 注册不能直接登录,还需要管理员审核司机资质 return ResponseStatus.getStatusEntity(200, "注册成功"); } else { return ResponseStatus.getStatusEntity(200, "注册失败!"); } } // 获取所有拼车订单 @PostMapping("/getOrder.do") public Map<String, Object> getCarPoolAll(Integer page, Integer size) { if(null == page) page = 1; if(null == size) size = 10; return ResponseStatus.getStatusEntity(200, driverOrderService.selectCarPoolByHaveCar(page, size)); } // 获取指定条件的拼车信息 @PostMapping("/getOrderByCondition.do") public Map<String, Object> getCarPoolByCondition(Carpool carpool, Integer page, Integer size) { if(null == page) page = 1; if(null == size) size = 10; // 时间范围的结束时间传给releaseTime return ResponseStatus.getStatusEntity(200, driverOrderService.selectCarPoolByConditionOnDriver(page, size, carpool)); } @PostMapping("/agreeOrder.do") public Map<String, Object> agreeOrder(HttpSession session, String carpool, String price) { DriverOrder tmp = driverOrderService.IsOrder(String.valueOf(session.getAttribute("driver")), carpool); if(null != tmp) { return ResponseStatus.getStatus(100, "请勿重复接单,请在我的订单查看"); } DriverOrder driverOrder = new DriverOrder(); driverOrder.setDriver(String.valueOf(session.getAttribute("driver"))); driverOrder.setCarpool(carpool); driverOrder.setPrice(price); int n = driverOrderService.agreeOrder(driverOrder); if(n > 0) { Carpool carInfo = carPoolService.getCarPoolInfo(carpool); messagePushUtil.pushMsg(carInfo.getReleaseSno(), MessageReminderStructure.Structure(MsgFlag.AgreeOrder, carInfo)); return ResponseStatus.getStatus(200, "订单处理成功,请在个人中心查看"); } else { return ResponseStatus.getStatus(100, "订单处理失败,请重试...."); } } // 获取司机个人所有的订单 @PostMapping("/getMyOrder.do") public Map<String, Object> getMyOrder(HttpSession session) { String id = String.valueOf(session.getAttribute("driver")); Carpool[] carpools = driverOrderService.selectDriverOrderByDriver(id); return ResponseStatus.getStatusEntity(200, carpools); } // 司机取消订单 @PostMapping("/deleteOrder.do") public Map<String, Object> deleteOrder(String carpoolId, HttpSession session) { String driverId = String.valueOf(session.getAttribute("driver")); int n = driverOrderService.deleteOrderByStudent(driverId, carpoolId); if(n > 0) { Carpool carInfo = carPoolService.getCarPoolInfo(carpoolId); messagePushUtil.pushMsg(carInfo.getReleaseSno(), MessageReminderStructure.Structure(MsgFlag.QuitOrder, carInfo)); return ResponseStatus.getStatus(200, "该订单取消成功"); } else { return ResponseStatus.getStatus(100, "订单取消失败,请重试...."); } } @PostMapping("/changePassword.do") public Map<String, Object> DriverAdd(String phone, String oldPass, String newPass, HttpSession session) { String id = String.valueOf(session.getAttribute("driver")); Driver login = driverService.driverLogin(phone, MD5Util.stringMD5(oldPass)); if (login != null) { newPass = MD5Util.stringMD5(newPass); if (driverService.changePassword(newPass, id) > 0) { session.invalidate(); return ResponseStatus.getStatus(200, "密码修改成功!"); } else { return ResponseStatus.getStatus(100, "密码修改失败"); } } else { return ResponseStatus.getStatus(100, "手机号或旧密码输入错误!"); } } @PostMapping("/all.do") public Map<String, Object> DriverList() { Object map = driverService.selectDrivers(); if(redisUtil.hasKey("driver")) { Object s = redisUtil.get("driver"); return ResponseStatus.getStatusEntity(1000, s); // 返回缓存 } else { redisUtil.set("driver", map, 20); } return ResponseStatus.getStatusEntity(200, map); } @PostMapping("/name.do") public Map<String, Object> DriverByName(String name) { return ResponseStatus.getStatusEntity(200, driverService.selectDriverByName(name)); } @PostMapping("/id.do") public Map<String, Object> DriverById(String id) { return ResponseStatus.getStatusEntity(200, driverService.selectDriverById(id)); } @PostMapping("/add.do") public Map<String, Object> DriverAdd(Driver driver) { if (driverService.insertDriver(driver) > 0) { return ResponseStatus.getStatus(200, "新增司机成功"); } else { return ResponseStatus.getStatus(100, "新增司机失败"); } } @PostMapping("/update.do") public Map<String, Object> DriverUpdate(Driver driver) { if (driverService.updateDriverInfo(driver) > 0) { return ResponseStatus.getStatus(200, "更新司机信息成功"); } else { return ResponseStatus.getStatus(100, "更新司机信息失败"); } } @PostMapping("/delete.do") public Map<String, Object> DriverDelete(String id) { if (driverService.deleteDriver(id) > 0) { return ResponseStatus.getStatus(200, "删除司机信息成功"); } else { return ResponseStatus.getStatus(100, "删除司机信息失败"); } } }
五,项目总结
首先用户进入用户/司机/管理员登录页面进行登录,系统收到登录请求后会进行身份验证并进行相关页面跳转。若为司机用户,则进入到司机用户操作模块。若为学生用户则进入到拼车系统首页。当检测为管理账号时,则进行管理员类型判断,若为普通管理员可以进行指定权限模块管理,若为超级管理员则可以管理网站全部内容。
系统整体架构主要分为五层,分别为视图层、交互层、业务层、事务层、持久层,运行环境基于阿里云OSS、Tomcat、Windows 10操作系统。