前言

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

       闲的无聊,把大学时候做的一个系统进行了重构。将项目拆分成完全前后端分离的形式。客户端采用一套、商家端采用一套。后端只负责接口数据的处理(当然也可以只用一套)。对其中的一些页面进行了重新组织和美化。个人信息管理和后台商品信息添加、公告发布等模块做的比较好看一点。我直接仿照CSDN的个人信息管理界面进行的设计,包括头像的上修改。还有商品信息的展示,然后点击某一个商品进行商品详情的查看。公告的上传等等。使用到蛮多新的小技术。说实话,我还是不太满意,vue中的大部分代码有重复的,好想给他全部改成组件的形式。但是由于工作忙,现就这样了。

资料(源代码)

部分源代码在博客的最后给出

       把一个系统拆分成了几个练习使用。我还可以进一步将其改造为分布式微服务系统。其实不难。有时间在改造一下。有需要源码的可以加我联系方式,博客最下方有我的联系方式

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

技术栈

前端主要使用:Vue框架、组件使用ElementUI
后端主要使用:SpringBoot框架、Mybatis-plus、Redis等。

提示:主要说大的方面,小的技术点不在赘述

功能划分

1.1 客户端

客户端主要实现的功能划分

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

1.2 管理员

管理员方面主要负责的功能划分

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

顾客+游客(页面效果展示)

       游客可以免登录浏览商品信息,公告信息;但是不能查看个人信息,订单、购物车等信息。等用户注册登录系统后。这些信息可以看到

一、个人信息

1.1 信息展示

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

1.2 修改头像

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


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

1.3 修改信息

       直接在个人资料修改用户信息,点击保存就行了。还可以进行模拟充值

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

1.4 充值

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

1.5 修改密码

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

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


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

1.6 修改手机号

       邮箱和手机号采用数据脱敏的形式,隐藏部分数据。这里修改手机号和邮箱类似,这里使用redis模拟发送验证码,同时保留三分钟的过期时间。在redis中很容易实现。还可以通过接入支付宝,购买他的那个验证码接口次数。可以实现真正的发送验证码到手机。我博客也有写过。这里不在赘述。

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

       这里的redis我是直接装在了虚拟机中,采用docker安装redis是真的很方便。

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


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

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


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

1.7 修改邮箱

同修改手机号

二、 商品首页

1.1 首页

       首页采用轮播图的形式,这个图片是我随机找的。可以换成校园二手商城类似的。然后商品展示不同的分类对应不同的商品。

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

1.2 商品分类

       这里的分类数据我使用的同一个分类下的数据,这个只需要插入一些其它的测试数据就行了。大致思想就是,sql语句查询携带分类信息。查询的数据在对应的内容区域遍历出来。

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

1.3 商品详情页面

       这里的详情就是在首页通过点击某一个商品,然后跳转到新的页面。这个新页面根据跳转商品id查询数据库,然后展示出来。这里可以进行购买,或者进行加入购物车等操作。

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

二、 购物车

1.1 查看购物车商品

       购物车中的商品进行购买后,会自动删除在购物车中保留的商品信息。你也可以选择不删除,目前是只能进行单个商品的结算。有时间做一下一个订单进行多个商品的结算

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

1.2 购买

       购买的时候,会出现收获地址。和商品的一信息。

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

1.3 删除购物车商品

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

三、 订单

1.1 查看订单

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

1.2 查看订单状态

       在进行付款后,可以查看订单的信息状态。这里提示,订单状态使用int类型的数字替代,展示到前台的时候替换成对应的文字就可以

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

四、 公告

       公告这里点击左侧的公告列表,右侧的内容会替换对应公告内容。

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


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

五、登录(顾客)

       说实话、这个登录页面有点丑。但是我不想换了。我还有其它不同的登录页面。懒得换了

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

六、注册页面

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

管理员(页面效果展示)

提示:后台管理,基本上就是一些表格。增删改查

一、查看数据

       这个就是用到了echart,我也写过怎样使用。这个数据可以替换来自数据库中实际的数据

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

二、管理用户信息

1.1 查看用户信息

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

1.2 修改用户信息

       一般来说是不允许修改的。这里为了练习使用。就修改吧。实在不想修改,就把操作中的修改按钮屏蔽掉。

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

1.3 删除用户信息

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

1.4 添加用户信息

       按照常理,这里是不应该有的这个添加用户操作。为了练习弹窗的功能。就写出来了。你也可以屏蔽掉

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

三、商品种类

       这里新添加相同的商品种类,会提示错误信息。不能重复添加相同商品种类。不在演示。

1.1 添加商品种类

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

1.2 修改商品信息

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

1.3 删除商品信息

二次提示删除操作

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

四、商品详情

1.1 查看商品详情

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

对应商品图片浏览

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

1.2 添加商品

       这里的商品图片上传,是和表格数据一块提交到后台保存的数据库的。大致流程,首先点击图片上传,选择图片。然后先发一个接口到后端。将图片复制到其它位置。返回前端保存该图片的位置。然后再次将表格内容和图片地址一块发送给后端。将数据放入数据库。要访问图片,只需要根据图片地址访问就可以。减少数据库存储的呢内容。

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


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


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

此时前台可以看到商品的商品

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

如果将商品上架情况改为未上架

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


前台不展示

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

1.3 修改商品

       点击修改商品信息。这里图片的修改,只需要重新上传一个图片就可以。相当于换了一个图片保存的地址。弊端,没有将之前的图片删除。可以优化,但是目前先不搞

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

修改后,预览修改后的图片,修改成功。

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

1.4 删除商品

其实也就是二次提示确认

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

五、订单信息

1.1 查看订单

       这里管理员可以看到商品的发货情况,然后根据订单情况,选择操作。

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


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

1.2 发货

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

六、公告信息

1.1 查看公告

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

1.2 添加公告

       这里通过vue集成Quill可以实现编辑框的样式

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


添加公告

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

前台查看公告

       这个时间排序可以调整,查询数据的时候,按照注册的时间顺序就可以。

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

1.3 修改公告

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


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

1.4 删除公告

也是进行二次确认删除

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

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

删除成功。

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

七、登录界面

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

部分源码

1、前端

1.1 项目结构

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

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 项目结构

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

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;
    }
}

后语

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