作者主页:编程指南针
作者简介:Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师
主要内容:Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助
收藏点赞不迷路 关注作者有好处
文末获取源码
项目编号: BS-XX-171
前言:
快递栈管理系统提供了前台和后台两套系统,管理员可以通过后台管理系统的控制台查看全国快递分布、用户人数、快递员人数、总件数和待取件的可视化,同时管理快递的信息、快递员的信息、和用户的信息;快递员和用户可以通过前台系统分别进行快件的管理和体验。
该系统能够满足市场需求,对快递进行实现快递员对快件的管理以及用户取件的管理,根据当前的快递栈系统所存在的或多或少的问题,提出了更加完整和完善的管理系统方案。本系统从用的是B/S架构,此系统以Java、HTML、CSS、JavaScript作为基础的开发语言,后台使用SpringBoot框架、前台使用vue框架进行并结合三层架构进行开发。同时关于本系统的遍及性,前台系统开发成微信端小程序,极大程度上提高了该系统的扩展性以及用户使用方便性。
快递e栈允许用户在前端模仿小程序进行个人快递的历史查询和取件二维码的展示,快递员对用户的快件快速入库、出库等操作。解决了快件管理的很多不方便。主要完成以下几个方面的研究:
1.分析在J2EE应用程序开发过程中所采用的和B/S结构的优缺点,提出了基于J2EE的快递栈系统的基本实行方案;
2.对功能需求进行详细分析,并且也对非功能需求和系统运行环境进行简单分析,分析各个功能模块的设计和实现,分析快递栈程序对用户程序的处理流程和评判标准。
3.实现了用户管理、快递管理、快递员管理、登录注册、快递懒人排行榜功等功能。
一,项目简介
快递e栈管理系统,是一款高效、快捷、高质量的快递管理系统,是物流快递的一个重要组成部分。主要包含的功能模块:快递员管理、快递管理、用户管理、数据统计、停车位管理、短信验证登录注册、二维码取件、搜索功能等功能模块。本系统分为前台模仿微信小程序系统和pc端后台管理系统,后台基于springBoot、Vue、Axios、等技术,前台系统基HTML、ajax、阿里短信验证等技术,在系统的设计与开发过程中严格遵守软件工程的规范,运用软件设计模式,从而减少系统模块间的偶合,力求保障系统的稳定性、可重用性和可扩充性。
系统用例如图3-2,详细展示了该系统的各角色的用例情况,以及如图3-1详细展示了该系统的功能模块信息。
图3-1 功能模块图
图3-2 系统用例图
用户功能主要满足用户可以在微信端系统的用户体验,需要能够登录退出系统、快递单号搜索、扫描出库快递、查看懒人排行榜等功能,具体功能详细介绍如表3-1
所示:
表3-1 用户功能描述
功能名称 | 功能描述 |
短信验证登录注册 | 用户可以通过短信验证登录注册进入小程序 |
快递单号搜素 | 用户可以通过快递单号搜索快递详细信息 |
扫码取件 | 用户可以通过展示二维码扫码给快递员取件 |
历史快件详情 | 用户可以在我的快件中查看历史快递信息 |
退出登录 | 用户可以注销并退出登录账号 |
懒人排行榜 | 用户可以查看自己月、年和总快递数量排行 |
修改信息 | 用户可以在个人中心修改和补全信息 |
快递员功能主要满足快递员可以在微信端系统进行正常工作,将用户的快递进行出库和查询修改操作,具体功能详细介绍如表3-2所示:
表3-2 快递员功能描述
功能名称 | 功能描述 |
录入快递 | 快递员可以通过用户快递信息进行入库操作 |
扫码取件 | 快递员可以通过用户展示的二维码进行出库操作 |
历史快件查询 | 快递员可以通过手机号搜索用户历史快件信息 |
单号搜索 | 快递员可以在搜索框同时单号进行搜索快递信息 |
修改信息 | 快递员可以在个人中心修改和补全信息 |
退出登录 | 快递员可以注销并退出登录账号 |
短信验证登录注册 | 用户可以通过短信验证登录注册进入小程序 |
管理员功能主要满足管理员可以在后台管理系统对快递员、用户和快递进行管理,具体功能详细介绍如表3- 2所示:
表3-3 管理员功能描述
功能名称 | 功能描述 |
首页查看统计数据 | 可以查看用户、快递员、总快递、待取件的数量 |
快递员信息管理 | 管理员可以对快递员信息的增删改查进行操作 |
用户信息管理 | 管理员可以用户信息的增删改查进行操作 |
快递员信息管理 | 快递员可以在搜索框同时单号进行搜索快递信息 |
登录退出 | 账号密码登录和注销账号退出 |
针对本系统不同的角色对各个功能模块进行划分。快递栈系统的主功能模块分为用户管理、快递员管理和管理员管理模块。系统主要功能设计图如图4-2所示:
图3-3 系统功能结构图
2.1.1 用户模块
从系统的实用性和可推广性俩方面考虑,用户模块下分几个子模块,主要分为登录注册,个人中心,认证、懒人排行榜、我的快件、订单号搜索和退出登录等七个子模块。详细介绍如下:
- 登录注册子模块:用户通过手机号注册登录时,会对用户信息验证,已注册用户注册,提醒用户登录,未注册用户登录提醒用户注册,登录用户首先验证短信验证码输入是否正确,同时对该手机号判断是否是已经注册的账号,如果未注册则直接注册,反之进行判断该用户的权限是用户还是快递员,使之不同用户登陆进入前台系统时显示的界面不同。
- 个人中心子模块:用户可点击个人头像进入个人中心,查看修改个人信息,并完善个人信息。
- 订单号搜索子模块:所有用户可以通过主界面的订单搜索模块进行快递单号搜索信息。
- 历史订单子模块:快递员可以通过取件码或手机号码查询该用户的历史快递信息,用户则可以查看自己所有的历史取件和未取件的快递信息。
- 认证子模块:当新用户通过手机号注册快递栈系统后可以通过认证完善信息,方便快递员配送快递
- 懒人排行榜子模块:懒人排行榜功能是所有用户可以通过排行榜看到用户使用快递栈系统总快递数量、年快递数量、月快递数量排行,排名越靠前说明网上购物越多,故名懒人排行榜
- 退出登录子模块:用户点击个人头像,选择注销,即可退出登录。
2.1.2 快递员模块
从系统的实用性和可推广性俩方面考虑,快递员模块下分几个子模块,主要为快递助手和二维码扫描取件两个子模块。详细介绍如下:
- 快递助手子模块:快递助手是专门为快递员提供的一个功能,快递员可以手机登陆微信端系统进行录入入库的快递信息、扫描出库和历史查询用户快递的功能。
- 扫码取件子模块:用户可以通过个人快递的取件码让快递员进行扫码区间内出库。
2.1.3 管理员模块
从管理员对快递员和用户管理的需求出发,为管理员的管理划分为几个子模块,主要为用户管理、快递员管理、快递管理、后台登录和控制台数据可视化五个子模块,详细设计介绍如下:
- 用户管理子模块:主要是为管理员提供对用户进行增加、删除、修改和多条件模糊查询分页的操作。
- 快递员管理子模块:主要是为管理员提供对快递员进行增加、删除、修改和多条件模糊查询分页的操作。
- 快递管理子模块:主要是为管理员提供对快递进行增加、删除、修改和多条件模糊查询分页的操作。
- 后台登录子模块:主要是为管理员提供通过输入管理员权限的账号和密码并成功匹对登进后台系统的功能更。
- 控制台数据可视化子模块:主要是为管理员提供可视化数据进行分析。
二,环境介绍
语言环境:Java: jdk1.8
数据库:Mysql: mysql5.7
应用服务器:Tomcat: tomcat8.5.31
开发工具:IDEA或eclipse
后台开发技术:Springboot+Mybatis
前端开发技术:Vue+ElementUI
三,系统展示
3.1 后台管理系统展示
快递员管理模块
快递管理模块
用户管理模块
数据分析模块
快件实时分布展示
3.2 前端用户登陆
客户相关模块
个人中心
懒人排行
我的快递
快递查询
快递员登陆
快递助手
录入快递
扫描取货:快递员扫描客户展示的收货二维码,得到用户取件码输入后进行确认取货
查询客户取件记录
四,核心代码展示
package com.qst.express.controller;
import com.qst.commonUtils.result.R;
import com.qst.commonUtils.user.IpAddrUtils;
import com.qst.express.service.EadminService;
import com.qst.express.utils.UserUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
/**
* <p>
* 前端控制器
* </p>
*
* @author znz
* @since 2022-09-25
*/
@Api(description = "管理员模块")
@RestController
@RequestMapping("/express/eadmin")
@CrossOrigin
public class EadminController {
@Autowired
private EadminService eadminService;
@ApiOperation(value = "登录")
@PostMapping("/login")
public R login(@RequestBody(required = false) HashMap<String,String> admin, HttpServletRequest request) {
String username = admin.get("username");
String password = admin.get("password");
System.out.println(username + " ," + password);
boolean result = eadminService.login(username,password);
if (result) {
// 登录成功后操作
// 1.更新登录时间的 和 ip 的更新
// String ipAddr = IpAddrUtils.getIpAddr(request);
// eadminService.updateLogin(username,ipAddr);
//2. 存管理员手机号到session
String adminPhone = eadminService.getAdminPhone(username);
System.out.println("存入时管理员手机:"+adminPhone);
UserUtil.setAdminPhone(request.getSession(),adminPhone);
String adminPhone2 = UserUtil.getAdminPhone(request.getSession());
System.out.println("管理员手机号:"+adminPhone2);
//存管理员名字到session
request.getSession().setAttribute("adminName",username);
return R.ok().data("token","admin");
}else {
return R.error().message("登录失败");
}
}
@ApiOperation(value = "登录信息")
@RequestMapping("/info")
public R info() {
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
return R.ok().data("roles", "[admin]").data("name", "admin").data("avatar", "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
}
//登出
@ApiOperation("登出操作")
@PostMapping("/logout")
public R logout(){
return R.ok();
}
}
package com.qst.express.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qst.commonUtils.express.RandomUtil;
import com.qst.commonUtils.result.R;
import com.qst.express.entity.Express;
import com.qst.express.entity.User;
import com.qst.express.entity.vo.ExpressVo;
import com.qst.express.service.ExpressService;
import com.qst.express.utils.AddressUtil;
import com.qst.express.utils.SMSUtil;
import com.qst.express.utils.UserUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author znz
* @since 2022-09-25
*/
@Api(description = "快件管理")
@RestController
@RequestMapping("/e/express")
@CrossOrigin
public class ExpressController {
@Autowired
ExpressService expressService;
/**
* TODO 条件查询带分页
* @param page
* @param limit
* @return
*/
@ApiOperation(value = "快递分页查询")
@PostMapping("/pageTeacherCondition/{page}/{limit}")
public R pageTeacherCondition(@PathVariable("page") Integer page,
@PathVariable("limit") Integer limit,
@RequestBody(required = false) ExpressVo expressVo,HttpServletRequest request) {
String adminPhone = UserUtil.getAdminPhone(request.getSession());
System.out.println("管理员手机号:"+adminPhone);
System.out.println("管理员名字:"+request.getSession().getAttribute("adminName"));
// 获取用户手机号码
// User wxUser = UserUtil.getWxUser(request.getSession());
// String userphone = wxUser.getUphone();
// System.out.println("wx管理员手机号:"+userphone);
Page<Express> expressVoPage = new Page<>(page, limit);
IPage<Express> teacherIPage = expressService.pageTeacherCondition(expressVoPage, expressVo);
return R.ok().data("total", teacherIPage.getTotal()).data("rows", teacherIPage.getRecords());
}
/**
* 用于查询数据库中的全部快递(总数+新增),待取件快递(总数+新增)
* @return [{size:总数,day:新增},{size:待取件数,day:今日新增}]
*/
@ApiOperation(value = "快递控制台数据")
@GetMapping("/console")
public R console() {
List<Map<String, Integer>> data = expressService.console();
return R.ok().data("expressTotal", data);
}
/**
* 按月查询
* @return
*/
@ApiOperation(value = "按月查询")
@GetMapping("/console-column")
public R consoleColumn() {
List<Map<String, Integer>> data = expressService.consoleMonth();
return R.ok().data("expressMonth", data);
}
/**
* 添加快递
* @param express
* @return
*/
@ApiOperation(value = "添加快递")
@PostMapping("/addExpress")
public R addExpress(@RequestBody(required = false) Express express, HttpServletRequest request) {
System.out.println(express);
// 获取管理或快递员的手机号码
String adminPhone = UserUtil.getAdminPhone(request.getSession());
express.setSysphone(adminPhone);
System.out.println(adminPhone);
System.out.println(request.getSession().getAttribute("adminName"));
// 生成取件码
String code = RandomUtil.getCode();
express.setCode(code);
express.setIntime(new Date());
boolean save = expressService.save(express);
if (save) {
String address = AddressUtil.getAddress();
SMSUtil.send(express.getUserphone(),code,address,adminPhone);
return R.ok();
}else {
return R.error();
}
}
/**
* 删除快递
* @param expressId
* @return
*/
@ApiOperation(value = "删除快递")
@DeleteMapping("/deleteExpressId/{id}")
public R removeExpressId(@PathVariable(value = "id") String expressId){
boolean remove = expressService.removeById(Integer.parseInt(expressId));
if (remove) {
return R.ok();
}else {
return R.error();
}
}
/**
* 批量删除快递
* @param ids
* @return
*/
@ApiOperation(value = "批量删除快递")
@PostMapping("/deletes")
public R deltes(@RequestBody(required = false) Integer[] ids) {
System.out.println(ids);
boolean remove = false;
for (Integer id : ids) {
remove = expressService.removeById(id);
}
if (remove) {
return R.ok();
} else {
return R.error();
}
}
/**
* 查询快递信息同id
* @param expressId
* @return
*/
@ApiOperation(value = "查询快递信息同id")
@GetMapping("/getExpressInfo/{id}")
public R findExpressInfoById(@PathVariable(value = "id") String expressId){
Express express = expressService.getById(expressId);
if (express != null) {
return R.ok().data("express",express);
}else {
return R.error();
}
}
/**
* 更新快递信息
* @param express
* @return
*/
@ApiOperation(value = "更新快递信息")
@PutMapping("/updateExpressInfo")
public R updateExpressInfo(@RequestBody(required = false) Express express){
boolean update = expressService.updateById(express);
if (update) {
return R.ok();
}else {
return R.error();
}
}
}
package com.qst.express.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qst.commonUtils.result.R;
import com.qst.commonUtils.user.UserUtil;
import com.qst.express.entity.Courier;
import com.qst.express.entity.Express;
import com.qst.express.entity.User;
import com.qst.express.entity.vo.ExpressVo;
import com.qst.express.entity.vo.UserVo;
import com.qst.express.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @authorznz
* @since 2022-09-25
*/
@Api(description = "用户管理")
@RestController
@RequestMapping("/e/user")
@CrossOrigin
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/console")
public R console(HttpServletRequest request, HttpServletResponse response){
List<Map<String, Integer>> data = userService.console();
return R.ok().data("userConsole", data);
}
/**
* TODO 条件查询带分页
* @param page
* @param limit
* @return
*/
@ApiOperation(value = "用户分页查询")
@PostMapping("/pageUserCondition/{page}/{limit}")
public R pageUserCondition(@PathVariable("page") Integer page,
@PathVariable("limit") Integer limit,
@RequestBody(required = false) UserVo userVo) {
Page<User> userPage = new Page<>(page, limit);
IPage<User> teacherIPage = userService.pageTeacherCondition(userPage, userVo);
return R.ok().data("total", teacherIPage.getTotal()).data("rows", teacherIPage.getRecords());
}
/**
* 添加快递员
*
* @return
*/
@ApiOperation(value = "添加用户")
@PostMapping("/addUser")
public R addUser(@RequestBody(required = false) User user) {
user.setCreatetime(new Date());
boolean save = userService.save(user);
if (save) {
return R.ok();
} else {
return R.error();
}
}
/**
* 删除快递员
* @param userId
* @return
*/
@ApiOperation(value = "删除用户")
@DeleteMapping("/removeUser/{id}")
public R removeUser(@PathVariable(value = "id") String userId) {
boolean remove = userService.removeById(Integer.parseInt(userId));
if (remove) {
return R.ok();
} else {
return R.error();
}
}
/**
* 批量删除用户
* @param ids
* @return
*/
@ApiOperation(value = "批量删除用户")
@PostMapping("/deletes")
public R deltes(@RequestBody(required = false) Integer[] ids) {
System.out.println(ids);
boolean remove = false;
for (Integer id : ids) {
remove = userService.removeById(id);
}
if (remove) {
return R.ok();
} else {
return R.error();
}
}
/**
* 通过id查询快递员信息
* @param userId
* @return
*/
@ApiOperation(value = "通过id查询用户信息")
@GetMapping("/findUserById/{id}")
public R findUserById(@PathVariable(value = "id") String userId) {
User user = userService.getById(userId);
if (user != null) {
return R.ok().data("user", user);
} else {
return R.error();
}
}
/**
* 更新快递员信息
* @param user
* @return
*/
@ApiOperation(value = "更新用户信息")
@PutMapping("/updateUserById")
public R updateCourierById(@RequestBody(required = false) User user){
boolean update = userService.updateById(user);
if (update) {
return R.ok();
} else {
return R.error();
}
}
}
五,项目总结
项目的目标将本系统初步分为两个部分,面向用户和快递员的前台系统,面向管理的后台管理系统。前台系统为快递员提供了快件查询、快件入库、快件出库、快递签收、个人中心的服务,为用户提供了单号查询快件、个人中心、懒人排行榜的服务;后台系统为管理员提供了快递员信息管理、快件信息管理、用户信息管理、控制台可视化分析服务,分为以下几个功能模块:
(1)快递信息管理功能模块:管理员可以对快递的增加入库、删除出库、修改快件信息、查询快件信息进行管理。
(2)快递员信息管理功能模块:管理员通过后台系统可以录入快递员信息,从而赋予快递一些特权,管理用户快件的入库和出库、对快递员信息的修改、快递员的删除、快递员信息的查询。
(3)用户信息管理功能模块:管理员可以在后台增加新用户、修改用户信息、查询用户信息、注销用户信息的操作。
(4)控制台可视化功能模块:管理员可以在后台系统查看全国快件分布情况、用户注册总人数、快递栈库存快件总数、快递待取件数、快递日入库数量的信息。
(5)登录注册功能模块:使用短信注册技术进行注册登录,如果是第一次使用则为注册,反之登录,同时系统会通过手机号码进行判断该用户是为快递员还是用户,从而让不同角色用户进入前台系统能够使用的功能模块不一样。
(6)个人中心功能模块:因为使用的是手机短信登录注册,所以当用户登陆系统后需要在个人中心进行实名认证,修改个人信息。
(7)快递单号搜索查询功能模块:在前台系统,不同角色用户都可以通过该功能使用快递单号进行快递详细的查询。
(8)录入快递功能模块:快递员可以在前台系统将快递信息进行入库操作。
(9)取件出库功能模块:快递可以通过取件码或者通过微信对用户的取件码进行扫码出库。
(10)快递懒人排行榜功能模块:在前台系统中将所以用户的快递信息进行总排名、年排名、月排名的信息展示。