基于Java+SpringBoot+Vue前后端分离书店购书系统设计与实现

news2024/11/15 4:24:35

博主介绍:✌全网粉丝3W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌

博主作品:《微服务实战》专栏是本人的实战经验总结,《Spring家族及微服务系列》专注Spring、SpringMVC、SpringBoot、SpringCloud系列、Nacos等源码解读、热门面试题、架构设计等。除此之外还有不少文章等你来细细品味,更多惊喜等着你哦

🍅开源项目免费哦:点击这里克隆或者下载 🍅

🍅文末获取联系🍅精彩专栏推荐订阅👇🏻👇🏻 不然下次找不到哟
 ✨【微服务】Nacos为什么丢弃短连接(http)而选择拥抱长连接(gRPC)

目录

一、前言

二、系统设计

1、系统运行环境

2、系统架构设计​编辑

3、管理员维护订单时序图设计:

三、功能性分析 

2、功能模块

四、非功能性与可行性分析 

五、功能截图

1、注册登录

2、图书

2.1、图书列表 

2.2、添加图书

2.3、图书分类

2.4、出版社

2.5、书单专题

3、订单

3.1、订单列表

3.2、订单详情

4、权限

5、首页

6、点击书籍进来

6.1、需要登录,才能加入购物车成功

6.2、 去购买

6.3、立即下单展示订单信息 

六、实现代码 

1、角色控制器

2、服务接口

3、实现类

七、参考论文

八、获取源码


一、前言

    本系统是基于SpringBoot+MyBatis+Vue+Uniapp的前后端完全分离的书店管理系统。值得一提的是前端使用了目前市场上较流行的组件elementui,在本系统里面对其进行了二次封装,使得页面更加的简洁与优雅,也提高了系统的可维护性。同时探究前端与后端是如何建立数据交互的,以及它为系统提供的服务和已经建好的多张表之间的关系。故课题研究的是这些技术的关联以及如何实现本系统,同时探究系统如何在Linux系统进行Docker容器化部署。
 

二、系统设计

1、系统运行环境

开发系统:Windows10

架构模式:MVC/前后端分离

JDK版本:Java JDK1.8

开发工具:IDEA

数据库版本: mysql5.7

数据库可视化工具: SQL yog或Navicat for MySQL

服务器:SpringBoot自带 apache tomcat

主要技术:Java、SpringBoot、MyBatis、SpringSecurity、MySQL、Redis、Html、Vue、Elementui等

2、系统架构设计

3、管理员维护订单时序图设计:

三、功能性分析 

2、功能模块

这个项目总共分为两类人员,管理员和普通用户。下面对这两类人员的使用的功能进行介绍。

2.1管理员

  • 图书管理

    • 添加图书
    • 删除图书(可批量删除)
    • 修改图书
    • 查看图书(分页查看)
    • 图书上下架(可批量处理)
    • 图书推荐(新品推荐、精品推荐,可批量处理)
  • 出版社管理

    • 新增出版社
    • 删除出版社
    • 修改出版社(基本信息、排序、启用状态,可分开处理)
    • 查看出版社(分页查看)
  • 图书分类管理(两级分类)

    • 添加分类(两级分类,可自行添加一级分类和二级分类)
    • 删除分类(删除一级分类的话所有二级分类也都会删除)
    • 修改分类(基本信息和排序)
    • 查看分类(分页查看一级分类,以及查看某个一级分类下的二级分类)
  • 书单管理

    • 添加一个书单专题
    • 添加指定图书到书单专题中(可批量处理)
    • 删除书单
    • 移除书单中的指定图书
    • 修改书单(基本信息、权重、上下架状态,可分开处理)
    • 查看书单(分页查看)
    • 查看指定书单的图书信息(分页查看)
  • 订单管理

    • 查看订单(分页查看)
    • 查看指定订单详细信息(订单商品明细、费用详情、收货地址详情)
    • 订单发货(手工填写订单号和快递公司之后确认发货)
    • 删除订单
  • 用户管理

    • 查看注册用户(分页查看)
    • 修改用户禁用状态
  • 数据统计

    • 根据选取时间段查看订单统计(图标显示)
    • 其他各类数据的统计

2.2用户

  • 页面浏览

    • 首页图书的各级分类
    • 首页书单的轮播图
    • 点击轮播图可查看书单详情页
    • 首页图书的各类展示(最新出版、精品推荐、新品推荐、以及图书的分类展示)
    • 点击某个分类可查看对应的图书数据(分页展示)
    • 图书详情页数据的展示
  • 购物车

    • 添加商品到购物车
    • 删除购物车中指定商品
    • 在购物车中修改商品数量
    • 查看购物车商品
  • 下单模块

    • 在商品详情页下单
    • 在图书分类展示和书单页面下单
    • 在购物车中下单
    • 点击下单后会跳转至购买页面进行地址选择,最后再下单确认
  • 地址管理

    • 添加收货地址信息
    • 删除收货地址信息
    • 修改收货地址信息
    • 查看收货地址地址信息
  • 订单管理

    • 查看自己所下订单(可分类查看,已付款、未收货、订单回收站)
    • 删除订单
    • 确认收货
  • 个人信息管理

    • 个人信息查看
    • 个人信息修改
    • 密码修改

四、非功能性与可行性分析 

2.5非功能性需求分析

非功能性需求:用户对软件质量属性、运行环境、资源约束、外部接口等方面的要求或期望,包括:

2.5.1性能需求:

用户在软件响应速度、结果精度、运行时资源消耗量等方面的要求。

2.5.2可行性需求:

用户在软件失效的频率、严重程度、易恢复性,以及故障可预测性等方面的要求。

2.5.3易用性需求:

用户在界面的易用性、美观性,以及对面向用户的文档和培训资料等方面的要求。

2.5.4安全性需求:

用户在身份证、授权控制、私密性等方面的要求。

2.5.5运行环境约束:

用户对软件系统运行环境的要求。

2.5.6外部接口:

用户对待开发软件系统与其它软件系统或设备之间的接口要求

2.6可行性分析

可行性分析是从不同的角度,对可能影响系统的各方面因素进行分析,确认系统在实际生活上是可行的。本系统只是单纯地从经济、法律、技术、操作可行性四个方面来分析说明。

2.6.1技术可行性

技术上的可行性分析主要分析技术条件能否顺利完成开发工作,软、硬件能否满足需要。本系统采用Vue+Elementui开发出友好美观的人机界面,便于用户理解、操作。数据库管理系统采用MySQL,它能够处理大量数据,同时保持数据的完整性、安全性和持久性。后端技术使用SpringBoot、MyBatis,这些技术在许多公司已经被商用了,因此本系统的开发平台已成熟可行。硬件方面,在科技飞速发展的今天,硬件更新速度越来越快,容量越来越大,可靠性越来越高,价格越来越便宜,因此硬件平台也能够满足本系统所需。

2.6.2经济可行性

  项目放在阿里学生服务器或者本地虚拟机的linux环境,故可行。

2.6.3法律可行性

  可行,自己写的项目,目的明确,没有违法违规。

2.6.4操作可行性
操作较为简单,而且当下信息科技发达,界面的设计也着实考虑到用户的体验,系统也是为用户而生。故操作是可行的,不存在难度大的操作。
 

五、功能截图

管理员登录:admin 123456

1、注册登录

首页

2、图书

2.1、图书列表 

2.2、添加图书

1)填写书籍信息

2)上传图片等

2.3、图书分类

1)列表

2)查看下级

2.4、出版社

2.5、书单专题

3、订单

3.1、订单列表

3.2、订单详情

4、权限

 点击管理系统右上角的首页退出到用户页面

用户登录: 123@qq.com 123456    还可以自己注册

5、首页

6、点击书籍进来

6.1、需要登录,才能加入购物车成功

点击加入购物车,然后到购物车查看

6.2、 去购买

6.3、立即下单展示订单信息 

还有一些功能就不一一截图了。 

六、实现代码 

1、角色控制器

/**
 * <p>
 * 角色表 服务类
 * </p>
 *
 * @author CeaM
 * @since 2023-01-28
 */
public interface ICeamSysRoleService extends IService<CeamSysRole> {
 
    IPage<CeaMSysRoleVO> pageCeaMSysRoleVO(PageableDTO pageable);
 
    /**
     * 获取用户权限信息
     * @param userId 用户信息
     * @return 权限信息
     */
    Collection<SimpleGrantedAuthority> grantedAuthorities(Long userId);
 
    /**
     *
     * @param userId 用户ID
     * @return RoleItemVOs
     */
    List<RoleDTO> listByUserId(Long userId);
 
    void updateMenu(CeaMSysRoleDTO roleDTO, CeamSysRole role);
}

2、服务接口

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author CeaM
 * @since 2023-01-28
 */
@Slf4j
@Service
@AllArgsConstructor
public class CeamSysRoleServiceImpl extends ServiceImpl<CeamSysRoleMapper, CeamSysRole> implements ICeamSysRoleService {
 
    private ICeamSysMenuService ceamSysMenuService;
    private ICeamRoleMenuService ceamRoleMenuService;
 
    @Override
    public IPage<CeaMSysRoleVO> pageCeaMSysRoleVO(PageableDTO pageable) {
        LambdaQueryWrapper<CeamSysRole> queryWrapper = Wrappers.<CeamSysRole>lambdaQuery()
                .eq(CeamSysRole::getDeleted, GlobalConstants.FALSE);
        Page<CeamSysRole> page = new Page<>(pageable.getPage(), pageable.getSize());
        // 手动设置当前页,不然分页失效
        page.setCurrent((long)pageable.getPage() + GlobalConstants.ONE);
        Page<CeamSysRole> ceamSysRolePage = page(page, queryWrapper);
        IPage<CeaMSysRoleVO> ceaMSysRoleVOIPage = PageVOUtil.copyToPageVO(ceamSysRolePage, CeaMSysRoleVO.class);
 
        for (CeaMSysRoleVO role : ceaMSysRoleVOIPage.getRecords()) {
 
            List<MenuDTO> menuDTOS = ceamSysMenuService.findByRoleId(role.getId(), GlobalConstants.ZERO);
            role.setMenus(menuDTOS);
        }
 
        return ceaMSysRoleVOIPage;
    }
 
    @Override
    public Collection<SimpleGrantedAuthority> grantedAuthorities(Long userId) {
        List<RoleDTO> roleItemDTOS = this.baseMapper.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleItemDTOS)) {
            throw new ServiceException("没有分配角色");
        }
 
        List<MenuDTO> menuDTOS = ceamSysMenuService.findByRoles(roleItemDTOS, GlobalConstants.ZERO);
 
        // 角色
        Set<String> permissions = roleItemDTOS.stream()
                .filter(role -> StringUtils.isNotBlank(role.getName()))
                .map(RoleDTO::getName).collect(Collectors.toSet());
        permissions.addAll(
                menuDTOS.stream()
                        .filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
                        .map(MenuDTO::getPermission).collect(Collectors.toSet())
        );
 
        return permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }
 
    @Override
    public List<RoleDTO> listByUserId(Long userId) {
        return this.baseMapper.listByUserId(userId);
    }
 
    @Override
    public void updateMenu(CeaMSysRoleDTO roleDTO, CeamSysRole role) {
        if (roleDTO.getMenus().size() > 0) {
            List<CeamRoleMenu> rolesMenusList = roleDTO.getMenus().stream().map(i -> {
                CeamRoleMenu rolesMenus = new CeamRoleMenu();
                rolesMenus.setRoleId(roleDTO.getId());
                rolesMenus.setMenuId(i.getId());
                return rolesMenus;
            }).collect(Collectors.toList());
            ceamRoleMenuService.remove(new LambdaQueryWrapper<CeamRoleMenu>()
                    .eq(CeamRoleMenu::getRoleId, roleDTO.getId()));
            ceamRoleMenuService.saveBatch(rolesMenusList);
        }
    }
}

3、实现类

/**
 * <p>
 * 角色表 服务实现类
 * </p>
 *
 * @author CeaM
 * @since 2023-01-28
 */
@Slf4j
@Service
@AllArgsConstructor
public class CeamSysRoleServiceImpl extends ServiceImpl<CeamSysRoleMapper, CeamSysRole> implements ICeamSysRoleService {
 
    private ICeamSysMenuService ceamSysMenuService;
    private ICeamRoleMenuService ceamRoleMenuService;
 
    @Override
    public IPage<CeaMSysRoleVO> pageCeaMSysRoleVO(PageableDTO pageable) {
        LambdaQueryWrapper<CeamSysRole> queryWrapper = Wrappers.<CeamSysRole>lambdaQuery()
                .eq(CeamSysRole::getDeleted, GlobalConstants.FALSE);
        Page<CeamSysRole> page = new Page<>(pageable.getPage(), pageable.getSize());
        // 手动设置当前页,不然分页失效
        page.setCurrent((long)pageable.getPage() + GlobalConstants.ONE);
        Page<CeamSysRole> ceamSysRolePage = page(page, queryWrapper);
        IPage<CeaMSysRoleVO> ceaMSysRoleVOIPage = PageVOUtil.copyToPageVO(ceamSysRolePage, CeaMSysRoleVO.class);
 
        for (CeaMSysRoleVO role : ceaMSysRoleVOIPage.getRecords()) {
 
            List<MenuDTO> menuDTOS = ceamSysMenuService.findByRoleId(role.getId(), GlobalConstants.ZERO);
            role.setMenus(menuDTOS);
        }
 
        return ceaMSysRoleVOIPage;
    }
 
    @Override
    public Collection<SimpleGrantedAuthority> grantedAuthorities(Long userId) {
        List<RoleDTO> roleItemDTOS = this.baseMapper.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleItemDTOS)) {
            throw new ServiceException("没有分配角色");
        }
 
        List<MenuDTO> menuDTOS = ceamSysMenuService.findByRoles(roleItemDTOS, GlobalConstants.ZERO);
 
        // 角色
        Set<String> permissions = roleItemDTOS.stream()
                .filter(role -> StringUtils.isNotBlank(role.getName()))
                .map(RoleDTO::getName).collect(Collectors.toSet());
        permissions.addAll(
                menuDTOS.stream()
                        .filter(menu -> StringUtils.isNotBlank(menu.getPermission()))
                        .map(MenuDTO::getPermission).collect(Collectors.toSet())
        );
 
        return permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }
 
    @Override
    public List<RoleDTO> listByUserId(Long userId) {
        return this.baseMapper.listByUserId(userId);
    }
 
    @Override
    public void updateMenu(CeaMSysRoleDTO roleDTO, CeamSysRole role) {
        if (roleDTO.getMenus().size() > 0) {
            List<CeamRoleMenu> rolesMenusList = roleDTO.getMenus().stream().map(i -> {
                CeamRoleMenu rolesMenus = new CeamRoleMenu();
                rolesMenus.setRoleId(roleDTO.getId());
                rolesMenus.setMenuId(i.getId());
                return rolesMenus;
            }).collect(Collectors.toList());
            ceamRoleMenuService.remove(new LambdaQueryWrapper<CeamRoleMenu>()
                    .eq(CeamRoleMenu::getRoleId, roleDTO.getId()));
            ceamRoleMenuService.saveBatch(rolesMenusList);
        }
    }
}

七、参考论文

八、获取源码

 大家点赞、收藏、关注、评论啦 、关注下方公众号获取联系方式👇🏻👇🏻

🍅开源项目免费下载🍅商业使用需授权:点击这里下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/377159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat部署及多实例

Tomcat部署及多实例一、Tomcat简介1、Tomcat核心组件2、什么是JSP二、Tomcat数据流向1、Tomcat数据流向2、Tomcat-Nginx数据流向三、Tomcat服务部署安装1、安装jdk包2、解压Tomcat所需的安装包3、在/etc/profile添加环境变量4、启动服务并查看5、在浏览器网页验证6、创建用户&a…

flink常用算子介绍

flink任务中【Transformation 数据转换】是对数据进行操作&#xff0c;有 Map、FlatMap、Filter、KeyBy 、Reduce 、Fold 、Aggregations、Window 、WindowAll 、Union 、Window join 、Split 、Select 、Project 等&#xff0c;通过对数据的操作&#xff0c;转换成想要的数据&…

【设计模式】4.建造者模式

概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。由于实现了构建和装配的解耦。不…

【沐风老师】3DMAX一键玻璃门生成器使用教程

3DMAX一键玻璃门生成器使用方法详解 3dMax一键玻璃门生成器是在3dMax中自动创建三维玻璃门模型的高效脚本。有6种风格的玻璃门&#xff0c;它可以在Archviz项目中灵活应用&#xff0c;同时为3D艺术家节省大量时间。 【适用版本】 3dMax 2018.2及更高版本 【安装方法】…

day37|完全背包、518. 零钱兑换 II、377. 组合总和 Ⅳ 复健运动

完全背包 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品都有无限个&#xff08;也就是可以放入背包多次&#xff09;&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 完全背包和01背包问题唯一不同…

什么是MES系统?本文解释得很清楚了

MES&#xff08;英文Manufacturing Execution System的缩写&#xff09;&#xff0c;即生产执行系统&#xff0c;是近几年发展起来的企业信息化系统&#xff0c;目前在发达国家已经普遍推广。 MES软件是介于ERP&#xff08;企业资源计划系统&#xff09;和自控系统&#xff08…

百度前端训练营

视频&#xff1a;前端训练营开营仪式20220627_哔哩哔哩_bilibili http://bit.baidu.com/productsBuy?id248 一、Git安装与使用【因为重装系统&#xff0c;所以重新装一次环境】 查看电脑32位还是64&#xff0c;安装git TortoiseGit 及TortoiseGit 汉化包 下载64位对应的版本…

Java集合概述(Collection集合)

目录集合一、集合与数组二、集合类体系结构三、泛型(约定集合存储数据类型)四、Collection集合常用API五、Collection集合的遍历方式5.1 迭代器遍历5.2 增强for循环(for each):5.3 lambda表达式六、Collection集合存储自定义类型的对象七、常见数据结构集合 一、集合与数组 数…

【设计模式】9.桥接模式

概述 现在有一个需求&#xff0c;需要创建不同的图形&#xff0c;并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系&#xff1a; 我们可以发现有很多的类&#xff0c;假如我们再增加一个形状或再增加一种颜色&#xff0c;就需要创建更多的类。 试…

redis 05 篇——主从复制

redis 05 篇——主从复制1. 前言1.1 什么是复制&#xff1f;1.1.1 复制概述1.1.2 主从复制的架构1.2 为什么要使用主从复制&#xff1f;1.3 主从复制主要的命令配置2. 准备工作3. 核心配置3.1 主服务器3.2 从服务器4. 实例演示4.1 简单实例——两台服务器4.1.1 同一服务多个red…

小程序:使用分包异步化解决一个分包引入另一个分包的组件/函数的问题

背景 我们一般使用小程序插件的时候&#xff0c;喜欢将其放在分包中&#xff0c;因为插件体积会打包进主包内&#xff0c;很容易造成主包体积超过 2M 从而无法发布&#xff0c;我们暂且叫这个有插件的分包叫分包P&#xff0c;这时候另外两个业务分包XY&#xff0c;想引入这个分…

从Java培训班出来好找工作吗?

个人觉得这个问题要从两方面来看&#xff0c;首先是培训班的Java课程质量如何&#xff0c;是否贴合用人单位实际需求&#xff0c;学出来的技术能对口&#xff1b;其次是培训班是否保障就业&#xff0c;有就业机会渠道推荐&#xff0c;比如老学员内推、合作企业人才输送以及企业…

【Spring Cloud Alibaba】008-Sentinel

【Spring Cloud Alibaba】008-Sentinel 文章目录【Spring Cloud Alibaba】008-Sentinel一、服务雪崩1、概述2、解决方案常见的容错机制二、Sentinel&#xff1a;分布式系统的流量防卫兵1、**Sentinel** 概述简介特性Sentinel 的开源生态Sentinel 的历史2、Sentinel 基本概念资源…

低代码系统能够解决哪些痛点?

低代码系统能够解决哪些痛点&#xff1f;如果用4句话去归纳&#xff0c;低代码开发可以解决以下问题—— 为企业提供更高的灵活性&#xff0c;用户可以突破代码的限制自主开发业务应用&#xff1b;通过减少对专业软件开发人员的依赖&#xff0c;公司可以快速响应市场上的新业务…

cartographer中分支定界法理解——为什么能保证上界

定界原理 储存的不同分辨率栅格图&#xff0c;为保证上边界正确性&#xff0c;即高层中的评分一定高于其底层节点的评分&#xff0c;压缩的地图并非直接从原图固定间隔采样&#xff0c;而是将固定间隔中所有坐标概率值最大值作为低分辨率地图。 理解&#xff1a; 1、其在计算…

ESP32中MQTT通讯

MQTT文档介绍 一、在PC上可以使用 MQTT X 工具&#xff1a;&#xff08;参考地址&#xff09; 1、客户端下载&#xff1a;MQTT X 工具下载地址 2、EMQX服务器下载地址 3.打开命令行工具&#xff0c;进入目录运行EMQX服务。 电脑左下角&#xff0c;右键开始->运行->输…

“双碳”目标下二氧化碳地质封存技术应用前景及模型构建

我国二氧化碳地质封存技术起步较晚&#xff0c;目前仍没有一套相对完整的行业规范&#xff1b;且就该技术而言&#xff0c;涉及环节众多&#xff0c;理论相对复杂&#xff0c;对于行业的新入局者不太友好。因此&#xff0c;结合时代背景&#xff0c;我们首次尝试对二氧化碳地质…

升级多语言,应用国际化_三叠云

国际化配置 路径 表单设计 >> 字段属性 功能简介 【字段】新增 「国际化配置」 这是一个和国际化配合的功能&#xff0c;可以在用户通过切换不同的语言环境时&#xff0c;表单的标题、提示语等将会根据相应的语言环境切换到相应的表单字段标题、提示语&#xff0c;使…

Eureka注册中心-Ribbon负载均衡

1、Eureka注册中心服务注册与发现提供了一个服务注册中心、服务发现的客户端&#xff0c;还有一个方便查看所有注册的服务的界面。所有的服务使用Eureka的服务发现客户端来将自己注册到Eureka的服务器上。1.1 、Eureka的结构和作用1.1.1、Eureka的作用1.1.2、获取地址信息的流程…

【C++进阶】三、二叉搜索树

目录 一、二叉搜索树 1.1 概念 1.2 二叉搜索树操作 二、二叉搜索树实现 2.1 框架总览 2.2 实现接口总览 2.2.1 构造函数 2.2.2 拷贝构造 2.2.3 赋值重载 2.2.4 析构函数 2.2.5 二叉搜索树的遍历 2.2.6 插入函数 2.2.7 查找函数 2.2.8 删除函数 2.3 二叉搜索数完整…