全部源代码地址:传送门
文章内容有点长,建议打开右侧目录导航栏查看。
这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间,做几个变体系统。
闲的无聊,把大学时候做的一个系统进行了重构。将项目拆分成完全前后端分离的形式。客户端采用一套、商家端采用一套。后端只负责接口数据的处理(当然也可以只用一套)。对其中的一些页面进行了重新组织和美化。个人信息管理和后台商品信息添加、公告发布等模块做的比较好看一点。我直接仿照CSDN的个人信息管理界面进行的设计,包括头像的上修改。还有商品信息的展示,然后点击某一个商品进行商品详情的查看。公告的上传等等。使用到蛮多新的小技术。说实话,我还是不太满意,vue中的大部分代码有重复的,好想给他全部改成组件的形式。但是由于工作忙,现就这样了。
部分源代码在博客的最后给出
把一个系统拆分成了几个练习使用。我还可以进一步将其改造为分布式微服务系统。其实不难。有时间在改造一下。有需要源码的可以加我联系方式,博客最下方有我的联系方式
前端主要使用:Vue框架、组件使用ElementUI
后端主要使用:SpringBoot框架、Mybatis-plus、Redis等。
提示:主要说大的方面,小的技术点不在赘述
游客可以免登录浏览商品信息,公告信息;但是不能查看个人信息,订单、购物车等信息。等用户注册登录系统后。这些信息可以看到
直接在个人资料修改用户信息,点击保存就行了。还可以进行模拟充值
邮箱和手机号采用数据脱敏的形式,隐藏部分数据。这里修改手机号和邮箱类似,这里使用redis模拟发送验证码,同时保留三分钟的过期时间。在redis中很容易实现。还可以通过接入支付宝,购买他的那个验证码接口次数。可以实现真正的发送验证码到手机。我博客也有写过。这里不在赘述。
这里的redis我是直接装在了虚拟机中,采用docker安装redis是真的很方便。
同修改手机号
首页采用轮播图的形式,这个图片是我随机找的。可以换成校园二手商城类似的。然后商品展示不同的分类对应不同的商品。
这里的分类数据我使用的同一个分类下的数据,这个只需要插入一些其它的测试数据就行了。大致思想就是,sql语句查询携带分类信息。查询的数据在对应的内容区域遍历出来。
这里的详情就是在首页通过点击某一个商品,然后跳转到新的页面。这个新页面根据跳转商品id查询数据库,然后展示出来。这里可以进行购买,或者进行加入购物车等操作。
购物车中的商品进行购买后,会自动删除在购物车中保留的商品信息。你也可以选择不删除,目前是只能进行单个商品的结算。有时间做一下一个订单进行多个商品的结算
购买的时候,会出现收获地址。和商品的一信息。
在进行付款后,可以查看订单的信息状态。这里提示,订单状态使用int类型的数字替代,展示到前台的时候替换成对应的文字就可以
说实话、这个登录页面有点丑。但是我不想换了。我还有其它不同的登录页面。懒得换了
提示:后台管理,基本上就是一些表格。增删改查
这个就是用到了echart,我也写过怎样使用。这个数据可以替换来自数据库中实际的数据
一般来说是不允许修改的。这里为了练习使用。就修改吧。实在不想修改,就把操作中的修改按钮屏蔽掉。
按照常理,这里是不应该有的这个添加用户操作。为了练习弹窗的功能。就写出来了。你也可以屏蔽掉
这里新添加相同的商品种类,会提示错误信息。不能重复添加相同商品种类。不在演示。
二次提示删除操作
对应商品图片浏览
这里的商品图片上传,是和表格数据一块提交到后台保存的数据库的。大致流程,首先点击图片上传,选择图片。然后先发一个接口到后端。将图片复制到其它位置。返回前端保存该图片的位置。然后再次将表格内容和图片地址一块发送给后端。将数据放入数据库。要访问图片,只需要根据图片地址访问就可以。减少数据库存储的呢内容。
点击修改商品信息。这里图片的修改,只需要重新上传一个图片就可以。相当于换了一个图片保存的地址。弊端,没有将之前的图片删除。可以优化,但是目前先不搞
修改后,预览修改后的图片,修改成功。
这里管理员可以看到商品的发货情况,然后根据订单情况,选择操作。
这里通过vue集成Quill可以实现编辑框的样式
前台查看公告
这个时间排序可以调整,查询数据的时候,按照注册的时间顺序就可以。
也是进行二次确认删除
一些接口数据请求
//用户调用的一些接口
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)
},
}
这个是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;
}
}
做系统是学习提升最快的方式了