欢迎光临
我们一直在努力

[Java]RuoYi帝可得-1项目搭建

项目介绍

帝可得是什么?

帝可得是一个基于物联网概念下的智能售货机运营管理系统

售货机术语

售货机业务中有一些专业名词

角色与功能

一个完整的售货机系统由五端五角色组成:

  • 管理员: 对基础数据(区域、点位、设备、货道、商品等)进行管理,创建工单、查看订单、统计报表等。
  • 运维人员: 投放设备、撤除设备、维修设备。
  • 运营人员: 补货。
  • 合作商: 仅提供点位,坐收渔翁之利。
  • 消费者: 在小程序或屏幕端下单购买商品。
  • 产品原型

    帝可得项目点击链接立即查看 https://codesign.qq.com/s/426304924036117

    库表设计

    系统后台基础数据表关系说明:

    认识AI

    AIGC

    AI(ArtificialIntelligence): 即人工智能,是指通过计算机系统模拟人类思维和行为一种技术, 它通过机器学习、深度学习等算法,使计算机具备对数据分析、理解、推理和决策的能力

    AIGC(AIGeneratedContent):是AI领域的一个应用分支,专注于利用AI技术自动生成内容

    AI大模型: 是一种机器学习模型,经过大量数据训练,具备复杂计算能力的人工智能,其中包括生成内容

    国内常见的通用大模型(AGI)产品:

  • 文心一言
  • 讯飞星火
  • 通义千问
  • KIMI
  • 提示工程

    提示(Prompt)是我们对大模型提出的问题

  • "你是谁"这个问题便是Prompt
  • 同一个问题使用不同的Prompt可能会获得不同的答案
  • 提示工程(Prompt Engineering)也被称为上下文提示
  • 设计和优化输入文本(Prompt)来引导AI模型生成预期的输出
  • Prompt的组成
    • 角色: 给AI定义一个最匹配任务的角色,比如:「你是一位专业的博客作者」
    • 指示: 对任务进行描述,比如:「撰写一篇关于最新AI技术发展的文章」
    • 上下文: 给出与任务相关的其它背景信息
    • 例子: 必要时给出举例,[实践证明其对输出正确性有帮助]
    • 输入: 任务的输入信息; 在提示词中明确的标识出输入
    • 输出: 输出的格式描述,以便后继模块自动解析模型的输出结果,比如(JSON、Java)
  • Prompt练习
  • 角色: 你是一位专业的博客作者。
    指示: 撰写一篇关于最新AI技术发展的文章。
    上下文: 文章应该涵盖AI技术的当前状态和未来趋势。
    例子: 可以引用最近的AI技术突破和行业专家的见解。
    输入: 当前AI技术的相关信息和数据。
    输出: 一篇结构清晰、观点鲜明的文章草稿。
    你是一个软件工程师,帮我生成MysQL的表结构
    需求如下:
    1,课程管理表,表名tb_course,字段有主键id、课程编码、课程学科、课程名称、课程价格、适用人群、课程介绍
    其他要求:
    1,每个表中都有创建时间(create_time)、修改时间(date_time)、创建人(create_by)、修改人(update_by)、备注(remark)这些字段
    2,每个表的主键都是自增的
    3,课程价格是整型、课程编码是字符串
    4,请为每个字段都添加上comment
    5,帮我给生成的表中插入一些IT课程示例数据
    课程学科: Java、人工智能、大数据
    适用人群: 小白学员、中级程序员
    你是一个软件工程师,现在要根据数据库的sq1脚本,编写数据库说明文档,sql脚本如下:
    CREATE TABLE `tb_course` (
    `id` INT AUTO_INCREMENT COMMENT '主键ID',
    `course_code` VARCHAR(255) NOT NULL COMMENT '课程编码',
    `course_subject` VARCHAR(100) NOT NULL COMMENT '课程学科',
    `course_name` VARCHAR(255) NOT NULL COMMENT '课程名称',
    `course_price` INT COMMENT '课程价格',
    `target_audience` VARCHAR(100) COMMENT '适用人群',
    `course_introduction` TEXT COMMENT '课程介绍',
    `create_time` DATETIME COMMENT '创建时间',
    `update_time` DATETIME COMMENT '修改时间',
    `create_by` VARCHAR(64) COMMENT '创建人',
    `update_by` VARCHAR(64) COMMENT '修改人',
    `remark` VARCHAR(255) COMMENT '备注',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='课程管理表';
    输出要求是:
    1,每个表以及每个表的字段都要详细说明,包括,字段名称、类型、作用
    2,使用markdown的输出格式,字段的描述需要使用表格展示
    3,如果表之间有关系,需要描述清楚表之间的关系
    你是一个软件工程师,为了方便理解代码执行流程,需要给出代码执行的流程图,代码如下:
    ****代码****

    输出: 请使用mermaid语言来描述这个方法的流程
    graph TD
    A[查询售货机] –> B{售货机存在?}
    B — no –> C[抛出错误:设备不存在]
    B — yes –> D[校验售货机状态与工单类型]
    D –> E{校验通过?}
    E — no –> F[抛出错误:状态或类型不符]
    E — yes –> G[查询是否存在未完成同类型工单]
    G –> H{存在未完成工单?}
    H — yes –> I[抛出错误:存在未完成同类型工单]
    H — no –> J[查询员工]
    J –> K{员工存在?}
    K — no –> L[抛出错误:员工不存在]
    K — yes –> M[校验员工区域与售货机区域是否一致]
    M –> N{区域不一致?}
    N — yes –> O[抛出错误:非同区域员工不能接受工单]
    N — no –> P[构造工单信息]
    P –> Q[保存工单基本信息至数据库]
    Q –> R{工单类型是否为补货?}
    R — no –> S[结束流程]
    R — yes –> T[检查补货工单明细]
    T –> U{明细为空?}
    U — yes –> V[抛出错误:补货工单明细不能为空]

    mermaid看起来不直观,可以把graph TD交给ai识别或者mackdown识别

    生成代码

    代码生成算是比较常规的方案,用的也比较多,分为了几种情况

  • 给出表生成代码(项目中常见)
    • 给出表结构的ddI,可以输出这个表的增删改查的所有代码。
    • 给出表结构的dlIl,可以输出增删改查的接口文档
  • 补全代码
    • 例1-给出实体类,帮助编写getter、setter、toString、构造方法等等
    • 例2-给出一个controller,帮助编写swagger注解等
  • 提取结构(无含金量,费时间的编程)
    • 例1-根据接口文档提取dto类或者vo类

    项目搭建

    搭建后端项目

  • Git克隆并初始化项目
    • 后端仓库地址: https://gitee.com/yudian1991/dkd-parent.git
    • 资料中提供了离线版项目可以使用

  • MySQL导入与配置
  • 启动Redis与配置
  • 运行后端项目
  • 搭建前端工程

  • Git克隆并初始化项目
    • 前端仓库地址: https://gitee.com/yudian1991/dkd-vue.git
    • 资料中提供了离线版的工程可以使用
  • 安装依赖
  • 运行前端项目
  • 点位管理

    需求说明

    业务场景:

    公司计划在北京的高流量商业和居民区与潜在合作商洽谈,确定点位部署智能售货机,提供便捷的购买服务

  • 点位管理主要涉及到三个功能模块,业务流程如下:
  • 库表设计

    参考页面原型和具体需求完成库表设计

  • 区域表: 主键id、区域名称、备注说明
  • 合作商表: 主键id、合作商名称、联系人、联系电话、分成比例、账号、密码
  • 点位表: 主键id、点位名称、详细地址、商圈类型、区域外键、合作商外键
  • 若衣提供了基础实体类,封装了所有实体类的公共字段
  • 使用AI生成建表语句

    你是一位软件工程师,帮我生成MySQL的表结构
    需求如下:
    1,区域表,表名tb_region,字段有主键id、区域名称
    2,合作商表,表名tb_partner,字段有主键id、合作商名称、联系人、联系电话、分成比例(int类型)、账号、密码
    3,点位表,表名tb_node,字段有主键id、点位名称、详细地址、商圈类型(int类型)
    其他要求:
    1,每张表中都有创建时间(create_time)、修改时间(update_time)、创建人(create_by)、修改人(update_by)、备注(remark)这些字段
    2,每张表的主键都是自增的
    3,区域与点位是一对多的关系,合作商与点位是一对多的关系,请用字段表示出来,并建立外键约束
    4,请为每个字段都添加上comment
    5,帮我给生成的表中插入一些北京城市相关区域、点位、合作商的测试数据
    — 1. 创建区域表 tb_region
    CREATE TABLE tb_region (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '区域主键ID',
    region_name VARCHAR(255) NOT NULL COMMENT '区域名称',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    create_by VARCHAR(64) DEFAULT '' COMMENT '创建人',
    update_by VARCHAR(64) DEFAULT '' COMMENT '修改人',
    remark TEXT COMMENT '备注'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='区域表';

    — 1. 插入北京区域测试数据
    INSERT INTO tb_region (region_name) VALUES ('北京市朝阳区'),('北京市海淀区'),('北京市东城区');
    — 2. 创建合作商表 tb_partner
    CREATE TABLE tb_partner (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '合作商主键ID',
    partner_name VARCHAR(255) NOT NULL COMMENT '合作商名称',
    contact_person VARCHAR(64) DEFAULT '' COMMENT '联系人',
    contact_phone VARCHAR(15) DEFAULT '' COMMENT '联系电话',
    profit_ratio INT DEFAULT 0 COMMENT '分成比例(%)',
    account VARCHAR(64) NOT NULL COMMENT '账号',
    password VARCHAR(64) NOT NULL COMMENT '密码',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    create_by VARCHAR(64) DEFAULT '' COMMENT '创建人',
    update_by VARCHAR(64) DEFAULT '' COMMENT '修改人',
    remark TEXT COMMENT '备注'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合作商表';

    — 2. 插入合作商测试数据
    INSERT INTO tb_partner (partner_name, contact_person, contact_phone, profit_ratio, account, password) VALUES
    ('合作商A', '张三', '13800138000', 30, 'a001', 'pwdA'),
    ('合作商B', '李四', '13900139000', 25, 'a002', 'pwdB');
    — 3. 创建点位表 tb_node(含外键关联区域/合作商)
    CREATE TABLE tb_node (
    id INT AUTO_INCREMENT PRIMARY KEY COMMENT '点位主键ID',
    node_name VARCHAR(255) NOT NULL COMMENT '点位名称',
    address VARCHAR(255) DEFAULT '' COMMENT '详细地址',
    business_type INT DEFAULT 0 COMMENT '商圈类型',
    region_id INT COMMENT '关联区域ID',
    partner_id INT COMMENT '关联合作商ID',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    create_by VARCHAR(50) DEFAULT '' COMMENT '创建人',
    update_by VARCHAR(50) DEFAULT '' COMMENT '修改人',
    remark TEXT COMMENT '备注',
    — 外键约束:关联区域表
    FOREIGN KEY (region_id) REFERENCES tb_region(id) ON DELETE CASCADE ON UPDATE CASCADE,
    — 外键约束:关联合作商表
    FOREIGN KEY (partner_id) REFERENCES tb_partner(id) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='点位表';

    — 3. 插入点位测试数据(关联上述区域和合作商)
    INSERT INTO tb_node (node_name, address, business_type, region_id, partner_id) VALUES
    ('三里屯站点', '北京市朝阳区三里屯路', 1, 1, 1),
    ('五道口站点', '北京市海淀区五道口', 2, 2, 2);

    对于点位管理数据模型,下面是示意图:

  • 关系字段: region_id、partner_id
  • 数据字典: business_type
  • 生成基础代码

    使用若依代码生成器,生成区域管理、合作商管理、点位管理前后端基础代码,并导入到项目中:

  • 创建目录菜单
  • 添加数据字典
  • 配置代码生成信息
    • 导入数据表信息

    • 配置区域表

    • 配置合作商表

    • 配置点位表

    • 生成代码

  • 下载代码导入到项目中
  • 说明:.gitkeep是占位的空文件,没有实际意义,因为git不允许空文件夹所以占用用

    区域管理改造

    参考页面原型,完成基础布局展示改造

    在查询区域列表时,同时显示每个区域的点位数

    方案选型

  • 同步存储在区域表中有点位数的字段,当点位发生变化时,同步区域表中的点位数。
  • 关联查询编写关联查询语句,在mapper层封装。
  • 区域和点位表,记录个数都不是很多,所以我们采用关联查询这种方案。
  • 代码实现

  • 确定关联查询方案并编写sql
  • # 传统模式
    # 1.先聚合统计每个区域下的点位数
    # 确定查询表 tb_node-
    # 确定分组字段 region_id
    select region_id,count(*) as node_count from tb_node group by region_id;
    # 2.然后与区域表进行关联查询
    select r.id,r.region_name,r.remark, ifnull(n.node_count, 0) as node_count from tb_region r
    left join (select region_id,count(*) as node_count from tb_node group by region_id) n on r.id=n.region_id;

    # AI生成sql
    # 查询区域表(tb_region)所有的信息,需要显示每个区域的点位数(tb_node)
    SELECT
    r.*,
    COUNT(n.id) AS node_count
    FROM
    tb_region r
    LEFT JOIN
    tb_node n ON r.id = n.region_id
    GROUP BY
    r.id;

  • 创建RegionVo
  • package com.dkd.manage.domain.vo;

    import com.dkd.manage.domain.Region;
    import lombok.Data;

    @Data
    public class RegionVo extends Region {
    // 点位数量
    private Integer nodeCount;
    }

  • 在RegionMapper和xml中添加查询Vo方法和sql
  • package com.dkd.manage.mapper;

    import java.util.List;

    import com.dkd.manage.domain.Region;
    import com.dkd.manage.domain.vo.RegionVo;

    /**
    * 区域管理Mapper接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface RegionMapper {

    /**
    * 查询区域列表
    *
    * @param region
    * @return RegionVo集合
    */
    public List<RegionVo> selectRegionVoList(Region region);
    }

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.dkd.manage.mapper.RegionMapper">

    <select id="selectRegionVoList" resultType="com.dkd.manage.domain.vo.RegionVo"
    parameterType="com.dkd.manage.domain.Region">
    SELECT r.*, COUNT(n.id) AS node_count FROM tb_region r LEFT JOIN tb_node n ON r.id = n.region_id
    <where>
    <if test="regionName != null and regionName != ''">and r.region_name like concat('%', #{regionName}, '%')
    </if>
    </where>
    GROUP BY r.id
    </select>

    </mapper>

  • 在RegionService接口和实现类中添加查询Vo方法
  • package com.dkd.manage.service;

    import java.util.List;

    import com.dkd.manage.domain.Region;
    import com.dkd.manage.domain.vo.RegionVo;

    /**
    * 区域管理Service接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface IRegionService {

    /**
    * 查询区域管理
    */
    public List<RegionVo> selectRegionVoList(Region region);
    }

    package com.dkd.manage.service.impl;

    import java.util.List;

    import com.dkd.common.utils.DateUtils;
    import com.dkd.manage.domain.vo.RegionVo;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import com.dkd.manage.mapper.RegionMapper;
    import com.dkd.manage.domain.Region;
    import com.dkd.manage.service.IRegionService;

    /**
    * 区域管理Service业务层处理
    *
    * @author itheima
    * @date 2026-02-19
    */
    @Service
    public class RegionServiceImpl implements IRegionService {

    /**
    * 查询区域列表
    *
    * @param region
    * @return RegionVo集合
    */
    @Override
    public List<RegionVo> selectRegionVoList(Region region) {
    return regionMapper.selectRegionVoList(region);
    }
    }

  • 修改RegionController查询方法
  • package com.dkd.manage.controller;

    /**
    * 区域管理Controller
    *
    * @author itheima
    * @date 2026-02-19
    */
    @RestController
    @RequestMapping("/manage/region")
    public class RegionController extends BaseController
    {
    @Autowired
    private IRegionService regionService;

    /**
    * 查询区域管理列表
    */
    @PreAuthorize("@ss.hasPermi('manage:region:list')")
    @GetMapping("/list")
    public TableDataInfo list(Region region)
    {
    startPage();
    // List<Region> list = regionService.selectRegionList(region);
    List<RegionVo> list = regionService.selectRegionVoList(region);
    return getDataTable(list);
    }

    }

  • 修改前端视图组件
  • 若衣提供了热更新插件,只要文件不变化,仅文件内容内容变化就可以热更新,避免频繁重启,
  • 快捷键是 ctrl+f9
  • 查看详情,需要显示当前区域下所有点位列表

    合作商管理改造

    参考页面原型,完成基础布局展示改造

    避免密码明文存储

    package com.dkd.manage.service.impl;

    import java.util.List;
    import com.dkd.common.utils.DateUtils;
    import com.dkd.common.utils.SecurityUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.stereotype.Service;
    import com.dkd.manage.mapper.PartnerMapper;
    import com.dkd.manage.domain.Partner;
    import com.dkd.manage.service.IPartnerService;

    /**
    * 合作商管理Service业务层处理
    *
    * @author itheima
    * @date 2026-02-19
    */
    @Service
    public class PartnerServiceImpl implements IPartnerService
    {

    /**
    * 新增合作商管理
    *
    * @param partner 合作商管理
    * @return 结果
    */
    @Override
    public int insertPartner(Partner partner)
    {
    // 使用springSecurity工具类,对密码加密处理
    partner.setPassword(SecurityUtils.encryptPassword(partner.getPassword()));
    partner.setCreateTime(DateUtils.getNowDate());
    return partnerMapper.insertPartner(partner);
    }
    }

    查看详情,需要显示合作商名称、联系人、联系电话、分成比例

    在查询合作商列表时,同时显示每个合作商的点位数。

    # AI生成sql
    # 查询合作商表(tb_partner)的所有信息,同时查询每个合作商的点位数(node_count),生成sql语句
    SELECT
    p.*,
    COUNT(n.id) AS node_count
    FROM
    tb_partner p
    LEFT JOIN
    tb_node n ON p.id = n.partner_id
    GROUP BY
    p.id

    package com.dkd.manage.mapper;

    import java.util.List;
    import com.dkd.manage.domain.Partner;
    import com.dkd.manage.domain.vo.PartnerVo;

    /**
    * 合作商管理Mapper接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface PartnerMapper
    {
    /**
    * 查询合作商管理
    */
    public List<PartnerVo> selectPartnerVoList(Partner partner);
    }

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.dkd.manage.mapper.PartnerMapper">

    <select id="selectPartnerVoList" resultType="com.dkd.manage.domain.vo.PartnerVo"
    parameterType="com.dkd.manage.domain.Partner">
    SELECT p.*,COUNT(n.id) AS node_count FROM tb_partner p LEFT JOIN tb_node n ON p.id = n.partner_id
    <where>
    <if test="partnerName != null and partnerName != ''">and p.partner_name like concat('%', #{partnerName},
    '%')
    </if>
    </where>
    GROUP BY p.id
    </select>

    </mapper>
    package com.dkd.manage.service;

    import java.util.List;
    import com.dkd.manage.domain.Partner;
    import com.dkd.manage.domain.vo.PartnerVo;

    /**
    * 合作商管理Service接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface IPartnerService
    {

    /**
    * 查询合作商管理
    */
    public List<PartnerVo> selectPartnerVoList(Partner partner);
    }

    package com.dkd.manage.service.impl;

    /**
    * 合作商管理Service业务层处理
    *
    * @author itheima
    * @date 2026-02-19
    */
    @Service
    public class PartnerServiceImpl implements IPartnerService {
    @Autowired
    private PartnerMapper partnerMapper;

    /**
    * 查询合作商列表
    *
    * @param partner
    * @return
    */
    @Override
    public List<PartnerVo> selectPartnerVoList(Partner partner) {
    return partnerMapper.selectPartnerVoList(partner);
    }
    }

    package com.dkd.manage.controller;

    /**
    * 合作商管理Controller
    *
    * @author itheima
    * @date 2026-02-19
    */
    @RestController
    @RequestMapping("/manage/partner")
    public class PartnerController extends BaseController
    {
    @Autowired
    private IPartnerService partnerService;

    /**
    * 查询合作商管理列表
    */
    @PreAuthorize("@ss.hasPermi('manage:partner:list')")
    @GetMapping("/list")
    public TableDataInfo list(Partner partner)
    {
    startPage();
    // List<Partner> list = partnerService.selectPartnerList(partner);
    List<PartnerVo> list = partnerService.selectPartnerVoList(partner);
    return getDataTable(list);
    }

    }

    ctrl + f9热更新服务

    重置密码,初始密码为123456

  • 重置密码开发流程
  • 后端代码实现
  • package com.dkd.manage.controller;

    /**
    * 合作商管理Controller
    *
    * @author itheima
    * @date 2026-02-19
    */
    @RestController
    @RequestMapping("/manage/partner")
    public class PartnerController extends BaseController
    {
    @Autowired
    private IPartnerService partnerService;

    /**
    * 重置合作商密码
    */
    @PreAuthorize("@ss.hasPermi('manage:partner:edit')")
    @Log(title = "重置合作商密码", businessType = BusinessType.UPDATE)
    @PutMapping("resetPwd/{id}")
    public AjaxResult resetPwd(@PathVariable Long id)
    {
    Partner partner = new Partner();
    partner.setId(id);
    partner.setPassword(SecurityUtils.encryptPassword("123456"));
    return toAjax(partnerService.updatePartner(partner));
    }
    }

  • 前端代码实现
  • 点位管理改造

    在点位列表查询中,关联显示区域、合作商等信息

  • 实现思路
    • 关联查询: 对于设备数量的统计,我们需要执行关联查询,在mapper层封装。
    • 关联实体: 对于区域和合作商的数据,我们会采用Mybatis提供的嵌套查询功能。
    • MyBatis嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用mybatis的语法嵌套在一起,通过定义resultMap和sql语句中的association 或collection 元素来实现嵌套查询。

  • 执行资料中的建表语句
  • 生成sql语句
  • SELECT
    n.id,
    n.node_name,
    n.address,
    n.business_type,
    n.region_id,
    n.partner_id,
    n.create_time,
    n.update_time,
    n.create_by,
    n.update_by,
    n.remark,
    COUNT(vm.id) AS vm_count
    FROM tb_node n
    LEFT JOIN tb_vending_machine vm ON n.id = vm.node_id
    GROUP BY
    n.id;

    # 再根据点位的区域外键region_id查询区域的信息
    select * from tb_region where id=1;

    # 再根据点位的合作商外键partner_id查询合作商信息
    select * from tb_partner where id=1;

  • 实体类
  • mapper
  • package com.dkd.manage.mapper;

    import java.util.List;
    import com.dkd.manage.domain.Node;
    import com.dkd.manage.domain.vo.NodeVo;

    /**
    * 点位管理Mapper接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface NodeMapper
    {
    /**
    * 查询点位管理列表
    * @param node
    * @return
    */
    public List<NodeVo> selectNodeVoList(Node node);
    }

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.dkd.manage.mapper.NodeMapper">

    <resultMap type="NodeVo" id="NodeVoResult">
    <result property="id" column="id" />
    <result property="nodeName" column="node_name" />
    <result property="address" column="address" />
    <result property="businessType" column="business_type" />
    <result property="regionId" column="region_id" />
    <result property="partnerId" column="partner_id" />
    <result property="createTime" column="create_time" />
    <result property="updateTime" column="update_time" />
    <result property="createBy" column="create_by" />
    <result property="updateBy" column="update_by" />
    <result property="remark" column="remark" />
    <result property="vmCount" column="vm_count" />
    <association property="region" javaType="Region" column="region_id" select="com.dkd.manage.mapper.RegionMapper.selectRegionById" />
    <association property="partner" javaType="Partner" column="partner_id" select="com.dkd.manage.mapper.PartnerMapper.selectPartnerById" />
    </resultMap>

    <select id="selectNodeVoList" resultMap="NodeVoResult"
    parameterType="com.dkd.manage.domain.Node">
    SELECT
    n.id,
    n.node_name,
    n.address,
    n.business_type,
    n.region_id,
    n.partner_id,
    n.create_time,
    n.update_time,
    n.create_by,
    n.update_by,
    n.remark,
    COUNT(vm.id) AS vm_count
    FROM tb_node n
    LEFT JOIN tb_vending_machine vm ON n.id = vm.node_id
    <where>
    <if test="nodeName != null and nodeName != ''"> and n.node_name like concat('%', #{nodeName}, '%')</if>
    <if test="regionId != null "> and n.region_id = #{regionId}</if>
    <if test="partnerId != null "> and n.partner_id = #{partnerId}</if>
    </where>
    GROUP BY
    n.id
    </select>

    </mapper>

  • service
  • package com.dkd.manage.service;

    import java.util.List;
    import com.dkd.manage.domain.Node;
    import com.dkd.manage.domain.vo.NodeVo;

    /**
    * 点位管理Service接口
    *
    * @author itheima
    * @date 2026-02-19
    */
    public interface INodeService
    {
    /**
    * 查询点位管理列表
    * @param node
    * @return
    */
    public List<NodeVo> selectNodeVoList(Node node);
    }

    package com.dkd.manage.service.impl;

    /**
    * 点位管理Service业务层处理
    *
    * @author itheima
    * @date 2026-02-19
    */
    @Service
    public class NodeServiceImpl implements INodeService
    {
    @Autowired
    private NodeMapper nodeMapper;

    @Override
    public List<NodeVo> selectNodeVoList(Node node) {
    return nodeMapper.selectNodeVoList(node);
    }
    }

  • controller
  • package com.dkd.manage.controller;

    /**
    * 点位管理Controller
    *
    * @author itheima
    * @date 2026-02-19
    */
    @RestController
    @RequestMapping("/manage/node")
    public class NodeController extends BaseController {
    @Autowired
    private INodeService nodeService;

    /**
    * 查询点位管理列表
    */
    @PreAuthorize("@ss.hasPermi('manage:node:list')")
    @GetMapping("/list")
    public TableDataInfo list(Node node) {
    startPage();
    // List<Node> list = nodeService.selectNodeList(node);
    List<NodeVo> list = nodeService.selectNodeVoList(node);
    return getDataTable(list);
    }
    }

  • 前端修改
  • 查看详情,需要显示当前点位下所有设备列表

    数据完整性

    在删除区域或合作商数据时,关联的点位数据该如何处理?

  • 由于数据库进行了外键约束,当删除区域数据时,关联的点位数据也会被删除
  • 从业务角度看,这样是不合理的,现在要进行改造
  • 修改区域/合作商删除操作的处理流程
    • 将点位表级联操作改为限制删除
    • 在全局异常处理器中捕获异常友情提示
  • 数据库操作
  • 全局异常处理
    • 把数据库外键的约束由联级操作改为拒绝操作之后,再删除区域数据,由于区域关键了点位数据,所以数据库拒绝操作,这符合数据一致性要求,但是这个报错信息可读性太差

    • SQLIntegrityConstraintViolationException: 这个类通常用于表示SQL数据库操作中的完整性约束违反异常
    • 例如: 外键约束、唯一约束等。当数据库操作违反了这些约束时,就会抛出这个异常。
    • DatalntegrityViolationException: 在使用SpringBoot框架时,如果违反了数据完整性抛出这个异常。
    • RuoYi框架已经提供了全局异常处理器,我们只需要添加一个自定义异常就能处理了

    人员管理

    前置工作

    需求说明

    业务场景: 想象一下,在我们确定了区域、合作商、点位之后,接下来的步骤是什么?

  • 人员管理主要涉及到人员列表功能模块,业务流程如下:
  • 库表设计

    对于人员管理数据模型,下面是示意图:

  • 关系字段: role_id、region_id
  • 数据字典: status(1启用、0停用)
  • 冗余字段: region_name、role_code、role_name
  • 生成基础代码

    使用若依代码生成器,生成人员列表前后端基础代码,并导入到项目中:

  • 创建目录菜单
  • 添加数据字典
  • 配置代码生成信息
  • 下载代码并导入项目
  • 重启服务
  • 人员列表改造

    把添加和修改弹窗中的所属区域和角色修改为下拉框

  • 修改角色
  • 修改所属区域
  • 信息补全

    添加员工后,由于前端只传递角色和所属区域的id, 所以角色和所属区域的名称并没有入库

    package com.dkd.manage.service.impl;

    /**
    * 人员列表Service业务层处理
    *
    * @author itheima
    * @date 2026-02-21
    */
    @Service
    public class EmpServiceImpl implements IEmpService
    {
    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private RoleMapper roleMapper;

    /**
    * 新增人员列表
    *
    * @param emp 人员列表
    * @return 结果
    */
    @Override
    public int insertEmp(Emp emp)
    {
    // 补充区域名称
    emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
    // 补充角色信息
    Role role = roleMapper.selectRoleByRoleId(emp.getRoleId());
    emp.setRoleCode(role.getRoleCode());
    emp.setRoleName(role.getRoleName());
    // 创建时间
    emp.setCreateTime(DateUtils.getNowDate());
    return empMapper.insertEmp(emp);
    }

    /**
    * 修改人员列表
    *
    * @param emp 人员列表
    * @return 结果
    */
    @Override
    public int updateEmp(Emp emp)
    {
    // 补充区域名称
    emp.setRegionName(regionMapper.selectRegionById(emp.getRegionId()).getRegionName());
    // 补充角色信息
    Role role = roleMapper.selectRoleByRoleId(emp.getRoleId());
    emp.setRoleCode(role.getRoleCode());
    emp.setRoleName(role.getRoleName());
    // 修改时间
    emp.setUpdateTime(DateUtils.getNowDate());
    return empMapper.updateEmp(emp);
    }

    }

    问题复现

    修改区域信息后,人员列表中的区域信息未同步

    数据一致性维护

    同步存储: 在员工表中有区域名称的冗余字段,在更新区域表的同时,同步更新员工表中区域名称。

    package com.dkd.manage.mapper;

    import java.util.List;
    import com.dkd.manage.domain.Emp;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Update;

    /**
    * 人员列表Mapper接口
    *
    * @author itheima
    * @date 2026-02-21
    */
    public interface EmpMapper
    {

    /**
    * 根据区域id修改区域名称
    * @return
    */
    @Update("update tb_emp set region_name = #{regionName} where region_id = #{regionId}")
    public int updateByRegionId(@Param("regionName") String regionName, @Param("regionId") Long regionId);
    }

    package com.dkd.manage.service.impl;

    /**
    * 区域管理Service业务层处理
    *
    * @author itheima
    * @date 2026-02-19
    */
    @Service
    public class RegionServiceImpl implements IRegionService {
    @Autowired
    private RegionMapper regionMapper;

    @Autowired
    private EmpMapper empMapper;

    /**
    * 修改区域管理
    *
    * @param region 区域管理
    * @return 结果
    */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateRegion(Region region) {
    // 先更新区域信息
    region.setUpdateTime(DateUtils.getNowDate());
    int result = regionMapper.updateRegion(region);
    // 同步更新员工表的区域名称
    empMapper.updateByRegionId(region.getRegionName(), region.getId());

    return result;
    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » [Java]RuoYi帝可得-1项目搭建
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址