基于Java+VUE+MariaDB实现(Web)仿小米商城

news2025/6/12 8:14:03

仿小米商城

环境安装

nodejs

maven

JDK11

运行

mvn clean install -DskipTests

cd admin

mvn spring-boot:run

cd ../web

mvn spring-boot:run

cd ../xiaomi-store-admin-vue

npm install

npm run serve

cd ../xiaomi-store-vue

npm install

npm run serve

注意:运行前请更改数据库相关属性文件

实训日志

数据库设计

根据项目需求,该项目相关实体有:用户(普通用户 user 与管理员 admin),商品 item,订单 order,购物车 shopping_cart,用户详细信息 user_detail(包括地址 address),商品类型 item_type
如下表:

实体名称

数据库表

普通用户

user

管理员

admin

商品

item

订单

order

购物车

shopping_cart

用户详细信息

user_detail

地址

address

商品类型

item_type

实体之间的关联关系如下:

  • user user_detail OneToOne
  • user shopping_cart OneToOne
  • user order OneToMany
  • item shopping_cart ManyToOne
  • item order ManyToOne
  • address user_detail ManyToOne
  • address order OneToOne
  • item item_type OneToOne

所以数据库设计为:

项目设计

模块

自顶向下分析,顶层模块有用户系统,管理员系统,向下有服务层,数据库读写 dao 层,Java 实体 model 层,各层次依赖关系为,admin 和 Web 依赖 service,service 依赖 dao,dao 依赖 model,它们都是 xiaomi_store 的子项目。

Java 实体关系设计

model 层 uml 类图如下:

各实体间没有关系,但都继承自一个基类,基类存放实体创建时间,修改时间等信息。

用户系统实现

jpa 与 MyBatis 选择

Hibernate 是一个 ORM 框架,而 JPA 则是一种 ORM 规范,JPA 和 Hibernate 的关系就像 JDBC 与 JDBC 驱动的关系,即 JPA 制定了 ORM 规范,而 Hibernate 是这些规范的实现(事实上,是先有 Hibernate 后有 JPA,JPA 规范的起草者也是 Hibernate 的作者),因此从功能上来说,JPA 相当于 Hibernate 的一个子集。

jpa 使用方便,不需要开发者编写 SQL 代码,通过实体之间的关系自动创建或修改数据库;MyBatis 支持定制化 SQL、存储过程以及高级映射。MyBatis 几乎避免了所有的 JDBC 代码手动设置参数以及获取结果集。

MyBatis 灵活,jpa 简单,我认为,MyBatis 更适合长期维护的项目,jpa 更适合短期快速开发上线项目。jpa 与 MyBatis 都是通过 interface 来映射 Java 方法进行数据库操作,可以使用 MyBatis 对 jpa 接口进行继承重写,迁移也比较方便。所以该实训项目选择 jpa。

模型层设计

使用 jpa 或是 MyBatis 提供的逆向工程并不包含依赖关系,所以我将各实体模型中加入了相应映射对象,来实现数据库映射读写懒加载,拿商品举例,商品代码如下。

/**
 * 商品实体
 */
@Entity
@Table(name = "items")
@Data
@Accessors(chain = true)
public class ItemEntity extends Auditable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    // 商品描述
    @Column(nullable = false, length = 500)
    @NotNull
    @NotBlank
    private String description;
    // 商品价格
    @Column(nullable = false, length = 10)
    private double price;
    // 商品数量
    @Column(nullable = false, length = 10)
    private int stockQuantity;
    // 商品图片
    @Column(nullable = false, length = 150)
    @NotBlank
    @NotNull
    private String picUrl;
    @Column(nullable = false, length = 50)
    @NotBlank
    @NotNull
    private String productName;
    @Column(nullable = false, length = 11)
    private int typeId;
    @Transient
    private ItemTypeEntity itemTypeEntity;
}

商品中包含一个商品类型的属性 ItemTypeEntity,通过 @Transient 注解来使得该属性不参与数据库的读写。

用户角色认证,使用 spring-security 框架,进行角色假认证,在从数据库读取用户时,直接设置用户权限为 user,因为普通用户角色与管理员用户角色基本上不用互通,而商品的查询不需要进行认证,游客也可进行访问。

用户客户端实现

客户端采用 vue 框架,实现商品的查找,购物车的显示,商品加入购物车等操作。

商城主页
 


商品信息
 


购物车

管理员系统实现

管理员系统中需要新增功能:对用户的禁用与启用,商品的修改和增加。

  1. 新建 admin 实体类
  2. 新建 AdminRepository 接口
  3. 新建使用 AdminService 进行登录的验证
  4. 在 Controller 中增加几个 Controller 用于管理员的相关操作

管理员客户端实现

同样使用 vue 框架,效果图如下:

面板
 


所有用户
 


所有商品
 


商品修改

spring-security 鉴权优化

将 spring-security 功能分别从 admin 与 Web 模块中提取出来整合到一个新的模块中,修改原实体类中的假认证(用户角色直接指定),转变成从数据库中读取。修改后的 Security 配置如下:

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                .antMatchers("/api/order/**", "/api/cart/**").hasRole(UserRole.USER.name)
                .antMatchers("/api/admin/**").hasRole(UserRole.ADMIN.name)
                .antMatchers("/api/user/**").authenticated()
                .and()
                .formLogin().loginProcessingUrl("/api/login").loginPage("/loginPage")
                .usernameParameter("username").passwordParameter("password")
                .successHandler((httpServletRequest, httpServletResponse, authentication) -> {
                    Object principal = authentication.getPrincipal();
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    httpServletResponse.setStatus(200);
                    Map<String, Object> map = new HashMap<>(2);
                    map.put("status", 200);
                    map.put("msg", principal);
                    ObjectMapper objectMapper = new ObjectMapper();
                    writer.write(objectMapper.writeValueAsString(map));
                    writer.flush();
                    writer.close();
                })
                .failureHandler((httpServletRequest, httpServletResponse, e) -> {
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    httpServletResponse.setStatus(401);
                    Map<String, Object> map = new HashMap<>(2);
                    map.put("status", 401);
                    if (e instanceof LockedException) {
                        map.put("msg", "账户被锁定,登录失败");
                    } else if (e instanceof BadCredentialsException) {
                        map.put("msg", "用户名或密码错误");
                    } else if (e instanceof DisabledException) {
                        map.put("msg", "账户被禁用,登录失败");
                    } else if (e instanceof AccountExpiredException) {
                        map.put("msg", "账户过期,登录失败");
                    } else if (e instanceof CredentialsExpiredException) {
                        map.put("msg", "密码过期,登录失败");
                    } else {
                        map.put("msg", "登录失败");
                    }
                    ObjectMapper objectMapper = new ObjectMapper();
                    writer.write(objectMapper.writeValueAsString(map));
                    writer.flush();
                    writer.close();
                })
                .permitAll()
                .and()
                .logout().logoutUrl("/api/logout").clearAuthentication(true).invalidateHttpSession(true)
                .addLogoutHandler((httpServletRequest, httpServletResponse, authentication) -> {

                })
                .logoutSuccessHandler((httpServletRequest, httpServletResponse, authentication) -> httpServletResponse.sendRedirect("/"))
                .and().csrf().disable();
    }

修改数据库,增加用户角色表与用户、角色中间表。修改后的数据库如下:

辅助功能增加

API 文档生成

向 Web 和 admin 模块中添加 swagger2 依赖,修改 controller 类,增加相关注解与描述即可生成文档。

应用端点监控

Actuator 是 Spring Boot 提供的对应用系统的自省和监控的集成功能,可以查看应用配置的详细信息,例如自动化配置信息、创建的 Spring beans 以及一些环境属性等。

向 Web 中增加 actuator 依赖,在浏览器地址栏访问 http://localhost:8080/actuator 即可看到如下信息。

在 idea 环境下也可以看到如下信息:

利用 webpack 模拟分布式

前端开发打包工具 webpack 提供了 dev-server 功能,可以使前端在开发期间完全独立进行运行,而无需部署。dev-server 需配置一套转发规则,将满足条件的请求转发到指定 host 上,而完全解决请求发送问题。

代理规则详细配置如下:

    devServer: {
        // overlay: { // 让浏览器 overlay 同时显示警告和错误
        //   warnings: true,
        //   errors: true
        // },
        // open: false, // 是否打开浏览器
        // host: "localhost",
        // port: "8080", // 代理断就
        // https: false,
        // hotOnly: false, // 热更新
        proxy: {
            "/api": {
                target:
                    "http://localhost:8080", // 目标代理接口地址
                secure: false,
                changeOrigin: true, // 开启代理,在本地创建一个虚拟服务端
                // ws: true, // 是否启用websockets
                pathRewrite: {
                    "^/api": "/api"
                }
            }
        }
    }

以上配置是将以 /api 开头的请求转发到:8080 端口上。

我们的项目分为用户使用的前台应用与管理员使用的后台应用,而管理员用户有着比普通用户更高的权限,所以普通用户的一些请求操作管理员也应该是可以完成的,但是如果将这些 controller 再编写一遍不仅工作量加大,而且没达到代码复用的效果。

利用 webpack 可以将不同请求转发到不同 host 上,而不影响用户使用。

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

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

相关文章

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…

STM32---外部32.768K晶振(LSE)无法起振问题

晶振是否起振主要就检查两个1、晶振与MCU是否兼容&#xff1b;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容&#xff08;CL&#xff09;与匹配电容&#xff08;CL1、CL2&#xff09;的关系 2. 如何选择 CL1 和 CL…

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …

PHP 8.5 即将发布:管道操作符、强力调试

前不久&#xff0c;PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5&#xff01;作为 PHP 语言的又一次重要迭代&#xff0c;PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是&#xff0c;借助强大的本地开发环境 ServBay&am…

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…

HubSpot推出与ChatGPT的深度集成引发兴奋与担忧

上周三&#xff0c;HubSpot宣布已构建与ChatGPT的深度集成&#xff0c;这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋&#xff0c;但同时也存在一些关于数据安全的担忧。 许多网络声音声称&#xff0c;这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…