SpringBoot+Vue实现校园二手系统。前后端分离技术【完整功能介绍+实现详情+源码】

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 文章介绍了如何使用SpringBoot和Vue实现一个校园二手系统,采用前后端分离技术。系统具备完整的功能,包括客户端和管理员端的界面设计、个人信息管理、商品浏览和交易、订单处理、公告发布等。技术栈包括Vue框架、ElementUI、SpringBoot、Mybatis-plus和Redis。文章还提供了部分源代码,展示了前后端的请求接口和Redis验证码功能实现,以及系统重构和模块化设计的一些思考。

前言

全部源代码地址传送门

文章内容有点长,建议打开右侧目录导航栏查看。

   **这个系统基本上可以改造为其它类似的系统。后台管理基本上一致。前台进行一些页面样式的改造就可以变成一个新的系统。有时间,做几个变体系统。**

   闲的无聊,把大学时候做的一个系统进行了重构。将项目拆分成完全前后端分离的形式。客户端采用一套、商家端采用一套。后端只负责接口数据的处理(当然也可以只用一套)。对其中的一些页面进行了重新组织和美化。个人信息管理和后台商品信息添加、公告发布等模块做的比较好看一点。我直接仿照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;
    }
}

后语

做系统是学习提升最快的方式了

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
25 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
28 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
22 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
12天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
10天前
|
存储 缓存 Java
在Spring Boot中使用缓存的技术解析
通过利用Spring Boot中的缓存支持,开发者可以轻松地实现高效和可扩展的缓存策略,进而提升应用的性能和用户体验。Spring Boot的声明式缓存抽象和对多种缓存技术的支持,使得集成和使用缓存变得前所未有的简单。无论是在开发新应用还是优化现有应用,合理地使用缓存都是提高性能的有效手段。
15 1
|
12天前
|
JavaScript 前端开发 Java
一个基于 SpringBoot + Vue 的在线考试系统
【9月更文挑战第24天】这是一个基于 Spring Boot 和 Vue 构建的在线考试系统。后端采用 Spring Boot、Spring Data JPA 和 MySQL 实现快速开发和数据库操作;前端使用 Vue.js 和 Element UI 快速搭建界面。系统包括用户管理、考试管理、考试答题和成绩管理等功能模块,并设计了相应的数据库表结构。通过 RESTful API 实现前后端数据交互,支持多种题型和权限管理,适用于学校和企业等场景。
|
缓存 Java Spring
Spring&SpringBoot源码笔记整理 |Bean的加载流程二
昨天的文章里提到Bean的加载流程和如何获取bean,今天继续源码解读。还是老规矩,看着Bean加载的时序图进入主题。
324 0
Spring&SpringBoot源码笔记整理 |Bean的加载流程二
|
缓存 Java Spring
Spring&SpringBoot源码笔记整理 |Bean的加载流程一
本篇文章主要介绍Bean的加载流程,以及Spring是怎么解决循环依赖的问题。
131 0
Spring&SpringBoot源码笔记整理 |Bean的加载流程一
|
13天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
40 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
13天前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
66 1
下一篇
无影云桌面