前言
全部源代码地址:传送门
文章内容有点长,建议打开右侧目录导航栏查看。
**这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间,做几个变体系统。**
闲的无聊,把大学时候做的一个系统进行了重构。将项目拆分成完全前后端分离的形式。客户端采用一套、商家端采用一套。后端只负责接口数据的处理(当然也可以只用一套)。对其中的一些页面进行了重新组织和美化。个人信息管理和后台商品信息添加、公告发布等模块做的比较好看一点。我直接仿照CSDN的个人信息管理界面进行的设计,包括头像的上修改。还有商品信息的展示,然后点击某一个商品进行商品详情的查看。公告的上传等等。使用到蛮多新的小技术。说实话,我还是不太满意,vue中的大部分代码有重复的,好想给他全部改成组件的形式。但是由于工作忙,现就这样了。
资料(源代码)
部分源代码在博客的最后给出
把一个系统拆分成了几个练习使用。我还可以进一步将其改造为分布式微服务系统。其实不难。有时间在改造一下。有需要源码的可以加我联系方式,博客最下方有我的联系方式
技术栈
前端主要使用:Vue框架、组件使用ElementUI
后端主要使用:SpringBoot框架、Mybatis-plus、Redis等。
提示:主要说大的方面,小的技术点不在赘述
功能划分
1.1 客户端
客户端主要实现的功能划分
1.2 管理员
管理员方面主要负责的功能划分
顾客+游客(页面效果展示)
游客可以免登录浏览商品信息,公告信息;但是不能查看个人信息,订单、购物车等信息。等用户注册登录系统后。这些信息可以看到
一、个人信息
1.1 信息展示
1.2 修改头像
1.3 修改信息
直接在个人资料修改用户信息,点击保存就行了。还可以进行模拟充值
1.4 充值
1.5 修改密码
1.6 修改手机号
邮箱和手机号采用数据脱敏的形式,隐藏部分数据。这里修改手机号和邮箱类似,这里使用redis模拟发送验证码,同时保留三分钟的过期时间。在redis中很容易实现。还可以通过接入支付宝,购买他的那个验证码接口次数。可以实现真正的发送验证码到手机。我博客也有写过。这里不在赘述。
这里的redis我是直接装在了虚拟机中,采用docker安装redis是真的很方便。
1.7 修改邮箱
同修改手机号
二、 商品首页
1.1 首页
首页采用轮播图的形式,这个图片是我随机找的。可以换成校园二手商城类似的。然后商品展示不同的分类对应不同的商品。
1.2 商品分类
这里的分类数据我使用的同一个分类下的数据,这个只需要插入一些其它的测试数据就行了。大致思想就是,sql语句查询携带分类信息。查询的数据在对应的内容区域遍历出来。
1.3 商品详情页面
这里的详情就是在首页通过点击某一个商品,然后跳转到新的页面。这个新页面根据跳转商品id查询数据库,然后展示出来。这里可以进行购买,或者进行加入购物车等操作。
二、 购物车
1.1 查看购物车商品
购物车中的商品进行购买后,会自动删除在购物车中保留的商品信息。你也可以选择不删除,目前是只能进行单个商品的结算。有时间做一下一个订单进行多个商品的结算
1.2 购买
购买的时候,会出现收获地址。和商品的一信息。
1.3 删除购物车商品
三、 订单
1.1 查看订单
1.2 查看订单状态
在进行付款后,可以查看订单的信息状态。这里提示,订单状态使用int类型的数字替代,展示到前台的时候替换成对应的文字就可以
四、 公告
公告这里点击左侧的公告列表,右侧的内容会替换对应公告内容。
五、登录(顾客)
说实话、这个登录页面有点丑。但是我不想换了。我还有其它不同的登录页面。懒得换了
六、注册页面
管理员(页面效果展示)
提示:后台管理,基本上就是一些表格。增删改查
一、查看数据
这个就是用到了echart,我也写过怎样使用。这个数据可以替换来自数据库中实际的数据
二、管理用户信息
1.1 查看用户信息
1.2 修改用户信息
一般来说是不允许修改的。这里为了练习使用。就修改吧。实在不想修改,就把操作中的修改按钮屏蔽掉。
1.3 删除用户信息
1.4 添加用户信息
按照常理,这里是不应该有的这个添加用户操作。为了练习弹窗的功能。就写出来了。你也可以屏蔽掉
三、商品种类
这里新添加相同的商品种类,会提示错误信息。不能重复添加相同商品种类。不在演示。
1.1 添加商品种类
1.2 修改商品信息
1.3 删除商品信息
二次提示删除操作
四、商品详情
1.1 查看商品详情
对应商品图片浏览
1.2 添加商品
这里的商品图片上传,是和表格数据一块提交到后台保存的数据库的。大致流程,首先点击图片上传,选择图片。然后先发一个接口到后端。将图片复制到其它位置。返回前端保存该图片的位置。然后再次将表格内容和图片地址一块发送给后端。将数据放入数据库。要访问图片,只需要根据图片地址访问就可以。减少数据库存储的呢内容。
此时前台可以看到商品的商品
如果将商品上架情况改为未上架
前台不展示
1.3 修改商品
点击修改商品信息。这里图片的修改,只需要重新上传一个图片就可以。相当于换了一个图片保存的地址。弊端,没有将之前的图片删除。可以优化,但是目前先不搞
修改后,预览修改后的图片,修改成功。
1.4 删除商品
其实也就是二次提示确认
五、订单信息
1.1 查看订单
这里管理员可以看到商品的发货情况,然后根据订单情况,选择操作。
1.2 发货
六、公告信息
1.1 查看公告
1.2 添加公告
这里通过vue集成Quill可以实现编辑框的样式
添加公告
前台查看公告
这个时间排序可以调整,查询数据的时候,按照注册的时间顺序就可以。
1.3 修改公告
1.4 删除公告
也是进行二次确认删除
删除成功。
七、登录界面
部分源码
1、前端
1.1 项目结构
1.2 部分源码
一些接口数据请求
//用户调用的一些接口
import { Get, Post, Put, MyPut, Patch, Delete } from "@/api/request";
export default {
//注销
logout: (params) => {
return Get('http://localhost:8282/user/logout', params)
},
//登录
Login: (params) => {
return Get('http://localhost:8282/user/userLogin', params)
},
//判断是否登录
isLogin: (params) => {
return Get('http://localhost:8282/user/isLogin', params)
},
//注册
Register: (params) => {
return Post('http://localhost:8282/user/register', params)
},
findAllGoodsInfo: (params) => {
return Get('http://localhost:8282/goodsInfo/getInfo', params)
},
findGoodsDetail: (params) => {
return Get('http://localhost:8282/goodsInfo/GoodsDetail', params)
},
/**
* 购物车 addCartShopInfo
*/
addCartShopInfo: (params) => {
return Post('http://localhost:8282/cartshop/add', params)
},
queryCartShopInfo: (params) => {
return Get('http://localhost:8282/cartshop/find', params)
},
deleteCartShopInfo: (params) => {
return Delete('http://localhost:8282/cartshop/delete', params)
},
/**
* 订单
*/
addOrder: (params) => {
return Post('http://localhost:8282/order/add', params)
},
queryOrder: (params) => {
return Get('http://localhost:8282/order/findAll', params)
},
onPaymoney: (params) => {
return Put('http://localhost:8282/order/paymoney', params)
},
onRefund: (params) => {
return Put('http://localhost:8282/order/refund', params)
},
onCancelRefund: (params) => {
return Put('http://localhost:8282/order/cancelRefund', params)
},
onReturnable: (params) => {
return Put('http://localhost:8282/order/onReturnable', params)
},
onCancelReturnable: (params) => {
return Put('http://localhost:8282/order/onCancelReturnable', params)
},
/**
* 用户信息
*/
updateFaceImage: (params) => {
return Put('http://localhost:8282/user/updateFaceImage', params)
},
rechargeMoney: (params) => {
return Put('http://localhost:8282/user/rechargeMoney', params)
},
findUserById: (params) => {
return Get('http://localhost:8282/user/findUserById', params)
},
onChangePWD: (params) => {
return Put('http://localhost:8282/user/changePwd', params)
},
UpdateUserInfo: (params) => {
return Put('http://localhost:8282/user/updateUserInfo', params)
},
//获取验证码
GetCode: (params) => {
return Get('http://localhost:8282/user/getCode', params)
},
//验证验证码
VerifyCode: (params) => {
return Get('http://localhost:8282/user/verifyCode', params)
},
//修改手机号
UpdatePhone: (params) => {
return Put('http://localhost:8282/user/updatePhone', params)
},
/**
* 公告
*/
findAllAnnounceInfo: (params) => {
return Get('http://localhost:8282/announce/findAllAnnounceInfo', params)
},
}
//管理员
import { Get, Post, Put, MyPut, Patch, Delete } from "@/api/request";
export default {
getListData: (params) => {
return Get('../../static/data.json', params);
},
postListData: (params) => {
return Post('../../static/data.json', params);
},
deleteListData: (params) => {
return Delete('../../static/data.json', params);
},
Register: (params) => {
return Post('http://localhost:8282/user/register', params)
},
adminRegister: (params) => {
return Post('http://localhost:8282/admin/register', params)
},
Login: (params) => {
return Post('http://localhost:8282/user/login', params)
},
findAllUser: (params) => {
return Get('http://localhost:8282/user/findAllUser', params)
},
findAllAdmin: (params) => {
return Get('http://localhost:8282/admin/findAllUser', params)
},
submitUpdateAdminForm: (params) => {
return Put('http://localhost:8282/admin/updateUserInfo', params)
},
handleAdminDelete: (params) => {
return Delete('http://localhost:8282/admin/deleteUser/', params)
},
submitUpdateUserForm: (params) => {
return Put('http://localhost:8282/user/updateUserInfo', params)
},
handleDelete: (params) => {
return Delete('http://localhost:8282/user/deleteUser/', params)
},
/**
* 商品种类
*/
addTypeInfo: (params) => {
return Post('http://localhost:8282/typeInfo/addTypeInfo', params)
},
findAllTypeInfo: (params) => {
return Get('http://localhost:8282/typeInfo/findAllTypeInfo', params)
},
handleDeleteTypeInfo: (params) => {
return Delete('http://localhost:8282/typeInfo/deleteTypeInfo', params)
},
submitUpdateUserForm: (params) => {
return Put('http://localhost:8282/typeInfo/updateTypeInfo', params)
},
/**
* 商品详情
*/
getTypeInfoOption: (params) => {
return Get('http://localhost:8282/goodsInfo/getTypeInfo', params)
},
addGoodsInfo: (params) => {
return Post('http://localhost:8282/goodsInfo/addGoodsInfo', params)
},
handleDeleteGoodsInfo: (params) => {
return Delete('http://localhost:8282/goodsInfo/deleteGoodsInfo', params)
},
updateGoodsInfo: (params) => {
return Put('http://localhost:8282/goodsInfo/updateGoodsInfo', params)
},
findAllGoodsInfo: (params) => {
return Get('http://localhost:8282/goodsInfo/findAllGoodsInfo', params)
},
updateSaleStatus: (params) => {
return Put('http://localhost:8282/goodsInfo/updateSaleStatus',params)
},
/**
* 文件上传
*/
uploadFile: (params) => {
return Post('http://localhost:8282/goodsInfo/upload', params);
},
/**
* 订单
*/
findAllOrder: (params) => {
return Get('http://localhost:8282/order/findAllOrderInfo', params)
},
onShipments: (params) => {
return Put('http://localhost:8282/order/shipments', params)
},
/**
* 公告
*/
findAllAnnounceInfo: (params) => {
return Get('http://localhost:8282/announce/findAllAnnounceInfo', params)
},
addAnnounceInfo: (params) => {
return Post('http://localhost:8282/announce/addAnnounceInfo', params)
},
handleDeleteAnnounceInfo: (params) => {
return Delete('http://localhost:8282/announce/deleteAnnounceInfo', params)
},
submitUpdateAnnounce: (params) => {
return Put('http://localhost:8282/announce/updateAnnounceInfo', params)
},
}
2、后端
1.1 项目结构
1.2 部分源码
这个是redis关于验证码的部分代码
/**
* @author zyz
* @version 1.0
* @data 2022/12/5 14:18
* @Description:
*/
@RestController
public class RedisController {
@Autowired
private RedisTemplate redisTemplate;
//六位数验证码
public static String getRandom() {
Random random = new Random();
String code = "";
for (int i = 0; i < 6; i++) {
int rand = random.nextInt(10);
code += rand;
}
return code;
}
/**
* 发送手机号、获取验证码
*
* @return
*/
@RequestMapping(value = "/user/getCode", method = RequestMethod.GET)
public Result getVerifyCode(@RequestParam Map<String, Object> maps) {
String phone = (String) maps.get("phone");
//手机发送次数key
String countKey = "verifyCode" + phone + "count";
//验证码key
String codeKey = "verifyCode" + phone + "code";
//每个手机1小时发送三次
Integer count = (Integer) redisTemplate.opsForValue().get(countKey);
if (count == null) {
//第一次发送
redisTemplate.opsForValue().set(countKey, 1, 60 * 60, TimeUnit.SECONDS);
System.out.println("第几次发送:" + count);
} else if (count <= 2) {
Integer nums = ++count;
redisTemplate.opsForValue().set(countKey, nums, 60 * 60, TimeUnit.SECONDS);
System.out.println("第几次发送:" + count);
} else {
System.out.println("请一个小时后再次尝试");
return Result.error().data("errMessage", "请一个小时后再次尝试");
}
//发送验证码到redis中
String vcode = getRandom();
System.out.println("生成的验证码是:" + vcode);
redisTemplate.opsForValue().set(codeKey, vcode, 120, TimeUnit.SECONDS);
return Result.ok().data("vcode", vcode);
}
/**
* 验证验证码
*
* @return
*/
@RequestMapping(value = "/user/verifyCode", method = RequestMethod.GET)
public Result verifyCode(@RequestParam Map<String, Object> maps) {
String phone = (String) maps.get("phone");
String code = (String) maps.get("code");
//验证码的key
String codeKey = "verifyCode" + phone + "code";
String redisCode = (String) redisTemplate.opsForValue().get(codeKey);
//判断
if (redisCode.equals(code)) {
return Result.ok();
} else {
return Result.error();
}
}
@GetMapping(value = "/getName")
public String testRedis() {
//设置值到redis
redisTemplate.opsForValue().set("name", "lucy");
//从redis获取值
String name = (String) redisTemplate.opsForValue().get("name");
return name;
}
}
后语
做系统是学习提升最快的方式了