文章目录
🍇1. 点位管理 - 表关系
🍋2. 生成基础代码
2.1 创建目录菜单
2.2 添加字典数据
2.3 配置代码生成信息
- partner
- region
- node
2.4 下载代码并导入项目
🍎3. 区域管理 - 表关系
3.1 开启mybatis的驼峰映射
3.2 新增用户时对密码加密
@Override
public int insertPartner(Partner partner) {
// 使用SecurityUtil工具类,对密码加密
partner.setPassword(SecurityUtils.encryptPassword(partner.getPassword()));
partner.setCreateTime(DateUtils.getNowDate());
return partnerMapper.insertPartner(partner);
}
🍒4. 合作商管理 - 表关系
4.1 合作商重置密码
@PutMapping("/resetPwd/{id}")
public AjaxResult resetpwd(@PathVariable Long id) {//1. 接收参数
//2. 创建合作商对象
Partner partner = new Partner();
partner.setId(id);// 设置id
partner.setPassword(SecurityUtils.encryptPassword("123456"));// 设置加密后的初始密码
//3. 调用service更新密码
return toAjax(partnerService.updatePartner(partner));
}
// 重置合作商密码
export function resetPartnerPwd(id){
return request({
url: '/manage/partner/resetPwd/' + id,
method: 'put'
})
}
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="300px">
<template #default="scope">
<el-button link type="primary" @click="resetPwd(scope.row)" v-hasPermi="['manage:partner:edit']">重置密码</el-button>
</template>
</el-table-column>
<script>
import { listPartner, getPartner, delPartner, addPartner, updatePartner,resetPartnerPwd } from "@/api/manage/partner";
/* 重置合作商密码 */
function resetPwd(row) {
proxy.$modal.confirm('你确定要重置该合作商密码吗?').then(function () {
return resetPartnerPwd(row.id);
}).then(() => {
proxy.$modal.msgSuccess("重置成功");
}).catch(() => { });
}
</script>
4.2 点位列表查询中,会关联显示区域、商圈
关联查询:对于设备数量的统计,我们需要执行关联查询,在mapper 层封装。
关联实体:对于区域和合作商的数据,我们会采用Mybatis提供的嵌套查询功能。
MyBatis 嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用mybatis的语法嵌套在一 起,通过定义**resultMap**
和**sql**
语句中的**association**
或**collection**
元素来实现嵌套查询。
4.3 NodeMapper.xml
<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">
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(v.id) AS vm_count
FROM
tb_node n
LEFT JOIN
tb_vending_machine v ON n.id = v.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>
🥝5. 数据完整性
现在我们要思考一个问题,当我们删除区域或合作商数据时,与之关联的点位数据该如何处理?
- **CASCADE(级联操作)😗*当父表中的某行记录被删除或更新时,与其关联的所有子表中的匹配行也会自动被删除或更新。适用于希望保持数据一致性的场景,即父记录不存在时,相关的子记录也应该被移除。
- **SET NULL(设为空)😗*若父表中的记录被删除或更新,子表中对应的外键字段会被设置为NULL。选择此选项的前提是子表的外键列允许为NULL值。这适用于那些子记录不再需要明确关联到任何父记录的情况。
- **RESTRICT(限制)😗*在尝试删除或更新父表中的记录之前,数据库首先检查是否有相关联的子记录存在。如果有,则拒绝执行删除或更新操作,以防止意外丢失数据或破坏数据关系的完整性。这是一种保守策略,确保数据间的引用完整性。
- **NO ACTION(无操作)😗*在标准SQL中,NO ACTION是一个关键字,它要求数据库在父表记录被删除或更新前,检查是否会影响子表中的相关记录。在MySQL中,NO ACTION的行为与RESTRICT相同,即如果子表中有匹配的行,则禁止执行父表的删除或更新操作。这意味着如果存在依赖关系,操作将被阻止,从而保护数据的参照完整性。
🌶️6. 全局异常处理器
/**
* 数据完整性异常
*/
@ExceptionHandler(DataIntegrityViolationException.class)
public AjaxResult handelDataIntegrityViolationException(DataIntegrityViolationException e) {
if (e.getMessage().contains("foreign")) {
return AjaxResult.error("无法删除,有其他数据引用");
}
return AjaxResult.error("您的操作违反了数据库中的完整性约束");
}
🥑7. 人员管理 - 表关系
- 关系字段:role_id、region_id
- 数据字典:status(1启用、0停用)
- 冗余字段:region_name、role_code、role_name
7.1 生成基础代码
7.2 创建目录菜单
7.3 添加数据字典
7.4 配置代码生成信息
7.5 下载代码并导入项目
注意:角色动态菜单sql和视图组件不需要导入
7.6 emp/index.vue
<!-- 搜索区域 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="人员名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入人员名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 人员列表 -->
<el-table v-loading="loading" :data="empList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" width="80" align="center" prop="id" />
<el-table-column label="人员名称" align="center" prop="userName" />
<el-table-column label="归属区域" align="center" prop="regionName" />
<el-table-column label="角色" align="center" prop="roleName" />
<el-table-column label="联系电话" align="center" prop="mobile" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['manage:emp:edit']">修改</el-button>
<el-button link type="primary" @click="handleDelete(scope.row)" v-hasPermi="['manage:emp:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改人员列表对话框 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="empRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="员工名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入员工名称" />
</el-form-item>
<el-form-item label="角色" prop="roleId">
<!-- <el-input v-model="form.roleId" placeholder="请输入角色id" /> -->
<el-select v-model="form.roleId" placeholder="请选择角色">
<el-option v-for="item in roleList" :key="item.roleId" :label="item.roleName" :value="item.roleId" />
</el-select>
</el-form-item>
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="form.mobile" placeholder="请输入联系电话" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime" v-if="form.id!=null">
{{form.createTime }}
</el-form-item>
<el-form-item label="负责区域" prop="regionId">
<!-- <el-input v-model="form.regionId" placeholder="请输入所属区域Id" /> -->
<el-select v-model="form.regionId" placeholder="请选择所属区域">
<el-option v-for="item in regionList" :key="item.id" :label="item.regionName" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="员工头像" prop="image">
<image-upload v-model="form.image" />
</el-form-item>
<el-form-item label="是否启用" prop="status">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in emp_status" :key="dict.value"
:label="parseInt(dict.value)">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
<script>
import { listRegion } from "@/api/manage/region";
import { listRole } from "@/api/manage/role";
import { loadAllParams } from "@/api/page";
// 查询角色列表
const roleList = ref([]);
function getRoleList() {
listRole(loadAllParams).then(response => {
roleList.value = response.rows;
});
}
// 查询区域列表
const regionList = ref([]);
function getRegionList() {
listRegion(loadAllParams).then(response => {
regionList.value = response.rows;
});
}
getRegionList();
getRoleList();
</script>
🍄8. 同步存储
同步存储:在员工表中有区域名称的冗余字段,在更新区域表的同时,同步更新员工表中区域名称。
- 优点:由于是单表查询操作,查询列表效率最高。
- 缺点:需要在区域修改时修改员工表中的数据,有额外的开销,数据也可能不一致。
8.1 impl
@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;
}
8.2 mapper
@Update("update tb_emp set region_name=#{regionName} where region_id=#{regionId}")
int updateByRegionId(@Param("regionName") String regionName, @Param("regionId") Long regionId);